diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/CREDITS linux/CREDITS --- v2.2.18/CREDITS Sun Mar 25 11:28:15 2001 +++ linux/CREDITS Sun Mar 25 11:37:29 2001 @@ -23,6 +23,12 @@ S: University of Limerick S: Ireland +N: Tigran Aivazian +E: tigran@veritas.com +W: http://www.moses.uklinux.net/patches +D: Intel IA32 microcode update driver +S: United Kingdom + N: Werner Almesberger E: werner.almesberger@lrc.di.epfl.ch D: dosfs, LILO, some fd features, various other hacks here and there @@ -235,8 +241,8 @@ S: Australia N: Hugh Blemings -E: hugh@linuxcare.com -W: http://www.linuxcare.com.au/hugh/ +E: hugh@misc.nu +W: http://misc.nu/hugh D: Author and maintainer of the Keyspan USB to Serial drivers S: Po Box 234 S: Belconnen ACT 2616 @@ -515,13 +521,9 @@ S: Belgium N: Cort Dougan -E: cort@cs.nmt.edu -W: http://www.cs.nmt.edu/~cort/ +E: cort@fsmlabs.com +W: http://www.fsmlabs.com/linuxppcbk.html D: PowerPC -S: Computer Science Department -S: New Mexico Tech -S: Socorro, New Mexico 87801 -S: USA N: Oleg Drokin E: green@ccssu.crimea.ua @@ -804,11 +806,11 @@ S: Canada N: Richard Günther -E: richard.guenther@student.uni-tuebingen.de +E: rguenth@tat.physik.uni-tuebingen.de +W: http://www.tat.physik.uni-tuebingen.de/~rguenth P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2 93 7A 32 42 45 37 23 57 D: binfmt_misc -S: Fichtenweg 3/511 -S: 72076 Tübingen +S: 72074 Tübingen S: Germany N: Danny ter Haar @@ -878,13 +880,13 @@ S: USA N: Benjamin Herrenschmidt -E: bh40@calva.net +E: benh@kernel.crashing.org E: benh@mipsys.com -D: PowerMac booter (BootX) +D: PowerMac booters (BootX, yaboot) D: Additional PowerBook support D: Apple "Core99" machines support (ibook,g4,...) -S: 22, rue des Marguettes -S: 75012 Paris +S: 122, blvd. Baille +S: 13005 Marseille S: France N: Sebastian Hetze @@ -966,13 +968,12 @@ S: USA N: Harald Hoyer -E: HarryH@Royal.Net -W: http://hot.spotline.de/ -W: http://home.pages.de/~saturn +E: harald.hoyer@parzelle.de +W: http://parzelle.de/ D: ip_masq_quake D: md boot support -S: Alleenstrasse 27 -S: D-71679 Asperg +S: Hohe Strasse 30 +S: D-70176 Stuttgart S: Germany N: Kenn Humborg @@ -1335,6 +1336,13 @@ S: Niwot, Colorado 80503 S: USA +N: Robert M. Love +E: rml@tech9.net +E: rml@ufl.edu +D: misc. kernel hacking and debugging +S: Gainesville, Florida 32608 +S: USA + N: H.J. Lu E: hjl@gnu.ai.mit.edu D: GCC + libraries hacker @@ -1371,12 +1379,8 @@ S: Czech Republic N: Paul Mackerras -E: paulus@linuxcare.com +E: paulus@samba.org D: Linux port for PCI Power Macintosh -S: Linuxcare, Inc. -S: 24 Marcus Clarke Street -S: Canberra ACT 2601 -S: Australia N: Pat Mackinlay E: pat@it.com.au @@ -1735,15 +1739,15 @@ S: USA N: Kai Petzke -E: wpp@marie.physik.tu-berlin.de -W: http://physik.tu-berlin.de/~wpp -P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 +E: petzke@teltarif.de +W: http://www.teltarif.de/ +P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 D: Driver for Laser Magnetic Storage CD-ROM D: Some kernel bug fixes D: Port of the database Postgres -D: "Unix fuer Jedermann" a German introduction to linux (see my web page) -S: M"ullerstr. 69 -S: 13349 Berlin +D: Book: "Linux verstehen und anwenden" (Hanser-Verlag) +S: Triftstra=DFe 55 +S: 13353 Berlin S: Germany N: Ken Pizzini @@ -1860,8 +1864,8 @@ S: Germany N: Stephen Rothwell -E: sfr@linuxcare.com -W: http://linuxcare.com.au/sfr +E: sfr@canb.auug.org.au +W: http://www.canb.auug.org.au/~sfr P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02 D: Boot/setup/build work for setup > 2K D: Author, APM driver @@ -2145,7 +2149,7 @@ N: Andrew Tridgell E: tridge@samba.org -W: http://linuxcare.com.au/tridge/ +W: http://samba.org/tridge/ D: dosemu, networking, samba S: 3 Ballow Crescent S: MacGregor A.C.T 2615 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/Changes linux/Documentation/Changes --- v2.2.18/Documentation/Changes Sun Mar 25 11:28:15 2001 +++ linux/Documentation/Changes Sun Mar 25 11:37:29 2001 @@ -517,6 +517,28 @@ Older isdn4k-utils versions don't support EXTRAVERSION into kernel version string. A upgrade to isdn4k-utils.v3.1beta7 or later is recomented. +Intel IA32 microcode +==================== + +A driver has been added to allow updating of Intel IA32 microcode, +accessible as both a devfs regular file and as a normal (misc) +character device. If you are not using devfs you may need to: + +mkdir /dev/cpu +mknod /dev/cpu/microcode c 10 184 +chmod 0644 /dev/cpu/microcode + +as root before you can use this. You'll probably also want to +get the user-space microcode_ctl utility to use with this. + +If you have compiled the driver as a module you may need to add +the following line: + +alias char-major-10-184 microcode + +to your /etc/modules.conf file. + + Where to get the files ********************** diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/Configure.help linux/Documentation/Configure.help --- v2.2.18/Documentation/Configure.help Sun Mar 25 11:28:15 2001 +++ linux/Documentation/Configure.help Sun Mar 25 11:37:29 2001 @@ -1530,7 +1530,7 @@ inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. You will get modules called i2o_core.o - and i20_config.o. + and i2o_config.o. If unsure, say N. @@ -1765,7 +1765,7 @@ - "586" for generic Pentium CPUs, possibly lacking the TSC (time stamp counter) register. - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and - K6-3D. + K6-3D, as well as the Cyrix/VIA CyrixIII - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and Intel Pentium II/Pentium Pro. @@ -2233,7 +2233,7 @@ The module will be called parport.o. If you have more than one parallel port and want to specify which port and IRQ to be used by this driver at module load time, read - Documentation/networking/net-modules.txt. + Documentation/parport.txt. If unsure, say Y. @@ -3771,6 +3771,24 @@ module, say M here and read Documentation/modules.txt and Documentation/scsi.txt . +OnStream SC-x0 SCSI tape support +CONFIG_CHR_DEV_OSST + The OnStream SC-x0 SCSI tape drives can not be driven by the + standard st driver, but instead need this special osst driver and + use the /dev/osstX char device nodes (major 206). + For more information, you may have a look at the SCSI-HOWTO + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and + drivers/scsi/README.osst in the kernel source. + Most info may be found on http://linux1.onstream.nl/test/ + Please also have a look at the standard st docu, as most of it + applies to osst as well. + + 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 osst.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt and + Documentation/scsi.txt . + SCSI CDROM support CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the @@ -5869,6 +5887,25 @@ If you want to compile this as a module, say M and read Documentation/modules.txt. The module will be called comx-hw-mixcom.o. +i810 TCO support +CONFIG_I810_TCO + Hardware driver for the TCO timer built into the Intel i810 and i815 + chipset family. The TCO (Total Cost of Ownership) timer is a watchdog + timer that will reboot the machine after it's second expiration. The + expiration time can be configured by commandline argument + "i810_margin=" where is the counter initial value. It is + decremented every 0.6 secs, the default is 50 which gives a timeout + of 30 seconds and one minute until reset. + + On some motherboards the driver may fail to reset the chipset's + NO_REBOOT flag which prevents the watchdog from rebooting the machine. + If this is the case you will get a kernel message like + "i810tco init: failed to reset NO_REBOOT flag". + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called + i810-tco.o. + MultiGate Cisco-HDLC and synchronous PPP protocol support CONFIG_COMX_PROTO_PPP Cisco-HDLC and synchronous PPP protocol driver for all MultiGate boards. @@ -6187,6 +6224,37 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called rtl8139.o. +Alternative RealTek 8139 driver (8139too) support +CONFIG_RTL8139TOO + This is a sophisticated, multi platform driver for RealTek 8139x + based Fast Ethernet cards. It tries to work around several not + well documented hardware bugs in these chips and is also + usually faster than the original driver. However, 8129 is not + supported. + If you are sure you have a RTL8139-based card, choose this driver. + You can find more information in the Ethernet-HOWTO, available by + anonymous FTP from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called rtl8139too.o . + +Use PIO instead of MMIO +CONFIG_8139TOO_PIO + This instructs the driver to use PIO (only on i386 architecture) + instead of memory mapped IO. This can possibly solve some problems + in case your mainboard has memory consistency issues. If unsure, + say n. + +Support for automatic channel equalization +CONFIG_8139TOO_TUNE_TWISTER + This implements a function which might come in handy in case + you are using low quality on long cabling. It tries to match + the transceiver to the cable characteristics. This is experimental + since hardly documented by the manufacturer. + If unsure, say n. + SiS 900/7016 support CONFIG_SIS900 This is a driver for the Fast Ethernet PCI network cards based on @@ -6238,6 +6306,18 @@ If you don't have this card, of course say N. +Adaptec Starfire support (EXPERIMENTAL) +CONFIG_ADAPTEC_STARFIRE + Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network + adapter. The DuraLAN chip is used on the 64 bit PCI boards from + Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip + driver. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called starfire.o. + Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit @@ -6790,6 +6870,16 @@ Documentation/networking/net-modules.txt. The module will be called apricot.o. +LP486E on board Ethernet +CONFIG_LP486E + If you have an Intel Panther motherboard with on board 82596 network + (Ethernet) controller, say Y here. + The initialization code tries to guess the ethernet address by looking + at the EISA configuration area. Probably it finds precisely one thing + that looks like an address, but if this fails use the command + ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6 + to assign the address (revealed by the BIOS Setup) by hand. + Generic DECchip & DIGITAL EtherWORKS PCI/EISA CONFIG_DE4X5 This is support for the DIGITAL series of PCI/EISA Ethernet cards. @@ -7475,13 +7565,6 @@ ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota support is only useful for multi user systems. If unsure, say N. -Acorn's ADFS filesystem support (read only) (EXPERIMENTAL) -CONFIG_ADFS_FS - The Advanced Disk File System is the filesystem used on floppy and - hard disks by Acorn Systems. Currently in development, as a read- - only driver for hard disks. These should be the first partition - (eg. /dev/[sh]d?1) on each of your drives. If unsure, say N. - Support for USB CONFIG_USB Universal Serial Bus (USB) is a specification for a serial bus @@ -7854,6 +7937,16 @@ The module will be called digi_acceleport.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB Empeg empeg-car Mark I/II Driver +CONFIG_USB_SERIAL_EMPEG + Say Y here if you want to connect to your Empeg empeg-car Mark I/II + mp3 player via USB. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called empeg.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + USB Serial Converter verbose debug CONFIG_USB_SERIAL_DEBUG Say Y here if you want verbose debug messages from the USB Serial @@ -8423,10 +8516,10 @@ The module is called nfsd.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -Provide NFSv3 server support (EXPERIMENTAL) +Provide NFSv3 server support CONFIG_NFSD_V3 If you would like to include the NFSv3 server as well as the NFSv2 - server, say Y here. File locking, via the NLMv4 protocol, is now + server, say Y here. File locking, via the NLMv4 protocol, is also supported. If unsure, say N. OS/2 HPFS filesystem support (read only) @@ -8730,6 +8823,12 @@ partition tables of Macintosh hard drives, and thus use partitions on those drives. +Minix subpartition support +CONFIG_MINIX_SUBPARTITION + Minix 2.0.0/2.0.2 subpartition table support for Linux. + Say Y here if you want to mount and use Minix 2.0.0/2.0.2 + subpartitions. + SMB filesystem support (to mount Windows shares etc...) CONFIG_SMB_FS SMB (Server Message Block) is the protocol Windows for Workgroups @@ -9262,6 +9361,14 @@ input/output character sets. Say Y here for the preferred Russian character set. +nls koi8-ru +CONFIG_NLS_KOI8_RU + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the preferred Russian + character set. + Virtual terminal CONFIG_VT If you say Y here, you will get support for terminal devices with @@ -9654,6 +9761,24 @@ If you have more than 3 printers, you need to increase the LP_NO variable in lp.c. +Amiga built-in parallel port support +CONFIG_PARPORT_AMIGA + Say Y here if you need support for the parallel port hardware on + Amiga machines. This code is also available as a module (say M), + called parport_amiga.o. If in doubt, saying N is the safe plan. + +Atari built-in parallel port support +CONFIG_PARPORT_ATARI + Say Y here if you need support for the parallel port hardware on + Atari machines. This code is also available as a module (say M), + called parport_atari.o. If in doubt, saying N is the safe plan. + +Multiface 3 parallel port card support +CONFIG_PARPORT_MFC3 + Say Y here if you need parallel port support for the MFC3 card. + This code is also available as a module (say M), called + parport_mfc3.o. If in doubt, saying N is the safe plan. + Support IEEE1284 status readback CONFIG_PRINTER_READBACK If your printer conforms to IEEE 1284, it may be able to provide a @@ -10411,12 +10536,12 @@ it as a module. The module will be called sbc60xxwdt.o. CONFIG_MICROCODE - /dev/cpu/microcode - Intel P6 CPU microcode support + /dev/cpu/microcode - Intel IA32 CPU microcode support If you say Y here you will be able to update the microcode on - Intel processors in the P6 family, e.g. Pentium Pro, Pentium II, - Pentium III, Xeon etc. You will obviously need the actual microcode - binary data itself which is not shipped with the Linux kernel. + Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II, + Pentium III, Xeon, Pentium 4 etc. You will obviously need the actual + microcode binary data itself which is not shipped with the Linux kernel. For latest news and information on obtaining all the required ingredients for this driver, check: @@ -10425,7 +10550,9 @@ 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 microcode.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read Documentation/modules.txt. If you use + modprobe or kmod you may also want to add the line + 'alias char-major-10-184 microcode' to your /etc/modules.conf file. /dev/cpu/*/msr - Model-specific register support CONFIG_X86_MSR @@ -10476,8 +10603,8 @@ Intel 440LX/BX/GX support CONFIG_AGP_INTEL - This option give you AGP support for the GLX component of the - "soon to be released" XFree86-4 on Intel 440LX/BX/GX chipsets. + This option gives you AGP support for the GLX component of + XFree86 4.x on Intel 440LX/BX/GX, 815, and 840 chipsets. For the moment, most people should say no, unless you want to test the GLX component which can be downloaded from @@ -10485,9 +10612,9 @@ Intel I810/I810 DC100/I810e support CONFIG_AGP_I810 - This option give you AGP support for the Xserver for the intel - 810 chipset boards. This is required to do any useful video - modes. + This option gives you AGP support for XFree86 on the Intel 810 + and 815 chipsets for their on-board integrated graphics. This + is required to do any useful video modes with these boards. VIA VP3/MVP3/Apollo Pro support CONFIG_AGP_VIA @@ -10698,17 +10825,6 @@ to it. For more information on how to use the driver please read Documentation/joystick.txt -Atomwide Serial Support -CONFIG_ATOMWIDE_SERIAL - If you have an Atomwide Serial card for an Acorn system, say Y to - this option. The driver can handle 1, 2, or 3 port cards. - If unsure, say N - -The Serial Port Dual Serial Port -CONFIG_DUALSP_SERIAL - If you have the Serial Port's dual serial card for an Acorn system, - say Y to this option. If unsure, say N - NetWinder Button CONFIG_NWBUTTON If you enable this driver and create a character device node @@ -10976,8 +11092,7 @@ Support for OPTi MAD16 and/or Mozart based cards CONFIG_SOUND_MAD16 Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi - 82C928 or 82C929 or 82C931) audio interface chip. For the 82C931, - please read drivers/sound/README.C931. These chips are currently + 82C928 or 82C929 or 82C931) audio interface chip. These chips are quite common so it's possible that many no-name cards have one of them. In addition the MAD16 chip is used in some cards made by known manufacturers such as Turtle Beach (Tropez), Reveal (some models) @@ -11377,7 +11492,15 @@ CONFIG_SOUND_MAESTRO Say Y or M if you have a sound system driven by ESS's Maestro line of PCI sound chips. These include the Maestro 1, Maestro 2, and - Maestro 2E. See Documentation/sound/Maestro for more details. + Maestro 2E, but _does not_ include the Maestro 3 and Allegro + line of chips. See Documentation/sound/Maestro for more details + on the 1/2/2e line. + +ESS Maestro3/Allegro sound chipsets +CONFIG_SOUND_MAESTRO3 + Say Y or M if you have a sound system driven by ESS's Maestro3 line + of PCI sound chips. This includes the Allegro sound chip that is + a lighter version of the Maestro3. Are you using a crosscompiler CONFIG_CROSSCOMPILE @@ -11560,6 +11683,10 @@ CONFIG_HISAX_1TR6 Enable this if you have a old german 1TR6 line. +HiSax Support for US NI1 +CONFIG_HISAX_NI1 + Enable this if you like to use ISDN in US on a NI1 basic rate interface. + Teles 16.0/8.0 CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 @@ -11688,6 +11815,13 @@ See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. +NETspider U card +CONFIG_HISAX_NETJET_U + This enables HiSax support for the Netspider U interface ISDN card from + Traverse Technologies. + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + Niccy PnP/PCI card CONFIG_HISAX_NICCY This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. @@ -11776,7 +11910,7 @@ called sc.o. See Documentation/isdn/README.sc and http://www.spellcast.com for more information. -Eicon.Diehl active card support +Eicon active card support CONFIG_ISDN_DRV_EICON Say Y here if you have an Eicon active ISDN card. In order to use this card, additional firmware is necessary, which has to be loaded @@ -11784,6 +11918,16 @@ latest isdn4k-utils package. Please read the file Documentation/isdn/README.eicon for more information. +Eicon legacy driver +CONFIG_ISDN_DRV_EICON_OLD + Say Y here to use your Eicon active ISDN card with ISDN4Linux + isdn module. + +Eicon Diva Server card support +CONFIG_ISDN_DRV_EICON_PCI + Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card. + Please read Documentation/isdn/README.eicon for more information. + Eicon old-type card support CONFIG_ISDN_DRV_EICON_ISA Say Y here if you have an old-type Eicon active ISDN card. In order @@ -11792,6 +11936,14 @@ the latest isdn4k-utils package. Please read the file Documentation/isdn/README.eicon for more information. +Eicon driver type standalone +CONFIG_ISDN_DRV_EICON_DIVAS + Enable this option if you want the eicon driver as standalone + version with no interface to the ISDN4Linux isdn module. If you + say Y here, the eicon module only supports the Diva Server PCI + cards and will provide its own IDI interface. You should say N + here. + Support AT-Fax Class 2 commands CONFIG_ISDN_TTY_FAX If you say Y here, the modem-emulator will support a subset of the @@ -11800,22 +11952,19 @@ an ISDN-fax-machine. This must be supported by the lowlevel driver also. See Documentation/isdn/README.fax for more information. -AVM CAPI2.0 support -CONFIG_ISDN_DRV_AVMB1 - This enables support for the AVM B1/T1 ISDN networking cards.In - addition, a CAPI (Common ISDN Application Programming Interface, a - standard making it easy for programs to access ISDN hardware, see - http://www.capi.org/; to browse the WWW, you need to have access to - a machine on the Internet that has a program like lynx or netscape) - interface for this card is provided. In order to use this card, - additional firmware is necessary, which has to be downloaded into - the card using a utility which is distributed separately. Please - read the file Documentation/isdn/README.avmb1. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called avmb1.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. +CAPI2.0 support +CONFIG_ISDN_CAPI + This option enables a CAPI2.0 (Common ISDN Application Programming + Interface), a standard making it easy for programs to access ISDN + hardware, see http://www.capi.org/ + +CAPI2.0 Middleware support +CONFIG_ISDN_CAPI_MIDDLEWARE + This option enables CAPI2.0 Middleware support + +CAPI2.0 filesystem support +CONFIG_ISDN_CAPIFS + This option enables CAPI CAPI2.0 filesystem support AVM B1 ISA support CONFIG_ISDN_DRV_AVMB1_B1ISA @@ -12764,22 +12913,6 @@ CONFIG_RADIO_ZOLTRIX_PORT Enter the I/O port of your Zoltrix radio card. -ADS Cadet AM/FM Tuner -CONFIG_RADIO_CADET - Say Y here if this is your AM/FM radio card. - - In order to control your radio card, you will need to use programs - that are compatible with the Video for Linux API. Information on - this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, - you need to have access to a machine on the Internet that has a - program like lynx or netscape. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called radio-cadet.o - Miro PCM20 Radio CONFIG_RADIO_MIROPCM20 Choose Y here if you have this FM radio card. You also need to say Y @@ -13086,6 +13219,10 @@ it as a module, say M here and read Documentation/modules.txt. The module will be called +IrDA protocol options +CONFIG_IRDA_OPTIONS + Say Y here if you want to configure any of the following IrDA options. + IrDA Cache last LSAP CONFIG_IRDA_CACHE_LAST_LSAP Say Y here if you want IrLMP to cache the last LSAP used. This makes @@ -13505,6 +13642,20 @@ If you do not have a CompactPCI model CP1400 or CP1500, or another UltraSPARC-IIi-cEngine boardset with digital display, you should say N to this option. + +CP1XXX Hardware Watchdog support +CONFIG_WATCHDOG_CP1XXX + This is the driver for the hardware watchdog timers present on + Sun Microsystems CompactPCI models CP1400 and CP1500. + + 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 cpwatchdog.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + + If you do not have a CompactPCI model CP1400 or CP1500, or + another UltraSPARC-IIi-cEngine boardset with hardware watchdog, + you should say N to this option. # # A couple of things I keep forgetting: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/README.DAC960 linux/Documentation/README.DAC960 --- v2.2.18/Documentation/README.DAC960 Sun Mar 25 11:28:15 2001 +++ linux/Documentation/README.DAC960 Sun Mar 25 11:37:29 2001 @@ -1,17 +1,17 @@ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - Version 2.2.9 for Linux 2.2.17 - Version 2.4.9 for Linux 2.4.0 + Version 2.2.10 for Linux 2.2.18 + Version 2.4.10 for Linux 2.4.1 PRODUCTION RELEASE - 7 September 2000 + 1 February 2001 Leonard N. Zubkoff Dandelion Digital lnz@dandelion.com - Copyright 1998-2000 by Leonard N. Zubkoff + Copyright 1998-2001 by Leonard N. Zubkoff INTRODUCTION @@ -197,19 +197,19 @@ properly initializes the AcceleRAID 250, AcceleRAID 200, AcceleRAID 150, DAC960PJ, and DAC960PG because the Intel i960RD/RP is a multi-function device. If in doubt, contact Mylex RAID Technical Support (support@mylex.com) to verify -compatibility. Mylex makes available a hard disk compatibility list by FTP at -ftp://ftp.mylex.com/pub/dac960/diskcomp.html. +compatibility. Mylex makes available a hard disk compatibility list at +http://www.mylex.com/support/hdcomp/hd-lists.html. DRIVER INSTALLATION -This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0. +This distribution was prepared for Linux kernel version 2.2.18 or 2.4.1. To install the DAC960 RAID driver, you may use the following commands, replacing "/usr/src" with wherever you keep your Linux kernel source tree: cd /usr/src - tar -xvzf DAC960-2.2.9.tar.gz (or DAC960-2.4.9.tar.gz) + tar -xvzf DAC960-2.2.10.tar.gz (or DAC960-2.4.10.tar.gz) mv README.DAC960 linux/Documentation mv DAC960.[ch] linux/drivers/block patch -p0 < DAC960.patch (if DAC960.patch is included) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/SubmittingDrivers linux/Documentation/SubmittingDrivers --- v2.2.18/Documentation/SubmittingDrivers Sun Mar 25 11:28:15 2001 +++ linux/Documentation/SubmittingDrivers Sun Mar 25 11:37:29 2001 @@ -105,7 +105,7 @@ Kernel traffic: Weekly summary of kernel list activity (much easier to read) - [http://kt.linuxcare.com/kernel-traffic] + [http://kt.zork.net/kernel-traffic] Linux USB project: http://sourceforge.net/projects/linux-usb/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt --- v2.2.18/Documentation/binfmt_misc.txt Sun Mar 25 11:13:38 2001 +++ linux/Documentation/binfmt_misc.txt Sun Mar 25 11:37:29 2001 @@ -81,6 +81,6 @@ There is a web page about binfmt_misc at -http://www.anatom.uni-tuebingen.de/~richi/linux/binfmt_misc.html +http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html -Richard Günther, richard.guenther@student.uni-tuebingen.de +Richard Günther diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/devices.txt linux/Documentation/devices.txt --- v2.2.18/Documentation/devices.txt Sun Mar 25 11:13:34 2001 +++ linux/Documentation/devices.txt Sun Mar 25 11:37:29 2001 @@ -1,8 +1,8 @@ LINUX ALLOCATED DEVICES - Maintained by H. Peter Anvin + Maintained by H. Peter Anvin - Last revised: March 23, 2000 + Last revised: December 29, 2000 This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating @@ -37,7 +37,7 @@ reply. - **** PLEASE READ THIS BEFORE SUBMITTING A DEVICE ENTRY **** + **** DEVICE DRIVERS AUTHORS PLEASE READ THIS **** To have a major number allocated, or a minor number in situations where that applies (e.g. busmice), please contact me with the @@ -45,24 +45,32 @@ information regarding any of the devices listed below, or if I have made a mistake, I would greatly appreciate a note. -I do, however, make two requests about the nature of your report. +I do, however, make a few requests about the nature of your report. This is necessary for me to be able to keep this list up to date and -correct in a timely manner. First of all, *please* include the word -"device" in the subject so your mail won't accidentally get buried! I -receive hundreds of email messages a day, so mail sent with other -subjects may very well get lost in the avalanche. +correct in a timely manner. First of all, *please* send it to the +correct address... . I receive hundreds of email +messages a day, so mail sent to other addresses may very well get lost +in the avalanche. Please put in a descriptive subject, so I can find +your mail again should I need to. Too many people send me email +saying just "device number request" in the subject. Second, please include a description of the device *in the same format as this list*. The reason for this is that it is the only way I have found to ensure I have all the requisite information to publish your device and avoid conflicts. +Third, please don't assume that the distributed version of the list is +up to date. Due to the number of registrations I have to maintain it +in "batch mode", so there is likely additional registrations that +haven't been listed yet. + Finally, sometimes I have to play "namespace police." Please don't be offended. I often get submissions for /dev names that would be bound to cause conflicts down the road. I am trying to avoid getting in a situation where we would have to suffer an incompatible forward -change. - +change. Therefore, please consult with me *before* you make your +device names and numbers in any way public, at least to the point +where it would be at all difficult to get them changed. Your cooperation is appreciated. @@ -80,16 +88,18 @@ 7 = /dev/full Returns ENOSPC on write 8 = /dev/random Nondeterministic random number gen. 9 = /dev/urandom Faster, less secure random number gen. + 10 = /dev/aio Asyncronous I/O notification interface block RAM disk 0 = /dev/ram0 First RAM disk + 1 = /dev/ram1 Second RAM disk ... - 7 = /dev/ram7 Eighth RAM disk - 250 = /dev/initrd Initial RAM disk + 250 = /dev/initrd Initial RAM disk {2.6} Older kernels had /dev/ramdisk (1, 1) here. /dev/initrd refers to a RAM disk which was preloaded - by the boot loader. - + by the boot loader; newer kernels use /dev/ram0 for + the initrd. + 2 char Pseudo-TTY masters 0 = /dev/ptyp0 First PTY master 1 = /dev/ptyp1 Second PTY master @@ -200,6 +210,8 @@ ... 255 = /dev/ttyS191 192nd UART serial port + UART serial ports refer to 8250/16450/16550 series devices. + Older versions of the Linux kernel used this major number for BSD PTY devices. As of Linux 2.1.115, this is no longer supported. Use major numbers 2 and 3. @@ -311,6 +323,8 @@ 10 = /dev/adbmouse Apple Desktop Bus mouse 11 = /dev/vrtpanel Vr41xx embedded touch panel 13 = /dev/vpcmouse Connectix Virtual PC Mouse + 14 = /dev/touchscreen/ucb1x00 UCB 1x00 touchscreen + 15 = /dev/touchscreen/mk712 MK712 touchscreen 128 = /dev/beep Fancy beep device 129 = /dev/modreq Kernel module load request {2.6} 130 = /dev/watchdog Watchdog timer port @@ -322,7 +336,7 @@ 139 = /dev/openprom SPARC OpenBoot PROM 140 = /dev/relay8 Berkshire Products Octal relay card 141 = /dev/relay16 Berkshire Products ISO-16 relay card - 142 = /dev/msr x86 model-specific registers + 142 = /dev/msr x86 model-specific registers {2.6} 143 = /dev/pciconf PCI configuration space 144 = /dev/nvram Non-volatile configuration RAM 145 = /dev/hfmodem Soundcard shortwave modem control {2.6} @@ -364,6 +378,26 @@ 182 = /dev/perfctr Performance-monitoring counters 183 = /dev/intel_rng Intel i8x0 random number generator 184 = /dev/cpu/microcode CPU microcode update interface + 186 = /dev/atomicps Atomic shapshot of process state data + 187 = /dev/irnet IrNET device + 188 = /dev/smbusbios SMBus BIOS + 189 = /dev/ussp_ctl User space serial port control + 190 = /dev/crash Mission Critical Linux crash dump facility + 191 = /dev/pcl181 + 192 = /dev/nas_xbus NAS xbus LCD/buttons access + 193 = /dev/d7s SPARC 7-segment display + 194 = /dev/zkshim Zero-Knowledge network shim control + 195 = /dev/elographics/e2201 Elographics touchscreen E271-2201 + 198 = /dev/sexec Signed executable interface + 199 = /dev/scanners/cuecat :CueCat barcode scanner + 200 = /dev/net/tun TAP/TUN network device + 201 = /dev/button/gulpb Transmeta GULP-B buttons + 204 = /dev/video/em8300 EM8300 DVD decoder control + 205 = /dev/video/em8300_mv EM8300 DVD decoder video + 206 = /dev/video/em8300_ma EM8300 DVD decoder audio + 207 = /dev/video/em8300_sp EM8300 DVD decoder subpicture + 208 = /dev/compaq/cpqphpc Compaq PCI Hot Plug Controller + 209 = /dev/compaq/cpqrid Compaq Remote Insight Driver 240-255 Reserved for local use 11 char Raw keyboard device @@ -902,29 +936,62 @@ 0 = /dev/ttyL0 First RISCom port 1 = /dev/ttyL1 Second RISCom port ... - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; first controller + 0 = /dev/rd/c0d0 First disk, whole disk + 8 = /dev/rd/c0d1 Second disk, whole disk + ... + 248 = /dev/rd/c0d15 16th disk, whole disk + + For partitions add: + 0 = /dev/rd/c?d? Whole disk + 1 = /dev/rd/c?d?p1 First partition + ... + 7 = /dev/rd/c?d?p7 Seventh partition 49 char SDL RISCom serial card - alternate devices 0 = /dev/cul0 Callout device for ttyL0 1 = /dev/cul1 Callout device for ttyL1 ... - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; second controller + 0 = /dev/rd/c1d0 First disk, whole disk + 8 = /dev/rd/c1d1 Second disk, whole disk + ... + 248 = /dev/rd/c1d15 16th disk, whole disk + + Partitions are handled as for major 48. 50 char Reserved for GLINT - block Reserved for Mylex DAC960 PCI RAID controller + + block Mylex DAC960 PCI RAID controller; third controller + 0 = /dev/rd/c2d0 First disk, whole disk + 8 = /dev/rd/c2d1 Second disk, whole disk + ... + 248 = /dev/rd/c2d15 16th disk, whole disk 51 char Baycom radio modem 0 = /dev/bc0 First Baycom radio modem 1 = /dev/bc1 Second Baycom radio modem ... - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; fourth controller + 0 = /dev/rd/c3d0 First disk, whole disk + 8 = /dev/rd/c3d1 Second disk, whole disk + ... + 248 = /dev/rd/c3d15 16th disk, whole disk + + Partitions are handled as for major 48. 52 char Spellcaster DataComm/BRI ISDN card 0 = /dev/dcbri0 First DataComm card 1 = /dev/dcbri1 Second DataComm card 2 = /dev/dcbri2 Third DataComm card 3 = /dev/dcbri3 Fourth DataComm card - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; fifth controller + 0 = /dev/rd/c4d0 First disk, whole disk + 8 = /dev/rd/c4d1 Second disk, whole disk + ... + 248 = /dev/rd/c4d15 16th disk, whole disk + + Partitions are handled as for major 48. 53 char BDM interface for remote debugging MC683xx microcontrollers 0 = /dev/pd_bdm0 PD BDM interface on lp0 @@ -940,7 +1007,13 @@ Domain Interface and ICD is the commercial interface by P&E. - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; sixth controller + 0 = /dev/rd/c5d0 First disk, whole disk + 8 = /dev/rd/c5d1 Second disk, whole disk + ... + 248 = /dev/rd/c5d15 16th disk, whole disk + + Partitions are handled as for major 48. 54 char Electrocardiognosis Holter serial card 0 = /dev/holter0 First Holter port @@ -951,11 +1024,23 @@ to transfer data from Holter 24-hour heart monitoring equipment. - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; seventh controller + 0 = /dev/rd/c6d0 First disk, whole disk + 8 = /dev/rd/c6d1 Second disk, whole disk + ... + 248 = /dev/rd/c6d15 16th disk, whole disk + + Partitions are handled as for major 48. 55 char DSP56001 digital signal processor 0 = /dev/dsp56k First DSP56001 - block Reserved for Mylex DAC960 PCI RAID controller + block Mylex DAC960 PCI RAID controller; eigth controller + 0 = /dev/rd/c7d0 First disk, whole disk + 8 = /dev/rd/c7d1 Second disk, whole disk + ... + 248 = /dev/rd/c7d15 16th disk, whole disk + + Partitions are handled as for major 48. 56 char Apple Desktop Bus 0 = /dev/adb ADB bus control @@ -1002,6 +1087,8 @@ running small fs translation drivers) through serial / IRDA / parallel links. + NAMING CONFLICT -- PROPOSED REVISED NAME /dev/rpda0 etc + 60-63 LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not assigned official numbers, these ranges should be @@ -1176,6 +1263,16 @@ ... 255 = /dev/cuf255 Callout device for ttyF255 + block Compaq Intelligent Drive Array, first controller + 0 = /dev/ida/c0d0 First logical drive whole disk + 16 = /dev/ida/c0d1 Second logical drive whole disk + ... + 240 = /dev/ida/c0d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 73 char Computone IntelliPort II serial card - control devices 0 = /dev/ip2ipl0 Loadware device for board 0 1 = /dev/ip2stat0 Status device for board 0 @@ -1186,6 +1283,16 @@ 12 = /dev/ip2ipl3 Loadware device for board 3 13 = /dev/ip2stat3 Status device for board 3 + block Compaq Intelligent Drive Array, second controller + 0 = /dev/ida/c1d0 First logical drive whole disk + 16 = /dev/ida/c1d1 Second logical drive whole disk + ... + 240 = /dev/ida/c1d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 74 char SCI bridge 0 = /dev/SCI/0 SCI device 0 1 = /dev/SCI/1 SCI device 1 @@ -1194,6 +1301,16 @@ Currently for Dolphin Interconnect Solutions' PCI-SCI bridge. + block Compaq Intelligent Drive Array, third controller + 0 = /dev/ida/c2d0 First logical drive whole disk + 16 = /dev/ida/c2d1 Second logical drive whole disk + ... + 240 = /dev/ida/c2d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 75 char Specialix IO8+ serial card 0 = /dev/ttyW0 First IO8+ port, first card 1 = /dev/ttyW1 Second IO8+ port, first card @@ -1201,6 +1318,16 @@ 8 = /dev/ttyW8 First IO8+ port, second card ... + block Compaq Intelligent Drive Array, fourth controller + 0 = /dev/ida/c3d0 First logical drive whole disk + 16 = /dev/ida/c3d1 Second logical drive whole disk + ... + 240 = /dev/ida/c3d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 76 char Specialix IO8+ serial card - alternate devices 0 = /dev/cuw0 Callout device for ttyW0 1 = /dev/cuw1 Callout device for ttyW1 @@ -1208,19 +1335,63 @@ 8 = /dev/cuw8 Callout device for ttyW8 ... + block Compaq Intelligent Drive Array, fifth controller + 0 = /dev/ida/c4d0 First logical drive whole disk + 16 = /dev/ida/c4d1 Second logical drive whole disk + ... + 240 = /dev/ida/c4d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 77 char ComScire Quantum Noise Generator 0 = /dev/qng ComScire Quantum Noise Generator + block Compaq Intelligent Drive Array, sixth controller + 0 = /dev/ida/c5d0 First logical drive whole disk + 16 = /dev/ida/c5d1 Second logical drive whole disk + ... + 240 = /dev/ida/c5d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 78 char PAM Software's multimodem boards 0 = /dev/ttyM0 First PAM modem 1 = /dev/ttyM1 Second PAM modem ... + block Compaq Intelligent Drive Array, seventh controller + 0 = /dev/ida/c6d0 First logical drive whole disk + 16 = /dev/ida/c6d1 Second logical drive whole disk + ... + 240 = /dev/ida/c6d15 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 79 char PAM Software's multimodem boards - alternate devices 0 = /dev/cum0 Callout device for ttyM0 1 = /dev/cum1 Callout device for ttyM1 ... + block Compaq Intelligent Drive Array, eigth controller + 0 = /dev/ida/c7d0 First logical drive whole disk + 16 = /dev/ida/c7d1 Second logical drive whole disk + ... + 240 = /dev/ida/c715 16th logical drive whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + + 80 char Photometrics AT200 CCD camera 0 = /dev/at200 Photometrics AT200 CCD camera @@ -1497,14 +1668,13 @@ 1 = /dev/parport1 Second parallel port ... -100 char POTS (analogue telephone) A/B port {2.6} - 0 = /dev/phone0 First telephone port - 1 = /dev/phone1 Second telephone port - ... + block JavaStation flash disk + 0 = /dev/jsfd JavaStation flash disk - The names have been reallocated to Telephony For - Linux, major 159. All use of major 100 should be - considered legacy and deprecated. +100 char Telephony for Linux + 0 = /dev/phone0 First telephony device + 1 = /dev/phone1 Second telephony device + ... 101 char Motorola DSP 56xxx board 0 = /dev/mdspstat Status information @@ -1512,6 +1682,19 @@ ... 16 = /dev/mdsp16 16th DSP board I/O controls + block AMI HyperDisk RAID controller + 0 = /dev/amiraid/ar0 First array whole disk + 16 = /dev/amiraid/ar1 Second array whole disk + ... + 240 = /dev/amiraid/ar15 16th array whole disk + + For each device, partitions are added as: + 0 = /dev/amiraid/ar? Whole disk + 1 = /dev/amiraid/ar?p1 First partition + 2 = /dev/amiraid/ar?p2 Second partition + ... + 15 = /dev/amiraid/ar?p15 15th partition + 102 char Philips SAA5249 Teletext signal decoder {2.6} 0 = /dev/tlk0 First Teletext decoder 1 = /dev/tlk1 Second Teletext decoder @@ -1528,36 +1711,119 @@ to the arla announce mailing list by sending a mail to . + block Audit device + 0 = /dev/audit Audit device + 104 char Flash BIOS support + block Compaq Next Generation Drive Array, first controller + 0 = /dev/cciss/c0d0 First logical drive, whole disk + 16 = /dev/cciss/c0d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c0d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 105 char Comtrol VS-1000 serial controller 0 = /dev/ttyV0 First VS-1000 port 1 = /dev/ttyV1 Second VS-1000 port ... + block Compaq Next Generation Drive Array, second controller + 0 = /dev/cciss/c1d0 First logical drive, whole disk + 16 = /dev/cciss/c1d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c1d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 106 char Comtrol VS-1000 serial controller - alternate devices 0 = /dev/cuv0 First VS-1000 port 1 = /dev/cuv1 Second VS-1000 port ... + block Compaq Next Generation Drive Array, third controller + 0 = /dev/cciss/c2d0 First logical drive, whole disk + 16 = /dev/cciss/c2d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c2d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 107 char 3Dfx Voodoo Graphics device 0 = /dev/3dfx Primary 3Dfx graphics device + block Compaq Next Generation Drive Array, fourth controller + 0 = /dev/cciss/c3d0 First logical drive, whole disk + 16 = /dev/cciss/c3d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c3d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 108 char Device independent PPP interface 0 = /dev/ppp Device independent PPP interface + block Compaq Next Generation Drive Array, fifth controller + 0 = /dev/cciss/c4d0 First logical drive, whole disk + 16 = /dev/cciss/c4d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c4d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 109 char Reserved for logical volume manager + block Compaq Next Generation Drive Array, sixth controller + 0 = /dev/cciss/c5d0 First logical drive, whole disk + 16 = /dev/cciss/c5d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c5d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 110 char miroMEDIA Surround board 0 = /dev/srnd0 First miroMEDIA Surround board 1 = /dev/srnd1 Second miroMEDIA Surround board ... + block Compaq Next Generation Drive Array, seventh controller + 0 = /dev/cciss/c6d0 First logical drive, whole disk + 16 = /dev/cciss/c6d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c6d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 111 char Philips SAA7146-based audio/video card {2.6} 0 = /dev/av0 First A/V card 1 = /dev/av1 Second A/V card ... + block Compaq Next Generation Drive Array, eigth controller + 0 = /dev/cciss/c7d0 First logical drive, whole disk + 16 = /dev/cciss/c7d1 Second logical drive, whole disk + ... + 240 = /dev/cciss/c7d15 16th logical drive, whole disk + + Partitions are handled the same way as for Mylex + DAC960 (see major number 48) except that the limit on + partitions is 15. + 112 char ISI serial card 0 = /dev/ttyM0 First ISI port 1 = /dev/ttyM1 Second ISI port @@ -1718,10 +1984,7 @@ 1 = /dev/gfax1 GammaLink channel 1 ... -159 char Telephony for Linux - 0 = /dev/phone0 First telephony device - 1 = /dev/phone1 Second telephony device - ... +159 RESERVED 160 char General Purpose Instrument Bus (GPIB) 0 = /dev/gpib0 First GPIB bus @@ -1945,7 +2208,244 @@ 240 = /dev/mvideo/status15 16th device ... -195-239 UNALLOCATED +195 char Nvidia graphics devices + 0 = /dev/nvidia0 First Nvidia card + 1 = /dev/nvidia1 Second Nvidia card + ... + 255 = /dev/nvidiactl Nvidia card control device + +196-197 UNASSIGNED + +198 char Total Impact TPMP2 quad coprocessor PCI card + 0 = /dev/tpmp2/0 First card + 1 = /dev/tpmp2/1 Second card + ... + +199 char Veritas volume manager (VxVM) volumes + 0 = /dev/vx/rdsk/*/* First volume + 1 = /dev/vx/rdsk/*/* Second volume + ... + block Veritas volume manager (VxVM) volumes + 0 = /dev/vx/dsk/*/* First volume + 1 = /dev/vx/dsk/*/* First volume + ... + + The namespace in these directories is maintained by + the user space VxVM software. + +200 char Veritas VxVM configuration interface + 0 = /dev/vx/config Configuration access node + 1 = /dev/vx/trace Volume i/o trace access node + 2 = /dev/vx/iod Volume i/o daemon access node + 3 = /dev/vx/info Volume information access node + 4 = /dev/vx/task Volume tasks access node + 5 = /dev/vx/taskmon Volume tasks monitor daemon + +201 char Veritas VxVM dynamic multipathing driver + 0 = /dev/vx/rdmp/* First multipath device + 1 = /dev/vx/rdmp/* Second multipath device + ... + block Veritas VxVM dynamic multipathing driver + 0 = /dev/vx/dmp/* First multipath device + 1 = /dev/vx/dmp/* Second multipath device + ... + + The namespace in these directories is maintained by + the user space VxVM software. + +202 char CPU model-specific registers + 0 = /dev/cpu/0/msr MSRs on CPU 0 + 1 = /dev/cpu/1/msr MSRs on CPU 1 + ... + +203 char CPU CPUID information + 0 = /dev/cpu/0/cpuid CPUID on CPU 0 + 1 = /dev/cpu/1/cpuid CPUID on CPU 1 + ... + +204 char Low-density serial ports + 0 = /dev/ttyLU0 LinkUp Systems L72xx UART - port 0 + 1 = /dev/ttyLU1 LinkUp Systems L72xx UART - port 1 + 2 = /dev/ttyLU2 LinkUp Systems L72xx UART - port 2 + 3 = /dev/ttyLU3 LinkUp Systems L72xx UART - port 3 + 4 = /dev/ttyFB0 Intel Footbridge (ARM) + 5 = /dev/ttySA0 StrongARM builtin serial port 0 + 6 = /dev/ttySA1 StrongARM builtin serial port 1 + 7 = /dev/ttySA2 StrongARM builtin serial port 2 + 8 = /dev/ttySC0 SCI serial port (SuperH) - port 0 + 9 = /dev/ttySC1 SCI serial port (SuperH) - port 1 + 10 = /dev/ttySC2 SCI serial port (SuperH) - port 2 + 11 = /dev/ttySC3 SCI serial port (SuperH) - port 3 + 12 = /dev/ttyFW0 Firmware console - port 0 + 13 = /dev/ttyFW1 Firmware console - port 1 + 14 = /dev/ttyFW2 Firmware console - port 2 + 15 = /dev/ttyFW3 Firmware console - port 3 + 16 = /dev/ttyAM0 ARM "AMBA" serial port 0 + ... + 31 = /dev/ttyAM15 ARM "AMBA" serial port 15 + +205 char Low-density serial ports (alternate device) + 0 = /dev/culu0 Callout device for ttyLU0 + 1 = /dev/culu1 Callout device for ttyLU1 + 2 = /dev/culu2 Callout device for ttyLU2 + 3 = /dev/culu3 Callout device for ttyLU3 + 4 = /dev/cufb0 Callout device for ttyFB0 + 5 = /dev/cusa0 Callout device for ttySA0 + 6 = /dev/cusa1 Callout device for ttySA1 + 7 = /dev/cusa2 Callout device for ttySA2 + 8 = /dev/cusc0 Callout device for ttySC0 + 9 = /dev/cusc1 Callout device for ttySC1 + 10 = /dev/cusc2 Callout device for ttySC2 + 11 = /dev/cusc3 Callout device for ttySC3 + 12 = /dev/cufw0 Callout device for ttyFW0 + 13 = /dev/cufw1 Callout device for ttyFW1 + 14 = /dev/cufw2 Callout device for ttyFW2 + 15 = /dev/cufw3 Callout device for ttyFW3 + 16 = /dev/cuam0 Callout device for ttyAM0 + ... + 31 = /dev/cuam15 Callout device for ttyAM15 + +206 char OnStream SC-x0 tape devices + 0 = /dev/osst0 First OnStream SCSI tape, mode 0 + 1 = /dev/osst1 Second OnStream SCSI tape, mode 0 + ... + 32 = /dev/osst0l First OnStream SCSI tape, mode 1 + 33 = /dev/osst1l Second OnStream SCSI tape, mode 1 + ... + 64 = /dev/osst0m First OnStream SCSI tape, mode 2 + 65 = /dev/osst1m Second OnStream SCSI tape, mode 2 + ... + 96 = /dev/osst0a First OnStream SCSI tape, mode 3 + 97 = /dev/osst1a Second OnStream SCSI tape, mode 3 + ... + 128 = /dev/nosst0 No rewind version of /dev/osst0 + 129 = /dev/nosst1 No rewind version of /dev/osst1 + ... + 160 = /dev/nosst0l No rewind version of /dev/osst0l + 161 = /dev/nosst1l No rewind version of /dev/osst1l + ... + 192 = /dev/nosst0m No rewind version of /dev/osst0m + 193 = /dev/nosst1m No rewind version of /dev/osst1m + ... + 224 = /dev/nosst0a No rewind version of /dev/osst0a + 225 = /dev/nosst1a No rewind version of /dev/osst1a + ... + + The OnStream SC-x0 SCSI tapes do not support the + standard SCSI SASD command set and therefore need + their own driver "osst". Note that the IDE, USB (and + maybe ParPort) versions may be driven via ide-scsi or + usb-storage SCSI emulation and this osst device and + driver as well. The ADR-x0 drives are QIC-157 + compliant and don't need osst. + +207 char Compaq ProLiant health feature indicate + 0 = /dev/cpqhealth/cpqw Redirector interface + 1 = /dev/cpqhealth/crom EISA CROM + 2 = /dev/cpqhealth/cdt Data Table + 3 = /dev/cpqhealth/cevt Event Log + 4 = /dev/cpqhealth/casr Automatic Server Recovery + 5 = /dev/cpqhealth/cecc ECC Memory + 6 = /dev/cpqhealth/cmca Machine Check Architecture + 7 = /dev/cpqhealth/ccsm Deprecated CDT + 8 = /dev/cpqhealth/cnmi NMI Handling + 9 = /dev/cpqhealth/css Sideshow Management + 10 = /dev/cpqhealth/cram CMOS interface + 11 = /dev/cpqhealth/cpci PCI IRQ interface + +208 char User space serial ports + 0 = /dev/ttyU0 First user space serial port + 1 = /dev/ttyU1 Second user space serial port + ... + +209 char User space serial ports (alternate devices) + 0 = /dev/cuu0 Callout device for ttyU0 + 1 = /dev/cuu1 Callout device for ttyU1 + ... + +210 char SBE, Inc. sync/async serial card + 0 = /dev/sbei/wxcfg0 Configuration device for board 0 + 1 = /dev/sbei/dld0 Download device for board 0 + 2 = /dev/sbei/wan00 WAN device, port 0, board 0 + 3 = /dev/sbei/wan01 WAN device, port 1, board 0 + 4 = /dev/sbei/wan02 WAN device, port 2, board 0 + 5 = /dev/sbei/wan03 WAN device, port 3, board 0 + 6 = /dev/sbei/wanc00 WAN clone device, port 0, board 0 + 7 = /dev/sbei/wanc01 WAN clone device, port 1, board 0 + 8 = /dev/sbei/wanc02 WAN clone device, port 2, board 0 + 9 = /dev/sbei/wanc03 WAN clone device, port 3, board 0 + 10 = /dev/sbei/wxcfg1 Configuration device for board 1 + 11 = /dev/sbei/dld1 Download device for board 1 + 12 = /dev/sbei/wan10 WAN device, port 0, board 1 + 13 = /dev/sbei/wan11 WAN device, port 1, board 1 + 14 = /dev/sbei/wan12 WAN device, port 2, board 1 + 15 = /dev/sbei/wan13 WAN device, port 3, board 1 + 16 = /dev/sbei/wanc10 WAN clone device, port 0, board 1 + 17 = /dev/sbei/wanc11 WAN clone device, port 1, board 1 + 18 = /dev/sbei/wanc12 WAN clone device, port 2, board 1 + 19 = /dev/sbei/wanc13 WAN clone device, port 3, board 1 + ... + + Yes, each board is really spaced 10 (decimal) apart. + +211 char Addinum CPCI1500 digital I/O card + 0 = /dev/addinum/cpci1500/0 First CPCI1500 card + 1 = /dev/addinum/cpci1500/1 Second CPCI1500 card + ... + +216 char USB BlueTooth devices + 0 = /dev/ttyUB0 First USB BlueTooth device + 1 = /dev/ttyUB1 Second USB BlueTooth device + ... + +217 char USB BlueTooth devices (alternate devices) + 0 = /dev/cuub0 Callout device for ttyUB0 + 1 = /dev/cuub1 Callout device for ttyUB1 + ... + +218 char The Logical Company bus Unibus/Qbus adapters + 0 = /dev/logicalco/bci/0 First bus adapter + 1 = /dev/logicalco/bci/1 First bus adapter + ... + +219 char The Logical Company DCI-1300 digital I/O card + 0 = /dev/logicalco/dci1300/0 First DCI-1300 card + 1 = /dev/logicalco/dci1300/1 Second DCI-1300 card + ... + +220 char Myricom Myrinet "GM" board + 0 = /dev/myricom/gm0 First Myrinet GM board + 1 = /dev/myricom/gmp0 First board "root access" + 2 = /dev/myricom/gm1 Second Myrinet GM board + 3 = /dev/myricom/gmp1 Second board "root access" + ... + +221 char VME bus + 0 = /dev/bus/vme/m0 First master image + 1 = /dev/bus/vme/m1 Second master image + 2 = /dev/bus/vme/m2 Third master image + 3 = /dev/bus/vme/m3 Fourth master image + 4 = /dev/bus/vme/s0 First slave image + 5 = /dev/bus/vme/s1 Second slave image + 6 = /dev/bus/vme/s2 Third slave image + 7 = /dev/bus/vme/s3 Fourth slave image + 8 = /dev/bus/vme/ctl Control + + It is expected that all VME bus drivers will use the + same interface. For interface documentation see + http://www.vmelinux.org/. + +224 char A2232 serial card + 0 = /dev/ttyY0 First A2232 port + 1 = /dev/cuy0 Second A2232 port + ... + +225 char A2232 serial card (alternate devices) + 0 = /dev/cuy0 Callout device for ttyY0 + 1 = /dev/cuy1 Callout device for ttyY1 + ... + +226-239 UNASSIGNED 240-254 LOCAL/EXPERIMENTAL USE @@ -2026,6 +2526,14 @@ /dev/log socket syslog local socket /dev/gpmdata socket gpm mouse multiplexer + Mount points + +The following names are reserved for mounting special filesystems +under /dev. These special filesystems provide kernel interfaces that +cannot be provided with standard device nodes. + +/dev/pts devpts PTY slave filesystem +/dev/shm shmfs POSIX shared memory maintenance access **** TERMINAL DEVICES diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/filesystems/minix-part.txt linux/Documentation/filesystems/minix-part.txt --- v2.2.18/Documentation/filesystems/minix-part.txt Wed Dec 31 19:00:00 1969 +++ linux/Documentation/filesystems/minix-part.txt Sun Mar 25 11:37:29 2001 @@ -0,0 +1,43 @@ +Minix 2.0.0/2.0.2 subpartition support. +======================================= + + Minix subpartition support is provided in `linux/drivers/block/genhd.c'. +Minix partitions are shown with the device name suffixed with an `@' +followed by any detected subpartitions inside angle brackets, like this: + +Partition check: + hda: hda1 hda2@ < hda5 hda6 > hda3 hda4 + +Usage +===== + +Add entries to /etc/fstab, change for your setup: + /dev/hda5 /mnt/minix minix rw,noauto 0 0 + /dev/hda6 /mnt/minix/usr minix rw,noauto 0 0 + +To mount your Minix filesystems: + mount /mnt/minix # mount / + mount /mnt/minix/usr # mount /usr + + +Note +==== + +The first sector of a Minix 2.0.0/2.0.2 partition containing +subpartitions looks like the master boot record (MBR) on the first +sector of the hard disk. + +It has + 1) a small loader program which loads the boot sector from + the Minix root partition (usually hd?a). + 2) a small partition table which gives the starting + C/H/S values and sizes for the 4 Minix subpartitions. + +If there are no subpartitions then the first sector of the Minix +partition contains the usual boot sector. + +Bug Reports +=========== + +Anand Krishnamurthy +Rajeev V. Pillai diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.2.18/Documentation/ioctl-number.txt Sun Mar 25 11:28:15 2001 +++ linux/Documentation/ioctl-number.txt Sun Mar 25 11:37:29 2001 @@ -66,6 +66,7 @@ 0x22 all scsi/sg.h 'A' all linux/apm_bios.h 'C' all linux/soundcard.h +'D' all asm-s390/dasd.h 'F' all linux/fb.h 'I' all linux/isdn.h 'K' all linux/kd.h @@ -113,6 +114,8 @@ 'z' 40-7F CAN bas card in development: +'6' 00-10 Intel IA32 microcode update driver + 0x89 00-0F asm-i386/sockios.h 0x89 10-DF linux/sockios.h 0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/isdn/00-INDEX linux/Documentation/isdn/00-INDEX --- v2.2.18/Documentation/isdn/00-INDEX Sun Mar 25 11:28:15 2001 +++ linux/Documentation/isdn/00-INDEX Sun Mar 25 11:37:29 2001 @@ -38,3 +38,6 @@ - info on driver for Spellcaster cards. README.x25 _ info for running X.25 over ISDN. +README.hysdn + - info on driver for Hypercope active HYSDN cards + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.2.18/Documentation/isdn/README.HiSax Sun Mar 25 11:28:15 2001 +++ linux/Documentation/isdn/README.HiSax Sun Mar 25 11:37:29 2001 @@ -53,7 +53,8 @@ Sedlbauer ISDN-Controller PC/104 USR Sportster internal TA (compatible Stollmann tina-pp V3) ith Kommunikationstechnik GmbH MIC 16 ISA card -Traverse Technologie NETjet PCI S0 card +Traverse Technologie NETjet PCI S0 card and NETspider U card +Ovislink ISDN sc100-p card (NETjet driver) Dr. Neuhaus Niccy PnP/PCI Siemens I-Surf 1.0 Siemens I-Surf 2.0 (with IPAC, try type 12 asuscom) @@ -134,7 +135,12 @@ The parameter for the D-Channel protocol may be omitted if you selected the correct one during kernel config. Valid values are "1" for German 1TR6, -"2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel). +"2" for EDSS1 (Euro ISDN), "3" for leased lines (no D-Channel) and "4" +for US NI1. +With US NI1 you have to include your SPID into the MSN setting in the form +: for example (your phonenumber is 1234 your SPID 5678): +AT&E1234:5678 on ttyI interfaces +isdnctrl eaz ippp0 1234:5678 on network devices The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying the I/O addresses of the ISAC and HSCX chips, respectively. @@ -186,8 +192,9 @@ 34 Gazel ISDN cards (PCI) none 35 HFC 2BDS0 PCI none 36 W6692 based PCI cards none - 37 HFC 2BDS0 S+, SP/PCMCIA irq,io (pcmcia must be set with cardmgr) - + 37 HFC 2BDS0 S+, SP irq,io + 38 NETspider U PCI card none + 39 HFC 2BDS0 SP/PCMCIA irq,io (set with cardmgr) At the moment IRQ sharing is only possible with PCI cards. Please make sure that your IRQ is free and enabled for ISA use. @@ -291,7 +298,9 @@ 34 Gazel ISDN cards (PCI) no parameter 35 HFC 2BDS0 PCI no parameter 36 W6692 based PCI cards none - 37 HFC 2BDS0 S+,SP/PCMCIA pa=irq, pb=io + 37 HFC 2BDS0 S+,SP/PCMCIA ONLY WORKS AS A MODULE ! + 38 NETspider U PCI card none + Running the driver ------------------ @@ -433,6 +442,7 @@ Enrik Berkhan (enrik@starfleet.inka.de) for S0BOX specific stuff Ton van Rosmalen for Teles PCI Petr Novak for Winbond W6692 support + Werner Cornelius for HFC-PCI, HFC-S(+/P) and supplementary services support and more people who are hunting bugs. (If I forgot somebody, please send me a mail). diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/isdn/README.diversion linux/Documentation/isdn/README.diversion --- v2.2.18/Documentation/isdn/README.diversion Sun Mar 25 11:28:15 2001 +++ linux/Documentation/isdn/README.diversion Sun Mar 25 11:37:29 2001 @@ -6,7 +6,7 @@ the HiSax driver. The diversion kernel interface and controlling tool divertctrl were written by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) under the -GNU Public License. +GNU General Public License. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon --- v2.2.18/Documentation/isdn/README.eicon Sun Mar 25 11:13:36 2001 +++ linux/Documentation/isdn/README.eicon Sun Mar 25 11:37:29 2001 @@ -1,4 +1,4 @@ -$Id: README.eicon,v 1.6 2000/01/27 09:54:44 armin Exp $ +$Id: README.eicon,v 1.10 2000/08/13 12:19:15 armin Exp $ (c) 1999,2000 Armin Schindler (mac@melware.de) (c) 1999,2000 Cytronics & Melware (info@melware.de) @@ -40,6 +40,7 @@ ------------------ - DIVA Server BRI/PCI 2M - DIVA Server PRI/PCI 2M (9M 23M 30M) +- DIVA Server 4BRI/PCI supported functions of onboard DSPs: - analog modem - fax group 2/3 (Fax Class 2 commands) @@ -78,6 +79,10 @@ eiconctrl [-d DriverId] load etsi +Example for a BRI card with E-DSS1 Protocol with PtP configuration. + + eiconctrl [-d DriverId] load etsi -n -t1 -s1 + Example for loading and starting a PRI card with E-DSS1 Protocol. @@ -95,6 +100,7 @@ the necessary D-Channel traces for isdnlog. + Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH for sponsoring and testing fax @@ -109,3 +115,4 @@ Armin Schindler mac@melware.de http://www.melware.de + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/isdn/README.fax linux/Documentation/isdn/README.fax --- v2.2.18/Documentation/isdn/README.fax Sun Mar 25 11:13:36 2001 +++ linux/Documentation/isdn/README.fax Sun Mar 25 11:37:29 2001 @@ -24,6 +24,9 @@ Eicon DIVA Server BRI/PCI - full support with both B-channels. +Eicon DIVA Server 4BRI/PCI + - full support with all B-channels. + Eicon DIVA Server PRI/PCI - full support on amount of B-channels depending on DSPs on board. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/isdn/README.hfc-pci linux/Documentation/isdn/README.hfc-pci --- v2.2.18/Documentation/isdn/README.hfc-pci Sun Mar 25 11:13:36 2001 +++ linux/Documentation/isdn/README.hfc-pci Sun Mar 25 11:37:29 2001 @@ -35,7 +35,7 @@ supplied else the parameter is assumed 0 and a auto search for a free card is invoked which may not give the wanted result. -Comments and reports to werner@isdn4linux.de or werner@titro.de . +Comments and reports to werner@isdn4linux.de or werner@isdn-development.de diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/isdn/README.hysdn linux/Documentation/isdn/README.hysdn --- v2.2.18/Documentation/isdn/README.hysdn Wed Dec 31 19:00:00 1969 +++ linux/Documentation/isdn/README.hysdn Sun Mar 25 11:37:29 2001 @@ -0,0 +1,195 @@ +$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $ +The hysdn driver has been written by +by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) +for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver +under the GNU General Public License. + +The CAPI 2.0-support was added by Ulrich Albrecht (ualbrecht@hypercope.de) +for Hypercope GmbH Aachen, Germany. + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Table of contents +================= + +1. About the driver + +2. Loading/Unloading the driver + +3. Entries in the /proc filesystem + +4. The /proc/net/hysdn/cardconfX file + +5. The /proc/net/hysdn/cardlogX file + +6. Where to get additional info and help + + +1. About the driver + + The drivers/isdn/hysdn subdir contains a driver for HYPERCOPEs active + PCI isdn cards Champ, Ergo and Metro. To enable support for this cards + enable ISDN support in the kernel config and support for HYSDN cards in + the active cards submenu. The driver may only be compiled and used if + support for loadable modules and the process filesystem have been enabled. + + These cards provide two different interfaces to the kernel. Without the + optional CAPI 2.0 support, they register as ethernet card. IP-routing + to a ISDN-destination is performed on the card itself. All necessary + handlers for various protocols like ppp and others as well as config info + and firmware may be fetched from Hypercopes WWW-Site www.hypercope.de. + + With CAPI 2.0 support enabled, the card can also be used as a CAPI 2.0 + compliant devices with either CAPI 2.0 applications + (check isdn4k-utils) or -using the capidrv module- as a regular + isdn4linux device. This is done via the same mechanism as with the + active AVM cards and in fact uses the same module. + + +2. Loading/Unloading the driver + + The module has no command line parameters and auto detects up to 10 cards + in the id-range 0-9. + If a loaded driver shall be unloaded all open files in the /proc/net/hysdn + subdir need to be closed and all ethernet interfaces allocated by this + driver must be shut down. Otherwise the module counter will avoid a module + unload. + + If you are using the CAPI 2.0-interface, make sure to load/modprobe the + kernelcapi-module first. + + If you plan to use the capidrv-link to isdn4linux, make sure to load + capidrv.o after all modules using this driver (i.e. after hysdn and + any avm-specific modules). + +3. Entries in the /proc filesystem + + When the module has been loaded it adds the directory hysdn in the + /proc/net tree. This directory contains exactly 2 file entries for each + card. One is called cardconfX and the other cardlogX, where X is the + card id number from 0 to 9. + The cards are numbered in the order found in the PCI config data. + +4. The /proc/net/hysdn/cardconfX file + + This file may be read to get by everyone to get info about the cards type, + actual state, available features and used resources. + The first 3 entries (id, bus and slot) are PCI info fields, the following + type field gives the information about the cards type: + + 4 -> Ergo card (server card with 2 b-chans) + 5 -> Metro card (server card with 4 or 8 b-chans) + 6 -> Champ card (client card with 2 b-chans) + + The following 3 fields show the hardware assignments for irq, iobase and the + dual ported memory (dp-mem). + The fields b-chans and fax-chans announce the available card resources of + this types for the user. + The state variable indicates the actual drivers state for this card with the + following assignments. + + 0 -> card has not been booted since driver load + 1 -> card booting is actually in progess + 2 -> card is in an error state due to a previous boot failure + 3 -> card is booted and active + + And the last field (device) shows the name of the ethernet device assigned + to this card. Up to the first successful boot this field only shows a - + to tell that no net device has been allocated up to now. Once a net device + has been allocated it remains assigned to this card, even if a card is + rebooted and an boot error occurs. + + Writing to the cardconfX file boots the card or transfers config lines to + the cards firmware. The type of data is automatically detected when the + first data is written. Only root has write access to this file. + The firmware boot files are normally called hyclient.pof for client cards + and hyserver.pof for server cards. + After successfully writing the boot file, complete config files or single + config lines may be copied to this file. + If an error occurs the return value given to the writing process has the + following additional codes (decimal): + + 1000 Another process is currently bootng the card + 1001 Invalid firmware header + 1002 Boards dual-port RAM test failed + 1003 Internal firmware handler error + 1004 Boot image size invalid + 1005 First boot stage (bootstrap loader) failed + 1006 Second boot stage failure + 1007 Timeout waiting for card ready during boot + 1008 Operation only allowed in booted state + 1009 Config line to long + 1010 Invalid channel number + 1011 Timeout sending config data + + Additional info about error reasons may be fetched from the log output. + +5. The /proc/net/hysdn/cardlogX file + + The cardlogX file entry may be opened multiple for reading by everyone to + get the cards and drivers log data. Card messages always start with the + keyword LOG. All other lines are output from the driver. + The driver log data may be redirected to the syslog by selecting the + appropriate bitmask. The cards log messages will always be send to this + interface but never to the syslog. + + A root user may write a decimal or hex (with 0x) value t this file to select + desired output options. As mentioned above the cards log dat is always + written to the cardlog file independent of the following options only used + to check and debug the driver itself: + + For example: + echo "0x34560078" > /proc/net/hysdn/cardlog0 + to output the hex log mask 34560078 for card 0. + + The written value is regarded as an unsigned 32-Bit value, bit ored for + desired output. The following bits are already assigned: + + 0x80000000 All driver log data is alternatively via syslog + 0x00000001 Log memory allocation errors + 0x00000010 Firmware load start and close are logged + 0x00000020 Log firmware record parser + 0x00000040 Log every firmware write actions + 0x00000080 Log all card related boot messages + 0x00000100 Output all config data sent for debugging purposes + 0x00000200 Only non comment config lines are shown wth channel + 0x00000400 Additional conf log output + 0x00001000 Log the asynchronous scheduler actions (config and log) + 0x00100000 Log all open and close actions to /proc/net/hysdn/card files + 0x00200000 Log all actions from /proc file entries + 0x00010000 Log network interface init and deinit + +6. Where to get additional info and help + + If you have any problems concerning the driver or configuration contact + the Hypercope support team (support@hypercope.de) and or the authors + Werner Cornelius (werner@isdn4linux or cornelius@titro.de) or + Ulrich Albrecht (ualbrecht@hypercope.de). + + + + + + + + + + + + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/kernel-docs.txt linux/Documentation/kernel-docs.txt --- v2.2.18/Documentation/kernel-docs.txt Sun Mar 25 11:13:40 2001 +++ linux/Documentation/kernel-docs.txt Sun Mar 25 11:37:29 2001 @@ -529,7 +529,7 @@ produced during the week. Published every Thursday. * Name: "Kernel Traffic" - URL: http://kt.linuxcare.com + URL: http://kt.zork.net Keywords: linux-kernel mailing list, weekly kernel news. Description: Weekly newsletter covering the most relevant discussions of the linux-kernel mailing list. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt --- v2.2.18/Documentation/networking/cs89x0.txt Sun Mar 25 11:13:34 2001 +++ linux/Documentation/networking/cs89x0.txt Sun Mar 25 11:37:29 2001 @@ -205,9 +205,8 @@ * mmode=##### - specify memory base address * dma=# - specify DMA channel * media=rj45 - specify media type - or media=2 + or media=bnc or media=aui - or medai=auto * duplex=f - specify forced half/full/autonegotiate duplex or duplex=h or duplex=auto diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/networking/ip_masq/rc.masqfw linux/Documentation/networking/ip_masq/rc.masqfw --- v2.2.18/Documentation/networking/ip_masq/rc.masqfw Wed Dec 31 19:00:00 1969 +++ linux/Documentation/networking/ip_masq/rc.masqfw Sun Mar 25 11:37:29 2001 @@ -0,0 +1,106 @@ +#!/bin/sh +# +# rc.masqfw v0.2 +# +# Author: Juanjo Ciarlante +# 03-Oct-00 +# +# Setup reverse masquerading (ala portfw) with using firewall mark-ing +# _AND_ userspace "redir" support for complete redirection (even local +# connects). +# +# Semantics: +# Let ip_masq_mfw intercept truly "forward-able" packets based +# on ipchains ruling _AND_ leave the rest for redir tool. +# +# Requirement: +# - ipmasqadm http://juanjox.kernelnotes.org/ +# . setups kernel mark forwarding) +# - redir 2.2.x http://freshmeat.net/search/?q=redir +# . setups "local" socket forwarding) +# - ip_masq_ftp PATCHED for firewall marking (module parm "in_mark") +# . support internal server forwarding for PASV clients) +# +# Setup: +# EXT_IP, EXT_PORT: external (visible) IP address (can be '0') and port. +# INT_IP, INT_PORT: internal server address and port +# IN_MARK: arbitrary value to use when marking pkts (ipchains -m) +# FTP: if not-null activate ftp support +# REDIR: path to redir-2.2.x (set to "" to avoid using) + +export PATH="/sbin:/usr/sbin:$PATH" + +EXT_IP=192.168.2.16 +EXT_PORT=2021 +INT_IP=10.1.1.128 +INT_PORT=21 +IN_MARK=4321 +FTP=1 +REDIR="/usr/sbin/redir" + +FW_IPCHAINS="-i eth0 -d $EXT_IP $EXT_PORT -p tcp" +PID_FILE="/var/run/redir-$EXT_IP-$EXT_PORT" + +# seems ascii art... but it runs!! =) +# +run() { + $* || { + echo "-> '$*'" + return 1 + } +} + +get_pid() { + test -f $PID_FILE || return 1 + typeset pid=`cat $PID_FILE` + test -n "$pid" || return 1 + kill -0 $pid || return 1 + echo $pid +} +exit_err() { + ERR=$1;shift + echo $@ >&2 + exit $ERR +} +redir_on() { + test -n "$REDIR" || return 1 + test -n "$FTP" && REDIR="$REDIR --ftp=both" + $SHELL -c 'echo $$ > '"$PID_FILE + exec $REDIR \ + --laddr $EXT_IP --lport $EXT_PORT \ + --caddr $INT_IP --cport $INT_PORT + " & + +} +redir_off() { + test -n "$REDIR" || return 1 + if pid=`get_pid`;then + kill $pid + rm $PID_FILE + fi + fuser -k -n tcp $EXT_PORT +} + +case "$1" in +start) + #run modprobe ip_masq_mfw + run ipmasqadm mfw -I -m $IN_MARK -r $INT_IP $INT_PORT + if test -n "$FTP";then + run modprobe ip_masq_ftp in_mark=$IN_MARK || \ + exit_err 1 "Incorrect ftp module version ?" + fi + run ipchains -m $IN_MARK -I input $FW_IPCHAINS + redir_on + ;; +stop) + run ipchains -m $IN_MARK -D input $FW_IPCHAINS + if test -n "$FTP";then + run rmmod ip_masq_ftp + fi + run ipmasqadm mfw -D -m $IN_MARK -r $INT_IP $INT_PORT + #run ipmasqadm mfw -F + #run rmmod ip_masq_mfw + redir_off + ;; + +esac diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt --- v2.2.18/Documentation/networking/vortex.txt Sun Mar 25 11:13:34 2001 +++ linux/Documentation/networking/vortex.txt Sun Mar 25 11:37:29 2001 @@ -1,35 +1,348 @@ +Documentation/networking/vortex.txt +Andrew Morton +18 Feb 2001 + + This document describes the usage and errata of the 3Com "Vortex" device -driver for Linux. +driver for Linux, 3c59x.c. + +The driver was written by Donald Becker + +Don is no longer the prime maintainer of this version of the driver. +Please report problems to one or more of: + + Andrew Morton + Netdev mailing list + Linux kernel mailing list + +Please note the 'Reporting and Diagnosing Problems' section at the end +of this file. This driver supports the following hardware: - 3c590, 3c592, 3c595, 3c597 -When loaded as a module the following variables may be set: - name type description - debug int The debug message level, 0 (no messages) to 6 (wordy). - options int[] The media type override and card operation settings - (See list below.) - -An example of loading the vortex module is - insmod 3c59x.o debug=1 options=0,,12 -This sets the debug message level to minimal messages, sets the first card to -the 10baseT transceiver, the second to the EEPROM-set transceiver, and the -third card to operate in full-duplex mode using its 100baseTx transceiver. -(Note: card ordering is set by the PCI BIOS.) + 3c590 Vortex 10Mbps + 3c592 EISA 10mbps Demon/Vortex + 3c597 EISA Fast Demon/Vortex + 3c595 Vortex 100baseTx + 3c595 Vortex 100baseT4 + 3c595 Vortex 100base-MII + 3Com Vortex + 3c900 Boomerang 10baseT + 3c900 Boomerang 10Mbps Combo + 3c900 Cyclone 10Mbps Combo + 3c900B-FL Cyclone 10base-FL + 3c900 Cyclone 10Mbps TPO + 3c900 Cyclone 10Mbps TPC + 3c905 Boomerang 100baseTx + 3c905 Boomerang 100baseT4 + 3c905B Cyclone 100baseTx + 3c905B Cyclone 10/100/BNC + 3c905B-FX Cyclone 100baseFx + 3c905C Tornado + 3c980 Cyclone + 3cSOHO100-TX Hurricane + 3c555 Laptop Hurricane + 3c556 10/100 Mini PCI Adapter + 3c556B Laptop Hurricane + 3c575 Boomerang CardBus + 3CCFE575 Cyclone CardBus + 3CCFE656 Cyclone CardBus + 3CCFEM656 Cyclone CardBus + 3c575 series CardBus (unknown version) + 3c450 HomePNA Tornado + 3Com Boomerang (unknown version) + +Module parameters +================= + +There are several parameters which may be provided to the driver when +its module is loaded. These are usually placed in /etc/modules.conf +(used to be conf.modules). Example: + +options 3c59x debug=3 rx_copybreak=300 + +The supported parameters are: + +debug=N + + Where N is a number from 0 to 7. Anything above 3 produces a lot + of output in your system logs. debug=1 is default. + +options=N1,N2,N3,... -Possible media type settings + Each number in the list provides an option to the corresponding + network card. So if you have two 3c905's and you wish to provide + them with option 0x204 you would use: + + options=0x204,0x204 + + The individual options are composed of a number of bitfields which + have the following meanings: + + ssible media type settings 0 10baseT 1 10Mbs AUI 2 undefined 3 10base2 (BNC) 4 100base-TX 5 100base-FX - 6 MII (not yet available) - 7 - - 8 Full-duplex bit - 8 10baseT full-duplex - 12 100baseTx full-duplex - 16 Bus-master enable bit (experimental use only!) + 6 MII (Media Independent Interface) + 7 Use default setting from EEPROM + 8 Autonegotiate + 9 External MII + 10 Use default setting from EEPROM + + When generating a value for the 'options' setting, the above media + selection values may be OR'ed (or added to) the following: + + 512 (0x200) Force full duplex mode. + 16 (0x10) Bus-master enable bit (Old Vortex cards only) + + For example: + + insmod 3c59x options=0x204 + + will force full-duplex 100base-TX, rather than allowing the usual + autonegotiation. + +full_duplex=N1,N2,N3... + + Similar to bit 9 of 'options'. Forces the corresponding card into + full-duplex mode. Please use this in preference to the `options' + parameter. + + In fact, please don't use this at all! You're better off getting + autonegotiation working properly. + +rx_copybreak=M + + The driver preallocates 32 full-sized (1536 byte) network buffers + for receiving. When a packet arrives, the driver has to decide + whether to leave the packet in its full-sized buffer, or to allocate + a smaller buffer and copy the packet across into it. + + This is a speed/space tradeoff. + + The value of rx_copybreak is used to decide when to make the copy. + If the packet size is less than rx_copybreak, the packet is copied. + The default value for rx_copybreak is 200 bytes. + +max_interrupt_work=N + + The driver's interrupt service routine can handle many receive and + transmit packets in a single invocation. It does this in a loop. + The value of max_interrupt_work governs how mnay times the interrupt + service routine will loop. The default value is 32 loops. If this + is exceeded the interrupt service routine gives up and generates a + warning message "eth0: Too much work in interrupt". + +compaq_ioaddr=N +compaq_irq=N +compaq_device_id=N + + "Variables to work-around the Compaq PCI BIOS32 problem".... + +enable_wol=N1,N2,N3,... + + Enable Wake-on-LAN support for the relevant interface. Donald + Becker's `ether-wake' application may be used to wake suspended + machines. + + +Media selection +--------------- + +A number of the older NICs such as the 3c590 and 3c900 series have +10base2 and AUI interfaces. + +Prior to January, 2001 this driver would autoeselect the 10base2 or AUI +port if it didn't detect activity on the 10baseT port. It would then +get stuck on the 10base2 port and a driver reload was necessary to +switch back to 10baseT. This behaviour could not be prevented with a +module option override. + +Later (current) versions of the driver _do_ support locking of the +media type. So if you load the driver module with + + modprobe 3c59x options=0 + +it will permanently select the 10baseT port. Automatic selection of +other media types does not occur. + + +Additional resources +-------------------- Details of the device driver implementation are at the top of the source file. + +Additional documentation is available at Don Becker's Linux Drivers site: + + http://www.scyld.com/network/vortex.html + +Donald Becker's driver development site: + + http://www.scyld.com/network + +Donald's vortex-diag program is useful for inspecting the NIC's state: + + http://www.scyld.com/diag/#pci-diags + +Donald's mii-diag program may be used for inspecting and manipulating +the NIC's Media Independent Interface subsystem: + + http://www.scyld.com/diag/#mii-diag + +Donald's wake-on-LAN page: + + http://www.scyld.com/expert/wake-on-lan.html + +3Com's documentation for many NICs, including the ones supported by +this driver is available at + + http://support.3com.com/partners/developer/developer_form.html + +3Com's DOS-based application for setting up the NICs EEPROMs: + + ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe + +Driver updates and a detailed changelog for the modifications which +were made for the 2.3/2,4 series kernel is available at + + http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 + + +Autonegotiation notes +--------------------- + + The driver uses a one-minute heartbeat for adapting to changes in + the external LAN environment. This means that when, for example, a + machine is unplugged from a hubbed 10baseT LAN plugged into a + switched 100baseT LAN, the throughput will be quite dreadful for up + to sixty seconds. Be patient. + + Cisco interoperability note from Walter Wong : + + On a side note, adding HAS_NWAY seems to share a problem with the + Cisco 6509 switch. Specifically, you need to change the spanning + tree parameter for the port the machine is plugged into to 'portfast' + mode. Otherwise, the negotiation fails. This has been an issue + we've noticed for a while but haven't had the time to track down. + + Cisco switches (Jeff Busch ) + + My "standard config" for ports to which PC's/servers connect directly: + + interface FastEthernet0/N + description machinename + load-interval 30 + spanning-tree portfast + + If autonegotiation is a problem, you may need to specify "speed + 100" and "duplex full" as well (or "speed 10" and "duplex half"). + + WARNING: DO NOT hook up hubs/switches/bridges to these + specially-configured ports! The switch will become very confused. + + +Reporting and diagnosing problems +--------------------------------- + +Maintainers find that accurate and complete problem reports are +invaluable in resolving driver problems. We are frequently not able to +reproduce problems and must rely on your patience and efforts to get to +the bottom of the problem. + +If you believe you have a driver problem here are some of the +steps you should take: + +- Is it really a driver problem? + + Eliminate some variables: try different cards, different + computers, different cables, different ports on the switch/hub, + different versions of the kernel or ofthe driver, etc. + +- OK, it's a driver problem. + + You need to generate a report. Typically this is an email to the + maintainer and/or linux-net@vger.kernel.org. The maintainer's + email address will be inthe driver source or in the MAINTAINERS file. + +- The contents of your report will vary a lot depending upon the + problem. If it's a kernel crash then you should refer to the + REPORTING-BUGS file. + + But for most problems it is useful to provide the following: + + o Kernel version, driver version + + o A copy of the banner message which the driver generates when + it is initialised. For example: + + eth0: 3Com PCI 3c905C Tornado at 0xa400, 00:50:da:6a:88:f0, IRQ 19 + 8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface. + MII transceiver found at address 24, status 782d. + Enabling bus-master transmits and whole-frame receives. + + o If it is a PCI device, the relevant output from 'lspci -vx', eg: + + 00:09.0 Ethernet controller: 3Com Corporation 3c905C-TX [Fast Etherlink] (rev 74) + Subsystem: 3Com Corporation: Unknown device 9200 + Flags: bus master, medium devsel, latency 32, IRQ 19 + I/O ports at a400 [size=128] + Memory at db000000 (32-bit, non-prefetchable) [size=128] + Expansion ROM at [disabled] [size=128K] + Capabilities: [dc] Power Management version 2 + 00: b7 10 00 92 07 00 10 02 74 00 00 02 08 20 00 00 + 10: 01 a4 00 00 00 00 00 db 00 00 00 00 00 00 00 00 + 20: 00 00 00 00 00 00 00 00 00 00 00 00 b7 10 00 10 + 30: 00 00 00 00 dc 00 00 00 00 00 00 00 05 01 0a 0a + + o A description of the environment: 10baseT? 100baseT? + full/half duplex? switched or hubbed? + + o Any additional module parameters which you may be providing to the driver. + + o Any kernel logs which are produced. The more the merrier. + If this is a large file and you are sending your report to a + mailing list, mention that you have the logfile, but don't send + it. If you're reporting direct to the maintainer then just send + it. + + To ensure that all kernel logs are available, add the + following line to /etc/syslog.conf: + + kern.* /var/log/messages + + Then restart syslogd with: + + /etc/rc.d/init.d/syslog restart + + (The above may vary, depending upon which Linux distribution you use). + + o If your problem is reproducible then that's great. Try the + following: + + 1) Increase the debug level. Usually this is done via: + + a) modprobe driver.o debug=7 + b) In /etc/conf.modules (or modules.conf): + options driver_name debug=7 + + 2) Recreate the problem with the higher debug level, + send all logs to the maintainer. + + 3) Download you card's diagnostic tool from Donald + Backer's website http://www.scyld.com/diag. Download + mii-diag.c as well. Build these. + + a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is + working correctly. Save the output. + + b) Run the above commands when the card is malfunctioning. Send + both sets of output. + +Finally, please be patient and be prepared to do some work. You may end up working on +this problem for a week or more as the maintainer asks more questions, asks for more +tests, asks for patches to be applied, etc. At the end of it all, the problem may even +remain unresolved. + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/powerpc/00-INDEX linux/Documentation/powerpc/00-INDEX --- v2.2.18/Documentation/powerpc/00-INDEX Sun Mar 25 11:13:38 2001 +++ linux/Documentation/powerpc/00-INDEX Sun Mar 25 11:37:29 2001 @@ -1,7 +1,7 @@ Index of files in Documentation/powerpc. If you think something about Linux/PPC needs an entry here, needs correction or you've written one please mail me. - Cort Dougan (cort@cs.nmt.edu) + Cort Dougan (cort@fsmlabs.com) 00-INDEX - this file diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/powerpc/ppc_htab.txt linux/Documentation/powerpc/ppc_htab.txt --- v2.2.18/Documentation/powerpc/ppc_htab.txt Sun Mar 25 11:13:38 2001 +++ linux/Documentation/powerpc/ppc_htab.txt Sun Mar 25 11:37:29 2001 @@ -2,7 +2,7 @@ ===================================================================== This document and the related code was written by me (Cort Dougan), please -email me (cort@cs.nmt.edu) if you have questions, comments or corrections. +email me (cort@fsmlabs.com) if you have questions, comments or corrections. Last Change: 2.16.98 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/powerpc/smp.txt linux/Documentation/powerpc/smp.txt --- v2.2.18/Documentation/powerpc/smp.txt Sun Mar 25 11:13:38 2001 +++ linux/Documentation/powerpc/smp.txt Sun Mar 25 11:37:29 2001 @@ -2,7 +2,7 @@ ===================================================================== This document and the related code was written by me -(Cort Dougan, cort@cs.nmt.edu) please email me if you have questions, +(Cort Dougan, cort@fsmlabs.com) please email me if you have questions, comments or corrections. Last Change: 3.31.99 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/powerpc/sound.txt linux/Documentation/powerpc/sound.txt --- v2.2.18/Documentation/powerpc/sound.txt Sun Mar 25 11:13:38 2001 +++ linux/Documentation/powerpc/sound.txt Sun Mar 25 11:37:29 2001 @@ -1,7 +1,7 @@ Information about PowerPC Sound support ===================================================================== -Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions, +Please mail me (Cort Dougan, cort@fsmlabs.com) if you have questions, comments or corrections. Last Change: 6.16.99 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/powerpc/zImage_layout.txt linux/Documentation/powerpc/zImage_layout.txt --- v2.2.18/Documentation/powerpc/zImage_layout.txt Sun Mar 25 11:13:38 2001 +++ linux/Documentation/powerpc/zImage_layout.txt Sun Mar 25 11:37:29 2001 @@ -1,7 +1,7 @@ Information about the Linux/PPC kernel images ===================================================================== -Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions, +Please mail me me (Cort Dougan, cort@fsmlabs.com) if you have questions, comments or corrections. This document is meant to answer several questions I've had about how diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/rtc.txt linux/Documentation/rtc.txt --- v2.2.18/Documentation/rtc.txt Sun Mar 25 11:13:36 2001 +++ linux/Documentation/rtc.txt Sun Mar 25 11:37:29 2001 @@ -56,7 +56,7 @@ exclusive access to the device for your applications. The alarm and/or interrupt frequency are programmed into the RTC via -various ioctl(2) calls as listed in ./include/linux/mc146818rtc.h +various ioctl(2) calls as listed in ./include/linux/rtc.h Rather than write 50 pages describing the ioctl() and so on, it is perhaps more useful to include a small test program that demonstrates how to use them, and demonstrates the features of the driver. This is @@ -81,7 +81,7 @@ */ #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/s390/cds.txt linux/Documentation/s390/cds.txt --- v2.2.18/Documentation/s390/cds.txt Sun Mar 25 11:28:15 2001 +++ linux/Documentation/s390/cds.txt Sun Mar 25 11:37:29 2001 @@ -241,7 +241,7 @@ The get_dev_info_by_irq() / get_dev_info_by_devno() functions return: - 0 - sucessful completion + 0 - successful completion -ENODEV - irq or devno don't specify a known subchannel or device number. -EINVAL - invalid devinfo value. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/sound/ChangeLog.ymfsb linux/Documentation/sound/ChangeLog.ymfsb --- v2.2.18/Documentation/sound/ChangeLog.ymfsb Sun Mar 25 11:13:39 2001 +++ linux/Documentation/sound/ChangeLog.ymfsb Wed Dec 31 19:00:00 1969 @@ -1,19 +0,0 @@ -Sun May 21 15:14:37 2000 Daisuke Nagano - - * ymf_sb.c: Add 'master_vol' module parameter to change - 'PCM out Vol" of AC'97. - Should I support AC'97 mixer by implementing original mixer - codes... ? - - * ymf_sb.c: remove native UART401 support. External MIDI port - should be supported by sb_midi driver. - - *ymf_sb.c: add support for SPDIF OUT. Module parameter - 'spdif_out' is now available. - - -Tue May 16 19:29:29 2000 Daisuke Nagano - - * ymf_sb.c (checkCodec): add a little delays for reset devices. - - * ymf_sb.c (readRegWord): fixed addressing bug. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/sound/Maestro3 linux/Documentation/sound/Maestro3 --- v2.2.18/Documentation/sound/Maestro3 Wed Dec 31 19:00:00 1969 +++ linux/Documentation/sound/Maestro3 Sun Mar 25 11:37:29 2001 @@ -0,0 +1,84 @@ + An OSS/Lite Driver for the ESS Maestro3 family of sound chips + + Zach Brown, December 2000 + +Driver Status and Availability +------------------------------ + +The most recent version of this driver will hopefully always be available at + http://www.zabbo.net/maestro3/ + +I will try and maintain the most recent stable version of the driver +in both the stable and development kernel lines. + +Historically I've sucked pretty hard at actually doing that, however. + +ESS Maestro3 Chip Family +----------------------- + +The 'Maestro3' is much like the Maestro2 chip. The noted improvement +is the removal of the silicon in the '2' that did PCM mixing. All that +work is now done through a custom DSP called the ASSP, the Asynchronus +Specific Signal Processor. + +The 'Allegro' is a baby version of the Maestro3. I'm not entirely clear +on the extent of the differences, but the driver supports them both :) + +The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998, +both under ESS's vendor ID of 0x125D. The Maestro3 can also show up as +0x199a when hardware strapping is used. + +The chip can also act as a multi function device. The modem IDs follow +the audio multimedia device IDs. (so the modem part of an Allegro shows +up as 0x1989) + +Driver OSS Behavior +-------------------- + +This OSS driver exports /dev/mixer and /dev/dsp to applications, which +mostly adhere to the OSS spec. This driver doesn't register itself +with /dev/sndstat, so don't expect information to appear there. + +The /dev/dsp device exported behaves as expected. Playback is +supported in all the various lovely formats. 8/16bit stereo/mono from +8khz to 48khz, with both read()/write(), and mmap(). + +/dev/mixer is an interface to the AC'97 codec on the Maestro3. It is +worth noting that there are a variety of AC'97s that can be wired to +the Maestro3. Which is used is entirely up to the hardware implementor. +This should only be visible to the user by the presence, or lack, of +'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them. +The Allegro has an onchip AC'97. + +The driver doesn't support MIDI or FM playback at the moment. + +Compiling and Installing +------------------------ + +With the drivers inclusion into the kernel, compiling and installing +is the same as most OSS/Lite modular sound drivers. Compilation +of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable +in the config system. + +It may be modular or statically linked. If it is modular it should be +installed with the rest of the modules for the kernel on the system. +Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0 +maestro3' should also be added to your module configs (typically +/etc/modules.conf) if you're using modular OSS/Lite sound and want to +default to using a maestro3 chip. + +There are very few options to the driver. One is 'debug' which will +tell the driver to print minimal debugging information as it runs. This +can be collected with 'dmesg' or through the klogd daemon. + +The other is 'external_amp', which tells the driver to attempt to enable +an external amplifier. This defaults to '1', you can tell the driver +not to bother enabling such an amplifier by setting it to '0'. + +Power Management +---------------- + +This driver has a minimal understanding of PCI Power Management. It will +try and power down the chip when the system is suspended, and power +it up with it is resumed. It will also try and power down the chip +when the machine is shut down. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/sound/README.ymfsb linux/Documentation/sound/README.ymfsb --- v2.2.18/Documentation/sound/README.ymfsb Sun Mar 25 11:13:39 2001 +++ linux/Documentation/sound/README.ymfsb Wed Dec 31 19:00:00 1969 @@ -1,127 +0,0 @@ -Legacy audio driver for YMF7xx PCI cards. - - -FIRST OF ALL -============ - - This code references YAMAHA's sample codes and data sheets. - I respect and thank for all people they made open the informations - about YMF7xx cards. - - And this codes heavily based on Jeff Garzik 's - old VIA 82Cxxx driver (via82cxxx.c). I also respect him. - - -DISCLIMER -========= - - This driver is currently at early ALPHA stage. It may cause serious - damage to your computer when used. - PLEASE USE IT AT YOUR OWN RISK. - - -ABOUT THIS DRIVER -================= - - This code enables you to use your YMF724[A-F], YMF740[A-C], YMF744, YMF754 - cards as "SoundBlaster Pro" compatible card. It can only play 22.05kHz / - 8bit / Stereo samples, control external MIDI port. - And it can handle AC'97 mixer of these cards. - - If you want to use your card as recent "16-bit" card, you should use - Alsa or OSS/Linux driver. Ofcource you can write native PCI driver for - your cards :) - - -INSTALL -======= - - First, it requires some sound driver modules in Linux kernel - (soundcore.o , sound.o, sb.o and uart401.o), so you should enable - these modules at kernel configuration (please refer some other - documentations for configuration of kernel). - And add the following line in /etc/modules.conf: - - options sb support=1 - - (NOTE: There are no need any configuration of sb modules) - - To compile ymfsb module, type 'make'. - And copy it to /lib/modules/(kernel_version)/misc, type 'depmod -a'. - - This module also requires /usr/src/linux/drivers/sound/ac97.[ch]. - If your kernel doesn't have these files, you should upgrade your kernel. - - -USAGE -===== - - # modprobe ymfsb (options) - - -OPTIONS FOR YMFSB -================= - - io : SB base address (0x220, 0x240, 0x260, 0x280) - synth_io : OPL3 base address (0x388, 0x398, 0x3a0, 0x3a8) - dma : DMA number (0,1,3) - spdif_out : SPDIF-out flag (0:disable 1:enable) - - These options will change in future... - - -FREQUENCY -========= - - When playing sounds via this driver, you will hear its pitch is slightly - lower than original sounds. Since this driver recognizes your card acts - with 21.739kHz sample rates rather than 22.050kHz (I think it must be - hardware restriction). So many players become tone deafness. - To prevent this, you should express some options to your sound player - that specify correct sample frequency. For example, to play your MP3 file - correctly with mpg123, specify the frequency like following: - - % mpg123 -r 21739 foo.mp3 - - -SPDIF OUT -========= - - With installing modules with option 'spdif_out=1', you can enjoy your - sounds from SPDIF-out of your card (if it had). - Its Fs is fixed to 48kHz (It never means the sample frequency become - up to 48kHz. All sounds via SPDIF-out also 22kHz samples). So your - digital-in capable components has to be able to handle 48kHz Fs. - - -COPYING -======= - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - -TODO -==== - * support for multiple cards - (set the different SB_IO,MPU_IO,OPL_IO for each cards) - - * support for OPL (dmfm) : There will be no requirements... :-< - - -AUTHOR -====== - - Daisuke Nagano - diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt --- v2.2.18/Documentation/usb/usb-serial.txt Sun Mar 25 11:28:15 2001 +++ linux/Documentation/usb/usb-serial.txt Sun Mar 25 11:37:29 2001 @@ -185,6 +185,15 @@ -- Add everything else that is missing :) +Empeg empeg-car Mark I/II Driver (empeg.c) + + This is an experimental driver to provide connectivity support for the + client synchronization tools for an Empeg empeg-car mp3 player. + + The driver is still pretty new, so some testing 'in the wild' would be + helpful. :) + + Generic Serial driver If your device is not one of the above listed devices, compatible with diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/MAINTAINERS linux/MAINTAINERS --- v2.2.18/MAINTAINERS Sun Mar 25 11:28:16 2001 +++ linux/MAINTAINERS Sun Mar 25 11:37:29 2001 @@ -87,6 +87,12 @@ L: linux-hams@vger.kernel.org S: Maintained +8139too NETWORK DRIVER +P: Jeff Garzik, Jens David (Linux-2.2 port) +M: dg1kjd@afthd.tu-darmstadt.de +L: linux-net@vger.rutgers.edu +S: Maintained + 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] P: Paul Gortmaker M: p_gortmaker@yahoo.com @@ -129,9 +135,9 @@ APM DRIVER P: Stephen Rothwell -M: apm@linuxcare.com.au +M: sfr@canb.auug.org.au L: linux-laptop@vger.kernel.org -W: http://linuxcare.com.au/apm/ +W: http://www.canb.auug.org.au/~sfr/ S: Supported APPLETALK NETWORK LAYER @@ -251,7 +257,7 @@ DC390/AM53C974 SCSI driver P: Kurt Garloff -M: kurt@garloff.de +M: garloff@suse.de W: http://www.garloff.de/kurt/linux/dc390/ S: Maintained @@ -493,6 +499,13 @@ L: linux-kernel@vger.kernel.org S: Maintained +INTEL IA32 MICROCODE UPDATE DRIVER +P: Tigran Aivazian +M: Tigran Aivazian +W: http://www.urbanmyth.org/microcode +L: linux-kernel@vger.kernel.org +S: Maintained + IP FIREWALL P: Paul Russell M: Paul.Russell@rustcorp.com.au @@ -532,6 +545,13 @@ L: isdn4linux@listserv.isdn4linux.de S: Maintained +ISDN SUBSYSTEM (Eicon active card driver) +P: Armin Schindler +M: mac@melware.de +L: isdn4linux@listserv.isdn4linux.de +W: http://www.melware.net +S: Maintained + JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@suse.cz @@ -559,10 +579,12 @@ S: Maintained KERNEL NFSD -P: G. Allen Morris III -M: gam3@acm.org +P: Neil Brown +M: neilb@cse.unsw.edu.au L: nfs-devel@linux.kernel.org (Linux NFS) -W: http://csua.berkeley.edu/~gam3/knfsd +L: nfs@lists.sourceforge.net +W: http://nfs.sourceforge.net/ +W: http://www.cse.unsw.edu.au/~neilb/patches/knfsd-2.2/ S: Maintained LANMEDIA WAN CARD DRIVER @@ -579,13 +601,13 @@ LINUX FOR POWERPC (PREP) P: Cort Dougan -M: cort@cs.nmt.edu -W: http://linuxppc.cs.nmt.edu/ +M: cort@fsmlabs.com +W: http://www.fsmlabs.com/linuxppcbk.html S: Maintained LINUX FOR POWER MACINTOSH P: Paul Mackerras -M: paulus@linuxcare.com +M: paulus@samba.org W: http://www.linuxppc.org/ L: linuxppc-dev@lists.linuxppc.org S: Maintained @@ -725,6 +747,13 @@ W: http://www.linuxtr.net S: Maintained +ONSTREAM SCSI TAPE DRIVER +P: Willem Riede +M: osst@riede.org +L: osst@linux1.onstream.nl +L: linux-scsi@vger.rutgers.edu +S: Maintained + OPL3-SA2, SA3, and SAx DRIVER P: Scott Murray M: scott@spiteful.org @@ -915,6 +944,11 @@ M: support@stallion.oz.au W: http://www.stallion.com S: Supported + +STARFIRE/DURALAN NETWORK DRIVER +P: Ion Badulescu +M: ionut@cs.columbia.edu +S: Maintained STARMODE RADIO IP (STRIP) PROTOCOL DRIVER W: http://mosquitonet.Stanford.EDU/strip.html diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/Makefile linux/Makefile --- v2.2.18/Makefile Sun Mar 25 11:28:16 2001 +++ linux/Makefile Sun Mar 25 11:39:55 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 -SUBLEVEL = 18 -EXTRAVERSION = +SUBLEVEL = 19 +EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -25,7 +25,7 @@ # # foo-bar-gcc for cross builds # gcc272 for Debian's old compiler for kernels -# kgcc for Conectiva and Red Hat 7 +# kgcc for Conectiva, Mandrake and Red Hat 7 # otherwise 'cc' # CC =$(shell if [ -n "$(CROSS_COMPILE)" ]; then echo $(CROSS_COMPILE)gcc; else \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/config.in linux/arch/alpha/config.in --- v2.2.18/arch/alpha/config.in Sun Mar 25 11:28:16 2001 +++ linux/arch/alpha/config.in Sun Mar 25 11:37:29 2001 @@ -252,9 +252,11 @@ mainmenu_option next_comment comment 'ISDN subsystem' -tristate 'ISDN support' CONFIG_ISDN -if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in +if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.2.18/arch/alpha/kernel/alpha_ksyms.c Sun Mar 25 11:28:16 2001 +++ linux/arch/alpha/kernel/alpha_ksyms.c Sun Mar 25 11:37:29 2001 @@ -169,6 +169,7 @@ EXPORT_SYMBOL(global_bh_lock); EXPORT_SYMBOL(global_bh_count); EXPORT_SYMBOL(synchronize_bh); +EXPORT_SYMBOL(alpha_bh_lock); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.2.18/arch/alpha/kernel/entry.S Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/kernel/entry.S Sun Mar 25 11:37:29 2001 @@ -272,7 +272,11 @@ stq $26,0($30) stq $19,8($30) .prologue 1 +#ifdef __SMP__ + jsr $26,___kernel_execve +#else jsr $26,do_execve +#endif /* __SMP__ */ bne $0,1f /* error! */ ldq $30,8($30) br $31,ret_from_sys_call diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.2.18/arch/alpha/kernel/irq.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/kernel/irq.c Sun Mar 25 11:37:29 2001 @@ -385,6 +385,7 @@ /* This protects BH software state (masks, things like that). */ atomic_t global_bh_lock = ATOMIC_INIT(0); atomic_t global_bh_count = ATOMIC_INIT(0); +spinlock_t alpha_bh_lock = SPIN_LOCK_UNLOCKED; static void *previous_irqholder = NULL; @@ -650,6 +651,7 @@ void synchronize_bh(void) { + mb(); if (atomic_read(&global_bh_count) && !in_interrupt()) wait_on_bh(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.2.18/arch/alpha/kernel/osf_sys.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/kernel/osf_sys.c Sun Mar 25 11:37:29 2001 @@ -78,8 +78,10 @@ mm = current->mm; mm->end_code = bss_start + bss_len; mm->brk = bss_start + bss_len; +#if 0 printk("set_program_attributes(%lx %lx %lx %lx)\n", text_start, text_len, bss_start, bss_len); +#endif unlock_kernel(); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.2.18/arch/alpha/kernel/process.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/kernel/process.c Sun Mar 25 11:37:29 2001 @@ -249,8 +249,11 @@ alpha_mv.kill_arch(LINUX_REBOOT_CMD_POWER_OFF, NULL); } -void show_regs(struct pt_regs * regs) +void __show_regs(struct pt_regs * regs) { + extern void dik_show_trace(unsigned long *); + + printk("\nCPU: %d", smp_processor_id()); printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc); printk("rp: [<%016lx>] sp: %p\n", regs->r26, regs+1); printk(" r0: %016lx r1: %016lx r2: %016lx r3: %016lx\n", @@ -265,6 +268,15 @@ regs->r23, regs->r24, regs->r25, regs->r26); printk("r27: %016lx r28: %016lx r29: %016lx hae: %016lx\n", regs->r27, regs->r28, regs->gp, regs->hae); + dik_show_trace(regs+1); +} + +void show_regs(struct pt_regs * regs) +{ + __show_regs(regs); +#ifdef CONFIG_SMP + smp_show_regs(); +#endif } /* @@ -463,3 +475,29 @@ unlock_kernel(); return error; } + +#ifdef __SMP__ +/* + * execve() system call for in kernel use. + * + * Two(user and kernel) execve() have quite different call path and + * following function puts lock_kernel() and unlock_kernel() in kernel + * execve(). You could put them in unistd.h but you will have to + * modify many files to clear compile error - + * + * soohoon.lee@api-networks.com. */ + +asmlinkage int ___kernel_execve(char *filename, char **argp, char **envp, + struct pt_regs *regs) +{ + int error; + + lock_kernel(); + + error = do_execve(filename, argp, envp, regs); + + unlock_kernel(); + + return error; +} +#endif /* __SMP__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.2.18/arch/alpha/kernel/smp.c Sun Mar 25 11:28:16 2001 +++ linux/arch/alpha/kernel/smp.c Sun Mar 25 11:37:29 2001 @@ -95,8 +95,7 @@ smp_store_cpu_info(int cpuid) { cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy; - cpu_data[cpuid].last_asn - = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION; + cpu_data[cpuid].last_asn = ASN_FIRST_VERSION; cpu_data[cpuid].irq_count = 0; cpu_data[cpuid].bh_count = 0; @@ -739,7 +738,14 @@ /* At this point the structure may be gone unless wait is true. */ - (*func)(info); + { + static void ipi_show_regs(void *); + + if (func != ipi_show_regs) + (*func)(info); + else + (*func)((void *) regs); + } /* Notify the sending CPU that the task is done. */ mb(); @@ -856,6 +862,21 @@ } static void +ipi_show_regs(void * param) +{ + struct pt_regs *regs = (struct pt_regs *) param; + + __show_regs(regs); +} + +void +smp_show_regs(void) +{ + if (smp_call_function(ipi_show_regs, NULL, 1, 1)) + printk(KERN_CRIT "smp_show_regs: timed out\n"); +} + +static void ipi_flush_tlb_all(void *ignored) { tbia(); @@ -879,6 +900,8 @@ struct mm_struct *mm = (struct mm_struct *) x; if (mm == current->mm) flush_tlb_current(mm); + else + flush_tlb_other(mm); } void @@ -886,10 +909,17 @@ { if (mm == current->mm) { flush_tlb_current(mm); - if (atomic_read(&mm->count) == 1) + if (atomic_read(&mm->count) == 1) { + int i, cpu, this_cpu = smp_processor_id(); + for (i = 0; i < smp_num_cpus; i++) { + cpu = cpu_logical_map(i); + if (cpu == this_cpu) + continue; + mm->context[cpu] = 0; + } return; - } else - flush_tlb_other(mm); + } + } if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) { printk(KERN_CRIT "flush_tlb_mm: timed out\n"); @@ -906,8 +936,12 @@ ipi_flush_tlb_page(void *x) { struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x; - if (data->mm == current->mm) - flush_tlb_current_page(data->mm, data->vma, data->addr); + struct mm_struct * mm = data->mm; + + if (mm == current->mm) + flush_tlb_current_page(mm, data->vma, data->addr); + else + flush_tlb_other(mm); } void @@ -918,10 +952,17 @@ if (mm == current->mm) { flush_tlb_current_page(mm, vma, addr); - if (atomic_read(¤t->mm->count) == 1) + if (atomic_read(¤t->mm->count) == 1) { + int i, cpu, this_cpu = smp_processor_id(); + for (i = 0; i < smp_num_cpus; i++) { + cpu = cpu_logical_map(i); + if (cpu == this_cpu) + continue; + mm->context[cpu] = 0; + } return; - } else - flush_tlb_other(mm); + } + } data.vma = vma; data.mm = mm; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/sys_nautilus.c linux/arch/alpha/kernel/sys_nautilus.c --- v2.2.18/arch/alpha/kernel/sys_nautilus.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/kernel/sys_nautilus.c Sun Mar 25 11:37:29 2001 @@ -111,7 +111,7 @@ switch(mode) { case LINUX_REBOOT_CMD_HALT: - printk("Press Reset bottun"); + printk("Press Reset button"); break; case LINUX_REBOOT_CMD_RESTART: { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c --- v2.2.18/arch/alpha/kernel/sys_ruffian.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/kernel/sys_ruffian.c Sun Mar 25 11:37:29 2001 @@ -163,16 +163,91 @@ enable_irq(2); /* enable 2nd PIC cascade */ } +/* + * Interrupt routing: + * + * Primary bus + * IdSel INTA INTB INTC INTD + * 21052 13 - - - - + * SIO 14 23 - - - + * 21143 15 44 - - - + * Slot 0 17 43 42 41 40 + * + * Secondary bus + * IdSel INTA INTB INTC INTD + * Slot 0 8 (18) 19 18 17 16 + * Slot 1 9 (19) 31 30 29 28 + * Slot 2 10 (20) 27 26 25 24 + * Slot 3 11 (21) 39 38 37 36 + * Slot 4 12 (22) 35 34 33 32 + * 53c875 13 (23) 20 - - - + * + */ + +static int __init +ruffian_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[11][5] __initdata = { + /*INT INTA INTB INTC INTD */ + {-1, -1, -1, -1, -1}, /* IdSel 13, 21052 */ + {-1, -1, -1, -1, -1}, /* IdSel 14, SIO */ + {44, 44, 44, 44, 44}, /* IdSel 15, 21143 */ + {-1, -1, -1, -1, -1}, /* IdSel 16, none */ + {43, 43, 42, 41, 40}, /* IdSel 17, 64-bit slot */ + /* the next 6 are actually on PCI bus 1, across the bridge */ + {19, 19, 18, 17, 16}, /* IdSel 8, slot 0 */ + {31, 31, 30, 29, 28}, /* IdSel 9, slot 1 */ + {27, 27, 26, 25, 24}, /* IdSel 10, slot 2 */ + {39, 39, 38, 37, 36}, /* IdSel 11, slot 3 */ + {35, 35, 34, 33, 32}, /* IdSel 12, slot 4 */ + {20, 20, 20, 20, 20}, /* IdSel 13, 53c875 */ + }; + const long min_idsel = 13, max_idsel = 23, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static int __init +ruffian_swizzle(struct pci_dev *dev, int *pinp) +{ + int slot, pin = *pinp; + + if (dev->bus->number == 0) { + slot = PCI_SLOT(dev->devfn); + } + /* Check for the built-in bridge. */ + else if (PCI_SLOT(dev->bus->self->devfn) == 13) { + slot = PCI_SLOT(dev->devfn) + 10; + } + else + { + /* Must be a card-based bridge. */ + do { + if (PCI_SLOT(dev->bus->self->devfn) == 13) { + slot = PCI_SLOT(dev->devfn) + 10; + break; + } + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + + /* Move up the chain of bridges. */ + dev = dev->bus->self; + /* Slot of the next bridge. */ + slot = PCI_SLOT(dev->devfn); + } while (dev->bus->self); + } + *pinp = pin; + return slot; +} /* * For RUFFIAN, we do not want to make any modifications to the PCI - * setup. But we may need to do some kind of init. + * setup, except IRQ assignment. But we may need to do some kind of init. */ static void __init ruffian_pci_fixup(void) { /* layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); */ + common_pci_fixup(ruffian_map_irq, ruffian_swizzle); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.2.18/arch/alpha/kernel/traps.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/kernel/traps.c Sun Mar 25 11:37:29 2001 @@ -269,7 +269,7 @@ } } -static void +void dik_show_trace(unsigned long *sp) { int i = 1; @@ -1086,7 +1086,9 @@ { /* We only get here for OSF system calls, minus #112; the rest go to sys_ni_syscall. */ +#if 0 printk("", regs.r0, a0, a1, a2); +#endif return -ENOSYS; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/lib/strlen_user.S linux/arch/alpha/lib/strlen_user.S --- v2.2.18/arch/alpha/lib/strlen_user.S Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/lib/strlen_user.S Sun Mar 25 11:37:29 2001 @@ -28,17 +28,9 @@ .set noat .text - .globl __strlen_user - .ent __strlen_user - .frame sp, 0, ra - - .align 3 -__strlen_user: - ldah a1, 32767(zero) # do not use plain strlen_user() for strings - # that might be almost 2 GB long; you should - # be using strnlen_user() instead - .globl __strnlen_user + .ent __strnlen_user + .frame sp, 0, ra .align 3 __strnlen_user: @@ -89,4 +81,4 @@ subq a1, t2, v0 ret - .end __strlen_user + .end __strnlen_user diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/mm/extable.c linux/arch/alpha/mm/extable.c --- v2.2.18/arch/alpha/mm/extable.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/mm/extable.c Sun Mar 25 11:37:29 2001 @@ -88,7 +88,7 @@ */ ret = search_exception_table_without_gp(addr); if (ret) { - printk(KERN_ALERT, "%s: [%lx] EX_TABLE search fail with" + printk(KERN_ALERT "%s: [%lx] EX_TABLE search fail with" "exc frame GP, success with raw GP\n", current->comm, addr); return ret; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.2.18/arch/alpha/mm/fault.c Sun Mar 25 11:13:14 2001 +++ linux/arch/alpha/mm/fault.c Sun Mar 25 11:37:29 2001 @@ -41,7 +41,7 @@ get_new_mmu_context(struct task_struct *p, struct mm_struct *mm) { unsigned long new = __get_new_mmu_context(); - mm->context = new; + mm->context[smp_processor_id()] = new; p->tss.asn = new & HARDWARE_ASN_MASK; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.2.18/arch/arm/kernel/dec21285.c Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/kernel/dec21285.c Sun Mar 25 11:37:29 2001 @@ -169,9 +169,14 @@ __initfunc(void pcibios_init(void)) { unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET; + unsigned int mem_mask; unsigned long cntl; - *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; + for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1) + if (mem_mask >= mem_size) + break; + + *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000; *CSR_SDRAMBASEOFFSET = 0; *CSR_ROMBASEMASK = 0x80000000; *CSR_CSRBASEMASK = 0; @@ -224,7 +229,7 @@ *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); *CSR_PCIROMBASE = 0; *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.2.18/arch/arm/kernel/entry-armv.S Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/kernel/entry-armv.S Sun Mar 25 11:37:29 2001 @@ -322,7 +322,8 @@ .macro restore_user_regs ldr r0, [sp, #S_PSR] @ Get calling cpsr - msr cpsr_c, #I_BIT | MODE_SVC @ disable IRQs + mov r1, #I_BIT | MODE_SVC @ disable IRQs + msr cpsr_c, r1 msr spsr, r0 @ save in spsr_svc ldmia sp, {r0 - lr}^ @ Get calling r0 - lr mov r0, r0 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.2.18/arch/arm/kernel/head-armv.S Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/kernel/head-armv.S Sun Mar 25 11:37:29 2001 @@ -388,6 +388,7 @@ __arch_types_end: #ifdef CONFIG_DEBUG_LL + .text /* * Some debugging routines (useful if you've got MM problems and * printk isn't working). For DEBUGGING ONLY!!! Do not leave @@ -441,6 +442,10 @@ .endm #elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE) + +#include +#include + #ifndef CONFIG_DEBUG_DC21285_PORT /* For NetWinder debugging */ .macro addruart,rx diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c --- v2.2.18/arch/arm/kernel/hw-footbridge.c Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/kernel/hw-footbridge.c Sun Mar 25 11:37:29 2001 @@ -205,7 +205,8 @@ pci_read_config_word(dev, PCI_STATUS, &status); if (status & 0xf900) { - printk(KERN_DEBUG "PCI: [%04X:%04X] status = %X\n", + printk(KERN_DEBUG "PCI: %02x:%02x.%d [%04X:%04X] status = 0x%04X\n", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), dev->vendor, dev->device, status); pci_write_config_word(dev, PCI_STATUS, status & 0xf900); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.2.18/arch/arm/kernel/process.c Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/kernel/process.c Sun Mar 25 11:37:29 2001 @@ -228,10 +228,8 @@ void flush_thread(void) { - int i; - - for (i = 0; i < NR_DEBUGS; i++) - current->tss.debug[i] = 0; + memset(¤t->tss.debug, 0, sizeof(struct debug_info)); + memset(¤t->tss.fpstate, 0, sizeof(union fp_state)); current->used_math = 0; current->flags &= ~PF_USEDFPU; } @@ -263,12 +261,10 @@ */ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) { - int fpvalid = 0; - if (current->used_math) - memcpy (fp, ¤t->tss.fpstate.soft, sizeof (fp)); + memcpy (fp, ¤t->tss.fpstate.soft, sizeof (*fp)); - return fpvalid; + return current->used_math; } /* @@ -276,18 +272,20 @@ */ void dump_thread(struct pt_regs * regs, struct user * dump) { - int i; - + struct task_struct *tsk = current; dump->magic = CMAGIC; - dump->start_code = current->mm->start_code; + dump->start_code = tsk->mm->start_code; dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1); - dump->u_tsize = (current->mm->end_code - current->mm->start_code) >> PAGE_SHIFT; - dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; + dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT; + dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; dump->u_ssize = 0; - for (i = 0; i < NR_DEBUGS; i++) - dump->u_debugreg[i] = current->tss.debug[i]; + dump->u_debugreg[0] = tsk->tss.debug.bp[0].address; + dump->u_debugreg[1] = tsk->tss.debug.bp[1].address; + dump->u_debugreg[2] = tsk->tss.debug.bp[0].insn; + dump->u_debugreg[3] = tsk->tss.debug.bp[1].insn; + dump->u_debugreg[4] = tsk->tss.debug.nsaved; if (dump->start_stack < 0x04000000) dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT; @@ -310,14 +308,19 @@ pid_t __ret; __asm__ __volatile__( - "mov r0, %1 @ kernel_thread sys_clone\n" + "orr r0, %1, %2 @ kernel_thread\n" " mov r1, #0\n" __syscall(clone)"\n" -" mov %0, r0" +" movs %0, r0 + bne 1f + mov fp, r0 + mov r0, %4 + mov lr, pc + mov pc, %3 + b sys_exit +1: " : "=r" (__ret) - : "Ir" (flags | CLONE_VM) : "r0", "r1"); - if (__ret == 0) - sys_exit((fn)(arg)); + : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg): "r0", "r1", "lr"); return __ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.2.18/arch/arm/kernel/ptrace.c Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/kernel/ptrace.c Sun Mar 25 11:37:29 2001 @@ -16,6 +16,9 @@ #include #include + +#define REG_PC 15 +#define REG_PSR 16 /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -25,11 +28,12 @@ * Breakpoint SWI instruction: SWI &9F0001 */ #define BREAKINST 0xef9f0001 -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 -#define PTRACE_GETFPREGS 14 -#define PTRACE_SETFPREGS 15 +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + */ static inline struct pt_regs * get_user_regs(struct task_struct *task) { @@ -299,38 +303,42 @@ return 0; } +#define write_tsk_long(chld, addr, val) write_long((chld), (addr), (val)) +#define read_tsk_long(chld, addr, val) read_long((chld), (addr), (val)) + /* * Get value of register `rn' (in the instruction) */ -static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getrn(struct task_struct *child, unsigned long insn) { unsigned int reg = (insn >> 16) & 15; unsigned long val; + val = get_stack_long(child, reg); if (reg == 15) - val = pc_pointer (get_stack_long (child, reg)); - else - val = get_stack_long (child, reg); + val = pc_pointer(val + 8); + -printk ("r%02d=%08lX ", reg, val); return val; } /* * Get value of operand 2 (in an ALU instruction) */ -static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getaluop2(struct task_struct *child, unsigned long insn) { unsigned long val; int shift; int type; -printk ("op2="); + if (insn & 1 << 25) { val = insn & 255; shift = (insn >> 8) & 15; type = 3; -printk ("(imm)"); + } else { val = get_stack_long (child, insn & 15); @@ -340,9 +348,9 @@ shift = (insn >> 7) & 31; type = (insn >> 5) & 3; -printk ("(r%02ld)", insn & 15); + } -printk ("sh%dx%d", type, shift); + switch (type) { case 0: val <<= shift; break; case 1: val >>= shift; break; @@ -350,27 +358,28 @@ val = (((signed long)val) >> shift); break; case 3: - __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + val = (val >> shift) | (val << (32 - shift)); break; } -printk ("=%08lX ", val); + return val; } /* * Get value of operand 2 (in a LDR instruction) */ -static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getldrop2(struct task_struct *child, unsigned long insn) { unsigned long val; int shift; int type; - val = get_stack_long (child, insn & 15); + val = get_stack_long(child, insn & 15); shift = (insn >> 7) & 31; type = (insn >> 5) & 3; -printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type); + switch (type) { case 0: val <<= shift; break; case 1: val >>= shift; break; @@ -378,115 +387,88 @@ val = (((signed long)val) >> shift); break; case 3: - __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + val = (val >> shift) | (val << (32 - shift)); break; } -printk ("=%08lX ", val); + return val; } -#undef pc_pointer -#define pc_pointer(x) ((x) & 0x03fffffc) -int ptrace_set_bpt (struct task_struct *child) -{ - unsigned long insn, pc, alt; - int i, nsaved = 0, res; - - pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/)); - - res = read_long (child, pc, &insn); - if (res < 0) - return res; - - child->tss.debug[nsaved++] = alt = pc + 4; -printk ("ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc); - switch (insn & 0x0e100000) { + +static unsigned long +get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) +{ + unsigned long alt = 0; + + switch (insn & 0x0e000000) { case 0x00000000: - case 0x00100000: - case 0x02000000: - case 0x02100000: /* data processing */ - printk ("data "); - switch (insn & 0x01e0f000) { - case 0x0000f000: - alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn); - break; - case 0x0020f000: - alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn); - break; - case 0x0040f000: - alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn); - break; - case 0x0060f000: - alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn); - break; - case 0x0080f000: - alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn); - break; - case 0x00a0f000: - alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x00c0f000: - alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x00e0f000: - alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x0180f000: - alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn); - break; - case 0x01a0f000: - alt = ptrace_getaluop2(child, insn); - break; - case 0x01c0f000: - alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn); - break; - case 0x01e0f000: - alt = ~ptrace_getaluop2(child, insn); + case 0x02000000: { + /* + * data processing + */ + long aluop1, aluop2, ccbit; + + if ((insn & 0xf000) != 0xf000) break; + + + + aluop1 = ptrace_getrn(child, insn); + aluop2 = ptrace_getaluop2(child, insn); + ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0; + + switch (insn & 0x01e00000) { + case 0x00000000: alt = aluop1 & aluop2; break; + case 0x00200000: alt = aluop1 ^ aluop2; break; + case 0x00400000: alt = aluop1 - aluop2; break; + case 0x00600000: alt = aluop2 - aluop1; break; + case 0x00800000: alt = aluop1 + aluop2; break; + case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break; + case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break; + case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break; + case 0x01800000: alt = aluop1 | aluop2; break; + case 0x01a00000: alt = aluop2; break; + case 0x01c00000: alt = aluop1 & ~aluop2; break; + case 0x01e00000: alt = ~aluop2; break; } break; + } + + case 0x04000000: + case 0x06000000: + /* + * ldr + */ + if ((insn & 0x0010f000) == 0x0010f000) { + unsigned long base; - case 0x04100000: /* ldr */ - if ((insn & 0xf000) == 0xf000) { -printk ("ldr "); - alt = ptrace_getrn(child, insn); + base = ptrace_getrn(child, insn); if (insn & 1 << 24) { - if (insn & 1 << 23) - alt += ptrace_getldrop2 (child, insn); + long aluop2; + + if (insn & 0x02000000) + aluop2 = ptrace_getldrop2(child, insn); else - alt -= ptrace_getldrop2 (child, insn); - } - if (read_long (child, alt, &alt) < 0) - alt = pc + 4; /* not valid */ - else - alt = pc_pointer (alt); - } - break; + aluop2 = insn & 0xfff; - case 0x06100000: /* ldr imm */ - if ((insn & 0xf000) == 0xf000) { -printk ("ldrimm "); - alt = ptrace_getrn(child, insn); - if (insn & 1 << 24) { if (insn & 1 << 23) - alt += insn & 0xfff; + base += aluop2; else - alt -= insn & 0xfff; + base -= aluop2; } - if (read_long (child, alt, &alt) < 0) - alt = pc + 4; /* not valid */ - else - alt = pc_pointer (alt); + + if (read_tsk_long(child, base, &alt) == 0) + alt = pc_pointer(alt); } break; - case 0x08100000: /* ldm */ - if (insn & (1 << 15)) { + case 0x08000000: + /* + * ldm + */ + if ((insn & 0x00108000) == 0x00108000) { unsigned long base; - int nr_regs; -printk ("ldm "); + unsigned int nr_regs; + if (insn & (1 << 23)) { nr_regs = insn & 65535; @@ -506,23 +488,23 @@ nr_regs = 0; } - base = ptrace_getrn (child, insn); + base = ptrace_getrn(child, insn); - if (read_long (child, base + nr_regs, &alt) < 0) - alt = pc + 4; /* not valid */ - else - alt = pc_pointer (alt); + if (read_tsk_long(child, base + nr_regs, &alt) == 0) + alt = pc_pointer(alt); break; } break; - case 0x0a000000: - case 0x0a100000: { /* bl or b */ + case 0x0a000000: { + /* + * bl or b + */ signed long displ; -printk ("b/bl "); + /* It's a branch/branch link: instead of trying to * figure out whether the branch will be taken or not, - * we'll put a breakpoint at either location. This is + * we'll put a breakpoint at both locations. This is * simpler, more reliable, and probably not a whole lot * slower than the alternative approach of emulating the * branch. @@ -534,196 +516,230 @@ } break; } -printk ("=%08lX\n", alt); - if (alt != pc + 4) - child->tss.debug[nsaved++] = alt; - for (i = 0; i < nsaved; i++) { - res = read_long (child, child->tss.debug[i], &insn); - if (res >= 0) { - child->tss.debug[i + 2] = insn; - res = write_long (child, child->tss.debug[i], BREAKINST); - } - if (res < 0) { - child->tss.debug[4] = 0; - return res; + return alt; +} + +static int +add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr) +{ + int nr = dbg->nsaved; + int res = -EINVAL; + + if (nr < 2) { + res = read_tsk_long(child, addr, &dbg->bp[nr].insn); + if (res == 0) + res = write_tsk_long(child, addr, BREAKINST); + + if (res == 0) { + dbg->bp[nr].address = addr; + dbg->nsaved += 1; } + } else + printk(KERN_DEBUG "add_breakpoint: too many breakpoints\n"); + + return res; +} + +int ptrace_set_bpt(struct task_struct *child) +{ + unsigned long insn, pc; + int res; + + pc = pc_pointer(get_stack_long(child, REG_PC)); + + res = read_long(child, pc, &insn); + if (!res) { + struct debug_info *dbg = &child->tss.debug; + unsigned long alt; + + dbg->nsaved = 0; + + alt = get_branch_address(child, pc, insn); + + if (alt) + res = add_breakpoint(child, dbg, alt); + + /* + * Note that we ignore the result of setting the above + * breakpoint since it may fail. When it does, this is + * not so much an error, but a forewarning that we will + * be receiving a prefetch abort shortly. + * + * If we don't set this breakpoint here, then we can + * loose control of the thread during single stepping. + */ + if (!alt || predicate(insn) != PREDICATE_ALWAYS) + res = add_breakpoint(child, dbg, pc + 4); } - child->tss.debug[4] = nsaved; - return 0; + + return res; } -/* Ensure no single-step breakpoint is pending. Returns non-zero +/* + * Ensure no single-step breakpoint is pending. Returns non-zero * value if child was being single-stepped. */ int ptrace_cancel_bpt (struct task_struct *child) { - int i, nsaved = child->tss.debug[4]; + struct debug_info *dbg = &child->tss.debug; + int i, nsaved = dbg->nsaved; - child->tss.debug[4] = 0; + dbg->nsaved = 0; if (nsaved > 2) { - printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); + printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); nsaved = 2; } - for (i = 0; i < nsaved; i++) - write_long (child, child->tss.debug[i], child->tss.debug[i + 2]); + + for (i = 0; i < nsaved; i++) { + unsigned long tmp; + + read_tsk_long(child, dbg->bp[i].address, &tmp); + if (tmp != BREAKINST) + printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n"); + write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn); + } return nsaved != 0; } -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +static int do_ptrace(int request, struct task_struct *child, long addr, long data) { - struct task_struct *child; + unsigned long tmp; int ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->flags & PF_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; - ret = 0; - goto out; - } - if (pid == 1) /* you may not mess with init */ - goto out; - ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) - goto out; - ret = -EPERM; - if (request == PTRACE_ATTACH) { - if (child == current) - goto out; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out; - /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) - goto out; - child->flags |= PF_PTRACED; - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - send_sig(SIGSTOP, child, 1); - ret = 0; - goto out; - } - ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) - goto out; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out; - } - if (child->p_pptr != current) - goto out; - switch (request) { - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - - ret = read_long(child, addr, &tmp); - if (ret >= 0) - ret = put_user(tmp, (unsigned long *)data); - goto out; - } - - case PTRACE_PEEKUSR: { /* read the word at location addr in the USER area. */ - unsigned long tmp; + /* + * read word at location "addr" in the child process. + */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + ret = read_tsk_long(child, addr, &tmp); + if (!ret) + ret = put_user(tmp, (unsigned long *) data); + break; + /* + * read the word at location "addr" in the user registers. + */ + case PTRACE_PEEKUSR: ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - goto out; + break; tmp = 0; /* Default return condition */ - if (addr < sizeof (struct pt_regs)) + if (addr < sizeof(struct pt_regs)) tmp = get_stack_long(child, (int)addr >> 2); ret = put_user(tmp, (unsigned long *)data); - goto out; - } + break; - case PTRACE_POKETEXT: /* write the word at location addr. */ + /* + * write the word at location addr. + */ + case PTRACE_POKETEXT: case PTRACE_POKEDATA: - ret = write_long(child,addr,data); - goto out; + ret = write_tsk_long(child, addr, data); + break; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + /* + * write the word at location addr in the user registers. + */ + case PTRACE_POKEUSR: ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - goto out; + break; - if (addr < sizeof (struct pt_regs)) + if (addr < sizeof(struct pt_regs)) ret = put_stack_long(child, (int)addr >> 2, data); - goto out; + break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ + /* + * continue/restart and stop at next (return from) syscall + */ + case PTRACE_SYSCALL: + case PTRACE_CONT: ret = -EIO; if ((unsigned long) data > _NSIG) - goto out; + break; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else child->flags &= ~PF_TRACESYS; child->exit_code = data; - wake_up_process (child); /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); + ptrace_cancel_bpt(child); + wake_up_process(child); ret = 0; - goto out; + break; - /* make the child exit. Best I can do is send it a sigkill. + /* + * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: - if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; - wake_up_process (child); + /* already dead */ + ret = 0; + if (child->state == TASK_ZOMBIE) + break; child->exit_code = SIGKILL; /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); + ptrace_cancel_bpt(child); + wake_up_process(child); ret = 0; - goto out; + break; - case PTRACE_SINGLESTEP: /* execute single instruction. */ + /* + * execute single instruction. + */ + case PTRACE_SINGLESTEP: ret = -EIO; if ((unsigned long) data > _NSIG) - goto out; - child->tss.debug[4] = -1; + break; + child->tss.debug.nsaved = -1; child->flags &= ~PF_TRACESYS; - wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ + wake_up_process(child); ret = 0; - goto out; - - case PTRACE_GETREGS: - { /* Get all gp regs from the child. */ - unsigned char *stack; + break; + /* + * detach a process that was attached. + */ + case PTRACE_DETACH: + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + /* make sure single-step breakpoint is gone. */ + ptrace_cancel_bpt (child); + wake_up_process (child); ret = 0; - stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs)); - if (copy_to_user((void *)data, stack, + break; + + /* + * Get all gp regs from the child. + */ + case PTRACE_GETREGS: { + struct pt_regs *regs = get_user_regs(child); + + ret = 0; + if (copy_to_user((void *)data, regs, sizeof(struct pt_regs))) ret = -EFAULT; - goto out; - }; + break; + } - /* Set all gp regs in the child. */ - case PTRACE_SETREGS: - { + /* + * Set all gp regs in the child. + */ + case PTRACE_SETREGS: { struct pt_regs newregs; ret = -EFAULT; @@ -737,44 +753,103 @@ ret = 0; } } - goto out; + break; } + /* + * Get the child FPU state. + */ case PTRACE_GETFPREGS: - /* Get the child FPU state. */ - ret = 0; - if (copy_to_user((void *)data, &child->tss.fpstate, - sizeof(struct user_fp))) - ret = -EFAULT; - goto out; - - case PTRACE_SETFPREGS: - /* Set the child FPU state. */ - ret = 0; - if (copy_from_user(&child->tss.fpstate, (void *)data, - sizeof(struct user_fp))) - ret = -EFAULT; - goto out; + ret = -EIO; + if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp))) + break; + + /* we should check child->used_math here */ + ret = __copy_to_user((void *)data, &child->tss.fpstate, + sizeof(struct user_fp)) ? -EFAULT : 0; + break; - case PTRACE_DETACH: /* detach a process that was attached. */ + /* + * Set the child FPU state. + */ + case PTRACE_SETFPREGS: ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); - wake_up_process (child); - child->exit_code = data; - REMOVE_LINKS(child); - child->p_pptr = child->p_opptr; - SET_LINKS(child); - /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); - ret = 0; - goto out; + if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp))) + break; + + child->used_math = 1; + ret = __copy_from_user(&child->tss.fpstate, (void *)data, + sizeof(struct user_fp)) ? -EFAULT : 0; + break; default: ret = -EIO; + break; + } + + return ret; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) goto out; + /* set the ptrace bit in the process flags. */ + current->flags |= PF_PTRACED; + ret = 0; + goto out; } + ret = -ESRCH; + if (!(child = find_task_by_pid(pid))) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out; + + if (request == PTRACE_ATTACH) { + if (child == current) + goto out; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out; + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) + goto out; + child->flags |= PF_PTRACED; + + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out; + } + ret = -ESRCH; + if (!(child->flags & PF_PTRACED)) + goto out; + if (child->state != TASK_STOPPED && request != PTRACE_KILL) + goto out; + if (child->p_pptr != current) + goto out; + + ret = do_ptrace(request, child, addr, data); + out: unlock_kernel(); return ret; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.2.18/arch/arm/kernel/signal.c Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/kernel/signal.c Sun Mar 25 11:37:29 2001 @@ -539,6 +539,7 @@ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); + single_stepping |= ptrace_cancel_bpt(current); continue; case SIGQUIT: case SIGILL: case SIGTRAP: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/lib/delay.S linux/arch/arm/lib/delay.S --- v2.2.18/arch/arm/lib/delay.S Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/lib/delay.S Sun Mar 25 11:37:29 2001 @@ -9,17 +9,24 @@ LC0: .word SYMBOL_NAME(loops_per_jiffy) +/* + * 0 <= r0 <= 2000 + */ ENTRY(udelay) - mov r2, #0x1000 - orr r2, r2, #0x00c6 + mov r2, #0x00006800 + orr r2, r2, #0x000000db mul r1, r0, r2 ldr r2, LC0 ldr r2, [r2] mov r1, r1, lsr #11 mov r2, r2, lsr #11 mul r0, r1, r2 - movs r0, r0, lsr #10 + movs r0, r0, lsr #6 RETINSTR(moveq,pc,lr) + +/* + * loops = (r0 * 0x10c6 * 100 * loops_per_jiffie) / 2^32 + */ @ Delay routine ENTRY(__delay) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/lib/memset.S linux/arch/arm/lib/memset.S --- v2.2.18/arch/arm/lib/memset.S Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/lib/memset.S Sun Mar 25 11:37:29 2001 @@ -1,88 +1,80 @@ /* - * linux/arch/arm/lib/memset.S + * linux/arch/arm/lib/memset.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-2000 Russell King * - * ASM optimised string functions + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. * + * ASM optimised string functions */ #include #include -#include "constants.h" - .text - .align 5 -ENTRY(memset) - mov r3, r0 - cmp r2, #16 - blt 6f - ands ip, r3, #3 - beq 1f - cmp ip, #2 - strltb r1, [r3], #1 @ Align destination - strleb r1, [r3], #1 - strb r1, [r3], #1 - rsb ip, ip, #4 - sub r2, r2, ip -1: orr r1, r1, r1, lsl #8 - orr r1, r1, r1, lsl #16 - cmp r2, #256 - blt 4f - stmfd sp!, {r4, r5, lr} - mov r4, r1 - mov r5, r1 - mov lr, r1 - mov ip, r2, lsr #6 - sub r2, r2, ip, lsl #6 -2: stmia r3!, {r1, r4, r5, lr} @ 64 bytes at a time. - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - subs ip, ip, #1 - bne 2b - teq r2, #0 - LOADREGS(eqfd, sp!, {r4, r5, pc}) @ Now <64 bytes to go. - tst r2, #32 - stmneia r3!, {r1, r4, r5, lr} - stmneia r3!, {r1, r4, r5, lr} - tst r2, #16 - stmneia r3!, {r1, r4, r5, lr} - ldmia sp!, {r4, r5} -3: tst r2, #8 - stmneia r3!, {r1, lr} - tst r2, #4 - strne r1, [r3], #4 - tst r2, #2 - strneb r1, [r3], #1 - strneb r1, [r3], #1 - tst r2, #1 - strneb r1, [r3], #1 - LOADREGS(fd, sp!, {pc}) + .text + .align 5 + .word 0 -4: movs ip, r2, lsr #3 - beq 3b - sub r2, r2, ip, lsl #3 - stmfd sp!, {lr} - mov lr, r1 - subs ip, ip, #4 -5: stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - subges ip, ip, #4 - bge 5b - tst ip, #2 - stmneia r3!, {r1, lr} - stmneia r3!, {r1, lr} - tst ip, #1 - stmneia r3!, {r1, lr} - teq r2, #0 - LOADREGS(eqfd, sp!, {pc}) - b 3b +1: subs r2, r2, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r1, [r0], #1 @ 1 + strleb r1, [r0], #1 @ 1 + strb r1, [r0], #1 @ 1 + add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * memzero again. + */ -6: subs r2, r2, #1 - strgeb r1, [r3], #1 - bgt 6b - RETINSTR(mov, pc, lr) +ENTRY(memset) + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * we know that the pointer in r0 is aligned to a word boundary. + */ + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + mov r3, r1 + cmp r2, #16 + blt 4f +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! + mov ip, r1 + mov lr, r1 +2: subs r2, r2, #64 + stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time. + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + bgt 2b + LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go. +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r2, #32 + stmneia r0!, {r1, r3, ip, lr} + stmneia r0!, {r1, r3, ip, lr} + tst r2, #16 + stmneia r0!, {r1, r3, ip, lr} + ldr lr, [sp], #4 +4: tst r2, #8 + stmneia r0!, {r1, r3} + tst r2, #4 + strne r1, [r0], #4 +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r2, #2 + strneb r1, [r0], #1 + strneb r1, [r0], #1 + tst r2, #1 + strneb r1, [r0], #1 + RETINSTR(mov,pc,lr) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/vmlinux-armo.lds linux/arch/arm/vmlinux-armo.lds --- v2.2.18/arch/arm/vmlinux-armo.lds Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/vmlinux-armo.lds Wed Dec 31 19:00:00 1969 @@ -1,69 +0,0 @@ -/* ld script to make ARM Linux kernel - * taken from the i386 version by Russell King - * Written by Martin Mares - */ -OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - _text = .; /* Text and read-only data */ - .text : { - *(.text) - *(.fixup) - *(.gnu.warning) - } = 0x9090 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } - .kstrtab : { *(.kstrtab) } - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - _etext = .; /* End of text section */ - - . = ALIGN(8192); - .data : { /* Data */ - *(.init.task) - *(.data) - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - . = ALIGN(32768); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(16); /* __setup() commandline parameters */ - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - __initcall_start = .; /* the init functions to be called */ - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(32768); - __init_end = .; - - - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } - _end = . ; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/arm/vmlinux-armv.lds linux/arch/arm/vmlinux-armv.lds --- v2.2.18/arch/arm/vmlinux-armv.lds Sun Mar 25 11:28:16 2001 +++ linux/arch/arm/vmlinux-armv.lds Wed Dec 31 19:00:00 1969 @@ -1,70 +0,0 @@ -/* ld script to make ARM Linux kernel - * taken from the i386 version by Russell King - * Written by Martin Mares - */ -OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - _text = .; /* Text and read-only data */ - .text : { - *(.text) - *(.fixup) - *(.gnu.warning) - } = 0x9090 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } - .kstrtab : { *(.kstrtab) } - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - _etext = .; /* End of text section */ - - . = ALIGN(8192); - .data : { /* Data */ - *(.init.task) - *(.data) - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - . = ALIGN(4096); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(16); /* __setup() commandline parameters */ - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - - __initcall_start = .; /* the init functions to be called */ - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(4096); - __init_end = .; - - - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } - _end = . ; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.2.18/arch/i386/boot/setup.S Sun Mar 25 11:28:16 2001 +++ linux/arch/i386/boot/setup.S Sun Mar 25 11:37:29 2001 @@ -18,7 +18,7 @@ ! March 1993/June 1994 (Christoph.Niemann@linux.org) ! ! add APM BIOS checking by Stephen Rothwell, May 1994 -! (Stephen.Rothwell@canb.auug.org.au) +! (sfr@canb.auug.org.au) ! ! High load stuff, initrd support and position independency ! by Hans Lermen & Werner Almesberger, February 1996 @@ -32,7 +32,7 @@ ! ! ! A20 gating fiddled to work on AMD Elan AmSC4xx series by kira@linuxgrrls.org -! july 1999 +! july 1999 - from a 2.0 patch by Christian Lademann ! #define __ASSEMBLY__ @@ -248,16 +248,46 @@ loader_ok: ! Get memory size (extended mem, kB) - + xor eax, eax + mov [0x1e0], eax #ifndef STANDARD_MEMORY_BIOS_CALL - push ebx + mov [0x1e8], al +meme820: + xor ebx, ebx + mov di,#0x2d0 + +jmpe820: + mov eax,#0x0000e820 + mov edx,#0x534d4150 ! Some biosen trash edx each call + mov ecx,#20 + push ds + pop es + int 0x15 + jc bail820 - xor ebx,ebx ! preload new memory slot with 0k - mov [0x1e0], ebx + cmp eax,#0x534d4150 + jne bail820 - mov ax,#0xe801 - int 0x15 - jc oldstylemem + cmp 16(di),#1 + jne again820 + +good820: + mov al,[0x1e8] + cmp al,#32 + jnl bail820 + + incb [0x1e8] + mov ax,di + add ax,#20 + mov di,ax +again820: + cmp ebx,#0 + jne jmpe820 +bail820: +meme801: + mov ax,#0xe801 + int 0x15 + jc mem88 ! Memory size is in 1 k chunksizes, to avoid confusing loadlin. ! We store the 0xe801 memory size in a completely different place, @@ -266,23 +296,19 @@ ! alternative new memory detection scheme, and it's sensible ! to write everything into the same place.) - and ebx, #0xffff ! clear sign extend - shl ebx, 6 ! and go from 64k to 1k chunks - mov [0x1e0],ebx ! store extended memory size - - and eax, #0xffff ! clear sign extend - add [0x1e0],eax ! and add lower memory into total size. - - ! and fall into the old memory detection code to populate the - ! compatibility slot. + and ebx, #0xffff ! clear sign extend + shl ebx, 6 ! and go from 64k to 1k chunks + mov [0x1e0],ebx ! store extented memory size + + and eax, #0xffff ! clear sign extend + add [0x1e0],eax ! and add lower memory into total size. -oldstylemem: - pop ebx -#else - mov dword ptr [0x1e0], #0 + ! and fall into the old memory detection to populate the + ! compatibility slot. +mem88: #endif - mov ah,#0x88 - int 0x15 + mov ah,#0x88 + int 0x15 mov [2],ax ! Set the keyboard repeat rate to the max @@ -552,46 +578,44 @@ lgdt gdt_48 ! load gdt with whatever appropriate ! that was painless, now we enable A20 - -! if this is SC410 or a few other bits we need to do it with the 'fast' method - - in al,#0x92 ! read "System Control Port A" - or al,#0x02 ! Set "Alternate Gate A20" - Bit - out #0x92,al ! write "System Control Port A" + call empty_8042 ! do it the normal way too, so as not to upset normal machines - - call empty_8042 mov al,#0xD1 ! command write out #0x64,al call empty_8042 + mov al,#0xDF ! A20 on out #0x60,al call empty_8042 +! if this is SC410 or a few other bits we need to do it with the 'fast' method +! +! You must preserve the other bits here. Otherwise embarrasing things +! like laptops powering off on boot happen. Corrected version by Kira +! Brown from Linux 2.2 + + in al,#0x92 ! read "System Control Port A" + or al,#0x02 ! Set "Alternate Gate A20" - Bit + out #0x92,al ! write "System Control Port A" + ! wait until a20 really *is* enabled; it can take a fair amount of ! time on certain systems; Toshiba Tecras are known to have this -! problem. The memory location used here is the int 0x1f vector, -! which should be safe to use; any *unused* memory location < 0xfff0 -! should work here. +! problem. The memory location used here (0x200) is the int 0x80 +! vector, which should be safe to use. -#define TEST_ADDR 0x7c - - push ds xor ax,ax ! segment 0x0000 - mov ds,ax + mov fs,ax dec ax ! segment 0xffff (HMA) mov gs,ax - mov bx,[TEST_ADDR] ! we want to restore the value later a20_wait: - inc ax - mov [TEST_ADDR],ax + inc ax ! unused memory location <0xfff0 + seg fs + mov [0x200],ax ! we use the "int 0x80" vector seg gs - cmp ax,[TEST_ADDR+0x10] + cmp ax,[0x210] ! and its corresponding HMA addr je a20_wait ! loop until no longer aliased - mov [TEST_ADDR],bx ! restore original value - pop ds - + ! make sure any possible coprocessor is properly reset.. xor ax,ax @@ -771,10 +795,17 @@ ! ! Some machines have delusions that the keyboard buffer is always full ! with no keyboard attached... +! +! If there is no keyboard controller, we will usually get 0xff +! to all the reads. With each IO taking a microsecond and +! a timeout of 100,000 iterations, this can take about half a +! second ("delay" == outb to port 0x80). That should be ok, +! and should also be plenty of time for a real keyboard controller +! to empty. empty_8042: push ecx - mov ecx,#0xFFFFFF + mov ecx,#100000 empty_8042_loop: dec ecx @@ -814,7 +845,7 @@ ! Delay is needed after doing I/O ! delay: - .word 0x00eb ! jmp $+2 + out #0x80,al ret ! diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/config.in linux/arch/i386/config.in --- v2.2.18/arch/i386/config.in Sun Mar 25 11:28:16 2001 +++ linux/arch/i386/config.in Sun Mar 25 11:37:29 2001 @@ -12,11 +12,11 @@ mainmenu_option next_comment comment 'Processor type and features' choice 'Processor family' \ - "386 CONFIG_M386 \ - 486/Cx486 CONFIG_M486 \ - 586/K5/5x86/6x86 CONFIG_M586 \ - Pentium/K6/TSC CONFIG_M586TSC \ - PPro/6x86MX CONFIG_M686" PPro + "386 CONFIG_M386 \ + 486/Cx486 CONFIG_M486 \ + 586/K5/5x86/6x86 CONFIG_M586 \ + Pentium/K6/TSC/CyrixIII CONFIG_M586TSC \ + PPro/6x86MX CONFIG_M686" PPro # # Define implied options from the CPU selection here # @@ -33,7 +33,7 @@ define_bool CONFIG_X86_GOOD_APIC y fi -tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE +tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/defconfig linux/arch/i386/defconfig --- v2.2.18/arch/i386/defconfig Sun Mar 25 11:28:16 2001 +++ linux/arch/i386/defconfig Sun Mar 25 11:37:29 2001 @@ -21,6 +21,9 @@ CONFIG_X86_POPAD_OK=y CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set CONFIG_1GB=y # CONFIG_2GB is not set # CONFIG_MATH_EMULATION is not set @@ -58,6 +61,7 @@ CONFIG_BINFMT_MISC=y # CONFIG_PARPORT is not set # CONFIG_APM is not set +# CONFIG_TOSHIBA is not set # # Plug and Play support @@ -100,6 +104,7 @@ CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_HD is not set # @@ -133,6 +138,11 @@ # CONFIG_ATALK is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set @@ -148,6 +158,7 @@ # CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -166,7 +177,6 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set @@ -174,6 +184,7 @@ # CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_DMA is not set @@ -192,7 +203,6 @@ CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set # CONFIG_SCSI_PAS16 is not set @@ -209,6 +219,14 @@ # CONFIG_SCSI_ULTRASTOR is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -218,6 +236,7 @@ # # CONFIG_ARCNET is not set CONFIG_DUMMY=m +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_NET_SB1000 is not set @@ -233,8 +252,8 @@ CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set # CONFIG_APRICOT is not set +# CONFIG_LP486E is not set # CONFIG_CS89x0 is not set -# CONFIG_DM9102 is not set # CONFIG_DE4X5 is not set # CONFIG_DEC_ELCP is not set # CONFIG_DEC_ELCP_OLD is not set @@ -267,9 +286,12 @@ # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set # CONFIG_SEALEVEL_4021 is not set +# CONFIG_SYNCLINK_SYNCPPP is not set +# CONFIG_LANMEDIA is not set # CONFIG_COMX is not set # CONFIG_DLCI is not set # CONFIG_WAN_DRIVERS is not set +# CONFIG_XPEED is not set # CONFIG_SBNI is not set # @@ -323,6 +345,7 @@ # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_INTEL_RNG is not set # # Video For Linux @@ -336,6 +359,11 @@ # CONFIG_FTAPE is not set # +# USB support +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set @@ -363,6 +391,8 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -373,6 +403,7 @@ # # CONFIG_BSD_DISKLABEL is not set # CONFIG_MAC_PARTITION is not set +# CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SMD_DISKLABEL is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_NLS is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.2.18/arch/i386/kernel/Makefile Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/Makefile Sun Mar 25 11:37:29 2001 @@ -15,8 +15,8 @@ O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \ - bluesmoke.o dmi_scan.o -OX_OBJS := i386_ksyms.o + bluesmoke.o +OX_OBJS := i386_ksyms.o dmi_scan.o MX_OBJS := ifdef CONFIG_PCI diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.2.18/arch/i386/kernel/apm.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/apm.c Sun Mar 25 11:37:29 2001 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au) * * Initial development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -23,7 +23,7 @@ * March 1996, Rik Faith (faith@cs.unc.edu): * Prohibit APM BIOS calls unless apm_enabled. * (Thanks to Ulrich Windl ) - * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au) + * April 1996, Stephen Rothwell (sfr@canb.auug.org.au) * Version 1.0 and 1.1 * May 1996, Version 1.2 * Feb 1998, Version 1.3 @@ -36,6 +36,7 @@ * Oct 1999, Version 1.10 * Nov 1999, Version 1.11 * Jan 2000, Version 1.12 + * Feb 2000, Version 1.13 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -55,7 +56,7 @@ * The new replacment for it is, but Linux doesn't yet support this. * Alan Cox Linux 2.1.55 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's - * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by + * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by * Dean Gaudet . * C. Scott Ananian Linux 2.1.87 * 1.5: Fix segment register reloading (in case of bad segments saved @@ -115,7 +116,7 @@ * Make power off under SMP work again. * Fix thinko with initial engaging of BIOS. * Make sure power off only happens on CPU 0 - * (Paul "Rusty" Russell ). + * (Paul "Rusty" Russell ). * Do error notification to user mode if BIOS calls fail. * Move entrypoint offset fix to ...boot/setup.S * where it belongs (Cosmos ). @@ -127,7 +128,7 @@ * scripts that check for it before doing power off * work (Jim Avera ). * 1.13: Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS - * is now the way life works). + * is now the way life works). * Fix thinko in suspend() (wrong return). * 1.13ac: Added apm_battery_horked() for Compal boards (Dell 5000e etc) * @@ -242,8 +243,8 @@ /* * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend. - * This patched by Chad Miller , orig code by David - * Chen + * This patched by Chad Miller , original code by + * David Chen */ #undef INIT_TIMER_AFTER_SUSPEND @@ -326,7 +327,6 @@ #else static int power_off_enabled = 1; #endif -static int dell_crap = 0; /*Set if we find a 5000e */ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); @@ -522,7 +522,7 @@ &dummy, &dummy)) return (eax >> 8) & 0xff; *event = ebx; - if (apm_bios_info.version < 0x0102) + if (apm_info.connection_version < 0x0102) *info = ~0; /* indicate info not valid */ else *info = ecx; @@ -554,7 +554,7 @@ #ifdef ALWAYS_CALL_BUSY clock_slowed = 1; #else - clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0; + clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0; #endif return 1; } @@ -620,7 +620,7 @@ * This may be called on an SMP machine. */ #ifdef CONFIG_SMP - /* Many bioses don't like being called from CPU != 0 */ + /* Some bioses don't like being called from CPU != 0 */ while (cpu_number_map[smp_processor_id()] != 0) { kernel_thread(apm_magic, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); @@ -638,15 +638,15 @@ { u32 eax; - if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED)) + if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED)) return APM_NOT_ENGAGED; if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL, enable, &eax)) return (eax >> 8) & 0xff; if (enable) - apm_bios_info.flags &= ~APM_BIOS_DISABLED; + apm_info.bios.flags &= ~APM_BIOS_DISABLED; else - apm_bios_info.flags |= APM_BIOS_DISABLED; + apm_info.bios.flags |= APM_BIOS_DISABLED; return APM_SUCCESS; } @@ -658,6 +658,8 @@ u32 edx; u32 dummy; + if (apm_info.get_power_status_broken) + return APM_32_UNSUPPORTED; if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0, &eax, &ebx, &ecx, &edx, &dummy)) return (eax >> 8) & 0xff; @@ -677,7 +679,7 @@ u32 edx; u32 esi; - if (apm_bios_info.version < 0x0102) { + if (apm_info.connection_version < 0x0102) { /* pretend we only have one battery. */ if (which != 1) return APM_BAD_DEVICE; @@ -701,15 +703,15 @@ u32 eax; if ((enable == 0) && (device == APM_DEVICE_ALL) - && (apm_bios_info.flags & APM_BIOS_DISABLED)) + && (apm_info.bios.flags & APM_BIOS_DISABLED)) return APM_DISABLED; if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax)) return (eax >> 8) & 0xff; if (device == APM_DEVICE_ALL) { if (enable) - apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; + apm_info.bios.flags &= ~APM_BIOS_DISENGAGED; else - apm_bios_info.flags |= APM_BIOS_DISENGAGED; + apm_info.bios.flags |= APM_BIOS_DISENGAGED; } return APM_SUCCESS; } @@ -931,7 +933,7 @@ if (call->callback(event) && undo) { for (fix = callback_list; fix != call; fix = fix->next) fix->callback(undo); - if (apm_bios_info.version > 0x100) + if (apm_info.connection_version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; } @@ -974,7 +976,7 @@ case APM_USER_SUSPEND: #ifdef CONFIG_APM_IGNORE_USER_SUSPEND - if (apm_bios_info.version > 0x100) + if (apm_info.connection_version > 0x100) apm_set_power_state(APM_STATE_REJECT); break; #endif @@ -1035,7 +1037,7 @@ int err; if ((standbys_pending > 0) || (suspends_pending > 0)) { - if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) { + if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) { pending_count = 4; if (debug) printk(KERN_DEBUG "apm: setting state busy\n"); @@ -1244,18 +1246,6 @@ return 0; } -/* - * This is called by the DMI code when it finds an Inspiron 5000e - * (aka compal reference board). We actually do the check by the BIOS - * vendor name, version and serial so we can extend it to try and catch - * non Dell stuff later. - */ - -void apm_battery_horked(void) -{ - dell_crap = 1; -} - static int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy) { char * p; @@ -1272,14 +1262,14 @@ p = buf; - if ((smp_num_cpus == 1) && (!dell_crap) && + if ((smp_num_cpus == 1) && !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; battery_status = bx & 0xff; if ((cx & 0xff) != 0xff) percentage = cx & 0xff; - if (apm_bios_info.version > 0x100) { + if (apm_info.connection_version > 0x100) { battery_flag = (cx >> 8) & 0xff; if (dx != 0xffff) { units = (dx & 0x8000) ? "min" : "sec"; @@ -1327,9 +1317,9 @@ p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", driver_version, - (apm_bios_info.version >> 8) & 0xff, - apm_bios_info.version & 0xff, - apm_bios_info.flags, + (apm_info.bios.version >> 8) & 0xff, + apm_info.bios.version & 0xff, + apm_info.bios.flags, ac_line_status, battery_status, battery_flag, @@ -1349,22 +1339,28 @@ char * power_stat; char * bat_stat; - if (apm_bios_info.version > 0x100) { - /* - * We only support BIOSs up to version 1.2 - */ - if (apm_bios_info.version > 0x0102) - apm_bios_info.version = 0x0102; - if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) { - /* Fall back to an APM 1.0 connection. */ - apm_bios_info.version = 0x100; + if (apm_info.connection_version == 0) { + apm_info.connection_version = apm_info.bios.version; + if (apm_info.connection_version > 0x100) { + /* + * We only support BIOSs up to version 1.2 + */ + if (apm_info.connection_version > 0x0102) + apm_info.connection_version = 0x0102; + error = apm_driver_version(&apm_info.connection_version); + if (error != APM_SUCCESS) { + apm_error("driver version", error); + /* Fall back to an APM 1.0 connection. */ + apm_info.connection_version = 0x100; + } } } - if (debug && (smp_num_cpus == 1)) { + if (debug) printk(KERN_INFO "apm: Connection version %d.%d\n", - (apm_bios_info.version >> 8) & 0xff, - apm_bios_info.version & 0xff); + (apm_info.connection_version >> 8) & 0xff, + apm_info.connection_version & 0xff); + if (debug && (smp_num_cpus == 1)) { error = apm_get_power_status(&bx, &cx, &dx); if (error) printk(KERN_INFO "apm: power status not available\n"); @@ -1389,7 +1385,7 @@ printk("unknown\n"); else printk("%d%%\n", cx & 0xff); - if (apm_bios_info.version > 0x100) { + if (apm_info.connection_version > 0x100) { printk(KERN_INFO "apm: battery flag 0x%02x, battery life ", (cx >> 8) & 0xff); @@ -1404,7 +1400,7 @@ } #ifdef CONFIG_APM_DO_ENABLE - if (apm_bios_info.flags & APM_BIOS_DISABLED) { + if (apm_info.bios.flags & APM_BIOS_DISABLED) { /* * This call causes my NEC UltraLite Versa 33/C to hang if it * is booted with PM disabled but not in the docking station. @@ -1417,8 +1413,8 @@ } } #endif - if ((apm_bios_info.flags & APM_BIOS_DISENGAGED) - && (apm_bios_info.version > 0x0100)) { + if ((apm_info.bios.flags & APM_BIOS_DISENGAGED) + && (apm_info.connection_version > 0x0100)) { error = apm_engage_power_management(APM_DEVICE_ALL, 1); if (error) { apm_error("engage power management", error); @@ -1482,17 +1478,17 @@ static int __init apm_init(void) { - if (apm_bios_info.version == 0) { + if (apm_info.bios.version == 0) { printk(KERN_INFO "apm: BIOS not found.\n"); return -ENODEV; } printk(KERN_INFO "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", - ((apm_bios_info.version >> 8) & 0xff), - (apm_bios_info.version & 0xff), - apm_bios_info.flags, + ((apm_info.bios.version >> 8) & 0xff), + (apm_info.bios.version & 0xff), + apm_info.bios.flags, driver_version); - if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { + if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) { printk(KERN_INFO "apm: no 32 bit BIOS support\n"); return -ENODEV; } @@ -1501,23 +1497,23 @@ * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1 * but is reportedly a 1.0 BIOS. */ - if (apm_bios_info.version == 0x001) - apm_bios_info.version = 0x100; + if (apm_info.bios.version == 0x001) + apm_info.bios.version = 0x100; /* BIOS < 1.2 doesn't set cseg_16_len */ - if (apm_bios_info.version < 0x102) - apm_bios_info.cseg_16_len = 0; /* 64k */ + if (apm_info.bios.version < 0x102) + apm_info.bios.cseg_16_len = 0; /* 64k */ if (debug) { printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x", - apm_bios_info.cseg, apm_bios_info.offset, - apm_bios_info.cseg_16, apm_bios_info.dseg); - if (apm_bios_info.version > 0x100) + apm_info.bios.cseg, apm_info.bios.offset, + apm_info.bios.cseg_16, apm_info.bios.dseg); + if (apm_info.bios.version > 0x100) printk(" cseg len %x, dseg len %x", - apm_bios_info.cseg_len, - apm_bios_info.dseg_len); - if (apm_bios_info.version > 0x101) - printk(" cseg16 len %x", apm_bios_info.cseg_16_len); + apm_info.bios.cseg_len, + apm_info.bios.dseg_len); + if (apm_info.bios.version > 0x101) + printk(" cseg16 len %x", apm_info.bios.cseg_16_len); printk("\n"); } @@ -1540,16 +1536,16 @@ __va((unsigned long)0x40 << 4)); _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4)); - apm_bios_entry.offset = apm_bios_info.offset; + apm_bios_entry.offset = apm_info.bios.offset; apm_bios_entry.segment = APM_CS; set_base(gdt[APM_CS >> 3], - __va((unsigned long)apm_bios_info.cseg << 4)); + __va((unsigned long)apm_info.bios.cseg << 4)); set_base(gdt[APM_CS_16 >> 3], - __va((unsigned long)apm_bios_info.cseg_16 << 4)); + __va((unsigned long)apm_info.bios.cseg_16 << 4)); set_base(gdt[APM_DS >> 3], - __va((unsigned long)apm_bios_info.dseg << 4)); + __va((unsigned long)apm_info.bios.dseg << 4)); #ifndef APM_RELAX_SEGMENTS - if (apm_bios_info.version == 0x100) { + if (apm_info.bios.version == 0x100) { #endif /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1); @@ -1560,11 +1556,11 @@ #ifndef APM_RELAX_SEGMENTS } else { _set_limit((char *)&gdt[APM_CS >> 3], - (apm_bios_info.cseg_len - 1) & 0xffff); + (apm_info.bios.cseg_len - 1) & 0xffff); _set_limit((char *)&gdt[APM_CS_16 >> 3], - (apm_bios_info.cseg_16_len - 1) & 0xffff); + (apm_info.bios.cseg_16_len - 1) & 0xffff); _set_limit((char *)&gdt[APM_DS >> 3], - (apm_bios_info.dseg_len - 1) & 0xffff); + (apm_info.bios.dseg_len - 1) & 0xffff); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c --- v2.2.18/arch/i386/kernel/cpuid.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/cpuid.c Sun Mar 25 11:37:29 2001 @@ -152,6 +152,7 @@ static void cpuid_exit(void) { + unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); } module_init(cpuid_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c --- v2.2.18/arch/i386/kernel/dmi_scan.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/dmi_scan.c Sun Mar 25 11:37:29 2001 @@ -1,8 +1,8 @@ -#include #include #include #include #include +#include #include struct dmi_header @@ -125,17 +125,19 @@ * < Does it Boot Win98 >-N-- * |Y * [Ship It] + * + * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) + * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) */ - if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0 && - strcmp(dmi_string(dm, data[5]), "A04")==0 && - strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) + if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0) { -#ifdef CONFIG_APM - extern void apm_battery_horked(void); - apm_battery_horked(); - printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling battery reporting.\n"); -#endif + if(strcmp(dmi_string(dm, data[5]), "A04")==0 + && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) + { + apm_info.get_power_status_broken = 1; + printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); + } } break; #ifdef DUMP_DMI diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.2.18/arch/i386/kernel/entry.S Sun Mar 25 11:13:13 2001 +++ linux/arch/i386/kernel/entry.S Sun Mar 25 11:37:29 2001 @@ -267,16 +267,18 @@ pushl %ebx cld movl %es,%cx - xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) + movl ORIG_EAX(%esp), %esi # get the error code + movl ES(%esp), %edi # get the function address + movl %eax, ORIG_EAX(%esp) + movl %ecx, ES(%esp) movl %esp,%edx - xchgl %ecx, ES(%esp) # get the address and save es. - pushl %eax # push the error code - pushl %edx + pushl %esi # push the error code + pushl %edx # push the pt_regs pointer movl $(__KERNEL_DS),%edx movl %dx,%ds movl %dx,%es GET_CURRENT(%ebx) - call *%ecx + call *%edi addl $8,%esp jmp ret_from_exception @@ -331,11 +333,6 @@ ENTRY(coprocessor_segment_overrun) pushl $0 pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun) - jmp error_code - -ENTRY(reserved) - pushl $0 - pushl $ SYMBOL_NAME(do_reserved) jmp error_code ENTRY(double_fault) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c --- v2.2.18/arch/i386/kernel/microcode.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/microcode.c Sun Mar 25 11:37:29 2001 @@ -4,12 +4,13 @@ * Copyright (C) 2000 Tigran Aivazian * * This driver allows to upgrade microcode on Intel processors - * belonging to P6 family - PentiumPro, Pentium II, Pentium III etc. + * belonging to IA32 family - PentiumPro, Pentium II, Pentium III, + * Pentium II Xeon, Pentium III Xeon, Pentium 4 etc. * - * Reference: Section 8.10 of Volume III, Intel Pentium III Manual, - * Order Number 243192 or download from: + * Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual, + * Order Number 245472 or free download from: * - * http://developer.intel.com/design/pentiumii/manuals/243192.htm + * http://developer.intel.com/design/pentium4/manuals/245472.htm * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -30,6 +31,12 @@ * Added MICROCODE_IOCFREE ioctl to clear memory. * 1.05 09 June 2000, Simon Trimmer * Messages for error cases (non intel & no suitable microcode). + * 1.06 07 Dec 2000, Tigran Aivazian + * Pentium 4 support + backported fixes from 2.4 + * 1.07 13 Dec 2000, Tigran Aivazian + * More bugfixes backported from 2.4 + * 1.08 27 Dec 2000, Tigran Aivazian + * Fix: X86_FEATURE_30 was used incorrectly (in a 2.4 manner) */ #include @@ -37,7 +44,6 @@ #include #include #include -#include #include #include @@ -45,45 +51,25 @@ #include #include -#define MICROCODE_MINOR 184 -#define MICROCODE_IOCFREE _IO('6',0) -struct microcode { - unsigned int hdrver; - unsigned int rev; - unsigned int date; - unsigned int sig; - unsigned int cksum; - unsigned int ldrver; - unsigned int pf; - unsigned int reserved[5]; - unsigned int bits[500]; -}; - -#define MICROCODE_VERSION "1.05" +#define MICROCODE_VERSION "1.08" -MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver"); +MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian "); EXPORT_NO_SYMBOLS; /* VFS interface */ static int microcode_open(struct inode *, struct file *); -static int microcode_release(struct inode *, struct file *); static ssize_t microcode_read(struct file *, char *, size_t, loff_t *); static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *); static int microcode_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +/* read()/write()/ioctl() are serialized on this */ +static struct semaphore microcode_sem = MUTEX; /* internal helpers to do the work */ static int do_microcode_update(void); static void do_update_one(void *); -/* - * Bits in microcode_status. (31 bits of room for future expansion) - */ -#define MICROCODE_IS_OPEN 0 /* set if device is in use */ - -static unsigned long microcode_status; - /* the actual array of microcode blocks, each 2048 bytes */ static struct microcode *microcode; static unsigned int microcode_num; @@ -95,7 +81,6 @@ write: microcode_write, ioctl: microcode_ioctl, open: microcode_open, - release: microcode_release, }; static struct miscdevice microcode_dev = { @@ -106,26 +91,23 @@ int __init microcode_init(void) { - int error = 0; - if (misc_register(µcode_dev) < 0) { - printk(KERN_WARNING - "microcode: can't misc_register on minor=%d\n", + printk(KERN_ERR "microcode: can't misc_register on minor=%d\n", MICROCODE_MINOR); - error = 1; + return -EINVAL; } - printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", + printk(KERN_INFO "IA-32 Microcode Update Driver: v%s \n", MICROCODE_VERSION); return 0; } #ifdef MODULE -static void microcode_exit(void) +void cleanup_module(void) { misc_deregister(µcode_dev); if (mc_applied) kfree(mc_applied); - printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", + printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); } @@ -133,34 +115,14 @@ { return microcode_init(); } -void cleanup_module(void) -{ - microcode_exit(); -} #endif -/* - * We enforce only one user at a time here with open/close. - */ static int microcode_open(struct inode *inode, struct file *file) { - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* one at a time, please */ - if (test_and_set_bit(MICROCODE_IS_OPEN, µcode_status)) - return -EBUSY; - - return 0; -} - -static int microcode_release(struct inode *inode, struct file *file) -{ - clear_bit(MICROCODE_IS_OPEN, µcode_status); - return 0; + return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; } -/* a pointer to 'struct update_req' is passed to the IPI handler = do_update_one() +/* * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode */ @@ -174,10 +136,10 @@ int i, error = 0, err; struct microcode *m; - if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0) + if (smp_call_function(do_update_one, NULL, 1, 1) != 0) panic("do_microcode_update(): timed out waiting for other CPUs\n"); - do_update_one((void *)update_req); + do_update_one(NULL); for (i=0; ierr = 1; /* be pessimistic */ - if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6){ - printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num ); + if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || + (c->x86_capability & X86_FEATURE_30) ) { /* IA64 */ + printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num); return; } sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8); - if (c->x86_model >= 5) { - /* get processor flags from BBL_CR_OVRD MSR (0x17) */ - rdmsr(0x17, val[0], val[1]); + if ((c->x86_model >= 5) || (c->x86 > 6)) { + /* get processor flags from MSR 0x17 */ + rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); pf = 1 << ((val[1] >> 18) & 7); } @@ -219,7 +182,12 @@ found=1; - rdmsr(0x8B, val[0], rev); + /* trick, to work even if there was no prior update by the BIOS */ + wrmsr(MSR_IA32_UCODE_REV, 0, 0); + __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); + + /* get current (on-cpu) revision into rev (ignore val[0]) */ + rdmsr(MSR_IA32_UCODE_REV, val[0], rev); if (microcode[i].rev < rev) { printk(KERN_ERR "microcode: CPU%d not 'upgrading' to earlier revision" @@ -241,10 +209,16 @@ break; } - wrmsr(0x79, (unsigned int)(m->bits), 0); + /* write microcode via MSR 0x79 */ + wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0); + + /* serialize */ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); - rdmsr(0x8B, val[0], val[1]); + /* get the current revision from MSR 0x8B */ + rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); + + /* notify the caller of success on this cpu */ req->err = 0; req->slot = i; printk(KERN_ERR "microcode: CPU%d updated from revision " @@ -255,19 +229,27 @@ } if(!found) - printk(KERN_ERR "microcode: found no data for CPU%d (sig=%x, pflags=%d)\n", cpu_num, sig, pf); + printk(KERN_ERR "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n", + cpu_num, sig, pf); } static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) { + ssize_t err = 0; + + down(µcode_sem); if (*ppos >= mc_fsize) - return 0; + goto out; if (*ppos + len > mc_fsize) len = mc_fsize - *ppos; + err = -EFAULT; if (copy_to_user(buf, mc_applied + *ppos, len)) - return -EFAULT; + goto out; *ppos += len; - return len; + err = len; +out: + up(µcode_sem); + return err; } static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos) @@ -279,17 +261,18 @@ sizeof(struct microcode)); return -EINVAL; } + down(µcode_sem); if (!mc_applied) { mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode), GFP_KERNEL); if (!mc_applied) { + up(µcode_sem); printk(KERN_ERR "microcode: out of memory for saved microcode\n"); return -ENOMEM; } memset(mc_applied, 0, mc_fsize); } - lock_kernel(); microcode_num = len/sizeof(struct microcode); microcode = vmalloc(len); if (!microcode) { @@ -310,7 +293,7 @@ out_fsize: vfree(microcode); out_unlock: - unlock_kernel(); + up(µcode_sem); return ret; } @@ -319,15 +302,19 @@ { switch(cmd) { case MICROCODE_IOCFREE: + down(µcode_sem); if (mc_applied) { + int bytes = smp_num_cpus * sizeof(struct microcode); + memset(mc_applied, 0, mc_fsize); kfree(mc_applied); mc_applied = NULL; - printk(KERN_WARNING - "microcode: freed %d bytes\n", mc_fsize); mc_fsize = 0; + printk(KERN_WARNING "microcode: freed %d bytes\n", bytes); + up(µcode_sem); return 0; } + up(µcode_sem); return -ENODATA; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c --- v2.2.18/arch/i386/kernel/msr.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/msr.c Sun Mar 25 11:37:29 2001 @@ -260,6 +260,7 @@ static void msr_exit(void) { + unregister_chrdev(MSR_MAJOR, "cpu/msr"); } module_init(msr_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.2.18/arch/i386/kernel/setup.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/setup.c Sun Mar 25 11:37:29 2001 @@ -73,6 +73,7 @@ #include #include #include +#include /* * Machine setup.. @@ -98,11 +99,12 @@ */ struct drive_info_struct { char dummy[32]; } drive_info; struct screen_info screen_info; -struct apm_bios_info apm_bios_info; +struct apm_info apm_info; struct sys_desc_table_struct { unsigned short length; unsigned char table[0]; }; +struct e820map e820 __initdata = { 0, }; unsigned char aux_device_present; @@ -123,6 +125,8 @@ #define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) #define EXT_MEM_K (*(unsigned short *) (PARAM+2)) #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0)) +#define E820_MAP_NR (*(char*) (PARAM+E820NR)) +#define E820_MAP ((struct e820entry *) (PARAM+E820MAP)) #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40)) #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0)) @@ -269,18 +273,128 @@ } #endif +static void __init add_memory_region(unsigned long long start, + unsigned long long size, int type) +{ + int x = e820.nr_map; + + if (x == E820MAX) { + printk("Ooops! Too many entries in the memory map!\n"); + return; + } + + e820.map[x].addr = start; + e820.map[x].size = size; + e820.map[x].type = type; + e820.nr_map++; +} /* add_memory_region */ + +unsigned long i386_endbase __initdata = 0; + +static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) +{ + /* Only one memory region (or negative)? Ignore it */ + if (nr_map < 2) + return -1; + + do { + unsigned long long start = biosmap->addr; + unsigned long long size = biosmap->size; + unsigned long long end = start + size; + unsigned long type = biosmap->type; + + /* Overflow in 64 bits? Ignore the memory map. */ + if (start > end) + return -1; + + /* + * Some BIOSes claim RAM in the 640k - 1M region. + * Not right. Fix it up. + */ + if (type == E820_RAM) { + if (start < 0x100000ULL && end > i386_endbase) { + if (start < i386_endbase) + add_memory_region(start, i386_endbase-start, type); + if (end <= 0x100000ULL) + continue; + start = 0x100000ULL; + size = end - start; + } + } + add_memory_region(start, size, type); + } while (biosmap++,--nr_map); + return 0; +} + +static void __init print_memory_map(char *who) +{ + int i; + + for (i = 0; i < e820.nr_map; i++) { + printk(" %s: %08lx @ %08lx ", who, + (unsigned long) e820.map[i].size, + (unsigned long) e820.map[i].addr); + switch (e820.map[i].type) { + case E820_RAM: printk("(usable)\n"); + break; + case E820_RESERVED: + printk("(reserved)\n"); + break; + case E820_ACPI: + printk("(ACPI data)\n"); + break; + case E820_NVS: + printk("(ACPI NVS)\n"); + break; + default: printk("type %lu\n", e820.map[i].type); + break; + } + } +} + +static void __init setup_memory_region(void) +{ + char *who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, i386_endbase, E820_RAM); + add_memory_region(HIGH_MEMORY, (mem_size << 10), E820_RAM); + } + printk("BIOS-provided physical RAM map:\n"); + print_memory_map(who); +} /* setup_memory_region */ + static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; -unsigned long i386_endbase __initdata = 0; __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { - unsigned long memory_start, memory_end; + unsigned long memory_start, memory_end = 0; char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; int read_endbase_from_BIOS = 1; + int i; + unsigned long user_mem = 0; #ifdef CONFIG_VISWS visws_get_board_type_and_rev(); @@ -289,7 +403,7 @@ ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; - apm_bios_info = APM_BIOS_INFO; + apm_info.bios = APM_BIOS_INFO; if( SYS_DESC_TABLE.length != 0 ) { MCA_bus = SYS_DESC_TABLE.table[3] &0x2; machine_id = SYS_DESC_TABLE.table[0]; @@ -297,17 +411,7 @@ BIOS_revision = SYS_DESC_TABLE.table[2]; } aux_device_present = AUX_DEVICE_INFO; - memory_end = (1<<20) + (EXT_MEM_K<<10); -#ifndef STANDARD_MEMORY_BIOS_CALL - { - unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10); - /* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */ - if (memory_alt_end > memory_end) - memory_end = memory_alt_end; - } -#endif - memory_end &= PAGE_MASK; #ifdef CONFIG_BLK_DEV_RAM rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); @@ -337,12 +441,12 @@ from += 9+4; boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE; } else { - memory_end = simple_strtoul(from+4, &from, 0); + user_mem = simple_strtoul(from+4, &from, 0); if ( *from == 'K' || *from == 'k' ) { - memory_end = memory_end << 10; + user_mem = user_mem << 10; from++; } else if ( *from == 'M' || *from == 'm' ) { - memory_end = memory_end << 20; + user_mem = user_mem << 20; from++; } } @@ -351,7 +455,6 @@ { if (to != command_line) to--; i386_endbase = simple_strtoul(from+8, &from, 0); - i386_endbase += PAGE_OFFSET; read_endbase_from_BIOS = 0; } c = *(from++); @@ -387,7 +490,35 @@ } i386_endbase = BIOS_ENDBASE; } - i386_endbase += PAGE_OFFSET; + } + + if (!user_mem) + setup_memory_region(); + else { + e820.nr_map = 0; + add_memory_region(0, i386_endbase, E820_RAM); + add_memory_region(HIGH_MEMORY, user_mem-HIGH_MEMORY, E820_RAM); + printk("USER-provided physical RAM map:\n"); + print_memory_map("USER"); + } + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) + for (i = 0; i < e820.nr_map; i++) { + unsigned long long start, end; + /* RAM? */ + if (e820.map[i].type != E820_RAM) + continue; + start = e820.map[i].addr; + if (start >= 0xffffffff) + continue; + end = e820.map[i].addr + e820.map[i].size; + if (start >= end) + continue; + if (end > 0xffffffff) + end = 0xffffffff; + if (end > memory_end) + memory_end = end; } #define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */ @@ -1147,7 +1278,9 @@ wrmsr(0x1107, lv, hv); /* Cyrix III */ c->x86_capability |= X86_FEATURE_CX8; - rdmsr(0x80000001, lv, hv); + + /* Check for 3dnow */ + cpuid(0x80000001, &lv, &lv, &lv, &hv); if(hv&(1<<31)) c->x86_capability |= X86_FEATURE_AMD3D; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.2.18/arch/i386/kernel/smp.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/smp.c Sun Mar 25 11:37:29 2001 @@ -680,7 +680,7 @@ */ unsigned long __init smp_alloc_memory(unsigned long mem_base) { - if (mem_base + PAGE_SIZE > i386_endbase) + if (mem_base + PAGE_SIZE > i386_endbase + PAGE_OFFSET) panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.", mem_base); trampoline_base = (void *)mem_base; return mem_base + PAGE_SIZE; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.2.18/arch/i386/kernel/time.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/time.c Sun Mar 25 11:37:30 2001 @@ -176,6 +176,14 @@ count |= inb_p(0x40) << 8; + /* VIA686a test code... reset the latch if count > max */ + if (count > LATCH-1) { + outb_p(0x34, 0x43); + outb_p(LATCH & 0xff, 0x40); + outb(LATCH >> 8, 0x40); + count = LATCH - 1; + } + /* * avoiding timer inconsistencies (they are rare, but they happen)... * there are two kinds of problems that must be avoided here: @@ -468,6 +476,22 @@ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; + + /* VIA686a test code... reset the latch if count > max */ + if (count > LATCH-1) { + static int last_whine; + outb_p(0x34, 0x43); + outb_p(LATCH & 0xff, 0x40); + outb(LATCH >> 8, 0x40); + count = LATCH - 1; + if(time_after(jiffies, last_whine)) + { + printk(KERN_WARNING "probable hardware bug: clock timer configuration lost - probably a VIA686a.\n"); + printk(KERN_WARNING "probable hardware bug: restoring chip configuration.\n"); + last_whine = jiffies + HZ; + } + } + #if 0 spin_unlock(&i8253_lock); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.2.18/arch/i386/kernel/traps.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/kernel/traps.c Sun Mar 25 11:37:30 2001 @@ -106,7 +106,6 @@ asmlinkage void general_protection(void); asmlinkage void page_fault(void); asmlinkage void coprocessor_error(void); -asmlinkage void reserved(void); asmlinkage void alignment_check(void); asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); @@ -156,7 +155,7 @@ printk("\nStack: "); stack = (unsigned long *) esp; for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) + if (((long) stack & 8191) == 0) break; if (i && ((i % 8) == 0)) printk("\n "); @@ -171,7 +170,7 @@ module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { + while (((long) stack & 8191) != 0) { addr = *stack++; /* * If the address is either in the text segment of the @@ -246,7 +245,6 @@ DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) -DO_ERROR(18, SIGSEGV, "reserved", reserved, current) /* I don't have documents for this but it does seem to cover the cache flush from user space exception some people get. */ DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.2.18/arch/i386/mm/init.c Sun Mar 25 11:28:17 2001 +++ linux/arch/i386/mm/init.c Sun Mar 25 11:37:30 2001 @@ -27,6 +27,7 @@ #include #include #include +#include extern void show_net_buffers(void); extern unsigned long init_smp_mappings(unsigned long); @@ -384,8 +385,6 @@ printk(".\n"); } -extern unsigned long i386_endbase; - __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) { unsigned long start_low_mem = PAGE_SIZE; @@ -417,15 +416,36 @@ #endif start_mem = PAGE_ALIGN(start_mem); - while (start_low_mem < i386_endbase) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); - start_low_mem += PAGE_SIZE; - } + for (tmp = __pa(start_low_mem); tmp < __pa(end_mem); + tmp += PAGE_SIZE) { + struct page * page = mem_map + (tmp >> PAGE_SHIFT); + int i; + extern struct e820map e820; - while (start_mem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; + /* don't include kernel memory and bootmem allocations */ + if (tmp >= 0x100000 && tmp < __pa(start_mem)) + continue; + + for (i = 0; i < e820.nr_map; i++) { + unsigned long long start, end; + /* RAM? */ + if (e820.map[i].type != E820_RAM) + continue; + start = e820.map[i].addr; + if (start >= 0xffffffff) + continue; + end = e820.map[i].addr + e820.map[i].size; + if (start >= end) + continue; + if (end > 0xffffffff) + end = 0xffffffff; + + /* start and end are valid here */ + if (start <= tmp && tmp+PAGE_SIZE <= end) + clear_bit(PG_reserved, &page->flags); + } } + for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) { if (tmp >= MAX_DMA_ADDRESS) clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/config.in linux/arch/ppc/config.in --- v2.2.18/arch/ppc/config.in Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/config.in Sun Mar 25 11:37:30 2001 @@ -151,9 +151,11 @@ mainmenu_option next_comment comment 'ISDN subsystem' -tristate 'ISDN support' CONFIG_ISDN -if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in +if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi fi endmenu @@ -176,22 +178,25 @@ mainmenu_option next_comment comment 'Mac device drivers' + if [ "$CONFIG_INPUT_KEYBDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "y" ]; then - bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID + bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID fi if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then - define_bool CONFIG_MAC_HID y - bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES - bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN + define_bool CONFIG_INPUT_KEYBDEV $CONFIG_VT + define_bool CONFIG_INPUT_MOUSEDEV y + define_bool CONFIG_MAC_HID y + bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES + bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN else - bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD - bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE + bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD + bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE fi tristate 'Support for /dev/rtc' CONFIG_PPC_RTC bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL if [ "$CONFIG_MAC_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c --- v2.2.18/arch/ppc/kernel/feature.c Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/kernel/feature.c Sun Mar 25 11:37:30 2001 @@ -2,7 +2,7 @@ * arch/ppc/kernel/feature.c * * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * Ben. Herrenschmidt (bh40@calva.net) + * Ben. Herrenschmidt (benh@kernel.crashing.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.2.18/arch/ppc/kernel/misc.S Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/kernel/misc.S Sun Mar 25 11:37:30 2001 @@ -563,6 +563,14 @@ isync /* Handle erratas in some cases */ blr +_GLOBAL(_get_ICTC) + mfspr r3,ICTC + blr + +_GLOBAL(_set_ICTC) + mtspr ICTC,r3 + blr + /* L2CR functions Copyright İ 1997-1998 by PowerLogix R & D, Inc. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c --- v2.2.18/arch/ppc/kernel/openpic.c Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/kernel/openpic.c Sun Mar 25 11:37:30 2001 @@ -8,8 +8,7 @@ * * Added initialisation code for Apple Core99 machines, tweaked a few things * to avoid bogus interrupts and to make sure the disable function exits with - * the interrupt actually masked. - * Benjamin Herrenschmidt + * the interrupt actually masked. --BenH * Todo: map interrupts to all available CPUs after the ack round * * This file is subject to the terms and conditions of the GNU General Public diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.2.18/arch/ppc/kernel/pmac_setup.c Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/kernel/pmac_setup.c Sun Mar 25 11:37:30 2001 @@ -449,6 +449,16 @@ #ifdef CONFIG_BLK_DEV_IDE_PMAC +void +ide_pmac_init(void) +{ + if (_machine == _MACH_Pmac) + pmu_suspend(); + ide_init(); + if (_machine == _MACH_Pmac) + pmu_resume(); +} + extern kdev_t pmac_find_ide_boot(char *bootdevice, int n); __initfunc(kdev_t find_ide_boot(void)) @@ -657,6 +667,10 @@ ppc_md.set_rtc_time = pmac_set_rtc_time; ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; + + ppc_md.pci_dev_root_bridge = pmac_pci_dev_root_bridge; + ppc_md.pci_dev_mem_base = pmac_pci_dev_mem_base; + ppc_md.pci_dev_io_base = pmac_pci_dev_io_base; #ifdef CONFIG_VT #ifdef CONFIG_MAC_KEYBOARD diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.2.18/arch/ppc/kernel/ppc_ksyms.c Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/kernel/ppc_ksyms.c Sun Mar 25 11:37:30 2001 @@ -5,30 +5,24 @@ #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 @@ -179,10 +173,10 @@ #endif #ifdef __SMP__ -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(cpu_number_map); +EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(_spin_lock); EXPORT_SYMBOL(_spin_unlock); EXPORT_SYMBOL(spin_trylock); @@ -190,6 +184,17 @@ EXPORT_SYMBOL(_read_unlock); EXPORT_SYMBOL(_write_lock); EXPORT_SYMBOL(_write_unlock); + +/* Global SMP irq stuff */ +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(synchronize_bh); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); #endif /* __SMP__ */ EXPORT_SYMBOL(_machine); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.2.18/arch/ppc/kernel/prom.c Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/kernel/prom.c Sun Mar 25 11:37:30 2001 @@ -668,8 +668,8 @@ } #endif - /* If OpenFirmware version >= 3, then use quiesce call */ - if (RELOC(prom_version) >= 3) { + /* If PowerMac, then use quiesce call */ + if (!chrp) { prom_print(RELOC("Calling quiesce ...\n")); call_prom(RELOC("quiesce"), 0, 0); offset = reloc_offset(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/ppc/kernel/sleep.S linux/arch/ppc/kernel/sleep.S --- v2.2.18/arch/ppc/kernel/sleep.S Sun Mar 25 11:28:18 2001 +++ linux/arch/ppc/kernel/sleep.S Sun Mar 25 11:37:30 2001 @@ -1,6 +1,6 @@ /* * This file contains sleep low-level functions for PowerBook G3. - * Copyright (C) 1999 Benjamin Herrenschmidt (bh40@calva.net) + * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) * and Paul Mackerras (paulus@cs.anu.edu.au). * * This program is free software; you can redistribute it and/or diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/config.in linux/arch/s390/config.in --- v2.2.18/arch/s390/config.in Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/config.in Sun Mar 25 11:37:30 2001 @@ -44,11 +44,14 @@ endmenu source drivers/s390/Config.in + +mainmenu_option next_comment comment 'Character devices' bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 fi +endmenu if [ "$CONFIG_NET" = "y" ]; then source net/Config.in diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/Makefile linux/arch/s390/kernel/Makefile --- v2.2.18/arch/s390/kernel/Makefile Sun Mar 25 11:13:31 2001 +++ linux/arch/s390/kernel/Makefile Sun Mar 25 11:37:30 2001 @@ -18,16 +18,15 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ - setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - s390fpu.o s390io.o reipl.o debug.o s390_ext.o s390dyn.o \ - s390mach.o +O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o \ + setup.o sys_s390.o ptrace.o signal.o cpcmd.o \ + s390fpu.o reipl.o s390mach.o -OX_OBJS := s390_ksyms.o +OX_OBJS := debug.o ebcdic.o irq.o process.o s390_ext.o s390_ksyms.o s390dyn.o s390io.o MX_OBJS := ifdef CONFIG_SMP -O_OBJS += smp.o +OX_OBJS += smp.o endif ifeq ($(CONFIG_IEEEFPU_EMULATION),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/cpcmd.c linux/arch/s390/kernel/cpcmd.c --- v2.2.18/arch/s390/kernel/cpcmd.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/cpcmd.c Sun Mar 25 11:37:30 2001 @@ -22,10 +22,10 @@ ASCEBC(obuffer,olen); if (response != NULL && rlen > 0) { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 4,%1\n\t" "O 4,%4\n\t" - "LRA 3,0(0,%2)\n\t" + "LRA 3,0(%2)\n\t" "LR 5,%3\n\t" ".long 0x83240008 # Diagnose 83\n\t" : /* no output */ @@ -34,7 +34,7 @@ : "2", "3", "4", "5" ); EBCASC(response, rlen); } else { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 3,%1\n\t" ".long 0x83230008 # Diagnose 83\n\t" : /* no output */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c --- v2.2.18/arch/s390/kernel/debug.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/debug.c Sun Mar 25 11:37:30 2001 @@ -10,48 +10,58 @@ * Bugreports to: */ +#include #include #include #include #include -#include #include #include -#include #include #include -#ifdef MODULE #include -#endif #include #define MIN(a,b) (((a)<(b))?(a):(b)) - -#if defined(CONFIG_ARCH_S390) -#define DEBUG_PROC_HEADER_SIZE 38 -#endif - -#define ADD_BUFFER 1000 +#define DEBUG_PROLOG_ENTRY -1 /* typedefs */ typedef struct file_private_info { - loff_t len; /* length of output in byte */ - int size; /* size of buffer for output */ - char *data; /* buffer for output */ - debug_info_t *debug_info; /* the debug information struct */ + loff_t offset; /* offset of last read in file */ + int act_area; /* number of last formated area */ + int act_entry; /* last formated entry (offset */ + /* relative to beginning of last */ + /* formated area) */ + size_t act_entry_offset; /* up to this offset we copied */ + /* in last read the last formated */ + /* entry to userland */ + char temp_buf[2048]; /* buffer for output */ + debug_info_t *debug_info_org; /* original debug information */ + debug_info_t *debug_info_snap; /* snapshot of debug information */ struct debug_view *view; /* used view of debug info */ } file_private_info_t; +typedef struct +{ + char *string; + /* + * This assumes that all args are converted into longs + * on L/390 this is the case for all types of parameter + * except of floats, and long long (32 bit) + * + */ + long args[0]; +} debug_sprintf_entry; + + extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); /* internal function prototyes */ static int debug_init(void); -static int debug_format_output(debug_info_t * debug_area, char *buf, - int size, struct debug_view *view); static ssize_t debug_output(struct file *file, char *user_buf, size_t user_len, loff_t * offset); static ssize_t debug_input(struct file *file, const char *user_buf, @@ -65,6 +75,7 @@ struct file_operations *fops); static void debug_delete_proc_dir_entry(struct proc_dir_entry *root, struct proc_dir_entry *entry); +static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size); static void debug_info_get(debug_info_t *); static void debug_info_put(debug_info_t *); static int debug_prolog_level_fn(debug_info_t * id, @@ -72,38 +83,34 @@ static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, struct file *file, const char *user_buf, size_t user_buf_size, loff_t * offset); -static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf); -static int debug_ascii_format_fn(debug_info_t * id, +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf); +static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, char *out_buf, const char *in_buf); -static int debug_ebcdic_format_fn(debug_info_t * id, - struct debug_view *view, char *out_buf, - const char *in_buf); +static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf); + +static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event); /* globals */ -struct debug_view debug_ascii_view = { - "ascii", +struct debug_view debug_raw_view = { + "raw", NULL, - &debug_dflt_header_fn, - &debug_ascii_format_fn, - NULL -}; - -struct debug_view debug_ebcdic_view = { - "ebcdic", + &debug_raw_header_fn, + &debug_raw_format_fn, NULL, - &debug_dflt_header_fn, - &debug_ebcdic_format_fn, NULL }; -struct debug_view debug_hex_view = { - "hex", +struct debug_view debug_hex_ascii_view = { + "hex_ascii", NULL, &debug_dflt_header_fn, - &debug_hex_format_fn, + &debug_hex_ascii_format_fn, + NULL, NULL }; @@ -112,13 +119,26 @@ &debug_prolog_level_fn, NULL, NULL, - &debug_input_level_fn + &debug_input_level_fn, + NULL +}; + +struct debug_view debug_sprintf_view = { + "sprintf", + NULL, + &debug_dflt_header_fn, + (debug_format_proc_t*)&debug_sprintf_format_fn, + NULL, + NULL }; + +unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; + /* static globals */ -static debug_info_t debug_areas[DEBUG_MAX_AREAS]; -static debug_info_t *free_area = 0; +static debug_info_t *debug_area_first = NULL; +static debug_info_t *debug_area_last = NULL; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) static struct semaphore debug_lock = MUTEX; #else @@ -143,10 +163,155 @@ static struct proc_dir_entry *debug_proc_root_entry; - /* functions */ /* + * debug_info_alloc + * - alloc new debug-info + */ + +static debug_info_t* debug_info_alloc(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + int i; + + /* alloc everything */ + + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + if(!rc) + goto fail_malloc_rc; + rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); + if(!rc->active_entry) + goto fail_malloc_active_entry; + memset(rc->active_entry, 0, nr_areas * sizeof(int)); + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) + goto fail_malloc_areas; + for (i = 0; i < nr_areas; i++) { + rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC, + page_order); + if (!rc->areas[i]) { + for (i--; i >= 0; i--) { + free_pages((unsigned long) rc->areas[i], + page_order); + } + goto fail_malloc_areas2; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + /* initialize members */ + + spin_lock_init(&rc->lock); + rc->page_order = page_order; + rc->nr_areas = nr_areas; + rc->active_area = 0; + rc->level = DEBUG_DEFAULT_LEVEL; + rc->buf_size = buf_size; + rc->entry_size = sizeof(debug_entry_t) + buf_size; + strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); + rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; + memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct proc_dir_entry*)); + atomic_set(&(rc->ref_count), 0); + + return rc; + +fail_malloc_areas2: + kfree(rc->areas); +fail_malloc_areas: + kfree(rc->active_entry); +fail_malloc_active_entry: + kfree(rc); +fail_malloc_rc: + return NULL; +} + +/* + * debug_info_free + * - free memory debug-info + */ + +static void debug_info_free(debug_info_t* db_info){ + int i; + for (i = 0; i < db_info->nr_areas; i++) { + free_pages((unsigned long) db_info->areas[i], + db_info->page_order); + } + kfree(db_info->areas); + kfree(db_info->active_entry); + kfree(db_info); +} + +/* + * debug_info_create + * - create new debug-info + */ + +static debug_info_t* debug_info_create(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + + rc = debug_info_alloc(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; + + + /* create proc rood directory */ + + rc->proc_root_entry = + debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, + S_IFDIR | S_IRUGO | S_IXUGO | + S_IWUSR | S_IWGRP, NULL, NULL); + + /* append new element to linked list */ + + if(debug_area_first == NULL){ + /* first element in list */ + debug_area_first = rc; + rc->prev = NULL; + } + else{ + /* append element to end of list */ + debug_area_last->next = rc; + rc->prev = debug_area_last; + } + debug_area_last = rc; + rc->next = NULL; + + debug_info_get(rc); +out: + return rc; +} + +/* + * debug_info_copy + * - copy debug-info + */ + +static debug_info_t* debug_info_copy(debug_info_t* in) +{ + int i; + debug_info_t* rc; + rc = debug_info_alloc(in->name, in->page_order, + in->nr_areas, in->buf_size); + if(!rc) + goto out; + + for(i = 0; i < in->nr_areas; i++){ + memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order); + } +out: + return rc; +} + +/* * debug_info_get * - increments reference count for debug-info */ @@ -179,44 +344,120 @@ } debug_delete_proc_dir_entry(debug_proc_root_entry, db_info->proc_root_entry); - for (i = 0; i < db_info->nr_areas; i++) { - free_pages((unsigned long) db_info->areas[i], - db_info->page_order); - } - kfree(db_info->areas); - db_info->areas = NULL; - *((debug_info_t **) db_info) = free_area; - free_area = db_info; + if(db_info == debug_area_first) + debug_area_first = db_info->next; + if(db_info == debug_area_last) + debug_area_last = db_info->prev; + if(db_info->prev) db_info->prev->next = db_info->next; + if(db_info->next) db_info->next->prev = db_info->prev; + debug_info_free(db_info); } } +/* + * debug_format_entry: + * - format one debug entry and return size of formated data + */ + +static int debug_format_entry(file_private_info_t *p_info) +{ + debug_info_t *id_org = p_info->debug_info_org; + debug_info_t *id_snap = p_info->debug_info_snap; + struct debug_view *view = p_info->view; + debug_entry_t *act_entry; + size_t len = 0; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(id_org, view,p_info->temp_buf); + goto out; + } + + act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] + + p_info->act_entry); + + if (act_entry->id.stck == 0LL) + goto out; /* empty entry */ + if (view->header_proc) + len += view->header_proc(id_org, view, p_info->act_area, + act_entry, p_info->temp_buf + len); + if (view->format_proc) + len += view->format_proc(id_org, view, p_info->temp_buf + len, + DEBUG_DATA(act_entry)); + out: + return len; +} + +/* + * debug_next_entry: + * - goto next entry in p_info + */ + +extern inline int debug_next_entry(file_private_info_t *p_info) +{ + debug_info_t *id = p_info->debug_info_snap; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + p_info->act_entry = 0; + goto out; + } + if ((p_info->act_entry += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) + - id->entry_size)){ + + /* next area */ + p_info->act_entry = 0; + p_info->act_area++; + if(p_info->act_area >= id->nr_areas) + return 1; + } +out: + return 0; +} /* * debug_output: * - called for user read() - * - copies formated output form private_data of the file - * handle to the user buffer + * - copies formated debug entries to the user buffer */ static ssize_t debug_output(struct file *file, /* file descriptor */ char *user_buf, /* user buffer */ - size_t user_len, /* length of buffer */ + size_t len, /* length of buffer */ loff_t *offset /* offset in the file */ ) { - loff_t len; + size_t count = 0; + size_t entry_offset, size = 0; int rc; file_private_info_t *p_info; p_info = ((file_private_info_t *) file->private_data); - if (*offset >= p_info->len) { - return 0; /* EOF */ - } else { - len = MIN(user_len, (p_info->len - *offset)); - if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len))) - return rc;; - (*offset) += len; - return len; /* number of bytes "read" */ + if (*offset != p_info->offset) + return -EPIPE; + if(p_info->act_area >= p_info->debug_info_snap->nr_areas) + return 0; + + entry_offset = p_info->act_entry_offset; + + while(count < len){ + size = debug_format_entry(p_info); + size = MIN((len - count), (size - entry_offset)); + + if(size){ + if ((rc = copy_to_user(user_buf + count, + p_info->temp_buf + entry_offset, size))) + return rc; + } + count += size; + entry_offset = 0; + if(count != len) + if(debug_next_entry(p_info)) + goto out; } +out: + p_info->offset = *offset + count; + p_info->act_entry_offset = size; + *offset = p_info->offset; + return count; } /* @@ -235,69 +476,16 @@ down(&debug_lock); p_info = ((file_private_info_t *) file->private_data); if (p_info->view->input_proc) - rc = p_info->view->input_proc(p_info->debug_info, + rc = p_info->view->input_proc(p_info->debug_info_org, p_info->view, file, user_buf, length, offset); + else + rc = -EPERM; up(&debug_lock); return rc; /* number of input characters */ } /* - * debug_format_output: - * - calls prolog, header and format functions of view to format output - */ - -static int debug_format_output(debug_info_t * debug_area, char *buf, - int size, struct debug_view *view) -{ - int len = 0; - int i, j; - int nr_of_entries; - debug_entry_t *act_entry; - - /* print prolog */ - if (view->prolog_proc) - len += view->prolog_proc(debug_area, view, buf); - /* print debug records */ - if (!(view->format_proc) && !(view->header_proc)) - goto out; - nr_of_entries = PAGE_SIZE / debug_area->entry_size - << debug_area->page_order; - for (i = 0; i < debug_area->nr_areas; i++) { - act_entry = debug_area->areas[i]; - for (j = 0; j < nr_of_entries; j++) { - if (act_entry->id.fields.used == 0) - break; /* empty entry */ - if (view->header_proc) - len += view->header_proc(debug_area, view, i, - act_entry, buf + len); - if (view->format_proc) - len += view->format_proc(debug_area, view, - buf + len, - act_entry->data); - len += sprintf(buf + len, "\n"); - if (len > size) { - printk(KERN_ERR - "debug: error -- memory exceeded for (%s/%s)\n", - debug_area->name, view->name); - printk(KERN_ERR "debug: fix view %s!!\n", - view->name); - printk(KERN_ERR - "debug: area: %i (0 - %i) entry: %i (0 - %i)\n", - i, debug_area->nr_areas - 1, j, - nr_of_entries - 1); - goto out; - } - act_entry = (debug_entry_t *) (((char *) act_entry) + - debug_area->entry_size); - } - } - out: - return len; -} - - -/* * debug_open: * - called for user open() * - copies formated output to private_data area of the file @@ -306,119 +494,68 @@ static int debug_open(struct inode *inode, struct file *file) { - int i, j = 0, size = 0, rc = 0, f_entry_size = 0; + int i = 0, rc = 0; file_private_info_t *p_info; + debug_info_t *debug_info, *debug_info_snapshot; #ifdef DEBUG printk("debug_open\n"); #endif - -#ifdef MODULE MOD_INC_USE_COUNT; -#endif down(&debug_lock); /* find debug log and view */ - for (i = 0; i < DEBUG_MAX_AREAS; i++) { - if (debug_areas[i].areas == NULL) - continue; /* not in use */ - for (j = 0; j < DEBUG_MAX_VIEWS; j++) { - if (debug_areas[i].views[j] == NULL) + debug_info = debug_area_first; + while(debug_info != NULL){ + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (debug_info->views[i] == NULL) continue; - else if (debug_areas[i].proc_entries[j]->low_ino == + else if (debug_info->proc_entries[i]->low_ino == file->f_dentry->d_inode->i_ino) { goto found; /* found view ! */ } } + debug_info = debug_info->next; } /* no entry found */ rc = -EINVAL; goto out; + found: - if ((file->private_data = - kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { - printk(KERN_ERR "debug_open: kmalloc failed\n"); - rc = -ENOMEM; - goto out; - } - p_info = (file_private_info_t *) file->private_data; - /* - * the size for the formated output is calculated - * with the following formula: - * - * prolog-size - * + - * (record header size + record data field size) - * * number of entries per page - * * number of pages per area - * * number of areas - */ - - if (debug_areas[i].views[j]->prolog_proc) - size += - debug_areas[i].views[j]->prolog_proc(&debug_areas[i], - debug_areas[i]. - views[j], NULL); - - if (debug_areas[i].views[j]->header_proc) - f_entry_size = - debug_areas[i].views[j]->header_proc(&debug_areas[i], - debug_areas[i]. - views[j], 0, NULL, - NULL); - if (debug_areas[i].views[j]->format_proc) - f_entry_size += - debug_areas[i].views[j]->format_proc(&debug_areas[i], - debug_areas[i]. - views[j], NULL, - NULL); - if (f_entry_size) - f_entry_size += 1; /* \n in each line */ - - - size += f_entry_size - * (PAGE_SIZE / debug_areas[i].entry_size - << debug_areas[i].page_order) - * debug_areas[i].nr_areas + 1; /* terminating \0 */ -#ifdef DEBUG - printk("debug_open: size: %i\n", size); -#endif + /* make snapshot of current debug areas to get it consistent */ + + debug_info_snapshot = debug_info_copy(debug_info); - /* alloc some bytes more to be safe against bad views */ - if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) { - printk(KERN_ERR "debug_open: vmalloc failed\n"); - vfree(file->private_data); + if(!debug_info_snapshot){ + printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n"); rc = -ENOMEM; goto out; } - p_info->size = size; - p_info->debug_info = &debug_areas[i]; - p_info->view = debug_areas[i].views[j]; - - spin_lock_irq(&debug_areas[i].lock); - - p_info->len = - debug_format_output(&debug_areas[i], p_info->data, size, - debug_areas[i].views[j]); -#ifdef DEBUG - { - int ilen = p_info->len; - printk("debug_open: len: %i\n", ilen); + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + debug_info_free(debug_info_snapshot); + rc = -ENOMEM; + goto out; } -#endif + p_info = (file_private_info_t *) file->private_data; + p_info->offset = 0; + p_info->debug_info_snap = debug_info_snapshot; + p_info->debug_info_org = debug_info; + p_info->view = debug_info->views[i]; + p_info->act_area = 0; + p_info->act_entry = DEBUG_PROLOG_ENTRY; + p_info->act_entry_offset = 0; - spin_unlock_irq(&debug_areas[i].lock); - debug_info_get(&debug_areas[i]); + debug_info_get(debug_info); out: up(&debug_lock); -#ifdef MODULE if (rc != 0) MOD_DEC_USE_COUNT; -#endif return rc; } @@ -434,18 +571,11 @@ #ifdef DEBUG printk("debug_close\n"); #endif - down(&debug_lock); p_info = (file_private_info_t *) file->private_data; - debug_info_put(p_info->debug_info); - if (p_info->data) { - vfree(p_info->data); - kfree(file->private_data); - } - up(&debug_lock); - -#ifdef MODULE + debug_info_free(p_info->debug_info_snap); + debug_info_put(p_info->debug_info_org); + kfree(file->private_data); MOD_DEC_USE_COUNT; -#endif return 0; /* success */ } @@ -522,74 +652,25 @@ (char *name, int page_order, int nr_areas, int buf_size) { debug_info_t *rc = NULL; - int i; -#ifdef MODULE MOD_INC_USE_COUNT; -#endif if (!initialized) debug_init(); down(&debug_lock); - if (!free_area) { - printk(KERN_WARNING "debug: no free debug area for %s\n", - name); - goto out; - } - rc = free_area; - free_area = *((debug_info_t **) rc); - rc->areas = (debug_entry_t **) kmalloc(nr_areas * - sizeof(debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) { - free_area = rc; - rc = NULL; - goto out; - } - for (i = 0; i < nr_areas; i++) { - rc->areas[i] = - (debug_entry_t *) __get_free_pages(GFP_ATOMIC, - page_order); - if (!rc->areas[i]) { - for (i--; i >= 0; i--) { - free_pages((unsigned long) rc->areas[i], - page_order); - } - free_area = rc; - rc = NULL; - goto out; - } else { - memset(rc->areas[i], 0, PAGE_SIZE << page_order); - } - } - rc->page_order = page_order; - rc->nr_areas = nr_areas; - rc->active_area = 0; - rc->level = DEBUG_DEFAULT_LEVEL; - rc->buf_size = buf_size; - rc->entry_size = sizeof(debug_entry_t) - + buf_size - 4; /* must subtract data[4] */ - strncpy(rc->name, name, - MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); - rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; - memset(rc->active_entry, 0, nr_areas * sizeof(int)); - memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); - atomic_set(&(rc->ref_count), 0); - rc->proc_root_entry = - debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, - S_IFDIR | S_IRUGO | S_IXUGO | - S_IWUSR | S_IWGRP, NULL, NULL); + /* create new debug_info */ + + rc = debug_info_create(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; debug_register_view(rc, &debug_level_view); - debug_info_get(rc); printk(KERN_INFO "debug: reserved %d areas of %d pages for debugging %s\n", nr_areas, 1 << page_order, rc->name); out: if (rc == NULL){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif } up(&debug_lock); return rc; @@ -609,20 +690,44 @@ debug_info_put(id); up(&debug_lock); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif out: return; } +/* + * debug_set_level: + * - set actual debug level + */ + +void debug_set_level(debug_info_t* id, int new_level) +{ + unsigned long flags; + if(!id) + return; + spin_lock_irqsave(&id->lock,flags); + if(new_level == DEBUG_OFF_LEVEL){ + id->level = DEBUG_OFF_LEVEL; + printk(KERN_INFO "debug: %s: switched off\n",id->name); + } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { + printk(KERN_INFO + "debug: %s: level %i is out of range (%i - %i)\n", + id->name, new_level, 0, DEBUG_MAX_LEVEL); + } else { + id->level = new_level; + printk(KERN_INFO + "debug: %s: new level %i\n",id->name,id->level); + } + spin_unlock_irqrestore(&id->lock,flags); +} + /* * proceed_active_entry: * - set active entry to next in the ring buffer */ -static inline void proceed_active_entry(debug_info_t * id) +extern inline void proceed_active_entry(debug_info_t * id) { if ((id->active_entry[id->active_area] += id->entry_size) > ((PAGE_SIZE << (id->page_order)) - id->entry_size)) @@ -634,7 +739,7 @@ * - set active area to next in the ring buffer */ -static inline void proceed_active_area(debug_info_t * id) +extern inline void proceed_active_area(debug_info_t * id) { id->active_area++; id->active_area = id->active_area % id->nr_areas; @@ -644,7 +749,7 @@ * get_active_entry: */ -static inline debug_entry_t *get_active_entry(debug_info_t * id) +extern inline debug_entry_t *get_active_entry(debug_info_t * id) { return (debug_entry_t *) ((char *) id->areas[id->active_area] + id->active_entry[id->active_area]); @@ -655,162 +760,126 @@ * - set timestamp, caller address, cpu number etc. */ -static inline debug_entry_t *debug_common(debug_info_t * id) +extern inline debug_entry_t *debug_common(debug_info_t * id, int level, + const void *buf, int len, int exception) { + unsigned long flags; debug_entry_t *active; + spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); STCK(active->id.stck); active->id.fields.cpuid = smp_processor_id(); - active->id.fields.used = 1; active->caller = __builtin_return_address(0); - return active; -} - -/* - * debug_event: - */ - -debug_entry_t *debug_event(debug_info_t * id, int level, void *buf, - int len) -{ - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 0; - memset(active->data, 0, id->buf_size); - memcpy(active->data, buf, MIN(len, id->buf_size)); + active->id.fields.exception = exception; + active->id.fields.level = level; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); proceed_active_entry(id); + if(exception) + proceed_active_area(id); spin_unlock_irqrestore(&id->lock, flags); - out: + return active; } /* - * debug_int_event: + * debug_event_common: + * - write debug entry with given size */ -debug_entry_t *debug_int_event(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf, + int len) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 0; - memset(active->data, 0, id->buf_size); - memcpy(active->data, &tag, MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + return debug_common(id, level, buf, len, 0); } /* - * debug_text_event: + * debug_exception_common: + * - write debug entry with given size and switch to next debug area */ -debug_entry_t *debug_text_event(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_exception_common(debug_info_t * id, int level, + const void *buf, int len) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - memset(active->data, 0, id->buf_size); - strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); - ASCEBC(active->data, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 0; - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; - + return debug_common(id, level, buf, len, 1); } /* - * debug_exception: + * counts arguments in format string for sprintf view */ -debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, - int len) +extern inline int debug_count_numargs(char *string) { - long flags; - debug_entry_t *active = NULL; + int numargs=0; - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(active->data, 0, id->buf_size); - memcpy(active->data, buf, MIN(len, id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + while(*string) { + if(*string++=='%') + numargs++; + } + return(numargs); } /* - * debug_int_exception: + * debug_sprintf_event: */ -debug_entry_t *debug_int_exception(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_sprintf_event(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(active->data, 0, id->buf_size); - memcpy(active->data, &tag, - MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idxargs[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,0); + va_end(ap); + } + return retval; + } } /* - * debug_text_exception: + * debug_sprintf_exception: */ -debug_entry_t *debug_text_exception(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_sprintf_exception(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - memset(active->data, 0, id->buf_size); - strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); - ASCEBC(active->data, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 1; - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idxargs[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,1); + va_end(ap); + } + return retval; + } } /* @@ -821,7 +890,6 @@ int debug_init(void) { int rc = 0; - int i; down(&debug_lock); if (!initialized) { @@ -830,15 +898,7 @@ S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP, NULL, NULL); - for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) { - *(debug_info_t **) (&debug_areas[i]) = - (debug_info_t *) (&debug_areas[i + 1]); - } - *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL; - free_area = &(debug_areas[0]); - printk(KERN_INFO - "debug: %d areas reserved for debugging information\n", - DEBUG_MAX_AREAS); + printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; } up(&debug_lock); @@ -854,7 +914,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; mode_t mode = S_IFREG; if (!id) @@ -897,7 +957,7 @@ { int rc = 0; int i; - long flags; + unsigned long flags; if (!id) goto out; @@ -933,12 +993,8 @@ { int rc = 0; - if (out_buf == NULL) { - rc = 2; - goto out; - } - rc = sprintf(out_buf, "%i\n", id->level); - out: + if(id->level == -1) rc = sprintf(out_buf,"-\n"); + else rc = sprintf(out_buf, "%i\n", id->level); return rc; } @@ -955,20 +1011,15 @@ if (*offset != 0) goto out; - if ((rc = copy_from_user(input_buf, user_buf, 1))) + if (copy_from_user(input_buf, user_buf, 1)){ + rc = -EFAULT; goto out; + } if (isdigit(input_buf[0])) { int new_level = ((int) input_buf[0] - (int) '0'); - if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { - printk(KERN_INFO - "debug: level %i is out of range (%i - %i)\n", - new_level, 0, DEBUG_MAX_LEVEL); - } else { - id->level = new_level; - printk(KERN_INFO - "debug: set new level %i for %s\n", - id->level, id->name); - } + debug_set_level(id, new_level); + } else if(input_buf[0] == '-') { + debug_set_level(id, DEBUG_OFF_LEVEL); } else { printk(KERN_INFO "debug: level `%c` is not valid\n", input_buf[0]); @@ -979,72 +1030,55 @@ } /* - * prints debug data in hex format + * prints debug header in raw format */ -static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf) +int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) { - int i, rc = 0; + int rc; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size * 3; - goto out; - } - for (i = 0; i < id->buf_size; i++) { - rc += sprintf(out_buf + rc, "%02x ", - ((unsigned char *) in_buf)[i]); - } - out: - return rc; + rc = sizeof(debug_entry_t); + memcpy(out_buf,entry,sizeof(debug_entry_t)); + return rc; } /* - * prints debug data in ascii format + * prints debug data in raw format */ -static int debug_ascii_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf) +static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) { - int i, rc = 0; + int rc; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size; - goto out; - } - for (i = 0; i < id->buf_size; i++) { - unsigned char c = in_buf[i]; - if (!isprint(c)) - rc += sprintf(out_buf + rc, "."); - else - rc += sprintf(out_buf + rc, "%c", c); - } - out: + rc = id->buf_size; + memcpy(out_buf, in_buf, id->buf_size); return rc; } /* - * prints debug data in ebcdic format + * prints debug data in hex/ascii format */ -static int debug_ebcdic_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf) +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) { int i, rc = 0; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size; - goto out; - } + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + rc += sprintf(out_buf + rc, "| "); for (i = 0; i < id->buf_size; i++) { unsigned char c = in_buf[i]; - EBCASC(&c, 1); if (!isprint(c)) rc += sprintf(out_buf + rc, "."); else rc += sprintf(out_buf + rc, "%c", c); } - out: + rc += sprintf(out_buf + rc, "\n"); return rc; } @@ -1060,12 +1094,9 @@ char *except_str; unsigned long caller; int rc = 0; + unsigned int level; - if (out_buf == NULL) { - rc = DEBUG_PROC_HEADER_SIZE; - goto out; - } - + level = entry->id.fields.level; time = entry->id.stck; /* adjust todclock to 1970 */ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); @@ -1076,14 +1107,61 @@ else except_str = "-"; caller = (unsigned long) entry->caller; -#if defined(CONFIG_ARCH_S390) +#if defined(CONFIG_ARCH_S390X) + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); +#else caller &= 0x7fffffff; - rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ", - area, time_val.tv_sec, - time_val.tv_usec, except_str, - entry->id.fields.cpuid, caller); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #endif - out: + return rc; +} + +/* + * prints debug data sprintf-formated: + * debug_sprinf_event/exception calls must be used together with this view + */ + +#define DEBUG_SPRINTF_MAX_ARGS 10 + +int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event) +{ + int num_longs, num_used_args = 0,i, rc = 0; + int index[DEBUG_SPRINTF_MAX_ARGS]; + + /* count of longs fit into one entry */ + num_longs = id->buf_size / sizeof(long); + + if(num_longs < 1) + goto out; /* bufsize of entry too small */ + if(num_longs == 1) { + /* no args, we use only the string */ + strcpy(out_buf, curr_event->string); + rc = strlen(curr_event->string); + goto out; + } + + /* number of arguments used for sprintf (without the format string) */ + num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + + memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int)); + + for(i = 0; i < num_used_args; i++) + index[i] = i; + + rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]], + curr_event->args[index[1]], curr_event->args[index[2]], + curr_event->args[index[3]], curr_event->args[index[4]], + curr_event->args[index[5]], curr_event->args[index[6]], + curr_event->args[index[7]], curr_event->args[index[8]], + curr_event->args[index[9]]); + +out: + return rc; } @@ -1118,3 +1196,17 @@ } #endif /* MODULE */ + +EXPORT_SYMBOL(debug_register); +EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_set_level); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); +EXPORT_SYMBOL(debug_event_common); +EXPORT_SYMBOL(debug_exception_common); +EXPORT_SYMBOL(debug_hex_ascii_view); +EXPORT_SYMBOL(debug_raw_view); +EXPORT_SYMBOL(debug_dflt_header_fn); +EXPORT_SYMBOL(debug_sprintf_view); +EXPORT_SYMBOL(debug_sprintf_exception); +EXPORT_SYMBOL(debug_sprintf_event); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/ebcdic.c linux/arch/s390/kernel/ebcdic.c --- v2.2.18/arch/s390/kernel/ebcdic.c Sun Mar 25 11:13:31 2001 +++ linux/arch/s390/kernel/ebcdic.c Sun Mar 25 11:37:30 2001 @@ -9,6 +9,7 @@ * Martin Peschke */ +#include #include /* @@ -389,3 +390,11 @@ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + +EXPORT_SYMBOL_NOVERS(_ascebc_500); +EXPORT_SYMBOL_NOVERS(_ebcasc_500); +EXPORT_SYMBOL_NOVERS(_ascebc); +EXPORT_SYMBOL_NOVERS(_ebcasc); +EXPORT_SYMBOL_NOVERS(_ebc_tolower); +EXPORT_SYMBOL_NOVERS(_ebc_toupper); + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.2.18/arch/s390/kernel/entry.S Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/entry.S Sun Mar 25 11:37:30 2001 @@ -148,11 +148,11 @@ xc 0(4,%r15),0(%r15) ; /* clear back chain */ #define RESTORE_ALL \ - mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ + mvc __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ - ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \ - lpsw __LC_RETURN_PSW /* back to caller */ + lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ + ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ + lpsw __LC_RETURN_PSW /* back to caller */ #define GET_CURRENT /* load pointer to task_struct to R9 */ \ lr %r9,%r15 ; \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S --- v2.2.18/arch/s390/kernel/head.S Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/head.S Sun Mar 25 11:37:30 2001 @@ -5,7 +5,7 @@ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com), - * Rob van der Heij + * Rob van der Heij (rvdhei@iae.nl) * * There are 5 different IPL methods * 1) load the image directly into ram at address 0 and do an PSW restart @@ -13,11 +13,18 @@ * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated) * 3) generate the tape ipl header, store the generated image on a tape * and ipl from it + * In case of SL tape you need to IPL 5 times to get past VOL1 etc * 4) generate the vm reader ipl header, move the generated image to the * VM reader (use option NOH!) and do a ipl from reader (VM only) * 5) direct call of start by the SALIPL loader * We use the cpuid to distinguish between VM and native ipl * params for kernel are pushed to 0x10400 (see setup.h) + + Changes: + Okt 25 2000 + added code to skip HDR and EOF to allow SL tape IPL (5 retries) + changed first CCW from rewind to backspace block + */ #include @@ -32,7 +39,7 @@ #define IPL_BS 1024 .org 0 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded - .long 0x07000000,0x60000001 # by ipl to addresses 0-23. + .long 0x27000000,0x60000001 # by ipl to addresses 0-23. .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs). .long 0x00000000,0x00000000 # external old psw .long 0x00000000,0x00000000 # svc old psw @@ -140,7 +147,7 @@ .Lcrash:.long 0x000a0000,0x00000000 .Lldret:.long 0 .Lsnsret: .long 0 -#endif /* CONFIG_IPL_NONE */ +#endif /* CONFIG_IPL_TAPE */ #ifdef CONFIG_IPL_VM #define IPL_BS 0x730 @@ -260,6 +267,7 @@ # # load parameter file from ipl device # +.Lagain1: l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp bas %r14,.Lloader # load parameter file ltr %r2,%r2 # got anything ? @@ -269,6 +277,10 @@ la %r2,895 .Lnotrunc: l %r4,INITRD_START-PARMAREA(%r12) + clc 0(3,%r4),.L_hdr # if it is HDRx + bz .Lagain1 # skip dataset header + clc 0(3,%r4),.L_eof # if it is EOFx + bz .Lagain1 # skip dateset trailer la %r5,0(%r4,%r2) lr %r3,%r2 .Lidebc: @@ -306,6 +318,7 @@ # # load ramdisk from ipl device # +.Lagain2: l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk bas %r14,.Lloader # load ramdisk st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk @@ -313,6 +326,12 @@ bnz .Lrdcont st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it .Lrdcont: + l %r2,INITRD_START-PARMAREA(%r12) + + clc 0(3,%r2),.L_hdr # skip HDRx and EOFx + bz .Lagain2 + clc 0(3,%r2),.L_eof + bz .Lagain2 #ifdef CONFIG_IPL_VM # @@ -340,7 +359,8 @@ .Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" - +.L_eof: .long 0xc5d6c600 /* C'EOF' */ +.L_hdr: .long 0xc8c4d900 /* C'HDR' */ #endif /* CONFIG_IPL */ # @@ -375,7 +395,7 @@ .long 0x83300060 # diag 3,0,x'0060' - storage size b .done .test: - mvc 0x68(8,0),.pgmnw # set up pgm check handler + mvc 0x68(8),.pgmnw # set up pgm check handler l %r2,.fourmeg lr %r3,%r2 bctr %r3,%r0 # 4M-1 @@ -443,7 +463,7 @@ # # find out memory size. # - mvc 104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler slr %r1,%r1 lhi %r2,1 sll %r2,20 @@ -507,7 +527,7 @@ # # find out if we have an IEEE fpu # - mvc 104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0 ldr %f2,%f0 adbr %f0,%f2 # test IEEE add instruction @@ -517,7 +537,7 @@ # # find out if we have the CSP instruction # - mvc 104(8,0),.Lpccsp-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler la %r0,0 lr %r1,%r0 la %r2,.Lflt0-.LPG1(%r13) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c --- v2.2.18/arch/s390/kernel/irq.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/irq.c Sun Mar 25 11:37:30 2001 @@ -11,6 +11,7 @@ * S/390 I/O interrupt processing and I/O request processing is * implemented in arch/s390/kernel/s390io.c */ +#include #include #include #include @@ -426,3 +427,12 @@ } +#ifdef CONFIG_SMP +EXPORT_SYMBOL(s390_bh_lock); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(synchronize_bh); +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/reipl.S linux/arch/s390/kernel/reipl.S --- v2.2.18/arch/s390/kernel/reipl.S Sun Mar 25 11:13:31 2001 +++ linux/arch/s390/kernel/reipl.S Sun Mar 25 11:37:30 2001 @@ -16,7 +16,7 @@ ni .Lctlsave-.Lpg0(%r13),0xef lctl %c0,%c0,.Lctlsave-.Lpg0(%r13) lr %r1,%r2 - mvc __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13) + mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13) stsch .Lschib-.Lpg0(%r13) oi .Lschib+5-.Lpg0(%r13),0x84 .Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 @@ -24,9 +24,9 @@ ssch .Liplorb-.Lpg0(%r13) jz .L001 bas %r14,.Ldisab-.Lpg0(%r13) -.L001: mvc __LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13) +.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13) .Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13) -.Lcont: c %r1,__LC_SUBCHANNEL_ID(%r0) +.Lcont: c %r1,__LC_SUBCHANNEL_ID jnz .Ltpi clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13) jnz .Ltpi @@ -38,7 +38,7 @@ jz .L003 bas %r14,.Ldisab-.Lpg0(%r13) .L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID(%r0) + st %r1,__LC_SUBCHANNEL_ID lpsw 0 sigp 0,0,0(6) .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c --- v2.2.18/arch/s390/kernel/s390_ext.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/s390_ext.c Sun Mar 25 11:37:30 2001 @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -74,4 +75,6 @@ return 0; } +EXPORT_SYMBOL(register_external_interrupt); +EXPORT_SYMBOL(unregister_external_interrupt); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c --- v2.2.18/arch/s390/kernel/s390_ksyms.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/s390_ksyms.c Sun Mar 25 11:37:30 2001 @@ -3,71 +3,15 @@ * * S390 version */ -#include #include -#include -#include #include -#include -#include -#include #include -#include -#include -#include -#include #include #if CONFIG_IP_MULTICAST #include #endif /* - * I/O subsystem - */ -EXPORT_SYMBOL(halt_IO); -EXPORT_SYMBOL(clear_IO); -EXPORT_SYMBOL(do_IO); -EXPORT_SYMBOL(resume_IO); -EXPORT_SYMBOL(ioinfo); -EXPORT_SYMBOL(get_dev_info_by_irq); -EXPORT_SYMBOL(get_dev_info_by_devno); -EXPORT_SYMBOL(get_irq_by_devno); -EXPORT_SYMBOL(get_devno_by_irq); -EXPORT_SYMBOL(get_irq_first); -EXPORT_SYMBOL(get_irq_next); -EXPORT_SYMBOL(read_conf_data); -EXPORT_SYMBOL(read_dev_chars); -EXPORT_SYMBOL(s390_request_irq_special); -EXPORT_SYMBOL(s390_device_register); -EXPORT_SYMBOL(s390_device_unregister); - -EXPORT_SYMBOL(s390_bh_lock); - -EXPORT_SYMBOL(ccw_alloc_request); -EXPORT_SYMBOL(ccw_free_request); - -EXPORT_SYMBOL(register_external_interrupt); -EXPORT_SYMBOL(unregister_external_interrupt); - -/* - * debug feature - */ -EXPORT_SYMBOL(debug_register); -EXPORT_SYMBOL(debug_unregister); -EXPORT_SYMBOL(debug_register_view); -EXPORT_SYMBOL(debug_unregister_view); -EXPORT_SYMBOL(debug_event); -EXPORT_SYMBOL(debug_int_event); -EXPORT_SYMBOL(debug_text_event); -EXPORT_SYMBOL(debug_exception); -EXPORT_SYMBOL(debug_int_exception); -EXPORT_SYMBOL(debug_text_exception); -EXPORT_SYMBOL(debug_hex_view); -EXPORT_SYMBOL(debug_ascii_view); -EXPORT_SYMBOL(debug_ebcdic_view); -EXPORT_SYMBOL(debug_dflt_header_fn); - -/* * memory management */ EXPORT_SYMBOL(init_mm); @@ -92,32 +36,12 @@ EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(_ascebc_500); -EXPORT_SYMBOL_NOVERS(_ebcasc_500); -EXPORT_SYMBOL_NOVERS(_ascebc); -EXPORT_SYMBOL_NOVERS(_ebcasc); -EXPORT_SYMBOL_NOVERS(_ebc_tolower); -EXPORT_SYMBOL_NOVERS(_ebc_toupper); - /* * misc. */ EXPORT_SYMBOL(__copy_from_user_fixup); EXPORT_SYMBOL(__copy_to_user_fixup); EXPORT_SYMBOL(__udelay); -#ifdef CONFIG_SMP -#include -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(synchronize_bh); -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(smp_ctl_set_bit); -EXPORT_SYMBOL(smp_ctl_clear_bit); -EXPORT_SYMBOL(smp_do_callback_all); -#endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(genhd_dasd_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/s390dyn.c linux/arch/s390/kernel/s390dyn.c --- v2.2.18/arch/s390/kernel/s390dyn.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/s390dyn.c Sun Mar 25 11:37:30 2001 @@ -7,6 +7,7 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) */ +#include #include #include @@ -204,3 +205,5 @@ return( pdevreg); } +EXPORT_SYMBOL(s390_device_register); +EXPORT_SYMBOL(s390_device_unregister); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c --- v2.2.18/arch/s390/kernel/s390io.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/s390io.c Sun Mar 25 11:37:30 2001 @@ -8,6 +8,7 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) */ +#include #include #include #include @@ -126,7 +127,7 @@ not_oper_handler_func_t not_oper_handler, unsigned long irqflags, const char *devname, - void *dev_id) + devstat_t *dev_id) { int retval; struct s390_irqaction *action; @@ -204,7 +205,7 @@ NULL, irqflags, devname, - dev_id); + (devstat_t *)dev_id); if ( ret == 0 ) { @@ -2041,6 +2042,7 @@ int ending_status = 0; int allow4handler = 1; int chnchk = 0; + devstat_t *dp; #if 0 int cpu = smp_processor_id(); @@ -2058,7 +2060,8 @@ action = ioinfo[irq]->irq_desc.action; } /* endif */ - + dp = &ioinfo[irq]->devstat; + #ifdef CONFIG_DEBUG_IO /* * It might be possible that a device was not-oper. at the time @@ -2176,8 +2179,26 @@ chnchk = 1; } /* endif */ + if( dp->ii.irb.scsw.ectl==0) + { + issense=0; + } + else if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) + && (dp->ii.irb.scsw.eswf == 0 )) + { + issense = 0; + } + else if ( (dp->ii.irb.scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) + && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)) + { + issense = 0; + } + else + { + issense = dp->ii.irb.esw.esw0.erw.cons; - issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons; + } /* endif */ if ( issense ) { @@ -5524,3 +5545,17 @@ do_reipl( 0x10000 | sch ); } +EXPORT_SYMBOL(halt_IO); +EXPORT_SYMBOL(clear_IO); +EXPORT_SYMBOL(do_IO); +EXPORT_SYMBOL(resume_IO); +EXPORT_SYMBOL(ioinfo); +EXPORT_SYMBOL(get_dev_info_by_irq); +EXPORT_SYMBOL(get_dev_info_by_devno); +EXPORT_SYMBOL(get_irq_by_devno); +EXPORT_SYMBOL(get_devno_by_irq); +EXPORT_SYMBOL(get_irq_first); +EXPORT_SYMBOL(get_irq_next); +EXPORT_SYMBOL(read_conf_data); +EXPORT_SYMBOL(read_dev_chars); +EXPORT_SYMBOL(s390_request_irq_special); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c --- v2.2.18/arch/s390/kernel/setup.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/setup.c Sun Mar 25 11:37:30 2001 @@ -36,6 +36,9 @@ #include #include #include +#include "cpcmd.h" + +extern void reipl(int ipl_device); /* * Machine setup.. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c --- v2.2.18/arch/s390/kernel/signal.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/signal.c Sun Mar 25 11:37:30 2001 @@ -327,6 +327,11 @@ #endif /* Martin wants this for pthreads */ regs->gprs[3] = (addr_t)&frame->sc; + + /* We forgot to include these in the sigcontext. + To avoid breaking binary compatibility, they are passed as args. */ + regs->gprs[4] = current->tss.trap_no; + regs->gprs[5] = current->tss.prot_addr; return; give_sigsegv: @@ -383,7 +388,7 @@ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { /* Are we from a system call? */ - if (regs->orig_gpr2 >= 0) { + if (regs->trap == __LC_SVC_OLD_PSW) { /* If so, check system call restarting.. */ switch (regs->gprs[2]) { case -ERESTARTNOHAND: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c --- v2.2.18/arch/s390/kernel/smp.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/kernel/smp.c Sun Mar 25 11:37:30 2001 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -721,3 +722,7 @@ } } +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_do_callback_all); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/lib/strcmp.S linux/arch/s390/lib/strcmp.S --- v2.2.18/arch/s390/lib/strcmp.S Sun Mar 25 11:13:32 2001 +++ linux/arch/s390/lib/strcmp.S Sun Mar 25 11:37:30 2001 @@ -18,8 +18,8 @@ CLST 2,3 JO .-4 JE strcmp_equal - IC 0,0(0,3) - IC 1,0(0,2) + IC 0,0(3) + IC 1,0(2) SR 1,0 strcmp_equal: LR 2,1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/lib/strncpy.S linux/arch/s390/lib/strncpy.S --- v2.2.18/arch/s390/lib/strncpy.S Sun Mar 25 11:13:32 2001 +++ linux/arch/s390/lib/strncpy.S Sun Mar 25 11:37:30 2001 @@ -20,9 +20,9 @@ SR 0,0 strncpy_loop: ICM 0,1,0(3) # ICM sets the cc, IC does not - LA 3,1(0,3) - STC 0,0(0,1) - LA 1,1(0,1) + LA 3,1(3) + STC 0,0(1) + LA 1,1(1) JZ strncpy_exit # ICM inserted a 0x00 BRCT 4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0 strncpy_exit: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/mm/init.c linux/arch/s390/mm/init.c --- v2.2.18/arch/s390/mm/init.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/mm/init.c Sun Mar 25 11:37:30 2001 @@ -141,7 +141,7 @@ if(pgtable_cache_size > high) { do { if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; + free_pgd_slow(get_pgd_fast()), freed += 2; if(pmd_quicklist) free_pmd_slow(get_pmd_fast()), freed++; if(pte_quicklist) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c --- v2.2.18/arch/s390/tools/dasdfmt/dasdfmt.c Sun Mar 25 11:28:19 2001 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.c Sun Mar 25 11:37:30 2001 @@ -201,7 +201,7 @@ /* fgets(line,sizeof(line),file); omit first line */ while (fgets(line,sizeof(line),file)!=NULL) { - rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i); + rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i); ma=ma_i; mi=mi_i; if ( (rc==3) && @@ -219,7 +219,8 @@ fclose(file); ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \ - "filesystem (are you sure to have the right param line?)\n", + "filesystem (are you sure to have the right parameter " \ + "dasd=xxx?)\n", prog_name); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc/config.in linux/arch/sparc/config.in --- v2.2.18/arch/sparc/config.in Sun Mar 25 11:28:19 2001 +++ linux/arch/sparc/config.in Sun Mar 25 11:37:30 2001 @@ -133,9 +133,11 @@ mainmenu_option next_comment comment 'ISDN subsystem' -tristate 'ISDN support' CONFIG_ISDN -if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in +if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.2.18/arch/sparc/defconfig Sun Mar 25 11:28:19 2001 +++ linux/arch/sparc/defconfig Sun Mar 25 11:37:30 2001 @@ -284,6 +284,7 @@ # CONFIG_BSD_DISKLABEL=y # CONFIG_MAC_PARTITION is not set +# CONFIG_MINIX_SUBPARTITION is not set CONFIG_SMD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_UNIXWARE_DISKLABEL is not set @@ -326,6 +327,7 @@ # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_RU is not set # # Watchdog diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.2.18/arch/sparc/kernel/sys_sunos.c Sun Mar 25 11:28:19 2001 +++ linux/arch/sparc/kernel/sys_sunos.c Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.94.2.5 2000/09/16 14:15:15 davem Exp $ +/* $Id: sys_sunos.c,v 1.94.2.6 2001/02/02 05:16:11 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -712,7 +712,7 @@ struct sunos_nfs_mount_args { struct sockaddr_in *addr; /* file server address */ - struct nfs_fh *fh; /* File handle to be mounted */ + struct nfs3_fh *fh; /* File handle to be mounted */ int flags; /* flags */ int wsize; /* write size in bytes */ int rsize; /* read size in bytes */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.2.18/arch/sparc/kernel/systbls.S Sun Mar 25 11:13:14 2001 +++ linux/arch/sparc/kernel/systbls.S Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.83.2.2 2000/03/24 00:03:18 davem Exp $ +/* $Id: systbls.S,v 1.83.2.4 2001/01/11 19:12:10 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -26,7 +26,7 @@ /*25*/ .long sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause /*30*/ .long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice /*35*/ .long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile -/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall +/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_lfs_syscall /*45*/ .long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl /*55*/ .long sys_reboot, sys_lfs_syscall, sys_symlink, sys_readlink, sys_execve @@ -48,8 +48,8 @@ /*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_lfs_syscall /*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit /*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write -/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall -/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount +/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_lfs_syscall +/*155*/ .long sys_lfs_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall /*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc/lib/strlen_user.S linux/arch/sparc/lib/strlen_user.S --- v2.2.18/arch/sparc/lib/strlen_user.S Sun Mar 25 11:13:15 2001 +++ linux/arch/sparc/lib/strlen_user.S Sun Mar 25 11:37:30 2001 @@ -47,9 +47,7 @@ mov 3, %o0 .align 4 - .global C_LABEL(__strlen_user), C_LABEL(__strnlen_user) -C_LABEL(__strlen_user): - sethi %hi(32768), %o1 + .global C_LABEL(__strnlen_user) C_LABEL(__strnlen_user): mov %o1, %g1 mov %o0, %o1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.2.18/arch/sparc64/config.in Sun Mar 25 11:28:19 2001 +++ linux/arch/sparc64/config.in Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.67.2.13 2000/10/24 21:00:53 davem Exp $ +# $Id: config.in,v 1.67.2.14 2001/01/26 22:26:07 davem Exp $ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # @@ -92,6 +92,7 @@ fi tristate 'SUNW,envctrl support' CONFIG_ENVCTRL tristate '7-Segment Display support' CONFIG_DISPLAY7SEG + tristate 'CP1XXX Hardware Watchdog support' CONFIG_WATCHDOG_CP1XXX fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.2.18/arch/sparc64/defconfig Sun Mar 25 11:28:19 2001 +++ linux/arch/sparc64/defconfig Sun Mar 25 11:37:30 2001 @@ -19,7 +19,7 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y -# CONFIG_SMP is not set +CONFIG_SMP=y CONFIG_SPARC64=y CONFIG_SBUS=y CONFIG_SBUSCHAR=y @@ -100,6 +100,7 @@ CONFIG_PRINTER_READBACK=y CONFIG_ENVCTRL=m CONFIG_DISPLAY7SEG=m +CONFIG_WATCHDOG_CP1XXX=m # # Floppy, IDE, and other block devices @@ -339,6 +340,7 @@ # CONFIG_BSD_DISKLABEL=y # CONFIG_MAC_PARTITION is not set +# CONFIG_MINIX_SUBPARTITION is not set CONFIG_SMD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_UNIXWARE_DISKLABEL is not set @@ -381,6 +383,7 @@ # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_RU is not set # # Watchdog diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c --- v2.2.18/arch/sparc64/kernel/ebus.c Sun Mar 25 11:13:27 2001 +++ linux/arch/sparc64/kernel/ebus.c Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.36.2.5 2000/07/27 01:50:59 davem Exp $ +/* $Id: ebus.c,v 1.36.2.6 2001/01/26 22:26:07 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -46,6 +46,9 @@ #endif #ifdef CONFIG_DISPLAY7SEG extern int d7s_init(void); +#endif +#ifdef CONFIG_WATCHDOG_CP1XXX +extern int wd_init(void); #endif static inline unsigned long ebus_alloc(size_t size) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.2.18/arch/sparc64/kernel/ioctl32.c Sun Mar 25 11:28:20 2001 +++ linux/arch/sparc64/kernel/ioctl32.c Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.62.2.17 2000/11/08 09:43:04 davem Exp $ +/* $Id: ioctl32.c,v 1.62.2.18 2001/01/26 22:26:07 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -63,6 +63,7 @@ #include #include #include +#include #include @@ -3093,6 +3094,17 @@ case AUTOFS_IOC_CATATONIC: case AUTOFS_IOC_PROTOVER: case AUTOFS_IOC_EXPIRE: + + /* Big W for hardware watchdog timers */ + /* WIOC_GETSUPPORT not yet implemented -E */ + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + case WDIOC_GETTEMP: + case WDIOC_SETOPTIONS: + case WDIOC_KEEPALIVE: + case WIOCSTART: + case WIOCSTOP: + case WIOCGSTAT: /* Raw devices */ case _IO(0xac, 0): /* RAW_SETBIND */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.2.18/arch/sparc64/kernel/sparc64_ksyms.c Sun Mar 25 11:28:20 2001 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.58.2.11 2000/10/25 21:17:44 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.58.2.13 2001/01/03 22:05:54 anton Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -167,6 +167,7 @@ EXPORT_SYMBOL_PRIVATE(flushw_user); +EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(flush_dcache_page); EXPORT_SYMBOL(mstk48t02_regs); @@ -209,6 +210,11 @@ /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(get_pmd_slow); +EXPORT_SYMBOL(get_pte_slow); +#ifndef CONFIG_SMP +EXPORT_SYMBOL(pgt_quicklists); +#endif /* math-emu wants this */ EXPORT_SYMBOL(die_if_kernel); @@ -247,7 +253,6 @@ #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91) EXPORT_SYMBOL(strlen); #endif -EXPORT_SYMBOL(__strlen_user); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.2.18/arch/sparc64/kernel/sys_sparc32.c Sun Mar 25 11:28:20 2001 +++ linux/arch/sparc64/kernel/sys_sparc32.c Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.107.2.14 2000/10/10 04:50:50 davem Exp $ +/* $Id: sys_sparc32.c,v 1.107.2.16 2000/12/20 02:45:00 anton Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -3462,7 +3462,7 @@ set_fs (KERNEL_DS); sys_get_kernel_syms(tbl); set_fs (old_fs); - for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) { + for (i = 0; i < len; i++, table++) { if (put_user (tbl[i].value, &table->value) || copy_to_user (table->name, tbl[i].name, 60)) break; @@ -3553,6 +3553,12 @@ s32 gf32_version; }; +struct nfsctl_fdparm32 { + struct sockaddr gd32_addr; + s8 gd32_path[NFS_MAXPATHLEN+1]; + s32 gd32_version; +}; + struct nfsctl_arg32 { s32 ca32_version; /* safeguard */ union { @@ -3561,6 +3567,7 @@ struct nfsctl_export32 u32_export; struct nfsctl_uidmap32 u32_umap; struct nfsctl_fhparm32 u32_getfh; + struct nfsctl_fdparm32 u32_getfd; u32 u32_debug; } u; #define ca32_svc u.u32_svc @@ -3569,6 +3576,7 @@ #define ca32_umap u.u32_umap #define ca32_getfh u.u32_getfh #define ca32_authd u.u32_authd +#define ca32_getfd u.u32_getfd #define ca32_debug u.u32_debug }; @@ -3698,6 +3706,22 @@ return err; } +static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_getfd.gd_addr, + &arg32->ca32_getfd.gd32_addr, + (sizeof(struct sockaddr))); + err |= copy_from_user(&karg->ca_getfd.gd_path, + &arg32->ca32_getfd.gd32_path, + (NFS_MAXPATHLEN+1)); + err |= __get_user(karg->ca_getfd.gd_version, + &arg32->ca32_getfd.gd32_version); + return err; +} + static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32) { int err; @@ -3739,6 +3763,7 @@ err = nfs_clnt32_trans(karg, arg32); break; case NFSCTL_EXPORT: + case NFSCTL_UNEXPORT: err = nfs_exp32_trans(karg, arg32); break; /* This one is unimplemented, be we're ready for it. */ @@ -3748,6 +3773,9 @@ case NFSCTL_GETFH: err = nfs_getfh32_trans(karg, arg32); break; + case NFSCTL_GETFD: + err = nfs_getfd32_trans(karg, arg32); + break; case NFSCTL_LOCKD: /* We still have to copy over the version * because nfsctl still checks that. @@ -3765,7 +3793,11 @@ err = sys_nfsservctl(cmd, karg, kres); set_fs(oldfs); - if(!err && cmd == NFSCTL_GETFH) + if (err) + goto done; + + if((cmd == NFSCTL_GETFH) || + (cmd == NFSCTL_GETFD)) err = nfs_getfh32_res_trans(kres, res32); done: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.2.18/arch/sparc64/kernel/sys_sunos32.c Sun Mar 25 11:28:20 2001 +++ linux/arch/sparc64/kernel/sys_sunos32.c Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.22.2.4 2000/09/16 14:15:15 davem Exp $ +/* $Id: sys_sunos32.c,v 1.22.2.6 2001/02/02 01:30:09 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -677,7 +677,7 @@ struct sunos_nfs_mount_args { struct sockaddr_in *addr; /* file server address */ - struct nfs_fh *fh; /* File handle to be mounted */ + struct nfs3_fh *fh; /* File handle to be mounted */ int flags; /* flags */ int wsize; /* write size in bytes */ int rsize; /* read size in bytes */ @@ -1168,6 +1168,7 @@ (current->tss.kregs->u_regs[UREG_FP] & 0xffffffffUL); if(get_user(arg5, &sp->xxargs[0])) { rval = -EFAULT; + kfree(kmbuf); break; } set_fs(KERNEL_DS); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.2.18/arch/sparc64/kernel/systbls.S Sun Mar 25 11:28:20 2001 +++ linux/arch/sparc64/kernel/systbls.S Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.53.2.5 2000/08/23 04:18:26 davem Exp $ +/* $Id: systbls.S,v 1.53.2.7 2001/01/11 19:12:10 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -27,7 +27,7 @@ /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys32_sendfile -/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall +/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_lfs_syscall .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl .word sys_reboot, sys_lfs_syscall, sys_symlink, sys_readlink, sys32_execve @@ -49,8 +49,8 @@ .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_lfs_syscall /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write -/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount +/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_lfs_syscall + .word sys_lfs_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/lib/strlen_user.S linux/arch/sparc64/lib/strlen_user.S --- v2.2.18/arch/sparc64/lib/strlen_user.S Sun Mar 25 11:13:28 2001 +++ linux/arch/sparc64/lib/strlen_user.S Sun Mar 25 11:37:30 2001 @@ -14,9 +14,7 @@ #define HI_MAGIC 0x80808080 .align 4 - .global __strlen_user, __strnlen_user -__strlen_user: - sethi %hi(32768), %o1 + .global __strnlen_user __strnlen_user: mov %o1, %g1 mov %o0, %o1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.2.18/arch/sparc64/mm/init.c Sun Mar 25 11:13:29 2001 +++ linux/arch/sparc64/mm/init.c Sun Mar 25 11:37:30 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.127.2.8 2000/03/03 23:50:41 davem Exp $ +/* $Id: init.c,v 1.127.2.9 2000/12/11 12:31:06 anton Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -87,6 +87,14 @@ } #endif return freed; +} + +void flush_icache_range(unsigned long start, unsigned long end) +{ + unsigned long kaddr; + + for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) + flush_icache_page(__get_phys(kaddr)); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.2.18/drivers/block/DAC960.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/block/DAC960.c Sun Mar 25 11:37:30 2001 @@ -2,7 +2,7 @@ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - Copyright 1998-2000 by Leonard N. Zubkoff + Copyright 1998-2001 by Leonard N. Zubkoff This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License Version 2 as published by the @@ -19,8 +19,8 @@ */ -#define DAC960_DriverVersion "2.2.9" -#define DAC960_DriverDate "7 September 2000" +#define DAC960_DriverVersion "2.2.10" +#define DAC960_DriverDate "1 February 2001" #include @@ -120,7 +120,7 @@ DAC960_Announce("***** DAC960 RAID Driver Version " DAC960_DriverVersion " of " DAC960_DriverDate " *****\n", Controller); - DAC960_Announce("Copyright 1998-2000 by Leonard N. Zubkoff " + DAC960_Announce("Copyright 1998-2001 by Leonard N. Zubkoff " "\n", Controller); } @@ -521,7 +521,7 @@ DAC960_V1_ClearCommand(Command); Command->CommandType = DAC960_ImmediateCommand; CommandMailbox->Type3.CommandOpcode = CommandOpcode; - CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer); + CommandMailbox->Type3.BusAddress = Virtual_to_Bus32(DataPointer); DAC960_ExecuteCommand(Command); CommandStatus = Command->V1.CommandStatus; DAC960_DeallocateCommand(Command); @@ -549,7 +549,7 @@ CommandMailbox->Type3D.CommandOpcode = CommandOpcode; CommandMailbox->Type3D.Channel = Channel; CommandMailbox->Type3D.TargetID = TargetID; - CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer); + CommandMailbox->Type3D.BusAddress = Virtual_to_Bus32(DataPointer); DAC960_ExecuteCommand(Command); CommandStatus = Command->V1.CommandStatus; DAC960_DeallocateCommand(Command); @@ -583,7 +583,7 @@ CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(DataPointer); + Virtual_to_Bus64(DataPointer); CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -622,7 +622,7 @@ CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(DataPointer); + Virtual_to_Bus64(DataPointer); CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -665,7 +665,7 @@ CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(DataPointer); + Virtual_to_Bus64(DataPointer); CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -710,7 +710,7 @@ CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(DataPointer); + Virtual_to_Bus64(DataPointer); CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -826,9 +826,9 @@ CommandMailbox.TypeX.CommandIdentifier = 0; CommandMailbox.TypeX.CommandOpcode2 = 0x14; CommandMailbox.TypeX.CommandMailboxesBusAddress = - Virtual_to_Bus(Controller->V1.FirstCommandMailbox); + Virtual_to_Bus32(Controller->V1.FirstCommandMailbox); CommandMailbox.TypeX.StatusMailboxesBusAddress = - Virtual_to_Bus(Controller->V1.FirstStatusMailbox); + Virtual_to_Bus32(Controller->V1.FirstStatusMailbox); for (i = 0; i < 2; i++) switch (Controller->HardwareType) { @@ -950,11 +950,11 @@ CommandMailbox.SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox; CommandMailbox.SetMemoryMailbox.HealthStatusBufferSizeKB = 1; CommandMailbox.SetMemoryMailbox.HealthStatusBufferBusAddress = - Virtual_to_Bus(Controller->V2.HealthStatusBuffer); + Virtual_to_Bus64(Controller->V2.HealthStatusBuffer); CommandMailbox.SetMemoryMailbox.FirstCommandMailboxBusAddress = - Virtual_to_Bus(Controller->V2.FirstCommandMailbox); + Virtual_to_Bus64(Controller->V2.FirstCommandMailbox); CommandMailbox.SetMemoryMailbox.FirstStatusMailboxBusAddress = - Virtual_to_Bus(Controller->V2.FirstStatusMailbox); + Virtual_to_Bus64(Controller->V2.FirstStatusMailbox); switch (Controller->HardwareType) { case DAC960_BA_Controller: @@ -1344,7 +1344,7 @@ Command->CommandType = DAC960_ImmediateCommand; Command->Semaphore = Semaphore; Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; - Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB); DCDB->Channel = Channel; DCDB->TargetID = TargetID; DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; @@ -1353,7 +1353,7 @@ DCDB->NoAutomaticRequestSense = false; DCDB->DisconnectPermitted = true; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData); + DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData); DCDB->CDBLength = 6; DCDB->TransferLengthHigh4 = 0; DCDB->SenseLength = sizeof(DCDB->SenseData); @@ -1380,7 +1380,7 @@ Command->Semaphore = Semaphore; DCDB = &DCDBs[Channel]; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber); + DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber); DCDB->SenseLength = sizeof(DCDB->SenseData); DCDB->CDB[0] = 0x12; /* INQUIRY */ DCDB->CDB[1] = 1; /* EVPD = 1 */ @@ -1471,7 +1471,7 @@ CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(InquiryUnitSerialNumber); + Virtual_to_Bus64(InquiryUnitSerialNumber); CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -2541,7 +2541,8 @@ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; - CommandMailbox->Type5.BusAddress = Virtual_to_Bus(Command->RequestBuffer); + CommandMailbox->Type5.BusAddress = + Virtual_to_Bus32(Command->RequestBuffer); } else { @@ -2559,7 +2560,7 @@ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; - CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList); + CommandMailbox->Type5.BusAddress = Virtual_to_Bus32(ScatterGatherList); CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount; while (BufferHeader != NULL) { @@ -2572,7 +2573,7 @@ else { ScatterGatherList[SegmentNumber].SegmentDataPointer = - Virtual_to_Bus(BufferHeader->b_data); + Virtual_to_Bus32(BufferHeader->b_data); ScatterGatherList[SegmentNumber].SegmentByteCount = BufferHeader->b_size; LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size; @@ -2604,7 +2605,7 @@ CommandMailbox->SCSI_10.DataTransferSize = Command->BlockCount << DAC960_BlockSizeBits; CommandMailbox->SCSI_10.RequestSenseBusAddress = - Virtual_to_Bus(&Command->V2.RequestSense); + Virtual_to_Bus64(&Command->V2.RequestSense); CommandMailbox->SCSI_10.PhysicalDevice = Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber]; CommandMailbox->SCSI_10.RequestSenseSize = @@ -2623,7 +2624,7 @@ CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(Command->RequestBuffer); + Virtual_to_Bus64(Command->RequestBuffer); CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -2645,7 +2646,7 @@ Command->SegmentCount; CommandMailbox->SCSI_10.DataTransferMemoryAddress .ExtendedScatterGather.ScatterGatherList0Address = - Virtual_to_Bus(ScatterGatherList); + Virtual_to_Bus64(ScatterGatherList); } else ScatterGatherList = @@ -2662,7 +2663,7 @@ else { ScatterGatherList[SegmentNumber].SegmentDataPointer = - Virtual_to_Bus(BufferHeader->b_data); + Virtual_to_Bus64(BufferHeader->b_data); ScatterGatherList[SegmentNumber].SegmentByteCount = BufferHeader->b_size; LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size; @@ -3047,7 +3048,7 @@ Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits; CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; CommandMailbox->Type5.BusAddress = - Virtual_to_Bus(BufferHeader->b_data); + Virtual_to_Bus32(BufferHeader->b_data); DAC960_QueueCommand(Command); return; } @@ -3103,7 +3104,7 @@ CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; CommandMailbox->Type5.BusAddress = - Virtual_to_Bus(NextBufferHeader->b_data); + Virtual_to_Bus32(NextBufferHeader->b_data); DAC960_QueueCommand(Command); return; } @@ -3116,11 +3117,13 @@ { if (CommandOpcode == DAC960_V1_Enquiry) memcpy(&Controller->V1.NewEnquiry, - Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress), + Bus32_to_Virtual(Command->V1.CommandMailbox + .Type3.BusAddress), sizeof(DAC960_V1_Enquiry_T)); else if (CommandOpcode == DAC960_V1_GetRebuildProgress) memcpy(&Controller->V1.RebuildProgress, - Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress), + Bus32_to_Virtual(Command->V1.CommandMailbox + .Type3.BusAddress), sizeof(DAC960_V1_RebuildProgress_T)); } if (CommandOpcode == DAC960_V1_Enquiry && @@ -3134,18 +3137,25 @@ NewEnquiry->CriticalLogicalDriveCount; if (NewEnquiry->NumberOfLogicalDrives > Controller->LogicalDriveCount) { - int LogicalDriveNumber = Controller->LogicalDriveCount; - while (LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives) - { - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "Now Exists\n", Controller, - LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - LogicalDriveNumber++; - } - Controller->LogicalDriveCount = LogicalDriveNumber; + int LogicalDriveNumber = Controller->LogicalDriveCount - 1; + while (++LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "Now Exists\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + } + if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount) + { + int LogicalDriveNumber = NewEnquiry->NumberOfLogicalDrives - 1; + while (++LogicalDriveNumber < Controller->LogicalDriveCount) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "No Longer Exists\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); } + Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives; if (NewEnquiry->StatusFlags.DeferredWriteError != OldEnquiry->StatusFlags.DeferredWriteError) DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller, @@ -3170,8 +3180,7 @@ NewEnquiry->EventLogSequenceNumber; Controller->V1.NeedErrorTableInformation = true; Controller->V1.NeedDeviceStateInformation = true; - Controller->V1.DeviceStateChannel = 0; - Controller->V1.DeviceStateTargetID = -1; + Controller->V1.StartDeviceStateScan = true; Controller->SecondaryMonitoringTime = jiffies; } if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress || @@ -3230,7 +3239,7 @@ Controller->V1.RebuildFlagPending) { DAC960_V1_Enquiry_T *Enquiry = (DAC960_V1_Enquiry_T *) - Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress); + Bus32_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress); Enquiry->RebuildFlag = Controller->V1.PendingRebuildFlag; Controller->V1.RebuildFlagPending = false; } @@ -3376,6 +3385,9 @@ { Controller->V1.NeedDeviceInquiryInformation = true; Controller->V1.NeedDeviceSerialNumberInformation = true; + Controller->V1.DeviceResetCount + [Controller->V1.DeviceStateChannel] + [Controller->V1.DeviceStateTargetID] = 0; } memcpy(OldDeviceState, NewDeviceState, sizeof(DAC960_V1_DeviceState_T)); @@ -3515,7 +3527,7 @@ Command->V1.CommandMailbox.Type3E.SequenceNumber = Controller->V1.OldEventLogSequenceNumber; Command->V1.CommandMailbox.Type3E.BusAddress = - Virtual_to_Bus(&Controller->V1.EventLogEntry); + Virtual_to_Bus32(&Controller->V1.EventLogEntry); DAC960_QueueCommand(Command); return; } @@ -3525,7 +3537,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetErrorTable; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(&Controller->V1.NewErrorTable); + Virtual_to_Bus32(&Controller->V1.NewErrorTable); DAC960_QueueCommand(Command); return; } @@ -3536,7 +3548,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetRebuildProgress; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(&Controller->V1.RebuildProgress); + Virtual_to_Bus32(&Controller->V1.RebuildProgress); DAC960_QueueCommand(Command); return; } @@ -3552,7 +3564,7 @@ InquiryStandardData->PeripheralDeviceType = 0x1F; Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(DCDB); + Virtual_to_Bus32(DCDB); DCDB->Channel = Controller->V1.DeviceStateChannel; DCDB->TargetID = Controller->V1.DeviceStateTargetID; DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; @@ -3561,7 +3573,7 @@ DCDB->NoAutomaticRequestSense = false; DCDB->DisconnectPermitted = true; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData); + DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData); DCDB->CDBLength = 6; DCDB->TransferLengthHigh4 = 0; DCDB->SenseLength = sizeof(DCDB->SenseData); @@ -3585,7 +3597,7 @@ InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(DCDB); + Virtual_to_Bus32(DCDB); DCDB->Channel = Controller->V1.DeviceStateChannel; DCDB->TargetID = Controller->V1.DeviceStateTargetID; DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; @@ -3595,7 +3607,7 @@ DCDB->DisconnectPermitted = true; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber); + DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber); DCDB->CDBLength = 6; DCDB->TransferLengthHigh4 = 0; DCDB->SenseLength = sizeof(DCDB->SenseData); @@ -3609,35 +3621,31 @@ Controller->V1.NeedDeviceSerialNumberInformation = false; return; } - if (++Controller->V1.DeviceStateTargetID == Controller->Targets) + if (Controller->V1.StartDeviceStateScan) + { + Controller->V1.DeviceStateChannel = 0; + Controller->V1.DeviceStateTargetID = 0; + Controller->V1.StartDeviceStateScan = false; + } + else if (++Controller->V1.DeviceStateTargetID == Controller->Targets) { Controller->V1.DeviceStateChannel++; Controller->V1.DeviceStateTargetID = 0; } - while (Controller->V1.DeviceStateChannel < Controller->Channels) + if (Controller->V1.DeviceStateChannel < Controller->Channels) { - DAC960_V1_DeviceState_T *OldDeviceState = - &Controller->V1.DeviceState[Controller->V1.DeviceStateChannel] - [Controller->V1.DeviceStateTargetID]; - if (OldDeviceState->Present && - OldDeviceState->DeviceType == DAC960_V1_DiskType) - { - Command->V1.CommandMailbox.Type3D.CommandOpcode = - DAC960_V1_GetDeviceState; - Command->V1.CommandMailbox.Type3D.Channel = - Controller->V1.DeviceStateChannel; - Command->V1.CommandMailbox.Type3D.TargetID = - Controller->V1.DeviceStateTargetID; - Command->V1.CommandMailbox.Type3D.BusAddress = - Virtual_to_Bus(&Controller->V1.NewDeviceState); - DAC960_QueueCommand(Command); - return; - } - if (++Controller->V1.DeviceStateTargetID == Controller->Targets) - { - Controller->V1.DeviceStateChannel++; - Controller->V1.DeviceStateTargetID = 0; - } + Controller->V1.NewDeviceState.DeviceState = + DAC960_V1_Device_Dead; + Command->V1.CommandMailbox.Type3D.CommandOpcode = + DAC960_V1_GetDeviceState; + Command->V1.CommandMailbox.Type3D.Channel = + Controller->V1.DeviceStateChannel; + Command->V1.CommandMailbox.Type3D.TargetID = + Controller->V1.DeviceStateTargetID; + Command->V1.CommandMailbox.Type3D.BusAddress = + Virtual_to_Bus32(&Controller->V1.NewDeviceState); + DAC960_QueueCommand(Command); + return; } Controller->V1.NeedDeviceStateInformation = false; } @@ -3647,7 +3655,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetLogicalDriveInformation; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(&Controller->V1.NewLogicalDriveInformation); + Virtual_to_Bus32(&Controller->V1.NewLogicalDriveInformation); DAC960_QueueCommand(Command); return; } @@ -3657,7 +3665,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetRebuildProgress; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(&Controller->V1.RebuildProgress); + Virtual_to_Bus32(&Controller->V1.RebuildProgress); DAC960_QueueCommand(Command); return; } @@ -3667,7 +3675,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_RebuildStat; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(&Controller->V1.RebuildProgress); + Virtual_to_Bus32(&Controller->V1.RebuildProgress); DAC960_QueueCommand(Command); return; } @@ -4045,7 +4053,7 @@ Command->BlockCount << DAC960_BlockSizeBits; CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0].SegmentDataPointer = - Virtual_to_Bus(BufferHeader->b_data); + Virtual_to_Bus64(BufferHeader->b_data); CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0].SegmentByteCount = CommandMailbox->SCSI_10.DataTransferSize; @@ -4106,7 +4114,7 @@ CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(NextBufferHeader->b_data); + Virtual_to_Bus64(NextBufferHeader->b_data); CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4132,12 +4140,9 @@ Controller->LogicalDriveCount = NewControllerInfo->LogicalDevicesPresent; Controller->V2.NeedLogicalDeviceInformation = true; - Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber = 0; Controller->V2.NeedPhysicalDeviceInformation = true; - Controller->V2.PhysicalDeviceIndex = 0; - Controller->V2.NewPhysicalDeviceInformation.Channel = 0; - Controller->V2.NewPhysicalDeviceInformation.TargetID = 0; - Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0; + Controller->V2.StartLogicalDeviceInformationScan = true; + Controller->V2.StartPhysicalDeviceInformationScan = true; Controller->MonitoringAlertMode = (NewControllerInfo->LogicalDevicesCritical > 0 || NewControllerInfo->LogicalDevicesOffline > 0 || @@ -4160,7 +4165,49 @@ unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex; DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo = Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex]; + unsigned int DeviceIndex; + while (PhysicalDeviceInfo != NULL && + (NewPhysicalDeviceInfo->Channel > + PhysicalDeviceInfo->Channel || + (NewPhysicalDeviceInfo->Channel == + PhysicalDeviceInfo->Channel && + (NewPhysicalDeviceInfo->TargetID > + PhysicalDeviceInfo->TargetID || + (NewPhysicalDeviceInfo->TargetID == + PhysicalDeviceInfo->TargetID && + NewPhysicalDeviceInfo->LogicalUnit > + PhysicalDeviceInfo->LogicalUnit))))) + { + DAC960_Critical("Physical Device %d:%d No Longer Exists\n", + Controller, + PhysicalDeviceInfo->Channel, + PhysicalDeviceInfo->TargetID); + Controller->V2.PhysicalDeviceInformation + [PhysicalDeviceIndex] = NULL; + Controller->V2.InquiryUnitSerialNumber + [PhysicalDeviceIndex] = NULL; + kfree(PhysicalDeviceInfo); + kfree(InquiryUnitSerialNumber); + for (DeviceIndex = PhysicalDeviceIndex; + DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1; + DeviceIndex++) + { + Controller->V2.PhysicalDeviceInformation[DeviceIndex] = + Controller->V2.PhysicalDeviceInformation[DeviceIndex+1]; + Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = + Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1]; + } + Controller->V2.PhysicalDeviceInformation + [DAC960_V2_MaxPhysicalDevices-1] = NULL; + Controller->V2.InquiryUnitSerialNumber + [DAC960_V2_MaxPhysicalDevices-1] = NULL; + PhysicalDeviceInfo = + Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex]; + InquiryUnitSerialNumber = + Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex]; + } if (PhysicalDeviceInfo == NULL || (NewPhysicalDeviceInfo->Channel != PhysicalDeviceInfo->Channel) || @@ -4169,14 +4216,14 @@ (NewPhysicalDeviceInfo->LogicalUnit != PhysicalDeviceInfo->LogicalUnit)) { - unsigned int DeviceIndex; PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *) kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC); InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *) kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); - if (InquiryUnitSerialNumber == NULL) + if (InquiryUnitSerialNumber == NULL && + PhysicalDeviceInfo != NULL) { kfree(PhysicalDeviceInfo); PhysicalDeviceInfo = NULL; @@ -4189,21 +4236,6 @@ ? "" : " - Allocation Failed")); if (PhysicalDeviceInfo != NULL) { - for (DeviceIndex = PhysicalDeviceIndex; - DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1; - DeviceIndex++) - { - Controller->V2.PhysicalDeviceInformation[DeviceIndex+1] = - Controller->V2.PhysicalDeviceInformation[DeviceIndex]; - Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1] = - Controller->V2.InquiryUnitSerialNumber[DeviceIndex]; - Controller->V2.PhysicalDeviceInformation - [PhysicalDeviceIndex] = - PhysicalDeviceInfo; - Controller->V2.InquiryUnitSerialNumber - [PhysicalDeviceIndex] = - InquiryUnitSerialNumber; - } memset(PhysicalDeviceInfo, 0, sizeof(DAC960_V2_PhysicalDeviceInfo_T)); PhysicalDeviceInfo->PhysicalDeviceState = @@ -4211,6 +4243,21 @@ memset(InquiryUnitSerialNumber, 0, sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + for (DeviceIndex = DAC960_V2_MaxPhysicalDevices - 1; + DeviceIndex > PhysicalDeviceIndex; + DeviceIndex--) + { + Controller->V2.PhysicalDeviceInformation[DeviceIndex] = + Controller->V2.PhysicalDeviceInformation[DeviceIndex-1]; + Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = + Controller->V2.InquiryUnitSerialNumber[DeviceIndex-1]; + } + Controller->V2.PhysicalDeviceInformation + [PhysicalDeviceIndex] = + PhysicalDeviceInfo; + Controller->V2.InquiryUnitSerialNumber + [PhysicalDeviceIndex] = + InquiryUnitSerialNumber; Controller->V2.NeedDeviceSerialNumberInformation = true; } } @@ -4273,8 +4320,10 @@ NewPhysicalDeviceInfo ->PredictedFailuresDetected); } - if (PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Dead && + if ((PhysicalDeviceInfo->PhysicalDeviceState + == DAC960_V2_Device_Dead || + PhysicalDeviceInfo->PhysicalDeviceState + == DAC960_V2_Device_InvalidState) && NewPhysicalDeviceInfo->PhysicalDeviceState != DAC960_V2_Device_Dead) Controller->V2.NeedDeviceSerialNumberInformation = true; @@ -4285,7 +4334,28 @@ Controller->V2.PhysicalDeviceIndex++; } else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid) - Controller->V2.NeedPhysicalDeviceInformation = false; + { + unsigned int DeviceIndex; + for (DeviceIndex = Controller->V2.PhysicalDeviceIndex; + DeviceIndex < DAC960_V2_MaxPhysicalDevices; + DeviceIndex++) + { + DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo = + Controller->V2.PhysicalDeviceInformation[DeviceIndex]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + Controller->V2.InquiryUnitSerialNumber[DeviceIndex]; + if (PhysicalDeviceInfo == NULL) break; + DAC960_Critical("Physical Device %d:%d No Longer Exists\n", + Controller, + PhysicalDeviceInfo->Channel, + PhysicalDeviceInfo->TargetID); + Controller->V2.PhysicalDeviceInformation[DeviceIndex] = NULL; + Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = NULL; + kfree(PhysicalDeviceInfo); + kfree(InquiryUnitSerialNumber); + } + Controller->V2.NeedPhysicalDeviceInformation = false; + } else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid && CommandStatus == DAC960_V2_NormalCompletion) { @@ -4392,13 +4462,50 @@ NewLogicalDeviceInfo ->PatrolOperationBlockNumber, LogicalDeviceSize); + if (LogicalDeviceInfo->BackgroundInitializationInProgress && + !NewLogicalDeviceInfo->BackgroundInitializationInProgress) + DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) " + "Background Initialization %s\n", + Controller, + LogicalDeviceNumber, + Controller->ControllerNumber, + LogicalDeviceNumber, + (NewLogicalDeviceInfo->LogicalDeviceControl + .LogicalDeviceInitialized + ? "Completed" : "Failed")); memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo, sizeof(DAC960_V2_LogicalDeviceInfo_T)); } + Controller->V2.LogicalDriveFoundDuringScan + [LogicalDeviceNumber] = true; NewLogicalDeviceInfo->LogicalDeviceNumber++; } else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid) - Controller->V2.NeedLogicalDeviceInformation = false; + { + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < DAC960_MaxLogicalDrives; + LogicalDriveNumber++) + { + DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = + Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; + if (LogicalDeviceInfo == NULL || + Controller->V2.LogicalDriveFoundDuringScan + [LogicalDriveNumber]) + continue; + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "No Longer Exists\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + Controller->V2.LogicalDeviceInformation + [LogicalDriveNumber] = NULL; + kfree(LogicalDeviceInfo); + Controller->LogicalDriveInitiallyAccessible + [LogicalDriveNumber] = false; + } + Controller->V2.NeedLogicalDeviceInformation = false; + } if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber - Controller->V2.NextEventSequenceNumber > 0) { @@ -4414,7 +4521,7 @@ CommandMailbox->GetEvent.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(&Controller->V2.Event); + Virtual_to_Bus64(&Controller->V2.Event); CommandMailbox->GetEvent.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4451,7 +4558,7 @@ CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(InquiryUnitSerialNumber); + Virtual_to_Bus64(InquiryUnitSerialNumber); CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4460,6 +4567,14 @@ Controller->V2.NeedDeviceSerialNumberInformation = false; return; } + if (Controller->V2.StartPhysicalDeviceInformationScan) + { + Controller->V2.PhysicalDeviceIndex = 0; + Controller->V2.NewPhysicalDeviceInformation.Channel = 0; + Controller->V2.NewPhysicalDeviceInformation.TargetID = 0; + Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0; + Controller->V2.StartPhysicalDeviceInformationScan = false; + } CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; CommandMailbox->PhysicalDeviceInfo.DataTransferSize = sizeof(DAC960_V2_PhysicalDeviceInfo_T); @@ -4474,7 +4589,7 @@ CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(&Controller->V2.NewPhysicalDeviceInformation); + Virtual_to_Bus64(&Controller->V2.NewPhysicalDeviceInformation); CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4484,6 +4599,18 @@ } if (Controller->V2.NeedLogicalDeviceInformation) { + if (Controller->V2.StartLogicalDeviceInformationScan) + { + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < DAC960_MaxLogicalDrives; + LogicalDriveNumber++) + Controller->V2.LogicalDriveFoundDuringScan + [LogicalDriveNumber] = false; + Controller->V2.NewLogicalDeviceInformation + .LogicalDeviceNumber = 0; + Controller->V2.StartLogicalDeviceInformationScan = false; + } CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; CommandMailbox->LogicalDeviceInfo.DataTransferSize = sizeof(DAC960_V2_LogicalDeviceInfo_T); @@ -4494,7 +4621,7 @@ CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(&Controller->V2.NewLogicalDeviceInformation); + Virtual_to_Bus64(&Controller->V2.NewLogicalDeviceInformation); CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4792,7 +4919,8 @@ DAC960_V1_ClearCommand(Command); Command->CommandType = DAC960_MonitoringCommand; CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry; - CommandMailbox->Type3.BusAddress = Virtual_to_Bus(&Controller->V1.NewEnquiry); + CommandMailbox->Type3.BusAddress = + Virtual_to_Bus32(&Controller->V1.NewEnquiry); DAC960_QueueCommand(Command); } @@ -4820,7 +4948,7 @@ CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(&Controller->V2.NewControllerInformation); + Virtual_to_Bus64(&Controller->V2.NewControllerInformation); CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4863,6 +4991,28 @@ &Controller->V2.ControllerInformation; unsigned int StatusChangeCounter = Controller->V2.HealthStatusBuffer->StatusChangeCounter; + boolean ForceMonitoringCommand = false; + if (jiffies - Controller->SecondaryMonitoringTime + > DAC960_SecondaryMonitoringInterval) + { + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < DAC960_MaxLogicalDrives; + LogicalDriveNumber++) + { + DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = + Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; + if (LogicalDeviceInfo == NULL) continue; + if (!LogicalDeviceInfo->LogicalDeviceControl + .LogicalDeviceInitialized && + Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 0) + { + ForceMonitoringCommand = true; + break; + } + } + Controller->SecondaryMonitoringTime = jiffies; + } if (StatusChangeCounter == Controller->V2.StatusChangeCounter && Controller->V2.HealthStatusBuffer->NextEventSequenceNumber == Controller->V2.NextEventSequenceNumber && @@ -4873,7 +5023,8 @@ ControllerInfo->RebuildsActive + ControllerInfo->OnlineExpansionsActive == 0 || jiffies - Controller->PrimaryMonitoringTime - < DAC960_MonitoringTimerInterval)) + < DAC960_MonitoringTimerInterval) && + !ForceMonitoringCommand) { Controller->MonitoringTimer.expires = jiffies + DAC960_HealthStatusMonitoringInterval; @@ -4997,8 +5148,7 @@ DiskGeometry_T Geometry, *UserGeometry; DAC960_Controller_T *Controller; int PartitionNumber; - if (File == NULL) return -EINVAL; - if (File->f_flags & O_NONBLOCK) + if (File != NULL && (File->f_flags & O_NONBLOCK)) return DAC960_UserIOCTL(Inode, File, Request, Argument); if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) return -ENXIO; @@ -5225,10 +5375,17 @@ if (CommandOpcode == DAC960_V1_DCDB) { DAC960_AcquireControllerLock(Controller, &ProcessorFlags); - while (Controller->V1.DirectCommandActive[DCDB.Channel] - [DCDB.TargetID] || - (Command = DAC960_AllocateCommand(Controller)) == NULL) + while ((Command = DAC960_AllocateCommand(Controller)) == NULL) DAC960_WaitForCommand(Controller); + while (Controller->V1.DirectCommandActive[DCDB.Channel] + [DCDB.TargetID]) + { + spin_unlock_irq(&io_request_lock); + __wait_event(Controller->CommandWaitQueue, + !Controller->V1.DirectCommandActive + [DCDB.Channel][DCDB.TargetID]); + spin_lock_irq(&io_request_lock); + } Controller->V1.DirectCommandActive[DCDB.Channel] [DCDB.TargetID] = true; DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); @@ -5237,8 +5394,8 @@ memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox, sizeof(DAC960_V1_CommandMailbox_T)); Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(&DCDB); - DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer); + Virtual_to_Bus32(&DCDB); + DCDB.BusAddress = Virtual_to_Bus32(DataTransferBuffer); } else { @@ -5252,7 +5409,7 @@ sizeof(DAC960_V1_CommandMailbox_T)); if (DataTransferBuffer != NULL) Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(DataTransferBuffer); + Virtual_to_Bus32(DataTransferBuffer); } DAC960_ExecuteCommand(Command); CommandStatus = Command->V1.CommandStatus; @@ -5365,7 +5522,7 @@ CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(DataTransferBuffer); + Virtual_to_Bus64(DataTransferBuffer); CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -5377,7 +5534,7 @@ .NoAutoRequestSense = false; CommandMailbox->Common.RequestSenseSize = RequestSenseLength; CommandMailbox->Common.RequestSenseBusAddress = - Virtual_to_Bus(RequestSenseBuffer); + Virtual_to_Bus64(RequestSenseBuffer); } DAC960_ExecuteCommand(Command); CommandStatus = Command->V2.CommandStatus; @@ -5557,9 +5714,9 @@ memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox, sizeof(DAC960_V1_CommandMailbox_T)); Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(DCDB); + Virtual_to_Bus32(DCDB); Command->V1.KernelCommand = KernelCommand; - DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer); + DCDB->BusAddress = Virtual_to_Bus32(DataTransferBuffer); DAC960_QueueCommand(Command); DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); } @@ -5578,7 +5735,7 @@ sizeof(DAC960_V1_CommandMailbox_T)); if (DataTransferBuffer != NULL) Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus(DataTransferBuffer); + Virtual_to_Bus32(DataTransferBuffer); Command->V1.KernelCommand = KernelCommand; DAC960_QueueCommand(Command); DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); @@ -5655,7 +5812,7 @@ CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(DataTransferBuffer); + Virtual_to_Bus64(DataTransferBuffer); CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -5666,7 +5823,7 @@ CommandMailbox->Common.CommandControlBits .NoAutoRequestSense = false; CommandMailbox->Common.RequestSenseBusAddress = - Virtual_to_Bus(RequestSenseBuffer); + Virtual_to_Bus64(RequestSenseBuffer); } Command->V2.KernelCommand = KernelCommand; DAC960_QueueCommand(Command); @@ -6104,7 +6261,7 @@ CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl; CommandMailbox->Type3R.RebuildRateConstant = 0xFF; CommandMailbox->Type3R.BusAddress = - Virtual_to_Bus(&OldRebuildRateConstant); + Virtual_to_Bus32(&OldRebuildRateConstant); DAC960_ExecuteCommand(Command); switch (Command->V1.CommandStatus) { @@ -6160,7 +6317,7 @@ CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus(&PhysicalToLogicalDevice); + Virtual_to_Bus64(&PhysicalToLogicalDevice); CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/block/DAC960.h linux/drivers/block/DAC960.h --- v2.2.18/drivers/block/DAC960.h Sun Mar 25 11:12:56 2001 +++ linux/drivers/block/DAC960.h Sun Mar 25 11:37:30 2001 @@ -2,7 +2,7 @@ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - Copyright 1998-2000 by Leonard N. Zubkoff + Copyright 1998-2001 by Leonard N. Zubkoff This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License Version 2 as published by the @@ -259,6 +259,7 @@ DAC960_V1_ClearBadDataTable = 0x26, DAC960_V1_GetErrorTable = 0x17, DAC960_V1_AddCapacityAsync = 0x2A, + DAC960_V1_BackgroundInitializationControl = 0x2B, /* Configuration Related Commands */ DAC960_V1_ReadConfig2 = 0x3D, DAC960_V1_WriteConfig2 = 0x3C, @@ -450,14 +451,16 @@ unsigned int NonVolatileMemorySize; /* Bytes 36-39 */ struct { enum { - DAC960_V1_DRAM = 0x0, - DAC960_V1_EDO = 0x1, - DAC960_V1_SDRAM = 0x2 + DAC960_V1_RamType_DRAM = 0x0, + DAC960_V1_RamType_EDO = 0x1, + DAC960_V1_RamType_SDRAM = 0x2, + DAC960_V1_RamType_Last = 0x7 } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */ enum { - DAC960_V1_None = 0x0, - DAC960_V1_Parity = 0x1, - DAC960_V1_ECC = 0x2 + DAC960_V1_ErrorCorrection_None = 0x0, + DAC960_V1_ErrorCorrection_Parity = 0x1, + DAC960_V1_ErrorCorrection_ECC = 0x2, + DAC960_V1_ErrorCorrection_Last = 0x7 } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */ boolean FastPageMode:1; /* Byte 40 Bit 6 */ boolean LowPowerMemory:1; /* Byte 40 Bit 7 */ @@ -523,7 +526,9 @@ struct { boolean Clustering:1; /* Byte 116 Bit 0 */ boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */ - unsigned int :30; /* Bytes 116-119 */ + boolean ReadAhead:1; /* Byte 116 Bit 2 */ + boolean BackgroundInitialization:1; /* Byte 116 Bit 3 */ + unsigned int :28; /* Bytes 116-119 */ } FirmwareFeatures; unsigned int :32; /* Bytes 120-123 */ unsigned int :32; /* Bytes 124-127 */ @@ -993,7 +998,8 @@ DAC960_V2_MemoryType_DRAM = 0x01, DAC960_V2_MemoryType_EDRAM = 0x02, DAC960_V2_MemoryType_EDO = 0x03, - DAC960_V2_MemoryType_SDRAM = 0x04 + DAC960_V2_MemoryType_SDRAM = 0x04, + DAC960_V2_MemoryType_Last = 0x1F } __attribute__ ((packed)) MemoryType:5; /* Byte 0 Bits 0-4 */ boolean :1; /* Byte 0 Bit 5 */ boolean MemoryParity:1; /* Byte 0 Bit 6 */ @@ -1269,13 +1275,15 @@ DAC960_V2_ReadCacheDisabled = 0x0, DAC960_V2_ReadCacheEnabled = 0x1, DAC960_V2_ReadAheadEnabled = 0x2, - DAC960_V2_IntelligentReadAheadEnabled = 0x3 + DAC960_V2_IntelligentReadAheadEnabled = 0x3, + DAC960_V2_ReadCache_Last = 0x7 } __attribute__ ((packed)) ReadCache:3; /* Byte 8 Bits 0-2 */ enum { DAC960_V2_WriteCacheDisabled = 0x0, DAC960_V2_LogicalDeviceReadOnly = 0x1, DAC960_V2_WriteCacheEnabled = 0x2, - DAC960_V2_IntelligentWriteCacheEnabled = 0x3 + DAC960_V2_IntelligentWriteCacheEnabled = 0x3, + DAC960_V2_WriteCache_Last = 0x7 } __attribute__ ((packed)) WriteCache:3; /* Byte 8 Bits 3-5 */ boolean :1; /* Byte 8 Bit 6 */ boolean LogicalDeviceInitialized:1; /* Byte 8 Bit 7 */ @@ -2336,6 +2344,7 @@ boolean NeedDeviceSerialNumberInformation; boolean NeedRebuildProgress; boolean NeedConsistencyCheckProgress; + boolean StartDeviceStateScan; boolean RebuildProgressFirst; boolean RebuildFlagPending; boolean RebuildStatusPending; @@ -2375,6 +2384,8 @@ boolean NeedLogicalDeviceInformation; boolean NeedPhysicalDeviceInformation; boolean NeedDeviceSerialNumberInformation; + boolean StartLogicalDeviceInformationScan; + boolean StartPhysicalDeviceInformationScan; DAC960_V2_CommandMailbox_T *FirstCommandMailbox; DAC960_V2_CommandMailbox_T *LastCommandMailbox; DAC960_V2_CommandMailbox_T *NextCommandMailbox; @@ -2397,6 +2408,7 @@ DAC960_V2_PhysicalDevice_T LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives]; DAC960_V2_Event_T Event; + boolean LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives]; } V2; } FW; DiskPartition_T DiskPartitions[DAC960_MinorCount]; @@ -2504,26 +2516,39 @@ /* - Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. + Virtual_to_Bus32 maps from Kernel Virtual Addresses to 32 Bit PCI Bus + Addresses. */ -static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress) +static inline DAC960_BusAddress32_T Virtual_to_Bus32(void *VirtualAddress) { return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress); } /* - Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. + Bus32_to_Virtual maps from 32 Bit PCI Bus Addresses to Kernel Virtual + Addresses. */ -static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress) +static inline void *Bus32_to_Virtual(DAC960_BusAddress32_T BusAddress) { return (void *) bus_to_virt(BusAddress); } /* + Virtual_to_Bus64 maps from Kernel Virtual Addresses to 64 Bit PCI Bus + Addresses. +*/ + +static inline DAC960_BusAddress64_T Virtual_to_Bus64(void *VirtualAddress) +{ + return (DAC960_BusAddress64_T) virt_to_bus(VirtualAddress); +} + + +/* Define the DAC960 BA Series Controller Interface Register Offsets. */ @@ -2790,8 +2815,13 @@ void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress, DAC960_V2_CommandMailbox_T *CommandMailbox) { - writel(Virtual_to_Bus(CommandMailbox), +#ifdef __ia64__ + writeq(Virtual_to_Bus64(CommandMailbox), ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset); +#else + writel(Virtual_to_Bus32(CommandMailbox), + ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset); +#endif } static inline DAC960_V2_CommandIdentifier_T @@ -3091,8 +3121,13 @@ void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress, DAC960_V2_CommandMailbox_T *CommandMailbox) { - writel(Virtual_to_Bus(CommandMailbox), +#ifdef __ia64__ + writeq(Virtual_to_Bus64(CommandMailbox), + ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset); +#else + writel(Virtual_to_Bus32(CommandMailbox), ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset); +#endif } static inline DAC960_V2_CommandIdentifier_T diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.2.18/drivers/block/genhd.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/block/genhd.c Sun Mar 25 11:37:30 2001 @@ -54,6 +54,14 @@ le32_to_cpu(__a); \ }) +#define MSDOS_LABEL_MAGIC1 0x55 +#define MSDOS_LABEL_MAGIC2 0xAA + +static inline int +msdos_magic_present(unsigned char *p) { + return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2); +} + struct gendisk *gendisk_head = NULL; static int current_minor = 0; @@ -244,8 +252,6 @@ * only for the actual data partitions. */ -#define MSDOS_LABEL_MAGIC 0xAA55 - static void extended_partition(struct gendisk *hd, kdev_t dev, int sector_size) { struct buffer_head *bh; @@ -273,10 +279,10 @@ */ bh->b_state = 0; - if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC)) + if (!(msdos_magic_present(bh->b_data + 510))) goto done; - p = (struct partition *) (0x1BE + bh->b_data); + p = (struct partition *) (bh->b_data + 0x1be); this_size = hd->part[MINOR(dev)].nr_sects; @@ -499,7 +505,51 @@ printk(" >"); } #endif + +#ifdef CONFIG_MINIX_SUBPARTITION +/* + * Minix 2.0.0/2.0.2 subpartition support. + * Anand Krishnamurthy + * Rajeev V. Pillai + */ +#define MINIX_PARTITION 0x81 /* Minix Partition ID */ +#define MINIX_NR_SUBPARTITIONS 4 +static void minix_partition(struct gendisk *hd, kdev_t dev) +{ + struct buffer_head *bh; + struct partition *p; + int mask = (1 << hd->minor_shift) - 1; + int i; + if (!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) + return; + bh->b_state = 0; + + p = (struct partition *)(bh->b_data + 0x1be); + + /* The first sector of a Minix partition can have either + * a secondary MBR describing its subpartitions, or + * the normal boot sector. */ + if (msdos_magic_present(bh->b_data + 510) && + SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ + + printk(" <"); + for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { + if ((current_minor & mask) == 0) + break; + /* add each partition in use */ + if (SYS_IND(p) == MINIX_PARTITION) { + add_partition(hd, current_minor, + START_SECT(p), NR_SECTS(p), 0); + current_minor++; + } + } + printk(" >"); + } + brelse(bh); +} +#endif /* CONFIG_MINIX_SUBPARTITION */ + static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) { int i, minor = current_minor; @@ -540,11 +590,11 @@ #ifdef CONFIG_BLK_DEV_IDE check_table: #endif - if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { + if (!(msdos_magic_present(data + 510))) { brelse(bh); return 0; } - p = (struct partition *) (0x1be + data); + p = (struct partition *) (data + 0x1be); #ifdef CONFIG_BLK_DEV_IDE if (!tested_for_xlate++) { /* Do this only once per disk */ @@ -649,8 +699,8 @@ for (i=1 ; i<=4 ; minor++,i++,p++) { if (!NR_SECTS(p)) continue; - add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size, - ptype(SYS_IND(p))); + add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, + NR_SECTS(p)*sector_size, ptype(SYS_IND(p))); if (is_extended_partition(p)) { printk(" <"); /* @@ -682,6 +732,12 @@ } } #endif +#ifdef CONFIG_MINIX_SUBPARTITION + if (SYS_IND(p) == MINIX_PARTITION) { + printk("@"); /* Minix partitions are indicated by '@' */ + minix_partition(hd, MKDEV(hd->major, minor)); + } +#endif #ifdef CONFIG_UNIXWARE_DISKLABEL if (SYS_IND(p) == UNIXWARE_PARTITION) unixware_partition(hd, MKDEV(hd->major, minor)); @@ -709,7 +765,7 @@ /* * Check for old-style Disk Manager partition table */ - if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) { + if (msdos_magic_present(data + 0xfc)) { p = (struct partition *) (0x1be + data); for (i = 4 ; i < 16 ; i++, current_minor++) { p--; @@ -1736,7 +1792,7 @@ } #ifdef CONFIG_PROC_FS -int get_partition_list(char * page) +int get_partition_list(char *page, char **start, off_t offset, int count) { struct gendisk *p; char buf[MAX_DISKNAME_LEN]; @@ -1745,14 +1801,23 @@ len = sprintf(page, "major minor #blocks name\n\n"); for (p = gendisk_head; p; p = p->next) { for (n=0; n < (p->nr_real << p->minor_shift); n++) { - if (p->part[n].nr_sects && len < PAGE_SIZE - 80) { + if (p->part[n].nr_sects) { len += sprintf(page+len, "%4d %4d %10d %s\n", p->major, n, p->sizes[n], disk_name(p, n, buf)); + if (len < offset) + offset -= len, len = 0; + else if (len >= offset + count) + goto leave_loops; } } } - return len; +leave_loops: + *start = page + offset; + len -= offset; + if (len < 0) + len = 0; + return len > count ? count : len; } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/block/hd.c linux/drivers/block/hd.c --- v2.2.18/drivers/block/hd.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/block/hd.c Sun Mar 25 11:37:30 2001 @@ -703,12 +703,12 @@ static void hd_geninit(struct gendisk *ignored) { int drive; - unsigned long flags; #ifdef __i386__ if (!NR_HD) { extern struct drive_info drive_info; unsigned char *BIOS = (unsigned char *) &drive_info; + unsigned long flags; int cmos_disks; for (drive=0 ; drive<2 ; drive++) { @@ -747,13 +747,15 @@ */ spin_lock_irqsave(&rtc_lock, flags); - if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) { + cmos_disks = CMOS_READ(0x12); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (cmos_disks & 0xf0) { if (cmos_disks & 0x0f) NR_HD = 2; else NR_HD = 1; } - spin_unlock_irqrestore(&rtc_lock, flags); } #endif /* __i386__ */ for (drive=0 ; drive < NR_HD ; drive++) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.2.18/drivers/block/ide-pmac.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/block/ide-pmac.c Sun Mar 25 11:37:30 2001 @@ -905,7 +905,8 @@ * Problem: This can schedule. I moved the block device * wakeup almost late by priority because of that. */ - DRIVER(drive)->media_change(drive); + if (DRIVER(drive)) + DRIVER(drive)->media_change(drive); /* We kick the VFS too (see fix in ide.c revalidate) */ check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS)); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.2.18/drivers/block/ll_rw_blk.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/block/ll_rw_blk.c Sun Mar 25 11:37:30 2001 @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_POWERMAC +#include +#endif + #include /* @@ -971,7 +975,11 @@ isp16_init(); #endif CONFIG_ISP16_CDI #ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_POWERMAC + ide_pmac_init(); +#else ide_init(); /* this MUST precede hd_init */ +#endif #endif #ifdef CONFIG_BLK_DEV_HD hd_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/block/rd.c linux/drivers/block/rd.c --- v2.2.18/drivers/block/rd.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/block/rd.c Sun Mar 25 11:37:30 2001 @@ -173,7 +173,7 @@ if (CURRENT->cmd == READ) memset(CURRENT->buffer, 0, len); else - set_bit(BH_Protected, &CURRENT->bh->b_state); + mark_buffer_protected(CURRENT->bh); end_request(1); goto repeat; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.2.18/drivers/cdrom/cdrom.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/cdrom/cdrom.c Sun Mar 25 12:44:42 2001 @@ -1140,15 +1140,18 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) { - int ret, i; - u_char buf[4 + 4 * 20], *base; + unsigned char buf[20], *base; struct dvd_layer *layer; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; + int ret, layer_num = s->physical.layer_num; + + if (layer_num >= DVD_LAYERS) + return -EINVAL; init_cdrom_command(&cgc, buf, sizeof(buf)); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; - cgc.cmd[6] = s->physical.layer_num; + cgc.cmd[6] = layer_num; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen & 0xff; @@ -1156,26 +1159,26 @@ return ret; base = &buf[4]; - layer = &s->physical.layer[0]; + layer = &s->physical.layer[layer_num]; - /* place the data... really ugly, but at least we won't have to - worry about endianess in userspace or here. */ - for (i = 0; i < 4; ++i, base += 20, ++layer) { - memset(layer, 0, sizeof(*layer)); - layer->book_version = base[0] & 0xf; - layer->book_type = base[0] >> 4; - layer->min_rate = base[1] & 0xf; - layer->disc_size = base[1] >> 4; - layer->layer_type = base[2] & 0xf; - layer->track_path = (base[2] >> 4) & 1; - layer->nlayers = (base[2] >> 5) & 3; - layer->track_density = base[3] & 0xf; - layer->linear_density = base[3] >> 4; - layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; - layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; - layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; - layer->bca = base[16] >> 7; - } + /* + * place the data... really ugly, but at least we won't have to + * worry about endianess in userspace. + */ + memset(layer, 0, sizeof(*layer)); + layer->book_version = base[0] & 0xf; + layer->book_type = base[0] >> 4; + layer->min_rate = base[1] & 0xf; + layer->disc_size = base[1] >> 4; + layer->layer_type = base[2] & 0xf; + layer->track_path = (base[2] >> 4) & 1; + layer->nlayers = (base[2] >> 5) & 3; + layer->track_density = base[3] & 0xf; + layer->linear_density = base[3] >> 4; + layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; + layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; + layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; + layer->bca = base[16] >> 7; return 0; } @@ -1939,6 +1942,9 @@ } while (ra.nframes > 0) { + if (frames > ra.nframes) + frames = ra.nframes; + ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW); if (ret) break; __copy_to_user(ra.buf, cgc.buffer, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/Config.in linux/drivers/char/Config.in --- v2.2.18/drivers/char/Config.in Sun Mar 25 11:28:21 2001 +++ linux/drivers/char/Config.in Sun Mar 25 11:37:30 2001 @@ -60,7 +60,7 @@ if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 fi -if [ "$CONFIG_PARPORT" != "n" ]; then +if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "m" ]; then dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT if [ "$CONFIG_PRINTER" != "n" ]; then bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK @@ -99,7 +99,14 @@ mainmenu_option next_comment comment 'Watchdog Cards' bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT - tristate ' WDT Watchdog timer' CONFIG_WDT + tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT + tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT + tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG + tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO + tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD + tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG + tristate ' WDT ISA Watchdog timer' CONFIG_WDT if [ "$CONFIG_WDT" != "n" ]; then bool ' WDT501 features' CONFIG_WDT_501 if [ "$CONFIG_WDT_501" = "y" ]; then @@ -107,11 +114,6 @@ fi fi tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI - tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG - tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG - tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT - tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT - tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD endmenu fi @@ -126,10 +128,10 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP n + tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP if [ "$CONFIG_AGP" != "n" ]; then - bool ' Intel 440LX/BX/GX support' CONFIG_AGP_INTEL - bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810 + bool ' Intel 440LX/BX/GX and I815/820 support' CONFIG_AGP_INTEL + bool ' Intel I810/I815 (on-board video) support' CONFIG_AGP_I810 bool ' VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA bool ' AMD Irongate support' CONFIG_AGP_AMD bool ' Generic SiS support' CONFIG_AGP_SIS @@ -166,24 +168,22 @@ if [ "$CONFIG_RADIO_TRUST" = "y" ]; then hex ' Trust FM Radio I/O port (0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350 fi - if [ "$CONFIG_PCI" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_BT848" != "n" ]; then comment ' MSP3400 sound decoder support is in the section "additional' comment ' low level sound drivers". You may need to enable it there.' fi fi - if [ "$CONFIG_PARPORT" != "n" ]; then + if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "m" ]; then dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then - if [ "CONFIG_PARPORT_1284" != "n" ]; then - dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT - fi - if [ "$CONFIG_USB" != "n" ]; then + dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT + if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then dep_tristate ' CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB fi fi diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/Makefile linux/drivers/char/Makefile --- v2.2.18/drivers/char/Makefile Sun Mar 25 11:28:21 2001 +++ linux/drivers/char/Makefile Sun Mar 25 11:37:30 2001 @@ -200,7 +200,13 @@ endif endif -obj-$(CONFIG_SX) += sx.o generic_serial.o +ifeq ($(CONFIG_SX),y) +O_OBJS += sx.o generic_serial.o +else + ifeq ($(CONFIG_SX),m) + M_OBJS += sx.o generic_serial.o + endif +endif ifeq ($(CONFIG_RIO),y) O_OBJS += rio/rio.o generic_serial.o @@ -295,6 +301,14 @@ endif endif +ifeq ($(CONFIG_ADVANTECH_WDT),y) +O_OBJS += advantechwdt.o +else + ifeq ($(CONFIG_ADVANTECH_WDT),m) + M_OBJS += advantechwdt.o + endif +endif + ifeq ($(CONFIG_60XX_WDT),y) O_OBJS += sbc60xxwdt.o else @@ -678,6 +692,14 @@ else ifeq ($(CONFIG_TOSHIBA),m) M_OBJS += toshiba.o + endif +endif + +ifeq ($(CONFIG_I810_TCO),y) +O_OBJS += i810-tco.o +else + ifeq ($(CONFIG_I810_TCO),m) + M_OBJS += i810-tco.o endif endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/advantechwdt.c linux/drivers/char/advantechwdt.c --- v2.2.18/drivers/char/advantechwdt.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/char/advantechwdt.c Sun Mar 25 11:37:30 2001 @@ -0,0 +1,243 @@ +/* + * Advantech Single Board Computer WDT driver for Linux 2.2.x + * + * (c) Copyright 2000 Marek Michalkiewicz + * + * Based on acquirewdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int advwdt_is_open = 0; + +/* + * You must set these - there is no sane way to probe for this board. + * + * To enable or restart, write the timeout value in seconds (1 to 63) + * to I/O port WDT_START. To disable, read I/O port WDT_STOP. + * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but + * check your manual (at least the PCA-6159 seems to be different - + * the manual says WDT_STOP is 0x43, not 0x443). + * (0x43 is also a write-only control register for the 8254 timer!) + * + * TODO: module parameters to set the I/O port addresses and NOWAYOUT + * option at load time. + */ + +#define WDT_STOP 0x443 +#define WDT_START 0x443 + +#define WD_TIMO 60 /* 1 minute */ + + +/* + * Kernel methods. + */ + + +static void +advwdt_ping(void) +{ + /* Write a watchdog value */ + outb_p(WD_TIMO, WDT_START); +} + +static ssize_t +advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + advwdt_ping(); + return 1; + } + return 0; +} + +static ssize_t +advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static int +advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING, 1, "Advantech WDT" + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *)arg, &advwdt_is_open, sizeof(int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + advwdt_ping(); + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int +advwdt_open(struct inode *inode, struct file *file) +{ + switch (MINOR(inode->i_rdev)) { + case WATCHDOG_MINOR: + if (advwdt_is_open) + return -EBUSY; + MOD_INC_USE_COUNT; + /* + * Activate + */ + + advwdt_is_open = 1; + advwdt_ping(); + return 0; + default: + return -ENODEV; + } +} + +static int +advwdt_close(struct inode *inode, struct file *file) +{ + if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + inb_p(WDT_STOP); +#endif + advwdt_is_open = 0; + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Notifier for system down + */ + +static int +advwdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the card off */ + inb_p(WDT_STOP); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + + +static struct file_operations advwdt_fops = { + NULL, + advwdt_read, + advwdt_write, + NULL, /* No Readdir */ + NULL, /* No Select */ + advwdt_ioctl, + NULL, /* No mmap */ + advwdt_open, + NULL, /* flush */ + advwdt_close +}; + +static struct miscdevice advwdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &advwdt_fops +}; + + +/* + * The WDT card needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block advwdt_notifier = { + advwdt_notify_sys, + NULL, + 0 +}; + +#ifdef MODULE + +#define advwdt_init init_module + +void +cleanup_module(void) +{ + misc_deregister(&advwdt_miscdev); + unregister_reboot_notifier(&advwdt_notifier); +#if WDT_START != WDT_STOP + release_region(WDT_STOP,1); +#endif + release_region(WDT_START,1); +} + +#endif + +int __init +advwdt_init(void) +{ + printk("WDT driver for Advantech single board computer initialising.\n"); + + misc_register(&advwdt_miscdev); +#if WDT_START != WDT_STOP + request_region(WDT_STOP, 1, "Advantech WDT"); +#endif + request_region(WDT_START, 1, "Advantech WDT"); + register_reboot_notifier(&advwdt_notifier); + return 0; +} + +/* end of advantechwdt.c */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/agp/agp_backend.h linux/drivers/char/agp/agp_backend.h --- v2.2.18/drivers/char/agp/agp_backend.h Sun Mar 25 11:28:21 2001 +++ linux/drivers/char/agp/agp_backend.h Sun Mar 25 11:37:30 2001 @@ -45,6 +45,7 @@ INTEL_BX, INTEL_GX, INTEL_I810, + INTEL_I815, INTEL_I840, VIA_GENERIC, VIA_VP3, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.2.18/drivers/char/agp/agpgart_be.c Sun Mar 25 11:28:21 2001 +++ linux/drivers/char/agp/agpgart_be.c Sun Mar 25 11:37:30 2001 @@ -2026,6 +2026,13 @@ "Intel", "440GX", intel_generic_setup }, + /* could we add support for PCI_DEVICE_ID_INTEL_815_1 too ? */ + { PCI_DEVICE_ID_INTEL_815_0, + PCI_VENDOR_ID_INTEL, + INTEL_I815, + "Intel", + "i815", + intel_generic_setup }, { PCI_DEVICE_ID_INTEL_840_0, PCI_VENDOR_ID_INTEL, INTEL_I840, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/console.c linux/drivers/char/console.c --- v2.2.18/drivers/char/console.c Sun Mar 25 11:28:22 2001 +++ linux/drivers/char/console.c Sun Mar 25 11:37:31 2001 @@ -2571,6 +2571,7 @@ console_blanked = 0; if (console_blank_hook) console_blank_hook(0); + set_palette(currcons); if (sw->con_blank(vc_cons[currcons].d, 0)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/cpia.c linux/drivers/char/cpia.c --- v2.2.18/drivers/char/cpia.c Sun Mar 25 11:28:22 2001 +++ linux/drivers/char/cpia.c Sun Mar 25 11:37:31 2001 @@ -3211,7 +3211,7 @@ DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame, vm.width, vm.height); #endif - if (vm.frame<0||vm.frame>FRAME_NUM) { + if (vm.frame<0||vm.frame>=FRAME_NUM) { retval = -EINVAL; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c --- v2.2.18/drivers/char/drm/gamma_drv.c Sun Mar 25 11:28:22 2001 +++ linux/drivers/char/drm/gamma_drv.c Sun Mar 25 11:37:31 2001 @@ -35,11 +35,6 @@ #include -static void __attribute__((unused)) unused(void) -{ - agp_enable(0); -} - #ifndef PCI_DEVICE_ID_3DLABS_GAMMA #define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008 #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/drm/i810_drv.c linux/drivers/char/drm/i810_drv.c --- v2.2.18/drivers/char/drm/i810_drv.c Sun Mar 25 11:28:22 2001 +++ linux/drivers/char/drm/i810_drv.c Sun Mar 25 11:37:31 2001 @@ -35,11 +35,6 @@ #include -static void __attribute__((unused)) unused(void) -{ - agp_enable(0); -} - #define I810_NAME "i810" #define I810_DESC "Intel I810" #define I810_DATE "20000719" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/drm/mga_drv.c linux/drivers/char/drm/mga_drv.c --- v2.2.18/drivers/char/drm/mga_drv.c Sun Mar 25 11:28:22 2001 +++ linux/drivers/char/drm/mga_drv.c Sun Mar 25 11:37:31 2001 @@ -36,11 +36,6 @@ #include -static void __attribute__((unused)) unused(void) -{ - agp_enable(0); -} - #define MGA_NAME "mga" #define MGA_DESC "Matrox G200/G400" #define MGA_DATE "20000910" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/drm/r128_drv.c linux/drivers/char/drm/r128_drv.c --- v2.2.18/drivers/char/drm/r128_drv.c Sun Mar 25 11:28:22 2001 +++ linux/drivers/char/drm/r128_drv.c Sun Mar 25 11:37:31 2001 @@ -35,11 +35,6 @@ #include -static void __attribute__((unused)) unused(void) -{ - agp_enable(0); -} - #define R128_NAME "r128" #define R128_DESC "ATI Rage 128" #define R128_DATE "20000719" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/drm/tdfx_drv.c linux/drivers/char/drm/tdfx_drv.c --- v2.2.18/drivers/char/drm/tdfx_drv.c Sun Mar 25 11:28:22 2001 +++ linux/drivers/char/drm/tdfx_drv.c Sun Mar 25 11:37:31 2001 @@ -38,13 +38,6 @@ #include #endif -static void __attribute__((unused)) unused(void) -{ -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) - agp_enable(0); -#endif -} - #define TDFX_NAME "tdfx" #define TDFX_DESC "3dfx Banshee/Voodoo3+" #define TDFX_DATE "20000719" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/i810-tco.c linux/drivers/char/i810-tco.c --- v2.2.18/drivers/char/i810-tco.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/char/i810-tco.c Sun Mar 25 11:37:31 2001 @@ -0,0 +1,343 @@ +/* + * i810-tco 0.02: TCO timer driver for i810 chipsets + * + * (c) Copyright 2000 kernel concepts , All Rights Reserved. + * http://www.kernelconcepts.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i810/i815 chipsets + * based on softdog.c by Alan Cox + * + * The TCO timer is implemented in the 82801AA (82801AB) chip, + * see intel documentation from http://developer.intel.com, + * order number 290655-003 + * + * 20000710 Nils Faerber + * Initial Version 0.01 + * 20000728 Nils Faerber + * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i810-tco.h" + + +/* Just in case that the PCI vendor and device IDs are not yet defined */ +#ifndef PCI_DEVICE_ID_INTEL_82801AA_0 +#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 +#endif + +/* Default expire timeout */ +#define TIMER_MARGIN 50 /* steps of 0.6sec, 2 0x3f || tmrval < 0x03) + return -1; + + spin_lock(&tco_lock); + val = inb (TCO1_TMR); + val &= 0xc0; + val |= tmrval; + outb (val, TCO1_TMR); + val = inb (TCO1_TMR); + spin_unlock(&tco_lock); + + if ((val & 0x3f) != tmrval) + return -1; + + return 0; +} + +/* + * Reload (trigger) the timer. Lock is needed so we dont reload it during + * a reprogramming event + */ + +static void tco_timer_reload (void) +{ + spin_lock(&tco_lock); + outb (0x01, TCO1_RLD); + spin_unlock(&tco_lock); +} + +/* + * Read the current timer value + */ +static unsigned char tco_timer_read (void) +{ + return (inb (TCO1_RLD)); +} + + +/* + * Allow only one person to hold it open + */ + +static int i810tco_open (struct inode *inode, struct file *file) +{ + if (timer_alive) + return -EBUSY; + + /* + * Reload and activate timer + */ + tco_timer_reload (); + tco_timer_start (); + timer_alive = 1; + MOD_INC_USE_COUNT; + return 0; +} + +static int i810tco_release (struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + */ + MOD_INC_USE_COUNT; + tco_timer_stop (); + timer_alive = 0; + MOD_DEC_USE_COUNT; + return 0; +} + +static ssize_t i810tco_write (struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if (len) { + tco_timer_reload (); + return 1; + } + return 0; +} + +static int i810tco_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + 0, + 0, + "i810 TCO timer" + }; + switch (cmd) { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + return put_user (tco_timer_read (), + (unsigned int *) (int) arg); + case WDIOC_GETBOOTSTATUS: + return put_user (boot_status, (int *) arg); + case WDIOC_KEEPALIVE: + tco_timer_reload (); + return 0; + } +} + +static struct pci_dev *i810tco_pci; + +static unsigned char i810tco_getdevice (void) +{ + u8 val1, val2; + u16 badr; + /* + * Find the PCI device which has vendor id 0x8086 + * and device ID 0x2410 + */ + i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801AA_0, NULL); + if (i810tco_pci) { + /* + * Find the ACPI base I/O address which is the base + * for the TCO registers (TCOBASE=ACPIBASE + 0x60) + * ACPIBASE is bits [15:7] from 0x40-0x43 + */ + pci_read_config_byte (i810tco_pci, 0x40, &val1); + pci_read_config_byte (i810tco_pci, 0x41, &val2); + badr = ((val2 << 1) | (val1 >> 7)) << 7; + ACPIBASE = badr; + /* Something's wrong here, ACPIBASE has to be set */ + if (badr == 0x0001 || badr == 0x0000) { + printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n"); + return 0; + } + /* + * Check chipset's NO_REBOOT bit + */ + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + val1 &= 0xfd; + pci_write_config_byte (i810tco_pci, 0xd4, val1); + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag\n"); + return 0; /* Cannot reset NO_REBOOT bit */ + } + } + /* Set the TCO_EN bit in SMI_EN register */ + val1 = inb (SMI_EN + 1); + val1 &= 0xdf; + outb (val1, SMI_EN + 1); + /* Clear out the (probably old) status */ + outb (0, TCO1_STS); + boot_status = (int) inb (TCO2_STS); + outb (3, TCO2_STS); + return 1; + } + return 0; +} + +static struct file_operations i810tco_fops = { + write: i810tco_write, + ioctl: i810tco_ioctl, + open: i810tco_open, + release: i810tco_release, +}; + +static struct miscdevice i810tco_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &i810tco_fops +}; + +static int __init watchdog_init (void) +{ + spin_lock_init(&tco_lock); + if (!i810tco_getdevice () || i810tco_pci == NULL) + return -ENODEV; + if (!check_region (TCOBASE, 0x10)) { + printk (KERN_ERR + "i810 TCO timer: I/O address 0x%04x already in use\n", + TCOBASE); + return -EIO; + } + request_region (TCOBASE, 0x10, "i810 TCO"); + if (misc_register (&i810tco_miscdev) != 0) { + release_region (TCOBASE, 0x10); + printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n"); + return -EIO; + } + tco_timer_settimer ((unsigned char) i810_margin); + tco_timer_reload (); + + printk (KERN_INFO + "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n", + (int) (i810_margin * 6 / 10), TCOBASE); + return 0; +} + +static void watchdog_cleanup (void) +{ + u8 val; + + /* Reset the timer before we leave */ + tco_timer_reload (); + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_byte (i810tco_pci, 0xd4, &val); + val |= 0x02; + pci_write_config_byte (i810tco_pci, 0xd4, val); + release_region (TCOBASE, 0x10); + misc_deregister (&i810tco_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/i810-tco.h linux/drivers/char/i810-tco.h --- v2.2.18/drivers/char/i810-tco.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/char/i810-tco.h Sun Mar 25 11:37:31 2001 @@ -0,0 +1,45 @@ +/* + * i810-tco 0.02: TCO timer driver for i810 chipsets + * + * (c) Copyright 2000 kernel concepts , All Rights Reserved. + * http://www.kernelconcepts.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i810 chipsets + * based on softdog.c by Alan Cox + * + * The TCO timer is implemented in the 82801AA (82801AB) chip, + * see intel documentation from http://developer.intel.com, + * order number 290655-003 + * + * For history see i810-tco.c + */ + + +/* + * Some address definitions for the i810 TCO + */ + +#define TCOBASE ACPIBASE + 0x60 /* TCO base address */ +#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ +#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */ +#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ +#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ +#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ +#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ +#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ +#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ + +#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/lp.c linux/drivers/char/lp.c --- v2.2.18/drivers/char/lp.c Sun Mar 25 11:12:56 2001 +++ linux/drivers/char/lp.c Sun Mar 25 11:37:31 2001 @@ -307,32 +307,11 @@ /* * NOTE: if you run with irqs you _must_ use * `tunelp /dev/lp? -c 1' to be rasonable efficient! + * + * ..but beware that data corruption can happen that way. -Tim */ if (++count == LP_CHAR(minor)) - { - if (irq_ok) - { - static int first_time = 1; - /* - * The printer is using a buggy handshake, so - * revert to polling to not overload the - * machine and warn the user that its printer - * could get optimized trusting the irq. -arca - */ - lp_table[minor].irq_missed = 1; - if (first_time) - { - first_time = 0; - printk(KERN_WARNING "lp%d: the " - "printing could be optimized " - "using the TRUST_IRQ flag, " - "see the top of " - "linux/drivers/char/lp.c\n", - minor); - } - } return 0; - } } w_dtr(minor, lpchar); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/mem.c linux/drivers/char/mem.c --- v2.2.18/drivers/char/mem.c Sun Mar 25 11:28:23 2001 +++ linux/drivers/char/mem.c Sun Mar 25 11:37:31 2001 @@ -34,9 +34,6 @@ #ifdef CONFIG_SPARCAUDIO extern int sparcaudio_init(void); #endif -#ifdef CONFIG_ISDN -int isdn_init(void); -#endif #ifdef CONFIG_PHONE extern int telephony_init(void); #endif @@ -646,9 +643,6 @@ #endif #if CONFIG_QIC02_TAPE qic02_tape_init(); -#endif -#if CONFIG_ISDN - isdn_init(); #endif #ifdef CONFIG_FTAPE ftape_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/misc.c linux/drivers/char/misc.c --- v2.2.18/drivers/char/misc.c Sun Mar 25 11:28:23 2001 +++ linux/drivers/char/misc.c Sun Mar 25 11:37:31 2001 @@ -139,8 +139,17 @@ int misc_register(struct miscdevice * misc) { + struct miscdevice *c; + if (misc->next || misc->prev) return -EBUSY; + c = misc_list.next; + + while ((c != &misc_list) && (c->minor != misc->minor)) + c = c->next; + if (c != &misc_list) + return -EBUSY; + if (misc->minor == MISC_DYNAMIC_MINOR) { int i = DYNAMIC_MINORS; while (--i >= 0) @@ -229,6 +238,9 @@ #endif #ifdef CONFIG_ACQUIRE_WDT acq_init(); +#endif +#ifdef CONFIG_ADVANTECH_WDT + advwdt_init(); #endif #ifdef CONFIG_60XX_WDT sbc60xxwdt_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c --- v2.2.18/drivers/char/n_hdlc.c Sun Mar 25 11:28:23 2001 +++ linux/drivers/char/n_hdlc.c Sun Mar 25 11:37:31 2001 @@ -9,7 +9,7 @@ * Al Longyear , Paul Mackerras * * Original release 01/11/99 - * ==FILEDATE 20000515== + * $Id: n_hdlc.c,v 2.2 2000/11/08 17:08:29 paul Exp $ * * This code is released under the GNU General Public License (GPL) * @@ -78,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "1.15" +#define HDLC_VERSION "2.2" #include #include @@ -93,14 +93,7 @@ #undef VERSION #define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch)) -#if LINUX_VERSION_CODE < VERSION(2,1,14) -#include -#endif - -#if LINUX_VERSION_CODE >= VERSION(2,1,23) #include -#endif - #include #include #include @@ -118,79 +111,23 @@ #include #endif -#if LINUX_VERSION_CODE >= VERSION(2,1,4) +#if LINUX_VERSION_CODE < VERSION(2,2,18) +typedef struct wait_queue *wait_queue_head_t; +#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL} +#define init_waitqueue_head(head) *(head) = NULL +#define set_current_state(a) current->state = (a) +#endif + #include #define GET_USER(error,value,addr) error = get_user(value,addr) #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 #define PUT_USER(error,value,addr) error = put_user(value,addr) #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 -#if LINUX_VERSION_CODE >= VERSION(2,1,5) #include -#endif - -#else /* 2.0.x and 2.1.x before 2.1.4 */ - -#define GET_USER(error,value,addr) \ -do { \ - error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ - if (error == 0) \ - value = get_user(addr); \ -} while (0) - -#define COPY_FROM_USER(error,dest,src,size) \ -do { \ - error = verify_area (VERIFY_READ, (void *) src, size); \ - if (error == 0) \ - memcpy_fromfs (dest, src, size); \ -} while (0) - -#define PUT_USER(error,value,addr) \ -do { \ - error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ - if (error == 0) \ - put_user (value, addr); \ -} while (0) - -#define COPY_TO_USER(error,dest,src,size) \ -do { \ - error = verify_area (VERIFY_WRITE, (void *) dest, size); \ - if (error == 0) \ - memcpy_tofs (dest, src, size); \ -} while (0) -#endif - -#if LINUX_VERSION_CODE < VERSION(2,1,0) -#define __init -typedef int spinlock_t; -#define spin_lock_init(a) -#define spin_lock_irqsave(a,b) {save_flags((b));cli();} -#define spin_unlock_irqrestore(a,b) {restore_flags((b));} -#define spin_lock(a) -#define spin_unlock(a) -#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();} -#endif - -#if LINUX_VERSION_CODE < VERSION(2,1,37) -#define test_and_set_bit(nr, addr) set_bit(nr, addr) -#endif - -#if LINUX_VERSION_CODE < VERSION(2,1,57) -#define signal_pending(p) ((p)->signal & ~(p)->blocked) -#endif - -#if LINUX_VERSION_CODE < VERSION(2,1,25) -#define net_device_stats enet_statistics -#endif - -#if LINUX_VERSION_CODE < VERSION(2,1,60) -typedef int rw_ret_t; -typedef unsigned int rw_count_t; -#else typedef ssize_t rw_ret_t; typedef size_t rw_count_t; -#endif /* * Buffers for individual HDLC frames @@ -254,10 +191,8 @@ static struct n_hdlc *n_hdlc_alloc (void); -#if LINUX_VERSION_CODE >= VERSION(2,1,19) MODULE_PARM(debuglevel, "i"); MODULE_PARM(maxframe, "i"); -#endif /* debug level can be set by insmod for debugging purposes */ #define DEBUG_LEVEL_INFO 1 @@ -274,13 +209,8 @@ struct file *, const __u8 *, rw_count_t); static int n_hdlc_tty_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); -#if LINUX_VERSION_CODE < VERSION(2,1,23) -static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode, - struct file *filp, int sel_type, select_table * wait); -#else static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait); -#endif static int n_hdlc_tty_open (struct tty_struct *); static void n_hdlc_tty_close (struct tty_struct *); static int n_hdlc_tty_room (struct tty_struct *tty); @@ -653,10 +583,10 @@ wake_up_interruptible (&n_hdlc->read_wait); wake_up_interruptible (&n_hdlc->poll_wait); if (n_hdlc->tty->fasync != NULL) -#if LINUX_VERSION_CODE < VERSION(2,3,0) - kill_fasync (n_hdlc->tty->fasync, SIGIO); -#else +#if LINUX_VERSION_CODE >= VERSION(2,2,14) && defined(__rh_config_h__) kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN); +#else + kill_fasync (n_hdlc->tty->fasync, SIGIO); #endif } /* end of n_hdlc_tty_receive() */ @@ -886,73 +816,6 @@ } /* end of n_hdlc_tty_ioctl() */ -#if LINUX_VERSION_CODE < VERSION(2,1,23) -/* n_hdlc_tty_select() - * - * Device select method. Determine if operation requires - * blocking and if so put appropriate wait queue in select - * table and return 0, otherwise return 1. - * - * Arguments: - * - * tty pointer to tty device instance data - * inode pointer to inode for device - * filp pointer to file object - * sel_type identified the select type (read/write/exception) - * wait select table for adding wait queue if appropriate - * - * Return Value: - * - * 1 if no need to block on operation - * 0 if must block and wait queue added to select table - */ -static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode, - struct file *filp, int sel_type, select_table * wait) -{ - struct n_hdlc *n_hdlc = tty2n_hdlc(tty); - int result = 1; - - if (debuglevel >= DEBUG_LEVEL_INFO) - printk("%s(%d)n_hdlc_tty_select() called\n",__FILE__,__LINE__); - - /* Verify the status of the device */ - if (!n_hdlc) - return -EBADF; - - if (n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) - return -EBADF; - - switch (sel_type) { - case SEL_IN: - if (n_hdlc->rx_buf_list.head) - break; - - case SEL_EX: /* Exceptions or read errors */ - /* Is this a pty link and the remote disconnected? */ - if (tty->flags & (1 << TTY_OTHER_CLOSED)) - break; - - /* Is this a local link and the modem disconnected? */ - if (tty_hung_up_p (filp)) - break; - - select_wait (&n_hdlc->read_wait, wait); - result = 0; - break; - - /* Write mode. A write is allowed if there is no current transmission */ - case SEL_OUT: - if (!n_hdlc->tx_free_buf_list.head) { - select_wait (&n_hdlc->write_wait, wait); - result = 0; - } - break; - } - return result; -} /* end of n_hdlc_tty_select() */ - -#else /* 2.1.23 or later */ - /* n_hdlc_tty_poll() * * TTY callback for poll system call. Determine which @@ -981,11 +844,8 @@ if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) { /* queue current process into any wait queue that */ /* may awaken in the future (read and write) */ -#if LINUX_VERSION_CODE < VERSION(2,1,89) - poll_wait(&n_hdlc->poll_wait, wait); -#else poll_wait(filp, &n_hdlc->poll_wait, wait); -#endif + /* set bits for operations that wont block */ if(n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ @@ -999,8 +859,6 @@ return mask; } /* end of n_hdlc_tty_poll() */ -#endif - /* n_hdlc_alloc() * * Allocate an n_hdlc instance data structure @@ -1153,19 +1011,13 @@ memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc)); n_hdlc_ldisc.magic = TTY_LDISC_MAGIC; -#if LINUX_VERSION_CODE >= VERSION(2,1,28) n_hdlc_ldisc.name = "hdlc"; -#endif n_hdlc_ldisc.open = n_hdlc_tty_open; n_hdlc_ldisc.close = n_hdlc_tty_close; n_hdlc_ldisc.read = n_hdlc_tty_read; n_hdlc_ldisc.write = n_hdlc_tty_write; n_hdlc_ldisc.ioctl = n_hdlc_tty_ioctl; -#if LINUX_VERSION_CODE < VERSION(2,1,23) - n_hdlc_ldisc.select = n_hdlc_tty_select; -#else n_hdlc_ldisc.poll = n_hdlc_tty_poll; -#endif n_hdlc_ldisc.receive_room = n_hdlc_tty_room; n_hdlc_ldisc.receive_buf = n_hdlc_tty_receive; n_hdlc_ldisc.write_wakeup = n_hdlc_tty_wakeup; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/serial.c linux/drivers/char/serial.c --- v2.2.18/drivers/char/serial.c Sun Mar 25 11:12:57 2001 +++ linux/drivers/char/serial.c Sun Mar 25 11:37:31 2001 @@ -150,6 +150,12 @@ #include #include +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 4 +#else +#define SERIAL_DEV_OFFSET 0 +#endif + #ifdef SERIAL_INLINE #define _INLINE_ inline #endif @@ -3130,7 +3136,7 @@ serial_driver.driver_name = "serial"; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; - serial_driver.minor_start = 64; + serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; @@ -3194,11 +3200,22 @@ state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; state->irq = irq_cannonicalize(state->irq); - if (check_region(state->port,8)) - continue; - if (state->flags & ASYNC_BOOT_AUTOCONF) - autoconfig(state); +#ifdef CONFIG_PPC + /* PowerMacs don't have legacy serial ports on IOs and would machine check */ + if (_machine != _MACH_Pmac) { +#endif + if (check_region(state->port,8)) + continue; + if (state->flags & ASYNC_BOOT_AUTOCONF) + autoconfig(state); +#ifdef CONFIG_PPC + } +#endif } +#ifdef CONFIG_PPC + if (_machine == _MACH_Pmac) + return 0; +#endif /* * Detect the IRQ only once every port is initialised, * because some 16450 do not reset to 0 the MCR register. @@ -3268,22 +3285,22 @@ state->irq = detect_uart_irq(state); printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n", - state->line, state->port, state->irq, + state->line + SERIAL_DEV_OFFSET, state->port, state->irq, uart_config[state->type].name); - return state->line; + return state->line + SERIAL_DEV_OFFSET; } void unregister_serial(int line) { unsigned long flags; - struct serial_state *state = &rs_table[line]; + struct serial_state *state = &rs_table[line + SERIAL_DEV_OFFSET]; save_flags(flags); cli(); if (state->info && state->info->tty) tty_hangup(state->info->tty); state->type = PORT_UNKNOWN; - printk(KERN_INFO "tty%02d unloaded\n", state->line); + printk(KERN_INFO "tty%02d unloaded\n", state->line + SERIAL_DEV_OFFSET); restore_flags(flags); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/sx.c linux/drivers/char/sx.c --- v2.2.18/drivers/char/sx.c Sun Mar 25 11:28:23 2001 +++ linux/drivers/char/sx.c Sun Mar 25 11:37:31 2001 @@ -1799,6 +1799,20 @@ } +static void sx_break (struct tty_struct * tty, int flag) +{ + struct sx_port *port = tty->driver_data; + int rv; + + if (flag) + rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK); + else + rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN); + if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n", + read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat))); +} + + static int sx_ioctl (struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { @@ -1867,7 +1881,6 @@ sx_reconfigure_port(port); } break; - default: rc = -ENOIOCTLCMD; break; @@ -2247,6 +2260,7 @@ sx_driver.table = sx_table; sx_driver.termios = sx_termios; sx_driver.termios_locked = sx_termios_locked; + sx_driver.break_ctl = sx_break; sx_driver.open = sx_open; sx_driver.close = gs_close; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/synclink.c linux/drivers/char/synclink.c --- v2.2.18/drivers/char/synclink.c Sun Mar 25 11:28:23 2001 +++ linux/drivers/char/synclink.c Sun Mar 25 11:37:31 2001 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * ==FILEDATE 20000821== + * $Id: synclink.c,v 2.4 2000/12/11 20:08:18 paul Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -79,17 +79,10 @@ #include #include #include - #include - -#if LINUX_VERSION_CODE >= VERSION(2,1,0) #include #include #include -#else -#include -#endif - #include #include @@ -102,90 +95,34 @@ #include #include +#if LINUX_VERSION_CODE < VERSION(2,2,18) +typedef struct wait_queue *wait_queue_head_t; +#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL} +#define init_waitqueue_head(head) *(head) = NULL +#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX +#define set_current_state(a) current->state = (a) +#endif + #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE #define CONFIG_SYNCLINK_SYNCPPP 1 #endif #ifdef CONFIG_SYNCLINK_SYNCPPP -#if LINUX_VERSION_CODE < VERSION(2,3,43) #include "../net/syncppp.h" #define net_device device #define netif_stop_queue(a) (a)->tbusy = 1 #define netif_start_queue(a) (a)->tbusy = 0 #define netif_wake_queue(a) (a)->tbusy = 0; mark_bh(NET_BH) #define netif_queue_stopped(a) ((a)->tbusy) -#else -#include "../net/wan/syncppp.h" -#endif #endif -#if LINUX_VERSION_CODE >= VERSION(2,1,4) #include #define GET_USER(error,value,addr) error = get_user(value,addr) #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 #define PUT_USER(error,value,addr) error = put_user(value,addr) #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 -#if LINUX_VERSION_CODE >= VERSION(2,1,5) #include -#endif - -#else /* 2.0.x and 2.1.x before 2.1.4 */ - -#define GET_USER(error,value,addr) \ -do { \ - error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ - if (error == 0) \ - value = get_user(addr); \ -} while (0) - -#define COPY_FROM_USER(error,dest,src,size) \ -do { \ - error = verify_area (VERIFY_READ, (void *) src, size); \ - if (error == 0) \ - memcpy_fromfs (dest, src, size); \ -} while (0) - -#define PUT_USER(error,value,addr) \ -do { \ - error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ - if (error == 0) \ - put_user (value, addr); \ -} while (0) - -#define COPY_TO_USER(error,dest,src,size) \ -do { \ - error = verify_area (VERIFY_WRITE, (void *) dest, size); \ - if (error == 0) \ - memcpy_tofs (dest, src, size); \ -} while (0) - -#endif - -#if LINUX_VERSION_CODE < VERSION(2,1,0) -/* - * This is used to figure out the divisor speeds and the timeouts - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; - -#define __init -#define ioremap(a,b) vremap((a),(b)) -#define iounmap(a) vfree((a)) -#define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 -typedef int spinlock_t; -#define spin_lock_init(a) -#define spin_lock_irqsave(a,b) {save_flags((b));cli();} -#define spin_unlock_irqrestore(a,b) {restore_flags((b));} -#define spin_lock(a) -#define spin_unlock(a) -#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();} -#define signal_pending(a) ((a)->signal & ~(a)->blocked) -#endif - - #include "linux/synclink.h" @@ -944,7 +881,6 @@ static int maxframe[MAX_TOTAL_DEVICES] = {0,}; static int dosyncppp[MAX_TOTAL_DEVICES] = {0,}; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) MODULE_PARM(break_on_load,"i"); MODULE_PARM(ttymajor,"i"); MODULE_PARM(cuamajor,"i"); @@ -954,10 +890,9 @@ MODULE_PARM(debug_level,"i"); MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); -#endif static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "1.22"; +static char *driver_version = "2.3"; static struct tty_driver serial_driver, callout_driver; static int serial_refcount; @@ -969,9 +904,9 @@ static void mgsl_change_params(struct mgsl_struct *info); static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); -static struct tty_struct **serial_table = NULL; -static struct termios **serial_termios = NULL; -static struct termios **serial_termios_locked = NULL; +static struct tty_struct *serial_table[MAX_TOTAL_DEVICES]; +static struct termios *serial_termios[MAX_TOTAL_DEVICES]; +static struct termios *serial_termios_locked[MAX_TOTAL_DEVICES]; #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -1372,11 +1307,6 @@ #endif } else info->input_signal_events.dcd_down++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & MISCSTATUS_DCD_LATCHED)) - hardpps(); -#endif } if (status & MISCSTATUS_CTS_LATCHED) { @@ -1583,14 +1513,8 @@ icount->parity,icount->frame,icount->overrun); } - if ( tty->flip.count ) { -#if LINUX_VERSION_CODE >= VERSION(2,1,0) + if ( tty->flip.count ) tty_flip_buffer_push(tty); -#else - queue_task(&tty->flip.tqueue, &tq_timer); -#endif - } - } /* end of mgsl_isr_receive_data() */ @@ -1787,11 +1711,7 @@ retval = mgsl_adapter_test(info); if ( retval ) { -#if LINUX_VERSION_CODE >= VERSION(2,1,0) if (capable(CAP_SYS_ADMIN) && info->tty) -#else - if (suser() && info->tty) -#endif set_bit(TTY_IO_ERROR, &info->tty->flags); mgsl_release_resources(info); return retval; @@ -1967,19 +1887,7 @@ * current data rate. */ if (info->params.data_rate <= 460800) { -#if LINUX_VERSION_CODE >= VERSION(2,1,0) info->params.data_rate = tty_get_baud_rate(info->tty); -#else - int i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 4) - info->tty->termios->c_cflag &= ~CBAUDEX; - else - i += 15; - } - info->params.data_rate = baud_table[i]; -#endif } if ( info->params.data_rate ) { @@ -2942,7 +2850,6 @@ } /* end of set_modem_info() */ -#if LINUX_VERSION_CODE >= VERSION(2,1,0) /* mgsl_break() Set or clear transmit break condition * * Arguments: tty pointer to tty instance data @@ -2969,7 +2876,6 @@ spin_unlock_irqrestore(&info->irq_spinlock,flags); } /* end of mgsl_break() */ -#endif /* mgsl_ioctl() Service an IOCTL request * @@ -3092,7 +2998,6 @@ if (error) return error; PUT_USER(error,cnow.dcd, &p_cuser->dcd); if (error) return error; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) PUT_USER(error,cnow.rx, &p_cuser->rx); if (error) return error; PUT_USER(error,cnow.tx, &p_cuser->tx); @@ -3107,7 +3012,6 @@ if (error) return error; PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); if (error) return error; -#endif return 0; default: return -ENOIOCTLCMD; @@ -3346,7 +3250,6 @@ } } - set_current_state(TASK_RUNNING); exit: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_wait_until_sent(%s) exit\n", @@ -3589,9 +3492,7 @@ tmp_buf = (unsigned char *) page; } -#if LINUX_VERSION_CODE >= VERSION(2,1,0) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { @@ -3978,27 +3879,19 @@ } /* end of mgsl_alloc_buffer_list_memory() */ -/* - * mgsl_free_buffer_list_memory() - * - * Free the common DMA buffer allocated for use as the - * receive and transmit buffer lists. The associated Memory - * Descriptor List (MDL) is also freed. - * +/* Free DMA buffers allocated for use as the + * receive and transmit buffer lists. * Warning: * * The data transfer buffers associated with the buffer list * MUST be freed before freeing the buffer list itself because * the buffer list contains the information necessary to free * the individual buffers! - * - * Arguments: info pointer to device extension - * Return Value: None */ void mgsl_free_buffer_list_memory( struct mgsl_struct *info ) { if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI ) - kfree_s(info->buffer_list, BUFFERLISTSIZE); + kfree(info->buffer_list); info->buffer_list = NULL; info->rx_buffer_list = NULL; @@ -4072,7 +3965,7 @@ for ( i = 0 ; i < Buffercount ; i++ ) { if ( BufferList[i].virt_addr ) { if ( info->bus_type != MGSL_BUS_TYPE_PCI ) - kfree_s(BufferList[i].virt_addr, DMABUFFERSIZE); + kfree(BufferList[i].virt_addr); BufferList[i].virt_addr = NULL; } } @@ -4131,19 +4024,12 @@ void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info) { if ( info->intermediate_rxbuffer ) - kfree_s( info->intermediate_rxbuffer, info->max_frame_size); + kfree(info->intermediate_rxbuffer); info->intermediate_rxbuffer = NULL; } /* end of mgsl_free_intermediate_rxbuffer_memory() */ -/* mgsl_claim_resources() - * - * Claim all resources used by a device - * - * Arguments: info pointer to device instance data - * Return Value: 0 if success, otherwise -ENODEV - */ int mgsl_claim_resources(struct mgsl_struct *info) { /* claim 16C32 I/O base address */ @@ -4168,7 +4054,7 @@ info->irq_requested = 1; if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { - /* claim shared memory range */ + info->memory_base = ioremap(info->phys_memory_base,0x40000); if (!info->memory_base) { printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n", @@ -4177,7 +4063,6 @@ return -ENODEV; } - /* test the shared memory range */ if ( !mgsl_memory_test(info) ) { printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); @@ -4185,7 +4070,6 @@ return -ENODEV; } - /* claim LCR memory range */ info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset; if (!info->lcr_base) { printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n", @@ -4221,13 +4105,6 @@ } /* end of mgsl_claim_resources() */ -/* mgsl_release_resources() - * - * Release all resources used by a device - * - * Arguments: info pointer to device instance data - * Return Value: None - */ void mgsl_release_resources(struct mgsl_struct *info) { if ( debug_level >= DEBUG_LEVEL_INFO ) @@ -4380,9 +4257,7 @@ printk("ISA device specified io=%04X,irq=%d,dma=%d\n", io[i], irq[i], dma[i] ); - info = mgsl_allocate_device(); - if ( !info ) { - /* error allocating device instance data */ + if (!(info = mgsl_allocate_device())) { if ( debug_level >= DEBUG_LEVEL_ERROR ) printk( "can't allocate device instance data.\n"); continue; @@ -4391,12 +4266,7 @@ /* Copy user configuration info to device instance data */ info->io_base = (unsigned int)io[i]; info->irq_level = (unsigned int)irq[i]; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) info->irq_level = irq_cannonicalize(info->irq_level); -#else - if (info->irq_level == 2) - info->irq_level = 9; -#endif info->dma_level = (unsigned int)dma[i]; info->bus_type = MGSL_BUS_TYPE_ISA; info->io_addr_size = 16; @@ -4412,73 +4282,29 @@ if ( pcibios_present() ) { unsigned char bus; unsigned char func; - unsigned int shared_mem_base; - unsigned int lcr_mem_base; - unsigned int io_base; - unsigned char irq_line; for(i=0;;i++){ if ( PCIBIOS_SUCCESSFUL == pcibios_find_device( MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) { -#if LINUX_VERSION_CODE >= VERSION(2,1,0) struct pci_dev *pdev = pci_find_slot(bus,func); - irq_line = pdev->irq; -#else - if (pcibios_read_config_byte(bus,func, - PCI_INTERRUPT_LINE,&irq_line) ) { - printk( "%s(%d):USC I/O addr not set.\n", - __FILE__,__LINE__); - continue; - } -#endif - - if (pcibios_read_config_dword(bus,func, - PCI_BASE_ADDRESS_3,&shared_mem_base) ) { - printk( "%s(%d):Shared mem addr not set.\n", - __FILE__,__LINE__); - continue; - } - - if (pcibios_read_config_dword(bus,func, - PCI_BASE_ADDRESS_0,&lcr_mem_base) ) { - printk( "%s(%d):LCR mem addr not set.\n", - __FILE__,__LINE__); - continue; - } - if (pcibios_read_config_dword(bus,func, - PCI_BASE_ADDRESS_2,&io_base) ) { - printk( "%s(%d):USC I/O addr not set.\n", - __FILE__,__LINE__); - continue; - } - - info = mgsl_allocate_device(); - if ( !info ) { - /* error allocating device instance data */ + if (!(info = mgsl_allocate_device())) { if ( debug_level >= DEBUG_LEVEL_ERROR ) printk( "can't allocate device instance data.\n"); continue; } /* Copy user configuration info to device instance data */ + info->irq_level = pdev->irq; + info->phys_lcr_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; + info->io_base = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK; + info->phys_memory_base = pdev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK; - info->io_base = io_base & PCI_BASE_ADDRESS_IO_MASK; - info->irq_level = (unsigned int)irq_line; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) - info->irq_level = irq_cannonicalize(info->irq_level); -#else - if (info->irq_level == 2) - info->irq_level = 9; -#endif - info->phys_memory_base = shared_mem_base & PCI_BASE_ADDRESS_MEM_MASK; - /* Because veremap only works on page boundaries we must map * a larger area than is actually implemented for the LCR * memory range. We map a full page starting at the page boundary. */ - info->phys_lcr_base = lcr_mem_base & PCI_BASE_ADDRESS_MEM_MASK; info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1); info->phys_lcr_base &= ~(PAGE_SIZE-1); @@ -4508,30 +4334,9 @@ } #endif - /* - * Allocate memory to hold the following tty/termios arrays - * with an element for each enumerated device. - */ - - serial_table = (struct tty_struct**)kmalloc(sizeof(struct tty_struct*)*mgsl_device_count, GFP_KERNEL); - serial_termios = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL); - serial_termios_locked = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL); - - if (!serial_table || !serial_termios || !serial_termios_locked){ - printk("%s(%d):Can't allocate tty/termios arrays.\n", - __FILE__,__LINE__); - if (serial_table) - kfree(serial_table); - if (serial_termios) - kfree(serial_termios); - if (serial_termios_locked) - kfree(serial_termios_locked); - return -ENOMEM; - } - - memset(serial_table,0,sizeof(struct tty_struct*)*mgsl_device_count); - memset(serial_termios,0,sizeof(struct termios*)*mgsl_device_count); - memset(serial_termios_locked,0,sizeof(struct termios*)*mgsl_device_count); + memset(serial_table,0,sizeof(struct tty_struct*)*MAX_TOTAL_DEVICES); + memset(serial_termios,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES); + memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES); return 0; @@ -4548,11 +4353,7 @@ { struct mgsl_struct *info; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) EXPORT_NO_SYMBOLS; -#else - register_symtab(NULL); -#endif printk("%s version %s\n", driver_name, driver_version); @@ -4567,9 +4368,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) serial_driver.driver_name = "synclink"; -#endif serial_driver.name = "ttySL"; serial_driver.major = ttymajor; serial_driver.minor_start = 64; @@ -4596,12 +4395,10 @@ serial_driver.ioctl = mgsl_ioctl; serial_driver.throttle = mgsl_throttle; serial_driver.unthrottle = mgsl_unthrottle; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) serial_driver.send_xchar = mgsl_send_xchar; serial_driver.break_ctl = mgsl_break; serial_driver.wait_until_sent = mgsl_wait_until_sent; serial_driver.read_proc = mgsl_read_proc; -#endif serial_driver.set_termios = mgsl_set_termios; serial_driver.stop = mgsl_stop; serial_driver.start = mgsl_start; @@ -4615,10 +4412,8 @@ callout_driver.name = "cuaSL"; callout_driver.major = cuamajor; callout_driver.subtype = SERIAL_TYPE_CALLOUT; -#if LINUX_VERSION_CODE >= VERSION(2,1,0) callout_driver.read_proc = 0; callout_driver.proc_entry = 0; -#endif if (tty_register_driver(&serial_driver) < 0) printk("%s(%d):Couldn't register serial driver\n", @@ -4645,8 +4440,7 @@ } /* end of mgsl_init() */ -#ifdef MODULE -int init_module(void) +int __init init_module(void) { /* Uncomment this to kernel debug module. * mgsl_get_text_ptr() leaves the .text address in eax @@ -4692,20 +4486,8 @@ tmp_buf = NULL; } - if (serial_table) - kfree_s(serial_table,sizeof(struct tty_struct*)*mgsl_device_count); - - if (serial_termios) - kfree_s(serial_termios,sizeof(struct termios*)*mgsl_device_count); - - if (serial_termios_locked) - kfree_s(serial_termios_locked,sizeof(struct termios*)*mgsl_device_count); - } /* end of cleanup_module() */ -#endif /* MODULE */ - - /* * usc_RTCmd() * @@ -6952,7 +6734,6 @@ while( EndTime-- && !info->irq_occurred ) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(jiffies_from_ms(10)); - set_current_state(TASK_RUNNING); } spin_lock_irqsave(&info->irq_spinlock,flags); @@ -7575,7 +7356,7 @@ sppp_attach(&info->pppdev); d = info->netdev; - strcpy(d->name, info->netname); + d->name = info->netname; d->base_addr = info->io_base; d->irq = info->irq_level; d->dma = info->dma_level; @@ -7586,10 +7367,6 @@ d->hard_start_xmit = mgsl_sppp_tx; d->do_ioctl = mgsl_sppp_ioctl; d->get_stats = mgsl_net_stats; -#if LINUX_VERSION_CODE >= VERSION(2,3,43) - d->tx_timeout = mgsl_sppp_tx_timeout; - d->watchdog_timeo = 10*HZ; -#endif dev_init_buffers(d); if (register_netdev(d) == -1) { @@ -7679,7 +7456,6 @@ if (debug_level >= DEBUG_LEVEL_INFO) printk("mgsl_sppp_tx(%s)\n",info->netname); -#if LINUX_VERSION_CODE < VERSION(2,3,43) if (dev->tbusy) { if (time_before(jiffies, dev->trans_start+10*HZ)) return -EBUSY; /* 10 seconds timeout */ @@ -7687,9 +7463,6 @@ } if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) return -EBUSY; -#else - netif_stop_queue(dev); -#endif info->xmit_cnt = skb->len; mgsl_load_tx_dma_buffer(info, skb->data, skb->len); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/char/toshiba.c linux/drivers/char/toshiba.c --- v2.2.18/drivers/char/toshiba.c Sun Mar 25 11:13:00 2001 +++ linux/drivers/char/toshiba.c Sun Mar 25 12:45:19 2001 @@ -1,19 +1,24 @@ /* toshiba.c -- Linux driver for accessing the SMM on Toshiba laptops * - * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) + * Copyright (c) 1996-2001 Jonathan A. Buzzard (jonathan@buzzard.org.uk) * * Valuable assistance and patches from: * Tom May * Rob Napier * * Fn status port numbers for machine ID's courtesy of + * 0xfc02: Scott Eisert + * 0xfc04: Steve VanDevender * 0xfc08: Garth Berry + * 0xfc0a: Egbert Eich + * 0xfc10: Andrew Lofthouse * 0xfc11: Spencer Olson * 0xfc13: Claudius Frankewitz * 0xfc15: Tom May * 0xfc17: Dave Konrad * 0xfc1a: George Betzos * 0xfc1d: Arthur Liu + * 0xfcd1: Mr. Dave Konrad * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * @@ -46,11 +51,19 @@ * */ -#define TOSH_VERSION "1.7 22/6/2000" +/* this appears to be needed for gcc 2.9.5 and upwards */ +/* +#define KERNEL_STRICT_NAMES +*/ + + +#define TOSH_VERSION "1.9 22/3/2001" #define TOSH_DEBUG 0 +#ifdef MODULE #include #include +#endif #include #include #include @@ -59,11 +72,13 @@ #include #include #include -#include +#include +#ifdef CONFIG_PROC_FS #include #include +#endif -#include +#include"toshiba.h" #define TOSH_MINOR_DEV 181 @@ -72,10 +87,8 @@ static int tosh_date = 0x0000; static int tosh_sci = 0x0000; static int tosh_fan = 0; -static int tosh_start = 0; -static int tosh_extent = 0; -static int tosh_fn = 0; +int tosh_fn = 0; MODULE_PARM(tosh_fn, "i"); @@ -108,9 +121,12 @@ &tosh_fops }; +#ifdef CONFIG_PROC_FS static struct proc_dir_entry tosh_proc_entry = { 0, 7, "toshiba", S_IFREG|S_IRUGO, 1, 0, 0, 33, NULL, tosh_get_info, NULL }; +#endif + /* * Read the Fn key status @@ -135,27 +151,6 @@ /* - * At some point we need to emulate setting the HDD auto off times for - * the new laptops. We can do this by calling the ide_ioctl on /dev/hda. - * The values we need for the various times are - * - * Disabled 0x00 - * 1 minute 0x0c - * 3 minutes 0x24 - * 5 minutes 0x3c - * 10 minutes 0x78 - * 15 minutes 0xb4 - * 20 minutes 0xf0 - * 30 minutes 0xf1 - * - */ -/*static int tosh_emulate_hdd(SMMRegisters *regs) -{ - return 0; -}*/ - - -/* * For the Portage 610CT and the Tecra 700CS/700CDT emulate the HCI fan function */ static int tosh_emulate_fan(SMMRegisters *regs) @@ -312,8 +307,7 @@ if (!arg) return -EINVAL; - if(copy_from_user(®s, (SMMRegisters *) arg, sizeof(SMMRegisters))) - return -EFAULT; + copy_from_user(®s, (SMMRegisters *) arg, sizeof(SMMRegisters)); switch (cmd) { case TOSH_SMM: @@ -336,8 +330,7 @@ return -EINVAL; } - if(copy_to_user((SMMRegisters *) arg, ®s, sizeof(SMMRegisters))) - return -EFAULT; + copy_to_user((SMMRegisters *) arg, ®s, sizeof(SMMRegisters)); return (err==0) ? 0:-EINVAL; } @@ -346,6 +339,7 @@ /* * Print the information for /proc/toshiba */ +#ifdef CONFIG_PROC_FS int tosh_get_info(char *buffer, char **start, off_t fpos, int length, int dummy) { char *temp; @@ -374,6 +368,7 @@ return temp-buffer; } +#endif /* @@ -382,11 +377,12 @@ static void tosh_set_fn_port(void) { switch (tosh_id) { + case 0xfc02: case 0xfc04: case 0xfc09: case 0xfc0a: case 0xfc10: case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a: tosh_fn = 0x62; break; - case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: - case 0xfce0: case 0xfce2: + case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: case 0xfce0: + case 0xfce2: tosh_fn = 0x68; break; default: @@ -506,7 +502,6 @@ 0xa0-0xbf we can't. We just have to live dangerously and use the ports anyway, oh boy! */ - /* do we need to emulate the fan? */ if ((tosh_id==0xfccb) || (tosh_id==0xfccc)) @@ -515,7 +510,7 @@ return 0; } -int __init tosh_init(void) +__initfunc(int tosh_init(void)) { /* are we running on a Toshiba laptop */ @@ -535,7 +530,11 @@ misc_register(&tosh_device); /* register the proc entry */ + +#ifdef CONFIG_PROC_FS proc_register(&proc_root, &tosh_proc_entry); +#endif + return 0; } @@ -548,13 +547,14 @@ void cleanup_module(void) { /* remove the proc entry */ + +#ifdef CONFIG_PROC_FS proc_unregister(&proc_root, tosh_proc_entry.low_ino); +#endif /* unregister the device file */ - misc_deregister(&tosh_device); - /* release ports */ - release_region(tosh_start, tosh_extent); + misc_deregister(&tosh_device); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.2.18/drivers/i2o/i2o_block.c Sun Mar 25 11:13:12 2001 +++ linux/drivers/i2o/i2o_block.c Sun Mar 25 11:37:31 2001 @@ -22,6 +22,14 @@ * Removed queue walk, fixed for 64bitness. * Boji T Kannanthanam: * Support for dynamic device creation/deletion + * Set the I2O Block devices to be detected in + * increasing order of TIDs during boot. + * Search and set the I2O block device that we + * boot off from as the first device to be + * claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure + * from the system gendisk list. The I2O block + * devices now appear in /proc/partitions. * To do: * Multiple majors * Serial number scanning to find duplicates for FC multipathing @@ -1538,14 +1546,14 @@ static struct gendisk i2ob_gendisk = { MAJOR_NR, - "i2ohd", + "i2o/hd", 4, 1<<4, MAX_I2OB, i2ob_geninit, i2ob, i2ob_sizes, - 0, + MAX_I2OB, NULL, NULL }; @@ -1654,6 +1662,13 @@ */ i2ob_probe(); + /* + * Adding i2ob_gendisk into the gendisk list. + */ + + i2ob_gendisk.next = gendisk_head; + gendisk_head = &i2ob_gendisk; + return 0; } @@ -1665,7 +1680,7 @@ void cleanup_module(void) { - struct gendisk **gdp; + struct gendisk *gdp; int i; /* @@ -1713,9 +1728,17 @@ * Why isnt register/unregister gendisk in the kernel ??? */ - for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) - if (*gdp == &i2ob_gendisk) - break; + if (gendisk_head == &i2ob_gendisk) { + gendisk_head = i2ob_gendisk.next; + } + else { + for (gdp = gendisk_head; gdp; gdp = gdp->next) + if (gdp->next == &i2ob_gendisk) + { + gdp->next = i2ob_gendisk.next; + break; + } + } } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.2.18/drivers/i2o/i2o_core.c Sun Mar 25 11:13:12 2001 +++ linux/drivers/i2o/i2o_core.c Sun Mar 25 11:37:31 2001 @@ -2901,7 +2901,6 @@ -#ifdef MODULE EXPORT_SYMBOL(i2o_install_handler); EXPORT_SYMBOL(i2o_remove_handler); @@ -2936,6 +2935,8 @@ EXPORT_SYMBOL(i2o_issue_params); EXPORT_SYMBOL(i2o_report_status); + +#ifdef MODULE MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Core"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.2.18/drivers/isdn/Config.in Sun Mar 25 11:13:06 2001 +++ linux/drivers/isdn/Config.in Sun Mar 25 11:37:31 2001 @@ -1,25 +1,31 @@ # # ISDN device configuration # + +# only included if CONFIG_ISDN != n + if [ "$CONFIG_INET" != "n" ]; then bool ' Support synchronous PPP' CONFIG_ISDN_PPP if [ "$CONFIG_ISDN_PPP" != "n" ]; then - bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ - bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP + bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ + bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP + dep_tristate ' Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN fi fi bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then - bool ' Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX + bool ' Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX fi -if [ "$CONFIG_X25" != "n" ]; then + +# CONFIG_X25 is defined only when CONFIG_EXPERIMENTAL=y +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X25" != "n" ]; then bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25 fi mainmenu_option next_comment comment 'ISDN feature submodules' dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN - bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION + dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN endmenu comment 'low-level hardware drivers' @@ -37,6 +43,7 @@ bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD fi bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 + bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1 comment ' HiSax supported cards' bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0 bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 @@ -55,6 +62,7 @@ bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER bool ' MIC card' CONFIG_HISAX_MIC bool ' NETjet card' CONFIG_HISAX_NETJET + bool ' NETspider U card' CONFIG_HISAX_NETJET_U bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR @@ -73,33 +81,62 @@ fi endmenu +### Active ISDN cards + mainmenu_option next_comment comment 'Active ISDN cards' -dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN -dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN -if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN - dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN -fi -dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN + +dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN +dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN +dep_tristate 'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN +dep_tristate 'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN + +bool 'Eicon active card support' CONFIG_ISDN_DRV_EICON if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then - bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA -fi -dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN -if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then - bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA - bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI - if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then - if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - bool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then + dep_tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN + fi + if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then + dep_tristate ' Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN + if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then + dep_bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI + bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA fi fi - bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA - bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA - bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI - if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - bool ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 +fi + +# CAPI subsystem + +tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI +if [ "$CONFIG_ISDN_CAPI" != "n" ]; then + bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON + dep_bool ' CAPI2.0 Middleware support (EXPERIMENTAL)' CONFIG_ISDN_CAPI_MIDDLEWARE $CONFIG_EXPERIMENTAL + dep_tristate ' CAPI2.0 /dev/capi support' CONFIG_ISDN_CAPI_CAPI20 $CONFIG_ISDN_CAPI + if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" = "y" ]; then + dep_mbool ' CAPI2.0 filesystem support' CONFIG_ISDN_CAPI_CAPIFS_BOOL $CONFIG_ISDN_CAPI_CAPI20 + if [ "$CONFIG_ISDN_CAPI_CAPIFS_BOOL" = "y" ]; then + define_tristate CONFIG_ISDN_CAPI_CAPIFS $CONFIG_ISDN_CAPI_CAPI20 + else + define_tristate CONFIG_ISDN_CAPI_CAPIFS n + fi fi - bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON + dep_tristate ' CAPI2.0 capidrv interface support' CONFIG_ISDN_CAPI_CAPIDRV $CONFIG_ISDN_CAPI $CONFIG_ISDN fi + +# CAPI drivers + +if [ "$CONFIG_ISDN_CAPI" != "n" ]; then + dep_tristate ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA $CONFIG_ISDN_CAPI + dep_tristate ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI + dep_mbool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 $CONFIG_ISDN_DRV_AVMB1_B1PCI + dep_tristate ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA $CONFIG_ISDN_CAPI + dep_tristate ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI $CONFIG_PCMCIA + dep_tristate ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI + dep_tristate ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI +fi + +# HYSDN + +dep_tristate ' Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)' CONFIG_HYSDN m $CONFIG_PROC_FS +dep_mbool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI $CONFIG_HYSDN $CONFIG_ISDN_CAPI endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.2.18/drivers/isdn/Makefile Sun Mar 25 11:13:06 2001 +++ linux/drivers/isdn/Makefile Sun Mar 25 11:37:31 2001 @@ -1,141 +1,56 @@ -SUB_DIRS := -MOD_SUB_DIRS := -ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert - -L_OBJS := -LX_OBJS := -M_OBJS := -MX_OBJS := -O_OBJS := -OX_OBJS := -L_TARGET := -O_TARGET := - -ifeq ($(CONFIG_ISDN),y) - L_TARGET := isdn.a - L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o isdn_v110.o - LX_OBJS += isdn_common.o - ifdef CONFIG_ISDN_PPP - L_OBJS += isdn_ppp.o - endif - ifdef CONFIG_ISDN_X25 - L_OBJS += isdn_x25iface.o - L_OBJS += isdn_concap.o - endif - ifdef CONFIG_ISDN_AUDIO - L_OBJS += isdn_audio.o - ifdef CONFIG_ISDN_TTY_FAX - L_OBJS += isdn_ttyfax.o - endif - endif -else - ifeq ($(CONFIG_ISDN),m) - M_OBJS += isdn.o - O_TARGET += isdn.o - O_OBJS += isdn_net.o isdn_tty.o isdn_v110.o - OX_OBJS += isdn_common.o - ifdef CONFIG_ISDN_PPP - O_OBJS += isdn_ppp.o - M_OBJS += isdn_bsdcomp.o - endif - ifdef CONFIG_ISDN_X25 - O_OBJS += isdn_x25iface.o - O_OBJS += isdn_concap.o - endif - ifdef CONFIG_ISDN_AUDIO - O_OBJS += isdn_audio.o - ifdef CONFIG_ISDN_TTY_FAX - O_OBJS += isdn_ttyfax.o - endif - endif - endif -endif - -ifeq ($(CONFIG_ISDN_DIVERSION),y) - ifeq ($(CONFIG_MODULES),y) - MOD_SUB_DIRS += divert - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_HISAX),y) - L_OBJS += hisax/hisax.o - SUB_DIRS += hisax - MOD_SUB_DIRS += hisax -else - ifeq ($(CONFIG_ISDN_DRV_HISAX),m) - MOD_SUB_DIRS += hisax - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_ICN),y) - L_OBJS += icn/icn_obj.o - SUB_DIRS += icn - MOD_SUB_DIRS += icn -else - ifeq ($(CONFIG_ISDN_DRV_ICN),m) - MOD_SUB_DIRS += icn - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_PCBIT),y) - L_OBJS += pcbit/pcbit.o - SUB_DIRS += pcbit - MOD_SUB_DIRS += pcbit -else - ifeq ($(CONFIG_ISDN_DRV_PCBIT),m) - MOD_SUB_DIRS += pcbit - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_SC),y) - L_OBJS += sc/sc.o - SUB_DIRS += sc - MOD_SUB_DIRS += sc -else - ifeq ($(CONFIG_ISDN_DRV_SC),m) - MOD_SUB_DIRS += sc - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) - L_OBJS += avmb1/avmb1.o - SUB_DIRS += avmb1 - MOD_SUB_DIRS += avmb1 -else - ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) - MOD_SUB_DIRS += avmb1 - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_LOOP),y) - L_OBJS += isdnloop/isdnloop.o - SUB_DIRS += isdnloop - MOD_SUB_DIRS += isdnloop -else - ifeq ($(CONFIG_ISDN_DRV_LOOP),m) - MOD_SUB_DIRS += isdnloop - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_ACT2000),y) - L_OBJS += act2000/act2000.o - SUB_DIRS += act2000 - MOD_SUB_DIRS += act2000 -else - ifeq ($(CONFIG_ISDN_DRV_ACT2000),m) - MOD_SUB_DIRS += act2000 - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_EICON),y) - L_OBJS += eicon/eicon.o - SUB_DIRS += eicon - MOD_SUB_DIRS += eicon -else - ifeq ($(CONFIG_ISDN_DRV_EICON),m) - MOD_SUB_DIRS += eicon - endif -endif +# Makefile for the kernel ISDN subsystem and device drivers. -include $(TOPDIR)/Rules.make +# The target object and module list name. +O_TARGET := isdn.a + +# Objects that export symbols. + +export-objs := isdn_common.o + +# Multipart objects. + +list-multi := isdn.o +isdn-objs := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o + +# Optional parts of multipart objects. + +isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o +isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o +isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o +isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o +isdn-objs-$(CONFIG_ISDN_WITH_ABC) += isdn_dwabc.o + +isdn-objs += $(isdn-objs-y) + +# Ordering constraints: isdn.o first, rest doesn't matter + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN) += isdn.o +obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o + +# Object files in subdirectories + +mod-subdirs := avmb1 eicon +subdir-$(CONFIG_ISDN_DIVERSION) += divert +subdir-$(CONFIG_ISDN_DRV_HISAX) += hisax +subdir-$(CONFIG_ISDN_DRV_ICN) += icn +subdir-$(CONFIG_ISDN_DRV_PCBIT) += pcbit +subdir-$(CONFIG_ISDN_DRV_SC) += sc +subdir-$(CONFIG_ISDN_CAPI) += avmb1 +subdir-$(CONFIG_ISDN_DRV_LOOP) += isdnloop +subdir-$(CONFIG_ISDN_DRV_ACT2000) += act2000 +subdir-$(CONFIG_ISDN_DRV_EICON) += eicon +subdir-$(CONFIG_HYSDN) += hysdn + +obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y)) + +# The global Rules.make. + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +isdn.o: $(isdn-objs) + $(LD) -r -o $@ $(isdn-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/Rules.make linux/drivers/isdn/Rules.make --- v2.2.18/drivers/isdn/Rules.make Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/Rules.make Sun Mar 25 11:37:31 2001 @@ -0,0 +1,32 @@ +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +both-m := $(filter $(mod-subdirs), $(subdir-y)) +SUB_DIRS := $(subdir-y) +MOD_SUB_DIRS := $(sort $(subdir-m) $(both-m)) +ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-)) + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/act2000/Makefile linux/drivers/isdn/act2000/Makefile --- v2.2.18/drivers/isdn/act2000/Makefile Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/act2000/Makefile Sun Mar 25 11:37:31 2001 @@ -1,15 +1,21 @@ -L_OBJS := -M_OBJS := -O_OBJS := module.o capi.o act2000_isa.o - -O_TARGET := -ifeq ($(CONFIG_ISDN_DRV_ACT2000),y) - O_TARGET += act2000.o -else - ifeq ($(CONFIG_ISDN_DRV_ACT2000),m) - O_TARGET += act2000.o - M_OBJS = act2000.o - endif -endif +# Makefile for the act2000 ISDN device driver -include $(TOPDIR)/Rules.make +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Multipart objects. + +list-multi := act2000.o +act2000-objs := module.o capi.o act2000_isa.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +act2000.o: $(act2000-objs) + $(LD) -r -o $@ $(act2000-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/act2000/act2000.h linux/drivers/isdn/act2000/act2000.h --- v2.2.18/drivers/isdn/act2000/act2000.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/act2000/act2000.h Sun Mar 25 11:37:31 2001 @@ -1,4 +1,4 @@ -/* $Id: act2000.h,v 1.7 1999/04/12 13:13:54 fritz Exp $ +/* $Id: act2000.h,v 1.8.6.1 2001/02/10 14:41:20 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * @@ -19,31 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: act2000.h,v $ - * Revision 1.7 1999/04/12 13:13:54 fritz - * Made cards pointer static to avoid name-clash. - * - * Revision 1.6 1998/11/05 22:12:38 fritz - * Changed mail-address. - * - * Revision 1.5 1997/10/09 22:22:59 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * - * Revision 1.4 1997/09/25 17:25:37 fritz - * Support for adding cards at runtime. - * Support for new Firmware. - * - * Revision 1.3 1997/09/24 23:11:43 fritz - * Optimized IRQ load and polling-mode. - * - * Revision 1.2 1997/09/24 19:44:12 fritz - * Added MSN mapping support, some cleanup. - * - * Revision 1.1 1997/09/23 18:00:05 fritz - * New driver for IBM Active 2000. - * */ #ifndef act2000_h @@ -113,7 +88,7 @@ #include #include #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/act2000/act2000_isa.c linux/drivers/isdn/act2000/act2000_isa.c --- v2.2.18/drivers/isdn/act2000/act2000_isa.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/act2000/act2000_isa.c Sun Mar 25 11:37:31 2001 @@ -1,4 +1,4 @@ -/* $Id: act2000_isa.c,v 1.10 1999/10/24 18:46:05 fritz Exp $ +/* $Id: act2000_isa.c,v 1.11 2000/11/12 16:32:06 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version). * @@ -19,43 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: act2000_isa.c,v $ - * Revision 1.10 1999/10/24 18:46:05 fritz - * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest - * kernels. - * - * Revision 1.9 1999/09/04 06:20:04 keil - * Changes from kernel set_current_state() - * - * Revision 1.8 1999/01/05 18:29:25 he - * merged remaining schedule_timeout() changes from 2.1.127 - * - * Revision 1.7 1998/11/05 22:12:41 fritz - * Changed mail-address. - * - * Revision 1.6 1998/06/17 19:51:09 he - * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) - * brute force fix to avoid Ugh's in isdn_tty_write() - * cleaned up some dead code - * - * Revision 1.5 1998/02/12 23:06:47 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.4 1997/10/09 22:23:00 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * - * Revision 1.3 1997/09/25 17:25:38 fritz - * Support for adding cards at runtime. - * Support for new Firmware. - * - * Revision 1.2 1997/09/24 23:11:44 fritz - * Optimized IRQ load and polling-mode. - * - * Revision 1.1 1997/09/23 18:00:05 fritz - * New driver for IBM Active 2000. - * */ #define __NO_VERSION__ @@ -78,7 +41,7 @@ act2000_isa_delay(long t) { sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(t); sti(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/act2000/act2000_isa.h linux/drivers/isdn/act2000/act2000_isa.h --- v2.2.18/drivers/isdn/act2000/act2000_isa.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/act2000/act2000_isa.h Sun Mar 25 11:37:31 2001 @@ -1,4 +1,4 @@ -/* $Id: act2000_isa.h,v 1.3 1999/10/24 18:46:05 fritz Exp $ +/* $Id: act2000_isa.h,v 1.4 2000/11/12 16:32:06 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version). * @@ -18,17 +18,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Log: act2000_isa.h,v $ - * Revision 1.3 1999/10/24 18:46:05 fritz - * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest - * kernels. - * - * Revision 1.2 1998/11/05 22:12:43 fritz - * Changed mail-address. - * - * Revision 1.1 1997/09/23 18:00:07 fritz - * New driver for IBM Active 2000. * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/act2000/capi.c linux/drivers/isdn/act2000/capi.c --- v2.2.18/drivers/isdn/act2000/capi.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/act2000/capi.c Sun Mar 25 11:37:31 2001 @@ -1,4 +1,4 @@ -/* $Id: capi.c,v 1.8 1998/11/05 22:12:46 fritz Exp $ +/* $Id: capi.c,v 1.9 2000/11/12 16:32:06 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * CAPI encoder/decoder @@ -19,34 +19,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Log: capi.c,v $ - * Revision 1.8 1998/11/05 22:12:46 fritz - * Changed mail-address. - * - * Revision 1.7 1998/02/23 23:35:41 fritz - * Eliminated some compiler warnings. - * - * Revision 1.6 1998/02/12 23:06:50 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.5 1997/10/09 22:23:02 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * - * Revision 1.4 1997/09/25 17:25:39 fritz - * Support for adding cards at runtime. - * Support for new Firmware. - * - * Revision 1.3 1997/09/24 19:44:14 fritz - * Added MSN mapping support, some cleanup. - * - * Revision 1.2 1997/09/23 19:41:24 fritz - * Disabled Logging of DATA_B3_IND/RESP/REQ/CONF Messages. - * - * Revision 1.1 1997/09/23 18:00:08 fritz - * New driver for IBM Active 2000. * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/act2000/capi.h linux/drivers/isdn/act2000/capi.h --- v2.2.18/drivers/isdn/act2000/capi.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/act2000/capi.h Sun Mar 25 11:37:31 2001 @@ -1,4 +1,4 @@ -/* $Id: capi.h,v 1.5 1998/11/05 22:12:48 fritz Exp $ +/* $Id: capi.h,v 1.6 2000/11/12 16:32:06 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * @@ -18,25 +18,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Log: capi.h,v $ - * Revision 1.5 1998/11/05 22:12:48 fritz - * Changed mail-address. - * - * Revision 1.4 1997/10/01 09:21:04 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.3 1997/09/25 17:25:41 fritz - * Support for adding cards at runtime. - * Support for new Firmware. - * - * Revision 1.2 1997/09/24 19:44:15 fritz - * Added MSN mapping support, some cleanup. - * - * Revision 1.1 1997/09/23 18:00:10 fritz - * New driver for IBM Active 2000. * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c --- v2.2.18/drivers/isdn/act2000/module.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/act2000/module.c Sun Mar 25 11:37:31 2001 @@ -1,4 +1,4 @@ -/* $Id: module.c,v 1.11 1999/10/30 09:48:04 keil Exp $ +/* $Id: module.c,v 1.14.6.2 2000/12/18 22:14:10 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * @@ -19,49 +19,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: module.c,v $ - * Revision 1.11 1999/10/30 09:48:04 keil - * miss one prefix act2000 - * - * Revision 1.10 1999/10/24 18:46:05 fritz - * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest - * kernels. - * - * Revision 1.9 1999/04/12 13:13:56 fritz - * Made cards pointer static to avoid name-clash. - * - * Revision 1.8 1998/11/05 22:12:51 fritz - * Changed mail-address. - * - * Revision 1.7 1998/02/12 23:06:52 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.6 1998/01/31 22:10:42 keil - * changes for 2.1.82 - * - * Revision 1.5 1997/10/09 22:23:04 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * - * Revision 1.4 1997/09/25 17:25:43 fritz - * Support for adding cards at runtime. - * Support for new Firmware. - * - * Revision 1.3 1997/09/24 23:11:45 fritz - * Optimized IRQ load and polling-mode. - * - * Revision 1.2 1997/09/24 19:44:17 fritz - * Added MSN mapping support, some cleanup. - * - * Revision 1.1 1997/09/23 18:00:13 fritz - * New driver for IBM Active 2000. - * */ #include "act2000.h" #include "act2000_isa.h" #include "capi.h" +#include static unsigned short act2000_isa_ports[] = { @@ -563,37 +526,6 @@ return count; } -static void -act2000_putmsg(act2000_card *card, char c) -{ - ulong flags; - - save_flags(flags); - cli(); - *card->status_buf_write++ = c; - if (card->status_buf_write == card->status_buf_read) { - if (++card->status_buf_read > card->status_buf_end) - card->status_buf_read = card->status_buf; - } - if (card->status_buf_write > card->status_buf_end) - card->status_buf_write = card->status_buf; - restore_flags(flags); -} - -static void -act2000_logstat(struct act2000_card *card, char *str) -{ - char *p = str; - isdn_ctrl c; - - while (*p) - act2000_putmsg(card, *p++); - c.command = ISDN_STAT_STAVAIL; - c.driver = card->myid; - c.arg = strlen(str); - card->interface.statcallb(&c); -} - /* * Find card with given driverId */ @@ -889,12 +821,7 @@ #define DRIVERNAME "IBM Active 2000 ISDN driver" -#ifdef MODULE -#define act2000_init init_module -#endif - -int -act2000_init(void) +static int __init act2000_init(void) { printk(KERN_INFO "%s\n", DRIVERNAME); if (!cards) @@ -906,9 +833,7 @@ return 0; } -#ifdef MODULE -void -cleanup_module(void) +static void act2000_exit(void) { act2000_card *card = cards; act2000_card *last; @@ -927,34 +852,5 @@ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } -#else -void -act2000_setup(char *str, int *ints) -{ - int i, j, argc, port, irq, bus; - - argc = ints[0]; - i = 1; - if (argc) - while (argc) { - port = irq = -1; - bus = 0; - if (argc) { - bus = ints[i]; - i++; - argc--; - } - if (argc) { - port = ints[i]; - i++; - argc--; - } - if (argc) { - irq = ints[i]; - i++; - argc--; - } - act2000_addcard(bus, port, irq, act_id); - } -} -#endif +module_init(act2000_init); +module_exit(act2000_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/Makefile linux/drivers/isdn/avmb1/Makefile --- v2.2.18/drivers/isdn/avmb1/Makefile Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/Makefile Sun Mar 25 11:37:31 2001 @@ -1,135 +1,40 @@ -# -# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $ -# -# Makefile for the CAPI and AVM-B1 device drivers. -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes.. -# -# $Log: Makefile,v $ -# Revision 1.8 2000/01/25 14:33:38 calle -# - Added Support AVM B1 PCI V4.0 (tested with prototype) -# - splitted up t1pci.c into b1dma.c for common function with b1pciv4 -# - support for revision register -# -# Revision 1.7 1999/09/15 08:16:03 calle -# Implementation of 64Bit extention complete. -# -# Revision 1.6 1999/07/20 06:41:44 calle -# Bugfix: After the redesign of the AVM B1 driver, the driver didn't even -# compile, if not selected as modules. -# -# Revision 1.5 1999/07/01 15:26:20 calle -# complete new version (I love it): -# + new hardware independed "capi_driver" interface that will make it easy to: -# - support other controllers with CAPI-2.0 (i.e. USB Controller) -# - write a CAPI-2.0 for the passive cards -# - support serial link CAPI-2.0 boxes. -# + wrote "capi_driver" for all supported cards. -# + "capi_driver" (supported cards) now have to be configured with -# make menuconfig, in the past all supported cards where included -# at once. -# + new and better informations in /proc/capi/ -# + new ioctl to switch trace of capi messages per controller -# using "avmcapictrl trace [contr] on|off|...." -# + complete testcircle with all supported cards and also the -# PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. -# -# Revision 1.4 1997/03/30 17:10:40 calle -# added support for AVM-B1-PCI card. -# -# Revision 1.3 1997/03/22 02:00:57 fritz -# -Reworked toplevel Makefile. From now on, no different Makefiles -# for standalone- and in-kernel-compilation are needed any more. -# -Added local Rules.make for above reason. -# -Experimental changes in teles3.c for enhanced IRQ-checking with -# 2.1.X and SMP kernels. -# -Removed diffstd-script, same functionality is in stddiff -r. -# -Enhanced scripts std2kern and stddiff. -# -# Revision 1.1 1997/03/05 21:26:14 fritz -# Renamed, according naming conventions in CVS tree. -# -# Revision 1.1 1997/03/04 21:50:26 calle -# Frirst version in isdn4linux -# -# Revision 2.2 1997/02/12 09:31:39 calle -# -# Revision 1.1 1997/01/31 10:32:20 calle -# Initial revision -# -# - -# -# Objects that don't export a symtab -# -L_OBJS := # used as component of an L_TARGET -O_OBJS := # used as component of an O_TARGET -M_OBJS := # used as module -# -# Objects that do export a symtab -# -LX_OBJS := # used as component of an L_TARGET -OX_OBJS := # used as component of an O_TARGET -MX_OBJS := # used as module -# -# Targets, created by linking others -# -O_TARGET := # used for .o targets (from O and OX objects) -L_TARGET := # used for .a targets (from L and LX objects) - -ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) - O_TARGET += avmb1.o - OX_OBJS += kcapi.o - O_OBJS += capi.o - ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA - O_OBJS += b1isa.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI - O_OBJS += b1pci.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA - O_OBJS += t1isa.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA - OX_OBJS += b1pcmcia.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI - O_OBJS += t1pci.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_C4 - O_OBJS += c4.o - endif - OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o -else - ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) - O_TARGET += kernelcapi.o - OX_OBJS += kcapi.o - M_OBJS += capi.o kernelcapi.o - ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA - M_OBJS += b1isa.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI - M_OBJS += b1pci.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA - M_OBJS += t1isa.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA - MX_OBJS += b1pcmcia.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI - M_OBJS += t1pci.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_C4 - M_OBJS += c4.o - endif - MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o - endif -endif +# Makefile for the AVM ISDN device drivers and CAPI subsystem. + +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Objects that export symbols. + +export-objs := kcapi.o capiutil.o b1dma.o b1pcmcia.o b1.o capifs.o + +# Multipart objects. + +list-multi := kernelcapi.o +kernelcapi-objs := kcapi.o + +# Ordering constraints: kernelcapi.o first + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o capiutil.o +obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o +obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o +obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o +obj-$(CONFIG_ISDN_DRV_AVMB1_B1ISA) += b1isa.o b1.o +obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCI) += b1pci.o b1.o b1dma.o +obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCMCIA) += b1pcmcia.o b1.o +obj-$(CONFIG_ISDN_DRV_AVMB1_AVM_CS) += avm_cs.o +obj-$(CONFIG_ISDN_DRV_AVMB1_T1ISA) += t1isa.o b1.o +obj-$(CONFIG_ISDN_DRV_AVMB1_T1PCI) += t1pci.o b1.o b1dma.o +obj-$(CONFIG_ISDN_DRV_AVMB1_C4) += c4.o b1.o + +# The global Rules.make. + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +kernelcapi.o: $(kernelcapi-objs) + $(LD) -r -o $@ $(kernelcapi-objs) -include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h --- v2.2.18/drivers/isdn/avmb1/avmcard.h Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/avmb1/avmcard.h Sun Mar 25 11:37:31 2001 @@ -1,9 +1,12 @@ /* - * $Id: avmcard.h,v 1.7 2000/01/25 14:33:38 calle Exp $ + * $Id: avmcard.h,v 1.8 2000/10/10 17:44:19 kai Exp $ * * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: avmcard.h,v $ + * Revision 1.8 2000/10/10 17:44:19 kai + * changes from/for 2.2.18 + * * Revision 1.7 2000/01/25 14:33:38 calle * - Added Support AVM B1 PCI V4.0 (tested with prototype) * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c --- v2.2.18/drivers/isdn/avmb1/b1.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/b1.c Sun Mar 25 11:37:31 2001 @@ -1,11 +1,38 @@ /* - * $Id: b1.c,v 1.13 2000/01/25 14:33:38 calle Exp $ + * $Id: b1.c,v 1.20.6.1 2001/02/13 11:43:29 kai Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.20.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.20 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.19 2000/11/19 17:02:47 kai + * compatibility cleanup - part 3 + * + * Revision 1.18 2000/11/19 17:01:53 kai + * compatibility cleanup - part 2 + * + * Revision 1.17 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.16 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.15 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * + * Revision 1.14 2000/06/19 16:51:53 keil + * don't free skb in irq context + * * Revision 1.13 2000/01/25 14:33:38 calle * - Added Support AVM B1 PCI V4.0 (tested with prototype) * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 @@ -85,13 +112,14 @@ #include #include #include +#include #include #include "capilli.h" #include "avmcard.h" #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.13 $"; +static char *revision = "$Revision: 1.20.6.1 $"; /* ------------------------------------------------------------- */ @@ -507,7 +535,7 @@ struct sk_buff *skb; unsigned ApplId; - signed MsgLen; + unsigned MsgLen; unsigned DataB3Len; unsigned NCCI; unsigned WindowSize; @@ -593,25 +621,29 @@ ctrl->ready(ctrl); break; - case RECEIVE_TASK_READY: + case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; - case RECEIVE_DEBUGMSG: + case RECEIVE_DEBUGMSG: MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; @@ -714,12 +746,7 @@ EXPORT_SYMBOL(b1ctl_read_proc); -#ifdef MODULE -#define b1_init init_module -void cleanup_module(void); -#endif - -int b1_init(void) +static int __init b1_init(void) { char *p; char rev[10]; @@ -736,8 +763,9 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +static void b1_exit(void) { } -#endif + +module_init(b1_init); +module_exit(b1_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.2.18/drivers/isdn/avmb1/b1dma.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/avmb1/b1dma.c Sun Mar 25 11:37:31 2001 @@ -1,11 +1,40 @@ /* - * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil Exp $ + * $Id: b1dma.c,v 1.11.6.1 2001/02/13 11:43:29 kai Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.11.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.11 2000/11/19 17:02:47 kai + * compatibility cleanup - part 3 + * + * Revision 1.10 2000/11/19 17:01:53 kai + * compatibility cleanup - part 2 + * + * Revision 1.9 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.8 2000/10/10 17:44:19 kai + * changes from/for 2.2.18 + * + * Revision 1.7 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * + * Revision 1.6 2000/06/29 13:59:06 calle + * Bugfix: reinit txdma without interrupt will confuse some AMCC chips. + * + * Revision 1.5 2000/06/19 16:51:53 keil + * don't free skb in irq context + * + * Revision 1.4 2000/04/03 16:38:05 calle + * made suppress_pollack static. + * * Revision 1.3 2000/02/26 01:00:53 keil * changes from 2.3.47 * @@ -28,13 +57,14 @@ #include #include #include +#include #include #include "capilli.h" #include "avmcard.h" #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.11.6.1 $"; /* ------------------------------------------------------------- */ @@ -462,8 +492,7 @@ struct capi_ctr *ctrl = cinfo->capi_ctrl; struct sk_buff *skb; void *p = dma->recvbuf+4; - __u32 ApplId, DataB3Len, NCCI, WindowSize; - __s32 MsgLen; + __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; __u8 b1cmd = _get_byte(&p); #ifdef CONFIG_B1DMA_DEBUG @@ -552,22 +581,26 @@ case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; @@ -613,11 +646,6 @@ if ((status & TX_TC_INT) != 0) { card->csr &= ~EN_TX_TC_INT; b1dma_dispatch_tx(card); - } else if (card->csr & EN_TX_TC_INT) { - if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) { - card->csr &= ~EN_TX_TC_INT; - b1dma_dispatch_tx(card); - } } b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); } @@ -959,11 +987,6 @@ EXPORT_SYMBOL(b1dma_send_message); EXPORT_SYMBOL(b1dmactl_read_proc); -#ifdef MODULE -#define b1dma_init init_module -void cleanup_module(void); -#endif - int b1dma_init(void) { char *p; @@ -981,8 +1004,9 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +void b1dma_exit(void) { } -#endif + +module_init(b1dma_init); +module_exit(b1dma_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c --- v2.2.18/drivers/isdn/avmb1/b1isa.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/b1isa.c Sun Mar 25 11:37:31 2001 @@ -1,11 +1,27 @@ /* - * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 calle Exp $ + * $Id: b1isa.c,v 1.10.6.1 2001/02/13 11:43:29 kai Exp $ * * Module for AVM B1 ISA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1isa.c,v $ + * Revision 1.10.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.10 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.9 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.8 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.7 2000/02/02 18:36:03 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -63,13 +79,14 @@ #include #include #include +#include #include #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.7 $"; +static char *revision = "$Revision: 1.10.6.1 $"; /* ------------------------------------------------------------- */ @@ -240,31 +257,29 @@ /* ------------------------------------------------------------- */ static struct capi_driver b1isa_driver = { - "b1isa", - "0.0", - b1_load_firmware, - b1_reset_ctr, - b1isa_remove_ctr, - b1_register_appl, - b1_release_appl, - b1_send_message, - - b1isa_procinfo, - b1ctl_read_proc, - 0, /* use standard driver_read_proc */ + name: "b1isa", + revision: "0.0", + load_firmware: b1_load_firmware, + reset_ctr: b1_reset_ctr, + remove_ctr: b1isa_remove_ctr, + register_appl: b1_register_appl, + release_appl: b1_release_appl, + send_message: b1_send_message, + + procinfo: b1isa_procinfo, + ctr_read_proc: b1ctl_read_proc, + driver_read_proc: 0, /* use standard driver_read_proc */ - b1isa_add_card, + add_card: b1isa_add_card, }; -#ifdef MODULE -#define b1isa_init init_module -void cleanup_module(void); -#endif - -int b1isa_init(void) +static int __init b1isa_init(void) { struct capi_driver *driver = &b1isa_driver; char *p; + int retval = 0; + + MOD_INC_USE_COUNT; if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); @@ -279,14 +294,16 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); - return -EIO; + retval = -EIO; } - return 0; + MOD_DEC_USE_COUNT; + return retval; } -#ifdef MODULE -void cleanup_module(void) +static void b1isa_exit(void) { detach_capi_driver(&b1isa_driver); } -#endif + +module_init(b1isa_init); +module_exit(b1isa_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.2.18/drivers/isdn/avmb1/b1pci.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/b1pci.c Sun Mar 25 11:37:31 2001 @@ -1,11 +1,54 @@ /* - * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $ + * $Id: b1pci.c,v 1.29.6.1 2000/11/28 12:02:45 kai Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.29.6.1 2000/11/28 12:02:45 kai + * MODULE_DEVICE_TABLE for 2.4 + * + * Revision 1.29.2.2 2000/11/26 17:47:53 kai + * added PCI_DEV_TABLE for 2.4 + * + * Revision 1.29.2.1 2000/11/26 17:14:19 kai + * fix device ids + * also needs patches to include/linux/pci_ids.h + * + * Revision 1.29 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.28 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.27 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * + * Revision 1.26 2000/07/20 10:21:21 calle + * Bugfix: driver will not be unregistered, if not cards were detected. + * this result in an oops in kcapi.c + * + * Revision 1.25 2000/05/29 12:29:18 keil + * make pci_enable_dev compatible to 2.2 kernel versions + * + * Revision 1.24 2000/05/19 15:43:22 calle + * added calls to pci_device_start(). + * + * Revision 1.23 2000/05/06 00:52:36 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * + * Revision 1.22 2000/04/21 13:01:33 calle + * Revision in b1pciv4 driver was missing. + * + * Revision 1.21 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.20 2000/02/02 18:36:03 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -70,22 +113,14 @@ #include #include #include +#include +#include #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.20 $"; - -/* ------------------------------------------------------------- */ - -#ifndef PCI_VENDOR_ID_AVM -#define PCI_VENDOR_ID_AVM 0x1244 -#endif - -#ifndef PCI_DEVICE_ID_AVM_B1 -#define PCI_DEVICE_ID_AVM_B1 0x700 -#endif +static char *revision = "$Revision: 1.29.6.1 $"; /* ------------------------------------------------------------- */ @@ -252,20 +287,20 @@ /* ------------------------------------------------------------- */ static struct capi_driver b1pci_driver = { - "b1pci", - "0.0", - b1_load_firmware, - b1_reset_ctr, - b1pci_remove_ctr, - b1_register_appl, - b1_release_appl, - b1_send_message, - - b1pci_procinfo, - b1ctl_read_proc, - 0, /* use standard driver_read_proc */ + name: "b1pci", + revision: "0.0", + load_firmware: b1_load_firmware, + reset_ctr: b1_reset_ctr, + remove_ctr: b1pci_remove_ctr, + register_appl: b1_register_appl, + release_appl: b1_release_appl, + send_message: b1_send_message, + + procinfo: b1pci_procinfo, + ctr_read_proc: b1ctl_read_proc, + driver_read_proc: 0, /* use standard driver_read_proc */ - 0, /* no add_card function */ + add_card: 0, /* no add_card function */ }; #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 @@ -320,10 +355,13 @@ avmctrl_info *cinfo; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -331,6 +369,7 @@ if (!card->dma) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card->dma, 0, sizeof(avmcard_dmainfo)); @@ -339,6 +378,7 @@ printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -357,6 +397,7 @@ kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -371,6 +412,7 @@ kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } @@ -383,6 +425,7 @@ kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } b1dma_reset(card); @@ -399,6 +442,7 @@ kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -411,6 +455,7 @@ kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } card->cardnr = cinfo->capi_ctrl->cnr; @@ -422,8 +467,6 @@ driver->name, card->port, card->irq, card->membase, card->revision); - MOD_INC_USE_COUNT; - return 0; } @@ -431,29 +474,24 @@ static struct capi_driver b1pciv4_driver = { - "b1pciv4", - "0.0", - b1dma_load_firmware, - b1dma_reset_ctr, - b1pciv4_remove_ctr, - b1dma_register_appl, - b1dma_release_appl, - b1dma_send_message, - - b1pciv4_procinfo, - b1dmactl_read_proc, - 0, /* use standard driver_read_proc */ + name: "b1pciv4", + revision: "0.0", + load_firmware: b1dma_load_firmware, + reset_ctr: b1dma_reset_ctr, + remove_ctr: b1pciv4_remove_ctr, + register_appl: b1dma_register_appl, + release_appl: b1dma_release_appl, + send_message: b1dma_send_message, + + procinfo: b1pciv4_procinfo, + ctr_read_proc: b1dmactl_read_proc, + driver_read_proc: 0, /* use standard driver_read_proc */ - 0, /* no add_card function */ + add_card: 0, /* no add_card function */ }; #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */ -#ifdef MODULE -#define b1pci_init init_module -void cleanup_module(void); -#endif - static int ncards = 0; static int add_card(struct pci_dev *dev) @@ -469,6 +507,8 @@ param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK; param.port = dev->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK; param.irq = dev->irq; + + printk(KERN_INFO "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", driver->name, param.port, param.irq, param.membase); @@ -486,6 +526,7 @@ param.membase = 0; param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; param.irq = dev->irq; + printk(KERN_INFO "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", driver->name, param.port, param.irq); @@ -499,7 +540,7 @@ return retval; } -int b1pci_init(void) +static int __init b1pci_init(void) { struct capi_driver *driver = &b1pci_driver; #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 @@ -509,10 +550,18 @@ char *p; int retval; + MOD_INC_USE_COUNT; + if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); p = strchr(driver->revision, '$'); *p = 0; +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + p = strchr(revision, ':'); + strncpy(driverv4->revision, p + 1, sizeof(driverv4->revision)); + p = strchr(driverv4->revision, '$'); + *p = 0; +#endif } printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); @@ -522,6 +571,7 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; } @@ -534,6 +584,7 @@ detach_capi_driver(driver); printk(KERN_ERR "%s: failed to attach capi_driver\n", driverv4->name); + MOD_DEC_USE_COUNT; return -EIO; } #endif @@ -545,15 +596,18 @@ #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 detach_capi_driver(driverv4); #endif + MOD_DEC_USE_COUNT; return -EIO; } while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) { retval = add_card(dev); if (retval != 0) { -#ifdef MODULE - cleanup_module(); + detach_capi_driver(driver); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + detach_capi_driver(driverv4); #endif + MOD_DEC_USE_COUNT; return retval; } ncards++; @@ -561,22 +615,30 @@ if (ncards) { printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n", driver->name, ncards); + MOD_DEC_USE_COUNT; return 0; } printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name); + detach_capi_driver(driver); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + detach_capi_driver(driverv4); +#endif + MOD_DEC_USE_COUNT; return -ESRCH; #else printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; #endif } -#ifdef MODULE -void cleanup_module(void) +static void b1pci_exit(void) { detach_capi_driver(&b1pci_driver); #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 detach_capi_driver(&b1pciv4_driver); #endif } -#endif + +module_init(b1pci_init); +module_exit(b1pci_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c --- v2.2.18/drivers/isdn/avmb1/b1pcmcia.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/b1pcmcia.c Sun Mar 25 11:37:31 2001 @@ -1,11 +1,36 @@ /* - * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $ + * $Id: b1pcmcia.c,v 1.12.6.1 2001/02/13 11:43:29 kai Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.12.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.12 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.11 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.10 2000/05/06 00:52:36 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * + * Revision 1.9 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * + * Revision 1.8 2000/03/06 18:00:23 calle + * - Middleware extention now working with 2.3.49 (capifs). + * - Fixed typos in debug section of capi.c + * - Bugfix: Makefile corrected for b1pcmcia.c + * * Revision 1.7 2000/02/02 18:36:03 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -62,6 +87,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +96,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.7 $"; +static char *revision = "$Revision: 1.12.6.1 $"; /* ------------------------------------------------------------- */ @@ -232,20 +258,20 @@ /* ------------------------------------------------------------- */ static struct capi_driver b1pcmcia_driver = { - "b1pcmcia", - "0.0", - b1_load_firmware, - b1_reset_ctr, - b1pcmcia_remove_ctr, - b1_register_appl, - b1_release_appl, - b1_send_message, - - b1pcmcia_procinfo, - b1ctl_read_proc, - 0, /* use standard driver_read_proc */ + name: "b1pcmcia", + revision: "0.0", + load_firmware: b1_load_firmware, + reset_ctr: b1_reset_ctr, + remove_ctr: b1pcmcia_remove_ctr, + register_appl: b1_register_appl, + release_appl: b1_release_appl, + send_message: b1_send_message, + + procinfo: b1pcmcia_procinfo, + ctr_read_proc: b1ctl_read_proc, + driver_read_proc: 0, /* use standard driver_read_proc */ - 0, + add_card: 0, }; /* ------------------------------------------------------------- */ @@ -287,15 +313,13 @@ /* ------------------------------------------------------------- */ -#ifdef MODULE -#define b1pcmcia_init init_module -void cleanup_module(void); -#endif - -int b1pcmcia_init(void) +static int __init b1pcmcia_init(void) { struct capi_driver *driver = &b1pcmcia_driver; char *p; + int retval = 0; + + MOD_INC_USE_COUNT; if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); @@ -310,14 +334,16 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); - return -EIO; + retval = -EIO; } - return 0; + MOD_DEC_USE_COUNT; + return retval; } -#ifdef MODULE -void cleanup_module(void) +static void b1pcmcia_exit(void) { detach_capi_driver(&b1pcmcia_driver); } -#endif + +module_init(b1pcmcia_init); +module_exit(b1pcmcia_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.2.18/drivers/isdn/avmb1/c4.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/avmb1/c4.c Sun Mar 25 11:37:31 2001 @@ -1,11 +1,75 @@ /* - * $Id: c4.c,v 1.5 2000/03/16 15:21:03 calle Exp $ + * $Id: c4.c,v 1.20.6.2 2001/02/13 11:43:29 kai Exp $ * * Module for AVM C4 card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: c4.c,v $ + * Revision 1.20.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.20.6.1 2000/11/28 12:02:45 kai + * MODULE_DEVICE_TABLE for 2.4 + * + * Revision 1.20.2.2 2000/11/26 17:47:53 kai + * added PCI_DEV_TABLE for 2.4 + * + * Revision 1.20.2.1 2000/11/26 17:14:19 kai + * fix device ids + * also needs patches to include/linux/pci_ids.h + * + * Revision 1.20 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.19 2000/11/19 17:02:47 kai + * compatibility cleanup - part 3 + * + * Revision 1.18 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.17 2000/10/10 17:44:19 kai + * changes from/for 2.2.18 + * + * Revision 1.16 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.15 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * + * Revision 1.14 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * + * Revision 1.13 2000/07/20 10:21:21 calle + * Bugfix: driver will not be unregistered, if not cards were detected. + * this result in an oops in kcapi.c + * + * Revision 1.12 2000/06/19 16:51:53 keil + * don't free skb in irq context + * + * Revision 1.11 2000/06/19 15:11:24 keil + * avoid use of freed structs + * changes from 2.4.0-ac21 + * + * Revision 1.10 2000/05/29 12:29:18 keil + * make pci_enable_dev compatible to 2.2 kernel versions + * + * Revision 1.9 2000/05/19 15:43:22 calle + * added calls to pci_device_start(). + * + * Revision 1.8 2000/04/03 16:38:05 calle + * made suppress_pollack static. + * + * Revision 1.7 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * + * Revision 1.6 2000/03/17 12:21:08 calle + * send patchvalues now working. + * * Revision 1.5 2000/03/16 15:21:03 calle * Bugfix in c4_remove: loop 5 times instead of 4 :-( * @@ -35,7 +99,9 @@ #include #include #include +#include #include +#include #include #include #include "capicmd.h" @@ -43,35 +109,16 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.20.6.2 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG /* ------------------------------------------------------------- */ -#ifndef PCI_VENDOR_ID_DEC -#define PCI_VENDOR_ID_DEC 0x1011 -#endif - -#ifndef PCI_DEVICE_ID_DEC_21285 -#define PCI_DEVICE_ID_DEC_21285 0x1065 -#endif - -#ifndef PCI_VENDOR_ID_AVM -#define PCI_VENDOR_ID_AVM 0x1244 -#endif - -#ifndef PCI_DEVICE_ID_AVM_C4 -#define PCI_DEVICE_ID_AVM_C4 0x0800 -#endif - -/* ------------------------------------------------------------- */ - -static int suppress_pollack = 0; +static int suppress_pollack; MODULE_AUTHOR("Carsten Paeth "); - MODULE_PARM(suppress_pollack, "0-1i"); /* ------------------------------------------------------------- */ @@ -535,8 +582,7 @@ avmctrl_info *cinfo; struct sk_buff *skb; void *p = dma->recvbuf; - __u32 ApplId, DataB3Len, NCCI, WindowSize; - __s32 MsgLen; + __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; __u8 b1cmd = _get_byte(&p); __u32 cidx; @@ -655,22 +701,26 @@ case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; @@ -774,45 +824,78 @@ c4_dispatch_tx(card); } -static int c4_send_config(avmcard *card, capiloaddatapart * config) +static int queue_sendconfigword(avmcard *card, __u32 val) { struct sk_buff *skb; - __u8 val[sizeof(__u32)]; void *p; - unsigned char *dp; - int left, retval; - - skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC); + + skb = alloc_skb(3+4, GFP_ATOMIC); if (!skb) { - printk(KERN_CRIT "%s: no memory, can't send config.\n", + printk(KERN_CRIT "%s: no memory, send config\n", card->name); - return -ENOMEM; + return -ENOMEM; } p = skb->data; _put_byte(&p, 0); _put_byte(&p, 0); _put_byte(&p, SEND_CONFIG); - _put_word(&p, 1); + _put_word(&p, val); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + return 0; +} + +static int queue_sendconfig(avmcard *card, char cval[4]) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(3+4, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, send config\n", + card->name); + return -ENOMEM; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); _put_byte(&p, SEND_CONFIG); - _put_word(&p, config->len); /* 12 */ + _put_byte(&p, cval[0]); + _put_byte(&p, cval[1]); + _put_byte(&p, cval[2]); + _put_byte(&p, cval[3]); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + return 0; +} + +static int c4_send_config(avmcard *card, capiloaddatapart * config) +{ + __u8 val[4]; + unsigned char *dp; + int left, retval; + + if ((retval = queue_sendconfigword(card, 1)) != 0) + return retval; + if ((retval = queue_sendconfigword(card, config->len)) != 0) + return retval; dp = config->data; left = config->len; while (left >= sizeof(__u32)) { if (config->user) { retval = copy_from_user(val, dp, sizeof(val)); - if (retval) { - dev_kfree_skb(skb); + if (retval) return -EFAULT; - } } else { memcpy(val, dp, sizeof(val)); } - _put_byte(&p, SEND_CONFIG); - _put_byte(&p, val[0]); - _put_byte(&p, val[1]); - _put_byte(&p, val[2]); - _put_byte(&p, val[3]); + if ((retval = queue_sendconfig(card, val)) != 0) + return retval; left -= sizeof(val); dp += sizeof(val); } @@ -820,25 +903,15 @@ memset(val, 0, sizeof(val)); if (config->user) { retval = copy_from_user(&val, dp, left); - if (retval) { - dev_kfree_skb(skb); + if (retval) return -EFAULT; - } } else { memcpy(&val, dp, left); } - _put_byte(&p, SEND_CONFIG); - _put_byte(&p, val[0]); - _put_byte(&p, val[1]); - _put_byte(&p, val[2]); - _put_byte(&p, val[3]); + if ((retval = queue_sendconfig(card, val)) != 0) + return retval; } - skb_put(skb, (__u8 *)p - (__u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - c4_dispatch_tx(card); - return 0; } @@ -875,8 +948,15 @@ c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); restore_flags(flags); - if (data->configuration.len > 0 && data->configuration.data) - c4_send_config(card, &data->configuration); + if (data->configuration.len > 0 && data->configuration.data) { + retval = c4_send_config(card, &data->configuration); + if (retval) { + printk(KERN_ERR "%s: failed to set config!!\n", + card->name); + c4_reset(card); + return retval; + } + } c4_send_init(card); @@ -910,8 +990,10 @@ for (i=0; i < 4; i++) { cinfo = &card->ctrlinfo[i]; - if (cinfo->capi_ctrl) + if (cinfo->capi_ctrl) { di->detach_ctr(cinfo->capi_ctrl); + cinfo->capi_ctrl = NULL; + } } free_irq(card->irq, card); @@ -1124,7 +1206,6 @@ cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - kfree(card->ctrlinfo); kfree(card->dma); kfree(card); MOD_DEC_USE_COUNT; @@ -1231,57 +1312,33 @@ /* ------------------------------------------------------------- */ static struct capi_driver c4_driver = { - "c4", - "0.0", - c4_load_firmware, - c4_reset_ctr, - c4_remove_ctr, - c4_register_appl, - c4_release_appl, - c4_send_message, - - c4_procinfo, - c4_read_proc, - 0, /* use standard driver_read_proc */ + name: "c4", + revision: "0.0", + load_firmware: c4_load_firmware, + reset_ctr: c4_reset_ctr, + remove_ctr: c4_remove_ctr, + register_appl: c4_register_appl, + release_appl: c4_release_appl, + send_message: c4_send_message, + + procinfo: c4_procinfo, + ctr_read_proc: c4_read_proc, + driver_read_proc: 0, /* use standard driver_read_proc */ - 0, /* no add_card function */ + add_card: 0, /* no add_card function */ }; -#ifdef MODULE -#define c4_init init_module -void cleanup_module(void); -#endif - -#ifndef PCI_ANY_ID -#define PCI_ANY_ID (~0) -#endif - -static struct pci_dev * -pci_find_subsys(unsigned int vendor, unsigned int device, - unsigned int ss_vendor, unsigned int ss_device, - struct pci_dev *from) -{ - unsigned short subsystem_vendor, subsystem_device; - - while ((from = pci_find_device(vendor, device, from))) { - pci_read_config_word(from, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); - pci_read_config_word(from, PCI_SUBSYSTEM_ID, &subsystem_device); - if ((ss_vendor == PCI_ANY_ID || subsystem_vendor == ss_vendor) && - (ss_device == PCI_ANY_ID || subsystem_device == ss_device)) - return from; - } - return NULL; -} - static int ncards = 0; -int c4_init(void) +static int __init c4_init(void) { struct capi_driver *driver = &c4_driver; struct pci_dev *dev = NULL; char *p; int retval; + MOD_INC_USE_COUNT; + if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); p = strchr(driver->revision, '$'); @@ -1295,6 +1352,7 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; } @@ -1302,6 +1360,7 @@ if (!pci_present()) { printk(KERN_ERR "%s: no PCI bus present\n", driver->name); detach_capi_driver(driver); + MOD_DEC_USE_COUNT; return -EIO; } @@ -1314,6 +1373,7 @@ param.irq = dev->irq; param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK; + printk(KERN_INFO "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n", driver->name, param.port, param.irq, param.membase); @@ -1322,9 +1382,8 @@ printk(KERN_ERR "%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n", driver->name, param.port, param.irq, param.membase); -#ifdef MODULE - cleanup_module(); -#endif + detach_capi_driver(driver); + MOD_DEC_USE_COUNT; return retval; } ncards++; @@ -1332,19 +1391,24 @@ if (ncards) { printk(KERN_INFO "%s: %d C4 card(s) detected\n", driver->name, ncards); + MOD_DEC_USE_COUNT; return 0; } printk(KERN_ERR "%s: NO C4 card detected\n", driver->name); + detach_capi_driver(driver); + MOD_DEC_USE_COUNT; return -ESRCH; #else printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; #endif } -#ifdef MODULE -void cleanup_module(void) +static void c4_exit(void) { detach_capi_driver(&c4_driver); } -#endif + +module_init(c4_init); +module_exit(c4_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.2.18/drivers/isdn/avmb1/capi.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/capi.c Sun Mar 25 11:37:31 2001 @@ -1,11 +1,120 @@ /* - * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $ + * $Id: capi.c,v 1.44.6.5 2001/02/13 11:43:29 kai Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.44.6.5 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.44.6.4 2001/02/10 14:41:20 kai + * Changes from kernel tree + * + * Revision 1.44.6.3 2000/12/17 22:45:08 kai + * That's hopefully it for test13-4 + * + * Revision 1.44.6.2 2000/12/14 23:04:12 kai + * Makefile changes and the like for 2.4.0-test13-pre1 + * No compatiblity code for older kernels yet, but note the branch + * + * Revision 1.45 2000/12/02 19:47:29 kai + * Change the Makefiles to new style. + * There may be problems there that I missed, so this shouldn't go into + * an offical kernel any time soon. + * However, if I didn't commit it, we wouldn't find the bugs... + * + * Revision 1.44 2000/11/25 17:00:59 kai + * compatibility cleanup - final part for the time being + * + * Revision 1.43 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.42 2000/11/19 17:03:55 kai + * compatibility cleanup - part 5 + * + * Revision 1.41 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.40 2000/10/24 15:15:04 calle + * Workaround: pppd calls restoretty before reseting the ldisc and + * ldisc "ppp_sync" didn't support this. So we call n_tty_ioctl + * in the driver ioctl function. (remember: driver ioctl function is + * only called if ldisc ioctl function did not handle the call) + * + * Revision 1.39 2000/07/24 13:42:50 calle + * - lock_kernel/unlock_kernel for _release functions. (from 2.4) + * + * Revision 1.38 2000/07/24 08:49:09 calle + * - Bugfix: capiminor_del_all_ack completely wrong :-( + * + * Revision 1.37 2000/07/20 10:22:27 calle + * - Made procfs function cleaner and removed variable "begin". + * + * Revision 1.36 2000/06/29 13:59:35 calle + * - call to devfs_register was wrong + * + * Revision 1.35 2000/06/19 15:11:24 keil + * avoid use of freed structs + * changes from 2.4.0-ac21 + * + * Revision 1.34 2000/06/18 16:09:54 keil + * more changes for 2.4 + * + * Revision 1.33 2000/05/18 16:35:43 calle + * Uaaahh. Bad memory leak fixed. + * + * Revision 1.32 2000/04/21 12:38:42 calle + * Bugfix: error in proc_ functions, begin-off => off-begin + * + * Revision 1.31 2000/04/03 13:29:24 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * + * Revision 1.30 2000/03/19 12:31:36 calle + * PPP over CAPI raw driver disabled for now, ppp_generic has been changed. + * + * Revision 1.29 2000/03/13 17:48:13 calle + * removed unused variable. + * + * Revision 1.28 2000/03/08 17:06:33 calle + * - changes for devfs and 2.3.49 + * - capifs now configurable (no need with devfs) + * - New Middleware ioctl CAPI_NCCI_GETUNIT + * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) + * + * Revision 1.27 2000/03/06 18:00:23 calle + * - Middleware extention now working with 2.3.49 (capifs). + * - Fixed typos in debug section of capi.c + * - Bugfix: Makefile corrected for b1pcmcia.c + * + * Revision 1.26 2000/03/03 16:48:38 calle + * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) + * It is now possible to create a connection with a CAPI2.0 applikation + * and than to handle the data connection from /dev/capi/ (capifs) and also + * using async or sync PPP on this connection. + * The two major device number 190 and 191 are not confirmed yet, + * but I want to save the code in cvs, before I go on. + * + * Revision 1.25 2000/03/03 16:37:11 kai + * incorporated some cosmetic changes from the official kernel tree back + * into CVS + * + * Revision 1.24 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.23 2000/02/26 01:00:53 keil * changes from 2.3.47 * @@ -114,96 +223,724 @@ * */ +#include #include #include #include #include #include -#include +#include #include #include #include #include +#include #include #include +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +#include +#ifdef CONFIG_PPP +#include +#include +#include +#undef CAPI_PPP_ON_RAW_DEVICE +#endif /* CONFIG_PPP */ +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include #include #include #include #include - +#include #include "capiutil.h" #include "capicmd.h" -#include "capidev.h" +#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) +#include "capifs.h" +#endif + +static char *revision = "$Revision: 1.44.6.5 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); +#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */ +#undef _DEBUG_TTYFUNCS /* call to tty_driver */ +#undef _DEBUG_DATAFLOW /* data flow */ + /* -------- driver information -------------------------------------- */ int capi_major = 68; /* allocated */ +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +int capi_rawmajor = 190; +int capi_ttymajor = 191; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ MODULE_PARM(capi_major, "i"); +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +MODULE_PARM(capi_rawmajor, "i"); +MODULE_PARM(capi_ttymajor, "i"); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +/* -------- defines ------------------------------------------------- */ + +#define CAPINC_MAX_RECVQUEUE 10 +#define CAPINC_MAX_SENDQUEUE 10 +#define CAPI_MAX_BLKSIZE 2048 + +/* -------- data structures ----------------------------------------- */ + +struct capidev; +struct capincci; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +struct capiminor; + +struct capiminor { + struct capiminor *next; + struct capincci *nccip; + unsigned int minor; + + __u16 applid; + __u32 ncci; + __u16 datahandle; + __u16 msgid; + + struct file *file; + struct tty_struct *tty; + int ttyinstop; + int ttyoutstop; + struct sk_buff *ttyskb; + atomic_t ttyopencount; + + struct sk_buff_head inqueue; + int inbytes; + struct sk_buff_head outqueue; + int outbytes; + + /* for raw device */ + struct sk_buff_head recvqueue; + wait_queue_head_t recvwait; + wait_queue_head_t sendwait; + + /* transmit path */ + struct datahandle_queue { + struct datahandle_queue *next; + __u16 datahandle; + } *ackqueue; + int nack; + +}; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +struct capincci { + struct capincci *next; + __u32 ncci; + struct capidev *cdev; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *minorp; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +}; + +struct capidev { + struct capidev *next; + struct file *file; + __u16 applid; + __u16 errcode; + unsigned int minor; + unsigned userflags; + + struct sk_buff_head recvqueue; + wait_queue_head_t recvwait; + + /* Statistic */ + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; + + struct capincci *nccis; +}; /* -------- global variables ---------------------------------------- */ -static struct capidev capidevs[CAPI_MAXMINOR + 1]; -struct capi_interface *capifuncs; +static struct capi_interface *capifuncs = 0; +static struct capidev *capidev_openlist = 0; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +static struct capiminor *minors = 0; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -/* -------- function called by lower level -------------------------- */ -static void capi_signal(__u16 applid, __u32 minor) +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +/* -------- datahandles --------------------------------------------- */ + +int capincci_add_ack(struct capiminor *mp, __u16 datahandle) +{ + struct datahandle_queue *n, **pp; + + n = (struct datahandle_queue *) + kmalloc(sizeof(struct datahandle_queue), GFP_ATOMIC); + if (!n) { + printk(KERN_ERR "capi: alloc datahandle failed\n"); + return -1; + } + n->next = 0; + n->datahandle = datahandle; + for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ; + *pp = n; + mp->nack++; + return 0; +} + +int capiminor_del_ack(struct capiminor *mp, __u16 datahandle) +{ + struct datahandle_queue **pp, *p; + + for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) { + if ((*pp)->datahandle == datahandle) { + p = *pp; + *pp = (*pp)->next; + kfree(p); + mp->nack--; + return 0; + } + } + return -1; +} + +void capiminor_del_all_ack(struct capiminor *mp) +{ + struct datahandle_queue **pp, *p; + + pp = &mp->ackqueue; + while (*pp) { + p = *pp; + *pp = (*pp)->next; + kfree(p); + mp->nack--; + } +} + + +/* -------- struct capiminor ---------------------------------------- */ + +struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci) +{ + struct capiminor *mp, **pp; + unsigned int minor = 0; + + MOD_INC_USE_COUNT; + mp = (struct capiminor *)kmalloc(sizeof(struct capiminor), GFP_ATOMIC); + if (!mp) { + MOD_DEC_USE_COUNT; + printk(KERN_ERR "capi: can't alloc capiminor\n"); + return 0; + } +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(&__this_module)); +#endif + memset(mp, 0, sizeof(struct capiminor)); + mp->applid = applid; + mp->ncci = ncci; + mp->msgid = 0; + atomic_set(&mp->ttyopencount,0); + + skb_queue_head_init(&mp->inqueue); + skb_queue_head_init(&mp->outqueue); + + skb_queue_head_init(&mp->recvqueue); + init_waitqueue_head(&mp->recvwait); + init_waitqueue_head(&mp->sendwait); + + for (pp = &minors; *pp; pp = &(*pp)->next) { + if ((*pp)->minor < minor) + continue; + if ((*pp)->minor > minor) + break; + minor++; + } + mp->minor = minor; + mp->next = *pp; + *pp = mp; + return mp; +} + +void capiminor_free(struct capiminor *mp) +{ + struct capiminor **pp; + struct sk_buff *skb; + + pp = &minors; + while (*pp) { + if (*pp == mp) { + *pp = (*pp)->next; + if (mp->ttyskb) kfree_skb(mp->ttyskb); + mp->ttyskb = 0; + while ((skb = skb_dequeue(&mp->recvqueue)) != 0) + kfree_skb(skb); + while ((skb = skb_dequeue(&mp->inqueue)) != 0) + kfree_skb(skb); + while ((skb = skb_dequeue(&mp->outqueue)) != 0) + kfree_skb(skb); + capiminor_del_all_ack(mp); + kfree(mp); + MOD_DEC_USE_COUNT; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(&__this_module)); +#endif + return; + } else { + pp = &(*pp)->next; + } + } +} + +struct capiminor *capiminor_find(unsigned int minor) +{ + struct capiminor *p; + for (p = minors; p && p->minor != minor; p = p->next) + ; + return p; +} +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +/* -------- struct capincci ----------------------------------------- */ + +static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci) +{ + struct capincci *np, **pp; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp = 0; + kdev_t kdev; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + np = (struct capincci *)kmalloc(sizeof(struct capincci), GFP_ATOMIC); + if (!np) + return 0; + memset(np, 0, sizeof(struct capincci)); + np->ncci = ncci; + np->cdev = cdev; + for (pp=&cdev->nccis; *pp; pp = &(*pp)->next) + ; + *pp = np; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + mp = 0; + if (cdev->userflags & CAPIFLAG_HIGHJACKING) + mp = np->minorp = capiminor_alloc(cdev->applid, ncci); + if (mp) { + mp->nccip = np; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "set mp->nccip\n"); +#endif +#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) + kdev = MKDEV(capi_rawmajor, mp->minor); + capifs_new_ncci('r', mp->minor, kdev); + kdev = MKDEV(capi_ttymajor, mp->minor); + capifs_new_ncci(0, mp->minor, kdev); +#endif + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + return np; +} + +static void capincci_free(struct capidev *cdev, __u32 ncci) +{ + struct capincci *np, **pp; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + pp=&cdev->nccis; + while (*pp) { + np = *pp; + if (ncci == 0xffffffff || np->ncci == ncci) { + *pp = (*pp)->next; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if ((mp = np->minorp) != 0) { +#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) + capifs_free_ncci('r', mp->minor); + capifs_free_ncci(0, mp->minor); +#endif + if (mp->tty) { + mp->nccip = 0; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "reset mp->nccip\n"); +#endif + tty_hangup(mp->tty); + } else if (mp->file) { + mp->nccip = 0; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "reset mp->nccip\n"); +#endif + wake_up_interruptible(&mp->recvwait); + wake_up_interruptible(&mp->sendwait); + } else { + capiminor_free(mp); + } + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + kfree(np); + if (*pp == 0) return; + } else { + pp = &(*pp)->next; + } + } +} + +struct capincci *capincci_find(struct capidev *cdev, __u32 ncci) +{ + struct capincci *p; + + for (p=cdev->nccis; p ; p = p->next) { + if (p->ncci == ncci) + break; + } + return p; +} + +/* -------- struct capidev ------------------------------------------ */ + +static struct capidev *capidev_alloc(struct file *file) { struct capidev *cdev; + struct capidev **pp; + + cdev = (struct capidev *)kmalloc(sizeof(struct capidev), GFP_KERNEL); + if (!cdev) + return 0; + memset(cdev, 0, sizeof(struct capidev)); + cdev->file = file; + cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev); + + skb_queue_head_init(&cdev->recvqueue); + init_waitqueue_head(&cdev->recvwait); + pp=&capidev_openlist; + while (*pp) pp = &(*pp)->next; + *pp = cdev; + return cdev; +} + +static void capidev_free(struct capidev *cdev) +{ + struct capidev **pp; + struct sk_buff *skb; + + if (cdev->applid) + (*capifuncs->capi_release) (cdev->applid); + cdev->applid = 0; + + while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) { + kfree_skb(skb); + } + + pp=&capidev_openlist; + while (*pp && *pp != cdev) pp = &(*pp)->next; + if (*pp) + *pp = cdev->next; + + kfree(cdev); +} + +static struct capidev *capidev_find(__u16 applid) +{ + struct capidev *p; + for (p=capidev_openlist; p; p = p->next) { + if (p->applid == applid) + break; + } + return p; +} + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +/* -------- handle data queue --------------------------------------- */ + +struct sk_buff * +gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) +{ + struct sk_buff *nskb; + nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC); + if (nskb) { + __u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2); + unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN); + capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN); + capimsg_setu16(s, 2, mp->applid); + capimsg_setu8 (s, 4, CAPI_DATA_B3); + capimsg_setu8 (s, 5, CAPI_RESP); + capimsg_setu16(s, 6, mp->msgid++); + capimsg_setu32(s, 8, mp->ncci); + capimsg_setu16(s, 12, datahandle); + } + return nskb; +} + +int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) +{ + struct sk_buff *nskb; + unsigned int datalen; + __u16 errcode, datahandle; + + datalen = skb->len - CAPIMSG_LEN(skb->data); + if (mp->tty) { + if (mp->tty->ldisc.receive_buf == 0) { + printk(KERN_ERR "capi: ldisc has no receive_buf function\n"); + return -1; + } + if (mp->ttyinstop) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: recv tty throttled\n"); +#endif + return -1; + } + if (mp->tty->ldisc.receive_room && + mp->tty->ldisc.receive_room(mp->tty) < datalen) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: no room in tty\n"); +#endif + return -1; + } + if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); + return -1; + } + datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); + errcode = (*capifuncs->capi_put_message)(mp->applid, nskb); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", + errcode); + kfree_skb(nskb); + return -1; + } + (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", + datahandle, skb->len); +#endif + mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len); + kfree_skb(skb); + return 0; + + } else if (mp->file) { + if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: no room in raw queue\n"); +#endif + return -1; + } + if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); + return -1; + } + datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); + errcode = (*capifuncs->capi_put_message)(mp->applid, nskb); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", + errcode); + kfree_skb(nskb); + return -1; + } + (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => raw\n", + datahandle, skb->len); +#endif + skb_queue_tail(&mp->recvqueue, skb); + wake_up_interruptible(&mp->recvwait); + return 0; + } +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: currently no receiver\n"); +#endif + return -1; +} + +void handle_minor_recv(struct capiminor *mp) +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(&mp->inqueue)) != 0) { + unsigned int len = skb->len; + mp->inbytes -= len; + if (handle_recv_skb(mp, skb) < 0) { + skb_queue_head(&mp->inqueue, skb); + mp->inbytes += len; + return; + } + } +} + +int handle_minor_send(struct capiminor *mp) +{ + struct sk_buff *skb; + __u16 len; + int count = 0; + __u16 errcode; + __u16 datahandle; + + if (mp->tty && mp->ttyoutstop) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: send: tty stopped\n"); +#endif + return 0; + } + + while ((skb = skb_dequeue(&mp->outqueue)) != 0) { + datahandle = mp->datahandle; + len = (__u16)skb->len; + skb_push(skb, CAPI_DATA_B3_REQ_LEN); + memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN); + capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN); + capimsg_setu16(skb->data, 2, mp->applid); + capimsg_setu8 (skb->data, 4, CAPI_DATA_B3); + capimsg_setu8 (skb->data, 5, CAPI_REQ); + capimsg_setu16(skb->data, 6, mp->msgid++); + capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */ + capimsg_setu32(skb->data, 12, (__u32) skb->data); /* Data32 */ + capimsg_setu16(skb->data, 16, len); /* Data length */ + capimsg_setu16(skb->data, 18, datahandle); + capimsg_setu16(skb->data, 20, 0); /* Flags */ + + if (capincci_add_ack(mp, datahandle) < 0) { + skb_pull(skb, CAPI_DATA_B3_REQ_LEN); + skb_queue_head(&mp->outqueue, skb); + return count; + } + errcode = (*capifuncs->capi_put_message) (mp->applid, skb); + if (errcode == CAPI_NOERROR) { + mp->datahandle++; + count++; + mp->outbytes -= len; +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n", + datahandle, len); +#endif + continue; + } + capiminor_del_ack(mp, datahandle); + + if (errcode == CAPI_SENDQUEUEFULL) { + skb_pull(skb, CAPI_DATA_B3_REQ_LEN); + skb_queue_head(&mp->outqueue, skb); + break; + } + + /* ups, drop packet */ + printk(KERN_ERR "capi: put_message = %x\n", errcode); + mp->outbytes -= len; + kfree_skb(skb); + } + if (count) + wake_up_interruptible(&mp->sendwait); + return count; +} + +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +/* -------- function called by lower level -------------------------- */ + +static void capi_signal(__u16 applid, void *param) +{ + struct capidev *cdev = (struct capidev *)param; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp; + __u16 datahandle; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + struct capincci *np; struct sk_buff *skb = 0; + __u32 ncci; - if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) { - printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor); + (void) (*capifuncs->capi_get_message) (applid, &skb); + if (!skb) { + printk(KERN_ERR "BUG: capi_signal: no skb\n"); return; } - cdev = &capidevs[minor]; - (void) (*capifuncs->capi_get_message) (applid, &skb); - if (skb) { - skb_queue_tail(&cdev->recv_queue, skb); - wake_up_interruptible(&cdev->recv_wait); + + if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + return; + } + ncci = CAPIMSG_CONTROL(skb->data); + for (np = cdev->nccis; np && np->ncci != ncci; np = np->next) + ; + if (!np) { + printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + return; + } +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + mp = np->minorp; + if (!mp) { + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + return; + } + + + if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", + datahandle, skb->len-CAPIMSG_LEN(skb->data)); +#endif + skb_queue_tail(&mp->inqueue, skb); + mp->inbytes += skb->len; + handle_minor_recv(mp); + + } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) { + + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n", + datahandle, + CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2)); +#endif + kfree_skb(skb); + (void)capiminor_del_ack(mp, datahandle); + if (mp->tty) { + if (mp->tty->ldisc.write_wakeup) + mp->tty->ldisc.write_wakeup(mp->tty); + } else { + wake_up_interruptible(&mp->sendwait); + } + (void)handle_minor_send(mp); + } else { - printk(KERN_ERR "BUG: capi_signal: no skb\n"); + /* ups, let capi application handle it :-) */ + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ } -/* -------- file_operations ----------------------------------------- */ +/* -------- file_operations for capidev ----------------------------- */ -static long long capi_llseek(struct file *file, - long long offset, int origin) +static loff_t +capi_llseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } -static ssize_t capi_read(struct file *file, char *buf, - size_t count, loff_t *ppos) +static ssize_t +capi_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; + struct capidev *cdev = (struct capidev *)file->private_data; struct sk_buff *skb; int retval; size_t copied; - if (ppos != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; - if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + if (!cdev->applid) return -ENODEV; - cdev = &capidevs[minor]; - - if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) { + if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; for (;;) { - interruptible_sleep_on(&cdev->recv_wait); - if ((skb = skb_dequeue(&cdev->recv_queue)) != 0) + interruptible_sleep_on(&cdev->recvwait); + if ((skb = skb_dequeue(&cdev->recvqueue)) != 0) break; if (signal_pending(current)) break; @@ -212,63 +949,58 @@ return -ERESTARTNOHAND; } if (skb->len > count) { - skb_queue_head(&cdev->recv_queue, skb); + skb_queue_head(&cdev->recvqueue, skb); return -EMSGSIZE; } retval = copy_to_user(buf, skb->data, skb->len); if (retval) { - skb_queue_head(&cdev->recv_queue, skb); + skb_queue_head(&cdev->recvqueue, skb); return retval; } copied = skb->len; - if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 - && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) { cdev->nrecvdatapkt++; - else cdev->nrecvctlpkt++; + } else { + cdev->nrecvctlpkt++; + } + kfree_skb(skb); return copied; } -static ssize_t capi_write(struct file *file, const char *buf, - size_t count, loff_t *ppos) +static ssize_t +capi_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; + struct capidev *cdev = (struct capidev *)file->private_data; struct sk_buff *skb; int retval; - __u8 cmd; - __u8 subcmd; __u16 mlen; - if (ppos != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; - if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + if (!cdev->applid) return -ENODEV; - cdev = &capidevs[minor]; - skb = alloc_skb(count, GFP_USER); if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb); return retval; } - cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); mlen = CAPIMSG_LEN(skb->data); - if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { - __u16 dlen = CAPIMSG_DATALEN(skb->data); - if (mlen + dlen != count) { + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { + if (mlen + CAPIMSG_DATALEN(skb->data) != count) { + kfree_skb(skb); + return -EINVAL; + } + } else { + if (mlen != count) { kfree_skb(skb); return -EINVAL; } - } else if (mlen != count) { - kfree_skb(skb); - return -EINVAL; } CAPIMSG_SETAPPID(skb->data, cdev->applid); @@ -278,63 +1010,56 @@ kfree_skb(skb); return -EIO; } - if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { cdev->nsentdatapkt++; - else cdev->nsentctlpkt++; + } else { + cdev->nsentctlpkt++; + } return count; } static unsigned int capi_poll(struct file *file, poll_table * wait) { + struct capidev *cdev = (struct capidev *)file->private_data; unsigned int mask = 0; - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); - struct capidev *cdev; - if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + if (!cdev->applid) return POLLERR; - cdev = &capidevs[minor]; - poll_wait(file, &(cdev->recv_wait), wait); + poll_wait(file, &(cdev->recvwait), wait); mask = POLLOUT | POLLWRNORM; - if (!skb_queue_empty(&cdev->recv_queue)) + if (!skb_queue_empty(&cdev->recvqueue)) mask |= POLLIN | POLLRDNORM; return mask; } -static int capi_ioctl(struct inode *inode, struct file *file, +static int +capi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; + struct capidev *cdev = (struct capidev *)file->private_data; capi_ioctl_struct data; - int retval; - - - if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) - return -ENODEV; - - cdev = &capidevs[minor]; + int retval = -EINVAL; switch (cmd) { case CAPI_REGISTER: { - if (!minor) - return -EINVAL; retval = copy_from_user((void *) &data.rparams, (void *) arg, sizeof(struct capi_register_params)); if (retval) return -EFAULT; - if (cdev->is_registered) + if (cdev->applid) return -EEXIST; cdev->errcode = (*capifuncs->capi_register) (&data.rparams, &cdev->applid); - if (cdev->errcode) + if (cdev->errcode) { + cdev->applid = 0; return -EIO; - (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor); - cdev->is_registered = 1; + } + (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, cdev); } - return 0; + return (int)cdev->applid; case CAPI_GET_VERSION: { @@ -440,8 +1165,6 @@ case CAPI_MANUFACTURER_CMD: { struct capi_manufacturer_cmd mcmd; - if (minor) - return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = copy_from_user((void *) &mcmd, (void *) arg, @@ -451,121 +1174,785 @@ return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data); } return 0; + + case CAPI_SET_FLAGS: + case CAPI_CLR_FLAGS: + { + unsigned userflags; + retval = copy_from_user((void *) &userflags, + (void *) arg, + sizeof(userflags)); + if (retval) + return -EFAULT; + if (cmd == CAPI_SET_FLAGS) + cdev->userflags |= userflags; + else + cdev->userflags &= ~userflags; + } + return 0; + + case CAPI_GET_FLAGS: + { + retval = copy_to_user((void *) arg, + (void *) &cdev->userflags, + sizeof(cdev->userflags)); + if (retval) + return -EFAULT; + } + return 0; + + case CAPI_NCCI_OPENCOUNT: + { + struct capincci *nccip; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + unsigned ncci; + int count = 0; + retval = copy_from_user((void *) &ncci, + (void *) arg, + sizeof(ncci)); + if (retval) + return -EFAULT; + nccip = capincci_find(cdev, (__u32) ncci); + if (!nccip) + return 0; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if ((mp = nccip->minorp) != 0) { + count += atomic_read(&mp->ttyopencount); + if (mp->file) + count++; + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + return count; + } + return 0; + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + case CAPI_NCCI_GETUNIT: + { + struct capincci *nccip; + struct capiminor *mp; + unsigned ncci; + retval = copy_from_user((void *) &ncci, + (void *) arg, + sizeof(ncci)); + if (retval) + return -EFAULT; + nccip = capincci_find(cdev, (__u32) ncci); + if (!nccip || (mp = nccip->minorp) == 0) + return -ESRCH; + return mp->minor; + } + return 0; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ } return -EINVAL; } -static int capi_open(struct inode *inode, struct file *file) +static int +capi_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); - - if (minor >= CAPI_MAXMINOR) - return -ENXIO; - - if (minor) { - if (capidevs[minor].is_open) - return -EEXIST; - - capidevs[minor].is_open = 1; - skb_queue_head_init(&capidevs[minor].recv_queue); - MOD_INC_USE_COUNT; - capidevs[minor].nopen++; + if (file->private_data) + return -EEXIST; - } else { - capidevs[minor].is_open++; - MOD_INC_USE_COUNT; - } + if ((file->private_data = capidev_alloc(file)) == 0) + return -ENOMEM; + MOD_INC_USE_COUNT; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(&__this_module)); +#endif return 0; } static int capi_release(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; - struct sk_buff *skb; - - if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) { - printk(KERN_ERR "capi20: release minor %d ???\n", minor); - return 0; - } - cdev = &capidevs[minor]; - - if (minor) { - - if (cdev->is_registered) - (*capifuncs->capi_release) (cdev->applid); - - cdev->is_registered = 0; - cdev->applid = 0; - - while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) { - kfree_skb(skb); - } - cdev->is_open = 0; - } else { - cdev->is_open--; - } + struct capidev *cdev = (struct capidev *)file->private_data; + lock_kernel(); + capincci_free(cdev, 0xffffffff); + capidev_free(cdev); + file->private_data = NULL; + MOD_DEC_USE_COUNT; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(&__this_module)); +#endif + unlock_kernel(); return 0; } static struct file_operations capi_fops = { - capi_llseek, - capi_read, - capi_write, - NULL, /* capi_readdir */ - capi_poll, - capi_ioctl, - NULL, /* capi_mmap */ - capi_open, - NULL, /* capi_flush */ - capi_release, - NULL, /* capi_fsync */ - NULL, /* capi_fasync */ + llseek: capi_llseek, + read: capi_read, + write: capi_write, + poll: capi_poll, + ioctl: capi_ioctl, + open: capi_open, + release: capi_release, }; -/* -------- /proc functions ----------------------------------- */ +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +/* -------- file_operations for capincci ---------------------------- */ -/* - * /proc/capi/capi20: - * minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt - */ -static int proc_capidev_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int +capinc_raw_open(struct inode *inode, struct file *file) { - struct capidev *cp; - int i; - int len = 0; - off_t begin = 0; + struct capiminor *mp; - for (i=0; i < CAPI_MAXMINOR; i++) { - cp = &capidevs[i+1]; - if (cp->nopen == 0) continue; - len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n", - i+1, - cp->nopen, - cp->nrecvctlpkt, - cp->nrecvdatapkt, - cp->nsentctlpkt, - cp->nsentdatapkt); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; - len = 0; + if (file->private_data) + return -EEXIST; + if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) + return -ENXIO; + if (mp->nccip == 0) + return -ENXIO; + if (mp->file) + return -EBUSY; + +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(&__this_module)); +#endif + + mp->datahandle = 0; + mp->file = file; + file->private_data = (void *)mp; + handle_minor_recv(mp); + return 0; +} + +static loff_t +capinc_raw_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t +capinc_raw_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + struct sk_buff *skb; + int retval; + size_t copied = 0; + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!mp || !mp->nccip) + return -EINVAL; + + if ((skb = skb_dequeue(&mp->recvqueue)) == 0) { + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + for (;;) { + interruptible_sleep_on(&mp->recvwait); + if (mp->nccip == 0) + return 0; + if ((skb = skb_dequeue(&mp->recvqueue)) != 0) + break; + if (signal_pending(current)) + break; + } + if (skb == 0) + return -ERESTARTNOHAND; + } + do { + if (count < skb->len) { + retval = copy_to_user(buf, skb->data, count); + if (retval) { + skb_queue_head(&mp->recvqueue, skb); + return retval; + } + skb_pull(skb, count); + skb_queue_head(&mp->recvqueue, skb); + copied += count; + return copied; + } else { + retval = copy_to_user(buf, skb->data, skb->len); + if (retval) { + skb_queue_head(&mp->recvqueue, skb); + return copied; + } + copied += skb->len; + count -= skb->len; + buf += skb->len; + kfree_skb(skb); + } + } while ((skb = skb_dequeue(&mp->recvqueue)) != 0); + + return copied; +} + +static ssize_t +capinc_raw_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + struct sk_buff *skb; + int retval; + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!mp || !mp->nccip) + return -EINVAL; + + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER); + + skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); + if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { + kfree_skb(skb); + return retval; + } + + while (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&mp->sendwait); + if (mp->nccip == 0) { + kfree_skb(skb); + return -EIO; + } + if (signal_pending(current)) + return -ERESTARTNOHAND; + } + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + return count; +} + +static unsigned int +capinc_raw_poll(struct file *file, poll_table * wait) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + unsigned int mask = 0; + + if (!mp || !mp->nccip) + return POLLERR|POLLHUP; + + poll_wait(file, &(mp->recvwait), wait); + if (!skb_queue_empty(&mp->recvqueue)) + mask |= POLLIN | POLLRDNORM; + poll_wait(file, &(mp->sendwait), wait); + if (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) + mask = POLLOUT | POLLWRNORM; + return mask; +} + +static int +capinc_raw_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + if (!mp || !mp->nccip) + return -EINVAL; + + switch (cmd) { + } + return -EINVAL; +} + +static int +capinc_raw_release(struct inode *inode, struct file *file) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + + if (mp) { + lock_kernel(); + mp->file = 0; + if (mp->nccip == 0) { + capiminor_free(mp); + file->private_data = NULL; + } + unlock_kernel(); + } + +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(&__this_module)); +#endif + return 0; +} + +static struct file_operations capinc_raw_fops = +{ + llseek: capinc_raw_llseek, + read: capinc_raw_read, + write: capinc_raw_write, + poll: capinc_raw_poll, + ioctl: capinc_raw_ioctl, + open: capinc_raw_open, + release: capinc_raw_release, +}; + +/* -------- tty_operations for capincci ----------------------------- */ + +int capinc_tty_open(struct tty_struct * tty, struct file * file) +{ + struct capiminor *mp; + + if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) + return -ENXIO; + if (mp->nccip == 0) + return -ENXIO; + if (mp->file) + return -EBUSY; + + skb_queue_head_init(&mp->recvqueue); + init_waitqueue_head(&mp->recvwait); + init_waitqueue_head(&mp->sendwait); + tty->driver_data = (void *)mp; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(&__this_module)); +#endif + if (atomic_read(&mp->ttyopencount) == 0) + mp->tty = tty; + atomic_inc(&mp->ttyopencount); +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); +#endif + handle_minor_recv(mp); + return 0; +} + +void capinc_tty_close(struct tty_struct * tty, struct file * file) +{ + struct capiminor *mp; + + mp = (struct capiminor *)tty->driver_data; + if (mp) { + if (atomic_dec_and_test(&mp->ttyopencount)) { +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_close lastclose\n"); +#endif + tty->driver_data = (void *)0; + mp->tty = 0; + } +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); +#endif + if (mp->nccip == 0) + capiminor_free(mp); + } + +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_close\n"); +#endif +} + +int capinc_tty_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct sk_buff *skb; + int retval; + +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n", + from_user, count); +#endif + + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n"); +#endif + return 0; + } + + skb = mp->ttyskb; + if (skb) { + mp->ttyskb = 0; + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + } + + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n"); + return -ENOMEM; + } + + skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); + if (from_user) { + if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { + kfree_skb(skb); +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval); +#endif + return retval; + } + } else { + memcpy(skb_put(skb, count), buf, count); + } + + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + (void)handle_minor_recv(mp); + return count; +} + +void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct sk_buff *skb; + +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_put_char(%u)\n", ch); +#endif + + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n"); +#endif + return; + } + + skb = mp->ttyskb; + if (skb) { + if (skb_tailroom(skb) > 0) { + *(skb_put(skb, 1)) = ch; + return; + } + mp->ttyskb = 0; + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + } + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC); + if (skb) { + skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); + *(skb_put(skb, 1)) = ch; + mp->ttyskb = skb; + } else { + printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); + } +} + +void capinc_tty_flush_chars(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct sk_buff *skb; + +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_flush_chars\n"); +#endif + + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n"); +#endif + return; + } + + skb = mp->ttyskb; + if (skb) { + mp->ttyskb = 0; + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + } + (void)handle_minor_recv(mp); +} + +int capinc_tty_write_room(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + int room; + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n"); +#endif + return 0; + } + room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue); + room *= CAPI_MAX_BLKSIZE; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room); +#endif + return room; +} + +int capinc_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n"); +#endif + return 0; + } +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", + mp->outbytes, mp->nack, + skb_queue_len(&mp->outqueue), + skb_queue_len(&mp->inqueue)); +#endif + return mp->outbytes; +} + +int capinc_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error = 0; + switch (cmd) { + default: + error = n_tty_ioctl (tty, file, cmd, arg); + break; + } + return error; +} + +void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_set_termios\n"); +#endif +} + +void capinc_tty_throttle(struct tty_struct * tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_throttle\n"); +#endif + if (mp) + mp->ttyinstop = 1; +} + +void capinc_tty_unthrottle(struct tty_struct * tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_unthrottle\n"); +#endif + if (mp) { + mp->ttyinstop = 0; + handle_minor_recv(mp); + } +} + +void capinc_tty_stop(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_stop\n"); +#endif + if (mp) { + mp->ttyoutstop = 1; + } +} + +void capinc_tty_start(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_start\n"); +#endif + if (mp) { + mp->ttyoutstop = 0; + (void)handle_minor_send(mp); + } +} + +void capinc_tty_hangup(struct tty_struct *tty) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_hangup\n"); +#endif +} + +void capinc_tty_break_ctl(struct tty_struct *tty, int state) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state); +#endif +} + +void capinc_tty_flush_buffer(struct tty_struct *tty) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_flush_buffer\n"); +#endif +} + +void capinc_tty_set_ldisc(struct tty_struct *tty) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_set_ldisc\n"); +#endif +} + +void capinc_tty_send_xchar(struct tty_struct *tty, char ch) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch); +#endif +} + +int capinc_tty_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return 0; +} + +int capinc_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + return 0; +} + +#define CAPINC_NR_PORTS 256 +static struct tty_driver capinc_tty_driver; +static int capinc_tty_refcount; +static struct tty_struct *capinc_tty_table[CAPINC_NR_PORTS]; +static struct termios *capinc_tty_termios[CAPINC_NR_PORTS]; +static struct termios *capinc_tty_termios_locked[CAPINC_NR_PORTS]; + +int capinc_tty_init(void) +{ + struct tty_driver *drv = &capinc_tty_driver; + + /* Initialize the tty_driver structure */ + + memset(drv, 0, sizeof(struct tty_driver)); + drv->magic = TTY_DRIVER_MAGIC; +#if (LINUX_VERSION_CODE > 0x20100) + drv->driver_name = "capi_nc"; +#endif + drv->name = "capi/%d"; + drv->major = capi_ttymajor; + drv->minor_start = 0; + drv->num = CAPINC_NR_PORTS; + drv->type = TTY_DRIVER_TYPE_SERIAL; + drv->subtype = SERIAL_TYPE_NORMAL; + drv->init_termios = tty_std_termios; + drv->init_termios.c_iflag = ICRNL; + drv->init_termios.c_oflag = OPOST | ONLCR; + drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + drv->init_termios.c_lflag = 0; + drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS; + drv->refcount = &capinc_tty_refcount; + drv->table = capinc_tty_table; + drv->termios = capinc_tty_termios; + drv->termios_locked = capinc_tty_termios_locked; + + drv->open = capinc_tty_open; + drv->close = capinc_tty_close; + drv->write = capinc_tty_write; + drv->put_char = capinc_tty_put_char; + drv->flush_chars = capinc_tty_flush_chars; + drv->write_room = capinc_tty_write_room; + drv->chars_in_buffer = capinc_tty_chars_in_buffer; + drv->ioctl = capinc_tty_ioctl; + drv->set_termios = capinc_tty_set_termios; + drv->throttle = capinc_tty_throttle; + drv->unthrottle = capinc_tty_unthrottle; + drv->stop = capinc_tty_stop; + drv->start = capinc_tty_start; + drv->hangup = capinc_tty_hangup; +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + drv->break_ctl = capinc_tty_break_ctl; +#endif + drv->flush_buffer = capinc_tty_flush_buffer; + drv->set_ldisc = capinc_tty_set_ldisc; +#if (LINUX_VERSION_CODE >= 131343) + drv->send_xchar = capinc_tty_send_xchar; + drv->read_proc = capinc_tty_read_proc; +#endif + if (tty_register_driver(drv)) { + printk(KERN_ERR "Couldn't register capi_nc driver\n"); + return -1; + } + return 0; +} + +void capinc_tty_exit(void) +{ + struct tty_driver *drv = &capinc_tty_driver; + int retval; + if ((retval = tty_unregister_driver(drv))) + printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval); +} + +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +/* -------- /proc functions ----------------------------------------- */ + +/* + * /proc/capi/capi20: + * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt + */ +static int proc_capidev_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capidev *cdev; + int len = 0; + + for (cdev=capidev_openlist; cdev; cdev = cdev->next) { + len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n", + cdev->minor, + cdev->applid, + cdev->nrecvctlpkt, + cdev->nrecvdatapkt, + cdev->nsentctlpkt, + cdev->nsentdatapkt); + if (len <= off) { + off -= len; + len = 0; + } else { + if (len-off > count) + goto endloop; } } endloop: - if (i >= CAPI_MAXMINOR) + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +/* + * /proc/capi/capi20ncci: + * applid ncci + */ +static int proc_capincci_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capidev *cdev; + struct capincci *np; + int len = 0; + + for (cdev=capidev_openlist; cdev; cdev = cdev->next) { + for (np=cdev->nccis; np; np = np->next) { + len += sprintf(page+len, "%d 0x%x%s\n", + cdev->applid, + np->ncci, +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE + ""); +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + np->minorp && np->minorp->file ? " open" : ""); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + if (len <= off) { + off -= len; + len = 0; + } else { + if (len-off > count) + goto endloop; + } + } + } +endloop: + *start = page+off; + if (len < count) + *eof = 1; + if (len>count) len = count; + if (len<0) len = 0; + return len; } static struct procfsentries { @@ -577,9 +1964,10 @@ } procfsentries[] = { /* { "capi", S_IFDIR, 0 }, */ { "capi/capi20", 0 , proc_capidev_read_proc }, + { "capi/capi20ncci", 0 , proc_capincci_read_proc }, }; -static void proc_init(void) +static void __init proc_init(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -591,7 +1979,7 @@ } } -static void proc_exit(void) +static void proc_exit(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -604,42 +1992,118 @@ } } } + /* -------- init function and module interface ---------------------- */ -#ifdef MODULE -#define capi_init init_module -#endif + +static void lower_callback(unsigned int cmd, __u32 contr, void *data) +{ + struct capi_ncciinfo *np; + struct capidev *cdev; + + switch (cmd) { + case KCI_CONTRUP: + printk(KERN_INFO "capi: controller %hu up\n", contr); + break; + case KCI_CONTRDOWN: + printk(KERN_INFO "capi: controller %hu down\n", contr); + break; + case KCI_NCCIUP: + np = (struct capi_ncciinfo *)data; + if ((cdev = capidev_find(np->applid)) == 0) + return; + (void)capincci_alloc(cdev, np->ncci); + break; + case KCI_NCCIDOWN: + np = (struct capi_ncciinfo *)data; + if ((cdev = capidev_find(np->applid)) == 0) + return; + (void)capincci_free(cdev, np->ncci); + break; + } +} static struct capi_interface_user cuser = { - "capi20", - 0, + name: "capi20", + callback: lower_callback, }; -int capi_init(void) +static char rev[10]; + +static int __init capi_init(void) { - - memset(capidevs, 0, sizeof(capidevs)); + char *p; + + MOD_INC_USE_COUNT; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 2); + p = strchr(rev, '$'); + *(p-1) = 0; + } else + strcpy(rev, "???"); if (register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); + MOD_DEC_USE_COUNT; + return -EIO; + } + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if (register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) { + unregister_chrdev(capi_major, "capi20"); + printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor); + MOD_DEC_USE_COUNT; return -EIO; } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major); if ((capifuncs = attach_capi_interface(&cuser)) == 0) { + + MOD_DEC_USE_COUNT; unregister_chrdev(capi_major, "capi20"); +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + unregister_chrdev(capi_rawmajor, "capi/r%d"); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ return -EIO; } + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if (capinc_tty_init() < 0) { + (void) detach_capi_interface(&cuser); + unregister_chrdev(capi_major, "capi20"); + unregister_chrdev(capi_rawmajor, "capi/r%d"); + MOD_DEC_USE_COUNT; + return -ENOMEM; + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + (void)proc_init(); + + printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n", + rev, capi_major); + + MOD_DEC_USE_COUNT; return 0; } -#ifdef MODULE -void cleanup_module(void) +static void capi_exit(void) { +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +#endif (void)proc_exit(); + unregister_chrdev(capi_major, "capi20"); + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + capinc_tty_exit(); + unregister_chrdev(capi_rawmajor, "capi/r%d"); +#endif (void) detach_capi_interface(&cuser); + printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev); } -#endif +module_init(capi_init); +module_exit(capi_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capicmd.h linux/drivers/isdn/avmb1/capicmd.h --- v2.2.18/drivers/isdn/avmb1/capicmd.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/capicmd.h Sun Mar 25 11:37:32 2001 @@ -1,11 +1,22 @@ /* - * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $ + * $Id: capicmd.h,v 1.2 2000/03/03 15:50:42 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capicmd.h,v $ + * Revision 1.2 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.1 1997/03/04 21:50:30 calle * Frirst version in isdn4linux * @@ -19,6 +30,10 @@ */ #ifndef __CAPICMD_H__ #define __CAPICMD_H__ + +#define CAPI_MSG_BASELEN 8 +#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2) +#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2) /*----- CAPI commands -----*/ #define CAPI_ALERT 0x01 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h --- v2.2.18/drivers/isdn/avmb1/capidev.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/capidev.h Sun Mar 25 11:37:32 2001 @@ -1,11 +1,25 @@ /* - * $Id: capidev.h,v 1.4 1999/07/01 15:26:32 calle Exp $ + * $Id: capidev.h,v 1.6 2000/11/25 17:00:59 kai Exp $ * * CAPI 2.0 Interface for Linux * * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidev.h,v $ + * Revision 1.6 2000/11/25 17:00:59 kai + * compatibility cleanup - final part for the time being + * + * Revision 1.5 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.4 1999/07/01 15:26:32 calle * complete new version (I love it): * + new hardware independed "capi_driver" interface that will make it easy to: @@ -40,18 +54,18 @@ */ struct capidev { - int is_open; - int is_registered; - __u16 applid; + struct capidev *next; + struct file *file; + __u16 applid; + __u16 errcode; + unsigned int minor; + struct sk_buff_head recv_queue; - struct wait_queue *recv_wait; - __u16 errcode; + wait_queue_head_t recv_wait; + /* Statistic */ - unsigned long nopen; - unsigned long nrecvctlpkt; - unsigned long nrecvdatapkt; - unsigned long nsentctlpkt; - unsigned long nsentdatapkt; + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; }; - -#define CAPI_MAXMINOR CAPI_MAXAPPL diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.2.18/drivers/isdn/avmb1/capidrv.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/capidrv.c Sun Mar 25 11:37:32 2001 @@ -1,11 +1,64 @@ /* - * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $ + * $Id: capidrv.c,v 1.39.6.2 2001/02/13 11:43:29 kai Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.39.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.39.6.1 2001/02/10 14:41:20 kai + * Changes from kernel tree + * + * Revision 1.39 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.38 2000/11/14 08:43:07 calle + * Bugfix for v110. Connectparamters where setup for sync ... + * + * Revision 1.37 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.36 2000/06/26 15:13:41 keil + * features should be or'ed + * + * Revision 1.35 2000/06/19 15:11:25 keil + * avoid use of freed structs + * changes from 2.4.0-ac21 + * + * Revision 1.34 2000/06/19 13:13:55 calle + * Added Modemsupport! + * + * Revision 1.33 2000/05/06 00:52:36 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * + * Revision 1.32 2000/04/07 15:19:58 calle + * remove warnings + * + * Revision 1.31 2000/04/06 15:01:25 calle + * Bugfix: crash in capidrv.c when reseting a capi controller. + * - changed code order on remove of controller. + * - using tq_schedule for notifier in kcapi.c. + * - now using spin_lock_irqsave() and spin_unlock_irqrestore(). + * strange: sometimes even MP hang on unload of isdn.o ... + * + * Revision 1.30 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.29 1999/12/06 17:13:06 calle * Added controller watchdog. * @@ -151,7 +204,7 @@ #include #include #include -#include +#include #include #include #include @@ -165,14 +218,15 @@ #include #include #include +#include #include #include "capiutil.h" #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.29 $"; -int debugmode = 0; +static char *revision = "$Revision: 1.39.6.2 $"; +static int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); MODULE_PARM(debugmode, "i"); @@ -280,6 +334,7 @@ /* -------- data definitions ----------------------------------------- */ static capidrv_data global; +static spinlock_t global_lock = SPIN_LOCK_UNLOCKED; static struct capi_interface *capifuncs; static void handle_dtrace_data(capidrv_contr *card, @@ -305,6 +360,8 @@ return 2; case ISDN_PROTO_L2_FAX: return 4; + case ISDN_PROTO_L2_MODEM: + return 8; } } @@ -321,6 +378,7 @@ case ISDN_PROTO_L2_V11096: case ISDN_PROTO_L2_V11019: case ISDN_PROTO_L2_V11038: + case ISDN_PROTO_L2_MODEM: return 1; case ISDN_PROTO_L2_FAX: return 4; @@ -338,6 +396,7 @@ case ISDN_PROTO_L2_V11096: case ISDN_PROTO_L2_V11019: case ISDN_PROTO_L2_V11038: + case ISDN_PROTO_L2_MODEM: default: return 0; case ISDN_PROTO_L2_FAX: @@ -345,16 +404,16 @@ } } -static _cstruct b1config_sync_v110(__u16 rate) +static _cstruct b1config_async_v110(__u16 rate) { /* CAPI-Spec "B1 Configuration" */ static unsigned char buf[9]; buf[0] = 8; /* len */ /* maximum bitrate */ buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff; - buf[3] = buf[4] = 0; /* reserved, bits per character */ - buf[5] = buf[6] = 0; /* reserved, parity */ - buf[7] = buf[9] = 0; /* reserved, stop bits */ + buf[3] = 8; buf[4] = 0; /* 8 bits per character */ + buf[5] = 0; buf[6] = 0; /* parity none */ + buf[7] = 0; buf[8] = 0; /* 1 stop bit */ return buf; } @@ -369,11 +428,11 @@ default: return 0; case ISDN_PROTO_L2_V11096: - return b1config_sync_v110(9600); + return b1config_async_v110(9600); case ISDN_PROTO_L2_V11019: - return b1config_sync_v110(19200); + return b1config_async_v110(19200); case ISDN_PROTO_L2_V11038: - return b1config_sync_v110(38400); + return b1config_async_v110(38400); } } @@ -439,26 +498,28 @@ static inline capidrv_contr *findcontrbydriverid(int driverid) { - capidrv_contr *p = global.contr_list; + unsigned long flags; + capidrv_contr *p; - while (p) { + spin_lock_irqsave(&global_lock, flags); + for (p = global.contr_list; p; p = p->next) if (p->myid == driverid) - return p; - p = p->next; - } - return (capidrv_contr *) 0; + break; + spin_unlock_irqrestore(&global_lock, flags); + return p; } static capidrv_contr *findcontrbynumber(__u32 contr) { + unsigned long flags; capidrv_contr *p = global.contr_list; - while (p) { + spin_lock_irqsave(&global_lock, flags); + for (p = global.contr_list; p; p = p->next) if (p->contrnr == contr) - return p; - p = p->next; - } - return (capidrv_contr *) 0; + break; + spin_unlock_irqrestore(&global_lock, flags); + return p; } @@ -1501,7 +1562,7 @@ static _cmsg s_cmsg; -static void capidrv_signal(__u16 applid, __u32 dummy) +static void capidrv_signal(__u16 applid, void *dummy) { struct sk_buff *skb = 0; @@ -1545,47 +1606,41 @@ static void handle_dtrace_data(capidrv_contr *card, int send, int level2, __u8 *data, __u16 len) { - long flags; - __u8 *p, *end; - isdn_ctrl cmd; + __u8 *p, *end; + isdn_ctrl cmd; - if (!len) { - printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", + if (!len) { + printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", card->contrnr, len); - return; - } - - save_flags(flags); - cli(); - - if (level2) { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '2'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } else { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '3'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } + return; + } - for (p = data, end = data+len; p < end; p++) { - __u8 w; - PUTBYTE_TO_STATUS(card, ' '); - w = (*p >> 4) & 0xf; - PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); - w = *p & 0xf; - PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); - } - PUTBYTE_TO_STATUS(card, '\n'); + if (level2) { + PUTBYTE_TO_STATUS(card, 'D'); + PUTBYTE_TO_STATUS(card, '2'); + PUTBYTE_TO_STATUS(card, send ? '>' : '<'); + PUTBYTE_TO_STATUS(card, ':'); + } else { + PUTBYTE_TO_STATUS(card, 'D'); + PUTBYTE_TO_STATUS(card, '3'); + PUTBYTE_TO_STATUS(card, send ? '>' : '<'); + PUTBYTE_TO_STATUS(card, ':'); + } + + for (p = data, end = data+len; p < end; p++) { + __u8 w; + PUTBYTE_TO_STATUS(card, ' '); + w = (*p >> 4) & 0xf; + PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); + w = *p & 0xf; + PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); + } + PUTBYTE_TO_STATUS(card, '\n'); - restore_flags(flags); - - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = len*3+5; - card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_STAVAIL; + cmd.driver = card->myid; + cmd.arg = len*3+5; + card->interface.statcallb(&cmd); } /* ------------------------------------------------------------------- */ @@ -1990,8 +2045,8 @@ return capidrv_command(c, card); printk(KERN_ERR - "capidrv-%d: if_command %d called with invalid driverId %d!\n", - card->contrnr, c->command, c->driver); + "capidrv: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); return -ENODEV; } @@ -2147,50 +2202,6 @@ send_message(card, &cmdcmsg); } -static void disable_dchannel_trace(capidrv_contr *card) -{ - __u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - __u16 contr = card->contrnr; - __u16 errcode; - __u16 avmversion[3]; - - errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", - card->name, errcode); - return; - } - if (strstr(manufacturer, "AVM") == 0) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", - card->name, manufacturer); - return; - } - errcode = (*capifuncs->capi_get_version)(contr, &version); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get version (0x%x)\n", - card->name, errcode); - return; - } - avmversion[0] = (version.majormanuversion >> 4) & 0x0f; - avmversion[1] = (version.majormanuversion << 4) & 0xf0; - avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; - avmversion[2] |= version.minormanuversion & 0x0f; - - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { - printk(KERN_INFO "%s: D2 trace disabled\n", card->name); - } else { - printk(KERN_INFO "%s: D3 trace disabled\n", card->name); - } - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\000\000\000\000"); - send_message(card, &cmdcmsg); -} static void send_listen(capidrv_contr *card) { @@ -2218,14 +2229,18 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) { capidrv_contr *card; + long flags; isdn_ctrl cmd; char id[20]; int i; + MOD_INC_USE_COUNT; + sprintf(id, "capidrv-%d", contr); if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) { printk(KERN_WARNING "capidrv: (%s) Could not allocate contr-struct.\n", id); + MOD_DEC_USE_COUNT; return -1; } memset(card, 0, sizeof(capidrv_contr)); @@ -2238,6 +2253,7 @@ printk(KERN_WARNING "capidrv: (%s) Could not allocate bchan-structs.\n", id); kfree(card); + MOD_DEC_USE_COUNT; return -1; } card->interface.channels = profp->nbchannel; @@ -2246,41 +2262,49 @@ card->interface.writebuf_skb = if_sendbuf; card->interface.writecmd = 0; card->interface.readstat = if_readstat; - card->interface.features = ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_X75UI | - ISDN_FEATURE_L2_X75BUI | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_L2_V11096 | - ISDN_FEATURE_L2_V11019 | - ISDN_FEATURE_L2_V11038 | - ISDN_FEATURE_P_UNKNOWN; + card->interface.features = ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_P_UNKNOWN | + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_X75UI | + ISDN_FEATURE_L2_X75BUI; + if (profp->support1 & (1<<2)) + card->interface.features |= ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038; + if (profp->support1 & (1<<8)) + card->interface.features |= ISDN_FEATURE_L2_MODEM; card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); - card->next = global.contr_list; - global.contr_list = card; - global.ncontr++; + + card->q931_read = card->q931_buf; card->q931_write = card->q931_buf; card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1; if (!register_isdn(&card->interface)) { - global.contr_list = global.contr_list->next; printk(KERN_ERR "capidrv: Unable to register contr %s\n", id); kfree(card->bchans); kfree(card); + MOD_DEC_USE_COUNT; return -1; } card->myid = card->interface.channels; + spin_lock_irqsave(&global_lock, flags); + card->next = global.contr_list; + global.contr_list = card; + global.ncontr++; + spin_unlock_irqrestore(&global_lock, flags); + memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan); for (i = 0; i < card->nbchan; i++) { card->bchans[i].contr = card; } - cmd.driver = card->myid; cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; card->interface.statcallb(&cmd); card->cipmask = 0x1FFF03FF; /* any */ @@ -2303,45 +2327,82 @@ static int capidrv_delcontr(__u16 contr) { capidrv_contr **pp, *card; + unsigned long flags; isdn_ctrl cmd; - int i; - for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { - if ((*pp)->contrnr == contr) + spin_lock_irqsave(&global_lock, flags); + for (card = global.contr_list; card; card = card->next) { + if (card->contrnr == contr) break; } - if (!*pp) { + if (!card) { + spin_unlock_irqrestore(&global_lock, flags); printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); return -1; } - card = *pp; + spin_unlock_irqrestore(&global_lock, flags); + + del_timer(&card->listentimer); if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", card->contrnr, card->myid); - cmd.command = ISDN_STAT_UNLOAD; + cmd.command = ISDN_STAT_STOP; cmd.driver = card->myid; card->interface.statcallb(&cmd); - *pp = (*pp)->next; - global.ncontr--; + while (card->nbchan) { - for (i = 0; i < card->nbchan; i++) { - if (card->bchans[i].nccip) - free_ncci(card, card->bchans[i].nccip); - if (card->bchans[i].plcip) - free_plci(card, card->bchans[i].plcip); + cmd.command = ISDN_STAT_DISCH; + cmd.driver = card->myid; + cmd.arg = card->nbchan-1; + cmd.parm.num[0] = 0; + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n", + card->contrnr, card->myid, cmd.arg); + card->interface.statcallb(&cmd); + + if (card->bchans[card->nbchan-1].nccip) + free_ncci(card, card->bchans[card->nbchan-1].nccip); + if (card->bchans[card->nbchan-1].plcip) + free_plci(card, card->bchans[card->nbchan-1].plcip); if (card->plci_list) printk(KERN_ERR "capidrv: bug in free_plci()\n"); + card->nbchan--; } kfree(card->bchans); - del_timer(&card->listentimer); + card->bchans = 0; + + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n", + card->contrnr, card->myid); + + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n", + card->contrnr, card->myid); + + spin_lock_irqsave(&global_lock, flags); + for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { + if (*pp == card) { + *pp = (*pp)->next; + card->next = 0; + global.ncontr--; + break; + } + } + spin_unlock_irqrestore(&global_lock, flags); printk(KERN_INFO "%s: now down.\n", card->name); kfree(card); + MOD_DEC_USE_COUNT; + return 0; } @@ -2394,7 +2455,7 @@ { "capi/capidrv", 0 , proc_capidrv_read_proc }, }; -static void proc_init(void) +static void __init proc_init(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -2406,7 +2467,7 @@ } } -static void proc_exit(void) +static void proc_exit(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -2421,15 +2482,11 @@ } static struct capi_interface_user cuser = { - "capidrv", - lower_callback + name: "capidrv", + callback: lower_callback }; -#ifdef MODULE -#define capidrv_init init_module -#endif - -int capidrv_init(void) +static int __init capidrv_init(void) { struct capi_register_params rparam; capi_profile profile; @@ -2438,10 +2495,14 @@ __u32 ncontr, contr; __u16 errcode; + MOD_INC_USE_COUNT; + capifuncs = attach_capi_interface(&cuser); - if (!capifuncs) + if (!capifuncs) { + MOD_DEC_USE_COUNT; return -EIO; + } if ((p = strchr(revision, ':'))) { strcpy(rev, p + 1); @@ -2456,6 +2517,7 @@ errcode = (*capifuncs->capi_register) (&rparam, &global.appid); if (errcode) { detach_capi_interface(&cuser); + MOD_DEC_USE_COUNT; return -EIO; } @@ -2463,6 +2525,7 @@ if (errcode != CAPI_NOERROR) { (void) (*capifuncs->capi_release) (global.appid); detach_capi_interface(&cuser); + MOD_DEC_USE_COUNT; return -EIO; } @@ -2477,17 +2540,18 @@ } proc_init(); + printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev); + MOD_DEC_USE_COUNT; + return 0; } -#ifdef MODULE -void cleanup_module(void) +static void capidrv_exit(void) { - capidrv_contr *card, *next; char rev[10]; char *p; - if ((p = strchr(revision, ':'))) { + if ((p = strchr(revision, ':')) != 0) { strcpy(rev, p + 1); p = strchr(rev, '$'); *p = 0; @@ -2495,17 +2559,14 @@ strcpy(rev, " ??? "); } - for (card = global.contr_list; card; card = next) { - next = card->next; - disable_dchannel_trace(card); - capidrv_delcontr(card->contrnr); - } - (void) (*capifuncs->capi_release) (global.appid); + detach_capi_interface(&cuser); + proc_exit(); printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev); } -#endif +module_init(capidrv_init); +module_exit(capidrv_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c --- v2.2.18/drivers/isdn/avmb1/capifs.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/avmb1/capifs.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,626 @@ +/* + * $Id: capifs.c,v 1.14.6.3 2001/02/13 11:43:29 kai Exp $ + * + * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) + * + * Heavily based on devpts filesystem from H. Peter Anvin + * + * $Log: capifs.c,v $ + * Revision 1.14.6.3 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.14.6.2 2001/02/10 14:41:20 kai + * Changes from kernel tree + * + * Revision 1.14.6.1 2000/11/28 12:02:45 kai + * MODULE_DEVICE_TABLE for 2.4 + * + * Revision 1.14.2.1 2000/11/26 17:47:53 kai + * added PCI_DEV_TABLE for 2.4 + * + * Revision 1.14 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.13 2000/11/18 16:17:25 kai + * change from 2.4 tree + * + * Revision 1.12 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.11 2000/10/24 15:08:47 calle + * Too much includes. + * + * Revision 1.10 2000/10/12 10:12:35 calle + * Bugfix: second iput(inode) on umount, destroies a foreign inode. + * + * Revision 1.9 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.8 2000/07/20 10:23:13 calle + * Include isdn_compat.h for people that don't use -p option of std2kern. + * + * Revision 1.7 2000/06/18 16:09:54 keil + * more changes for 2.4 + * + * Revision 1.6 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * + * Revision 1.5 2000/03/13 17:49:52 calle + * make it running with 2.3.51. + * + * Revision 1.4 2000/03/08 17:06:33 calle + * - changes for devfs and 2.3.49 + * - capifs now configurable (no need with devfs) + * - New Middleware ioctl CAPI_NCCI_GETUNIT + * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) + * + * Revision 1.3 2000/03/06 18:00:23 calle + * - Middleware extention now working with 2.3.49 (capifs). + * - Fixed typos in debug section of capi.c + * - Bugfix: Makefile corrected for b1pcmcia.c + * + * Revision 1.2 2000/03/06 09:17:07 calle + * - capifs: fileoperations now in inode (change for 2.3.49) + * - Config.in: Middleware extention not a tristate, uups. + * + * Revision 1.1 2000/03/03 16:48:38 calle + * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) + * It is now possible to create a connection with a CAPI2.0 applikation + * and than to handle the data connection from /dev/capi/ (capifs) and also + * using async or sync PPP on this connection. + * The two major device number 190 and 191 are not confirmed yet, + * but I want to save the code in cvs, before I go on. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Carsten Paeth "); + +static char *revision = "$Revision: 1.14.6.3 $"; + +struct capifs_ncci { + struct inode *inode; + char used; + char type; + unsigned int num; + kdev_t kdev; +}; + +struct capifs_sb_info { + u32 magic; + struct super_block *next; + struct super_block **back; + int setuid; + int setgid; + uid_t uid; + gid_t gid; + umode_t mode; + + unsigned int max_ncci; + struct capifs_ncci *nccis; +}; + +#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') +#define CAPIFS_SBI_MAGIC (('C'<<24)|('A'<<16)|('P'<<8)|'I') + +static inline struct capifs_sb_info *SBI(struct super_block *sb) +{ + return (struct capifs_sb_info *)(sb->u.generic_sbp); +} + +/* ------------------------------------------------------------------ */ + +static int capifs_root_readdir(struct file *,void *,filldir_t); +static struct dentry *capifs_root_lookup(struct inode *,struct dentry *); +static int capifs_revalidate(struct dentry *, int); + +static struct file_operations capifs_root_operations = { + readdir: capifs_root_readdir, +}; + +struct inode_operations capifs_root_inode_operations = { + default_file_ops: &capifs_root_operations, /* file operations */ + lookup: capifs_root_lookup, +}; + +static struct dentry_operations capifs_dentry_operations = { + d_revalidate: capifs_revalidate, +}; + +/* + * /dev/capi/%d + * /dev/capi/r%d + */ + +static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct inode * inode = filp->f_dentry->d_inode; + struct capifs_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb); + off_t nr; + char numbuf[32]; + + nr = filp->f_pos; + + switch(nr) + { + case 0: + if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + default: + while (nr < sbi->max_ncci) { + int n = nr - 2; + struct capifs_ncci *np = &sbi->nccis[n]; + if (np->inode && np->used) { + char *p = numbuf; + if (np->type) *p++ = np->type; + sprintf(p, "%u", np->num); + if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 ) + return 0; + } + filp->f_pos = ++nr; + } + break; + } + + return 0; +} + +/* + * Revalidate is called on every cache lookup. We use it to check that + * the ncci really does still exist. Never revalidate negative dentries; + * for simplicity (fix later?) + */ +static int capifs_revalidate(struct dentry * dentry, int flags) +{ + struct capifs_sb_info *sbi; + + if ( !dentry->d_inode ) + return 0; + + sbi = SBI(dentry->d_inode->i_sb); + + return ( sbi->nccis[dentry->d_inode->i_ino - 2].inode == dentry->d_inode ); +} + +static struct dentry *capifs_root_lookup(struct inode * dir, struct dentry * dentry) +{ + struct capifs_sb_info *sbi = SBI(dir->i_sb); + struct capifs_ncci *np; + unsigned int i; + char numbuf[32]; + char *p, *tmp; + unsigned int num; + char type = 0; + + dentry->d_inode = NULL; /* Assume failure */ + dentry->d_op = &capifs_dentry_operations; + + if (dentry->d_name.len >= sizeof(numbuf) ) + return NULL; + strncpy(numbuf, dentry->d_name.name, dentry->d_name.len); + numbuf[dentry->d_name.len] = 0; + p = numbuf; + if (!isdigit(*p)) type = *p++; + tmp = p; + num = (unsigned int)simple_strtoul(p, &tmp, 10); + if (tmp == p || *tmp) + return NULL; + + for (i = 0, np = sbi->nccis ; i < sbi->max_ncci; i++, np++) { + if (np->used && np->num == num && np->type == type) + break; + } + + if ( i >= sbi->max_ncci ) + return NULL; + + dentry->d_inode = np->inode; + if ( dentry->d_inode ) + dentry->d_inode->i_count++; + + d_add(dentry, dentry->d_inode); + + return NULL; +} + +/* ------------------------------------------------------------------ */ + +static struct super_block *mounts = NULL; + +static void capifs_put_super(struct super_block *sb) +{ + struct capifs_sb_info *sbi = SBI(sb); + struct inode *inode; + int i; + + for ( i = 0 ; i < sbi->max_ncci ; i++ ) { + if ( (inode = sbi->nccis[i].inode) ) { + if (inode->i_count != 1 ) + printk("capifs_put_super: badness: entry %d count %d\n", + i, (unsigned)inode->i_count); + inode->i_nlink--; + iput(inode); + } + } + + *sbi->back = sbi->next; + if ( sbi->next ) + SBI(sbi->next)->back = sbi->back; + + kfree(sbi->nccis); + kfree(sbi); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + MOD_DEC_USE_COUNT; +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) +static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); +static void capifs_write_inode(struct inode *inode) { }; +#else +static int capifs_statfs(struct super_block *sb, struct statfs *buf); +#endif +static void capifs_read_inode(struct inode *inode); + +static struct super_operations capifs_sops = { + read_inode: capifs_read_inode, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + write_inode: capifs_write_inode, +#endif + put_super: capifs_put_super, + statfs: capifs_statfs, +}; + +static int capifs_parse_options(char *options, struct capifs_sb_info *sbi) +{ + int setuid = 0; + int setgid = 0; + uid_t uid = 0; + gid_t gid = 0; + umode_t mode = 0600; + unsigned int maxncci = 512; + char *this_char, *value; + + this_char = NULL; + if ( options ) + this_char = strtok(options,","); + for ( ; this_char; this_char = strtok(NULL,",")) { + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"uid")) { + if (!value || !*value) + return 1; + uid = simple_strtoul(value,&value,0); + if (*value) + return 1; + setuid = 1; + } + else if (!strcmp(this_char,"gid")) { + if (!value || !*value) + return 1; + gid = simple_strtoul(value,&value,0); + if (*value) + return 1; + setgid = 1; + } + else if (!strcmp(this_char,"mode")) { + if (!value || !*value) + return 1; + mode = simple_strtoul(value,&value,8); + if (*value) + return 1; + } + else if (!strcmp(this_char,"maxncci")) { + if (!value || !*value) + return 1; + maxncci = simple_strtoul(value,&value,8); + if (*value) + return 1; + } + else + return 1; + } + sbi->setuid = setuid; + sbi->setgid = setgid; + sbi->uid = uid; + sbi->gid = gid; + sbi->mode = mode & ~S_IFMT; + sbi->max_ncci = maxncci; + + return 0; +} + +struct super_block *capifs_read_super(struct super_block *s, void *data, + int silent) +{ + struct inode * root_inode; + struct dentry * root; + struct capifs_sb_info *sbi; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + MOD_INC_USE_COUNT; + lock_super(s); +#endif + /* Super block already completed? */ + if (s->s_root) + goto out; + + sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL); + if ( !sbi ) + goto fail; + + memset(sbi, 0, sizeof(struct capifs_sb_info)); + sbi->magic = CAPIFS_SBI_MAGIC; + + if ( capifs_parse_options(data,sbi) ) { + kfree(sbi); + printk("capifs: called with bogus options\n"); + goto fail; + } + + sbi->nccis = kmalloc(sizeof(struct capifs_ncci) * sbi->max_ncci, GFP_KERNEL); + if ( !sbi->nccis ) { + kfree(sbi); + goto fail; + } + memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci); + + s->u.generic_sbp = (void *) sbi; + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = CAPIFS_SUPER_MAGIC; + s->s_op = &capifs_sops; + s->s_root = NULL; + + /* + * Get the root inode and dentry, but defer checking for errors. + */ + root_inode = iget(s, 1); /* inode 1 == root directory */ + root = d_alloc_root(root_inode, NULL); + + /* + * Check whether somebody else completed the super block. + */ + if (s->s_root) { + if (root) dput(root); + else iput(root_inode); + goto out; + } + + if (!root) { + printk("capifs: get root dentry failed\n"); + /* + * iput() can block, so we clear the super block first. + */ + iput(root_inode); + kfree(sbi->nccis); + kfree(sbi); + goto fail; + } + + /* + * Check whether somebody else completed the super block. + */ + if (s->s_root) + goto out; + + /* + * Success! Install the root dentry now to indicate completion. + */ + s->s_root = root; + + sbi->next = mounts; + if ( sbi->next ) + SBI(sbi->next)->back = &(sbi->next); + sbi->back = &mounts; + mounts = s; + +out: /* Success ... somebody else completed the super block for us. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + unlock_super(s); +#endif + return s; +fail: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + unlock_super(s); + MOD_DEC_USE_COUNT; +#endif + return NULL; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) +static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + struct statfs tmp; + + tmp.f_type = CAPIFS_SUPER_MAGIC; + tmp.f_bsize = 1024; + tmp.f_blocks = 0; + tmp.f_bfree = 0; + tmp.f_bavail = 0; + tmp.f_files = 0; + tmp.f_ffree = 0; + tmp.f_namelen = NAME_MAX; + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; +} +#else +static int capifs_statfs(struct super_block *sb, struct statfs *buf) +{ + buf->f_type = CAPIFS_SUPER_MAGIC; + buf->f_bsize = 1024; + buf->f_blocks = 0; + buf->f_bfree = 0; + buf->f_bavail = 0; + buf->f_files = 0; + buf->f_ffree = 0; + buf->f_namelen = NAME_MAX; + return 0; +} +#endif + +static void capifs_read_inode(struct inode *inode) +{ + ino_t ino = inode->i_ino; + struct capifs_sb_info *sbi = SBI(inode->i_sb); + + inode->i_mode = 0; + inode->i_nlink = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blocks = 0; + inode->i_blksize = 1024; + inode->i_uid = inode->i_gid = 0; + + if ( ino == 1 ) { + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; + inode->i_op = &capifs_root_inode_operations; + inode->i_nlink = 2; + return; + } + + ino -= 2; + if ( ino >= sbi->max_ncci ) + return; /* Bogus */ + + inode->i_mode = S_IFCHR; + inode->i_op = &chrdev_inode_operations; + + return; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) +static struct file_system_type capifs_fs_type = { + "capifs", + 0, + capifs_read_super, + NULL +}; +#else +static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0); +#endif + +void capifs_new_ncci(char type, unsigned int num, kdev_t device) +{ + struct super_block *sb; + struct capifs_sb_info *sbi; + struct capifs_ncci *np; + ino_t ino; + + for ( sb = mounts ; sb ; sb = sbi->next ) { + sbi = SBI(sb); + + for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) { + if (np->used == 0) { + np->used = 1; + np->type = type; + np->num = num; + np->kdev = device; + break; + } + } + + if ((np->inode = iget(sb, ino+2)) != 0) { + struct inode *inode = np->inode; + inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid; + inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid; + inode->i_mode = sbi->mode | S_IFCHR; + inode->i_rdev = np->kdev; + inode->i_nlink++; + } + } +} + +void capifs_free_ncci(char type, unsigned int num) +{ + struct super_block *sb; + struct capifs_sb_info *sbi; + struct inode *inode; + struct capifs_ncci *np; + ino_t ino; + + for ( sb = mounts ; sb ; sb = sbi->next ) { + sbi = SBI(sb); + + for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) { + if (!np->used || np->type != type || np->num != num) + continue; + if (np->inode) { + inode = np->inode; + np->inode = 0; + np->used = 0; + inode->i_nlink--; + iput(inode); + break; + } + } + } +} + +static int __init capifs_init(void) +{ + char rev[10]; + char *p; + int err; + + MOD_INC_USE_COUNT; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, "1.0"); + + err = register_filesystem(&capifs_fs_type); + if (err) { + MOD_DEC_USE_COUNT; + return err; + } +#ifdef MODULE + printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev); +#else + printk(KERN_NOTICE "capifs: Rev%s: started\n", rev); +#endif + MOD_DEC_USE_COUNT; + return 0; +} + +static void capifs_exit(void) +{ + unregister_filesystem(&capifs_fs_type); +} + +EXPORT_SYMBOL(capifs_new_ncci); +EXPORT_SYMBOL(capifs_free_ncci); + +module_init(capifs_init); +module_exit(capifs_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capifs.h linux/drivers/isdn/avmb1/capifs.h --- v2.2.18/drivers/isdn/avmb1/capifs.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/avmb1/capifs.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,25 @@ +/* + * $Id: capifs.h,v 1.2 2000/03/08 17:06:33 calle Exp $ + * + * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) + * + * $Log: capifs.h,v $ + * Revision 1.2 2000/03/08 17:06:33 calle + * - changes for devfs and 2.3.49 + * - capifs now configurable (no need with devfs) + * - New Middleware ioctl CAPI_NCCI_GETUNIT + * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) + * + * Revision 1.1 2000/03/03 16:48:38 calle + * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) + * It is now possible to create a connection with a CAPI2.0 applikation + * and than to handle the data connection from /dev/capi/ (capifs) and also + * using async or sync PPP on this connection. + * The two major device number 190 and 191 are not confirmed yet, + * but I want to save the code in cvs, before I go on. + * + * + */ + +void capifs_new_ncci(char type, unsigned int num, kdev_t device); +void capifs_free_ncci(char type, unsigned int num); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c --- v2.2.18/drivers/isdn/avmb1/capiutil.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/capiutil.c Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ /* - * $Id: capiutil.c,v 1.10 1999/08/31 11:19:54 paul Exp $ + * $Id: capiutil.c,v 1.13.6.1 2001/02/13 11:43:29 kai Exp $ * * CAPI 2.0 convert capi message to capi message struct * @@ -7,6 +7,29 @@ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capiutil.c,v $ + * Revision 1.13.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.13 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.12 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.11 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.10 1999/08/31 11:19:54 paul * various spelling corrections (new checksums may be needed, Karsten!) * @@ -70,6 +93,7 @@ #include #include #include +#include #include #include @@ -794,7 +818,7 @@ /*15 */ "Class", /*16 */ "ConnectedNumber", /*17 */ "ConnectedSubaddress", - /*18 */ "Data", + /*18 */ "Data32", /*19 */ "DataHandle", /*1a */ "DataLength", /*1b */ "FacilityConfirmationParameter", @@ -892,13 +916,7 @@ cmsg->l += 2; break; case _CDWORD: - if (strcmp(NAME, "Data") == 0) { - bufprint("%-*s = ", slen, NAME); - printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l), - *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32))); - bufprint("\n"); - } else - bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l)); + bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l)); cmsg->l += 4; break; case _CSTRUCT: @@ -973,7 +991,6 @@ return buf; } - EXPORT_SYMBOL(capi_cmsg2message); EXPORT_SYMBOL(capi_message2cmsg); EXPORT_SYMBOL(capi_cmsg_header); @@ -982,15 +999,14 @@ EXPORT_SYMBOL(capi_message2str); EXPORT_SYMBOL(capi_info2str); -#ifdef MODULE - -int init_module(void) -{ - return 0; +static int __init capiutil_init(void) +{ + return 0; } -void cleanup_module(void) +static void capiutil_exit(void) { } -#endif +module_init(capiutil_init); +module_exit(capiutil_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/capiutil.h linux/drivers/isdn/avmb1/capiutil.h --- v2.2.18/drivers/isdn/avmb1/capiutil.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/capiutil.h Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ /* - * $Id: capiutil.h,v 1.4 1999/09/15 08:16:03 calle Exp $ + * $Id: capiutil.h,v 1.5 2000/03/03 15:50:42 calle Exp $ * * CAPI 2.0 defines & types * @@ -7,6 +7,17 @@ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capiutil.h,v $ + * Revision 1.5 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.4 1999/09/15 08:16:03 calle * Implementation of 64Bit extention complete. * @@ -36,28 +47,47 @@ #include -#define CAPIMSG_LEN(m) (m[0] | (m[1] << 8)) -#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8)) -#define CAPIMSG_COMMAND(m) (m[4]) -#define CAPIMSG_SUBCOMMAND(m) (m[5]) -#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8)) +#define CAPIMSG_BASELEN 8 +#define CAPIMSG_U8(m, off) (m[off]) +#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8)) +#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24)) +#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0) +#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2) +#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4) +#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5) +#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5])) +#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6) #define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f) -#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24)) +#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8) #define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m) -#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24)) -#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8)) +#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */ + +static inline void capimsg_setu8(void *m, int off, __u8 val) +{ + ((__u8 *)m)[off] = val; +} + +static inline void capimsg_setu16(void *m, int off, __u16 val) +{ + ((__u8 *)m)[off] = val & 0xff; + ((__u8 *)m)[off+1] = (val >> 8) & 0xff; +} + +static inline void capimsg_setu32(void *m, int off, __u32 val) +{ + ((__u8 *)m)[off] = val & 0xff; + ((__u8 *)m)[off+1] = (val >> 8) & 0xff; + ((__u8 *)m)[off+2] = (val >> 16) & 0xff; + ((__u8 *)m)[off+3] = (val >> 24) & 0xff; +} -#define CAPIMSG_SETAPPID(m, applid) \ - do { \ - ((__u8 *)m)[2] = (__u16)(applid) & 0xff; \ - ((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \ - } while (0) - -#define CAPIMSG_SETLEN(m, len) \ - do { \ - ((__u8 *)m)[0] = (__u16)(len) & 0xff; \ - ((__u8 *)m)[1] = ((__u16)(len) >> 8) & 0xff; \ - } while (0) +#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len) +#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid) +#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd) +#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd) +#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid) +#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr) +#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len) /*----- basic-type definitions -----*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c --- v2.2.18/drivers/isdn/avmb1/kcapi.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/kcapi.c Sun Mar 25 11:37:32 2001 @@ -1,11 +1,62 @@ /* - * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $ + * $Id: kcapi.c,v 1.21.6.2 2001/02/13 11:43:29 kai Exp $ * * Kernel CAPI 2.0 Module * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kcapi.c,v $ + * Revision 1.21.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.21.6.1 2000/12/10 23:39:19 kai + * in 2.4 we don't have tq_scheduler anymore. + * also add one supported card to hfc_pci.c + * (from main branch) + * + * Revision 1.21 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.20 2000/11/19 17:01:53 kai + * compatibility cleanup - part 2 + * + * Revision 1.19 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.18 2000/07/20 10:22:27 calle + * - Made procfs function cleaner and removed variable "begin". + * + * Revision 1.17 2000/04/21 13:00:56 calle + * Bugfix: driver_proc_info was also wrong. + * + * Revision 1.16 2000/04/21 12:38:42 calle + * Bugfix: error in proc_ functions, begin-off => off-begin + * + * Revision 1.15 2000/04/06 15:01:25 calle + * Bugfix: crash in capidrv.c when reseting a capi controller. + * - changed code order on remove of controller. + * - using tq_schedule for notifier in kcapi.c. + * - now using spin_lock_irqsave() and spin_unlock_irqrestore(). + * strange: sometimes even MP hang on unload of isdn.o ... + * + * Revision 1.14 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * + * Revision 1.13 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.12 2000/01/28 16:45:39 calle * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), * will search named driver and call the add_card function if one exist. @@ -78,6 +129,8 @@ #include #include #include +#include +#include #include #include "capicmd.h" #include "capiutil.h" @@ -86,7 +139,7 @@ #include #endif -static char *revision = "$Revision: 1.12 $"; +static char *revision = "$Revision: 1.21.6.2 $"; /* ------------------------------------------------------------- */ @@ -125,8 +178,8 @@ __u16 applid; capi_register_params rparam; int releasing; - __u32 param; - void (*signal) (__u16 applid, __u32 param); + void *param; + void (*signal) (__u16 applid, void *param); struct sk_buff_head recv_queue; int nncci; struct capi_ncci *nccilist; @@ -137,6 +190,14 @@ unsigned long nsentdatapkt; }; +struct capi_notifier { + struct capi_notifier *next; + unsigned int cmd; + __u32 controller; + __u16 applid; + __u32 ncci; +}; + /* ------------------------------------------------------------- */ static struct capi_version driver_version = {2, 0, 1, 1<<4}; @@ -160,9 +221,9 @@ static int ncards = 0; static struct sk_buff_head recv_queue; static struct capi_interface_user *capi_users = 0; +static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED; static struct capi_driver *drivers; -static long notify_up_set = 0; -static long notify_down_set = 0; +static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; static struct tq_struct tq_state_notify; static struct tq_struct tq_recv_notify; @@ -226,7 +287,6 @@ struct capi_appl *ap; int i; int len = 0; - off_t begin = 0; for (i=0; i < CAPI_MAXAPPL; i++) { ap = &applications[i]; @@ -238,20 +298,21 @@ ap->rparam.datablklen, ap->nncci, skb_queue_len(&ap->recv_queue)); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; + if (len <= off) { + off -= len; len = 0; + } else { + if (len-off > count) + goto endloop; } } endloop: - if (i >= CAPI_MAXAPPL) + *start = page+off; + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; } /* @@ -265,7 +326,6 @@ struct capi_ncci *np; int i; int len = 0; - off_t begin = 0; for (i=0; i < CAPI_MAXAPPL; i++) { ap = &applications[i]; @@ -276,21 +336,22 @@ np->ncci, np->winsize, np->nmsg); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; + if (len <= off) { + off -= len; len = 0; + } else { + if (len-off > count) + goto endloop; } } } endloop: - if (i >= CAPI_MAXAPPL) + *start = page+off; + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; } /* @@ -302,27 +363,29 @@ { struct capi_driver *driver; int len = 0; - off_t begin = 0; + spin_lock(&drivers_lock); for (driver = drivers; driver; driver = driver->next) { len += sprintf(page+len, "%-32s %d %s\n", driver->name, driver->ncontroller, driver->revision); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; + if (len <= off) { + off -= len; len = 0; + } else { + if (len-off > count) + goto endloop; } } endloop: - if (!driver) + spin_unlock(&drivers_lock); + *start = page+off; + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; } /* @@ -334,24 +397,26 @@ { struct capi_interface_user *cp; int len = 0; - off_t begin = 0; + spin_lock(&capi_users_lock); for (cp = capi_users; cp ; cp = cp->next) { len += sprintf(page+len, "%s\n", cp->name); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; + if (len <= off) { + off -= len; len = 0; + } else { + if (len-off > count) + goto endloop; } } endloop: - if (cp == 0) + spin_unlock(&capi_users_lock); + *start = page+off; + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; } /* @@ -364,7 +429,6 @@ struct capi_ctr *cp; int i; int len = 0; - off_t begin = 0; for (i=0; i < CAPI_MAXCONTR; i++) { cp = &cards[i]; @@ -375,20 +439,21 @@ cp->name, cp->driver->procinfo ? cp->driver->procinfo(cp) : "" ); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; + if (len <= off) { + off -= len; len = 0; + } else { + if (len-off > count) + goto endloop; } } endloop: - if (i >= CAPI_MAXCONTR) + *start = page+off; + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; } /* @@ -401,7 +466,6 @@ struct capi_appl *ap; int i; int len = 0; - off_t begin = 0; for (i=0; i < CAPI_MAXAPPL; i++) { ap = &applications[i]; @@ -412,20 +476,21 @@ ap->nrecvdatapkt, ap->nsentctlpkt, ap->nsentdatapkt); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; + if (len <= off) { + off -= len; len = 0; + } else { + if (len-off > count) + goto endloop; } } endloop: - if (i >= CAPI_MAXAPPL) + *start = page+off; + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; } /* @@ -438,7 +503,6 @@ struct capi_ctr *cp; int i; int len = 0; - off_t begin = 0; for (i=0; i < CAPI_MAXCONTR; i++) { cp = &cards[i]; @@ -449,20 +513,21 @@ cp->nrecvdatapkt, cp->nsentctlpkt, cp->nsentdatapkt); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; + if (len <= off) { + off -= len; len = 0; + } else { + if (len-off > count) + goto endloop; } } endloop: - if (i >= CAPI_MAXCONTR) + *start = page+off; + if (len < count) *eof = 1; - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + if (len>count) len = count; + if (len<0) len = 0; + return len; } static struct procfsentries { @@ -510,6 +575,167 @@ } } +/* -------- Notifier handling --------------------------------- */ + +static struct capi_notifier_list{ + struct capi_notifier *head; + struct capi_notifier *tail; +} notifier_list; + +static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED; + +static inline void notify_enqueue(struct capi_notifier *np) +{ + struct capi_notifier_list *q = ¬ifier_list; + unsigned long flags; + + spin_lock_irqsave(¬ifier_lock, flags); + if (q->tail) { + q->tail->next = np; + q->tail = np; + } else { + q->head = q->tail = np; + } + spin_unlock_irqrestore(¬ifier_lock, flags); +} + +static inline struct capi_notifier *notify_dequeue(void) +{ + struct capi_notifier_list *q = ¬ifier_list; + struct capi_notifier *np = 0; + unsigned long flags; + + spin_lock_irqsave(¬ifier_lock, flags); + if (q->head) { + np = q->head; + if ((q->head = np->next) == 0) + q->tail = 0; + np->next = 0; + } + spin_unlock_irqrestore(¬ifier_lock, flags); + return np; +} + +static int notify_push(unsigned int cmd, __u32 controller, + __u16 applid, __u32 ncci) +{ + struct capi_notifier *np; + + MOD_INC_USE_COUNT; + np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC); + if (!np) { + MOD_DEC_USE_COUNT; + return -1; + } + memset(np, 0, sizeof(struct capi_notifier)); + np->cmd = cmd; + np->controller = controller; + np->applid = applid; + np->ncci = ncci; + notify_enqueue(np); + /* + * The notifier will result in adding/deleteing + * of devices. Devices can only removed in + * user process, not in bh. + */ + queue_task(&tq_state_notify, &tq_scheduler); + return 0; +} + +/* -------- KCI_CONTRUP --------------------------------------- */ + +static void notify_up(__u32 contr) +{ + struct capi_interface_user *p; + + printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile); + } + spin_unlock(&capi_users_lock); +} + +/* -------- KCI_CONTRDOWN ------------------------------------- */ + +static void notify_down(__u32 contr) +{ + struct capi_interface_user *p; + printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr); + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_CONTRDOWN, contr, 0); + } + spin_unlock(&capi_users_lock); +} + +/* -------- KCI_NCCIUP ---------------------------------------- */ + +static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci) +{ + struct capi_interface_user *p; + struct capi_ncciinfo n; + n.applid = applid; + n.ncci = ncci; + /*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/ + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_NCCIUP, contr, &n); + } + spin_unlock(&capi_users_lock); +}; + +/* -------- KCI_NCCIDOWN -------------------------------------- */ + +static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci) +{ + struct capi_interface_user *p; + struct capi_ncciinfo n; + n.applid = applid; + n.ncci = ncci; + /*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/ + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_NCCIDOWN, contr, &n); + } + spin_unlock(&capi_users_lock); +}; + +/* ------------------------------------------------------------ */ + +static void inline notify_doit(struct capi_notifier *np) +{ + switch (np->cmd) { + case KCI_CONTRUP: + notify_up(np->controller); + break; + case KCI_CONTRDOWN: + notify_down(np->controller); + break; + case KCI_NCCIUP: + notify_ncciup(np->controller, np->applid, np->ncci); + break; + case KCI_NCCIDOWN: + notify_nccidown(np->controller, np->applid, np->ncci); + break; + } +} + +static void notify_handler(void *dummy) +{ + struct capi_notifier *np; + + while ((np = notify_dequeue()) != 0) { + notify_doit(np); + kfree(np); + MOD_DEC_USE_COUNT; + } +} + /* -------- NCCI Handling ------------------------------------- */ static inline void mq_init(struct capi_ncci * np) @@ -617,6 +843,7 @@ APPL(appl)->nncci++; printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci); + notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci); } static void controllercb_free_ncci(struct capi_ctr * card, @@ -634,6 +861,7 @@ kfree(np); APPL(appl)->nncci--; printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci); + notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci); return; } } @@ -734,42 +962,6 @@ kfree_skb(skb); } -/* -------- Notifier ------------------------------------------ */ - -static void notify_up(__u32 contr) -{ - struct capi_interface_user *p; - - printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); - for (p = capi_users; p; p = p->next) { - if (!p->callback) continue; - (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile); - } -} - -static void notify_down(__u32 contr) -{ - struct capi_interface_user *p; - printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr); - for (p = capi_users; p; p = p->next) { - if (!p->callback) continue; - (*p->callback) (KCI_CONTRDOWN, contr, 0); - } -} - -static void notify_handler(void *dummy) -{ - __u32 contr; - - for (contr=1; VALID_CARD(contr); contr++) - if (test_and_clear_bit(contr, ¬ify_up_set)) - notify_up(contr); - for (contr=1; VALID_CARD(contr); contr++) - if (test_and_clear_bit(contr, ¬ify_down_set)) - notify_down(contr); -} - - static void controllercb_ready(struct capi_ctr * card) { __u16 appl; @@ -782,11 +974,10 @@ card->driver->register_appl(card, appl, &APPL(appl)->rparam); } - set_bit(CARDNR(card), ¬ify_up_set); - queue_task(&tq_state_notify, &tq_scheduler); - printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", CARDNR(card), card->name); + + notify_push(KCI_CONTRUP, CARDNR(card), 0, 0); } static void controllercb_reseted(struct capi_ctr * card) @@ -812,6 +1003,7 @@ struct capi_ncci *np = *pp; *pp = np->next; printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci); + notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci); kfree(np); nextpp = pp; } else { @@ -819,9 +1011,10 @@ } } } - set_bit(CARDNR(card), ¬ify_down_set); - queue_task(&tq_state_notify, &tq_scheduler); + printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card)); + + notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0); } static void controllercb_suspend_output(struct capi_ctr *card) @@ -937,7 +1130,7 @@ if (len < off) return 0; *eof = 1; - *start = page - off; + *start = page + off; return ((count < len-off) ? count : len-off); } @@ -952,9 +1145,12 @@ { struct capi_driver **pp; + MOD_INC_USE_COUNT; + spin_lock(&drivers_lock); for (pp = &drivers; *pp; pp = &(*pp)->next) ; driver->next = 0; *pp = driver; + spin_unlock(&drivers_lock); printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name); sprintf(driver->procfn, "capi/drivers/%s", driver->name); driver->procent = create_proc_entry(driver->procfn, 0, 0); @@ -974,6 +1170,7 @@ void detach_capi_driver(struct capi_driver *driver) { struct capi_driver **pp; + spin_lock(&drivers_lock); for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ; if (*pp) { *pp = (*pp)->next; @@ -981,10 +1178,12 @@ } else { printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name); } + spin_unlock(&drivers_lock); if (driver->procent) { remove_proc_entry(driver->procfn, 0); driver->procent = 0; } + MOD_DEC_USE_COUNT; } /* ------------------------------------------------------------- */ @@ -1041,6 +1240,7 @@ if (!VALID_APPLID(applid) || APPL(applid)->releasing) return CAPI_ILLAPPNR; + APPL(applid)->releasing++; while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0) kfree_skb(skb); for (i = 0; i < CAPI_MAXCONTR; i++) { @@ -1049,6 +1249,7 @@ APPL(applid)->releasing++; cards[i].driver->release_appl(&cards[i], applid); } + APPL(applid)->releasing--; if (APPL(applid)->releasing <= 0) { APPL(applid)->signal = 0; APPL_MARK_FREE(applid); @@ -1128,8 +1329,8 @@ } static __u16 capi_set_signal(__u16 applid, - void (*signal) (__u16 applid, __u32 param), - __u32 param) + void (*signal) (__u16 applid, void *param), + void *param) { if (!VALID_APPLID(applid)) return CAPI_ILLAPPNR; @@ -1194,10 +1395,12 @@ static struct capi_driver *find_driver(char *name) { struct capi_driver *dp; + spin_lock(&drivers_lock); for (dp = drivers; dp; dp = dp->next) if (strcmp(dp->name, name) == 0) - return dp; - return 0; + break; + spin_unlock(&drivers_lock); + return dp; } #ifdef CONFIG_AVMB1_COMPAT @@ -1272,6 +1475,10 @@ card = CARD(ldef.contr); if (card->cardstate == CARD_FREE) return -ESRCH; + if (card->driver->load_firmware == 0) { + printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name); + return -ESRCH; + } if (ldef.t4file.len <= 0) { printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); @@ -1304,7 +1511,7 @@ while (card->cardstate != CARD_RUNNING) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); /* 0.1 sec */ if (signal_pending(current)) @@ -1329,7 +1536,7 @@ while (card->cardstate > CARD_DETECTED) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); /* 0.1 sec */ if (signal_pending(current)) @@ -1380,7 +1587,7 @@ while (card->cardstate != CARD_FREE) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); /* 0.1 sec */ if (signal_pending(current)) @@ -1490,16 +1697,20 @@ { struct capi_interface_user *p; + MOD_INC_USE_COUNT; + spin_lock(&capi_users_lock); for (p = capi_users; p; p = p->next) { if (p == userp) { + spin_unlock(&capi_users_lock); printk(KERN_ERR "kcapi: double attach from %s\n", userp->name); + MOD_DEC_USE_COUNT; return 0; } } userp->next = capi_users; capi_users = userp; - MOD_INC_USE_COUNT; + spin_unlock(&capi_users_lock); printk(KERN_NOTICE "kcapi: %s attached\n", userp->name); return &avmb1_interface; @@ -1509,15 +1720,18 @@ { struct capi_interface_user **pp; + spin_lock(&capi_users_lock); for (pp = &capi_users; *pp; pp = &(*pp)->next) { if (*pp == userp) { *pp = userp->next; + spin_unlock(&capi_users_lock); userp->next = 0; - MOD_DEC_USE_COUNT; printk(KERN_NOTICE "kcapi: %s detached\n", userp->name); + MOD_DEC_USE_COUNT; return 0; } } + spin_unlock(&capi_users_lock); printk(KERN_ERR "kcapi: double detach from %s\n", userp->name); return -1; } @@ -1531,42 +1745,18 @@ EXPORT_SYMBOL(attach_capi_driver); EXPORT_SYMBOL(detach_capi_driver); -#ifndef MODULE -#ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA -extern int b1isa_init(void); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI -extern int b1pci_init(void); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA -extern int t1isa_init(void); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA -extern int b1pcmcia_init(void); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI -extern int t1pci_init(void); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_C4 -extern int c4_init(void); -#endif -#endif - /* * init / exit functions */ -#ifdef MODULE -#define kcapi_init init_module -#endif - -int kcapi_init(void) +static int __init kcapi_init(void) { char *p; char rev[10]; + MOD_INC_USE_COUNT; + skb_queue_head_init(&recv_queue); - /* init_bh(CAPI_BH, do_capi_bh); */ tq_state_notify.routine = notify_handler; tq_state_notify.data = 0; @@ -1587,30 +1777,12 @@ printk(KERN_NOTICE "CAPI-driver Rev%s: loaded\n", rev); #else printk(KERN_NOTICE "CAPI-driver Rev%s: started\n", rev); -#ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA - (void)b1isa_init(); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI - (void)b1pci_init(); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA - (void)t1isa_init(); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA - (void)b1pcmcia_init(); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI - (void)t1pci_init(); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1_C4 - (void)c4_init(); -#endif #endif + MOD_DEC_USE_COUNT; return 0; } -#ifdef MODULE -void cleanup_module(void) +static void kcapi_exit(void) { char rev[10]; char *p; @@ -1623,8 +1795,9 @@ strcpy(rev, "1.0"); } - schedule(); /* execute queued tasks .... */ proc_capi_exit(); printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev); } -#endif + +module_init(kcapi_init); +module_exit(kcapi_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.2.18/drivers/isdn/avmb1/t1isa.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/avmb1/t1isa.c Sun Mar 25 11:37:32 2001 @@ -1,11 +1,36 @@ /* - * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 calle Exp $ + * $Id: t1isa.c,v 1.16.6.1 2001/02/13 11:43:29 kai Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.16.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.16 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.15 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.14 2000/10/10 17:44:19 kai + * changes from/for 2.2.18 + * + * Revision 1.13 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.12 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * + * Revision 1.11 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.10 2000/02/02 18:36:04 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -75,13 +100,14 @@ #include #include #include +#include #include #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.16.6.1 $"; /* ------------------------------------------------------------- */ @@ -190,7 +216,7 @@ struct sk_buff *skb; unsigned ApplId; - signed MsgLen; + unsigned MsgLen; unsigned DataB3Len; unsigned NCCI; unsigned WindowSize; @@ -278,25 +304,30 @@ case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; + case 0xff: printk(KERN_ERR "%s: card reseted ?\n", card->name); return; @@ -573,31 +604,29 @@ /* ------------------------------------------------------------- */ static struct capi_driver t1isa_driver = { - "t1isa", - "0.0", - t1isa_load_firmware, - t1isa_reset_ctr, - t1isa_remove_ctr, - b1_register_appl, - b1_release_appl, - t1isa_send_message, - - t1isa_procinfo, - b1ctl_read_proc, - 0, /* use standard driver_read_proc */ + name: "t1isa", + revision: "0.0", + load_firmware: t1isa_load_firmware, + reset_ctr: t1isa_reset_ctr, + remove_ctr: t1isa_remove_ctr, + register_appl: b1_register_appl, + release_appl: b1_release_appl, + send_message: t1isa_send_message, + + procinfo: t1isa_procinfo, + ctr_read_proc: b1ctl_read_proc, + driver_read_proc: 0, /* use standard driver_read_proc */ - t1isa_add_card, + add_card: t1isa_add_card, }; -#ifdef MODULE -#define t1isa_init init_module -void cleanup_module(void); -#endif - -int t1isa_init(void) +static int __init t1isa_init(void) { struct capi_driver *driver = &t1isa_driver; char *p; + int retval = 0; + + MOD_INC_USE_COUNT; if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); @@ -612,14 +641,17 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); - return -EIO; + retval = -EIO; } - return 0; + + MOD_DEC_USE_COUNT; + return retval; } -#ifdef MODULE -void cleanup_module(void) +static void t1isa_exit(void) { detach_capi_driver(&t1isa_driver); } -#endif + +module_init(t1isa_init); +module_exit(t1isa_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c --- v2.2.18/drivers/isdn/avmb1/t1pci.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/avmb1/t1pci.c Sun Mar 25 11:37:32 2001 @@ -1,11 +1,54 @@ /* - * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $ + * $Id: t1pci.c,v 1.13.6.2 2001/02/13 11:43:29 kai Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.13.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.13.6.1 2000/11/28 12:02:45 kai + * MODULE_DEVICE_TABLE for 2.4 + * + * Revision 1.13.2.2 2000/11/26 17:47:53 kai + * added PCI_DEV_TABLE for 2.4 + * + * Revision 1.13.2.1 2000/11/26 17:14:19 kai + * fix device ids + * also needs patches to include/linux/pci_ids.h + * + * Revision 1.13 2000/11/23 20:45:14 kai + * fixed module_init/exit stuff + * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. + * + * Revision 1.12 2000/11/01 14:05:02 calle + * - use module_init/module_exit from linux/init.h. + * - all static struct variables are initialized with "membername:" now. + * - avm_cs.c, let it work with newer pcmcia-cs. + * + * Revision 1.11 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * + * Revision 1.10 2000/07/20 10:21:21 calle + * Bugfix: driver will not be unregistered, if not cards were detected. + * this result in an oops in kcapi.c + * + * Revision 1.9 2000/05/19 15:43:22 calle + * added calls to pci_device_start(). + * + * Revision 1.8 2000/05/06 00:52:36 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * + * Revision 1.7 2000/04/07 15:26:55 calle + * better error message if cabel not connected or T1 has no power. + * + * Revision 1.6 2000/04/03 13:29:25 calle + * make Tim Waugh happy (module unload races in 2.3.99-pre3). + * no real problem there, but now it is much cleaner ... + * * Revision 1.5 2000/02/02 18:36:04 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -40,30 +83,22 @@ #include #include #include +#include #include +#include #include #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.13.6.2 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG /* ------------------------------------------------------------- */ -#ifndef PCI_VENDOR_ID_AVM -#define PCI_VENDOR_ID_AVM 0x1244 -#endif - -#ifndef PCI_DEVICE_ID_AVM_T1 -#define PCI_DEVICE_ID_AVM_T1 0x1200 -#endif - -/* ------------------------------------------------------------- */ - MODULE_AUTHOR("Carsten Paeth "); /* ------------------------------------------------------------- */ @@ -164,7 +199,11 @@ b1dma_reset(card); if ((retval = t1pci_detect(card)) != 0) { - printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", + if (retval < 6) + printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", + driver->name, card->port, retval); + else + printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n", driver->name, card->port, retval); iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); kfree(card->ctrlinfo); @@ -234,36 +273,33 @@ /* ------------------------------------------------------------- */ static struct capi_driver t1pci_driver = { - "t1pci", - "0.0", - b1dma_load_firmware, - b1dma_reset_ctr, - t1pci_remove_ctr, - b1dma_register_appl, - b1dma_release_appl, - b1dma_send_message, - - t1pci_procinfo, - b1dmactl_read_proc, - 0, /* use standard driver_read_proc */ + name: "t1pci", + revision: "0.0", + load_firmware: b1dma_load_firmware, + reset_ctr: b1dma_reset_ctr, + remove_ctr: t1pci_remove_ctr, + register_appl: b1dma_register_appl, + release_appl: b1dma_release_appl, + send_message: b1dma_send_message, + + procinfo: t1pci_procinfo, + ctr_read_proc: b1dmactl_read_proc, + driver_read_proc: 0, /* use standard driver_read_proc */ - 0, /* no add_card function */ + add_card: 0, /* no add_card function */ }; -#ifdef MODULE -#define t1pci_init init_module -void cleanup_module(void); -#endif - static int ncards = 0; -int t1pci_init(void) +static int __init t1pci_init(void) { struct capi_driver *driver = &t1pci_driver; struct pci_dev *dev = NULL; char *p; int retval; + MOD_INC_USE_COUNT; + if ((p = strchr(revision, ':'))) { strncpy(driver->revision, p + 1, sizeof(driver->revision)); p = strchr(driver->revision, '$'); @@ -277,6 +313,7 @@ if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; } @@ -284,6 +321,7 @@ if (!pci_present()) { printk(KERN_ERR "%s: no PCI bus present\n", driver->name); detach_capi_driver(driver); + MOD_DEC_USE_COUNT; return -EIO; } @@ -291,9 +329,10 @@ struct capicardparams param; param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; - param.irq = dev->irq; + param.irq = dev->irq; param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK; + printk(KERN_INFO "%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n", driver->name, param.port, param.irq, param.membase); @@ -302,9 +341,8 @@ printk(KERN_ERR "%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n", driver->name, param.port, param.irq, param.membase); -#ifdef MODULE - cleanup_module(); -#endif + detach_capi_driver(&t1pci_driver); + MOD_DEC_USE_COUNT; return retval; } ncards++; @@ -312,19 +350,24 @@ if (ncards) { printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n", driver->name, ncards); + MOD_DEC_USE_COUNT; return 0; } printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name); + detach_capi_driver(&t1pci_driver); + MOD_DEC_USE_COUNT; return -ESRCH; #else printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + MOD_DEC_USE_COUNT; return -EIO; #endif } -#ifdef MODULE -void cleanup_module(void) +static void t1pci_exit(void) { detach_capi_driver(&t1pci_driver); } -#endif + +module_init(t1pci_init); +module_exit(t1pci_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/divert/Makefile linux/drivers/isdn/divert/Makefile --- v2.2.18/drivers/isdn/divert/Makefile Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/divert/Makefile Sun Mar 25 11:37:32 2001 @@ -1,18 +1,26 @@ -L_OBJS := -LX_OBJS := -M_OBJS := -MX_OBJS := -O_OBJS := -OX_OBJS := -L_TARGET := -O_TARGET := - -O_OBJS += isdn_divert.o divert_procfs.o -O_TARGET := dss1_divert.o -M_OBJS += dss1_divert.o -OX_OBJS += divert_init.o +# +# Makefile for the dss1_divert ISDN module +# -include $(TOPDIR)/Rules.make +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Multipart objects. + +list-multi := dss1_divert.o +dss1_divert-objs := isdn_divert.o divert_procfs.o divert_init.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +dss1_divert.o: $(dss1_divert-objs) + $(LD) -r -o $@ $(dss1_divert-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/divert/divert_init.c linux/drivers/isdn/divert/divert_init.c --- v2.2.18/drivers/isdn/divert/divert_init.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/divert/divert_init.c Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ /* - * $Id: divert_init.c,v 1.5 2000/11/13 22:51:47 kai Exp $ + * $Id: divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $ * * Module init for DSS1 diversion services for i4l. * @@ -23,6 +23,7 @@ #include #include +#include #include "isdn_divert.h" /********************/ @@ -46,7 +47,7 @@ /* Module interface code */ /* no cmd line parms */ /*************************/ -int init_module(void) +static int __init divert_init(void) { int i; if (divert_dev_init()) @@ -63,12 +64,12 @@ #endif printk(KERN_INFO "dss1_divert module successfully installed\n"); return(0); -} /* init_module */ +} /**********************/ /* Module deinit code */ /**********************/ -void cleanup_module(void) +static void divert_exit(void) { int flags; int i; @@ -89,6 +90,8 @@ deleterule(-1); /* delete all rules and free mem */ deleteprocs(); printk(KERN_INFO "dss1_divert module successfully removed \n"); -} /* cleanup_module */ +} +module_init(divert_init); +module_exit(divert_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c --- v2.2.18/drivers/isdn/divert/divert_procfs.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/divert/divert_procfs.c Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ /* - * $Id: divert_procfs.c,v 1.10 2000/11/13 22:51:47 kai Exp $ + * $Id: divert_procfs.c,v 1.11 2000/11/25 17:01:00 kai Exp $ * * Filesystem handling for the diversion supplementary services. * @@ -32,6 +32,7 @@ #include #endif #include +#include #include "isdn_divert.h" /*********************************/ @@ -40,7 +41,7 @@ ulong if_used = 0; /* number of interface users */ static struct divert_info *divert_info_head = NULL; /* head of queue */ static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */ -static struct wait_queue *rd_queue = 0; /* Queue IO */ +static wait_queue_head_t rd_queue; /*********************************/ /* put an info buffer into queue */ @@ -281,19 +282,14 @@ static struct file_operations isdn_fops = { - isdn_divert_lseek, - isdn_divert_read, - isdn_divert_write, - NULL, /* isdn_readdir */ - isdn_divert_poll, /* isdn_poll */ - isdn_divert_ioctl, /* isdn_ioctl */ - NULL, /* isdn_mmap */ - isdn_divert_open, - NULL, /* flush */ - isdn_divert_close, - NULL /* fsync */ + llseek: isdn_divert_lseek, + read: isdn_divert_read, + write: isdn_divert_write, + poll: isdn_divert_poll, + ioctl: isdn_divert_ioctl, + open: isdn_divert_open, + release: isdn_divert_close, }; - struct inode_operations divert_file_inode_operations; /****************************/ @@ -310,6 +306,7 @@ divert_dev_init(void) { + init_waitqueue_head(&rd_queue); #ifdef CONFIG_PROC_FS isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/divert/isdn_divert.c linux/drivers/isdn/divert/isdn_divert.c --- v2.2.18/drivers/isdn/divert/isdn_divert.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/divert/isdn_divert.c Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ /* - * $Id: isdn_divert.c,v 1.5 1999/08/31 11:20:04 paul Exp $ + * $Id: isdn_divert.c,v 1.6.6.1 2001/02/07 11:31:31 kai Exp $ * * DSS1 main diversion supplementary handling for i4l. * @@ -19,25 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_divert.c,v $ - * Revision 1.5 1999/08/31 11:20:04 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.4 1999/08/25 20:02:21 werner - * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts - * with existing software definitions. (PtP incomplete called party number) - * - * Revision 1.3 1999/08/22 20:26:35 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.2 1999/07/04 21:37:32 werner - * Ported from kernel version 2.0 - * - * - * */ @@ -206,7 +187,7 @@ restore_flags(flags); *procid = cs->ics.parm.dss1_io.ll_id; - sprintf(cs->info,"%d 0x%lx %s%s 0 %s %0x %d%s%s\n", + sprintf(cs->info,"%d 0x%lx %s%s 0 %s %02x %d%s%s\n", (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT, cs->ics.parm.dss1_io.ll_id, (mode != 2) ? "" : "0 ", diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/divert/isdn_divert.h linux/drivers/isdn/divert/isdn_divert.h --- v2.2.18/drivers/isdn/divert/isdn_divert.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/divert/isdn_divert.h Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ /* - * $Id: isdn_divert.h,v 1.4 1999/09/02 13:24:12 paul Exp $ + * $Id: isdn_divert.h,v 1.5 2000/11/13 22:51:47 kai Exp $ * * Header for the diversion supplementary ioctl interface. * @@ -18,19 +18,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Log: isdn_divert.h,v $ - * Revision 1.4 1999/09/02 13:24:12 paul - * cosmetics; text following #endif is not ANSI C - * - * Revision 1.3 1999/08/22 20:26:37 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.2 1999/07/04 21:37:33 werner - * Ported from kernel version 2.0 * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/Divas_mod.c linux/drivers/isdn/eicon/Divas_mod.c --- v2.2.18/drivers/isdn/eicon/Divas_mod.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/Divas_mod.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,151 @@ + +/* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include +#undef N_DATA + +#include + +#include +#include +#include +#include +#include + +#include "adapter.h" +#include "uxio.h" + +#include + +#ifdef MODULE +#include "idi.h" +void DIVA_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#endif + +int DivasCardsDiscover(void); + +static int __init +divas_init(void) +{ + printk(KERN_DEBUG "DIVA Server Driver - initialising\n"); + + printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.16\n"); + + +#if !defined(CONFIG_PCI) + printk(KERN_WARNING "CONFIG_PCI is not defined!\n"); + return -ENODEV; +#endif + + if (pci_present()) + { + if (DivasCardsDiscover() < 0) + { + printk(KERN_WARNING "Divas: Not loaded\n"); + return -ENODEV; + } + } + else + { + printk(KERN_WARNING "Divas: No PCI bus present\n"); + return -ENODEV; + } + + return 0; +} + +static void +divas_exit(void) +{ + card_t *pCard; + word wCardIndex; + extern int Divas_major; + + printk(KERN_DEBUG "DIVA Server Driver - unloading\n"); + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + pCard++; + } + + unregister_chrdev(Divas_major, "Divas"); +} + +module_init(divas_init); +module_exit(divas_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/Makefile linux/drivers/isdn/eicon/Makefile --- v2.2.18/drivers/isdn/eicon/Makefile Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/Makefile Sun Mar 25 11:37:32 2001 @@ -1,13 +1,42 @@ -L_OBJS := -M_OBJS := -O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o - -O_TARGET := -ifeq ($(CONFIG_ISDN_DRV_EICON),y) - O_TARGET += eicon.o -else - O_TARGET += eicon.o - M_OBJS = eicon.o -endif +# Makefile for the eicon ISDN device driver + +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Objects that export symbols. + +export-objs := Divas_mod.o eicon_mod.o + +# Multipart objects. + +list-multi := eicon.o divas.o +eicon-objs := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \ + eicon_io.o +divas-objs := common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \ + fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o + +# Optional parts of multipart objects. + +eicon-objs-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \ + xlog.o kprintf.o fpga.o fourbri.o lincfg.o linchr.o \ + linsys.o linio.o + +eicon-objs += $(eicon-objs-y) + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_EICON_OLD) += eicon.o +obj-$(CONFIG_ISDN_DRV_EICON_DIVAS) += divas.o + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +eicon.o: $(eicon-objs) + $(LD) -r -o $@ $(eicon-objs) + +divas.o: $(divas-objs) + $(LD) -r -o $@ $(divas-objs) + -include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/adapter.h linux/drivers/isdn/eicon/adapter.h --- v2.2.18/drivers/isdn/eicon/adapter.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/adapter.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,262 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.7 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Main internal include file for Diva Server driver */ + +#if !defined(ADAPTER_H) +#define ADAPTER_H + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" + +#define XMOREC 0x1f +#define XMOREF 0x20 +#define XBUSY 0x40 +#define RMORE 0x80 + + /* structure for all information we have to keep on a per */ + /* adapater basis */ + +typedef struct adapter_s ADAPTER; + +struct adapter_s { + void * io; + + byte IdTable[256]; + byte ReadyInt; + + byte (* ram_in)(ADAPTER * a, void * adr); + word (* ram_inw)(ADAPTER * a, void * adr); + void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length); + void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e); + + void (* ram_out)(ADAPTER * a, void * adr, byte data); + void (* ram_outw)(ADAPTER * a, void * adr, word data); + void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length); + + void (* ram_inc)(ADAPTER * a, void * adr); +}; + +typedef struct card card_t; + +typedef int card_load_fn_t(card_t *card, dia_load_t *load); +typedef int card_config_fn_t(card_t *card, dia_config_t *config); +typedef int card_start_fn_t(card_t *card, byte *channels); +typedef int card_reset_fn_t(card_t *card); +typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block); + +#define MAX_PENTITIES 256 /* Number of entities primary adapter */ +#define MAX_ENTITIES 16 /* Number of entities standard adapter */ + +typedef struct e_info_s E_INFO; + +struct e_info_s +{ + ENTITY *e; /* entity pointer */ + byte next; /* chaining index */ + word assign_ref; /* assign reference */ +}; + +/* DIVA card info (details hidden from user) */ + +typedef struct ux_diva_card_s ux_diva_card_t; + +/* card info */ + +struct card +{ + ADAPTER a; /* per-adapter information */ + dia_card_t cfg; /* card configuration */ + int state; /* State of the adapter */ + dword serial_no; /* serial number */ + int test_int_pend; /* set for interrupt testing */ + ux_diva_card_t *hw; /* O/S-specific handle */ + card_reset_fn_t *card_reset; /* call this to reset card */ + card_load_fn_t *card_load; /* call this to load card */ + card_config_fn_t *card_config; /* call this to config card */ + card_start_fn_t *card_start; /* call this to start card */ + card_mem_get_fn_t *card_mem_get; /* call this to get card memory */ + E_INFO *e_tbl; /* table of ENTITY pointers */ + byte e_head; /* list of active ENTITIES */ + byte e_tail; /* list of active ENTITIES */ + int e_count; /* # of active ENTITIES */ + int e_max; /* total # of ENTITIES */ + byte assign; /* assign queue entry */ + PBUFFER RBuffer; /* Copy of receive lookahead buffer */ + int log_types; /* bit-mask of active logs */ + word xlog_offset; /* offset to XLOG buffer on card */ + void (*out)(ADAPTER *a); + byte (*dpc)(ADAPTER * a); + byte (*test_int)(ADAPTER * a); + void (*clear_int)(ADAPTER * a); + void (*reset_int)(card_t *c); + int is_live; + + int (*card_isr)(card_t *card); + + int int_pend; /* interrupt pending */ + long interrupt_reentered; + long dpc_reentered; + int set_xlog_request; + +} ; + +/* card information */ + +#define MAX_CARDS 20 /* max number of cards on a system */ + +extern +card_t DivasCards[]; + +extern +int DivasCardNext; + +extern +dia_config_t DivasCardConfigs[]; + +extern +byte DivasFlavourConfig[]; + +/*------------------------------------------------------------------*/ +/* public functions of IDI common code */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a); +byte DivasDpc(ADAPTER * a); +byte DivasTestInt(ADAPTER * a); +void DivasClearInt(ADAPTER * a); + +/*------------------------------------------------------------------*/ +/* public functions of configuration platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasConfigGet(dia_card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of LOG related code */ +/*------------------------------------------------------------------*/ + +void DivasXlogReq(int card_num); +int DivasXlogRetrieve(card_t *card); +void DivasLog(dia_log_t *log); +void DivasLogIdi(card_t *card, ENTITY *e, int request); + +/*------------------------------------------------------------------*/ +/* public functions to initialise cards for each type supported */ +/*------------------------------------------------------------------*/ + +int DivasPriInit(card_t *card, dia_card_t *cfg); + +int DivasBriInit(card_t *card, dia_card_t *cfg); +int Divas4BriInit(card_t *card, dia_card_t *cfg); +void DivasBriPatch(card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of log common code */ +/*------------------------------------------------------------------*/ + +extern char *DivasLogFifoRead(void); +extern void DivasLogFifoWrite(char *entry, int length); +extern int DivasLogFifoEmpty(void); +extern int DivasLogFifoFull(void); +extern void DivasLogAdd(void *buffer, int length); + +/*------------------------------------------------------------------*/ +/* public functions of misc. platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasDpcSchedule(void); +void DivasDoDpc(void *); +void DivasDoRequestDpc(void *pData); +int DivasScheduleRequestDpc(void); + +/* table of IDI request functions */ + +extern +IDI_CALL DivasIdiRequest[]; + +/* + * intialisation entry point + */ + +int DivasInit(void); + +/* + * Get information on the number and type of cards present + */ + +extern +int DivasCardsDiscover(void); + +/* + * initialise a new card + */ + +int DivasCardNew(dia_card_t *card); + +/* + * configure specified card + */ + +int DivasCardConfig(dia_config_t *config); + +/* + * load specified binary code onto card + */ + +int DivasCardLoad(dia_load_t *load); + +/* + * start specified card running + */ + +int DivasCardStart(int card_id); + +/* + * ISR for card + * Returns 0 if specified card was interrupting + */ + +int DivasIsr(void *arg); + +/* + * Get number of active cards + */ + +int DivasGetNum(void); + +/* + * Get list of active cards + */ + +int DivasGetList(dia_card_list_t *card_list); + +/* definitions common to several card types */ + +#define DIVAS_SHARED_OFFSET (0x1000) + +#endif /* ADAPTER_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/bri.c linux/drivers/isdn/eicon/bri.c --- v2.2.18/drivers/isdn/eicon/bri.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/bri.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,714 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.8 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_BADDR0 0x10 +#define PCI_BADDR1 0x14 +#define PCI_BADDR2 0x18 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for BRI card */ + +#define PROTCAP_TELINDUS 0x1 +#define PROTCAP_V90D 0x8 + +word GetProtFeatureValue(char *sw_id); +byte io_in(ADAPTER *a, void *adr); +word io_inw(ADAPTER *a, void *adr); +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void io_out(ADAPTER *a, void *adr, byte data); +void io_outw(ADAPTER *a, void *adr, word data); +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_inc(ADAPTER *a, void *adr); + +static int diva_server_bri_test_int(card_t *card); +static int bri_ISR (card_t* card); + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +#define REG_DATA 0x00 +#define REG_ADDRLO 0x04 +#define REG_ADDRHI 0x0C +#define REG_IOCTRL 0x10 + +#define M_PCI_RESET 0x10 + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg); + +static +int diva_server_bri_reset(card_t *card) +{ + byte *DivasIOBase; + word i; + dword dwWait; + + UxCardLog(0); + + DPRINTF(("divas: resetting BRI adapter")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0); + + for (i=0; i < 50000; i++) + ; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000); + + for (i=0; i<0x8000; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + } + + for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++) + ; + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +void diva_server_bri_reset_int(card_t *card) +{ + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +int diva_server_bri_start(card_t *card, byte *channels) +{ + byte *DivasIOBase, *PLXIOBase; + word wSig = 0; + word i; + dword dwSerialNum; + byte bPLX9060 = FALSE; + + DPRINTF(("divas: starting Diva Server BRI card")); + + card->is_live = FALSE; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + /* wait for signature to indicate card has started */ + for (i = 0; i < 300; i++) + { + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + if (wSig == DIVAS_SIGNATURE) + { + DPRINTF(("divas: card started after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if (wSig != DIVAS_SIGNATURE) + { + DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig)); + UxCardMemDetach(card->hw, DivasIOBase); + return -1; + } + + card->is_live = TRUE; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6); + *channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + UxCardMemDetach(card->hw, DivasIOBase); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x22)); + DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum)); + } + else + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x26)); + DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum)); + } + + UxCardMemDetach(card->hw, PLXIOBase); + + card->serial_no = dwSerialNum; + + diva_server_bri_test_int(card); + + return 0; +} + +static +int diva_server_bri_load(card_t *card, dia_load_t *load) +{ + byte *DivasIOBase; + dword r3000_base; + dword dwAddr, dwLength, i; + word wTest, aWord; + + DPRINTF(("divas: loading Diva Server BRI card")); + + switch (load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: loading RISC %s", &load->code[0x80])); + + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + DPRINTF(("divas: features 0x%x", card->hw->features)); + if (card->hw->features == 0xFFFF) + { + DPRINTF(("divas: invalid feature string failed load\n")); + return -1; + } + + r3000_base = 0; + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code \"%s\"", load->code)); + + if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS))) + { + DPRINTF(("divas: only Telindus style binaries supported")); + return -1; + } + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: V.90 DSP binary")); + r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + else + { + DPRINTF(("divas: non-V.90 DSP binary")); + r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + DPRINTF(("divas: loading at 0x%x", r3000_base)); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000 + sizeof(dword); + } + else + { + r3000_base = 0xBF7A0000 + sizeof(dword); + } + + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000; + } + else + { + r3000_base = 0xBF7A0000; + } + break; + + default: + DPRINTF(("divas: unknown code type %d", load->code_type)); + return -1; + break; + } + + DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + DPRINTF(("divas: Attached to 0x%04X", DivasIOBase)); + + dwLength = load->length; + + for (i=0; i < dwLength; i++) + { + dwAddr = r3000_base + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]); + } + + DPRINTF(("divas: Verifying")); + + for (i=0; ihw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + + aWord = load->code[i]; + + if (wTest != aWord) + { + DPRINTF(("divas: load verify failed on byte %d", i)); + DPRINTF(("divas: RAM 0x%x File 0x%x",wTest,aWord)); + + UxCardMemDetach(card->hw, DivasIOBase); + + return -1; + } + } + + DPRINTF(("divas: Loaded and verified. Detaching from adapter")); + + UxCardMemDetach(card->hw, DivasIOBase); + + UxCardLog(0); + + return 0; +} + +static +int diva_server_bri_config(card_t *card, dia_config_t *config) +{ + byte *DivasIOBase, i; + + DPRINTF(("divas: configuring Diva Server BRI card")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->sig_flags); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4); + } + else + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + } + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21); + + for (i=0; i<32; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]); + + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +void DivasBriPatch(card_t *card) +{ + dword PLXIOBase = 0; + dword DivasIOBase = 0; + + PLXIOBase = card->cfg.reset_base; + DivasIOBase = card->cfg.io_base; + + if(card->hw == NULL) + { + DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null")); + return; + } + + if (PLXIOBase == 0) + { + DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may")); + DPRINTF(("Divas: not function properly. If you do encounter problems,")); + DPRINTF(("Divas: ensure that your machine is using the latest BIOS.")); + return; + } + + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + + if (PLXIOBase & 0x80) + { + dword dwSize, dwSerialNum, dwCmd; + boolean_t bPLX9060; + word wSerHi, wSerLo; + + DPRINTF(("Divas: Patch required")); + dwCmd = 0; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + PLXIOBase &= ~0x80; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase); + + dwSize = 0xFFFFFFFF; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize); + UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize); + + dwSize = (~ (dwSize & ~7)) + 1; + + DivasIOBase = PLXIOBase + dwSize; + + card->cfg.reset_base = PLXIOBase; + card->cfg.io_base = DivasIOBase; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base); + UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base); + + dwCmd = 5; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + } + else + { + word wSerHi, wSerLo; + boolean_t bPLX9060; + dword dwSerialNum; + + DPRINTF(("divas: No patch required")); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + } + DPRINTF(("Divas: After patching:")); + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + +} + +#define TEST_INT_DIVAS_BRI 0x12 +static +int diva_server_bri_test_int(card_t *card) +{ + boolean_t bPLX9060 = FALSE; + byte *PLXIOBase = NULL, *DivasIOBase = NULL; + + DPRINTF(("divas: test interrupt for Diva Server BRI card")); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { /* PLX9060 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09); + } + else + { /* PLX9050 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41); + } + + card->test_int_pend = TEST_INT_DIVAS_BRI; + + UxCardMemDetach(card->hw, PLXIOBase); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89); + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block) +{ + dword user_addr = mem_block->addr; + word length = 0; + dword addr; + word i; + byte *DivasIOBase; + + DPRINTF(("divas: Retrieving memory from 0x%x", user_addr)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + addr = user_addr; + + for (i=0; i < (16 * 8); i++) + { + addr = user_addr + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr); + + mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + length++; + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return length; +} + +int DivasBriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server BRI card")); + + if (DivasBRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_bri_reset; + card->card_start = diva_server_bri_start; + card->card_load = diva_server_bri_load; + card->card_config = diva_server_bri_config; + card->reset_int = diva_server_bri_reset_int; + card->card_mem_get = diva_server_bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = bri_ISR; + + card->a.ram_out = io_out; + card->a.ram_outw = io_outw; + card->a.ram_out_buffer = io_out_buffer; + card->a.ram_inc = io_inc; + + card->a.ram_in = io_in; + card->a.ram_inw = io_inw; + card->a.ram_in_buffer = io_in_buffer; + card->a.ram_look_ahead = io_look_ahead; + + return 0; +} + +word GetProtFeatureValue(char *sw_id) +{ + word features = 0; + + while ((*sw_id) && (sw_id[0] != '[')) + sw_id++; + + if (sw_id == NULL) + { + DPRINTF(("divas: no feature string present")); + features = -1; + } + else + { + byte i, shifter; + + sw_id += 3; + + for (i=0, shifter=12; i<4; i++, shifter-=4) + { + if ((sw_id[i] >= '0') && (sw_id[i] <= '9')) + { + features |= (sw_id[i] - '0') << shifter; + } + else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f')) + { + features |= (sw_id[i] - 'a' + 10) << shifter; + } + else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F')) + { + features |= (sw_id[i] - 'A' + 10) << shifter; + } + else + { + DPRINTF(("divas: invalid feature string")); + return -1; + } + } + } + + return features; +} + + +int bri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c --- v2.2.18/drivers/isdn/eicon/common.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/common.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,896 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.15 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" + +#include "uxio.h" +#include + +#define MAX_ADDR_LEN + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_INTERRUPT 0x3C + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_SIGNATURE 0x4447 + +#define MP_PROTOCOL_ADDR 0xA0011000 + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +int DivasCardNext; +card_t DivasCards[MAX_CARDS]; + +dia_config_t *DivasConfig(card_t *, dia_config_t *); + +static +DESCRIPTOR DIDD_Table[32]; + +void DIVA_DIDD_Read( DESCRIPTOR *table, int tablelength ) +{ + bzero(table, tablelength); + + if (tablelength > sizeof(DIDD_Table)) + tablelength = sizeof(DIDD_Table); + + if(tablelength % sizeof(DESCRIPTOR)) { + tablelength /= sizeof(DESCRIPTOR); + tablelength *= sizeof(DESCRIPTOR); + } + + if (tablelength > 0) + bcopy((caddr_t)DIDD_Table, (caddr_t)table, tablelength); + + return; +} + +void DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength) +{ + if (tablelength > sizeof(DIDD_Table)) + tablelength = sizeof(DIDD_Table); + + bcopy((caddr_t)table, (caddr_t)DIDD_Table, tablelength); + + return; +} + +static +void init_idi_tab(void) +{ + DESCRIPTOR d[32]; + + bzero(d, sizeof(d)); + + d[0].type = IDI_DIMAINT; /* identify the DIMAINT entry */ + d[0].channels = 0; /* zero channels associated with dimaint*/ + d[0].features = 0; /* no features associated with dimaint */ + d[0].request = (IDI_CALL) DivasPrintf; + + DIVA_DIDD_Write(d, sizeof(d)); + + return; +} + +/* + * I/O routines for memory mapped cards + */ + +byte mem_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + byte value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemIn(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +word mem_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + word value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemInBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (dword) &RBuffer->length; + card->RBuffer.length = UxCardMemInW(card->hw, m); + + m = b; + m += (dword) &RBuffer->P; + UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOut(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutW(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + value++; + UxCardMemOutW(card->hw, m, value); + + UxCardMemDetach(card->hw, b); + + return; +} + +/* + * I/O routines for I/O mapped cards + */ + +byte io_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + byte value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoIn(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +word io_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + word value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer); + + UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length); + + UxCardMemDetach(card->hw, DivasIOBase); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + return; +} + +void io_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOut(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutW(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + byte *DivasIOBase; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + value++; + + UxCardIoOutW(card->hw, DivasIOBase, adr, value); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +void test_int(card_t *card) + +{ + byte *shared, *DivasIOBase; + + switch (card->test_int_pend) + { + case TEST_INT_DIVAS: + DPRINTF(("divas: test interrupt pending")); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + if (UxCardMemIn(card->hw, &shared[0x3FE])) + { + UxCardMemOut(card->hw, + &(((struct pr_ram *)shared)->RcOutput), 0); + UxCardMemDetach(card->hw, shared); + (*card->reset_int)(card); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + DPRINTF(("divas: test interrupt cleared")); + } + + UxCardMemDetach(card->hw, shared); + + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_BRI: + DPRINTF(("divas: BRI test interrupt pending")); + (*card->reset_int)(card); + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0); + UxCardMemDetach(card->hw, DivasIOBase); + DPRINTF(("divas: test interrupt cleared")); + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_Q: + DPRINTF(("divas: 4BRI test interrupt pending")); + (*card->reset_int)(card); + card->test_int_pend = 0; + break; + + default: + DPRINTF(("divas: unknown test interrupt pending")); + return; + } + return; +} + +void card_isr (void *dev_id) +{ + card_t *card = (card_t *) dev_id; + ADAPTER *a = &card->a; + int ipl; + + if (card->test_int_pend) + { + ipl = UxCardLock(card->hw); + card->int_pend=0; + test_int(card); + UxCardUnlock(card->hw,ipl); + return; + } + + if(card->card_isr) + { + (*(card->card_isr))(card); + } + else + { + ipl = UxCardLock(card->hw); + + if ((card->test_int)(a)) + { + (card->reset_int)(card); + } + + UxCardUnlock(card->hw,ipl); + + } + +} + +int DivasCardNew(dia_card_t *card_info) +{ + card_t *card; + byte b; + static boolean_t first_call = TRUE; + boolean_t NeedISRandReset = FALSE; + + DPRINTF(("divas: new card ")); + + if (first_call) + { + first_call = FALSE; + init_idi_tab(); + } + + DivasConfigGet(card_info); + + if (DivasCardNext == DIM(DivasCards)) + { + KDPRINTF((KERN_WARNING "Divas: no space available for new card")); + return -1; + } + + card = &DivasCards[DivasCardNext]; + + card->state = DIA_UNKNOWN; + + card->cfg = *card_info; + + card->a.io = card; + + if (UxCardHandleGet(&card->hw, card_info)) + { + KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card")); + return -1; + } + + if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + DivasBriPatch(card); + card_info->io_base = card->cfg.io_base; + } + + switch (card_info->card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + if (DivasPriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + if (DivasBriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_Q: + if (Divas4BriInit(card, card_info)) + { + return -1; + } + + if (card_info->name[6] == '0') + { + NeedISRandReset = TRUE; + } + else // Need to set paramater for ISR anyway + { + card->hw->user_isr_arg = card; + card->hw->user_isr = card_isr; + } + break; + + default: + KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type)); + return -1; + } + + if (NeedISRandReset) + { + if (UxIsrInstall(card->hw, card_isr, card)) + { + KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq)); + UxCardHandleFree(card->hw); + return -1; + } + + b = card->cfg.irq; + + UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b); + + if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q) + { + if ((*card->card_reset)(card)) + { + KDPRINTF((KERN_WARNING "Divas: Adapter reset failed")); + return -1; + } + card->state = DIA_RESET; + } + + NeedISRandReset = FALSE; + } + + DivasCardNext++; + + return 0; +} + +void *get_card(int card_id) +{ + int i; + + for (i=0; i < DivasCardNext; i++) + { + if (DivasCards[i].cfg.card_id == card_id) + { + return(&DivasCards[i]); + } + } + + DPRINTF(("divas: get_card() : no such card id (%d)", card_id)); + + return NULL; +} + +int DivasCardConfig(dia_config_t *config) +{ + card_t *card; + int status; + + DPRINTF(("divas: configuring card")); + + card = get_card(config->card_id); + if (!card) + { + return -1; + } + + config = DivasConfig(card, config); + + status = (*card->card_config)(card, config); + + if (!status) + { + card->state = DIA_CONFIGURED; + } + return status; +} + +int DivasCardLoad(dia_load_t *load) +{ + card_t *card; + int status; + + card = get_card(load->card_id); + if (!card) + { + return -1; + } + + if (card->state == DIA_RUNNING) + { + (*card->card_reset)(card); + } + + status = (*card->card_load)(card, load); + if (!status) + { + card->state = DIA_LOADED; + } + return status; +} + +static int idi_register(card_t *card, byte channels) +{ + DESCRIPTOR d[32]; + int length, num_entities; + + DPRINTF(("divas: registering card with IDI")); + + num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES; + card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities); + + if (!card->e_tbl) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available")); + return -1; + } + + bzero(card->e_tbl, sizeof(E_INFO) * num_entities); + card->e_max = num_entities; + + DIVA_DIDD_Read(d, sizeof(d)); + + for(length=0; length < DIM(d); length++) + if (d[length].type == 0) break; + + if (length >= DIM(d)) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full")); + return -1; + } + + switch (card->cfg.card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + d[length].type = IDI_ADAPTER_PR; + /* d[length].serial = card->serial_no; */ + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + d[length].type = IDI_ADAPTER_MAESTRA; + /* d[length].serial = card->serial_no; */ + break; + + // 4BRI is treated as 4 BRI adapters + case DIA_CARD_TYPE_DIVA_SERVER_Q: + d[length].type = IDI_ADAPTER_MAESTRA; + /* d[length].serial = card->cfg.serial; */ + } + + d[length].features = 0; + d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120; + + if ( card->hw->features & PROTCAP_MANIF ) + { + d[length].features |= DI_MANAGE ; + } + if ( card->hw->features & PROTCAP_V_42 ) + { + d[length].features |= DI_V_42 ; + } + if ( card->hw->features & PROTCAP_EXTD_FAX ) + { + d[length].features |= DI_EXTD_FAX ; + } + + d[length].channels = channels; + d[length].request = DivasIdiRequest[card - DivasCards]; + + length++; + + DIVA_DIDD_Write(d, sizeof(d)); + + return 0; +} + +int DivasCardStart(int card_id) +{ + card_t *card; + byte channels; + int status; + + DPRINTF(("divas: starting card")); + + card = get_card(card_id); + if (!card) + { + return -1; + } + + status = (*card->card_start)(card, &channels); + if (status) + { + return status; + } + + /* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */ + if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + int i; + card_t *FourBRISlave; + + for (i=3; i >= 0; i--) + { + FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */ + if (FourBRISlave) + { + idi_register(FourBRISlave, 2); + FourBRISlave->state = DIA_RUNNING; + } + } + card->serial_no = card->cfg.serial; + + DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", + card_id - 3, card->serial_no, (int) channels)); + } + else + { + status = idi_register(card, channels); + if (!status) + { + card->state = DIA_RUNNING; + DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", + card_id, card->serial_no, (int) channels)); + } + } + + return status; +} + +int DivasGetMem(mem_block_t *mem_block) +{ + card_t *card; + word card_id = mem_block->card_id; + + card = get_card(card_id); + if (!card) + { + return 0; + } + + return (*card->card_mem_get)(card, mem_block); +} + + +/* + * Deleyed Procedure Call for handling interrupts from card + */ + +void DivaDoCardDpc(card_t *card) +{ + ADAPTER *a; + + a = &card->a; + + if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1) + { + return; + } + + do{ + if((*(card->test_int))(a)) + { + (*(card->dpc))(a); + (*(card->clear_int))(a); + } + (*(card->out))(a); + }while(UxInterlockedDecrement(card->hw, &card->dpc_reentered)); + +} + +void DivasDoDpc(void *pData) +{ + card_t *card = DivasCards; + int i = DivasCardNext; + + while(i--) + { + DivaDoCardDpc(card++); + } +} + +void DivasDoRequestDpc(void *pData) +{ + DivasDoDpc(pData); +} + +/* + * DivasGetNum + * Returns the number of active adapters + */ + +int DivasGetNum(void) +{ + return(DivasCardNext); +} + +/* + * DivasGetList + * Returns a list of active adapters + */ +int DivasGetList(dia_card_list_t *card_list) +{ + int i; + + bzero(card_list, sizeof(dia_card_list_t)); + + for(i = 0; i < DivasCardNext; i++) + { + card_list->card_type = DivasCards[i].cfg.card_type; + card_list->card_slot = DivasCards[i].cfg.slot; + card_list->state = DivasCards[i].state; + card_list++; + } + + return 0; + +} + +/* + * control logging for specified card + */ + +void DivasLog(dia_log_t *log) +{ + card_t *card; + + card = get_card(log->card_id); + if (!card) + { + return; + } + + card->log_types = log->log_types; + + return; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/constant.h linux/drivers/isdn/eicon/constant.h --- v2.2.18/drivers/isdn/eicon/constant.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/constant.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,176 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + + +/*------------------------------------------------------------------*/ +/* Q.931 information elements maximum length */ +/* excluding the identifier, including the length field */ +/*------------------------------------------------------------------*/ + +#define MAX_LEN_BC 13 +#define MAX_LEN_LLC 19 /* ctr3 */ +#define MAX_LEN_HLC 6 /* ctr3 */ +#define MAX_LEN_UUI 200 /* Hicom USBS req */ +#define MAX_LEN_NUM 24 +#define MAX_LEN_DSP 83 /* ctr3 */ +#define MAX_LEN_NI 4 +#define MAX_LEN_PI 5 +#define MAX_LEN_SIN 3 +#define MAX_LEN_CST 4 +#define MAX_LEN_SIG 2 +#define MAX_LEN_SPID 32 +#define MAX_LEN_EID 3 +#define MAX_LEN_CHI 35 /* ctr3 */ +#define MAX_LEN_CAU 33 +#define MAX_LEN_FTY 130 +#define MAX_LEN_KEY 83 /* ctr3 */ +#define MAX_LEN_RSI 4 +#define MAX_LEN_CAI 11 +#define MAX_NUM_SPID 4 +#define MAX_LEN_USERID 9 +#define MAX_LEN_APPLID 5 +#define MAX_LEN_NTTCIF 15 + +/*------------------------------------------------------------------*/ +/* decision return values */ +/*------------------------------------------------------------------*/ + +#define YES 1 +#define NO 0 + + +/*-------------------------------------------------------------------*/ +/* w element coding */ +/*-------------------------------------------------------------------*/ + +#define NTTCIF 0x01 +#define BC 0x04 +#define CAU 0x08 +#define CAD 0x0c +#define CAI 0x10 +#define CST 0x14 +#define CHI 0x18 +#define LLI 0x19 +#define CHA 0x1a +#define FTY 0x1c +#define PI 0x1e +#define NFAC 0x20 +#define TC 0x24 +#define ATT_EID 0x26 +#define NI 0x27 +#define DSP 0x28 +#define DT 0x29 +#define KEY 0x2c +#define KP 0x2c +#define UID 0x2d +#define SIG 0x34 +#define FI 0x39 +#define SPID 0x3a +#define EID 0x3b +#define DSPF 0x3c +#define ECAD 0x4c +#define OAD 0x6c +#define OSA 0x6d +#define DAD 0x70 +#define CPN 0x70 +#define DSA 0x71 +#define RDX 0x73 +#define RAD 0x74 +#define RDN 0x74 +#define RSI 0x79 +#define SCR 0x7A /* internal unscreened CPN */ +#define MIE 0x7a /* internal management info element */ +#define LLC 0x7c +#define HLC 0x7d +#define UUI 0x7e +#define ESC 0x7f + +#define SHIFT 0x90 +#define MORE 0xa0 +#define CL 0xb0 + +/* information elements used on the spid interface */ +#define SPID_CMD 0xc0 +#define SPID_LINK 0x10 +#define SPID_DN 0x70 +#define SPID_BC 0x04 +#define SPID_SWITCH 0x11 + +/*------------------------------------------------------------------*/ +/* global configuration parameters, defined in exec.c */ +/* these parameters are configured with program loading */ +/*------------------------------------------------------------------*/ + +#define PROT_1TR6 0 +#define PROT_ETSI 1 +#define PROT_FRANC 2 +#define PROT_BELG 3 +#define PROT_SWED 4 +#define PROT_NI 5 +#define PROT_5ESS 6 +#define PROT_JAPAN 7 +#define PROT_ATEL 8 +#define PROT_US 9 +#define PROT_ITALY 10 +#define PROT_TWAN 11 +#define PROT_AUSTRAL 12 + +#define INIT_PROT_1TR6 0x80|PROT_1TR6 +#define INIT_PROT_ETSI 0x80|PROT_ETSI +#define INIT_PROT_FRANC 0x80|PROT_FRANC +#define INIT_PROT_BELG 0x80|PROT_BELG +#define INIT_PROT_SWED 0x80|PROT_SWED +#define INIT_PROT_NI 0x80|PROT_NI +#define INIT_PROT_5ESS 0x80|PROT_5ESS +#define INIT_PROT_JAPAN 0x80|PROT_JAPAN +#define INIT_PROT_ATEL 0x80|PROT_ATEL +#define INIT_PROT_ITALY 0x80|PROT_ITALY +#define INIT_PROT_TWAN 0x80|PROT_TWAN +#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL + + +/* -----------------------------------------------------------** +** The PROTOCOL_FEATURE_STRING in feature.h (included ** +** in prstart.sx and astart.sx) defines capabilities and ** +** features of the actual protocol code. It's used as a bit ** +** mask. ** +** The following Bits are defined: ** +** -----------------------------------------------------------*/ + +#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ +#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ +#define PROTCAP_V_42 0x0004 /* V42 implemented */ +#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ +#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ +#define PROTCAP_FREE4 0x0020 /* not used */ +#define PROTCAP_FREE5 0x0040 /* not used */ +#define PROTCAP_FREE6 0x0080 /* not used */ +#define PROTCAP_FREE7 0x0100 /* not used */ +#define PROTCAP_FREE8 0x0200 /* not used */ +#define PROTCAP_FREE9 0x0400 /* not used */ +#define PROTCAP_FREE10 0x0800 /* not used */ +#define PROTCAP_FREE11 0x1000 /* not used */ +#define PROTCAP_FREE12 0x2000 /* not used */ +#define PROTCAP_FREE13 0x4000 /* not used */ +#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/divalog.h linux/drivers/isdn/eicon/divalog.h --- v2.2.18/drivers/isdn/eicon/divalog.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/divalog.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,54 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Include file for defining the kernel loggger messages + * These definitions are shared between the klog driver and the + * klogd daemon process + */ + +#if !defined(_KLOGMSG_H) +#define _KLOGMSG_H + +/* define a type for a log entry */ + +#define KLOG_TEXT_MSG (0) +#define KLOG_XLOG_MSG (1) +#define KLOG_XTXT_MSG (2) +#define KLOG_IDI_REQ (4) +#define KLOG_IDI_CALLBACK (5) +#define KLOG_CAPI_MSG (6) + +typedef struct +{ + unsigned long time_stamp; /* in ms since last system boot */ + int card; /* card number (-1 for all) */ + unsigned int type; /* type of log message (0 is text) */ + unsigned int length; /* message length (non-text messages only) */ + unsigned short code; /* message code (non-text messages only) */ + char buffer[110];/* text/data to log */ +} klog_t; + +void DivasLogAdd(void *buffer, int length); +#endif /* of _KLOGMSG_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/divas.h linux/drivers/isdn/eicon/divas.h --- v2.2.18/drivers/isdn/eicon/divas.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/divas.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,229 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.5 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* External Diva Server driver include file */ + +#if !defined(DIVAS_H) +#define DIVAS_H + +#include "sys.h" + + +/* IOCTL commands */ + +#define DIA_IOCTL_INIT (0) +#define DIA_IOCTL_LOAD (1) +#define DIA_IOCTL_CONFIG (2) +#define DIA_IOCTL_START (3) +#define DIA_IOCTL_GET_NUM (4) +#define DIA_IOCTL_GET_LIST (5) +#define DIA_IOCTL_LOG (6) +#define DIA_IOCTL_DETECT (7) +#define DIA_IOCTL_SPACE (8) +#define DIA_IOCTL_GET_MEM (9) +#define DIA_IOCTL_FLAVOUR (10) +#define DIA_IOCTL_XLOG_REQ (11) + +/* Error codes */ + +#define XLOG_ERR_CARD_NUM (13) +#define XLOG_ERR_DONE (14) +#define XLOG_ERR_CMD (15) +#define XLOG_ERR_TIMEOUT (16) +#define XLOG_ERR_CARD_STATE (17) +#define XLOG_ERR_UNKNOWN (18) +#define XLOG_OK (0) + +/* Adapter states */ + +#define DIA_UNKNOWN (0) +#define DIA_RESET (1) +#define DIA_LOADED (2) +#define DIA_CONFIGURED (3) +#define DIA_RUNNING (4) + +/* Stucture for getting card specific information from active cad driver */ + +typedef struct +{ + int card_type; + int card_slot; + int state; +} dia_card_list_t; + +/* use following to select which logging to have active */ + +#define DIVAS_LOG_DEBUG (1 << 0) +#define DIVAS_LOG_XLOG (1 << 1) +#define DIVAS_LOG_IDI (1 << 2) +#define DIVAS_LOG_CAPI (1 << 3) + +/* stucture for DIA_IOCTL_LOG to get information from adapter */ + +typedef struct +{ + int card_id; + int log_types; /* bit mask of log types: use DIVAS_LOG_XXX */ +} dia_log_t; + +/* list of cards supported by this driver */ + +#define DIA_CARD_TYPE_DIVA_SERVER (0) /* Diva Server PRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_B (1) /* Diva Server BRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_Q (2) /* Diva Server 4-BRI */ + +/* bus types */ + +#define DIA_BUS_TYPE_ISA (0) +#define DIA_BUS_TYPE_ISA_PNP (1) +#define DIA_BUS_TYPE_PCI (2) +#define DIA_BUS_TYPE_MCA (3) + +/* types of memory used (index for memory array below) */ + +#define DIVAS_RAM_MEMORY 0 +#define DIVAS_REG_MEMORY 1 +#define DIVAS_CFG_MEMORY 2 +#define DIVAS_SHARED_MEMORY 3 +#define DIVAS_CTL_MEMORY 4 +/* + * card config information + * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card + */ + +typedef struct +{ + int card_id; /* unique id assigned to this card */ + int card_type; /* use DIA_CARD_TYPE_xxx above */ + int bus_type; /* use DIA_BUS_TYPE_xxx above */ + int bus_num; /* bus number (instance number of bus type) */ + int func_num; /* adapter function number (PCI register) */ + int slot; /* slot number in bus */ + unsigned char irq; /* IRQ number */ + int reset_base; /* Reset register for I/O mapped cards */ + int io_base; /* I/O base for I/O mapped cards */ + void *memory[5]; /* memory base addresses for memory mapped cards */ + char name[9]; /* name of adapter */ + int serial; /* serial number */ + unsigned char int_priority; /* Interrupt priority */ +} dia_card_t; + +/* + * protocol configuration information + * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card + */ + +typedef struct +{ + int card_id; /* to identify particular card */ + unsigned char tei; + unsigned char nt2; + unsigned char watchdog; + unsigned char permanent; + unsigned char x_interface; + unsigned char stable_l2; + unsigned char no_order_check; + unsigned char handset_type; + unsigned char sig_flags; + unsigned char low_channel; + unsigned char prot_version; + unsigned char crc4; + struct + { + unsigned char oad[32]; + unsigned char osa[32]; + unsigned char spid[32]; + }terminal[2]; +} dia_config_t; + +/* + * code configuration + * passed as parameter to DIA_IOCTL_LOAD ioctl + * one of these ioctl per code file to load + */ + +typedef struct +{ + int card_id; /* card to load */ + enum + { + DIA_CPU_CODE, /* CPU code */ + DIA_DSP_CODE, /* DSP code */ + DIA_CONT_CODE, /* continuation of code */ + DIA_TABLE_CODE, /* code table */ + DIA_DLOAD_CNT, /* number of downloads*/ + DIA_FPGA_CODE + } code_type; /* code for CPU or DSP ? */ + int length; /* length of code */ + unsigned char *code; /* pointer (in user-space) to code */ +} dia_load_t; + +/* + * start configuration + * passed as parameter to DIA_IOCTL_START ioctl + */ + +typedef struct +{ + int card_id; /* card to start */ +} dia_start_t; + +/* used for retrieving memory from the card */ + +typedef struct { + word card_id; + dword addr; + byte data[16 * 8]; +} mem_block_t; + +/* DIVA Server specific addresses */ + +#define DIVAS_CPU_START_ADDR (0x0) +#define ORG_MAX_PROTOCOL_CODE_SIZE 0x000A0000 +#define ORG_MAX_DSP_CODE_SIZE (0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE) +#define ORG_DSP_CODE_BASE (0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE) +#define DIVAS_DSP_START_ADDR (0xBF7A0000) +#define DIVAS_SHARED_OFFSET (0x1000) +#define MP_DSP_CODE_BASE 0xa03a0000 +#define MQ_PROTCODE_OFFSET 0x100000 +#define MQ_SM_OFFSET 0X0f0000 + +#define V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 +#define V90D_MAX_DSP_CODE_SIZE (0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE) +#define V90D_DSP_CODE_BASE (0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE) + +#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ +#define MQ_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code */ +#define MQ_ORG_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_ORG_MAX_DSP_CODE_SIZE) +#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 /* max 576K Protocol-Code */ +#define MQ_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code if V.90D included */ +#define MQ_MAX_DSP_DOWNLOAD_ADDR 0xa03f0000 +#define MQ_V90D_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_V90D_MAX_DSP_CODE_SIZE) + + +#define ALIGNMENT_MASK_MAESTRA 0xfffffffc + +#endif /* DIVAS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/dsp_defs.h linux/drivers/isdn/eicon/dsp_defs.h --- v2.2.18/drivers/isdn/eicon/dsp_defs.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/dsp_defs.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,300 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef DSP_DEFS_H_ +#define DSP_DEFS_H_ + +#ifndef DSPDIDS_H_ +#include "dspdids.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif +#ifndef TRUE +#define TRUE (0 == 0) +#endif +#ifndef FALSE +#define FALSE (0 != 0) +#endif + + +/*---------------------------------------------------------------------------*/ + +#define DSP_MEMORY_TYPE_EXTERNAL_DM 0 +#define DSP_MEMORY_TYPE_EXTERNAL_PM 1 +#define DSP_MEMORY_TYPE_INTERNAL_DM 2 +#define DSP_MEMORY_TYPE_INTERNAL_PM 3 + +#define DSP_DOWNLOAD_FLAG_BOOTABLE 0x0001 +#define DSP_DOWNLOAD_FLAG_2181 0x0002 +#define DSP_DOWNLOAD_FLAG_TIMECRITICAL 0x0004 +#define DSP_DOWNLOAD_FLAG_COMPAND 0x0008 + +#define DSP_MEMORY_BLOCK_COUNT 16 + +#define DSP_SEGMENT_PM_FLAG 0x0001 +#define DSP_SEGMENT_SHARED_FLAG 0x0002 + +#define DSP_SEGMENT_EXTERNAL_DM DSP_MEMORY_TYPE_EXTERNAL_DM +#define DSP_SEGMENT_EXTERNAL_PM DSP_MEMORY_TYPE_EXTERNAL_PM +#define DSP_SEGMENT_INTERNAL_DM DSP_MEMORY_TYPE_INTERNAL_DM +#define DSP_SEGMENT_INTERNAL_PM DSP_MEMORY_TYPE_INTERNAL_PM +#define DSP_SEGMENT_FIRST_RELOCATABLE 4 + +#define DSP_DATA_BLOCK_PM_FLAG 0x0001 +#define DSP_DATA_BLOCK_DWORD_FLAG 0x0002 +#define DSP_DATA_BLOCK_RESOLVE_FLAG 0x0004 + +#define DSP_RELOC_NONE 0x00 +#define DSP_RELOC_SEGMENT_MASK 0x3f +#define DSP_RELOC_TYPE_MASK 0xc0 +#define DSP_RELOC_TYPE_0 0x00 /* relocation of address in DM word / high part of PM word */ +#define DSP_RELOC_TYPE_1 0x40 /* relocation of address in low part of PM data word */ +#define DSP_RELOC_TYPE_2 0x80 /* relocation of address in standard command */ +#define DSP_RELOC_TYPE_3 0xc0 /* relocation of address in call/jump on flag in */ + +#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 + +#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 + + +typedef struct tag_dsp_combifile_header +{ + char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word header_size; + word combifile_description_size; + word directory_entries; + word directory_size; + word download_count; + word usage_mask_size; +} t_dsp_combifile_header; + +typedef struct tag_dsp_combifile_directory_entry +{ + word card_type_number; + word file_set_number; +} t_dsp_combifile_directory_entry; + +typedef struct tag_dsp_file_header +{ + char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word header_size; + word download_description_size; + word memory_block_table_size; + word memory_block_count; + word segment_table_size; + word segment_count; + word symbol_table_size; + word symbol_count; + word total_data_size_dm; + word data_block_count_dm; + word total_data_size_pm; + word data_block_count_pm; +} t_dsp_file_header; + +typedef struct tag_dsp_memory_block_desc +{ + word alias_memory_block; + word memory_type; + word address; + word size; /* DSP words */ +} t_dsp_memory_block_desc; + +typedef struct tag_dsp_segment_desc +{ + word memory_block; + word attributes; + word base; + word size; + word alignment; /* ==0 -> no other legal start address than base */ +} t_dsp_segment_desc; + +typedef struct tag_dsp_symbol_desc +{ + word symbol_id; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_symbol_desc; + +typedef struct tag_dsp_data_block_header +{ + word attributes; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_data_block_header; + +typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ +{ + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word excess_header_size; + word memory_block_count; + word segment_count; + word symbol_count; + word data_block_count_dm; + word data_block_count_pm; + byte *p_excess_header_data; + char *p_download_description; + t_dsp_memory_block_desc *p_memory_block_table; + t_dsp_segment_desc *p_segment_table; + t_dsp_symbol_desc *p_symbol_table; + word *p_data_blocks_dm; + word *p_data_blocks_pm; +} t_dsp_download_desc; + +#define DSP_DOWNLOAD_INDEX_KERNEL 0 +#define DSP30TX_DOWNLOAD_INDEX_KERNEL 1 +#define DSP30RX_DOWNLOAD_INDEX_KERNEL 2 +#define DSP_MAX_DOWNLOAD_COUNT 35 + + +#define DSP_DOWNLOAD_MAX_SEGMENTS 16 + +#define DSP_UDATA_REQUEST_RECONFIGURE 0 +/* +parameters: + reconfigure delay (in 8kHz samples) + reconfigure code + reconfigure hdlc preamble flags +*/ + +#define DSP_RECONFIGURE_TX_FLAG 0x8000 +#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 +#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 +#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 +#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 +#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff +#define DSP_RECONFIGURE_IDLE 0 +#define DSP_RECONFIGURE_V25 1 +#define DSP_RECONFIGURE_V21_CH2 2 +#define DSP_RECONFIGURE_V27_2400 3 +#define DSP_RECONFIGURE_V27_4800 4 +#define DSP_RECONFIGURE_V29_7200 5 +#define DSP_RECONFIGURE_V29_9600 6 +#define DSP_RECONFIGURE_V33_12000 7 +#define DSP_RECONFIGURE_V33_14400 8 +#define DSP_RECONFIGURE_V17_7200 9 +#define DSP_RECONFIGURE_V17_9600 10 +#define DSP_RECONFIGURE_V17_12000 11 +#define DSP_RECONFIGURE_V17_14400 12 + +/* +data indications if transparent framer + data 0 + data 1 + ... + +data indications if HDLC framer + data 0 + data 1 + ... + CRC 0 + CRC 1 + preamble flags +*/ + +#define DSP_UDATA_INDICATION_SYNC 0 +/* +returns: + time of sync (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_OFF 1 +/* +returns: + time of DCD off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_ON 2 +/* +returns: + time of DCD on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s) +*/ + +#define DSP_UDATA_INDICATION_CTS_OFF 3 +/* +returns: + time of CTS off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_CTS_ON 4 +/* +returns: + time of CTS on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s) +*/ + +#define DSP_CONNECTED_NORM_UNSPECIFIED 0 +#define DSP_CONNECTED_NORM_V21 1 +#define DSP_CONNECTED_NORM_V23 2 +#define DSP_CONNECTED_NORM_V22 3 +#define DSP_CONNECTED_NORM_V22_BIS 4 +#define DSP_CONNECTED_NORM_V32_BIS 5 +#define DSP_CONNECTED_NORM_V34 6 +#define DSP_CONNECTED_NORM_V8 7 +#define DSP_CONNECTED_NORM_BELL_212A 8 +#define DSP_CONNECTED_NORM_BELL_103 9 +#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 +#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 +#define DSP_CONNECTED_NORM_TFAST 12 +#define DSP_CONNECTED_NORM_V21_CH2 13 +#define DSP_CONNECTED_NORM_V27_TER 14 +#define DSP_CONNECTED_NORM_V29 15 +#define DSP_CONNECTED_NORM_V33 16 +#define DSP_CONNECTED_NORM_V17 17 + +#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 + + +/*---------------------------------------------------------------------------*/ +#ifdef __cplusplus +} +#endif + +#endif + +/*---------------------------------------------------------------------------*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/dspdids.h linux/drivers/isdn/eicon/dspdids.h --- v2.2.18/drivers/isdn/eicon/dspdids.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/dspdids.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,81 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef DSPDIDS_H_ +#define DSPDIDS_H_ + + +/*---------------------------------------------------------------------------*/ + +#define DSP_DID_INVALID 0 +#define DSP_DID_DIVA 1 +#define DSP_DID_DIVA_PRO 2 +#define DSP_DID_DIVA_PRO_20 3 +#define DSP_DID_DIVA_PRO_PCCARD 4 +#define DSP_DID_DIVA_SERVER_BRI_1M 5 +#define DSP_DID_DIVA_SERVER_BRI_2M 6 +#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7 +#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8 +#define DSP_DID_DIVA_SERVER_PRI_30M 9 +#define DSP_DID_TASK_HSCX 100 +#define DSP_DID_TASK_HSCX_PRI_2M_TX 101 +#define DSP_DID_TASK_HSCX_PRI_2M_RX 102 +#define DSP_DID_TASK_V110KRNL 200 +#define DSP_DID_OVERLAY_V1100 201 +#define DSP_DID_OVERLAY_V1101 202 +#define DSP_DID_OVERLAY_V1102 203 +#define DSP_DID_OVERLAY_V1103 204 +#define DSP_DID_OVERLAY_V1104 205 +#define DSP_DID_OVERLAY_V1105 206 +#define DSP_DID_OVERLAY_V1106 207 +#define DSP_DID_OVERLAY_V1107 208 +#define DSP_DID_OVERLAY_V1108 209 +#define DSP_DID_OVERLAY_V1109 210 +#define DSP_DID_TASK_V110_PRI_2M_TX 220 +#define DSP_DID_TASK_V110_PRI_2M_RX 221 +#define DSP_DID_TASK_MODEM 300 +#define DSP_DID_TASK_FAX05 400 +#define DSP_DID_TASK_VOICE 500 +#define DSP_DID_TASK_TIKRNL81 600 +#define DSP_DID_OVERLAY_DIAL 601 +#define DSP_DID_OVERLAY_V22 602 +#define DSP_DID_OVERLAY_V32 603 +#define DSP_DID_OVERLAY_FSK 604 +#define DSP_DID_OVERLAY_FAX 605 +#define DSP_DID_OVERLAY_VXX 606 +#define DSP_DID_OVERLAY_V8 607 +#define DSP_DID_OVERLAY_INFO 608 +#define DSP_DID_OVERLAY_V34 609 +#define DSP_DID_OVERLAY_DFX 610 +#define DSP_DID_PARTIAL_OVERLAY_DIAL 611 +#define DSP_DID_PARTIAL_OVERLAY_FSK 612 +#define DSP_DID_PARTIAL_OVERLAY_FAX 613 +#define DSP_DID_TASK_TIKRNL05 700 + + +/*---------------------------------------------------------------------------*/ + +#endif + +/*---------------------------------------------------------------------------*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.2.18/drivers/isdn/eicon/eicon.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon.h Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,86 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon.h,v $ - * Revision 1.19 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.18 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.17 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.16 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.15 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.14 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.13 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.12 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.11 1999/08/29 17:23:44 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/22 20:26:41 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/18 20:16:57 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:01 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:23 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:24 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/03/29 11:19:41 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:42 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:07 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:04 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ @@ -124,6 +44,8 @@ #define EICON_IOCTL_TEST 98 #define EICON_IOCTL_DEBUGVAR 99 +#define EICON_IOCTL_DIA_OFFSET 100 + /* Bus types */ #define EICON_BUS_ISA 1 #define EICON_BUS_MCA 2 @@ -185,39 +107,10 @@ unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */ } eicon_isa_codebuf; -/* Struct for downloading protocol via ioctl for PCI cards */ -typedef struct { - /* start-up parameters */ - unsigned char tei; - unsigned char nt2; - unsigned char WatchDog; - unsigned char Permanent; - unsigned char XInterface; - unsigned char StableL2; - unsigned char NoOrderCheck; - unsigned char HandsetType; - unsigned char LowChannel; - unsigned char ProtVersion; - unsigned char Crc4; - unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */ - unsigned char Loopback; /* switch card into Loopback mode */ - struct q931_link_s - { - unsigned char oad[32]; - unsigned char osa[32]; - unsigned char spid[32]; - } l[2]; - unsigned long protocol_len; - unsigned int dsp_code_num; - unsigned long dsp_code_len[9]; - unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */ -} eicon_pci_codebuf; - /* Data for downloading protocol via ioctl */ typedef union { eicon_isa_codebuf isa; eicon_isa_codebuf mca; - eicon_pci_codebuf pci; } eicon_codebuf; /* Data for Management interface */ @@ -228,6 +121,7 @@ unsigned char data[700]; } eicon_manifbuf; +#define TRACE_OK (1) #ifdef __KERNEL__ @@ -245,7 +139,7 @@ #include #include #include -#include +#include #include #include #include @@ -257,7 +151,6 @@ #include #include - typedef struct { __u16 length __attribute__ ((packed)); /* length of data/parameter field */ __u8 P[1]; /* data/parameter field */ @@ -265,206 +158,34 @@ #include "eicon_isa.h" +#include "idi.h" + +typedef struct { + __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ + __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ + __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ + __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ + __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ + __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ + __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ + __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ + __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ + __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ + __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ + __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ + __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ + __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ + __u8 B[1]; /* buffer space for Req,Ind and Rc */ +} eicon_pr_ram; + /* Macro for delay via schedule() */ #define SLEEP(j) { \ - current->state = TASK_UNINTERRUPTIBLE; \ + set_current_state(TASK_UNINTERRUPTIBLE); \ schedule_timeout(j); \ } -#endif /* KERNEL */ - -#define DIVAS_SHARED_OFFSET (0x1000) - -#define MIPS_BUFFER_SZ 128 -#define MIPS_MAINT_OFFS 0xff00 - -#define XLOG_ERR_CARD_NUM (13) -#define XLOG_ERR_DONE (14) -#define XLOG_ERR_CMD (15) -#define XLOG_ERR_TIMEOUT (16) -#define XLOG_ERR_CARD_STATE (17) -#define XLOG_ERR_UNKNOWN (18) -#define XLOG_OK (0) - -#define TRACE_OK (1) - -typedef struct { - __u8 Id __attribute__ ((packed)); - __u8 uX __attribute__ ((packed)); - __u8 listen __attribute__ ((packed)); - __u8 active __attribute__ ((packed)); - __u8 sin[3] __attribute__ ((packed)); - __u8 bc[6] __attribute__ ((packed)); - __u8 llc[6] __attribute__ ((packed)); - __u8 hlc[6] __attribute__ ((packed)); - __u8 oad[20] __attribute__ ((packed)); -}DSigStruc; - -typedef struct { - __u32 cx_b1 __attribute__ ((packed)); - __u32 cx_b2 __attribute__ ((packed)); - __u32 cr_b1 __attribute__ ((packed)); - __u32 cr_b2 __attribute__ ((packed)); - __u32 px_b1 __attribute__ ((packed)); - __u32 px_b2 __attribute__ ((packed)); - __u32 pr_b1 __attribute__ ((packed)); - __u32 pr_b2 __attribute__ ((packed)); - __u16 er_b1 __attribute__ ((packed)); - __u16 er_b2 __attribute__ ((packed)); -}BL1Struc; - -typedef struct { - __u32 XTotal __attribute__ ((packed)); - __u32 RTotal __attribute__ ((packed)); - __u16 XError __attribute__ ((packed)); - __u16 RError __attribute__ ((packed)); -}L2Struc; - -typedef struct { - __u16 free_n; -}OSStruc; - -typedef union -{ - DSigStruc DSigStats; - BL1Struc BL1Stats; - L2Struc L2Stats; - OSStruc OSStats; - __u8 b[MIPS_BUFFER_SZ]; - __u16 w[MIPS_BUFFER_SZ>>1]; - __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ - __u32 d[MIPS_BUFFER_SZ>>2]; -} MIPS_BUFFER; - -typedef struct -{ - __u8 req __attribute__ ((packed)); - __u8 rc __attribute__ ((packed)); - __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */ - __u8 *mem __attribute__ ((packed)); - __u16 length __attribute__ ((packed)); /* used to be short */ - __u16 port __attribute__ ((packed)); - __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */ - MIPS_BUFFER data __attribute__ ((packed)); -} mi_pc_maint_t; - -typedef struct -{ - __u16 command; - mi_pc_maint_t pcm; -}xlogreq_t; - -typedef struct{ - __u16 code __attribute__ ((packed)); /* used to be short */ - __u16 timeh __attribute__ ((packed)); - __u16 timel __attribute__ ((packed)); - char buffer[MIPS_BUFFER_SZ - 6]; -}xlog_entry_t; - - -#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 - -#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 - -typedef struct tag_dsp_combifile_header -{ - char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 combifile_description_size __attribute__ ((packed)); - __u16 directory_entries __attribute__ ((packed)); - __u16 directory_size __attribute__ ((packed)); - __u16 download_count __attribute__ ((packed)); - __u16 usage_mask_size __attribute__ ((packed)); -} t_dsp_combifile_header; - -typedef struct tag_dsp_combifile_directory_entry -{ - __u16 card_type_number __attribute__ ((packed)); - __u16 file_set_number __attribute__ ((packed)); -} t_dsp_combifile_directory_entry; - -typedef struct tag_dsp_file_header -{ - char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 download_id __attribute__ ((packed)); - __u16 download_flags __attribute__ ((packed)); - __u16 required_processing_power __attribute__ ((packed)); - __u16 interface_channel_count __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 download_description_size __attribute__ ((packed)); - __u16 memory_block_table_size __attribute__ ((packed)); - __u16 memory_block_count __attribute__ ((packed)); - __u16 segment_table_size __attribute__ ((packed)); - __u16 segment_count __attribute__ ((packed)); - __u16 symbol_table_size __attribute__ ((packed)); - __u16 symbol_count __attribute__ ((packed)); - __u16 total_data_size_dm __attribute__ ((packed)); - __u16 data_block_count_dm __attribute__ ((packed)); - __u16 total_data_size_pm __attribute__ ((packed)); - __u16 data_block_count_pm __attribute__ ((packed)); -} t_dsp_file_header; - -typedef struct tag_dsp_memory_block_desc -{ - __u16 alias_memory_block; - __u16 memory_type; - __u16 address; - __u16 size; /* DSP words */ -} t_dsp_memory_block_desc; - -typedef struct tag_dsp_segment_desc -{ - __u16 memory_block; - __u16 attributes; - __u16 base; - __u16 size; - __u16 alignment; /* ==0 -> no other legal start address than base */ -} t_dsp_segment_desc; - -typedef struct tag_dsp_symbol_desc -{ - __u16 symbol_id; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_symbol_desc; - -typedef struct tag_dsp_data_block_header -{ - __u16 attributes; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_data_block_header; - -typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ -{ - __u16 download_id; - __u16 download_flags; - __u16 required_processing_power; - __u16 interface_channel_count; - __u16 excess_header_size; - __u16 memory_block_count; - __u16 segment_count; - __u16 symbol_count; - __u16 data_block_count_dm; - __u16 data_block_count_pm; - __u8 * p_excess_header_data __attribute__ ((packed)); - char * p_download_description __attribute__ ((packed)); - t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed)); - t_dsp_segment_desc *p_segment_table __attribute__ ((packed)); - t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed)); - __u16 * p_data_blocks_dm __attribute__ ((packed)); - __u16 * p_data_blocks_pm __attribute__ ((packed)); -} t_dsp_download_desc; - - -#ifdef __KERNEL__ - typedef struct { __u8 Req; /* pending request */ __u8 Rc; /* return code received */ @@ -508,6 +229,7 @@ unsigned short statectrl; /* State controling bits */ unsigned short eazmask; /* EAZ-Mask for this Channel */ int queued; /* User-Data Bytes in TX queue */ + int pqueued; /* User-Data Packets in TX queue */ int waitq; /* User-Data Bytes in wait queue */ int waitpq; /* User-Data Bytes in packet queue */ struct sk_buff *tskb1; /* temp skb 1 */ @@ -518,7 +240,9 @@ T30_s *fax; /* pointer to fax data in LL */ eicon_ch_fax_buf fax2; /* fax related struct */ #endif - entity e; /* Entity */ + entity e; /* Native Entity */ + ENTITY de; /* Divas D Entity */ + ENTITY be; /* Divas B Entity */ char cpn[32]; /* remember cpn */ char oad[32]; /* remember oad */ char dsa[32]; /* remember dsa */ @@ -542,8 +266,6 @@ #define EICON_FLAGS_MVALID 8 /* Cards membase is valid */ #define EICON_FLAGS_LOADED 8 /* Firmware loaded */ -#define EICON_BCH 2 /* # of channels per card */ - /* D-Channel states */ #define EICON_STATE_NULL 0 #define EICON_STATE_ICALL 1 @@ -565,9 +287,6 @@ #define EICON_MAX_QUEUE 2138 -#define EICON_LOCK_TX 0 -#define EICON_LOCK_RX 1 - typedef union { eicon_isa_card isa; eicon_pci_card pci; @@ -593,17 +312,12 @@ __u8 more; } eicon_indhdr; -typedef struct msn_entry { - char eaz; - char msn[16]; - struct msn_entry * next; -} msn_entry; - /* * Per card driver data */ typedef struct eicon_card { eicon_hwif hwif; /* Hardware dependant interface */ + DESCRIPTOR *d; /* IDI Descriptor */ u_char ptype; /* Protocol type (1TR6 or Euro) */ u_char bus; /* Bustype (ISA, MCA, PCI) */ u_char type; /* Cardtype (EICON_CTYPE_...) */ @@ -621,49 +335,23 @@ struct tq_struct snd_tq; /* Task struct for xmit bh */ struct tq_struct rcv_tq; /* Task struct for rcv bh */ struct tq_struct ack_tq; /* Task struct for ack bh */ - msn_entry *msn_list; eicon_chan* IdTable[256]; /* Table to find entity */ __u16 ref_in; __u16 ref_out; int nchannels; /* Number of B-Channels */ int ReadyInt; /* Ready Interrupt */ eicon_chan *bch; /* B-Channel status/control */ - char status_buf[256]; /* Buffer for status messages */ - char *status_buf_read; - char *status_buf_write; - char *status_buf_end; + DBUFFER *dbuf; /* Dbuffer for Diva Server */ + BUFFERS *sbuf; /* Buffer for Diva Server */ + char *sbufp; /* Data Buffer for Diva Server */ isdn_if interface; /* Interface to upper layer */ - char regname[35]; /* Name used for request_region */ + char regname[35]; /* Drivers card name */ #ifdef CONFIG_MCA int mca_slot; /* # of cards MCA slot */ int mca_io; /* MCA cards IO port */ #endif /* CONFIG_MCA */ } eicon_card; -/* -----------------------------------------------------------** -** The PROTOCOL_FEATURE_STRING ** -** defines capabilities and ** -** features of the actual protocol code. It's used as a bit ** -** mask. ** -** The following Bits are defined: ** -** -----------------------------------------------------------*/ -#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ -#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ -#define PROTCAP_V_42 0x0004 /* V42 implemented */ -#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ -#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ -#define PROTCAP_FREE4 0x0020 /* not used */ -#define PROTCAP_FREE5 0x0040 /* not used */ -#define PROTCAP_FREE6 0x0080 /* not used */ -#define PROTCAP_FREE7 0x0100 /* not used */ -#define PROTCAP_FREE8 0x0200 /* not used */ -#define PROTCAP_FREE9 0x0400 /* not used */ -#define PROTCAP_FREE10 0x0800 /* not used */ -#define PROTCAP_FREE11 0x1000 /* not used */ -#define PROTCAP_FREE12 0x2000 /* not used */ -#define PROTCAP_FREE13 0x4000 /* not used */ -#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ - #include "eicon_idi.h" extern eicon_card *cards; @@ -688,13 +376,11 @@ mark_bh(IMMEDIATE_BH); } -extern char *eicon_find_eaz(eicon_card *, char); -extern int eicon_addcard(int, int, int, char *); +extern int eicon_addcard(int, int, int, char *, int); extern void eicon_io_transmit(eicon_card *card); extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs); extern void eicon_io_rcv_dispatch(eicon_card *ccard); extern void eicon_io_ack_dispatch(eicon_card *ccard); -extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq); #ifdef CONFIG_MCA extern int eicon_mca_find_card(int, int, int, char *); extern int eicon_mca_probe(int, int, int, int, char *); @@ -704,6 +390,8 @@ extern ulong DebugVar; extern void eicon_log(eicon_card * card, int level, const char *fmt, ...); extern void eicon_putstatus(eicon_card * card, char * buf); + +extern spinlock_t eicon_lock; #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_dsp.h linux/drivers/isdn/eicon/eicon_dsp.h --- v2.2.18/drivers/isdn/eicon/eicon_dsp.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_dsp.h Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * DSP definitions @@ -20,75 +20,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_dsp.h,v $ - * Revision 1.5 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.4 1999/07/25 15:12:02 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.3 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.2 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.1 1999/03/02 12:18:54 armin - * First checkin of DSP defines for audio features. - * * */ #ifndef DSP_H #define DSP_H -#define DSP_UDATA_REQUEST_RECONFIGURE 0 -/* -parameters: - reconfigure delay (in 8kHz samples) - reconfigure code - reconfigure hdlc preamble flags -*/ - -#define DSP_RECONFIGURE_TX_FLAG 0x8000 -#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 -#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 -#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 -#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 -#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff -#define DSP_RECONFIGURE_IDLE 0 -#define DSP_RECONFIGURE_V25 1 -#define DSP_RECONFIGURE_V21_CH2 2 -#define DSP_RECONFIGURE_V27_2400 3 -#define DSP_RECONFIGURE_V27_4800 4 -#define DSP_RECONFIGURE_V29_7200 5 -#define DSP_RECONFIGURE_V29_9600 6 -#define DSP_RECONFIGURE_V33_12000 7 -#define DSP_RECONFIGURE_V33_14400 8 -#define DSP_RECONFIGURE_V17_7200 9 -#define DSP_RECONFIGURE_V17_9600 10 -#define DSP_RECONFIGURE_V17_12000 11 -#define DSP_RECONFIGURE_V17_14400 12 +#include "dsp_defs.h" -/* -data indications if transparent framer - data 0 - data 1 - ... - -data indications if HDLC framer - data 0 - data 1 - ... - CRC 0 - CRC 1 - preamble flags -*/ #define DSP_UDATA_REQUEST_SWITCH_FRAMER 1 /* @@ -122,49 +61,6 @@ - none - */ - -#define DSP_UDATA_INDICATION_SYNC 0 -/* -returns: - time of sync (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_OFF 1 -/* -returns: - time of DCD off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_ON 2 -/* -returns: - time of DCD on (sampled from counter at 8kHz) - connected norm - connected options - connected speed (bit/s, max of tx and rx speed) - roundtrip delay (ms) - connected speed tx (bit/s) - connected speed rx (bit/s) -*/ - -#define DSP_UDATA_INDICATION_CTS_OFF 3 -/* -returns: - time of CTS off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_CTS_ON 4 -/* -returns: - time of CTS on (sampled from counter at 8kHz) - connected norm - connected options - connected speed (bit/s, max of tx and rx speed) - roundtrip delay (ms) - connected speed tx (bit/s) - connected speed rx (bit/s) -*/ - typedef struct eicon_dsp_ind { __u16 time __attribute__ ((packed)); __u8 norm __attribute__ ((packed)); @@ -175,32 +71,11 @@ __u32 rxspeed __attribute__ ((packed)); } eicon_dsp_ind; -#define DSP_CONNECTED_NORM_UNSPECIFIED 0 -#define DSP_CONNECTED_NORM_V21 1 -#define DSP_CONNECTED_NORM_V23 2 -#define DSP_CONNECTED_NORM_V22 3 -#define DSP_CONNECTED_NORM_V22_BIS 4 -#define DSP_CONNECTED_NORM_V32_BIS 5 -#define DSP_CONNECTED_NORM_V34 6 -#define DSP_CONNECTED_NORM_V8 7 -#define DSP_CONNECTED_NORM_BELL_212A 8 -#define DSP_CONNECTED_NORM_BELL_103 9 -#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 -#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 -#define DSP_CONNECTED_NORM_V90 12 -#define DSP_CONNECTED_NORM_V21_CH2 13 -#define DSP_CONNECTED_NORM_V27_TER 14 -#define DSP_CONNECTED_NORM_V29 15 -#define DSP_CONNECTED_NORM_V33 16 -#define DSP_CONNECTED_NORM_V17 17 - -#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 #define DSP_CONNECTED_OPTION_V42_TRANS 0x0002 #define DSP_CONNECTED_OPTION_V42_LAPM 0x0004 #define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008 #define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010 - #define DSP_UDATA_INDICATION_DISCONNECT 5 /* returns: @@ -213,7 +88,6 @@ #define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY 0x03 #define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04 #define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05 - #define DSP_UDATA_INDICATION_TX_CONFIRMATION 6 /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.2.18/drivers/isdn/eicon/eicon_idi.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_idi.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $ +/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,135 +25,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.c,v $ - * Revision 1.33 2000/03/06 15:45:17 armin - * Fixed incomplete number handling with BRI PtP connection. - * - * Revision 1.32 2000/03/04 17:04:21 armin - * Fix of statemachine, B-connect before D-connect, - * thanks to Helmut Adams - * Minor change in send-data packet handling. - * - * Revision 1.31 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.30 2000/02/16 16:08:46 armin - * Fixed virtual channel handling of IDI. - * - * Revision 1.29 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.28 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.27 1999/11/29 13:12:03 armin - * Autoconnect on L2_TRANS doesn't work with link_level correctly, - * changed back to former mode. - * - * Revision 1.26 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.25 1999/11/18 20:30:55 armin - * removed old workaround for ISA cards. - * - * Revision 1.24 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.23 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.22 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.21 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.20 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.19 1999/09/21 20:06:40 armin - * Added pointer checks. - * - * Revision 1.18 1999/09/07 12:48:05 armin - * Prepared for sub-address usage. - * - * Revision 1.17 1999/09/07 12:35:39 armin - * Better checking and channel Id handling. - * - * Revision 1.16 1999/09/04 13:44:19 armin - * Fix of V.42 analog Modem negotiation handling. - * - * Revision 1.15 1999/08/28 21:32:50 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.14 1999/08/28 20:24:40 armin - * Corrected octet 3/3a in CPN/OAD information element. - * Thanks to John Simpson - * - * Revision 1.13 1999/08/22 20:26:44 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.12 1999/08/18 20:16:59 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.11 1999/07/25 15:12:03 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.10 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.9 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.8 1999/03/02 12:37:43 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.7 1999/02/03 18:34:35 armin - * Channel selection for outgoing calls w/o CHI. - * Added channel # in debug messages. - * L2 Transparent should work with 800 byte/packet now. - * - * Revision 1.6 1999/01/26 07:18:59 armin - * Bug with wrong added CPN fixed. - * - * Revision 1.5 1999/01/24 20:14:11 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.4 1999/01/10 18:46:05 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.3 1999/01/05 14:49:34 armin - * Added experimental usage of full BC and HLC for - * speech, 3.1kHz audio, fax gr.2/3 - * - * Revision 1.2 1999/01/04 13:19:29 armin - * Channel status with listen-request wrong - fixed. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -161,25 +32,14 @@ #include "eicon.h" #include "eicon_idi.h" #include "eicon_dsp.h" +#include "uxio.h" #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.33 $"; +char *eicon_idi_revision = "$Revision: 1.41.6.1 $"; eicon_manifbuf *manbuf; -static char BC_Speech[3] = { 0x80, 0x90, 0xa3 }; -static char BC_31khz[3] = { 0x90, 0x90, 0xa3 }; -static char BC_64k[2] = { 0x88, 0x90 }; -static char BC_video[3] = { 0x91, 0x90, 0xa5 }; - -#ifdef EICON_FULL_SERVICE_OKTETT -/* -static char HLC_telephony[2] = { 0x91, 0x81 }; -*/ -static char HLC_faxg3[2] = { 0x91, 0x84 }; -#endif - int eicon_idi_manage_assign(eicon_card *card); int eicon_idi_manage_remove(eicon_card *card); int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer); @@ -209,7 +69,7 @@ reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0; + reqbuf->ReqId = DSIG_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ } @@ -221,6 +81,9 @@ reqbuf->XBuffer.P[l++] = LLC; reqbuf->XBuffer.P[l++] = 2; switch(chan->l2prot) { + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; @@ -262,7 +125,7 @@ reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0x20; + reqbuf->ReqId = NL_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 1; /* Net Entity */ } @@ -282,6 +145,21 @@ } int +idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan) +{ + reqbuf->Req = SUSPEND; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.P[0] = CAI; + reqbuf->XBuffer.P[1] = 1; + reqbuf->XBuffer.P[2] = chan->No; + reqbuf->XBuffer.P[3] = 0; + reqbuf->XBuffer.length = 4; + reqbuf->Reference = 0; /* Sig Entity */ + return(0); +} + +int idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) { int l = 9; @@ -295,7 +173,7 @@ reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 3; + reqbuf->XBuffer.P[7] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -391,6 +269,12 @@ case HANGUP: idi_put_req(reqbuf, HANGUP, 0, 0); break; + case SUSPEND: + idi_put_suspend_req(reqbuf, chan); + break; + case RESUME: + idi_put_req(reqbuf, RESUME, 0 ,0); + break; case REJECT: idi_put_req(reqbuf, REJECT, 0 ,0); break; @@ -400,17 +284,20 @@ case CALL_RES: idi_call_res_req(reqbuf, chan); break; - case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); + case CALL_HOLD: + idi_put_req(reqbuf, CALL_HOLD, 0, 0); + break; + case N_CONNECT|0x700: + idi_put_req(reqbuf, N_CONNECT, 1, 0); break; - case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); + case N_CONNECT_ACK|0x700: + idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0); break; - case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); + case N_DISC|0x700: + idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh); break; - case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); + case N_DISC_ACK|0x700: + idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -492,7 +379,7 @@ if ((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) { - if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1); + if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1); } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { @@ -508,6 +395,32 @@ } int +capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm) +{ + if ((cm->para[0] != 3) || (cm->para[1] != 0)) + return -1; + if (cm->para[2] < 3) + return -1; + if (cm->para[4] != 0) + return -1; + switch(cm->para[3]) { + case 4: /* Suspend */ + eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No); + if (cm->para[5]) { + idi_do_req(card, chan, SUSPEND, 0); + } else { + idi_do_req(card, chan, CALL_HOLD, 0); + } + break; + case 5: /* Resume */ + eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No); + idi_do_req(card, chan, RESUME, 0); + break; + } + return 0; +} + +int idi_connect_res(eicon_card *card, eicon_chan *chan) { if ((!card) || (!chan)) @@ -612,7 +525,14 @@ reqbuf->XBuffer.P[l++] = *sub++ & 0x7f; } - if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { + if (si2 > 2) { + reqbuf->XBuffer.P[l++] = SHIFT|6; + reqbuf->XBuffer.P[l++] = SIN; + reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = si1; + reqbuf->XBuffer.P[l++] = si2; + } + else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { reqbuf->XBuffer.P[l++] = BC; reqbuf->XBuffer.P[l++] = tmp; for(i=0; iXBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 32; - reqbuf->XBuffer.P[l++] = 3; + reqbuf->XBuffer.P[l++] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -859,7 +779,7 @@ } for(i=0; i < wlen; i++) message->llc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0], + eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0], message->llc[1],message->llc[2],message->llc[3]); break; case HLC: @@ -869,7 +789,7 @@ } for(i=0; i < wlen; i++) message->hlc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No, + eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No, message->hlc[0], message->hlc[1], message->hlc[2], message->hlc[3], message->hlc[4]); break; @@ -1061,31 +981,55 @@ } void -idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2) +idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2) { - si1[0] = 0; - si2[0] = 0; - if (memcmp(bc, BC_Speech, 3) == 0) { /* Speech */ - si1[0] = 1; + si1[0] = 0; + si2[0] = 0; + + switch (bc[0] & 0x7f) { + case 0x00: /* Speech */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 1; + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_31khz, 3) == 0) { /* 3.1kHz audio */ - si1[0] = 1; + break; + case 0x10: /* 3.1 Khz audio */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 2; - if (memcmp(hlc, HLC_faxg3, 2) == 0) { /* Fax Gr.2/3 */ - si1[0] = 2; - } + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_64k, 2) == 0) { /* unrestricted 64 kbits */ - si1[0] = 7; - } - if (memcmp(bc, BC_video, 3) == 0) { /* video */ - si1[0] = 4; - } + break; + case 0x08: /* Unrestricted digital information */ + si1[0] = 7; + si2[0] = sin[1]; + break; + case 0x09: /* Restricted digital information */ + si1[0] = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + si1[0] = 3; + break; + case 0x18: /* Video */ + si1[0] = 4; + break; + } + switch (bc[1] & 0x7f) { + case 0x40: /* packed mode */ + si1[0] = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + /* moderate = bc[1] & 0x7f; */ + break; + } } /********************* FAX stuff ***************************/ @@ -1225,7 +1169,7 @@ reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_EDATA; + reqbuf->Req = N_EDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -1359,7 +1303,7 @@ eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength); break; } - idi_send_data(card, chan, 0, skb, 0); + idi_send_data(card, chan, 0, skb, 0, 0); } void @@ -1913,7 +1857,7 @@ OutBuf->Len = 0; OutBuf->Next = OutBuf->Data; - return(idi_send_data(ccard, chan, 0, skb, 1)); + return(idi_send_data(ccard, chan, 0, skb, 1, 0)); } int @@ -1958,6 +1902,8 @@ if (chan->queued + skb->len > 1200) return 0; + if (chan->pqueued > 1) + return 0; InBuf.Data = skb->data; InBuf.Size = skb->len; @@ -2183,6 +2129,7 @@ } if ((chan->fax->code > 1) && (chan->fax->code < 120)) chan->fax->code += 120; + eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code); chan->fax->r_code = ISDN_TTY_FAX_HNG; cmd.driver = ccard->myid; cmd.command = ISDN_STAT_FAXIND; @@ -2224,7 +2171,7 @@ reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_UDATA; + reqbuf->Req = N_UDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -2418,12 +2365,12 @@ while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (message.e_cau[0] & 0x7f) { cmd.driver = ccard->myid; cmd.arg = chan->No; @@ -2433,10 +2380,6 @@ ccard->interface.statcallb(&cmd); } chan->cause[0] = 0; -#ifdef CONFIG_ISDN_TTY_FAX - if (!chan->e.B2Id) - chan->fax = 0; -#endif if (((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) || ((chan->l2prot == ISDN_PROTO_L2_FAX) && @@ -2446,6 +2389,7 @@ if (chan->e.B2Id) idi_do_req(ccard, chan, REMOVE, 1); chan->statectrl &= ~WAITING_FOR_HANGUP; + chan->statectrl &= ~IN_HOLD; if (chan->statectrl & HAVE_CONN_REQ) { eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No); chan->statectrl &= ~HAVE_CONN_REQ; @@ -2463,6 +2407,9 @@ cmd.command = ISDN_STAT_DHUP; ccard->interface.statcallb(&cmd); eicon_idi_listen_req(ccard, chan); +#ifdef CONFIG_ISDN_TTY_FAX + chan->fax = 0; +#endif } } break; @@ -2475,7 +2422,7 @@ break; } chan->fsm_state = EICON_STATE_ICALL; - idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2); + idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2); strcpy(chan->cpn, message.cpn + 1); strcpy(chan->oad, message.oad); strcpy(chan->dsa, message.dsa); @@ -2553,12 +2500,15 @@ case ISDN_PROTO_L2_MODEM: /* do nothing, wait for connect */ break; + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); break; - default: + default:; /* On most incoming calls we use automatic connect */ - /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ + /* idi_do_req(ccard, chan, N_CONNECT, 1); */ } } else { if (chan->fsm_state != EICON_STATE_ACTIVE) @@ -2568,33 +2518,50 @@ case CALL_CON: eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No); if (chan->fsm_state == EICON_STATE_OCALL) { - chan->fsm_state = EICON_STATE_OBWAIT; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DCONN; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - /* check if old NetID has been removed */ if (chan->e.B2Id) { eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n", chan->No, chan->e.B2Id); idi_do_req(ccard, chan, REMOVE, 1); } - - idi_do_req(ccard, chan, ASSIGN, 1); - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { - if (chan->fax) + if (chan->fax) { chan->fax->phase = ISDN_FAX_PHASE_A; + } else { + eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n"); + idi_hangup(ccard, chan); + break; + } } #endif + chan->fsm_state = EICON_STATE_OBWAIT; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + + idi_do_req(ccard, chan, ASSIGN, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); } else - idi_hangup(ccard, chan); + idi_hangup(ccard, chan); break; case AOC_IND: eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No); break; + case CALL_HOLD_ACK: + chan->statectrl |= IN_HOLD; + eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No); + break; + case SUSPEND_REJ: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No); + break; + case SUSPEND: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No); + break; + case RESUME: + eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No); + break; default: eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind); } @@ -2613,7 +2580,7 @@ } else switch(ind->Ind) { - case IDI_N_CONNECT_ACK: + case N_CONNECT_ACK: eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No); if (chan->l2prot == ISDN_PROTO_L2_MODEM) { chan->fsm_state = EICON_STATE_WMCONN; @@ -2634,7 +2601,7 @@ } } else { - eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n"); + eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n"); } #endif break; @@ -2646,10 +2613,10 @@ strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_CONNECT: + case N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); chan->e.IndCh = ind->IndCh; - if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); + if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; } @@ -2664,43 +2631,47 @@ strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_DISC: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No); + case N_DISC: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No); if (chan->e.B2Id) { while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1); + idi_do_req(ccard, chan, N_DISC_ACK, 1); idi_do_req(ccard, chan, REMOVE, 1); } #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { + if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); idi_fax_hangup(ccard, chan); } #endif chan->e.IndCh = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); - idi_do_req(ccard, chan, HANGUP, 0); + spin_unlock_irqrestore(&eicon_lock, flags); + if (!(chan->statectrl & IN_HOLD)) { + idi_do_req(ccard, chan, HANGUP, 0); + } if (chan->fsm_state == EICON_STATE_ACTIVE) { cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BHUP; cmd.arg = chan->No; ccard->interface.statcallb(&cmd); chan->fsm_state = EICON_STATE_NULL; - chan->statectrl |= WAITING_FOR_HANGUP; + if (!(chan->statectrl & IN_HOLD)) { + chan->statectrl |= WAITING_FOR_HANGUP; + } } #ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0; #endif break; - case IDI_N_DISC_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No); + case N_DISC_ACK: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); @@ -2708,10 +2679,10 @@ } #endif break; - case IDI_N_DATA_ACK: - eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + case N_DATA_ACK: + eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No); break; - case IDI_N_DATA: + case N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len); if (chan->l2prot == ISDN_PROTO_L2_FAX) { @@ -2723,11 +2694,11 @@ free_buff = 0; } break; - case IDI_N_UDATA: + case N_UDATA: idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #ifdef CONFIG_ISDN_TTY_FAX - case IDI_N_EDATA: + case N_EDATA: idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #endif @@ -2747,6 +2718,8 @@ { ulong flags; isdn_ctrl cmd; + int tqueued = 0; + int twaitpq = 0; if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { /* I dont know why this happens, should not ! */ @@ -2770,16 +2743,15 @@ eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); ccard->IdTable[ack->RcId] = NULL; - eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, - ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); if (!chan->e.ReqCh) chan->e.D3Id = 0; else chan->e.B2Id = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, + ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); return 1; } @@ -2790,25 +2762,21 @@ } else { /* Network layer */ switch(chan->e.Req & 0x0f) { - case IDI_N_CONNECT: + case N_CONNECT: chan->e.IndCh = ack->RcCh; eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); break; - case IDI_N_MDATA: - case IDI_N_DATA: - if ((chan->e.Req & 0x0f) == IDI_N_DATA) { - if (chan->queued) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BSENT; - cmd.arg = chan->No; - cmd.parm.length = chan->waitpq; - ccard->interface.statcallb(&cmd); - } - save_flags(flags); - cli(); + case N_MDATA: + case N_DATA: + tqueued = chan->queued; + twaitpq = chan->waitpq; + if ((chan->e.Req & 0x0f) == N_DATA) { + spin_lock_irqsave(&eicon_lock, flags); chan->waitpq = 0; - restore_flags(flags); + if(chan->pqueued) + chan->pqueued--; + spin_unlock_irqrestore(&eicon_lock, flags); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { if (((chan->queued - chan->waitq) < 1) && @@ -2828,11 +2796,17 @@ } #endif } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued -= chan->waitq; if (chan->queued < 0) chan->queued = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) { + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BSENT; + cmd.arg = chan->No; + cmd.parm.length = twaitpq; + ccard->interface.statcallb(&cmd); + } break; default: eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, @@ -2858,11 +2832,10 @@ return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ack->RcId]) != NULL) dCh = chan->No; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); switch (ack->Rc) { case OK_FC: @@ -2890,8 +2863,7 @@ eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n", chan->No, chan->e.D3Id, chan->e.B2Id); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); for(j = 0; j < ccard->nchannels + 1; j++) { if ((ccard->bch[j].e.ref == ack->Reference) && (ccard->bch[j].e.Req == ASSIGN)) { @@ -2901,12 +2873,12 @@ ccard->bch[j].e.B2Id = ack->RcId; ccard->IdTable[ack->RcId] = &ccard->bch[j]; chan = &ccard->bch[j]; - eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, - ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); break; } - } - restore_flags(flags); + } + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, + ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); if (j > ccard->nchannels) { eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", ack->Reference, ack->RcId); @@ -2917,6 +2889,7 @@ case UNKNOWN_COMMAND: case WRONG_COMMAND: case WRONG_ID: + case ADAPTER_DEAD: case WRONG_CH: case UNKNOWN_IE: case WRONG_IE: @@ -2949,19 +2922,18 @@ ccard->interface.statcallb(&cmd); } } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if (chan) { chan->e.ref = 0; chan->e.busy = 0; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); dev_kfree_skb(skb); eicon_schedule_tx(ccard); } int -idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que) +idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk) { struct sk_buff *xmit_skb; struct sk_buff *skb2; @@ -2985,13 +2957,14 @@ return -1; if (!len) return 0; - if (chan->queued + len > EICON_MAX_QUEUE) + + if ((chk) && (chan->pqueued > 1)) return 0; - eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len); + eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n", + chan->No, len, chan->pqueued); - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while(offset < len) { plen = ((len - offset) > 270) ? 270 : len - offset; @@ -3000,7 +2973,7 @@ skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); if ((!xmit_skb) || (!skb2)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No); if (xmit_skb) dev_kfree_skb(skb); @@ -3013,13 +2986,10 @@ chan2->ptr = chan; reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); - if (((len - offset) > 270) && - (chan->l2prot != ISDN_PROTO_L2_MODEM) && - (chan->l2prot != ISDN_PROTO_L2_FAX) && - (chan->l2prot != ISDN_PROTO_L2_TRANS)) { - reqbuf->Req = IDI_N_MDATA; + if ((len - offset) > 270) { + reqbuf->Req = N_MDATA; } else { - reqbuf->Req = IDI_N_DATA; + reqbuf->Req = N_DATA; /* if (ack) reqbuf->Req |= N_D_BIT; */ } reqbuf->ReqCh = chan->e.IndCh; @@ -3033,9 +3003,11 @@ offset += plen; } - if (que) + if (que) { chan->queued += len; - restore_flags(flags); + chan->pqueued++; + } + spin_unlock_irqrestore(&eicon_lock, flags); eicon_schedule_tx(card); dev_kfree_skb(skb); return len; @@ -3073,7 +3045,7 @@ reqbuf->XBuffer.P[0] = 0; reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0xe0; + reqbuf->ReqId = MAN_ID; reqbuf->XBuffer.length = 1; reqbuf->Reference = 2; /* Man Entity */ @@ -3199,7 +3171,7 @@ reqbuf->XBuffer.P[1] = manbuf->length[0] + 1; reqbuf->XBuffer.P[l++] = 0; - reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */ + reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; reqbuf->XBuffer.length = l; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_idi.h linux/drivers/isdn/eicon/eicon_idi.h --- v2.2.18/drivers/isdn/eicon/eicon_idi.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_idi.h Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for the Eicon active cards. * IDI-Interface @@ -20,168 +20,30 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.h,v $ - * Revision 1.9 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.8 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.7 1999/08/22 20:26:46 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:04 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/07/11 17:16:26 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.4 1999/03/29 11:19:44 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:18 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:42 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * * */ -#ifndef IDI_H -#define IDI_H +#ifndef E_IDI_H +#define E_IDI_H #include -#define ASSIGN 0x01 -#define REMOVE 0xff - -#define CALL_REQ 1 /* call request */ -#define CALL_CON 1 /* call confirmation */ -#define CALL_IND 2 /* incoming call connected */ -#define LISTEN_REQ 2 /* listen request */ -#define HANGUP 3 /* hangup request/indication */ -#define SUSPEND 4 /* call suspend request/confirm */ -#define RESUME 5 /* call resume request/confirm */ -#define SUSPEND_REJ 6 /* suspend rejected indication */ -#define USER_DATA 8 /* user data for user to user signaling */ -#define CONGESTION 9 /* network congestion indication */ -#define INDICATE_REQ 10 /* request to indicate an incoming call */ -#define INDICATE_IND 10 /* indicates that there is an incoming call */ -#define CALL_RES 11 /* accept an incoming call */ -#define CALL_ALERT 12 /* send ALERT for incoming call */ -#define INFO_REQ 13 /* INFO request */ -#define INFO_IND 13 /* INFO indication */ -#define REJECT 14 /* reject an incoming call */ -#define RESOURCES 15 /* reserve B-Channel hardware resources */ -#define TEL_CTRL 16 /* Telephone control request/indication */ -#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ -#define FAC_REG_REQ 18 /* connection idependent fac registration */ -#define FAC_REG_ACK 19 /* fac registration acknowledge */ -#define FAC_REG_REJ 20 /* fac registration reject */ -#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ -#define AOC_IND 26/* Advice of Charge */ - -#define IDI_N_MDATA (0x01) -#define IDI_N_CONNECT (0x02) -#define IDI_N_CONNECT_ACK (0x03) -#define IDI_N_DISC (0x04) -#define IDI_N_DISC_ACK (0x05) -#define IDI_N_RESET (0x06) -#define IDI_N_RESET_ACK (0x07) -#define IDI_N_DATA (0x08) -#define IDI_N_EDATA (0x09) -#define IDI_N_UDATA (0x0a) -#define IDI_N_BDATA (0x0b) -#define IDI_N_DATA_ACK (0x0c) -#define IDI_N_EDATA_ACK (0x0d) - -#define N_Q_BIT 0x10 /* Q-bit for req/ind */ -#define N_M_BIT 0x20 /* M-bit for req/ind */ -#define N_D_BIT 0x40 /* D-bit for req/ind */ - - -#define SHIFT 0x90 /* codeset shift */ -#define MORE 0xa0 /* more data */ -#define CL 0xb0 /* congestion level */ - - /* codeset 0 */ - -#define BC 0x04 /* Bearer Capability */ -#define CAU 0x08 /* cause */ -#define CAD 0x0c /* Connected address */ -#define CAI 0x10 /* call identity */ -#define CHI 0x18 /* channel identification */ -#define LLI 0x19 /* logical link id */ -#define CHA 0x1a /* charge advice */ -#define FTY 0x1c -#define PI 0x1e /* Progress Indicator */ -#define NI 0x27 /* Notification Indicator */ -#define DT 0x29 /* ETSI date/time */ -#define KEY 0x2c /* keypad information element */ -#define DSP 0x28 /* display */ -#define OAD 0x6c /* origination address */ -#define OSA 0x6d /* origination sub-address */ -#define CPN 0x70 /* called party number */ -#define DSA 0x71 /* destination sub-address */ -#define RDN 0x74 /* redirecting number */ -#define LLC 0x7c /* low layer compatibility */ -#define HLC 0x7d /* high layer compatibility */ -#define UUI 0x7e /* user user information */ -#define ESC 0x7f /* escape extension */ - -#define DLC 0x20 /* data link layer configuration */ -#define NLC 0x21 /* network layer configuration */ - - /* codeset 6 */ - -#define SIN 0x01 /* service indicator */ -#define CIF 0x02 /* charging information */ -#define DATE 0x03 /* date */ -#define CPS 0x07 /* called party status */ - -/*------------------------------------------------------------------*/ -/* return code coding */ -/*------------------------------------------------------------------*/ - -#define UNKNOWN_COMMAND 0x01 /* unknown command */ -#define WRONG_COMMAND 0x02 /* wrong command */ -#define WRONG_ID 0x03 /* unknown task/entity id */ -#define WRONG_CH 0x04 /* wrong task/entity id */ -#define UNKNOWN_IE 0x05 /* unknown information el. */ -#define WRONG_IE 0x06 /* wrong information el. */ -#define OUT_OF_RESOURCES 0x07 /* card out of res. */ -#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ -#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ -#define ASSIGN_OK 0xef /* ASSIGN OK */ -#define OK_FC 0xfc /* Flow-Control RC */ -#define READY_INT 0xfd /* Ready interrupt */ -#define TIMER_INT 0xfe /* timer interrupt */ -#define OK 0xff /* command accepted */ +#undef N_DATA +#undef ID_MASK + +#include "pc.h" -/*------------------------------------------------------------------*/ +#define AOC_IND 26 /* Advice of Charge */ +#define PI 0x1e /* Progress Indicator */ +#define NI 0x27 /* Notification Indicator */ + +#define CALL_HOLD 0x22 +#define CALL_HOLD_ACK 0x24 /* defines for statectrl */ #define WAITING_FOR_HANGUP 0x01 #define HAVE_CONN_REQ 0x02 +#define IN_HOLD 0x04 typedef struct { char cpn[32]; @@ -242,26 +104,6 @@ } eicon_IND; typedef struct { - __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ - __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ - __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ - __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ - __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ - __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ - __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ - __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ - __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ - __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ - __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ - __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ - __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ - __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ - __u8 B[1]; /* buffer space for Req,Ind and Rc */ -} eicon_pr_ram; - -typedef struct { __u8 *Data; unsigned int Size; unsigned int Len; @@ -278,8 +120,9 @@ extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb); extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb); extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb); -extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que); +extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk); extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value); +extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm); #ifdef CONFIG_ISDN_TTY_FAX extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan); extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c --- v2.2.18/drivers/isdn/eicon/eicon_io.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_io.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_io.c,v 1.13.6.1 2001/02/16 09:09:50 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. @@ -6,7 +6,7 @@ * Copyright 1999,2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * * This program is free software; you can redistribute it and/or modify @@ -23,52 +23,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_io.c,v $ - * Revision 1.10 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.9 1999/11/18 20:55:25 armin - * Ready_Int fix of ISA cards. - * - * Revision 1.8 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.7 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.6 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.5 1999/08/31 11:20:11 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.4 1999/08/22 20:26:47 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.3 1999/08/18 20:17:01 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.2 1999/07/25 15:12:05 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.1 1999/03/29 11:19:45 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * */ #include #include "eicon.h" +#include "uxio.h" void eicon_io_rcv_dispatch(eicon_card *ccard) { @@ -85,12 +45,12 @@ while((skb = skb_dequeue(&ccard->rcvq))) { ind = (eicon_IND *)skb->data; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + spin_unlock_irqrestore(&eicon_lock, flags); if (DebugVar & 1) { switch(ind->Ind) { - case IDI_N_DISC_ACK: + case N_DISC_ACK: /* doesn't matter if this happens */ break; default: @@ -99,11 +59,10 @@ ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } } - restore_flags(flags); dev_kfree_skb(skb); continue; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (chan->e.complete) { /* check for rec-buffer chaining */ if (ind->MLength == ind->RBuffer.length) { @@ -119,12 +78,9 @@ } } else { - save_flags(flags); - cli(); if (!(skb2 = skb_dequeue(&chan->e.R))) { chan->e.complete = 1; eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n"); - restore_flags(flags); dev_kfree_skb(skb); continue; } @@ -133,7 +89,6 @@ GFP_ATOMIC); if (!skb_new) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n"); - restore_flags(flags); dev_kfree_skb(skb); dev_kfree_skb(skb2); continue; @@ -152,14 +107,12 @@ dev_kfree_skb(skb2); if (ind->MLength == ind->RBuffer.length) { chan->e.complete = 2; - restore_flags(flags); idi_handle_ind(ccard, skb_new); continue; } else { chan->e.complete = 0; skb_queue_tail(&chan->e.R, skb_new); - restore_flags(flags); continue; } } @@ -181,242 +134,120 @@ /* - * IO-Functions for different card-types + * IO-Functions for ISA cards */ u8 ram_inb(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inb((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readb(addr)); - } - return(0); + return(readb(addr)); } u16 ram_inw(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inw((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readw(addr)); - } - return(0); + return(readw(addr)); } void ram_outb(eicon_card *card, void *adr, u8 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outb((u8)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writeb(data, addr); - break; - } + writeb(data, addr); } void ram_outw(eicon_card *card, void *adr , u16 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outw((u16)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writew(data, addr); - break; - } + writew(data, addr); } void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - writeb(ram_inb(card, adr + i), adrto + i); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_fromio(adrto, adr, len); - break; - } + memcpy_fromio(adrto, adr, len); } void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - ram_outb(card, adrto + i, readb(adr + i)); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_toio(adrto, adr, len); - break; - } + memcpy_toio(adrto, adr, len); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * XLOG + * IDI-Callback function */ -int -eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq) +void +eicon_idi_callback(ENTITY *de) { - int timeout, i; - int divas_shared_offset = 0; + eicon_card *ccard = (eicon_card *)de->R; + struct sk_buff *skb; + eicon_RC *ack; + eicon_IND *ind; int len = 0; - int stype = 0; - __u32 time = 0; - mi_pc_maint_t *pcm = &xlogreq->pcm; - eicon_pci_card *pci_card = &card->hwif.pci; - eicon_isa_card *isa_card = &card->hwif.isa; - eicon_pr_ram *prram = 0; - char *ram; - switch(card->type) { - case EICON_CTYPE_MAESTRAP: - ram = (char *)pci_card->PCIram; - prram = (eicon_pr_ram *)ram; - divas_shared_offset = DIVAS_SHARED_OFFSET; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_MAESTRA: - prram = 0; - divas_shared_offset = 0; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - case EICON_CTYPE_S2M: - prram = (eicon_pr_ram *)isa_card->shmem; - divas_shared_offset = 0xfb80; - len = sizeof(mi_pc_maint_t) - 78; - stype = 1; - break; - default: - return -ENODEV; - } - - memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t)); - - xlogreq->pcm.rc = 0; - xlogreq->pcm.req = 1; /* DO_LOG */ - - ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset; - - ram_outb(card, ram+1, pcm->rc); - ram_outb(card, ram+0, pcm->req); - - timeout = jiffies + 50; - while (timeout > jiffies) { - pcm->rc = ram_inb(card, ram+1); - pcm->req = ram_inb(card, ram+0); - if (!pcm->req) break; - SLEEP(10); - } - - if (pcm->req) { - return XLOG_ERR_TIMEOUT; - } - - if (pcm->rc != OK) { - return XLOG_ERR_DONE; - } - - ram_copyfromcard(card, pcm, ram, len); - - if (stype) { - for (i=0; i<8; i++) - ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i]; - time = (__u32)pcm->data.w[2] * 3600 * 1000 + - (__u32)pcm->data.w[1] * 1000 + - (__u32)pcm->data.b[1] * 20 + - (__u32)pcm->data.b[0] ; - pcm->data.w[1] = (__u16) (time >> 16); - pcm->data.w[2] = (__u16) (time & 0x0000ffff); - pcm->data.w[0] = 2; + if (de->complete == 255) { + /* Return Code */ + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = de->Rc; + if (de->Rc == ASSIGN_OK) { + ack->RcId = de->Id; + de->user[1] = de->Id; + } else { + ack->RcId = de->user[1]; + } + ack->RcCh = de->RcCh; + ack->Reference = de->user[0]; + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Rc, ack->RcId, de->RLength, de->complete); + } + } else { + /* Indication */ + if (de->complete) { + len = de->RLength; + } else { + len = 270; + if (de->RLength <= 270) + eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n"); + } + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = de->Ind; + ind->IndId = de->user[1]; + ind->IndCh = de->IndCh; + ind->MInd = de->Ind; + ind->RBuffer.length = len; + ind->MLength = de->RLength; + memcpy(&ind->RBuffer.P, &de->RBuffer->P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Ind, ind->IndId, de->RLength, de->complete); + } } - return XLOG_OK; + de->RNum = 0; + de->RNR = 0; + de->Rc = 0; + de->Ind = 0; } +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ /* * Transmit-Function */ void eicon_io_transmit(eicon_card *ccard) { - eicon_pci_card *pci_card; eicon_isa_card *isa_card; struct sk_buff *skb; struct sk_buff *skb2; unsigned long flags; - char *ram, *reg, *cfg; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_REQ *ReqOut = 0; @@ -426,10 +257,11 @@ int ReqCount; int scom = 0; int tmp = 0; + int tmpid = 0; int quloop = 1; int dlev = 0; + ENTITY *ep = 0; - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; if (!ccard) { @@ -451,20 +283,17 @@ prram = (eicon_pr_ram *)isa_card->shmem; break; #endif +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = (eicon_pr_ram *)ram; + scom = 2; + break; + case EICON_CTYPE_MAESTRAQ: + scom = 2; break; case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = 0; + scom = 2; break; +#endif default: eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n"); return; @@ -474,69 +303,91 @@ if (!(skb2 = skb_dequeue(&ccard->sndq))) quloop = 0; while(quloop) { - save_flags(flags); - cli(); - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + switch (scom) { + case 1: if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) { if (!ccard->ReadyInt) { tmp = ram_inb(ccard, &com->ReadyInt) + 1; ram_outb(ccard, &com->ReadyInt, tmp); ccard->ReadyInt++; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } - } else { + break; + case 0: if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } + break; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + chan2 = (eicon_chan_ptr *)skb2->data; chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { - save_flags(flags); - cli(); + reqbuf = (eicon_REQ *)skb->data; if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); } else { - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + + switch (scom) { + case 1: ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh); - - } else { + break; + case 0: /* get address of next available request buffer */ ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)]; ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh); ram_outb(ccard, &ReqOut->Req, reqbuf->Req); + break; } + dlev = 160; + if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ - if (scom) + switch (scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.D3Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); - + break; + case 2: + ep = &chan->de; + break; + } + tmpid = chan->e.D3Id; chan->e.ReqCh = 0; } else { /* Net Layer */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.B2Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); - + break; + case 2: + ep = &chan->be; + break; + } + tmpid = chan->e.B2Id; chan->e.ReqCh = 1; if (((reqbuf->Req & 0x0f) == 0x08) || ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ @@ -548,51 +399,106 @@ } else { /* It is an ASSIGN */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, reqbuf->ReqId); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); + break; + case 2: + if (!reqbuf->Reference) + ep = &chan->de; + else + ep = &chan->be; + ep->Id = reqbuf->ReqId; + break; + } + tmpid = reqbuf->ReqId; if (!reqbuf->Reference) chan->e.ReqCh = 0; else chan->e.ReqCh = 1; } - if (scom) + + switch(scom) { + case 1: chan->e.ref = ccard->ref_out++; - else + break; + case 0: chan->e.ref = ram_inw(ccard, &ReqOut->Reference); + break; + case 2: + chan->e.ref = chan->No; + break; + } chan->e.Req = reqbuf->Req; ReqCount++; - if (scom) + + switch (scom) { + case 1: ram_outb(ccard, &com->Req, reqbuf->Req); - else + break; + case 0: ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); + break; + case 2: +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (!ep) break; + ep->callback = eicon_idi_callback; + ep->R = (BUFFERS *)ccard; + ep->user[0] = (word)chan->No; + ep->user[1] = (word)tmpid; + ep->XNum = 1; + ep->RNum = 0; + ep->RNR = 0; + ep->Rc = 0; + ep->Ind = 0; + ep->X->PLength = reqbuf->XBuffer.length; + memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); + ep->ReqCh = reqbuf->ReqCh; + ep->Req = reqbuf->Req; +#endif + break; + } chan->e.busy = 1; + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", - reqbuf->Req, - (scom) ? ram_inb(ccard, &com->ReqId) : - ram_inb(ccard, &ReqOut->ReqId), + reqbuf->Req, tmpid, reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (scom == 2) { + if (ep) { + ccard->d->request(ep); + if (ep->Rc) + eicon_idi_callback(ep); + } + } +#endif } - restore_flags(flags); dev_kfree_skb(skb); } dev_kfree_skb(skb2); } else { - skb_queue_tail(&ccard->sackq, skb2); - eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); + skb_queue_tail(&ccard->sackq, skb2); + eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); } - if (scom) - quloop = 0; - else - if (!(skb2 = skb_dequeue(&ccard->sndq))) + switch(scom) { + case 1: quloop = 0; + break; + case 0: + case 2: + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + break; + } } if (!scom) @@ -603,18 +509,14 @@ } } - +#ifdef CONFIG_ISDN_DRV_EICON_ISA /* * IRQ handler */ void eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { eicon_card *ccard = (eicon_card *)dev_id; - eicon_pci_card *pci_card; eicon_isa_card *isa_card; - char *ram = 0; - char *reg = 0; - char *cfg = 0; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_RC *RcIn; @@ -646,11 +548,9 @@ } } - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -664,23 +564,6 @@ prram = (eicon_pr_ram *)isa_card->shmem; irqprobe = &isa_card->irqprobe; break; -#endif - case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = (eicon_pr_ram *)ram; - break; - case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = 0; - break; default: eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n"); return; @@ -688,7 +571,6 @@ if (*irqprobe) { switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -706,26 +588,11 @@ } (*irqprobe)++; break; -#endif - case EICON_CTYPE_MAESTRAP: - if (readb(&ram[0x3fe])) { - writeb(0, &prram->RcOutput); - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - } - *irqprobe = 0; - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - *irqprobe = 0; - break; } return; } switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -736,20 +603,6 @@ return; } break; -#endif - case EICON_CTYPE_MAESTRAP: - if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; - case EICON_CTYPE_MAESTRA: - outw(0x3fe, pci_card->PCIreg + M_ADDR); - if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; } if (scom) { @@ -891,7 +744,6 @@ /* clear interrupt */ switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_QUADRO: writeb(0, isa_card->intack); writeb(0, &com[0x401]); @@ -902,19 +754,8 @@ case EICON_CTYPE_S2M: writeb(0, isa_card->intack); break; -#endif - case EICON_CTYPE_MAESTRAP: - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - outw(0x3fe, pci_card->PCIreg + M_ADDR); - outb(0, pci_card->PCIreg + M_DATA); - break; } return; } - +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c --- v2.2.18/drivers/isdn/eicon/eicon_isa.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_isa.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -21,62 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.c,v $ - * Revision 1.14 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.13 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.12 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.11 1999/11/25 11:33:09 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * - * Revision 1.10 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.9 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.8 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.7 1999/08/22 20:26:48 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:06 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/04/01 12:48:33 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:46 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:19 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:43 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -87,7 +31,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.14 $"; +char *eicon_isa_revision = "$Revision: 1.16 $"; #undef EICON_MCA_DEBUG @@ -354,7 +298,7 @@ printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) { tmp = eicon_addcard(card->type, card->physmem, card->irq, - ((eicon_card *)card->card)->regname); + ((eicon_card *)card->card)->regname, 0); printk(KERN_INFO "Eicon: %d adapters added\n", tmp); } return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_isa.h linux/drivers/isdn/eicon/eicon_isa.h --- v2.2.18/drivers/isdn/eicon/eicon_isa.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_isa.h Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,38 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.h,v $ - * Revision 1.8 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.7 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.6 1999/11/15 19:37:04 keil - * need config.h - * - * Revision 1.5 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.4 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.3 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:46 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_isa_h @@ -138,7 +106,6 @@ unsigned char mvalid; /* Flag: Memory is valid */ unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card ist Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_isa_card; /* Offsets for special locations on standard cards */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.2.18/drivers/isdn/eicon/eicon_mod.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_mod.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_mod.c,v 1.37.6.4 2001/02/16 09:09:50 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -6,11 +6,9 @@ * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax * capabilities with Diva Server cards. @@ -30,105 +28,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_mod.c,v $ - * Revision 1.25 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.24 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.23 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.22 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.21 1999/11/25 11:35:10 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * Minor cleanup. - * - * Revision 1.20 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.19 1999/11/12 13:21:44 armin - * Bugfix of undefined reference with CONFIG_MCA - * - * Revision 1.18 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.17 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.16 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.15 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.14 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.13 1999/09/04 17:37:59 armin - * Removed not used define, did not work and caused error - * in 2.3.16 - * - * Revision 1.12 1999/08/31 11:20:14 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.11 1999/08/29 17:23:45 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/28 21:32:53 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.9 1999/08/18 20:17:02 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:08 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:27 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:26 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/04/01 12:48:35 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:47 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:21 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ -#define DRIVERPATCH "" +#define DRIVERNAME "Eicon active ISDN driver" +#define DRIVERRELEASE "2.0" +#define DRIVERPATCH ".16" + #include #include @@ -139,17 +44,27 @@ #include "eicon.h" +#include "../avmb1/capicmd.h" /* this should be moved in a common place */ + +#undef N_DATA +#include "adapter.h" +#include "uxio.h" + #define INCLUDE_INLINE_FUNCS static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.25 $"; +static char *eicon_revision = "$Revision: 1.37.6.4 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; extern char *eicon_idi_revision; +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern void eicon_pci_init_conf(eicon_card *card); + #ifdef MODULE #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) #endif @@ -158,6 +73,10 @@ ulong DebugVar; +spinlock_t eicon_lock; + +DESCRIPTOR idi_d[32]; + /* Parameters to be set by insmod */ #ifdef CONFIG_ISDN_DRV_EICON_ISA static int membase = -1; @@ -189,23 +108,6 @@ "DIVA Server PRI/PCI" }; -static int -getrel(char *p) -{ - int v = 0; - char *tmp = 0; - - if ((tmp = strchr(p, '.'))) - p = tmp + 1; - while (p[0] >= '0' && p[0] <= '9') { - v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0'); - p++; - } - return v; - - -} - static char * eicon_getrev(const char *revision) { @@ -229,68 +131,26 @@ return NULL; } +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * Free MSN list + * Find pcicard with given card number */ -static void -eicon_clear_msn(eicon_card *card) +static inline eicon_card * +eicon_findnpcicard(int driverid) { - struct msn_entry *p = card->msn_list; - struct msn_entry *q; - unsigned long flags; + eicon_card *p = cards; - save_flags(flags); - cli(); - card->msn_list = NULL; - restore_flags(flags); while (p) { - q = p->next; - kfree(p); - p = q; + if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) && + (p->bus == EICON_BUS_PCI)) + return p; + p = p->next; } + return (eicon_card *) 0; } - -/* - * Find an MSN entry in the list. - * If ia5 != 0, return IA5-encoded EAZ, else - * return a bitmask with corresponding bit set. - */ -static __u16 -eicon_find_msn(eicon_card *card, char *msn, int ia5) -{ - struct msn_entry *p = card->msn_list; - __u8 eaz = '0'; - - while (p) { - if (!strcmp(p->msn, msn)) { - eaz = p->eaz; - break; - } - p = p->next; - } - if (!ia5) - return (1 << (eaz - '0')); - else - return eaz; -} - -/* - * Find an EAZ entry in the list. - * return a string with corresponding msn. - */ -char * -eicon_find_eaz(eicon_card *card, char eaz) -{ - struct msn_entry *p = card->msn_list; - - while (p) { - if (p->eaz == eaz) - return(p->msn); - p = p->next; - } - return("\0"); -} - +#endif +#endif /* CONFIG_PCI */ static void eicon_rcv_dispatch(struct eicon_card *card) @@ -337,39 +197,19 @@ } } -static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq) -{ - xlogreq_t *xlr; - int ret_val; - - if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) { - eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n"); - return -ENOMEM; - } - if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - - ret_val = eicon_get_xlog(card, xlr); - - if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - kfree(xlr); - - return ret_val; -} - static int eicon_command(eicon_card * card, isdn_ctrl * c) { ulong a; eicon_chan *chan; eicon_cdef cdef; +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + dia_start_t dstart; + int idi_length = 0; +#endif +#endif isdn_ctrl cmd; - char tmp[17]; int ret = 0; unsigned long flags; @@ -383,16 +223,15 @@ case EICON_IOCTL_GETVER: return(EICON_CTRL_VERSION); case EICON_IOCTL_GETTYPE: + if (card->bus == EICON_BUS_PCI) { + copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int)); + } return(card->type); case EICON_IOCTL_GETMMIO: switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: return (int)card->hwif.isa.shmem; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.PCIram; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -433,10 +272,6 @@ case EICON_BUS_ISA: case EICON_BUS_MCA: return card->hwif.isa.irq; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.irq; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -514,7 +349,9 @@ case EICON_IOCTL_MANIF: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - if (!card->Feature & PROTCAP_MANIF) + if (!card->d) + return -ENODEV; + if (!card->d->features & DI_MANAGE) return -ENODEV; ret = eicon_idi_manage( card, @@ -522,49 +359,12 @@ return ret; case EICON_IOCTL_GETXLOG: - if (!card->flags & EICON_FLAGS_RUNNING) - return XLOG_ERR_CARD_STATE; - ret = eicon_xlog(card, (xlogreq_t *)a); - return ret; -#if CONFIG_PCI - case EICON_IOCTL_LOADPCI: - if (card->flags & EICON_FLAGS_RUNNING) - return -EBUSY; - if (card->bus == EICON_BUS_PCI) { - switch(card->type) { - case EICON_CTYPE_MAESTRA: - ret = eicon_pci_load_bri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - - case EICON_CTYPE_MAESTRAP: - ret = eicon_pci_load_pri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - } - if (!ret) { - card->flags |= EICON_FLAGS_LOADED; - card->flags |= EICON_FLAGS_RUNNING; - if (card->hwif.pci.channels > 1) { - cmd.command = ISDN_STAT_ADDCH; - cmd.driver = card->myid; - cmd.arg = card->hwif.pci.channels - 1; - card->interface.statcallb(&cmd); - } - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - return ret; - } else return -ENODEV; -#endif + return -ENODEV; + case EICON_IOCTL_ADDCARD: if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef)))) return -EFAULT; - if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id))) + if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0))) return -EIO; return 0; case EICON_IOCTL_DEBUGVAR: @@ -577,8 +377,87 @@ MOD_INC_USE_COUNT; return 0; #endif - default: + case EICON_IOCTL_LOADPCI: + eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n"); + eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n"); + eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n"); return -EINVAL; + default: +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (c->arg < EICON_IOCTL_DIA_OFFSET) + return -EINVAL; + if (copy_from_user(&dstart, (char *)a, sizeof(dstart))) + return -1; + if (!(card = eicon_findnpcicard(dstart.card_id))) + return -EINVAL; + ret = do_ioctl(NULL, NULL, + c->arg - EICON_IOCTL_DIA_OFFSET, + (unsigned long) a); + if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) { + if (card->type != EICON_CTYPE_MAESTRAQ) { + DIVA_DIDD_Read(idi_d, sizeof(idi_d)); + for(idi_length = 0; idi_length < 32; idi_length++) { + if (idi_d[idi_length].type == 0) break; + } + if ((idi_length < 1) || (idi_length >= 32)) { + eicon_log(card, 1, "eicon: invalid idi table length.\n"); + break; + } + card->d = &idi_d[idi_length - 1]; + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x)\n", + (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI", + card->d->channels, card->d->features); + } else { + int i; + DIVA_DIDD_Read(idi_d, sizeof(idi_d)); + for(idi_length = 0; idi_length < 32; idi_length++) + if (idi_d[idi_length].type == 0) break; + if ((idi_length < 1) || (idi_length >= 32)) { + eicon_log(card, 1, "eicon: invalid idi table length.\n"); + break; + } + for(i = 3; i >= 0; i--) { + if (!(card = eicon_findnpcicard(dstart.card_id - i))) + return -EINVAL; + + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + card->d = &idi_d[idi_length - (i+1)]; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x)\n", + 4-i, card->d->channels, card->d->features); + } + } + } + return ret; +#else + return -EINVAL; +#endif +#endif /* CONFIG_PCI */ } break; case ISDN_CMD_DIAL: @@ -586,20 +465,15 @@ return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "Dial on channel %d with state %d\n", chan->No, chan->fsm_state); return -EBUSY; } - if (card->ptype == ISDN_PTYPE_EURO) - tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1); - else - tmp[0] = c->parm.setup.eazmsn[0]; chan->fsm_state = EICON_STATE_OCALL; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); ret = idi_connect_req(card, chan, c->parm.setup.phone, c->parm.setup.eazmsn, @@ -637,19 +511,7 @@ return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - if (strlen(c->parm.num)) { - if (card->ptype == ISDN_PTYPE_EURO) { - chan->eazmask = eicon_find_msn(card, c->parm.num, 0); - } - if (card->ptype == ISDN_PTYPE_1TR6) { - int i; - chan->eazmask = 0; - for (i = 0; i < strlen(c->parm.num); i++) - if (isdigit(c->parm.num[i])) - chan->eazmask |= (1 << (c->parm.num[i] - '0')); - } - } else - chan->eazmask = 0x3ff; + chan->eazmask = 0x3ff; eicon_idi_listen_req(card, chan); return 0; case ISDN_CMD_CLREAZ: @@ -680,8 +542,10 @@ break; chan->l3prot = (c->arg >> 8); #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) + if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) { chan->fax = c->parm.fax; + eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax); + } #endif return 0; case ISDN_CMD_GETL3: @@ -729,6 +593,23 @@ break; idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); return 0; + case CAPI_PUT_MESSAGE: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (c->parm.cmsg.Length < 8) + break; + switch(c->parm.cmsg.Command) { + case CAPI_FACILITY: + if (c->parm.cmsg.Subcommand == CAPI_REQ) + return(capipmsg(card, chan, &c->parm.cmsg)); + break; + case CAPI_MANUFACTURER: + default: + break; + } + return 0; } return -EINVAL; @@ -787,8 +668,7 @@ if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while((skb = skb_dequeue(&card->statq))) { if ((skb->len + count) > len) @@ -811,12 +691,12 @@ } else { skb_pull(skb, cnt); skb_queue_head(&card->statq, skb); - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } } card->statq_entries = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } printk(KERN_ERR @@ -848,7 +728,7 @@ } else #endif - ret = idi_send_data(card, chan, ack, skb, 1); + ret = idi_send_data(card, chan, ack, skb, 1, 1); return (ret); } else { return -ENODEV; @@ -895,12 +775,11 @@ return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); count = strlen(buf); skb = alloc_skb(count, GFP_ATOMIC); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); printk(KERN_ERR "eicon: could not alloc skb in putstatus\n"); return; } @@ -918,7 +797,7 @@ } else card->statq_entries++; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (count) { cmd.command = ISDN_STAT_STAVAIL; cmd.driver = card->myid; @@ -967,7 +846,7 @@ * link it into cards-list. */ static void -eicon_alloccard(int Type, int membase, int irq, char *id) +eicon_alloccard(int Type, int membase, int irq, char *id, int card_id) { int i; int j; @@ -976,9 +855,6 @@ char qid[5]; #endif eicon_card *card; -#if CONFIG_PCI - eicon_pci_card *pcic; -#endif qloop = (Type == EICON_CTYPE_QUADRO)?2:0; for (i = 0; i <= qloop; i++) { @@ -1088,9 +964,9 @@ card->interface.channels = 1; break; #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRA: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1101,11 +977,26 @@ ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; + card->hwif.pci.irq = irq; + card->hwif.pci.type = Type; + card->flags = 0; + card->nchannels = 2; + card->interface.channels = 1; + break; + + case EICON_CTYPE_MAESTRAQ: + card->bus = EICON_BUS_PCI; + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_TRANSDSP | + ISDN_FEATURE_L3_FCLASS2; + card->hwif.pci.card = (void *)card; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1114,7 +1005,6 @@ break; case EICON_CTYPE_MAESTRAP: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1125,13 +1015,7 @@ ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIram = pcic->PCIram; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1139,6 +1023,7 @@ card->interface.channels = 1; break; #endif +#endif #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_ISABRI: if (membase == -1) @@ -1197,6 +1082,53 @@ skb_queue_head_init(&card->bch[j].e.X); skb_queue_head_init(&card->bch[j].e.R); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI + /* *** Diva Server *** */ + if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2 + , GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate DBUFFER-struct.\n", id); + kfree(card); + kfree(card->bch); + return; + } + if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERS-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + return; + } + if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + kfree(card->sbuf); + return; + } + for (j=0; j< (card->nchannels + 1); j++) { + memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER)); + card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j]; + memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS)); + card->bch[j].de.X = (BUFFERS *)&card->sbuf[j]; + memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbufp[j], 0, 270); + card->bch[j].de.X->P = (char *)&card->sbufp[j * 270]; + memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270); + card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270]; + } + /* *** */ +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ + card->next = cards; cards = card; } @@ -1220,10 +1152,7 @@ #endif /* CONFIG_MCA */ #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_printpar(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon_registercard: Illegal BUS type %d\n", @@ -1241,8 +1170,7 @@ return 0; } -#ifdef MODULE -static void +static void unregister_card(eicon_card * card) { isdn_ctrl cmd; @@ -1260,10 +1188,7 @@ break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_release(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon: Invalid BUS type %d\n", @@ -1271,7 +1196,6 @@ break; } } -#endif /* MODULE */ static void eicon_freecard(eicon_card *card) { @@ -1295,13 +1219,17 @@ while((skb = skb_dequeue(&card->statq))) dev_kfree_skb(skb); - eicon_clear_msn(card); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + kfree(card->sbufp); + kfree(card->sbuf); + kfree(card->dbuf); +#endif kfree(card->bch); kfree(card); } int -eicon_addcard(int Type, int membase, int irq, char *id) +eicon_addcard(int Type, int membase, int irq, char *id, int card_id) { eicon_card *p; eicon_card *q = NULL; @@ -1314,7 +1242,7 @@ if ((Type = eicon_isa_find_card(membase, irq, id)) < 0) return 0; #endif - eicon_alloccard(Type, membase, irq, id); + eicon_alloccard(Type, membase, irq, id, card_id); p = cards; while (p) { registered = 0; @@ -1333,12 +1261,14 @@ break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI if (eicon_registercard(p)) break; registered = 1; break; #endif +#endif default: printk(KERN_ERR "eicon: addcard: Invalid BUS type %d\n", @@ -1371,46 +1301,35 @@ return (added - failed); } -#define DRIVERNAME "Eicon active ISDN driver" -#define DRIVERRELEASE "1" -#ifdef MODULE -#define eicon_init init_module -#endif - -int +static int __init eicon_init(void) { int card_count = 0; - int release = 0; char tmprev[50]; DebugVar = 1; + eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; printk(KERN_INFO "%s Rev: ", DRIVERNAME); strcpy(tmprev, eicon_revision); printk("%s/", eicon_getrev(tmprev)); - release += getrel(tmprev); strcpy(tmprev, eicon_pci_revision); -#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_isa_revision); #ifdef CONFIG_ISDN_DRV_EICON_ISA printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_idi_revision); printk("%s\n", eicon_getrev(tmprev)); - release += getrel(tmprev); - sprintf(tmprev,"%d", release); - printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME, - DRIVERRELEASE, tmprev, DRIVERPATCH); + printk(KERN_INFO "%s Release: %s%s\n", DRIVERNAME, + DRIVERRELEASE, DRIVERPATCH); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1427,18 +1346,23 @@ card_count++; }; #else - card_count = eicon_addcard(0, membase, irq, id); + card_count = eicon_addcard(0, membase, irq, id, 0); #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + DivasCardsDiscover(); card_count += eicon_pci_find_card(id); #endif +#endif + if (!cards) { #ifdef MODULE -#ifndef CONFIG_PCI +#ifndef CONFIG_ISDN_DRV_EICON_PCI #ifndef CONFIG_ISDN_DRV_EICON_ISA printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n"); + printk(KERN_INFO "Eicon: Driver not loaded !\n"); #else printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n"); #endif @@ -1451,17 +1375,34 @@ } else printk(KERN_INFO "Eicon: %d card%s added\n", card_count, (card_count>1)?"s":""); - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; return 0; } -#ifdef MODULE -void -cleanup_module(void) +#ifdef CONFIG_ISDN_DRV_EICON_PCI +void DIVA_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#else +int DivasCardNext; +card_t DivasCards[1]; +#endif + +static void +eicon_exit(void) { +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + card_t *pCard; + word wCardIndex; + extern int Divas_major; + int iTmp = 0; +#endif +#endif + eicon_card *card = cards; eicon_card *last; + while (card) { #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1481,10 +1422,58 @@ card = card->next; eicon_freecard(last); } + +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + for (iTmp = 0; iTmp < 3; iTmp++) + { + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + } + pCard++; + } + unregister_chrdev(Divas_major, "Divas"); +#endif +#endif /* CONFIG_PCI */ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } -#else /* no module */ +#ifndef MODULE void eicon_setup(char *str, int *ints) @@ -1669,7 +1658,7 @@ return ENODEV; }; /* matching membase & irq */ - if ( 1 == eicon_addcard(type, membase, irq, id)) { + if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name); mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards); @@ -1691,3 +1680,5 @@ #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ +module_init(eicon_init); +module_exit(eicon_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c --- v2.2.18/drivers/isdn/eicon/eicon_pci.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_pci.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.c,v 1.15.6.2 2001/02/16 09:09:50 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -6,11 +6,9 @@ * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -25,53 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.c,v $ - * Revision 1.11 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.10 1999/08/22 20:26:49 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/11 21:01:11 keil - * new PCI codefix - * - * Revision 1.8 1999/08/10 16:02:20 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.7 1999/06/09 19:31:29 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.6 1999/04/01 12:48:37 armin - * Changed some log outputs. - * - * Revision 1.5 1999/03/29 11:19:49 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:48 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:24 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:06 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:45 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -80,894 +31,90 @@ #include "eicon.h" #include "eicon_pci.h" +#undef N_DATA +#include "adapter.h" +#include "uxio.h" -char *eicon_pci_revision = "$Revision: 1.11 $"; +char *eicon_pci_revision = "$Revision: 1.15.6.2 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ - -#undef EICON_PCI_DEBUG +#ifdef CONFIG_ISDN_DRV_EICON_PCI int eicon_pci_find_card(char *ID) { - if (pci_present()) { - struct pci_dev *pdev = NULL; - int pci_nextindex=0, pci_cards=0, pci_akt=0; - int pci_type = PCI_MAESTRA; - int NoMorePCICards = FALSE; - char *ram, *reg, *cfg; - unsigned int pram=0, preg=0, pcfg=0; - char did[12]; - eicon_pci_card *aparms; - - if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) { - printk(KERN_WARNING - "eicon_pci: Could not allocate card-struct.\n"); - return 0; - } - - for (pci_cards = 0; pci_cards < 0x0f; pci_cards++) - { - do { - if ((pdev = pci_find_device(PCI_VENDOR_EICON, - pci_type, - pdev))) - { - pci_nextindex++; - break; - } - else { - pci_nextindex = 0; - switch (pci_type) /* switch to next card type */ - { - case PCI_MAESTRA: - pci_type = PCI_MAESTRAQ; break; - case PCI_MAESTRAQ: - pci_type = PCI_MAESTRAQ_U; break; - case PCI_MAESTRAQ_U: - pci_type = PCI_MAESTRAP; break; - default: - case PCI_MAESTRAP: - NoMorePCICards = TRUE; - } - } - } - while (!NoMorePCICards); - if (NoMorePCICards) - { - if (pci_cards < 1) { - printk(KERN_INFO "Eicon: No supported PCI cards found.\n"); - kfree(aparms); - return 0; - } - else - { - printk(KERN_INFO "Eicon: %d PCI card%s registered.\n", - pci_cards, (pci_cards > 1) ? "s":""); - kfree(aparms); - return (pci_cards); - } - } - - pci_akt = 0; - switch(pci_type) - { - case PCI_MAESTRA: - printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRA; - - aparms->irq = pdev->irq; - preg = pdev->base_address[ 2] & 0xfffffffc; - pcfg = pdev->base_address[ 1] & 0xffffff80; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg); -#endif - pci_akt = 1; - break; + int pci_cards = 0; + int card_id = 0; + int had_q = 0; + int ctype = 0; + char did[20]; + card_t *pCard; + word wCardIndex; - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n"); - pci_cards--; - pci_akt = 0; - break; - - case PCI_MAESTRAP: - printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/ - aparms->irq = pdev->irq; - pram = pdev->base_address[ 0] & 0xfffff000; - preg = pdev->base_address[ 2] & 0xfffff000; - pcfg = pdev->base_address[ 4] & 0xfffff000; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: ram=0x%x\n", - (pram)); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", - (preg)); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", - (pcfg)); -#endif - pci_akt = 1; - break; - default: - printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n"); - pci_cards--; - pci_akt = 0; - break; - } - - if (pci_akt) { - /* remapping memory */ - switch(pci_type) + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) { - case PCI_MAESTRA: - aparms->PCIreg = (unsigned int) preg; - aparms->PCIcfg = (unsigned int) pcfg; - if (check_region((aparms->PCIreg), 0x20)) { - printk(KERN_WARNING "eicon_pci: reg port already in use !\n"); - aparms->PCIreg = 0; - break; - } else { - request_region(aparms->PCIreg, 0x20, "eicon reg"); - } - if (check_region((aparms->PCIcfg), 0x80)) { - printk(KERN_WARNING "eicon_pci: cfg port already in use !\n"); - aparms->PCIcfg = 0; - release_region(aparms->PCIreg, 0x20); - break; - } else { - request_region(aparms->PCIcfg, 0x80, "eicon cfg"); + switch(pCard->hw->card_type) { + case DIA_CARD_TYPE_DIVA_SERVER: + ctype = EICON_CTYPE_MAESTRAP; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_B: + ctype = EICON_CTYPE_MAESTRA; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_Q: + ctype = EICON_CTYPE_MAESTRAQ; + if (!had_q) + card_id++; + if (++had_q >=4) + had_q = 0; + break; + default: + printk(KERN_ERR "eicon_pci: unknown card type %d !\n", + pCard->hw->card_type); + goto err; } - break; - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - case PCI_MAESTRAP: - aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000); - ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET); - reg = ioremap(preg, 0x4000); - cfg = ioremap(pcfg, 0x1000); - aparms->PCIram = (unsigned int) ram; - aparms->PCIreg = (unsigned int) reg; - aparms->PCIcfg = (unsigned int) cfg; - break; - } - if ((!aparms->PCIreg) || (!aparms->PCIcfg)) { - printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; - } else { - aparms->mvalid = 1; - sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards); - - printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did); - - if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) { + if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) { printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; + } else { + pci_cards++; + printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n", + eicon_ctype_name[ctype], did, card_id); } +err:; } + pCard++; } - - } - } else - printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n"); - return 0; -} - -/* - * Checks protocol file id for "F#xxxx" string fragment to - * extract the features, supported by this protocol version. - * binary representation of the feature string value is returned - * in *value. The function returns 0 if feature string was not - * found or has a wrong format, else 1. - */ -static int GetProtFeatureValue(char *sw_id, int *value) -{ - __u8 i, offset; - - while (*sw_id) - { - if ((sw_id[0] == 'F') && (sw_id[1] == '#')) - { - sw_id = &sw_id[2]; - for (i=0, *value=0; i<4; i++, sw_id++) - { - if ((*sw_id >= '0') && (*sw_id <= '9')) - { - offset = '0'; - } - else if ((*sw_id >= 'A') && (*sw_id <= 'F')) - { - offset = 'A' + 10; - } - else if ((*sw_id >= 'a') && (*sw_id <= 'f')) - { - offset = 'a' + 10; - } - else - { - return 0; - } - *value |= (*sw_id - offset) << (4*(3-i)); - } - return 1; - } - else - { - sw_id++; - } - } - return 0; -} - - -void -eicon_pci_printpar(eicon_pci_card *card) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->PCIreg, - (unsigned int)card->PCIcfg, - card->irq); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - printk(KERN_INFO "%s at 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->shmem, - card->irq); -#ifdef EICON_PCI_DEBUG - printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram); - printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg); - printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); -#endif - break; - } -} - - -static void -eicon_pci_release_shmem(eicon_pci_card *card) { - if (!card->master) - return; - if (card->mvalid) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - /* reset board */ - outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */ - outb(0, card->PCIreg + M_RESET); - SLEEP(20); - outb(0, card->PCIreg + M_ADDRH); - outw(0, card->PCIreg + M_ADDR); - outw(0, card->PCIreg + M_DATA); - - release_region(card->PCIreg, 0x20); - release_region(card->PCIcfg, 0x80); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - iounmap((void *)card->shmem); - iounmap((void *)card->PCIreg); - iounmap((void *)card->PCIcfg); - break; - } - } - card->mvalid = 0; -} - -static void -eicon_pci_release_irq(eicon_pci_card *card) { - if (!card->master) - return; - if (card->ivalid) - free_irq(card->irq, card); - card->ivalid = 0; + return pci_cards; } void -eicon_pci_release(eicon_pci_card *card) { - eicon_pci_release_irq(card); - eicon_pci_release_shmem(card); -} - -/* - * Upload buffer content to adapters shared memory - * on verify error, 1 is returned and a message is printed on screen - * else 0 is returned - * Can serve IO-Type and Memory type adapters - */ -int eicon_upload(t_dsp_download_space *p_para, - __u16 length, /* byte count */ - __u8 *buffer, - int verify) -{ - __u32 i, dwdata = 0, val = 0, timeout; - __u16 data; - eicon_pci_boot *boot = 0; - - switch (p_para->type) /* actions depend on type of union */ - { - case DL_PARA_IO_TYPE: - for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */ - outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); - } - if (verify) /* check written block */ - { - for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - data = inw(p_para->dat.io.ioDATA); - if (data != *(u16 *)&buffer[i]) - { - p_para->dat.io.r3addr += i; - p_para->dat.io.BadData = data; - p_para->dat.io.GoodData = *(u16 *)&buffer[i]; - return 1; - } - } - } - break; - - case DL_PARA_MEM_TYPE: - boot = p_para->dat.mem.boot; - writel(p_para->dat.mem.r3addr, &boot->addr); - for (i=0; i> 2], &boot->data[i]); - } - if (verify) /* check written block */ - { - for (i=0; idata[i]); - if (((u32 *)buffer)[i >> 2] != dwdata) - { - p_para->dat.mem.r3addr += i; - p_para->dat.mem.BadData = dwdata; - p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2]; - return 1; - } - } - } - writel(((length + 3) / 4), &boot->len); /* len in dwords */ - writel(2, &boot->cmd); - - timeout = jiffies + 20; - while (timeout > jiffies) { - val = readl(&boot->cmd); - if (!val) break; - SLEEP(2); - } - if (val) - { - p_para->dat.mem.timeout = 1; - return 1; - } - break; - } - return 0; -} - - -/* show header information of code file */ -static -int eicon_pci_print_hdr(unsigned char *code, int offset) +eicon_pci_init_conf(eicon_card *card) { - unsigned char hdr[80]; - int i, fvalue = 0; - - i = 0; - while ((i < (sizeof(hdr) -1)) - && (code[offset + i] != '\0') - && (code[offset + i] != '\r') - && (code[offset + i] != '\n')) - { - hdr[i] = code[offset + i]; - i++; - } - hdr[i] = '\0'; - printk(KERN_DEBUG "Eicon: loading %s\n", hdr); - if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue); - else return(0); -} - + int j; -/* - * Configure a card, download code into BRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - int i,j; - int timeout; - unsigned int offset, offp=0, size, length; - int signature = 0; - int FeatureValue = 0; - eicon_pci_codebuf cbuf; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - unsigned char *code; - unsigned int reg; - unsigned int cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - reg = card->PCIreg; - cfg = card->PCIcfg; - - /* reset board */ - outb(0, reg + M_RESET); - SLEEP(10); - outb(0, reg + M_ADDRH); - outw(0, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card\n"); -#endif + /* initializing some variables */ + card->ReadyInt = 0; - /* clear shared memory */ - outb(0xff, reg + M_ADDRH); - outw(0, reg + M_ADDR); - for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA); - SLEEP(10); + for(j = 0; j < 256; j++) + card->IdTable[j] = NULL; -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: clear shared memory\n"); -#endif - - /* download protocol and dsp file */ - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_IO_TYPE; - dl_para.dat.io.ioADDR = reg + M_ADDR; - dl_para.dat.io.ioADDRH = reg + M_ADDRH; - dl_para.dat.io.ioDATA = reg + M_DATA; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j == 0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - offset = 0; - - if (j == 0) dl_para.dat.io.r3addr = 0; - if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32); - - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - kfree(code); - return -EIO; - } - /* move onto next block */ - offset += length; - dl_para.dat.io.r3addr += length; - } while (offset < size); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset); -#endif - offp += size; + for(j = 0; j < (card->d->channels + 1); j++) { + card->bch[j].e.busy = 0; + card->bch[j].e.D3Id = 0; + card->bch[j].e.B2Id = 0; + card->bch[j].e.ref = 0; + card->bch[j].e.Req = 0; + card->bch[j].e.complete = 1; + card->bch[j].fsm_state = EICON_STATE_NULL; } - kfree(code); - - /* clear signature */ - outb(0xff, reg + M_ADDRH); - outw(0x1e, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* copy configuration data into shared memory */ - outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA); - outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA); - outw(10,reg + M_ADDR); outb(0, reg + M_DATA); - outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA); - outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA); - outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */ - outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA); - outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA); - outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */ - outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */ - outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA); - outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA); - outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA); - outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA); - - for (i=0;i<32;i++) - { - outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA); - outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA); - outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA); - outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA); - outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA); - outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA); - } - -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: starting CPU...\n"); -#endif - /* let the CPU run */ - outw(0x08, reg + M_RESET); - - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - outw(0x1e, reg + M_ADDR); - signature = inw(reg + M_DATA); - if (signature == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if (signature != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - outb(0xff, reg + M_ADDRH); - outw(0x3f6, reg + M_ADDR); - card->channels = inw(reg + M_DATA); - card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - /* Trigger an interrupt and check if it is delivered */ - outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */ - outb(0x89, reg + M_RESET); /* place int request */ - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(5); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; } - -/* - * Configure a card, download code into PRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - eicon_pci_boot *boot; - eicon_pr_ram *prram; - int i,j; - int timeout; - int FeatureValue = 0; - unsigned int offset, offp=0, size, length; - unsigned long int signature = 0; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - eicon_pci_codebuf cbuf; - unsigned char *code; - unsigned char req_int; - char *ram, *reg, *cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - boot = &card->shmem->boot; - ram = (char *)card->PCIram; - reg = (char *)card->PCIreg; - cfg = (char *)card->PCIcfg; - prram = (eicon_pr_ram *)ram; - - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - /* set command count to 0 */ - writel(0, &boot->reserved); - - /* check if CPU increments the life word */ - i = readw(&boot->live); - SLEEP(20); - if (i == readw(&boot->live)) { - printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n"); -#endif - - /* download firmware : DSP and Protocol */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); #endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_MEM_TYPE; - dl_para.dat.mem.boot = boot; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j==0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */ - - if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR; - if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32); - - offset = 0; - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - if (dl_para.dat.mem.timeout == 0) - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - else - printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n"); - kfree(code); - return -EIO; - } - - /* move onto next block */ - offset += length; - dl_para.dat.mem.r3addr += length; - } while (offset < size); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* initialize the adapter data structure */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* clear out config space */ - for (i = 0; i < 256; i++) writeb(0, &ram[i]); - - /* copy configuration down to the card */ - writeb(cbuf.tei, &ram[8]); - writeb(cbuf.nt2, &ram[9]); - writeb(0, &ram[10]); - writeb(cbuf.WatchDog, &ram[11]); - writeb(cbuf.Permanent, &ram[12]); - writeb(cbuf.XInterface, &ram[13]); - writeb(cbuf.StableL2, &ram[14]); - writeb(cbuf.NoOrderCheck, &ram[15]); - writeb(cbuf.HandsetType, &ram[16]); - writeb(0, &ram[17]); - writeb(cbuf.LowChannel, &ram[18]); - writeb(cbuf.ProtVersion, &ram[19]); - writeb(cbuf.Crc4, &ram[20]); - for (i = 0; i < 32; i++) - { - writeb(cbuf.l[0].oad[i], &ram[32 + i]); - writeb(cbuf.l[0].osa[i], &ram[64 + i]); - writeb(cbuf.l[0].spid[i], &ram[96 + i]); - writeb(cbuf.l[1].oad[i], &ram[128 + i]); - writeb(cbuf.l[1].osa[i], &ram[160 + i]); - writeb(cbuf.l[1].spid[i], &ram[192 + i]); - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: configured card OK\n"); -#endif - - /* start adapter */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: tell card to start...\n"); -#endif - writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */ - writel(3, &boot->cmd); /* DIVAS_START_CMD */ - - /* wait till card ACKs */ - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - signature = readl(&boot->signature); - if ((signature >> 16) == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if ((signature >> 16) != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - card->channels = readb(&ram[0x3f6]); - card->serial = readl(&ram[0x3f0]); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - readb(&ram[0x3fe]); - writeb(0, &ram[0x3fe]); /* reset any pending interrupt */ - readb(&ram[0x3fe]); - - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - - req_int = readb(&prram->ReadyInt); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - req_int++; - /* Trigger an interrupt and check if it is delivered */ - writeb(req_int, &prram->ReadyInt); - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(2); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; -} - #endif /* CONFIG_PCI */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/eicon_pci.h linux/drivers/isdn/eicon/eicon_pci.h --- v2.2.18/drivers/isdn/eicon/eicon_pci.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/eicon/eicon_pci.h Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards (PCI part). * @@ -19,26 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.h,v $ - * Revision 1.4 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.3 1999/03/29 11:19:51 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:50 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:46 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_pci_h @@ -46,147 +26,20 @@ #ifdef __KERNEL__ - -#define PCI_VENDOR_EICON 0x1133 -#define PCI_DIVA_PRO20 0xe001 /* Not supported */ -#define PCI_DIVA20 0xe002 /* Not supported */ -#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */ -#define PCI_DIVA20_U 0xe004 /* Not supported */ -#define PCI_MAESTRA 0xe010 -#define PCI_MAESTRAQ 0xe012 -#define PCI_MAESTRAQ_U 0xe013 -#define PCI_MAESTRAP 0xe014 - -#define DIVA_PRO20 1 -#define DIVA20 2 -#define DIVA_PRO20_U 3 -#define DIVA20_U 4 -#define MAESTRA 5 -#define MAESTRAQ 6 -#define MAESTRAQ_U 7 -#define MAESTRAP 8 - -#define TRUE 1 -#define FALSE 0 - -#define DIVAS_SIGNATURE 0x4447 - - -/* MAESTRA BRI PCI */ - -#define M_RESET 0x10 /* offset of reset register */ -#define M_DATA 0x00 /* offset of data register */ -#define M_ADDR 0x04 /* offset of address register */ -#define M_ADDRH 0x0c /* offset of high address register */ - -#define M_DSP_CODE_LEN 0xbf7d0000 -#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */ -#define M_DSP_CODE_BASE 0xbf7a0000 -#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */ - - - -/* MAESTRA PRI PCI */ - -#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */ - -#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */ -#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */ - -#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */ -#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */ -#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ -#define MP_DSP_CODE_BASE 0xa03a0000 -#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */ - -#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */ - -/* RESET register bits */ -#define _MP_S2M_RESET 0x10 /* active lo */ -#define _MP_LED2 0x08 /* 1 = on */ -#define _MP_LED1 0x04 /* 1 = on */ -#define _MP_DSP_RESET 0x02 /* active lo */ -#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */ - -/* boot interface structure */ -typedef struct { - __u32 cmd __attribute__ ((packed)); - __u32 addr __attribute__ ((packed)); - __u32 len __attribute__ ((packed)); - __u32 err __attribute__ ((packed)); - __u32 live __attribute__ ((packed)); - __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed)); - __u32 signature __attribute__ ((packed)); - __u8 data[1]; /* real interface description */ -} eicon_pci_boot; - - -#define DL_PARA_IO_TYPE 0 -#define DL_PARA_MEM_TYPE 1 - -typedef struct tag_dsp_download_space -{ - __u16 type; /* see definitions above to differ union elements */ - union - { - struct - { - __u32 r3addr; - __u16 ioADDR; - __u16 ioADDRH; - __u16 ioDATA; - __u16 BadData; /* in case of verify error */ - __u16 GoodData; - } io; /* for io based adapters */ - struct - { - __u32 r3addr; - eicon_pci_boot *boot; - __u32 BadData; /* in case of verify error */ - __u32 GoodData; - __u16 timeout; - } mem; /* for memory based adapters */ - } dat; -} t_dsp_download_space; - - -/* Shared memory */ -typedef union { - eicon_pci_boot boot; -} eicon_pci_shmem; - /* * card's description */ typedef struct { - int ramsize; int irq; /* IRQ */ - unsigned int PCIram; - unsigned int PCIreg; - unsigned int PCIcfg; - long int serial; /* Serial No. */ int channels; /* No. of supported channels */ void* card; - eicon_pci_shmem* shmem; /* Shared-memory area */ - unsigned char* intack; /* Int-Acknowledge */ - unsigned char* stopcpu; /* Writing here stops CPU */ - unsigned char* startcpu; /* Writing here starts CPU */ unsigned char type; /* card type */ - unsigned char irqprobe; /* Flag: IRQ-probing */ - unsigned char mvalid; /* Flag: Memory is valid */ - unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card is Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_pci_card; - - -extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern void eicon_pci_release(eicon_pci_card *card); -extern void eicon_pci_printpar(eicon_pci_card *card); extern int eicon_pci_find_card(char *ID); #endif /* __KERNEL__ */ #endif /* eicon_pci_h */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/fourbri.c linux/drivers/isdn/eicon/fourbri.c --- v2.2.18/drivers/isdn/eicon/fourbri.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/fourbri.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,573 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.7 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Diva Server 4BRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" +#include "constant.h" +#include "adapter.h" +#include "uxio.h" + +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for 4BRI card */ +#define MQ_BOARD_DSP_OFFSET 0x00a00000 +#define MQ_DSP1_ADDR_OFFSET 0x00000008 +#define MQ_DSP_JUNK_OFFSET 0x00000400 +#define MQ_DSP1_DATA_OFFSET 0x00000000 +#define MQ_BOARD_ISAC_DSP_RESET 0x00800028 +#define MQ_BREG_RISC 0x1200 /* RISC Reset */ +#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */ +#define MQ_RISC_COLD_RESET_MASK 0x0001 /* RISC Cold reset */ +#define MQ_RISC_WARM_RESET_MASK 0x0002 /* RISC Warm reset */ +#define MQ_IRQ_REQ_ON 0x1 +#define MQ_IRQ_REQ_OFF 0x0 +#define MQ_BREG_IRQ_TEST 0x0608 +#define PLX9054_INTCSR 0x69 +#define PLX9054_INT_ENA 0x09 + +#define DIVAS_IOBASE 0x01 +#define M_PCI_RESET 0x10 + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg); +static int fourbri_ISR (card_t* card); + +int FPGA_Download(word, dword, byte *, byte *, int); +extern byte FPGA_Bytes[]; +extern void *get_card(int); + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +word GetProtFeatureValue(char *sw_id); + +void memcp(byte *dst, byte *src, dword dwLen); +int memcm(byte *dst, byte *src, dword dwLen); + +static int diva_server_4bri_reset(card_t *card) +{ + byte *ctl; + + DPRINTF(("divas: reset Diva Server 4BRI")); + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + /* stop RISC, DSP's and ISAC */ + UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0); + UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0); + + UxCardMemDetach(card->hw, ctl); + + return 0; +} + +static int diva_server_4bri_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server 4BRI")); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], config->sig_flags); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardMemOut(card->hw, &shared[22], 4); + } + else + { + UxCardMemOut(card->hw, &shared[22], 0); + } + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_4bri_reset_int(card_t *card) +{ + byte *ctl; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + + UxCardMemDetach(card->hw, ctl); + + return; +} + + +static int diva_server_4bri_test_int(card_t *card) +{ + byte *ctl, i; + byte *reg; + + DPRINTF(("divas: test interrupt for Diva Server 4BRI")); + + /* We get the last (dummy) adapter in so we need to go back to the first */ + + card = get_card(card->cfg.card_id - 3); + + /* Enable interrupts on PLX chip */ + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA); + + UxCardMemDetach(card->hw, reg); + + /* Set the test interrupt flag */ + card->test_int_pend = TEST_INT_DIVAS_Q; + + /* Now to trigger the interrupt */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON); + + UxCardMemDetach(card->hw, ctl); + + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + if (card->test_int_pend) + { + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_4bri_load(card_t *card, dia_load_t *load) +{ + byte *pRAM=NULL; + int download_offset=0; + card_t *FirstCard; + byte sw_id[80]; + + DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id)); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + download_offset = 0; // Protocol code written to offset 0 + pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC); + + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword); + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword); + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_FPGA_CODE: + DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length)); + if (FPGA_Download(IDI_ADAPTER_MAESTRAQ, + card->hw->io_base, + sw_id, + load->code, + load->length + ) == -1) + { + DPRINTF(("divas: FPGA download failed")); + return -1; + } + + /* NOW reset the 4BRI */ + diva_server_4bri_reset(card); + return 0; // No need for anything further loading + + default: + DPRINTF(("divas: unknown code type")); + return -1; + } + + memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length); + + { + int mism_off; + if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length))) + { + DPRINTF(("divas: memory mismatch at offset %d", mism_off)); + UxCardMemDetach(card->hw, pRAM); + return -1; + } + } + + UxCardMemDetach(card->hw, pRAM); + + return 0; +} + +static int diva_server_4bri_start(card_t *card, byte *channels) +{ + byte *ctl; + byte *shared, i; + int adapter_num; + + DPRINTF(("divas: start Diva Server 4BRI")); + *channels = 0; + card->is_live = FALSE; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK); + + UxPause(2); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK); + + UxPause(10); + + UxCardMemDetach(card->hw, ctl); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for ( i = 0 ; i < 300 ; ++i ) + { + UxPause (10) ; + + if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 ) + { + DPRINTF(("divas: Protocol startup time %d.%02d seconds", + (i / 100), (i % 100) )); + + break; + } + } + + if (i==300) + { + DPRINTF(("divas: Timeout starting card")); + DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E]))); + + UxCardMemDetach(card->hw, shared); + return -1; + } + + UxCardMemDetach(card->hw, shared); + + for (adapter_num=3; adapter_num >= 0; adapter_num--) + { + card_t *qbri_card; + + qbri_card = get_card(card->cfg.card_id - adapter_num); + + if (qbri_card) + { + qbri_card->is_live = TRUE; + shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY); + *channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]); + UxCardMemDetach(qbri_card->hw, shared); + } + else + { + DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id)); + } + } + + diva_server_4bri_test_int(card); + + return 0; +} + +static +int diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise 4BRI specific entry points + */ + +int Divas4BriInit(card_t *card, dia_card_t *cfg) +{ +// byte sw_id[80]; +// extern int FPGA_Done; + + DPRINTF(("divas: initialise Diva Server 4BRI")); + + if (Divas4BRIInitPCI(card, cfg) == -1) + { + return -1; + } + + /* Need to download the FPGA */ +/* if (!FPGA_Done) + { + int retVal; + + retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ, + cfg->io_base, + sw_id, + FPGA_Bytes + ); + if(retVal==-1) + { + + DPRINTF(("divas: FPGA Download Failed")); + return -1; + + } + FPGA_Done = 1; + } */ + + card->card_reset = diva_server_4bri_reset; + card->card_load = diva_server_4bri_load; + card->card_config = diva_server_4bri_config; + card->card_start = diva_server_4bri_start; + card->reset_int = diva_server_4bri_reset_int; + card->card_mem_get = diva_server_4bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = fourbri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + +void memcp(byte *dst, byte *src, dword dwLen) +{ + while (dwLen) + { + *dst = *src; + dst++; src++; + dwLen--; + } +} + +int memcm(byte *dst, byte *src, dword dwLen) +{ + int offset = 0; + + while (offset < dwLen) + { + if(*dst != *src) + return (offset+1); + + offset++; + src++; + dst++; + } + + return 0; +} + + + +/*int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +}*/ + + +static int fourbri_ISR (card_t* card) +{ + byte *ctl; + + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + UxCardMemDetach(card->hw, ctl); + + return (1); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/fpga.c linux/drivers/isdn/eicon/fpga.c --- v2.2.18/drivers/isdn/eicon/fpga.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/fpga.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,155 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "uxio.h" + +#define FPGA_PORT 0x6E +#define FPGA_DLOAD_BUFLEN 256 +#define NAME_OFFSET 0x10 +#define NAME_MAXLEN 12 +#define DATE_OFFSET 0x2c +#define DATE_MAXLEN 10 + +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); +void UxPause(long int); + +/*-------------------------------------------------------------------------*/ +/* Loads the FPGA configuration file onto the hardware. */ +/* Function returns 0 on success, else an error number. */ +/* On success, an identifier string is returned in the buffer */ +/* */ +/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream */ +/* file and a file read function has to be provided by the operating */ +/* system part. */ +/* ----------------------------------------------------------------------- */ +int FPGA_Download( word cardtype, + dword RegBase, + byte *strbuf, + byte FPGA_SRC[], + int FPGA_LEN + ) +{ + word i, j, k; + word baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN; + dword addr; + byte *pFPGA; + + //--- check for legal cardtype + switch (cardtype) + { + case IDI_ADAPTER_MAESTRAQ: + addr = RegBase ; // address where to access FPGA + Mask_PROGRAM = 0x0001; // FPGA pins at address + Mask_DONE = 0x0002; + Mask_CCLK = 0x0100; + Mask_DIN = 0x0400; + baseval = 0x000d; // PROGRAM hi, CCLK lo, DIN lo by default + break; + + default: + + DPRINTF(("divas: FPGA Download ,Illegal Card")); + return -1; // illegal card + } + + //--- generate id string from file content + for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k++] = ' '; + for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k] = 0; + + DPRINTF(("divas: FPGA Download - %s", strbuf)); + + //--- prepare download, Pulse PROGRAM pin down. + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM); // PROGRAM low pulse + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // release + UxPause(50); // wait until FPGA finised internal memory clear + + //--- check done pin, must be low + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL")); + return -1; + } + + pFPGA = FPGA_SRC; + + i = 0; + /* Move past the header */ + while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN)) + { + i++; + } + + // We've hit the 0xFF so move on to the next byte + // i++; + DPRINTF(("divas: FPGA Code starts at offset %d", i)); + + //--- put data onto the FPGA + for (;i>j)) baseval |= Mask_DIN; // write a hi + else baseval &=~Mask_DIN; // write a lo + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + } + + //--- add some additional startup clock cycles and check done pin + for (i=0; i<5; i++) + { + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + + UxPause(100); + + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA download successful")); + } + else + { + DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT))); + return -1; + } + +return 0; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/idi.c linux/drivers/isdn/eicon/idi.c --- v2.2.18/drivers/isdn/eicon/idi.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/idi.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,867 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.8 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Core driver for Diva Server cards + * Implements the IDI interface + */ + +#include "idi.h" +#include "adapter.h" +#include "pc.h" +#include "pr_pc.h" +#include "sys.h" +#include "uxio.h" + +/* IDI request functions */ + +static void request(card_t *card, ENTITY *e); + +static void req_0(ENTITY *e) { request(&DivasCards[ 0], e); } +static void req_1(ENTITY *e) { request(&DivasCards[ 1], e); } +static void req_2(ENTITY *e) { request(&DivasCards[ 2], e); } +static void req_3(ENTITY *e) { request(&DivasCards[ 3], e); } +static void req_4(ENTITY *e) { request(&DivasCards[ 4], e); } +static void req_5(ENTITY *e) { request(&DivasCards[ 5], e); } +static void req_6(ENTITY *e) { request(&DivasCards[ 6], e); } +static void req_7(ENTITY *e) { request(&DivasCards[ 7], e); } +static void req_8(ENTITY *e) { request(&DivasCards[ 8], e); } +static void req_9(ENTITY *e) { request(&DivasCards[ 9], e); } +static void req_10(ENTITY *e) { request(&DivasCards[10], e); } +static void req_11(ENTITY *e) { request(&DivasCards[11], e); } +static void req_12(ENTITY *e) { request(&DivasCards[12], e); } +static void req_13(ENTITY *e) { request(&DivasCards[13], e); } +static void req_14(ENTITY *e) { request(&DivasCards[14], e); } +static void req_15(ENTITY *e) { request(&DivasCards[15], e); } + +IDI_CALL DivasIdiRequest[16] = +{ + &req_0, &req_1, &req_2, &req_3, + &req_4, &req_5, &req_6, &req_7, + &req_8, &req_9, &req_10, &req_11, + &req_12, &req_13, &req_14, &req_15 +}; + +#define PR_RAM ((struct pr_ram *)0) +#define RAM ((struct dual *)0) + +/*------------------------------------------------------------------*/ +/* local function prototypes */ +/*------------------------------------------------------------------*/ + +static byte isdn_rc(ADAPTER *, byte, byte, byte, word); +static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word); + +/* + * IDI related functions + */ + +static +ENTITY *entity_ptr(ADAPTER *a, byte e_no) +{ + card_t *card; + + card = a->io; + + return card->e_tbl[e_no].e; +} + +static +void CALLBACK(ADAPTER *a, ENTITY *e) +{ + card_t *card = a->io; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, FALSE); + } + + (*e->callback)(e); +} + +static +void *PTR_P(ADAPTER *a, ENTITY *e, void *P) +{ + return(P); +} + +static +void *PTR_R(ADAPTER *a, ENTITY *e) +{ + return((void*)e->R); +} + +static +void *PTR_X(ADAPTER *a, ENTITY *e) +{ + return((void*)e->X); +} + +static +void free_entity(ADAPTER *a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].e = NULL; + card->e_count--; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +void assign_queue(ADAPTER * a, byte e_no, word ref) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].assign_ref = ref; + card->e_tbl[e_no].next = card->assign; + card->assign = e_no; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte get_assign(ADAPTER *a, word ref) +{ + card_t *card; + byte e_no; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + e_no = (byte)card->assign; + while (e_no) + { + if (card->e_tbl[e_no].assign_ref == ref) + { + break; + } + e_no = card->e_tbl[e_no].next; + } + + UxCardUnlock(card->hw, ipl); + + return e_no; +} + +static +void req_queue(ADAPTER * a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].next = 0; + + if (card->e_head) + { + card->e_tbl[card->e_tail].next = e_no; + card->e_tail = e_no; + } + else + { + card->e_head = e_no; + card->e_tail = e_no; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte look_req(ADAPTER * a) +{ + card_t *card; + + card = a->io; + + return(card->e_head); +} + +static +void next_req(ADAPTER * a) +{ + card_t *card; + int ipl; + + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_head = card->e_tbl[card->e_head].next; + if (!card->e_head) + { + card->e_tail = 0; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + + +/* + * IDI request function for active cards + */ +static +void request(card_t *card, ENTITY *e) +{ + word *special_req; + int i; + int ipl; + + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, TRUE); + } + + if (!e->Req) + { + special_req = (word *) e; + + switch (*special_req) + { + case REQ_REMOVE: + return; + + case REQ_NAME: + for (i=0; i < DIM(card->cfg.name); i++) + { + ((struct get_name_s *) e)->name[i] = card->cfg.name[i]; + } + return; + + case REQ_SERIAL: + case REQ_XLOG: + DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG")); + return; + + default: + return; + } + } + + ipl = UxCardLock(card->hw); + + if (!(e->Id & 0x1f)) + { + DPRINTF(("IDI: ASSIGN req")); + + for (i = 1; i < card->e_max; i++) + { + if (!card->e_tbl[i].e) + { + break; + } + } + + if (i == card->e_max) + { + DPRINTF(("IDI: request all ids in use (IDI req ignored)")); + UxCardUnlock(card->hw, ipl); + e->Rc = OUT_OF_RESOURCES; + return; + } + + card->e_tbl[i].e = e; + card->e_count++; + + e->No = (byte) i; + e->More = 0; + e->RCurrent = 0xff; + } + else + { + i = e->No; + } + + if (e->More & XBUSY) + { + DPRINTF(("IDI: request - entity is busy")); + UxCardUnlock(card->hw, ipl); + return; + } + + e->More |= XBUSY; + e->More &= ~ XMOREF; + e->XCurrent = 0; + e->XOffset = 0; + + card->e_tbl[i].next = 0; + + if(card->e_head) + { + card->e_tbl[card->e_tail].next = i; + card->e_tail = i; + } + else + { + card->e_head = i; + card->e_tail = i; + } + + UxCardUnlock(card->hw, ipl); + + DivasScheduleRequestDpc(); + + return; +} + +static byte pr_ready(ADAPTER * a) +{ + byte ReadyCount; + + ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) - + a->ram_in(a, &PR_RAM->ReqInput)); + + if(!ReadyCount) { + if(!a->ReadyInt) { + a->ram_inc(a, &PR_RAM->ReadyInt); + a->ReadyInt++; + } + } + return ReadyCount; +} + +/*------------------------------------------------------------------*/ +/* output function */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a) +{ + byte e_no; + ENTITY * this = NULL; + BUFFERS *X; + word length; + word i; + word clength; + REQ * ReqOut; + byte more; + byte ReadyCount; + byte ReqCount; + byte Id; + + /* while a request is pending ... */ + e_no = look_req(a); + if(!e_no) + { + return; + } + + ReadyCount = pr_ready(a); + if(!ReadyCount) + { + DPRINTF(("IDI: card not ready for next request")); + return; + } + + ReqCount = 0; + while(e_no && ReadyCount) { + + next_req(a); + + this = entity_ptr(a, e_no); + +#ifdef USE_EXTENDED_DEBUGS + if ( !this ) + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum)) + e_no = look_req(a) ; + ReadyCount-- ; + continue ; + } + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req)) + } +#else + DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh)); +#endif + + /* get address of next available request buffer */ + ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)]; + + /* now copy the data from the current data buffer into the */ + /* adapters request buffer */ + length = 0; + i = this->XCurrent; + X = PTR_X(a,this); + while(iXNum && length<270) { + clength = MIN((word)(270-length),X[i].PLength-this->XOffset); + a->ram_out_buffer(a, + &ReqOut->XBuffer.P[length], + PTR_P(a,this,&X[i].P[this->XOffset]), + clength); + + length +=clength; + this->XOffset +=clength; + if(this->XOffset==X[i].PLength) { + this->XCurrent = (byte)++i; + this->XOffset = 0; + } + } + + a->ram_outw(a, &ReqOut->XBuffer.length, length); + a->ram_out(a, &ReqOut->ReqId, this->Id); + a->ram_out(a, &ReqOut->ReqCh, this->ReqCh); + + /* if its a specific request (no ASSIGN) ... */ + + if(this->Id &0x1f) { + + /* if buffers are left in the list of data buffers do */ + /* do chaining (LL_MDATA, N_MDATA) */ + + this->More++; + if(iXNum && this->MInd) { + a->ram_out(a, &ReqOut->Req, this->MInd); + more = TRUE; + } + else { + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + more = FALSE; + } + + /* if we did chaining, this entity is put back into the */ + /* request queue */ + + if(more) { + req_queue(a,this->No); + } + } + + /* else it's a ASSIGN */ + + else { + + /* save the request code used for buffer chaining */ + + this->MInd = 0; + if (this->Id==BLLC_ID) this->MInd = LL_MDATA; + if (this->Id==NL_ID || + this->Id==TASK_ID || + this->Id==MAN_ID + ) this->MInd = N_MDATA; + + /* send the ASSIGN */ + + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + + /* save the reference of the ASSIGN */ + + assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference)); + } + a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next)); + ReadyCount--; + ReqCount++; + + e_no = look_req(a); + } + + /* send the filled request buffers to the ISDN adapter */ + + a->ram_out(a, &PR_RAM->ReqInput, + (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount)); + + /* if it is a 'unreturncoded' UREMOVE request, remove the */ + /* Id from our table after sending the request */ + if(this->Req==UREMOVE && this->Id) { + Id = this->Id; + e_no = a->IdTable[Id]; + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + +} + +/*------------------------------------------------------------------*/ +/* isdn interrupt handler */ +/*------------------------------------------------------------------*/ + +byte DivasDpc(ADAPTER * a) +{ + byte Count; + RC * RcIn; + IND * IndIn; + byte c; + byte RNRId; + byte Rc; + byte Ind; + + /* if return codes are available ... */ + if((Count = a->ram_in(a, &PR_RAM->RcOutput))) { + + DPRINTF(("IDI: #Rc=%x",Count)); + + /* get the buffer address of the first return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)]; + + /* for all return codes do ... */ + while(Count--) { + + if((Rc=a->ram_in(a, &RcIn->Rc))) { + + /* call return code handler, if it is not our return code */ + /* the handler returns 2 */ + /* for all return codes we process, we clear the Rc field */ + isdn_rc(a, + Rc, + a->ram_in(a, &RcIn->RcId), + a->ram_in(a, &RcIn->RcCh), + a->ram_inw(a, &RcIn->Reference)); + + a->ram_out(a, &RcIn->Rc, 0); + } + + /* get buffer address of next return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)]; + } + + /* clear all return codes (no chaining!) */ + a->ram_out(a, &PR_RAM->RcOutput ,0); + + /* call output function */ + DivasOut(a); + } + + /* clear RNR flag */ + RNRId = 0; + + /* if indications are available ... */ + if((Count = a->ram_in(a, &PR_RAM->IndOutput))) { + + DPRINTF(("IDI: #Ind=%x",Count)); + + /* get the buffer address of the first indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)]; + + /* for all indications do ... */ + while(Count--) { + + /* if the application marks an indication as RNR, all */ + /* indications from the same Id delivered in this interrupt */ + /* are marked RNR */ + if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) { + a->ram_out(a, &IndIn->Ind, 0); + a->ram_out(a, &IndIn->RNR, TRUE); + } + else { + Ind = a->ram_in(a, &IndIn->Ind); + if(Ind) { + RNRId = 0; + + /* call indication handler, a return value of 2 means chain */ + /* a return value of 1 means RNR */ + /* for all indications we process, we clear the Ind field */ + c = isdn_ind(a, + Ind, + a->ram_in(a, &IndIn->IndId), + a->ram_in(a, &IndIn->IndCh), + &IndIn->RBuffer, + a->ram_in(a, &IndIn->MInd), + a->ram_inw(a, &IndIn->MLength)); + + if(c==1) { + DPRINTF(("IDI: RNR")); + a->ram_out(a, &IndIn->Ind, 0); + RNRId = a->ram_in(a, &IndIn->IndId); + a->ram_out(a, &IndIn->RNR, TRUE); + } + } + } + + /* get buffer address of next indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)]; + } + + a->ram_out(a, &PR_RAM->IndOutput, 0); + } + return FALSE; +} + +byte DivasTestInt(ADAPTER * a) +{ + return a->ram_in(a,(void *)0x3fe); +} + +void DivasClearInt(ADAPTER * a) +{ + a->ram_out(a,(void *)0x3fe,0); +} + +/*------------------------------------------------------------------*/ +/* return code handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_rc(ADAPTER * a, + byte Rc, + byte Id, + byte Ch, + word Ref) +{ + ENTITY * this; + byte e_no; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: ANum, Id, Rc)) + } +#else + DPRINTF(("IDI: ReadyInt) { + a->ReadyInt--; + return 0; + } + return 2; + } + + /* if we know this Id ... */ + e_no = a->IdTable[Id]; + if(e_no) { + + this = entity_ptr(a,e_no); + + this->RcCh = Ch; + + /* if it is a return code to a REMOVE request, remove the */ + /* Id from our table */ + if(this->Req==REMOVE && Rc==OK) { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; +/**************************************************************/ + if ((this->More & XMOREC) > 1) { + this->More &= ~XMOREC; + this->More |= 1; + DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id)); + } + } + + if (Rc==OK_FC) { + this->Rc = Rc; + this->More = (this->More & (~XBUSY | XMOREC)) | 1; + this->complete = 0xFF; + CALLBACK(a, this); + return 0; + } + if(this->More &XMOREC) + this->More--; + + /* call the application callback function */ + if(this->More &XMOREF && !(this->More &XMOREC)) { + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + } + return 0; + } + + /* if it's an ASSIGN return code check if it's a return */ + /* code to an ASSIGN request from us */ + if((Rc &0xf0)==ASSIGN_RC) { + + e_no = get_assign(a, Ref); + + if(e_no) { + + this = entity_ptr(a,e_no); + + this->Id = Id; + + /* call the application callback function */ + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + + if(Rc==ASSIGN_OK) { + a->IdTable[Id] = e_no; + } + else + { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + return 1; + } + } + return 2; +} + +/*------------------------------------------------------------------*/ +/* indication handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_ind(ADAPTER * a, + byte Ind, + byte Id, + byte Ch, + PBUFFER * RBuffer, + byte MInd, + word MLength) +{ + ENTITY * this; + word clength; + word offset; + BUFFERS *R; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: ANum, Id, Ind)) + } +#else + DPRINTF(("IDI: IdTable[Id]) { + + this = entity_ptr(a,a->IdTable[Id]); + + this->IndCh = Ch; + + /* if the Receive More flag is not yet set, this is the */ + /* first buffer of the packet */ + if(this->RCurrent==0xff) { + + /* check for receive buffer chaining */ + if(Ind==this->MInd) { + this->complete = 0; + this->Ind = MInd; + } + else { + this->complete = 1; + this->Ind = Ind; + } + + /* call the application callback function for the receive */ + /* look ahead */ + this->RLength = MLength; + + a->ram_look_ahead(a, RBuffer, this); + + this->RNum = 0; + CALLBACK(a, this); + + /* map entity ptr, selector could be re-mapped by call to */ + /* IDI from within callback */ + this = entity_ptr(a,a->IdTable[Id]); + + /* check for RNR */ + if(this->RNR==1) { + this->RNR = 0; + return 1; + } + + /* if no buffers are provided by the application, the */ + /* application want to copy the data itself including */ + /* N_MDATA/LL_MDATA chaining */ + if(!this->RNR && !this->RNum) { + return 0; + } + + /* if there is no RNR, set the More flag */ + this->RCurrent = 0; + this->ROffset = 0; + } + + if(this->RNR==2) { + if(Ind!=this->MInd) { + this->RCurrent = 0xff; + this->RNR = 0; + } + return 0; + } + /* if we have received buffers from the application, copy */ + /* the data into these buffers */ + offset = 0; + R = PTR_R(a,this); + do { + if(this->ROffset==R[this->RCurrent].PLength) { + this->ROffset = 0; + this->RCurrent++; + } + clength = MIN(a->ram_inw(a, &RBuffer->length)-offset, + R[this->RCurrent].PLength-this->ROffset); + if(R[this->RCurrent].P) { + a->ram_in_buffer(a, + &RBuffer->P[offset], + PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]), + clength); + } + offset +=clength; + this->ROffset +=clength; + } while(offset<(a->ram_inw(a, &RBuffer->length))); + + /* if it's the last buffer of the packet, call the */ + /* application callback function for the receive complete */ + /* call */ + if(Ind!=this->MInd) { + R[this->RCurrent].PLength = this->ROffset; + if(this->ROffset) this->RCurrent++; + this->RNum = this->RCurrent; + this->RCurrent = 0xff; + this->Ind = Ind; + this->complete = 2; + CALLBACK(a, this); + } + return 0; + } + return 2; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/idi.h linux/drivers/isdn/eicon/idi.h --- v2.2.18/drivers/isdn/eicon/idi.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/idi.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,143 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* External IDI interface */ + +#if !defined(IDI_H) +#define IDI_H + +#include "sys.h" + +/* typedefs for our data structures */ + +typedef struct get_name_s GET_NAME; +typedef struct entity_s ENTITY; +typedef struct buffers_s BUFFERS; + +/* IDI request/callback function pointer */ + +typedef void (* IDI_CALL)(ENTITY *); + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} DBUFFER; + +#define REQ_NAME 0x0100 +#define BOARD_NAME_LENGTH 9 +struct get_name_s { + word command; /* command = 0x0100 */ + byte name[BOARD_NAME_LENGTH]; +}; + +#define REQ_REMOVE 0x0000 /* pointer to word which is 0 */ +#define REQ_SERIAL 0x0200 +struct get_serial_s { + word command; /* command = 0x0200 */ + dword serial; /* serial number */ +}; + +#define REQ_POSTCALL 0x0300 +struct postcall_s { + word command; /* command = 0x0300 */ + word dummy; /* not used */ + IDI_CALL callback; /* routine adress to call back */ + ENTITY *contxt; /* ptr to entity to use */ +}; + +#define REQ_XLOG 0x0400 /* structure is card dependent/defined locally */ + +struct buffers_s { + word PLength; + byte *P; +}; + +struct entity_s { + byte Req; /* pending request */ + byte Rc; /* return code received */ + byte Ind; /* indication received */ + byte ReqCh; /* channel of current Req */ + byte RcCh; /* channel of current Rc */ + byte IndCh; /* channel of current Ind */ + byte Id; /* ID used by this entity */ + byte GlobalId; /* reserved field */ + byte XNum; /* number of X-buffers */ + byte RNum; /* number of R-buffers */ + BUFFERS *X; /* pointer to X-buffer list */ + BUFFERS *R; /* pointer to R-buffer list */ + word RLength; /* length of current R-data */ + DBUFFER *RBuffer; /* buffer of current R-data */ + byte RNR; /* receive not ready flag */ + byte complete; /* receive complete status */ + IDI_CALL callback; + + word user[2]; + + /* fields used by the driver internally */ + byte No; /* entity number */ + byte reserved2; /* reserved field */ + byte More; /* R/X More flags */ + byte MInd; /* MDATA coding for this ID */ + byte XCurrent; /* current transmit buffer */ + byte RCurrent; /* current receive buffer */ + word XOffset; /* offset in x-buffer */ + word ROffset; /* offset in r-buffer */ +}; + +typedef struct { + byte type; + byte channels; + word features; + /* dword serial; */ + IDI_CALL request; +} DESCRIPTOR; + +extern void DIVA_DIDD_Read(DESCRIPTOR *, int); + + /* descriptor type field coding */ +#define IDI_ADAPTER_S 1 +#define IDI_ADAPTER_PR 2 +#define IDI_ADAPTER_DIVA 3 +#define IDI_ADAPTER_MAESTRA 4 +#define IDI_ADAPTER_MAESTRAQ 5 +#define IDI_ADAPTER_MAESTRAP 6 +#define IDI_VADAPTER 0x40 +#define IDI_DRIVER 0x80 +#define IDI_DIMAINT 0xff + +/* feature bit mask values */ + +#define DI_VOICE 0x0 /* obsolete define */ +#define DI_FAX3 0x1 +#define DI_MODEM 0x2 +#define DI_POST 0x4 +#define DI_V110 0x8 +#define DI_V120 0x10 +#define DI_POTS 0x20 +#define DI_CODEC 0x40 +#define DI_MANAGE 0x80 +#define DI_V_42 0x0100 +#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */ + +#endif /* IDI_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/kprintf.c linux/drivers/isdn/eicon/kprintf.c --- v2.2.18/drivers/isdn/eicon/kprintf.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/kprintf.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,535 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.3 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Source file for kernel interface to kernel log facility + */ + + +#include "sys.h" +#include +#undef MAX +#undef MIN + +#include +#include + +#include "divas.h" +#include "divalog.h" +#include "uxio.h" + +/* + * Implementation of printf and sprintf for kernel + */ + +#define MAX_BUFF (80) /* limit size of temporary buffers */ + +#define WRITE_CHAR(BUFFER, SIZE, C) \ + if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C) + + +/* + * convert a number to decimal ASCII + */ + +static +void do_decimal( char *temp, + int temp_len, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i < temp_len; i++) + { + temp[i] = (char) ((value % 10) + (int) '0'); + value /= 10; + } + + for (i = (temp_len - 1); temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to octal ASCII + */ + +static +void do_octal( char *temp, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i <= 11; i++) + { + temp[i] = (char) ((value & 07) + (int) '0'); + value >>= 3; + } + temp[11] &= '3'; + + for (i = 11; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to hex ASCII + */ + +static +void do_hex( char *temp, + unsigned int value, + char *s) + +{ + int i; + static + char *dec_to_hex = "0123456789abcdef"; + + temp[0] = '\0'; + + for (i = 1; i <= 8; i++) + { + temp[i] = dec_to_hex[value & 0x0f]; + value >>= 4; + } + + for (i = 8; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a buffer to ASCII HEX + */ + +static +void do_buffer( char *buffer, + int length, + char *s) + +{ + static + char hex_char [] = "0123456789abcdef"; + char *b = buffer; + int hex_byte; + int nybble; + + length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length; + + while (length) + { + hex_byte = (int) *b++; + nybble = (hex_byte >> 4) & 0xf; + *s++ = hex_char[nybble]; + nybble = hex_byte & 0xf; + *s++ = hex_char[nybble]; + *s++ = ' '; + length--; + } + *s = '\0'; + + return; +} + +/* + * Body of sprintf function: behaves just like standard sprintf, except we + * have an extra argument (buffer size) which we use to ensure we don't + * overflow + */ + +void Divas_vsprintf( char *buffer, + int size, + char *fmt, + va_list argptr) + +{ + char c; /* single character buffer */ + int i; /* handy scratch counter */ + int f; /* format character (after %) */ + char *str; /* pointer into string */ + char temp[20]; /* temp buffer used in printing numbers */ + char string[MAX_BUFF]; /* output from number conversion */ + int length; /* length of string "str" */ + char fill; /* fill character ' ' or '0' */ + boolean_t leftjust; /* TRUE if left justified, else right justified */ + int fmax, fmin; /* field specifiers % MIN . MAX s */ + int leading; /* number of leading/trailing fill characters */ + char sign; /* set to '-' for negative decimals */ + int number; /* numeric argument */ + + char *buff_ptr; /* pointer to user's buffer of hex data */ + int buff_len; /* length of hex data */ + + /* make sure we have somthing to write into */ + + if ((!buffer) || (size <= 0)) + { + return; + } + + while (TRUE) + { + /* echo characters until end or '%' encountered */ + + while ((c = *fmt++) != '%') + { + if (!c) + { + *buffer = '\0'; + return; + } + WRITE_CHAR(buffer, size, c); + } + + /* echo %% as % */ + + if (*fmt == '%') + { + WRITE_CHAR(buffer, size, *fmt); + continue; + } + + /* %- turns on left-justify */ + + if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE))) + { + fmt++; + } + + /* %0 turns on zero filling */ + + if (*fmt == '0') + { + fill = '0'; + } + else + { + fill = ' '; + } + + /* minium field width specifier for %d, u, x, c, s */ + + fmin = 0; + + if (*fmt == '*') + { + fmin = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmin = (fmin * 10) + (*fmt++ - '0'); + } + } + + /* maximum string width specifier for %s */ + + fmax = 0; + + if (*fmt == '.') + { + if (*(++fmt) == '*') + { + fmax = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmax = (fmax * 10) + (*fmt++ - '0'); + } + } + } + + /* skip over 'l' option (ints are assumed same size as longs) */ + + if (*fmt == 'l') + { + fmt++; + } + + /* get the format chacater */ + + if (!(f = *fmt++)) + { + WRITE_CHAR(buffer, size, '%'); + *buffer = '\0'; + return; + } + + sign = '\0'; /* sign == '-' for negative decimal */ + + str = string; + + switch (f) + { + case 'c' : + string[0] = (char) va_arg(argptr, int); + string[1] = '\0'; + fmax = 0; + fill = ' '; + break; + + case 's' : + str = va_arg(argptr, char *); + fill = ' '; + break; + + case 'D' : + case 'd' : + number = va_arg(argptr, int); + if (number < 0) + { + sign = '-'; + number = -number; + } + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'U' : + case 'u' : + number = va_arg(argptr, int); + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'O' : + case 'o' : + number = va_arg(argptr, int); + do_octal(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'X' : + case 'x' : + number = va_arg(argptr, int); + do_hex(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'H' : + case 'h' : + buff_ptr = va_arg(argptr, char *); + buff_len = va_arg(argptr, int); + do_buffer(buff_ptr, buff_len, str); + fmax = 0; + break; + + default : + WRITE_CHAR(buffer, size, ((char) f)); + break; + } + + /* get the length of the string */ + + length = 0; + while (str[length]) + { + length++; + } + + /* make sure we have fmax and fmin values that are O.K. */ + + if (fmin > DIM(string) || fmin < 0) + { + fmin = 0; + } + + if (fmax > DIM(string) || fmax < 0) + { + fmax = 0; + } + + /* figure out how many leading characters thare are */ + + leading = 0; + + if (fmax || fmin) + { + if (fmax) + { + if (length > fmax) + { + length = fmax; + } + } + + if (fmin) + { + leading = fmin - length; + } + + if (sign == '-') + { + leading--; + } + } + + /* output sign now, if fill is numeric */ + + if (sign == '-' && fill == '0') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* if right justified, output fill characters */ + + if (!leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + + /* output sign now, if fill is spaces */ + + if (sign == '-' && fill == ' ') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* now the actual value */ + + for (i = 0; i < length; i++) + { + WRITE_CHAR(buffer, size, str[i]); + } + + /* if left justified, fill out with the fill character */ + + if (leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + } +} + +/* + * sprintf for kernel + * + * call our vsprintf assuming user has a big buffer.... + */ + +void DivasSprintf(char *buffer, char *fmt, ...) + +{ + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + Divas_vsprintf(buffer, 1024, fmt, argptr); + + va_end(argptr); + + return; +} + +void DivasPrintf(char *fmt, ...) + +{ + klog_t log; /* log entry buffer */ + + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + /* clear log entry */ + + bzero((caddr_t) &log, sizeof(klog_t)); + + log.card = -1; + log.type = KLOG_TEXT_MSG; + + /* time stamp the entry */ + + log.time_stamp = UxTimeGet(); + + /* call vsprintf to format the user's information */ + + Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr); + + va_end(argptr); + + /* send to the log streams driver and return */ + + DivasLogAdd(&log, sizeof(klog_t)); + + return; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/lincfg.c linux/drivers/isdn/eicon/lincfg.c --- v2.2.18/drivers/isdn/eicon/lincfg.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/lincfg.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,407 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.9 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#undef N_DATA /* Because we have our own definition */ + +#include +#include + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" +#include "pr_pc.h" + +#include "adapter.h" +#include "uxio.h" + +#include +#include +#include + +#define HW_ID_EICON_PCI 0x1133 +#define HW_ID_DIVA_SERVER_P 0xE014 +#define HW_ID_DIVA_SERVER_B_ST 0xE010 +#define HW_ID_DIVA_SERVER_B_U 0xE013 +#define HW_ID_DIVA_SERVER_Q 0xE012 + +struct file_operations Divas_fops; +int Divas_major; + +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable); +extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset); +extern int do_open(struct inode *, struct file *); +extern int do_release(struct inode *, struct file *); + +int FPGA_Done=0; + +int DivasCardsDiscover(void) +{ + word wNumCards = 0, wDeviceIndex = 0; + byte byBus, byFunc; + word wPCIConsultation, PCItmp; + dword j, i; + unsigned int PCIserial; + dia_card_t Card; + byte *b; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_Q, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + + dword dwRAM, dwDivasIOBase, dwCFG, dwCTL; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM); + dwRAM &= 0xFFC00000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG); + dwCFG &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL); + dwCTL &= 0xFFFFE000; + + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + /* Retrieve the serial number */ + + pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC); + + for (j=0, PCItmp=0; j<10000 && !PCItmp; j++) + { + pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp); + PCItmp &= 0x8000; // extract done flag + } + + pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial); + + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000); + Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100); + Card.io_base=dwDivasIOBase; + + Card.irq = byIRQ; + + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q; + Card.bus_type = DIA_BUS_TYPE_PCI; + + FPGA_Done = 0; + + /* Create four virtual card structures as we want to treat + the 4Bri card as 4 Bri cards*/ + for(i=0;i<4;i++) + { + + b=Card.memory[DIVAS_RAM_MEMORY]; + b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1); + DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET)); + Card.memory[DIVAS_RAM_MEMORY]=b; + + b = Card.memory[DIVAS_RAM_MEMORY]; + b += MQ_SM_OFFSET; + Card.memory[DIVAS_SHARED_MEMORY] = b; + + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + + + /* Fill in Name */ + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'Q'; + Card.name[6] = '0' + i; + Card.name[7] = '\0'; + + Card.serial = PCIserial; + + Card.card_id = wNumCards; + + if (DivasCardNew(&Card) != 0) + { + // Force for loop to terminate + i = 4; + continue; + } + wNumCards++; + + }//for + } + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_ST, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_U, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_P, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwRAM, dwREG, dwCFG; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM); + dwRAM &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG); + dwREG &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG); + dwCFG &= 0xFFFFF000; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000); + Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000); + Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET; + +/* pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFFFc; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF80; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); +*/ + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; +/* Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase;*/ + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'P'; + Card.name[6] = '\0'; + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + + printk(KERN_INFO "Divas: %d cards detected\n", wNumCards); + + if(wNumCards == 0) + { + return -1; + } + + Divas_fops.ioctl = do_ioctl; + Divas_fops.poll = do_poll; + Divas_fops.read = do_read; + Divas_fops.open = do_open; + Divas_fops.release = do_release; + + Divas_major = register_chrdev(0, "Divas", &Divas_fops); + + if (Divas_major < 0) + { + printk(KERN_WARNING "Divas: Unable to register character driver\n"); + return -1; + } + + return 0; +} + +/* Error return -1 */ +int DivasConfigGet(dia_card_t *card) +{ + /* Retrieve Config from O/S? Not in Linux */ + return 0; +} + +dia_config_t *DivasConfig(card_t *card, dia_config_t *config) +{ + /* If config retrieved from OS then copy the data into a dia_config_t structure here + and return the pointer here. If the config 'came from above' then just + + return config; + */ + + return config; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/linchr.c linux/drivers/isdn/eicon/linchr.c --- v2.2.18/drivers/isdn/eicon/linchr.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/linchr.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,269 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.12 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include + +#include +#include +#include +#include + +#undef N_DATA + +#include "adapter.h" +#include "divas.h" +#include "divalog.h" + +extern int DivasCardNext; +void UxPause(long ms); +void bcopy(void *pSource, void *pDest, dword dwLength); +int DivasGetMem(mem_block_t *); + +#define DIA_IOCTL_UNLOCK 12 +void UnlockDivas(void); + +int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg) +{ + dia_load_t *pDivaLoad; + dia_start_t *pDivaStart; + dia_config_t *pDivaConfig; + dia_log_t *pDivaLog; + byte *pUserCards, card_i; + word wCardNum; + mem_block_t *mem_block; + + switch (command) + { + case DIA_IOCTL_CONFIG: + pDivaConfig = (dia_config_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t))) + { + DivasCardConfig(pDivaConfig); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_DETECT: + pUserCards = (byte *) arg; + + if (!verify_area(VERIFY_WRITE, pUserCards, 20)) + { + put_user(DivasCardNext, pUserCards++); + + for (card_i=1; card_i < 20; card_i++) + { + put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++); + } + } + else + { + printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_START: + pDivaStart = (dia_start_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t))) + { + return DivasCardStart(pDivaStart->card_id); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n"); + return -1; + } + + + case DIA_IOCTL_FLAVOUR: + return 0; + + case DIA_IOCTL_LOAD: + pDivaLoad = (dia_load_t *) arg; + if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length)) + { + if (DivasCardLoad(pDivaLoad)) + { + printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n"); + return -EINVAL; + } + } + else + { + printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n"); + return -EINVAL; + } + return 0; + + case DIA_IOCTL_LOG: + pDivaLog = (dia_log_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t))) + { + DivasLog(pDivaLog); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_XLOG_REQ: + + if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word))) + { + wCardNum = * (word *) arg; + DivasXlogReq(wCardNum); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_NUM: + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) + { + * (int *) arg = DivasCardNext; + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_LIST: + DPRINTF(("divas: DIA_IOCTL_GET_LIST")); + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t))) + { + DivasGetList((dia_card_list_t *)arg); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_MEM: + mem_block = (mem_block_t *) arg; + + if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t))) + { + DivasGetMem(mem_block); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_UNLOCK: + UnlockDivas(); + return 0; + + default: + printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command); + return -EINVAL; + } + + return -EINVAL; +} + +unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable) +{ + word wMask = 0; + + if (!DivasLogFifoEmpty()) + { + wMask |= POLLIN | POLLRDNORM; + } + + return wMask; +} + +ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset) +{ + klog_t *pClientLogBuffer = (klog_t *) pUserBuffer; + klog_t *pHeadItem; + + if (BufferSize < sizeof(klog_t)) + { + printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n", + BufferSize, sizeof(klog_t)); + return 0; + } + + pHeadItem = (klog_t *) DivasLogFifoRead(); + + if (pHeadItem) + { + bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t)); + kfree(pHeadItem); + return sizeof(klog_t); + } + + return 0; +} +static int private_usage_count; + +int do_open(struct inode *pInode, struct file *pFile) +{ + MOD_INC_USE_COUNT; +#ifdef MODULE + private_usage_count++; +#endif + return 0; +} + +int do_release(struct inode *pInode, struct file *pFile) +{ + MOD_DEC_USE_COUNT; +#ifdef MODULE + private_usage_count--; +#endif + return 0; +} + +void UnlockDivas(void) +{ + while (private_usage_count > 0) + { + private_usage_count--; + MOD_DEC_USE_COUNT; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/linio.c linux/drivers/isdn/eicon/linio.c --- v2.2.18/drivers/isdn/eicon/linio.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/linio.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,747 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.16 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#define N_DATA + +#include +#include +#include +#include +#include +#undef N_DATA + +#include "uxio.h" + +static +int log_on=0; + +int Divasdevflag = 0; + +//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED; + +static +ux_diva_card_t card_pool[MAX_CARDS]; + +void UxPause(long int ms) +{ + int timeout = jiffies + ((ms * HZ) / 1000); + + while (time_before(jiffies, timeout)); +} + +int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg) +{ + int i; + ux_diva_card_t *c; + + if (cfg->bus_type != DIA_BUS_TYPE_PCI) + { + DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type)); + return -1; + } + + for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++) + { + ; + } + + if (i == DIM(card_pool)) + { + DPRINTF(("divas hw: card_pool exhausted")); + return -1; + } + + c = *card = &card_pool[i]; + + switch (cfg->bus_type) + { + case DIA_BUS_TYPE_PCI: + c->bus_num = cfg->bus_num; + c->func_num = cfg->func_num; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->card_type = cfg->card_type; + c->mapped = NULL; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + c->pCONTROL = cfg->memory[DIVAS_CTL_MEMORY]; + + /* c->bus_type = DIA_BUS_TYPE_PCI; + c->bus_num = cfg->bus_num & 0x3f; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->int_priority = (int) cfg->int_priority; + c->card_type = cfg->card_type; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM)); + DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED)); + DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG)); + c->cm_key = cm_getbrdkey("Divas", cfg->card_id);*/ + break; + default: + break; + } + + c->in_use = TRUE; + + return 0; +} + +void UxCardHandleFree(ux_diva_card_t *card) +{ + card->in_use = FALSE; +} + + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 +void *UxCardMemAttach(ux_diva_card_t *card, int id) +{ + if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = card->pDEVICES; + return card->pDEVICES; + break; + case DIVAS_CFG_MEMORY: + card->mapped = card->pCONFIG; + return card->pCONFIG; + break; + default: + ASSERT(FALSE); + card->mapped = NULL; + return (void *) 0; + } + } + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + switch (id) + { + case PLX_IOBASE: + return (void *) card->reset_base; + break; + case DIVAS_IOBASE: + return (void *) card->io_base; + break; + default: + ASSERT(FALSE); + return 0; + } + } + + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = (void *) card->io_base; + return (void *) card->io_base; + break; + case DIVAS_CTL_MEMORY: + card->mapped = card->pCONTROL; + return card->pCONTROL; + break; + default: + // ASSERT(FALSE); + DPRINTF(("divas: Trying to attach to mem %d", id)); + card->mapped = NULL; + return (void *) 0; + } + } else + DPRINTF(("divas: Tried to attach to unknown card")); + + /* Unknown card type */ + return NULL; +} + +void UxCardMemDetach(ux_diva_card_t *card, void *address) +{ + return; // Just a place holder. No un-mapping done. +} + +void UxCardLog(int turn_on) +{ + log_on = turn_on; +} + +/* + * Control Register I/O Routines to be performed on Attached I/O ports + */ + +void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outb(the_byte, base); +} + +void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outw(the_word, base); +} + +void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outl(the_dword, base); +} + +byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inb(base); +} + +word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inw(base); +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address) +{ + byte b; + volatile byte* t = (byte*)address; + + b = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a)); + } + + return(b); +} + +word UxCardMemInW(ux_diva_card_t *card, void *address) +{ + word w; + volatile word* t = (word*)address; + + w = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a)); + } + + return (w); +} + +dword UxCardMemInD(ux_diva_card_t *card, void *address) +{ + dword dw; + volatile dword* t = (dword*)address; + + dw = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a)); + } + + return (dw); +} + +void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + volatile byte *pSource = address; + byte *pDest = buffer; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data) +{ + volatile byte* t = (byte*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a)); + } + + *t = data; + + return; +} + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data) +{ + volatile word* t = (word*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a)); + } + + *t = data; + return; +} + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data) +{ + volatile dword* t = (dword*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a)); + } + + *t = data; + return; +} + +void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + byte *pSource = buffer; + byte *pDest = address; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + byte the_byte; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + + the_byte = inb(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)", + the_byte & 0xff, address)); + } + + return the_byte; +} + +word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + word the_word; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_word = inw(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)", + the_word & 0xffff, address)); + } + + return the_word; +} + +dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + dword the_dword; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_dword = inl(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)", + the_dword, address)); + } + + return the_dword; +} + +void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = address; + byte *pDest = buffer; + + if ((word) (dword) address & 0x1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + *pDest = (byte) inb(card->io_base); + pDest++; + pSource++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +/* Output */ + +void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)", + data & 0xff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outb((byte) data & 0xFF, card->io_base); + + return; +} + +void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)", + data & 0xffff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outw((word) data & 0xFFFF, card->io_base); + + return; +} + +void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outl((dword) data & 0xFFFFFFFF, card->io_base); + + return; +} + +void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = buffer; + byte *pDest = address; + + if ((word) (dword) address & 1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outb(*pSource, card->io_base); + pSource++; + pDest++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +void Divasintr(int arg, void *unused, struct pt_regs *unused_regs) +{ + int i; + card_t *card = NULL; + ux_diva_card_t *ux_ref = NULL; + + for (i = 0; i < DivasCardNext; i++) + { + + if (arg == DivasCards[i].cfg.irq) + { + card = &DivasCards[i]; + ux_ref = card->hw; + + if ((ux_ref) && (card->is_live)) + { + (*ux_ref->user_isr)(ux_ref->user_isr_arg); + } + else + { + DPRINTF(("divas: ISR couldn't locate card")); + } + } + } + + return; +} + + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg) +{ + int result; + + card->user_isr = isr_fn; + card->user_isr_arg = isr_arg; + + result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg); + + return result; +} + +void UxIsrRemove(ux_diva_card_t *card, void *dev_id) +{ + free_irq(card->irq, card->user_isr_arg); +} + +void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value); + break; + case sizeof(word): + pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value); + break; + case sizeof(dword): + pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n"); + } +} + +void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value); + break; + case sizeof(word): + pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value); + break; + case sizeof(dword): + pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n"); + } +} + +void *UxAlloc(unsigned int size) +{ + void *m; + + m = kmalloc(size, GFP_ATOMIC); + + return m; +} + +void UxFree(void *ptr) +{ + kfree(ptr); +} + +int UxCardLock(ux_diva_card_t *card) +{ + unsigned long flags; + + //spin_lock_irqsave(&diva_lock, flags); + + save_flags(flags); + cli(); + return flags; + +} + +void UxCardUnlock(ux_diva_card_t *card, int ipl) +{ + //spin_unlock_irqrestore(&diva_lock, ipl); + + restore_flags(ipl); + +} + +dword UxTimeGet(void) +{ + return jiffies; +} + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p += 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} + +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p -= 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/linsys.c linux/drivers/isdn/eicon/linsys.c --- v2.2.18/drivers/isdn/eicon/linsys.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/linsys.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,167 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.10 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#undef N_DATA +#include + +#include +struct pt_regs; +#include +#include + +#include "sys.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +#ifdef MODULE +void bcopy(void *pSource, void *pDest, dword dwLength) +{ + memcpy(pDest, pSource, dwLength); +} +#endif + +void bzero(void *pDataArea, dword dwLength) +{ + memset(pDataArea, 0, dwLength); +} + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); +*/ + return 0; +} + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/ + + return 0; +} + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Need to set these platform dependent values after patching */ + + card->hw->reset_base = card->cfg.reset_base; + card->hw->io_base = card->cfg.io_base; + + request_region(card->hw->reset_base,0x80,"Divas"); + request_region(card->hw->io_base,0x20,"Divas"); + + + /* Same as for PRI */ + return DivasPRIInitPCI(card, cfg); +} + +/* ######################### Stubs of routines that are not done yet ################## */ +/*void DivasLogIdi(card_t *card, ENTITY *e, int request) +{ +} +*/ + +int DivasDpcSchedule(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +int DivasScheduleRequestDpc(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoRequestDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +void DivasLogAdd(void *buffer, int length) +{ + static + boolean_t overflow = FALSE; + static + boolean_t busy = FALSE; + + /* make sure we're not interrupting ourselves */ + + if (busy) + { + printk(KERN_DEBUG "Divas: Logging interrupting self !\n"); + return; + } + busy = TRUE; + + /* ignore call if daemon isn't running and we've reached limit */ + + if (DivasLogFifoFull()) + { + if (!overflow) + { + printk(KERN_DEBUG "Divas: Trace buffer full\n"); + overflow = TRUE; + } + busy = FALSE; + return; + } + + DivasLogFifoWrite(buffer, length); + + busy = FALSE; + return; +} + +/* #################################################################################### */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/log.c linux/drivers/isdn/eicon/log.c --- v2.2.18/drivers/isdn/eicon/log.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/log.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,176 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.5 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Source file for diva log facility + */ + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +/*Counter to monitor number of messages */ +static int m_count; + +#define MAX_BUFFERED_MSGS (1000) + +/* Our Linked List Structure to hold message */ +typedef struct klog_link{ + klog_t klog; + struct klog_link *next; +}KNODE; + +/* First & Last structures in list*/ +KNODE *head; +KNODE *tail; + +/* + * retrieve message from FIFO buffer + * returns NULL if buffer empty + * otherwise returns pointer to entry + */ + +char *DivasLogFifoRead(void) + +{ + KNODE *old_head; + + if(head==NULL) + { + /* Buffer Empty - No Messages */ + return NULL; + } + + m_count--; + /* Keep track of message to be read & increment to next message*/ + old_head = head; + head = head->next; + /*Return ptr to Msg */ + return((char *)old_head); +} + +/* + * write message into FIFO buffer + */ + +void DivasLogFifoWrite(char *entry, int length) + +{ + KNODE *new_klog; + + if(head == NULL) + { + /* No Entries in Log */ + tail=NULL; + m_count=0; + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Set head & tail to point to the new Msg Struct */ + head=tail=new_klog; + tail->next=NULL; + } + else + { + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Let last Msg Struct point to new Msg Struct & inc tail */ + tail->next=new_klog; + tail=new_klog; + tail->next=NULL; + } + + if (length > sizeof(klog_t)) + { + length = sizeof(klog_t); + } + + bcopy(entry,&tail->klog,length); + + return; +} + +/* + * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE + */ +int DivasLogFifoEmpty(void) +{ + return (m_count == 0); +} + +/* + *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE + */ +int DivasLogFifoFull(void) +{ + return (m_count == MAX_BUFFERED_MSGS); +} + +/* + * generate an IDI log entry + */ + +void DivasLogIdi(card_t *card, ENTITY *e, int request) + +{ + klog_t klog; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = UxTimeGet(); + + klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ? + sizeof(klog.buffer) : sizeof(ENTITY); + + klog.card = (int) (card - DivasCards); + + klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK; + klog.code = 0; + bcopy(e, klog.buffer, klog.length); + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/pc.h linux/drivers/isdn/eicon/pc.h --- v2.2.18/drivers/isdn/eicon/pc.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/pc.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,317 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef PC_H_INCLUDED +#define PC_H_INCLUDED + + +#define byte unsigned char +#define word unsigned short +#define dword unsigned long +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/*------------------------------------------------------------------*/ +/* buffer definition */ +/*------------------------------------------------------------------*/ + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} PBUFFER; + +/*------------------------------------------------------------------*/ +/* dual port ram structure */ +/*------------------------------------------------------------------*/ + +struct dual +{ + byte Req; /* request register */ + byte ReqId; /* request task/entity identification */ + byte Rc; /* return code register */ + byte RcId; /* return code task/entity identification */ + byte Ind; /* Indication register */ + byte IndId; /* Indication task/entity identification */ + byte IMask; /* Interrupt Mask Flag */ + byte RNR; /* Receiver Not Ready (set by PC) */ + byte XLock; /* XBuffer locked Flag */ + byte Int; /* ISDN-S interrupt */ + byte ReqCh; /* Channel field for layer-3 Requests */ + byte RcCh; /* Channel field for layer-3 Returncodes */ + byte IndCh; /* Channel field for layer-3 Indications */ + byte MInd; /* more data indication field */ + word MLength; /* more data total packet length */ + byte ReadyInt; /* request field for ready interrupt */ + byte SWReg; /* Software register for special purposes */ + byte Reserved[11]; /* reserved space */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-S adapter Signature (GD) */ + PBUFFER XBuffer; /* Transmit Buffer */ + PBUFFER RBuffer; /* Receive Buffer */ +}; + +/*------------------------------------------------------------------*/ +/* SWReg Values (0 means no command) */ +/*------------------------------------------------------------------*/ +#define SWREG_DIE_WITH_LEDON 0x01 +#define SWREG_HALT_CPU 0x02 /* Push CPU into a while(1) loop */ + +/*------------------------------------------------------------------*/ +/* Id Fields Coding */ +/*------------------------------------------------------------------*/ + +#define ID_MASK 0xe0 /* Mask for the ID field */ +#define GL_ERR_ID 0x1f /* ID for error reporting on global requests*/ + +#define DSIG_ID 0x00 /* ID for D-channel signaling */ +#define NL_ID 0x20 /* ID for network-layer access (B or D) */ +#define BLLC_ID 0x60 /* ID for B-channel link level access */ +#define TASK_ID 0x80 /* ID for dynamic user tasks */ +#define TIMER_ID 0xa0 /* ID for timer task */ +#define TEL_ID 0xc0 /* ID for telephone support */ +#define MAN_ID 0xe0 /* ID for management */ + +/*------------------------------------------------------------------*/ +/* ASSIGN and REMOVE requests are the same for all entities */ +/*------------------------------------------------------------------*/ + +#define ASSIGN 0x01 +#define UREMOVE 0xfe /* without returncode */ +#define REMOVE 0xff + +/*------------------------------------------------------------------*/ +/* Timer Interrupt Task Interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TIM 0x01 +#define REMOVE_TIM 0xff + +/*------------------------------------------------------------------*/ +/* dynamic user task interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TSK 0x01 +#define REMOVE_TSK 0xff + +#define LOAD 0xf0 +#define RELOCATE 0xf1 +#define START 0xf2 +#define LOAD2 0xf3 +#define RELOCATE2 0xf4 + +/*------------------------------------------------------------------*/ +/* dynamic user task messages */ +/*------------------------------------------------------------------*/ + +#define TSK_B2 0x0000 +#define TSK_WAKEUP 0x2000 +#define TSK_TIMER 0x4000 +#define TSK_TSK 0x6000 +#define TSK_PC 0xe000 + +/*------------------------------------------------------------------*/ +/* LL management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_LL 1 /* assign logical link */ +#define REMOVE_LL 0xff /* remove logical link */ + +/*------------------------------------------------------------------*/ +/* LL service primitives */ +/*------------------------------------------------------------------*/ + +#define LL_UDATA 1 /* link unit data request/indication */ +#define LL_ESTABLISH 2 /* link establish request/indication */ +#define LL_RELEASE 3 /* link release request/indication */ +#define LL_DATA 4 /* data request/indication */ +#define LL_LOCAL 5 /* switch to local operation (COM only) */ +#define LL_DATA_PEND 5 /* data pending indication (SDLC SHM only) */ +#define LL_REMOTE 6 /* switch to remote operation (COM only) */ +#define LL_TEST 8 /* link test request */ +#define LL_MDATA 9 /* more data request/indication */ +#define LL_BUDATA 10 /* broadcast unit data request/indication */ +#define LL_XID 12 /* XID command request/indication */ +#define LL_XID_R 13 /* XID response request/indication */ + +/*------------------------------------------------------------------*/ +/* NL service primitives */ +/*------------------------------------------------------------------*/ + +#define N_MDATA 1 /* more data to come REQ/IND */ +#define N_CONNECT 2 /* OSI N-CONNECT REQ/IND */ +#define N_CONNECT_ACK 3 /* OSI N-CONNECT CON/RES */ +#define N_DISC 4 /* OSI N-DISC REQ/IND */ +#define N_DISC_ACK 5 /* OSI N-DISC CON/RES */ +#define N_RESET 6 /* OSI N-RESET REQ/IND */ +#define N_RESET_ACK 7 /* OSI N-RESET CON/RES */ +#define N_DATA 8 /* OSI N-DATA REQ/IND */ +#define N_EDATA 9 /* OSI N-EXPEDITED DATA REQ/IND */ +#define N_UDATA 10 /* OSI D-UNIT-DATA REQ/IND */ +#define N_BDATA 11 /* BROADCAST-DATA REQ/IND */ +#define N_DATA_ACK 12 /* data ack ind for D-bit procedure */ +#define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */ + +#define N_Q_BIT 0x10 /* Q-bit for req/ind */ +#define N_M_BIT 0x20 /* M-bit for req/ind */ +#define N_D_BIT 0x40 /* D-bit for req/ind */ + +/*------------------------------------------------------------------*/ +/* Signaling management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_SIG 1 /* assign signaling task */ +#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */ +#define REMOVE_SIG 0xff /* remove signaling task */ + +/*------------------------------------------------------------------*/ +/* Signaling service primitives */ +/*------------------------------------------------------------------*/ + +#define CALL_REQ 1 /* call request */ +#define CALL_CON 1 /* call confirmation */ +#define CALL_IND 2 /* incoming call connected */ +#define LISTEN_REQ 2 /* listen request */ +#define HANGUP 3 /* hangup request/indication */ +#define SUSPEND 4 /* call suspend request/confirm */ +#define RESUME 5 /* call resume request/confirm */ +#define SUSPEND_REJ 6 /* suspend rejected indication */ +#define USER_DATA 8 /* user data for user to user signaling */ +#define CONGESTION 9 /* network congestion indication */ +#define INDICATE_REQ 10 /* request to indicate an incoming call */ +#define INDICATE_IND 10 /* indicates that there is an incoming call */ +#define CALL_RES 11 /* accept an incoming call */ +#define CALL_ALERT 12 /* send ALERT for incoming call */ +#define INFO_REQ 13 /* INFO request */ +#define INFO_IND 13 /* INFO indication */ +#define REJECT 14 /* reject an incoming call */ +#define RESOURCES 15 /* reserve B-Channel hardware resources */ +#define TEL_CTRL 16 /* Telephone control request/indication */ +#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ +#define FAC_REG_REQ 18 /* connection idependent fac registration */ +#define FAC_REG_ACK 19 /* fac registration acknowledge */ +#define FAC_REG_REJ 20 /* fac registration reject */ +#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ +#define FACILITY_REQ 22 /* send a Facility Message type */ +#define FACILITY_IND 22 /* Facility Message type indication */ +#define SIG_CTRL 29 /* Control for signalling hardware */ +#define DSP_CTRL 30 /* Control for DSPs */ +#define LAW_REQ 31 /* Law config request for (returns info_i) */ + + +/*------------------------------------------------------------------*/ +/* management service primitives */ +/*------------------------------------------------------------------*/ + +#define MAN_READ 2 +#define MAN_WRITE 3 +#define MAN_EXECUTE 4 +#define MAN_EVENT_ON 5 +#define MAN_EVENT_OFF 6 +#define MAN_LOCK 7 +#define MAN_UNLOCK 8 + +#define MAN_INFO_IND 2 +#define MAN_EVENT_IND 3 +#define MAN_TRACE_IND 4 + +#define MAN_ESC 0x80 + +/*------------------------------------------------------------------*/ +/* return code coding */ +/*------------------------------------------------------------------*/ + +#define UNKNOWN_COMMAND 0x01 /* unknown command */ +#define WRONG_COMMAND 0x02 /* wrong command */ +#define WRONG_ID 0x03 /* unknown task/entity id */ +#define WRONG_CH 0x04 /* wrong task/entity id */ +#define UNKNOWN_IE 0x05 /* unknown information el. */ +#define WRONG_IE 0x06 /* wrong information el. */ +#define OUT_OF_RESOURCES 0x07 /* ISDN-S card out of res. */ +#define ADAPTER_DEAD 0x08 /* ISDN card CPU halted */ +#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ +#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ +#define ASSIGN_OK 0xef /* ASSIGN OK */ +#define OK_FC 0xfc /* Flow-Control RC */ +#define READY_INT 0xfd /* Ready interrupt */ +#define TIMER_INT 0xfe /* timer interrupt */ +#define OK 0xff /* command accepted */ + +/*------------------------------------------------------------------*/ +/* information elements */ +/*------------------------------------------------------------------*/ + +#define SHIFT 0x90 /* codeset shift */ +#define MORE 0xa0 /* more data */ +#define CL 0xb0 /* congestion level */ + + /* codeset 0 */ + +#define BC 0x04 /* Bearer Capability */ +#define CAU 0x08 /* cause */ +#define CAD 0x0c /* Connected address */ +#define CAI 0x10 /* call identity */ +#define CHI 0x18 /* channel identification */ +#define LLI 0x19 /* logical link id */ +#define CHA 0x1a /* charge advice */ +#define DT 0x29 /* ETSI date/time */ +#define KEY 0x2c /* keypad information element */ +#define FTY 0x1c /* facility information element */ +#define DSP 0x28 /* display */ +#define OAD 0x6c /* origination address */ +#define OSA 0x6d /* origination sub-address */ +#define CPN 0x70 /* called party number */ +#define DSA 0x71 /* destination sub-address */ +#define RDX 0x73 /* redirected number extended */ +#define RDN 0x74 /* redirected number */ +#define LLC 0x7c /* low layer compatibility */ +#define HLC 0x7d /* high layer compatibility */ +#define UUI 0x7e /* user user information */ +#define ESC 0x7f /* escape extension */ + +#define DLC 0x20 /* data link layer configuration */ +#define NLC 0x21 /* network layer configuration */ + + /* codeset 6 */ + +#define SIN 0x01 /* service indicator */ +#define CIF 0x02 /* charging information */ +#define DATE 0x03 /* date */ +#define CPS 0x07 /* called party status */ + +/*------------------------------------------------------------------*/ +/* TEL_CTRL contents */ +/*------------------------------------------------------------------*/ + +#define RING_ON 0x01 +#define RING_OFF 0x02 +#define HANDS_FREE_ON 0x03 +#define HANDS_FREE_OFF 0x04 +#define ON_HOOK 0x80 +#define OFF_HOOK 0x90 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/pc_maint.h linux/drivers/isdn/eicon/pc_maint.h --- v2.2.18/drivers/isdn/eicon/pc_maint.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/pc_maint.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,162 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef PC_MAINT_H +#define PC_MAINT_H + +#if !defined(MIPS_SCOM) +#define BUFFER_SZ 48 +#define MAINT_OFFS 0x380 +#else +#define BUFFER_SZ 128 +#define MAINT_OFFS 0xff00 +#endif + +#define MIPS_BUFFER_SZ 128 +#define MIPS_MAINT_OFFS 0xff00 + +#define DO_LOG 1 +#define MEMR 2 +#define MEMW 3 +#define IOR 4 +#define IOW 5 +#define B1TEST 6 +#define B2TEST 7 +#define BTESTOFF 8 +#define DSIG_STATS 9 +#define B_CH_STATS 10 +#define D_CH_STATS 11 +#define BL1_STATS 12 +#define BL1_STATS_C 13 +#define GET_VERSION 14 +#define OS_STATS 15 +#define XLOG_SET_MASK 16 +#define XLOG_GET_MASK 17 +#define DSP_READ 20 +#define DSP_WRITE 21 + +#define OK 0xff +#define MORE_EVENTS 0xfe +#define NO_EVENT 1 + +struct DSigStruc +{ + byte Id; + byte uX; + byte listen; + byte active; + byte sin[3]; + byte bc[6]; + byte llc[6]; + byte hlc[6]; + byte oad[20]; +}; + +struct BL1Struc { + dword cx_b1; + dword cx_b2; + dword cr_b1; + dword cr_b2; + dword px_b1; + dword px_b2; + dword pr_b1; + dword pr_b2; + word er_b1; + word er_b2; +}; + +struct L2Struc { + dword XTotal; + dword RTotal; + word XError; + word RError; +}; + +struct OSStruc { + word free_n; +}; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[BUFFER_SZ]; + word w[BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[BUFFER_SZ>>2]; +} BUFFER; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[MIPS_BUFFER_SZ]; + word w[MIPS_BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[MIPS_BUFFER_SZ>>2]; +} MIPS_BUFFER; + + +#if !defined(MIPS_SCOM) +struct pc_maint +{ + byte req; + byte rc; + byte *mem; /*far*/ + short length; + word port; + byte fill[6]; + BUFFER data; +}; +#else +struct pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte far *mem; + short length; + word port; + byte fill[4]; /* data at offset 16 */ + BUFFER data; +}; +#endif + +struct mi_pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte *mem; /*far*/ + short length; + word port; + byte fill[4]; /* data at offset 16 */ + MIPS_BUFFER data; +}; + +#endif /* PC_MAINT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/pr_pc.h linux/drivers/isdn/eicon/pr_pc.h --- v2.2.18/drivers/isdn/eicon/pr_pc.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/pr_pc.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,83 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#if !defined(PR_PC_H) +#define PR_PC_H + +struct pr_ram { + word NextReq; /* pointer to next Req Buffer */ + word NextRc; /* pointer to next Rc Buffer */ + word NextInd; /* pointer to next Ind Buffer */ + byte ReqInput; /* number of Req Buffers sent */ + byte ReqOutput; /* number of Req Buffers returned */ + byte ReqReserved; /* number of Req Buffers reserved */ + byte Int; /* ISDN-P interrupt */ + byte XLock; /* Lock field for arbitration */ + byte RcOutput; /* number of Rc buffers received */ + byte IndOutput; /* number of Ind buffers received */ + byte IMask; /* Interrupt Mask Flag */ + byte Reserved1[2]; /* reserved field, do not use */ + byte ReadyInt; /* request field for ready interrupt */ + byte Reserved2[12]; /* reserved field, do not use */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-P initialized indication */ + byte B[1]; /* buffer space for Req,Ind and Rc */ +}; + +typedef struct { + word next; + byte Req; + byte ReqId; + byte ReqCh; + byte Reserved1; + word Reference; + byte Reserved[8]; + PBUFFER XBuffer; +} REQ; + +typedef struct { + word next; + byte Rc; + byte RcId; + byte RcCh; + byte Reserved1; + word Reference; + byte Reserved2[8]; +} RC; + +typedef struct { + word next; + byte Ind; + byte IndId; + byte IndCh; + byte MInd; + word MLength; + word Reference; + byte RNR; + byte Reserved; + dword Ack; + PBUFFER RBuffer; +} IND; + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/pri.c linux/drivers/isdn/eicon/pri.c --- v2.2.18/drivers/isdn/eicon/pri.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/pri.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,530 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.5 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Diva Server PRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_RESET_REG 0x20 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xef00 /* value for PRI card */ + +#define MP_PROTOCOL_ADDR 0xA0011000 +#define MP_DSP_CODE_BASE 0xa03a0000 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg); +static int pri_ISR (card_t* card); + +static int diva_server_reset(card_t *card) +{ + byte *reg; + diva_server_boot_t *boot = NULL; + dword live = 0; + int i = 0; + dword dwWait; + + DPRINTF(("divas: reset Diva Server PRI")); + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], DIVAS_RESET | + DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], 0x00); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemDetach(card->hw, reg); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, boot->reserved, 0); + + live = UxCardMemInD(card->hw, &boot->live); + + for (i=0; i<5; i++) + { + if (live != UxCardMemInD(card->hw, &boot->live)) + { + break; + } + UxPause(10); + } + + if (i == 5) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card is reset but CPU not running")); + return -1; + } + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card reset after %d ms", i * 10)); + + return 0; +} + +static int diva_server_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardLog(0); + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], config->sig_flags); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_reset_int(card_t *card) +{ + byte *cfg; + + cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL); + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0); + UxCardMemDetach(card->hw, cfg); + + return; +} + + +static int diva_server_test_int(card_t *card) +{ + int i; + byte *shared; + byte req_int; + + DPRINTF(("divas: test interrupt for Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardMemIn(card->hw, &shared[0x3FE]); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + UxCardMemIn(card->hw, &shared[0x3FE]); + + UxCardMemDetach(card->hw, shared); + + diva_server_reset_int(card); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + card->test_int_pend = TEST_INT_DIVAS; + + req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt)); + + req_int++; + + UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int); + + UxCardMemDetach(card->hw, shared); + + UxCardLog(0); + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + + if (card->test_int_pend) + { + + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_load(card_t *card, dia_load_t *load) +{ + diva_server_boot_t *boot; + int i, offset, length; + dword cmd = 0; + + DPRINTF(("divas: loading Diva Server PRI")); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + (((sizeof(dword) + + (sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT)) + + ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA))); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + sizeof(dword))); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE); + break; + + default: + DPRINTF(("divas: unknown code type")); + UxCardMemDetach(card->hw, boot); + return -1; + } + + UxCardLog(0); + offset = 0; + + do + { + length = (load->length - offset >= 400) ? 400 : load->length - offset; + + for (i=0; ihw, &boot->data[i], load->code[offset+i]); + } + + for (i=0; icode[offset + i] != UxCardMemIn(card->hw, &boot->data[i])) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card code block verify failed")); + return -1; + } + } + + UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD); + + for (i=0; i<50000; i++) + { + cmd = UxCardMemInD(card->hw, &boot->cmd); + if (!cmd) + { + break; + } + /*UxPause(1);*/ + } + + if (cmd) + { + DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset)); + UxCardMemDetach(card->hw, boot); + return -1; + } + + offset += length; + + } while (offset < load->length); + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: DIVA Server card loaded")); + + return 0; +} + +static int diva_server_start(card_t *card, byte *channels) +{ + diva_server_boot_t *boot; + byte *ram; + int i; + dword signature = 0; + + DPRINTF(("divas: start Diva Server PRI")); + + card->is_live = FALSE; + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD); + + UxCardLog(0); + + for (i = 0; i < 300; i++) + { + signature = UxCardMemInD(card->hw, &boot->signature); + if ((signature >> 16) == DIVAS_SIGNATURE) + { + DPRINTF(("divas: started card after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if ((signature >> 16) != DIVAS_SIGNATURE) + { + UxCardMemDetach(card->hw, boot); + DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature)); + return -1; + } + + card->is_live = TRUE; + + ram = (byte *) boot; + ram += DIVAS_SHARED_OFFSET; + + *channels = UxCardMemIn(card->hw, &ram[0x3F6]); + card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]); + + UxCardMemDetach(card->hw, boot); + + if (diva_server_test_int(card)) + { + DPRINTF(("divas: interrupt test failed")); + return -1; + } + + DPRINTF(("divas: DIVA Server card started")); + + return 0; +} + +static +int diva_server_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise PRI specific entry points + */ + +int DivasPriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server PRI")); + + if (DivasPRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_reset; + card->card_load = diva_server_load; + card->card_config = diva_server_config; + card->card_start = diva_server_start; + card->reset_int = diva_server_reset_int; + card->card_mem_get = diva_server_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = pri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + + +static int pri_ISR (card_t* card) +{ + int served = 0; + byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET]; + register unsigned long val = *isr; + + if (val & 0x80000000) /* our card had caused interrupt ??? */ + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + *isr = (unsigned long)~0x03E00000; /* Clear interrupt line */ + } + + UxCardMemDetach(card->hw, cfg); + + return (served != 0); +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/sys.h linux/drivers/isdn/eicon/sys.h --- v2.2.18/drivers/isdn/eicon/sys.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/sys.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,116 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Environment provided by system and miscellaneous definitions */ + +#if !defined(SYS_H) +#define SYS_H + +/* abreviations for unsigned types */ +typedef int boolean_t; + +typedef unsigned char byte; + +typedef unsigned long dword; +typedef unsigned short word; + +/* abreviations for volatile types */ + +typedef volatile byte vbyte; +typedef volatile word vword; +typedef volatile dword vdword; + +/* Booleans */ + +#if !defined(TRUE) +#define TRUE (1) +#define FALSE (0) +#endif + +/* NULL pointer */ + +#if !defined(NULL) +#define NULL ((void *) 0) +#endif + +/* MIN and MAX */ + +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/* Return the dimension of an array */ + +#if !defined(DIM) +#define DIM(array) (sizeof (array)/sizeof ((array)[0])) +#endif + +/* + * Return the number of milliseconds since last boot + */ + +extern dword UxTimeGet(void); + +extern void DivasSprintf(char *buffer, char *format, ...); +extern void DivasPrintf(char *format, ...); + +/* fatal errors, asserts and tracing */ + +void HwFatalErrorFrom(char *file, int line); +void HwFatalError(void); +/* void HwAssert(char *file, int line, char *condition); */ + +#include +#define _PRINTK printk + +#define _PRINTF DivasPrintf +void _PRINTF(char *format, ...); +#define PRINTF(arg_list) _PRINTF arg_list +#if defined DTRACE +# define DPRINTF(arg_list) _PRINTF arg_list +# define KDPRINTF(arg_list) _PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n"); +#else +# define DPRINTF(arg_list) (void)0 +# define KDPRINTF(arg_list) _PRINTK arg_list ; _PRINTK("\n"); +#endif + +#if !defined(ASSERT) +#if defined DEBUG || defined DBG +# define HwFatalError() HwFatalErrorFrom(__FILE__, __LINE__) +# define ASSERT(cond) \ + if (!(cond)) \ + { \ +/* HwAssert(__FILE__, __LINE__, #cond);*/ \ + } +#else +# define ASSERT(cond) ((void)0) +#endif +#endif /* !defined(ASSERT) */ + +#define TRACE (_PRINTF(__FILE__"@%d\n", __LINE__)) + +#endif /* SYS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/uxio.h linux/drivers/isdn/eicon/uxio.h --- v2.2.18/drivers/isdn/eicon/uxio.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/uxio.h Sun Mar 25 11:37:32 2001 @@ -0,0 +1,217 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.6 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Interface to Unix specific code for performing card I/O + */ + +#if !defined(UXIO_H) +#define UXIO_H + +#include "sys.h" +#include "adapter.h" + + +struct pt_regs; + +/* user callback, returns zero if interrupt was from this card */ +typedef void isr_fn_t(void *); +struct ux_diva_card_s +{ + word in_use; + int io_base; + int reset_base; + int card_type; + byte *mapped; + int bus_num; + int func_num; + int slot; + int irq; + byte *pDRAM; + byte *pDEVICES; + byte *pCONFIG; + byte *pSHARED; + byte *pCONTROL; + word features; + void *user_isr_arg; + isr_fn_t *user_isr; +}; + +void bcopy(void *pSource, void *pDest, dword dwLength); +void bzero(void *pDataArea, dword dwLength); + + +/* + * Get a card handle to enable card to be accessed + */ + +int UxCardHandleGet( ux_diva_card_t **card, + dia_card_t *cfg); + +/* + * Free a card handle as no longer needed + */ + +void UxCardHandleFree(ux_diva_card_t *card); + +/* + * Lock and unlock access to a card + */ + +int UxCardLock(ux_diva_card_t *card); +void UxCardUnlock(ux_diva_card_t *card, int ipl); + +/* + * Set the mapping address for PCI cards + */ + +int UxCardAddrMappingSet(ux_diva_card_t *card, + int id, + void *address, + int size); + +/* + * Attach card to memory to enable it to be accessed + * Returns the mapped address + */ + +void *UxCardMemAttach(ux_diva_card_t *card, int id); + +/* + * map card out of memory after completion of access + */ + +void UxCardMemDetach(ux_diva_card_t *card, void *address); + +/* + * input functions for memory-mapped cards + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address); + +word UxCardMemInW(ux_diva_card_t *card, void *address); + +dword UxCardMemInD(ux_diva_card_t *card, void *address); + +void UxCardMemInBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * output functions for memory-mapped cards + */ + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data); + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data); + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data); + +void UxCardMemOutBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * input functions for I/O-mapped cards + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *, void *address); + +word UxCardIoInW(ux_diva_card_t *card, void *, void *address); + +dword UxCardIoInD(ux_diva_card_t *card, void *, void *address); + +void UxCardIoInBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * output functions for I/O-mapped cards + */ + +void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data); + +void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data); + +void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data); + +void UxCardIoOutBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * Get specified PCI config + */ + +void UxPciConfigRead(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* + * Set specified PCI config + */ + +void UxPciConfigWrite(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* allocate memory, returning NULL if none available */ + +void *UxAlloc(unsigned int size); + +void UxFree(void *); + +/* + * Pause for specified number of milli-seconds + */ + +void UxPause(long ms); + +/* + * Install an ISR for the specified card + */ + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg); + +/* + * Remove an ISR for the specified card + */ +void UxIsrRemove(ux_diva_card_t *card, void *); + +/* + * DEBUG function to turn logging ON or OFF + */ + +void UxCardLog(int turn_on); + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst); +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst); + +#endif /* of UXIO_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/eicon/xlog.c linux/drivers/isdn/eicon/xlog.c --- v2.2.18/drivers/isdn/eicon/xlog.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/eicon/xlog.c Sun Mar 25 11:37:32 2001 @@ -0,0 +1,180 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Unix Eicon active card driver + * XLOG related functions + */ + +#include "sys.h" +#include "idi.h" +#include "pc.h" +#include "pc_maint.h" +#include "divalog.h" + +#include "adapter.h" +#include "uxio.h" + +/* + * convert/copy XLOG info into a KLOG entry + */ + +static +void xlog_to_klog(byte *b, int size, int card_num) + +{ + typedef struct + { + word code; + word time_hi; + word time_lo; + word xcode; + byte data[2]; + } card_xlog_t; + + card_xlog_t *x; + + klog_t klog; + + x = (card_xlog_t *) b; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = (dword) x->time_hi; + klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo; + + klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size; + + klog.card = card_num; + if (x->code == 1) + { + klog.type = KLOG_XTXT_MSG; + klog.code = 0; + bcopy(&x->xcode, klog.buffer, klog.length); + } + else if (x->code == 2) + { + klog.type = KLOG_XLOG_MSG; + klog.code = x->xcode; + bcopy(&x->data, klog.buffer, klog.length); + } + else + { + char *c; int i; + klog.type = KLOG_TEXT_MSG; + klog.code = 0; + c = "divas: invalid xlog message code from card"; + i = 0; + while (*c) + { + klog.buffer[i] = *c; + c++; + i++; + } + klog.buffer[i] = *c; + } + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} + +/* + * send an XLOG request down to specified card + * if response available from previous request then read it + * if not then just send down new request, ready for next time + */ + +void DivasXlogReq(int card_num) + +{ + card_t *card; + ADAPTER *a; + + if ((card_num < 0) || (card_num > DivasCardNext)) + { + DPRINTF(("xlog: invalid card number")); + return; + } + + card = &DivasCards[card_num]; + + if (DivasXlogRetrieve(card)) + { + return; + } + + /* send down request for next time */ + + a = &card->a; + + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return; +} + +/* + * retrieve XLOG request from specified card + * returns non-zero if new request sent to card + */ + +int DivasXlogRetrieve(card_t *card) + +{ + ADAPTER *a; + struct mi_pc_maint pcm; + + a = &card->a; + + /* get status of last request */ + + pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1)); + + /* if nothing there from previous request, send down a new one */ + + if (pcm.rc == OK) + { + /* read in response */ + + a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm)); + + xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data), + (int) (card - DivasCards)); + } + + /* if any response received from card, re-send request */ + + if (pcm.rc) + { + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return 1; + } + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile --- v2.2.18/drivers/isdn/hisax/Makefile Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/Makefile Sun Mar 25 11:37:32 2001 @@ -1,217 +1,70 @@ -L_OBJS := -M_OBJS := -LX_OBJS := -MX_OBJS := -O_OBJS := -OX_OBJS := -L_TARGET := -O_TARGET := - -O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o cert.o - -# EXTRA_CFLAGS += -S - -ifeq ($(CONFIG_HISAX_EURO),y) - O_OBJS += l3dss1.o -endif - -ifeq ($(CONFIG_HISAX_NI1),y) - O_OBJS += l3ni1.o -endif - -ifeq ($(CONFIG_HISAX_1TR6),y) - O_OBJS += l3_1tr6.o -endif - -ISAC_OBJ := -HSCX_OBJ := -ISAR_OBJ := -HFC_OBJ := -HFC_2BDS0 := -JADE_OBJ := -W6692_OBJ := - -ifeq ($(CONFIG_HISAX_16_0),y) - O_OBJS += teles0.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_16_3),y) - O_OBJS += teles3.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_TELESPCI),y) - O_OBJS += telespci.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_S0BOX),y) - O_OBJS += s0box.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_AVM_A1),y) - O_OBJS += avm_a1.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_AVM_A1_PCMCIA),y) - O_OBJS += avm_a1p.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_FRITZPCI),y) - O_OBJS += avm_pci.o - ISAC_OBJ := isac.o -endif - - -ifeq ($(CONFIG_HISAX_ELSA),y) - O_OBJS += elsa.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_IX1MICROR2),y) - O_OBJS += ix1_micro.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_DIEHLDIVA),y) - O_OBJS += diva.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_ASUSCOM),y) - O_OBJS += asuscom.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_TELEINT),y) - O_OBJS += teleint.o - ISAC_OBJ := isac.o - HFC_OBJ := hfc_2bs0.o -endif - -ifeq ($(CONFIG_HISAX_SEDLBAUER),y) - O_OBJS += sedlbauer.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o - ISAR_OBJ := isar.o -endif - -ifeq ($(CONFIG_HISAX_SPORTSTER),y) - O_OBJS += sportster.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_MIC),y) - O_OBJS += mic.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_NETJET),y) - O_OBJS += netjet.o - ISAC_OBJ := isac.o -endif - -ifeq ($(CONFIG_HISAX_HFCS),y) - O_OBJS += hfcscard.o - HFC_2BDS0 := hfc_2bds0.o -endif - -ifeq ($(CONFIG_HISAX_HFC_PCI),y) - HFC_2BDS0 += hfc_pci.o -endif - -ifeq ($(CONFIG_HISAX_HFC_SX),y) - HFC_2BDS0 += hfc_sx.o -endif - -ifeq ($(CONFIG_HISAX_NICCY),y) - O_OBJS += niccy.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_ISURF),y) - O_OBJS += isurf.o - ISAC_OBJ := isac.o - ISAR_OBJ := isar.o -endif - -ifeq ($(CONFIG_HISAX_HSTSAPHIR),y) - O_OBJS += saphir.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_BKM_A4T),y) - O_OBJS += bkm_a4t.o - ISAC_OBJ := isac.o - JADE_OBJ := jade.o -endif -ifeq ($(CONFIG_HISAX_SCT_QUADRO),y) - O_OBJS += bkm_a8.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_GAZEL),y) - O_OBJS += gazel.o - ISAC_OBJ := isac.o - HSCX_OBJ := hscx.o -endif - -ifeq ($(CONFIG_HISAX_W6692),y) - W6692_OBJ := w6692.o -endif - -# ifeq ($(CONFIG_HISAX_TESTEMU),y) -# O_OBJS += testemu.o -# endif - -ifeq ($(ISAC_OBJ), isac.o) - ISAC_OBJ += arcofi.o -endif - -O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ) -O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) -OX_OBJS += config.o - -O_TARGET := - -ifeq ($(CONFIG_ISDN_DRV_HISAX),y) - O_TARGET += hisax.o -else - ifeq ($(CONFIG_ISDN_DRV_HISAX),m) - O_TARGET += hisax.o - M_OBJS += hisax.o - endif -endif - - -include $(TOPDIR)/Rules.make - -MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \ - tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ - elsa.c diva.c +# Makefile for the hisax ISDN device driver -CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) +# The target object and module list name. -cert.o: $(MD5FILES) md5sums.asc - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c +O_TARGET := vmlinux-obj.o +# Objects that export symbols. + +export-objs := config.o + +# Multipart objects. + +list-multi := hisax.o +hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ + lmgr.o q931.o callc.o fsm.o cert.o + +# Optional parts of multipart objects. + +hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o +hisax-objs-$(CONFIG_HISAX_NI1) += l3ni1.o +hisax-objs-$(CONFIG_HISAX_1TR6) += l3_1tr6.o + +hisax-objs-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o +hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o +hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o +hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o +hisax-objs-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o +hisax-objs-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o +hisax-objs-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o +hisax-objs-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o +hisax-objs-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o +hisax-objs-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o +hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o +hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o +#hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o + +hisax-objs += $(sort $(hisax-objs-y)) + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o + +MD5FILES := isac.c isdnl1.c isdnl2.c isdnl3.c \ + tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ + elsa.c diva.c sedlbauer.c +CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) +CFLAGS_cert.o := -DCERTIFICATION=$(CERT) + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +hisax.o: $(hisax-objs) + $(LD) -r -o $@ $(hisax-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c --- v2.2.18/drivers/isdn/hisax/amd7930.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/amd7930.c Sun Mar 25 11:37:32 2001 @@ -1,25 +1,9 @@ -/* $Id: amd7930.c,v 1.3 1999/07/12 21:04:52 keil Exp $ +/* $Id: amd7930.c,v 1.5 2000/11/24 17:05:37 kai Exp $ * * HiSax ISDN driver - chip specific routines for AMD 7930 * * Author Brent Baccala (baccala@FreeSoft.org) * - * - * - * $Log: amd7930.c,v $ - * Revision 1.3 1999/07/12 21:04:52 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.2 1998/02/12 23:07:10 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.1 1998/02/03 23:20:51 keil - * New files for SPARC isdn support - * - * Revision 1.1 1998/01/08 04:17:12 baccala - * ISDN comes to the Sparc. Key points: - * * - Existing ISDN HiSax driver provides all the smarts * - it compiles, runs, talks to an isolated phone switch, connects * to a Cisco, pings go through @@ -30,6 +14,7 @@ * * The code is unreliable enough to be consider alpha * + * This file is (c) under GNU PUBLIC LICENSE * * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the * SparcStation 1+. The chip provides microphone and speaker interfaces @@ -109,7 +94,7 @@ #include "rawhdlc.h" #include -static const char *amd7930_revision = "$Revision: 1.3 $"; +static const char *amd7930_revision = "$Revision: 1.5 $"; #define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */ #define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into @@ -749,8 +734,8 @@ return(0); } -__initfunc(int -setup_amd7930(struct IsdnCard *card)) +int __init +setup_amd7930(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c --- v2.2.18/drivers/isdn/hisax/arcofi.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/arcofi.c Sun Mar 25 11:37:32 2001 @@ -1,43 +1,10 @@ -/* $Id: arcofi.c,v 1.10 1999/12/23 15:09:32 keil Exp $ - +/* $Id: arcofi.c,v 1.12 2000/11/25 17:01:00 kai Exp $ + * * arcofi.c Ansteuerung ARCOFI 2165 * * Author Karsten Keil (keil@isdn4linux.de) * - * - * - * $Log: arcofi.c,v $ - * Revision 1.10 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.9 1999/12/19 13:09:41 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.8 1999/08/25 16:50:51 keil - * Fix bugs which cause 2.3.14 hangs (waitqueue init) - * - * Revision 1.7 1999/07/01 08:11:17 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.6 1998/09/30 22:21:56 keil - * cosmetics - * - * Revision 1.5 1998/09/27 12:52:57 keil - * cosmetics - * - * Revision 1.4 1998/08/20 13:50:24 keil - * More support for hybrid modem (not working yet) - * - * Revision 1.3 1998/05/25 12:57:38 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.2 1998/04/15 16:47:16 keil - * new interface - * - * Revision 1.1 1997/10/29 18:51:20 keil - * New files + * This file is (c) under GNU PUBLIC LICENSE * */ @@ -161,5 +128,6 @@ cs->dc.isac.arcofitimer.function = (void *) arcofi_timer; cs->dc.isac.arcofitimer.data = (long) cs; init_timer(&cs->dc.isac.arcofitimer); + init_waitqueue_head(&cs->dc.isac.arcofi_wait); test_and_set_bit(HW_ARCOFI, &cs->HW_Flags); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/arcofi.h linux/drivers/isdn/hisax/arcofi.h --- v2.2.18/drivers/isdn/hisax/arcofi.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/arcofi.h Sun Mar 25 11:37:32 2001 @@ -1,27 +1,10 @@ -/* $Id: arcofi.h,v 1.5 1999/12/23 15:09:32 keil Exp $ - +/* $Id: arcofi.h,v 1.6 2000/06/26 08:59:12 keil Exp $ + * * arcofi.h Ansteuerung ARCOFI 2165 * * Author Karsten Keil (keil@isdn4linux.de) * - * - * - * $Log: arcofi.h,v $ - * Revision 1.5 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.4 1999/07/01 08:11:18 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.3 1998/05/25 12:57:39 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.2 1998/04/15 16:47:17 keil - * new interface - * - * Revision 1.1 1997/10/29 18:51:20 keil - * New files + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c --- v2.2.18/drivers/isdn/hisax/asuscom.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/asuscom.c Sun Mar 25 11:37:32 2001 @@ -1,43 +1,17 @@ -/* $Id: asuscom.c,v 1.9 1999/12/19 13:09:41 keil Exp $ - +/* $Id: asuscom.c,v 1.11 2000/11/24 17:05:37 kai Exp $ + * * asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards * * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for informations * - * - * $Log: asuscom.c,v $ - * Revision 1.9 1999/12/19 13:09:41 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.8 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.7 1999/07/12 21:04:53 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.6 1999/07/01 08:11:18 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.5 1998/11/15 23:54:19 keil - * changes from 2.0 - * - * Revision 1.4 1998/06/18 23:18:20 keil - * Support for new IPAC card - * - * Revision 1.3 1998/04/15 16:46:53 keil - * new init code - * - * Revision 1.2 1998/02/02 13:27:06 keil - * New - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "ipac.h" @@ -46,7 +20,7 @@ extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.9 $"; +const char *Asuscom_revision = "$Revision: 1.11 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -295,13 +269,13 @@ byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->subtyp == ASUS_IPAC) writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0); else byteout(cs->hw.asus.adr, 0); /* Reset Off */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->subtyp == ASUS_IPAC) { writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0); @@ -333,8 +307,8 @@ return(0); } -__initfunc(int -setup_asuscom(struct IsdnCard *card)) +int __init +setup_asuscom(struct IsdnCard *card) { int bytecnt; struct IsdnCardState *cs = card->cs; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.2.18/drivers/isdn/hisax/avm_a1.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/avm_a1.c Sun Mar 25 11:37:32 2001 @@ -1,76 +1,21 @@ -/* $Id: avm_a1.c,v 2.11 1999/07/12 21:04:54 keil Exp $ - +/* $Id: avm_a1.c,v 2.13 2000/11/24 17:05:37 kai Exp $ + * * avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: avm_a1.c,v $ - * Revision 2.11 1999/07/12 21:04:54 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.10 1998/11/15 23:54:21 keil - * changes from 2.0 - * - * Revision 2.9 1998/08/13 23:36:12 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.8 1998/04/15 16:44:27 keil - * new init code - * - * Revision 2.7 1998/02/02 13:29:37 keil - * fast io - * - * Revision 2.6 1998/01/13 23:09:46 keil - * really disable timer - * - * Revision 2.5 1998/01/02 06:50:29 calle - * Perodic timer of A1 now disabled, no need for linux driver. - * - * Revision 2.4 1997/11/08 21:35:42 keil - * new l1 init - * - * Revision 2.3 1997/11/06 17:13:32 keil - * New 2.1 init code - * - * Revision 2.2 1997/10/29 18:55:48 keil - * changes for 2.1.60 (irq2dev_map) - * - * Revision 2.1 1997/07/27 21:47:13 keil - * new interface structures - * - * Revision 2.0 1997/06/26 11:02:48 keil - * New Layer and card interface - * - * Revision 1.6 1997/04/13 19:54:07 keil - * Change in IRQ check delay for SMP - * - * Revision 1.5 1997/04/06 22:54:10 keil - * Using SKB's - * - * Revision 1.4 1997/01/27 15:50:21 keil - * SMP proof,cosmetics - * - * Revision 1.3 1997/01/21 22:14:20 keil - * cleanups - * - * Revision 1.2 1996/10/27 22:07:31 keil - * cosmetic changes - * - * Revision 1.1 1996/10/13 20:04:49 keil - * Initial revision - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -static const char *avm_revision = "$Revision: 2.11 $"; +static const char *avm_revision = "$Revision: 2.13 $"; #define AVM_A1_STAT_ISAC 0x01 #define AVM_A1_STAT_HSCX 0x02 @@ -227,8 +172,8 @@ return(0); } -__initfunc(int -setup_avm_a1(struct IsdnCard *card)) +int __init +setup_avm_a1(struct IsdnCard *card) { u_char val; struct IsdnCardState *cs = card->cs; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c --- v2.2.18/drivers/isdn/hisax/avm_a1p.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/avm_a1p.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: avm_a1p.c,v 2.5 1999/09/01 08:26:34 calle Exp $ +/* $Id: avm_a1p.c,v 2.7 2000/11/24 17:05:37 kai Exp $ * * avm_a1p.c low level stuff for the following AVM cards: * A1 PCMCIA @@ -7,31 +7,10 @@ * * Author Carsten Paeth (calle@calle.in-berlin.de) * - * $Log: avm_a1p.c,v $ - * Revision 2.5 1999/09/01 08:26:34 calle - * Patch from Daniel Beichl to make A1 PCMCIA work again. - * - * Revision 2.4 1999/07/12 21:04:55 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.3 1998/11/15 23:54:22 keil - * changes from 2.0 - * - * Revision 2.2 1998/08/13 23:36:13 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.1 1998/07/15 15:01:23 calle - * Support for AVM passive PCMCIA cards: - * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 - * - * Revision 1.1.2.1 1998/07/15 14:43:26 calle - * Support for AVM passive PCMCIA cards: - * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 - * - * + * This file is (c) under GNU PUBLIC LICENSE */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" @@ -74,7 +53,7 @@ #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static const char *avm_revision = "$Revision: 2.5 $"; +static const char *avm_revision = "$Revision: 2.7 $"; static inline u_char ReadISAC(struct IsdnCardState *cs, u_char offset) @@ -266,8 +245,8 @@ return 0; } -__initfunc(int -setup_avm_a1_pcmcia(struct IsdnCard *card)) +int +setup_avm_a1_pcmcia(struct IsdnCard *card) { u_char model, vers; struct IsdnCardState *cs = card->cs; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c --- v2.2.18/drivers/isdn/hisax/avm_pci.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/avm_pci.c Sun Mar 25 11:37:32 2001 @@ -1,76 +1,29 @@ -/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $ - +/* $Id: avm_pci.c,v 1.22.6.3 2001/02/13 10:33:58 kai Exp $ + * * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: avm_pci.c,v $ - * Revision 1.14 1999/12/19 13:09:41 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.13 1999/12/03 12:10:14 keil - * Bugfix: Wrong channel use on hangup of channel 2 - * - * Revision 1.12 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.11 1999/08/11 21:01:18 keil - * new PCI codefix - * - * Revision 1.10 1999/08/10 16:01:44 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.9 1999/07/12 21:04:57 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.8 1999/07/01 08:11:19 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.7 1999/02/22 18:26:30 keil - * Argh ! ISAC address was only set with PCI - * - * Revision 1.6 1998/11/27 19:59:28 keil - * set subtype for Fritz!PCI - * - * Revision 1.5 1998/11/27 12:56:45 keil - * forgot to update setup function name - * - * Revision 1.4 1998/11/15 23:53:19 keil - * Fritz!PnP; changes from 2.0 - * - * Revision 1.3 1998/09/27 23:53:39 keil - * Fix error handling - * - * Revision 1.2 1998/09/27 12:54:55 keil - * bcs assign was lost in setstack, very bad results - * - * Revision 1.1 1998/08/20 13:47:30 keil - * first version - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ #include +#include #include "hisax.h" #include "isac.h" #include "isdnl1.h" #include +#include #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.14 $"; +static const char *avm_pci_rev = "$Revision: 1.22.6.3 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 -#define PCI_VENDOR_AVM 0x1244 -#define PCI_FRITZPCI_ID 0xa00 - #define HDLC_FIFO 0x0 #define HDLC_STATUS 0x4 @@ -339,7 +292,15 @@ if (cs->subtyp == AVM_FRITZ_PCI) { outl(idx, cs->hw.avm.cfg_reg + 4); while (cnt < count) { +#ifdef __powerpc__ +#ifdef CONFIG_APUS + *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#else + *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#endif /* CONFIG_APUS */ +#else *ptr++ = inl(cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -395,7 +356,15 @@ write_ctrl(bcs, 3); /* sets the correct index too */ if (cs->subtyp == AVM_FRITZ_PCI) { while (cnthw.avm.isac +_IO_BASE), *ptr++); +#else + out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); +#endif /* CONFIG_APUS */ +#else outl(*ptr++, cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -675,8 +644,8 @@ return (0); } -HISAX_INITFUNC(void -clear_pending_hdlc_ints(struct IsdnCardState *cs)) +void __init +clear_pending_hdlc_ints(struct IsdnCardState *cs) { u_int val; @@ -705,8 +674,8 @@ } } -HISAX_INITFUNC(void -inithdlc(struct IsdnCardState *cs)) +void __init +inithdlc(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_hdlc; cs->bcs[1].BC_SetStack = setstack_hdlc; @@ -751,11 +720,11 @@ save_flags(flags); sti(); outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3)); } @@ -790,10 +759,10 @@ return(0); } -static struct pci_dev *dev_avm __initdata = NULL; +static struct pci_dev *dev_avm __initdata = NULL; -__initfunc(int -setup_avm_pcipnp(struct IsdnCard *card)) +int __init +setup_avm_pcipnp(struct IsdnCard *card) { u_int val, ver; struct IsdnCardState *cs = card->cs; @@ -813,17 +782,18 @@ printk(KERN_ERR "FritzPCI: no PCI bus present\n"); return(0); } - if ((dev_avm = pci_find_device(PCI_VENDOR_AVM, - PCI_FRITZPCI_ID, dev_avm))) { + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_A1, dev_avm))) { cs->irq = dev_avm->irq; if (!cs->irq) { - printk(KERN_WARNING "FritzPCI: No IRQ for PCI card found\n"); + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); return(0); } - cs->hw.avm.cfg_reg = dev_avm->base_address[ 1] & - PCI_BASE_ADDRESS_IO_MASK; + if (pci_enable_device(dev_avm)) + return(0); + cs->hw.avm.cfg_reg = dev_avm->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; if (!cs->hw.avm.cfg_reg) { - printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n"); + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); return(0); } cs->subtyp = AVM_FRITZ_PCI; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.2.18/drivers/isdn/hisax/bkm_a4t.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/bkm_a4t.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.9 1999/12/19 13:09:41 keil Exp $ +/* $Id: bkm_a4t.c,v 1.13.6.3 2001/02/13 10:33:58 kai Exp $ * bkm_a4t.c low level stuff for T-Berkom A4T * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -6,53 +6,26 @@ * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * $Log: bkm_a4t.c,v $ - * Revision 1.9 1999/12/19 13:09:41 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.8 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.7 1999/08/22 20:26:55 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/08/11 21:01:22 keil - * new PCI codefix - * - * Revision 1.5 1999/08/10 16:01:46 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.4 1999/07/14 11:43:14 keil - * correct PCI_SUBSYSTEM_VENDOR_ID - * - * Revision 1.3 1999/07/12 21:04:58 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.2 1999/07/01 08:07:53 keil - * Initial version - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ #include +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "jade.h" #include "isdnl1.h" -#include "bkm_ax.h" #include +#include +#include "bkm_ax.h" extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.9 $"; +const char *bkm_a4t_revision = "$Revision: 1.13.6.3 $"; static inline u_char @@ -235,11 +208,11 @@ sti(); /* Issue the I20 soft reset */ pI20_Regs->i20SysControl = 0xFF; /* all in */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); /* Remove the soft reset */ pI20_Regs->i20SysControl = sysRESET | 0xFF; - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); /* Set our configuration */ pI20_Regs->i20SysControl = sysRESET | sysCFG; @@ -250,14 +223,14 @@ g_A4T_ISAC_RES | g_A4T_JADE_BOOTR | g_A4T_ISAR_BOOTR; - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); /* Remove RESET state from ISDN */ pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | g_A4T_JADE_RES | g_A4T_ISAR_RES); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); restore_flags(flags); } @@ -294,8 +267,8 @@ static struct pci_dev *dev_a4t __initdata = NULL; -__initfunc(int - setup_bkm_a4t(struct IsdnCard *card)) +int __init +setup_bkm_a4t(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -316,15 +289,20 @@ printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); return (0); } - if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) { - u_int sub_sys_id = 0; - - pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) { + while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN, + PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { + u16 sub_sys; + u16 sub_vendor; + + pci_read_config_word(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor); + pci_read_config_word(dev_a4t, PCI_SUBSYSTEM_ID, &sub_sys); + if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) { + if (pci_enable_device(dev_a4t)) + return(0); found = 1; - pci_memaddr = dev_a4t->base_address[ 0]; + pci_memaddr = dev_a4t->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK; cs->irq = dev_a4t->irq; + break; } } if (!found) { @@ -339,7 +317,6 @@ printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]); return (0); } - pci_memaddr &= PCI_BASE_ADDRESS_MEM_MASK; cs->hw.ax.base = (u_int) ioremap(pci_memaddr, 4096); /* Check suspecious address */ pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c --- v2.2.18/drivers/isdn/hisax/bkm_a8.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/bkm_a8.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.9 1999/12/19 13:09:41 keil Exp $ +/* $Id: bkm_a8.c,v 1.14.6.3 2001/02/13 10:33:58 kai Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -6,69 +6,29 @@ * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * $Log: bkm_a8.c,v $ - * Revision 1.9 1999/12/19 13:09:41 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.8 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.7 1999/08/22 20:26:58 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/08/11 21:01:24 keil - * new PCI codefix - * - * Revision 1.5 1999/08/10 16:01:48 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.4 1999/07/14 11:43:15 keil - * correct PCI_SUBSYSTEM_VENDOR_ID - * - * Revision 1.3 1999/07/12 21:04:59 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.2 1999/07/01 08:07:54 keil - * Initial version - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ #include +#include #include "hisax.h" #include "isac.h" #include "ipac.h" #include "hscx.h" #include "isdnl1.h" -#include "bkm_ax.h" #include +#include +#include "bkm_ax.h" + +#if CONFIG_PCI #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.9 $"; - -/* To survive the startup phase */ -typedef struct { - u_int active; /* true/false */ - u_int base; /* ipac base address */ -} IPAC_STATE; - -static IPAC_STATE ipac_state[4 + 1] __initdata = -{ - {0, 0}, /* dummy */ - {0, 0}, /* SCT_1 */ - {0, 0}, /* SCT_2 */ - {0, 0}, /* SCT_3 */ - {0, 0} /* SCT_4 */ -}; +const char sct_quadro_revision[] = "$Revision: 1.14.6.3 $"; static const char *sct_quadro_subtypes[] = { @@ -167,19 +127,13 @@ writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); } -/* Check whether the specified ipac is already active or not */ -static int -is_ipac_active(u_int ipac_nr) -{ - return (ipac_state[ipac_nr].active); -} - /* Set the specific ipac to active */ static void -set_ipac_active(u_int ipac_nr, u_int active) +set_ipac_active(struct IsdnCardState *cs, u_int active) { - /* set activation state */ - ipac_state[ipac_nr].active = active; + /* set irq mask */ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, + active ? 0xc0 : 0xff); } /* @@ -202,13 +156,14 @@ { struct IsdnCardState *cs = dev_id; u_char ista, val, icnt = 5; - int i; + if (!cs) { printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n"); return; } ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - + if (!(ista & 0x3f)) /* not this IPAC */ + return; Start_IPAC: if (cs->debug & L1_DEB_IPAC) debugl1(cs, "IPAC ISTA %02X", ista); @@ -245,30 +200,15 @@ sct_quadro_subtypes[cs->subtyp]); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); - - /* Read out all interrupt sources from currently not active ipacs */ - /* "Handle" all interrupts from currently not active ipac by reading the regs */ - for (i = SCT_1; i <= SCT_4; i++) - if (!is_ipac_active(i)) { - u_int base = ipac_state[i].base; - if (readreg(base, base + 4, 0xC1)) { - readreg(base, base + 4, 0xA0); - readreg(base, base + 4, 0xA4); - readreg(base, base + 4, 0x20); - readreg(base, base + 4, 0x24); - readreg(base, base + 4, 0x60); - readreg(base, base + 4, 0x64); - readreg(base, base + 4, 0xC1); - readreg(base, base + 4, ISAC_CIR0 + 0x80); - } - } } void release_io_sct_quadro(struct IsdnCardState *cs) { - /* ?? */ + release_region(cs->hw.ax.base & 0xffffffc0, 256); + if (cs->subtyp == SCT_1) + release_region(cs->hw.ax.plx_adr, 256); } static void @@ -278,11 +218,6 @@ if (bEnable) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); else - /* Issue general di only if no ipac is active */ - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); } } @@ -292,26 +227,17 @@ { long flags; - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) { - /* Issue total reset only if no ipac is active */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); - - save_flags(flags); - sti(); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout((10 * HZ) / 1000); - - /* Remove the soft reset */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout((10 * HZ) / 1000); - restore_flags(flags); - } + if (cs->subtyp == SCT_1) { + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); + save_flags(flags); + sti(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + /* Remove the soft reset */ + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + restore_flags(flags); } } @@ -321,20 +247,19 @@ switch (mt) { case CARD_RESET: /* Disable ints */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); reset_bkm(cs); return (0); case CARD_RELEASE: /* Sanity */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); - reset_bkm(cs); release_io_sct_quadro(cs); return (0); case CARD_INIT: cs->debug |= L1_DEB_IPAC; - set_ipac_active(cs->subtyp, 1); + set_ipac_active(cs, 1); inithscxisac(cs, 3); /* Enable ints */ enable_bkm_int(cs, 1); @@ -345,18 +270,38 @@ return (0); } +int __init +sct_alloc_io(u_int adr, u_int len) +{ + if (check_region(adr, len)) { + printk(KERN_WARNING + "HiSax: Scitel port %#x-%#x already in use\n", + adr, adr + len); + return (1); + } else { + request_region(adr, len, "scitel"); + } + return(0); +} + static struct pci_dev *dev_a8 __initdata = NULL; +static u16 sub_vendor_id __initdata = 0; +static u16 sub_sys_id __initdata = 0; +static u_char pci_bus __initdata = 0; +static u_char pci_device_fn __initdata = 0; +static u_char pci_irq __initdata = 0; + +#endif /* CONFIG_PCI */ -__initfunc(int - setup_sct_quadro(struct IsdnCard *card)) +int __init +setup_sct_quadro(struct IsdnCard *card) { +#if CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI - u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id; + u_char pci_rev_id; u_int found = 0; u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; -#endif strcpy(tmp, sct_quadro_revision); printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); @@ -368,32 +313,61 @@ /* Identify subtype by para[0] */ if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) cs->subtyp = card->para[0]; - else + else { printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n", - CardType[card->typ]); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + CardType[card->typ]); return (0); } - if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) { - u_int sub_sys_id = 0; - - pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) { - found = 1; - pci_ioaddr1 = dev_a8->base_address[ 1]; - pci_irq = dev_a8->irq; - pci_bus = dev_a8->bus->number; - pci_device_fn = dev_a8->devfn; - } - } - if (!found) { - printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); + if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) || + (sub_vendor_id != PCI_VENDOR_ID_BERKOM))) return (0); + if (cs->subtyp == SCT_1) { + if (!pci_present()) { + printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + return (0); + } + while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX, + PCI_DEVICE_ID_PLX_9050, dev_a8))) { + + pci_read_config_word(dev_a8, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id); + pci_read_config_word(dev_a8, PCI_SUBSYSTEM_ID, &sub_sys_id); + if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) && + (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) { + if (pci_enable_device(dev_a8)) + return(0); + pci_ioaddr1 = dev_a8->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; + pci_irq = dev_a8->irq; + pci_bus = dev_a8->bus->number; + pci_device_fn = dev_a8->devfn; + found = 1; + break; + } + } + if (!found) { + printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); + } +#ifdef ATTEMPT_PCI_REMAPPING +/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_REVISION_ID, &pci_rev_id); + if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { + printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + /* Restart PCI negotiation */ + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, (u_int) - 1); + /* Move up by 0x80 byte */ + pci_ioaddr1 += 0x80; + pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, pci_ioaddr1); + dev_a8->base_address[ 1] = pci_ioaddr1; + } +#endif /* End HACK */ } if (!pci_irq) { /* IRQ range check ?? */ printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n", @@ -401,25 +375,6 @@ sct_quadro_subtypes[cs->subtyp]); return (0); } -#ifdef ATTEMPT_PCI_REMAPPING -/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ - pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id); - if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { - printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - /* Restart PCI negotiation */ - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, (u_int) - 1); - /* Move up by 0x80 byte */ - pci_ioaddr1 += 0x80; - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, pci_ioaddr1); - dev_a8->base_address[ 1] = pci_ioaddr1; - } -/* End HACK */ -#endif pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3); @@ -446,23 +401,42 @@ /* pci_ioaddr5 is for the first subdevice only */ cs->hw.ax.plx_adr = pci_ioaddr1; /* Enter all ipac_base addresses */ - ipac_state[SCT_1].base = pci_ioaddr5 + 0x00; - ipac_state[SCT_2].base = pci_ioaddr4 + 0x08; - ipac_state[SCT_3].base = pci_ioaddr3 + 0x10; - ipac_state[SCT_4].base = pci_ioaddr2 + 0x20; - /* For isac and hscx control path */ - cs->hw.ax.base = ipac_state[cs->subtyp].base; + switch(cs->subtyp) { + case 1: + cs->hw.ax.base = pci_ioaddr5 + 0x00; + if (sct_alloc_io(pci_ioaddr1, 256)) + return(0); + if (sct_alloc_io(pci_ioaddr5, 256)) + return(0); + /* disable all IPAC */ + writereg(pci_ioaddr5, pci_ioaddr5 + 4, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24, + IPAC_MASK, 0xFF); + break; + case 2: + cs->hw.ax.base = pci_ioaddr4 + 0x08; + if (sct_alloc_io(pci_ioaddr4, 256)) + return(0); + break; + case 3: + cs->hw.ax.base = pci_ioaddr3 + 0x10; + if (sct_alloc_io(pci_ioaddr3, 256)) + return(0); + break; + case 4: + cs->hw.ax.base = pci_ioaddr2 + 0x20; + if (sct_alloc_io(pci_ioaddr2, 256)) + return(0); + break; + } /* For isac and hscx data path */ cs->hw.ax.data_adr = cs->hw.ax.base + 4; -#else - printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - return (0); -#endif /* CONFIG_PCI */ + printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n", CardType[card->typ], sct_quadro_subtypes[cs->subtyp], @@ -473,19 +447,6 @@ test_and_set_bit(HW_IPAC, &cs->HW_Flags); - /* Disable all currently not active ipacs */ - if (!is_ipac_active(SCT_1)) - set_ipac_active(SCT_1, 0); - if (!is_ipac_active(SCT_2)) - set_ipac_active(SCT_2, 0); - if (!is_ipac_active(SCT_3)) - set_ipac_active(SCT_3, 0); - if (!is_ipac_active(SCT_4)) - set_ipac_active(SCT_4, 0); - - /* Perfom general reset (if possible) */ - reset_bkm(cs); - cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; @@ -502,4 +463,7 @@ sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); +#else + printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); +#endif /* CONFIG_PCI */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/bkm_ax.h linux/drivers/isdn/hisax/bkm_ax.h --- v2.2.18/drivers/isdn/hisax/bkm_ax.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/bkm_ax.h Sun Mar 25 11:37:32 2001 @@ -1,13 +1,9 @@ -/* $Id: bkm_ax.h,v 1.2 1999/07/01 08:07:55 keil Exp $ +/* $Id: bkm_ax.h,v 1.5.6.1 2000/11/28 12:02:46 kai Exp $ * bkm_ax.h low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * $Log: bkm_ax.h,v $ - * Revision 1.2 1999/07/01 08:07:55 keil - * Initial version - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ @@ -20,19 +16,6 @@ #define SCT_3 3 #define SCT_4 4 #define BKM_A4T 5 - - -/* A4T */ -#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */ -#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */ -#define A4T_SUBVEN_ID 0x0871 -#define A4T_SUBSYS_ID 0xFFA4 -/* Scitel Quadro */ -#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */ -#define PLX_VENDOR_ID 0x10B5 -#define SCT_SUBVEN_ID 0x0871 -#define SCT_SUBSYS_ID 0xFFA8 - #define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */ #define PLX_ADDR_ISAC 0x18 /* Addr ISAC */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.2.18/drivers/isdn/hisax/callc.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/callc.c Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ -/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $ - +/* $Id: callc.c,v 2.51 2000/11/24 17:05:37 kai Exp $ + * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * @@ -10,156 +10,9 @@ * Thanks to Jan den Ouden * Fritz Elfert * - * $Log: callc.c,v $ - * Revision 2.40 1999/12/19 12:59:56 keil - * fix leased line handling - * and cosmetics - * - * Revision 2.39 1999/10/14 20:25:28 keil - * add a statistic for error monitoring - * - * Revision 2.38 1999/10/11 22:16:27 keil - * Suspend/Resume is possible without explicit ID too - * - * Revision 2.37 1999/09/20 19:49:47 keil - * Fix wrong init of PStack - * - * Revision 2.36 1999/09/20 12:13:13 keil - * Fix hang if no protocol was selected - * - * Revision 2.35 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 2.34 1999/08/25 20:02:34 werner - * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts - * with existing software definitions. (PtP incomplete called party number) - * - * Revision 2.33 1999/08/25 17:00:09 keil - * Make ISAR V32bis modem running - * Make LL->HL interface open for additional commands - * - * Revision 2.32 1999/08/22 20:27:01 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 2.31 1999/08/05 20:43:10 keil - * ISAR analog modem support - * - * Revision 2.30 1999/07/25 16:24:04 keil - * Fixed TEI now working again - * - * Revision 2.29 1999/07/13 21:05:41 werner - * Modified set_channel_limit to use new callback ISDN_STAT_DISCH. - * - * Revision 2.28 1999/07/09 08:30:02 keil - * cosmetics - * - * Revision 2.27 1999/07/05 23:51:38 werner - * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl - * hisaxctrl id 10 - * - * Revision 2.26 1999/07/01 08:11:21 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.25 1999/01/02 11:17:20 keil - * Changes for 2.2 - * - * Revision 2.24 1998/11/15 23:54:24 keil - * changes from 2.0 - * - * Revision 2.23 1998/09/30 22:21:57 keil - * cosmetics - * - * Revision 2.22 1998/08/20 13:50:29 keil - * More support for hybrid modem (not working yet) - * - * Revision 2.21 1998/08/13 23:36:15 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.20 1998/06/26 15:13:05 fritz - * Added handling of STAT_ICALL with incomplete CPN. - * Added AT&L for ttyI emulator. - * Added more locking stuff in tty_write. - * - * Revision 2.19 1998/05/25 14:08:06 keil - * HiSax 3.0 - * fixed X.75 and leased line to work again - * Point2Point and fixed TEI are runtime options now: - * hisaxctrl 7 1 set PTP - * hisaxctrl 8 - * set fixed TEI to TEIVALUE (0-63) - * - * Revision 2.18 1998/05/25 12:57:40 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.17 1998/04/15 16:46:06 keil - * RESUME support - * - * Revision 2.16 1998/04/10 10:35:17 paul - * fixed (silly?) warnings from egcs on Alpha. - * - * Revision 2.15 1998/03/19 13:18:37 keil - * Start of a CAPI like interface for supplementary Service - * first service: SUSPEND - * - * Revision 2.14 1998/03/07 22:56:54 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 2.13 1998/02/12 23:07:16 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 2.12 1998/02/09 10:55:54 keil - * New leased line mode - * - * Revision 2.11 1998/02/02 13:35:19 keil - * config B-channel delay - * - * Revision 2.10 1997/11/06 17:09:15 keil - * New 2.1 init code - * - * Revision 2.9 1997/10/29 19:01:58 keil - * new LL interface - * - * Revision 2.8 1997/10/10 20:56:44 fritz - * New HL interface. - * - * Revision 2.7 1997/10/01 09:21:28 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 2.6 1997/09/11 17:26:58 keil - * Open B-channel if here are incomming packets - * - * Revision 2.5 1997/08/07 17:46:05 keil - * Fix Incomming Call without broadcast - * - * Revision 2.4 1997/08/03 14:37:58 keil - * Activate Layer2 in PtP mode - * - * Revision 2.3 1997/07/31 19:23:40 keil - * LAYER2_WATCHING for PtP - * - * Revision 2.2 1997/07/31 11:48:18 keil - * experimental REJECT after ALERTING - * - * Revision 2.1 1997/07/30 17:12:59 keil - * more changes for 'One TEI per card' - * - * Revision 2.0 1997/07/27 21:12:21 keil - * CRef based L3; new channel handling; many other stuff - * - * Revision 1.31 1997/06/26 11:09:23 keil - * New managment and minor changes - * - * old logs removed /KKe - * */ - #define __NO_VERSION__ +#include #include "hisax.h" #include "../avmb1/capicmd.h" /* this should be moved in a common place */ @@ -167,7 +20,7 @@ #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module)) #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.40 $"; +const char *lli_revision = "$Revision: 2.51 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -177,10 +30,8 @@ static int init_b_st(struct Channel *chanp, int incoming); static void release_b_st(struct Channel *chanp); -static struct Fsm callcfsm = -{NULL, 0, 0, NULL, NULL}; - -static int chancount = 0; +static struct Fsm callcfsm; +static int chancount; /* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ #define ALERT_REJECT 0 @@ -349,6 +200,8 @@ { isdn_ctrl ic; + if (!chanp->proc) + return; if (chanp->proc->para.cause == NO_CAUSE) return; ic.driver = chanp->cs->myid; @@ -511,7 +364,7 @@ * No need to return "unknown" for calls without OAD, * cause that's handled in linklevel now (replaced by '0') */ - ic.parm.setup = chanp->proc->para.setup; + memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm)); ret = chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); @@ -528,12 +381,16 @@ FsmChangeState(fi, ST_IN_PROCEED_SEND); chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); if (ret == 5) { - chanp->setup = ic.parm.setup; + memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } break; case 2: /* Rejecting Call */ break; + case 3: /* incomplete number */ + FsmDelTimer(&chanp->drel_timer, 61); + chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); + break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); @@ -641,7 +498,8 @@ lli_leased_hup(fi, chanp); } else { FsmChangeState(fi, ST_WAIT_DRELEASE); - chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ + if (chanp->proc) + chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); } @@ -656,7 +514,8 @@ lli_leased_hup(fi, chanp); } else { FsmChangeState(fi, ST_WAIT_DRELEASE); - chanp->proc->para.cause = 0x15; /* Call Rejected */ + if (chanp->proc) + chanp->proc->para.cause = 0x15; /* Call Rejected */ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); } @@ -688,7 +547,8 @@ return; } #ifndef ALERT_REJECT - chanp->proc->para.cause = 0x15; /* Call Rejected */ + if (chanp->proc) + chanp->proc->para.cause = 0x15; /* Call Rejected */ chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); lli_dhup_close(fi, event, arg); #else @@ -920,7 +780,7 @@ } /* *INDENT-OFF* */ -static struct FsmNode fnlist[] HISAX_INITDATA = +static struct FsmNode fnlist[] __initdata = { {ST_NULL, EV_DIAL, lli_prep_dialout}, {ST_NULL, EV_RESUME, lli_resume}, @@ -937,6 +797,8 @@ {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req}, {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req}, {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close}, + {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call}, + {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error}, {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in}, {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect}, {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject}, @@ -988,8 +850,8 @@ #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) -HISAX_INITFUNC(void -CallcNew(void)) +void __init +CallcNew(void) { callcfsm.state_count = STATE_COUNT; callcfsm.event_count = EVENT_COUNT; @@ -1016,6 +878,7 @@ releasestack_isdnl2(st); break; case (ISDN_PROTO_L2_HDLC): + case (ISDN_PROTO_L2_HDLC_56K): case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): case (ISDN_PROTO_L2_FAX): @@ -1098,6 +961,9 @@ return; switch (pr) { + case (CC_MORE_INFO | INDICATION): + FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); + break; case (CC_DISCONNECT | INDICATION): FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); break; @@ -1245,7 +1111,7 @@ chanp->fi.printdebug = callc_debug; FsmInitTimer(&chanp->fi, &chanp->dial_timer); FsmInitTimer(&chanp->fi, &chanp->drel_timer); - if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { + if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) { init_d_st(chanp); } else { chanp->d_st = csta->channel->d_st; @@ -1318,9 +1184,12 @@ switch (pr) { case (DL_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lldata: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { + } else { + link_debug(chanp, 0, "lldata: channel not open"); dev_kfree_skb(skb); } break; @@ -1347,10 +1216,12 @@ switch (pr) { case (PH_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lltrans: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { - link_debug(chanp, 0, "channel not open"); + } else { + link_debug(chanp, 0, "lltrans: channel not open"); dev_kfree_skb(skb); } break; @@ -1375,6 +1246,8 @@ struct Channel *chanp = st->lli.userdata; isdn_ctrl ic; + if (chanp->debug & 0x800) + link_debug(chanp, 0, "llwakeup: %d", len); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BSENT; ic.arg = chanp->chan; @@ -1399,6 +1272,9 @@ case (ISDN_PROTO_L2_HDLC): st->l1.mode = L1_MODE_HDLC; break; + case (ISDN_PROTO_L2_HDLC_56K): + st->l1.mode = L1_MODE_HDLC_56K; + break; case (ISDN_PROTO_L2_TRANS): st->l1.mode = L1_MODE_TRANS; break; @@ -1435,6 +1311,7 @@ st->l2.debug = chanp->debug & 64; break; case (ISDN_PROTO_L2_HDLC): + case (ISDN_PROTO_L2_HDLC_56K): case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): case (ISDN_PROTO_L2_FAX): @@ -1648,7 +1525,7 @@ link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", ic->parm.setup.eazmsn, ic->parm.setup.phone, ic->parm.setup.si1, ic->parm.setup.si2); - chanp->setup = ic->parm.setup; + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (!strcmp(chanp->setup.eazmsn, "0")) chanp->setup.eazmsn[0] = '\0'; /* this solution is dirty and may be change, if @@ -1668,6 +1545,7 @@ break; case (ISDN_CMD_ACCEPTD): chanp = csta->channel + ic->arg; + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (chanp->debug & 1) link_debug(chanp, 1, "ACCEPTD"); FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); @@ -1864,7 +1742,7 @@ chanp = csta->channel + ic->arg; if (chanp->debug & 1) link_debug(chanp, 1, "REDIR"); - chanp->setup = ic->parm.setup; + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); FsmEvent(&chanp->fi, EV_REDIR, NULL); break; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/cert.c linux/drivers/isdn/hisax/cert.c --- v2.2.18/drivers/isdn/hisax/cert.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/cert.c Sun Mar 25 11:37:32 2001 @@ -1,22 +1,11 @@ -/* $Id: cert.c,v 2.2 1999/08/07 17:35:05 keil Exp $ - +/* $Id: cert.c,v 2.3 2000/06/26 08:59:12 keil Exp $ + * * Author Karsten Keil (keil@isdn4linux.de) * * This file is (c) under GNU PUBLIC LICENSE * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * - * $Log: cert.c,v $ - * Revision 2.2 1999/08/07 17:35:05 keil - * approval for Eicon Technology Diva 2.01 PCI - * - * Revision 2.1 1998/11/15 23:51:15 keil - * certification stuff - * - * Revision 1.2.2.1 1998/11/03 21:46:37 keil - * first version - * - * */ #include @@ -28,11 +17,9 @@ #if CERTIFICATION == 0 if (output) { printk(KERN_INFO "HiSax: Approval certification valid\n"); - printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n"); - printk(KERN_INFO "HiSax: Approval registration numbers:\n"); - printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n"); - printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n"); + printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n"); printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n"); + printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n"); } return(0); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.2.18/drivers/isdn/hisax/config.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/hisax/config.c Sun Mar 25 11:37:32 2001 @@ -1,167 +1,16 @@ -/* $Id: config.c,v 2.44 2000/02/26 00:35:12 keil Exp $ - +/* $Id: config.c,v 2.57.6.9 2001/02/13 10:33:58 kai Exp $ + * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * - * - * $Log: config.c,v $ - * Revision 2.44 2000/02/26 00:35:12 keil - * Fix skb freeing in interrupt context - * - * Revision 2.43 2000/01/20 19:49:36 keil - * Support teles 13.3c vendor version 2.1 - * - * Revision 2.42 1999/12/19 13:09:41 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 2.41 1999/11/18 00:00:43 werner - * - * Added support for HFC-S+ and HFC-SP cards - * - * Revision 2.40 1999/10/30 13:09:45 keil - * Version 3.3c - * - * Revision 2.39 1999/10/16 14:44:45 keil - * Fix module parm if only NICCY was selected - * - * Revision 2.38 1999/10/14 20:25:28 keil - * add a statistic for error monitoring - * - * Revision 2.37 1999/09/20 12:11:08 keil - * Fix hang if no protocol was selected - * - * Revision 2.36 1999/09/07 05:43:58 werner - * - * Added io as parameter 0 for HFC-PCI cards, if manual selection needed. - * - * Revision 2.35 1999/09/04 06:35:09 keil - * Winbond W6692 support - * - * Revision 2.34 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 2.33 1999/08/30 11:57:52 keil - * Fix broken avm pcmcia - * - * Revision 2.32 1999/08/28 22:11:10 keil - * __setup function should be static - * - * Revision 2.31 1999/08/25 16:47:43 keil - * Support new __setup; allow to add FEATURES after register_isdn - * - * Revision 2.30 1999/08/05 20:43:14 keil - * ISAR analog modem support - * - * Revision 2.29 1999/07/21 14:46:00 keil - * changes from EICON certification - * - * Revision 2.28 1999/07/14 12:38:36 werner - * Added changes for echo channel handling - * - * Revision 2.27 1999/07/12 21:05:00 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.26 1999/07/08 21:27:17 keil - * version 3.2 - * - * Revision 2.25 1999/07/05 23:51:44 werner - * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl - * hisaxctrl id 10 - * - * Revision 2.24 1999/07/01 08:11:26 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.23 1999/02/17 10:53:02 cpetig - * Added Hisax_closecard to exported symbols. - * As indicated by Oliver Schoett . - * - * If anyone is annoyed by exporting symbols deep inside the code, please - * contact me. - * - * Revision 2.22 1999/02/04 21:41:53 keil - * Fix printk msg - * - * Revision 2.21 1999/02/04 10:48:52 keil - * Fix readstat bug - * - * Revision 2.20 1998/11/15 23:54:28 keil - * changes from 2.0 - * - * Revision 2.19 1998/08/13 23:36:18 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.18 1998/07/30 21:01:37 niemann - * Fixed Sedlbauer Speed Fax PCMCIA missing isdnl3new - * - * Revision 2.17 1998/07/15 15:01:26 calle - * Support for AVM passive PCMCIA cards: - * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 - * - * Revision 2.16 1998/05/25 14:10:03 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.15 1998/05/25 12:57:43 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.14 1998/04/15 16:38:25 keil - * Add S0Box and Teles PCI support - * - * Revision 2.13 1998/03/09 23:19:23 keil - * Changes for PCMCIA - * - * Revision 2.12 1998/02/11 17:28:02 keil - * Niccy PnP/PCI support - * - * Revision 2.11 1998/02/09 21:26:13 keil - * fix export module for 2.1 - * - * Revision 2.10 1998/02/09 18:46:05 keil - * Support for Sedlbauer PCMCIA (Marcus Niemann) - * - * Revision 2.9 1998/02/03 23:31:28 keil - * add AMD7930 support - * - * Revision 2.8 1998/02/02 13:32:59 keil - * New card support - * - * Revision 2.7 1998/01/31 21:41:44 keil - * changes for newer 2.1 kernels - * - * Revision 2.6 1997/11/08 21:35:43 keil - * new l1 init - * - * Revision 2.5 1997/11/06 17:15:08 keil - * New 2.1 init; PCMCIA wrapper changes - * - * Revision 2.4 1997/10/29 19:07:52 keil - * changes for 2.1 - * - * Revision 2.3 1997/10/01 09:21:33 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 2.2 1997/09/11 17:24:46 keil - * Add new cards - * - * Revision 2.1 1997/07/27 21:41:35 keil - * version change - * - * Revision 2.0 1997/06/26 11:06:28 keil - * New card and L1 interface. - * Eicon.Diehl Diva and Dynalink IS64PH support - * - * old changes removed /KKe + * This file is (c) under GNU PUBLIC LICENSE * */ #include #include #include #include +#include #include "hisax.h" #include #include @@ -198,7 +47,7 @@ * 17 MIC card p0=irq p1=iobase * 18 ELSA Quickstep 1000PCI no parameter * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2 - * 20 Travers Technologies NETjet PCI card + * 20 Travers Technologies NETjet-S PCI card * 21 TELES PCI no parameter * 22 Sedlbauer Speed Star p0=irq p1=iobase * 23 reserved @@ -216,6 +65,8 @@ * 35 HFC 2BDS0 PCI none * 36 Winbond 6692 PCI none * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase + * 38 Travers Technologies NETspider-U PCI card + * 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase * * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * @@ -227,11 +78,11 @@ "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI", - "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", + "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", - "HFC 2BDS0 SX", + "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA", }; void HiSax_closecard(int cardnr); @@ -257,7 +108,6 @@ #define DEFAULT_CFG {11,0x170,0,0} int avm_a1_init_pcmcia(void*, int, int*, int); EXPORT_SYMBOL(avm_a1_init_pcmcia); -EXPORT_SYMBOL(HiSax_closecard); #endif /* CONFIG_HISAX_AVM_A1_PCMCIA */ #ifdef CONFIG_HISAX_FRITZPCI @@ -349,7 +199,7 @@ #ifdef CONFIG_HISAX_NETJET #undef DEFAULT_CARD #undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NETJET +#define DEFAULT_CARD ISDN_CTYPE_NETJET_S #define DEFAULT_CFG {0,0,0,0} #endif @@ -372,6 +222,8 @@ #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_HFC_SX #define DEFAULT_CFG {5,0x2E0,0,0} +int hfc_init_pcmcia(void*, int, int*, int); +EXPORT_SYMBOL(hfc_init_pcmcia); #endif @@ -431,22 +283,29 @@ #define DEFAULT_CFG {0,0,0,0} #endif +#ifdef CONFIG_HISAX_NETJET_U +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_NETJET_U +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_1TR6 #define DEFAULT_PROTO ISDN_PTYPE_1TR6 #define DEFAULT_PROTO_NAME "1TR6" #endif -#ifdef CONFIG_HISAX_EURO -#undef DEFAULT_PROTO -#define DEFAULT_PROTO ISDN_PTYPE_EURO -#undef DEFAULT_PROTO_NAME -#define DEFAULT_PROTO_NAME "EURO" -#endif #ifdef CONFIG_HISAX_NI1 #undef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_NI1 #undef DEFAULT_PROTO_NAME #define DEFAULT_PROTO_NAME "NI1" #endif +#ifdef CONFIG_HISAX_EURO +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_EURO +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "EURO" +#endif #ifndef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN #define DEFAULT_PROTO_NAME "UNKNOWN" @@ -455,6 +314,10 @@ #error "HiSax: No cards configured" #endif +int hisax_init_pcmcia(void *, int *, struct IsdnCard *); +EXPORT_SYMBOL(hisax_init_pcmcia); +EXPORT_SYMBOL(HiSax_closecard); + #define FIRST_CARD { \ DEFAULT_CARD, \ DEFAULT_PROTO, \ @@ -476,18 +339,14 @@ EMPTY_CARD, }; -static char HiSaxID[64] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -char *HiSax_id HISAX_INITDATA = HiSaxID; +static char HiSaxID[64] = { 0, }; + +char *HiSax_id = HiSaxID; #ifdef MODULE /* Variables for insmod */ -static int type[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0}; -static int protocol[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0}; -static int io[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0}; +static int type[8] = { 0, }; +static int protocol[8] = { 0, }; +static int io[8] = { 0, }; #undef IO0_IO1 #ifdef CONFIG_HISAX_16_3 #define IO0_IO1 @@ -497,16 +356,12 @@ #define IO0_IO1 #endif #ifdef IO0_IO1 -static int io0[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0}; -static int io1[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0}; -#endif -static int irq[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0}; -static int mem[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0}; -static char *id HISAX_INITDATA = HiSaxID; +static int io0[8] = { 0, }; +static int io1[8] = { 0, }; +#endif +static int irq[8] = { 0, }; +static int mem[8] = { 0, }; +static char *id = HiSaxID; MODULE_AUTHOR("Karsten Keil"); MODULE_PARM(type, "1-8i"); @@ -529,8 +384,8 @@ extern char *lli_revision; extern char *tei_revision; -HISAX_INITFUNC(char * -HiSax_getrev(const char *revision)) +char * +HiSax_getrev(const char *revision) { char *rev; char *p; @@ -544,16 +399,16 @@ return rev; } -HISAX_INITFUNC(void -HiSaxVersion(void)) +void __init +HiSaxVersion(void) { char tmp[64]; printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3e (module)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); @@ -580,11 +435,9 @@ MOD_INC_USE_COUNT; } -#ifdef MODULE -#define HiSax_init init_module -#else -__initfunc(void -HiSax_setup(char *str, int *ints)) +#ifndef MODULE +void __init +HiSax_setup(char *str, int *ints) { int i, j, argc; argc = ints[0]; @@ -689,8 +542,8 @@ extern int setup_mic(struct IsdnCard *card); #endif -#if CARD_NETJET -extern int setup_netjet(struct IsdnCard *card); +#if CARD_NETJET_S +extern int setup_netjet_s(struct IsdnCard *card); #endif #if CARD_HFCS @@ -741,6 +594,10 @@ extern int setup_w6692(struct IsdnCard *card); #endif +#if CARD_NETJET_U +extern int setup_netjet_u(struct IsdnCard *card); +#endif + /* * Find card with given driverId */ @@ -943,7 +800,7 @@ ic.command = ISDN_STAT_STOP; ic.driver = cs->myid; cs->iif.statcallb(&ic); - CallcFreeChan(cs); +// CallcFreeChan(cs); } static void @@ -991,7 +848,8 @@ ll_unload(csta); } -HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs)) +static int +init_card(struct IsdnCardState *cs) { int irq_cnt, cnt = 3; long flags; @@ -1012,7 +870,7 @@ while (cnt) { cs->cardmsg(cs, CARD_INIT, NULL); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); /* Timeout 10ms */ schedule_timeout((10*HZ)/1000); restore_flags(flags); @@ -1038,8 +896,8 @@ return(3); } -HISAX_INITFUNC(static int -checkcard(int cardnr, char *id, int *busy_flag)) +static int +checkcard(int cardnr, char *id, int *busy_flag) { long flags; int ret = 0; @@ -1066,6 +924,8 @@ cs->busy_flag = busy_flag; cs->irq_flags = I4L_IRQ_FLAG; #if TEI_PER_CARD + if (card->protocol == ISDN_PTYPE_NI1) + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #else test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #endif @@ -1099,6 +959,7 @@ cs->iif.features = ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_HDLC_56K | ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | #ifdef CONFIG_HISAX_1TR6 @@ -1210,9 +1071,9 @@ ret = setup_mic(card); break; #endif -#if CARD_NETJET - case ISDN_CTYPE_NETJET: - ret = setup_netjet(card); +#if CARD_NETJET_S + case ISDN_CTYPE_NETJET_S: + ret = setup_netjet_s(card); break; #endif #if CARD_HFCS @@ -1276,6 +1137,11 @@ ret = setup_w6692(card); break; #endif +#if CARD_NETJET_U + case ISDN_CTYPE_NETJET_U: + ret = setup_netjet_u(card); + break; +#endif default: printk(KERN_WARNING "HiSax: Support for %s Card not selected\n", @@ -1305,7 +1171,6 @@ cs->tx_skb = NULL; cs->tx_cnt = 0; cs->event = 0; - cs->tqueue.next = 0; cs->tqueue.sync = 0; cs->tqueue.data = cs; @@ -1329,8 +1194,8 @@ return (1); } -HISAX_INITFUNC(void -HiSax_shiftcards(int idx)) +void +HiSax_shiftcards(int idx) { int i; @@ -1338,8 +1203,8 @@ memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); } -HISAX_INITFUNC(int -HiSax_inithardware(int *busy_flag)) +int +HiSax_inithardware(int *busy_flag) { int foundcards = 0; int i = 0; @@ -1395,6 +1260,9 @@ if (cards[cardnr].cs) { ll_stop(cards[cardnr].cs); release_tei(cards[cardnr].cs); + + CallcFreeChan(cards[cardnr].cs); + closecard(cardnr); if (cards[cardnr].cs->irq) free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); @@ -1420,7 +1288,7 @@ printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n", (ulong) & HiSax_reportcard); printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs); - printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc1 flg %x\n", + printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n", cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag); printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n", cs->bcs[0].mode, cs->bcs[0].channel); @@ -1449,14 +1317,23 @@ #endif } - -__initfunc(int -HiSax_init(void)) +static int __init HiSax_init(void) { - int i; + int i,j; + int nzproto = 0; + + HiSaxVersion(); + CallcNew(); + Isdnl3New(); + Isdnl2New(); + TeiNew(); + Isdnl1New(); #ifdef MODULE - int nzproto = 0; + if (!type[0]) { + /* We 'll register drivers later, but init basic functions*/ + return 0; + } #ifdef CONFIG_HISAX_ELSA if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) { /* we have exported and return in this case */ @@ -1475,47 +1352,52 @@ return 0; } #endif +#ifdef CONFIG_HISAX_HFC_SX + if (type[0] == ISDN_CTYPE_HFC_SP_PCMCIA) { + /* we have to export and return in this case */ + return 0; + } +#endif #endif nrcards = 0; - HiSaxVersion(); #ifdef MODULE if (id) /* If id= string used */ HiSax_id = id; - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].typ = type[i]; + for (i = j = 0; j < HISAX_MAX_CARDS; i++) { + cards[j].typ = type[i]; if (protocol[i]) { - cards[i].protocol = protocol[i]; + cards[j].protocol = protocol[i]; nzproto++; } switch (type[i]) { case ISDN_CTYPE_16_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; - cards[i].para[2] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; + cards[j].para[2] = io[i]; break; case ISDN_CTYPE_8_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; break; #ifdef IO0_IO1 case ISDN_CTYPE_PNP: case ISDN_CTYPE_NICCY: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; break; case ISDN_CTYPE_COMPAQ_ISA: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; - cards[i].para[3] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; + cards[j].para[3] = io[i]; break; #endif case ISDN_CTYPE_ELSA: case ISDN_CTYPE_HFC_PCI: - cards[i].para[0] = io[i]; + cards[j].para[0] = io[i]; break; case ISDN_CTYPE_16_3: case ISDN_CTYPE_TELESPCMCIA: @@ -1539,30 +1421,46 @@ case ISDN_CTYPE_HSTSAPHIR: case ISDN_CTYPE_GAZEL: case ISDN_CTYPE_HFC_SX: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; + case ISDN_CTYPE_HFC_SP_PCMCIA: + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; break; case ISDN_CTYPE_ISURF: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].para[2] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; + cards[j].para[2] = mem[i]; break; case ISDN_CTYPE_ELSA_PCI: - case ISDN_CTYPE_NETJET: + case ISDN_CTYPE_NETJET_S: case ISDN_CTYPE_AMD7930: case ISDN_CTYPE_TELESPCI: case ISDN_CTYPE_W6692: + case ISDN_CTYPE_NETJET_U: break; case ISDN_CTYPE_BKM_A4T: - break; + break; case ISDN_CTYPE_SCT_QUADRO: - cards[i].para[0] = irq[i]; + if (irq[i]) { + cards[j].para[0] = irq[i]; + } else { + /* QUADRO is a 4 BRI card */ + cards[j++].para[0] = 1; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 2; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 3; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j].para[0] = 4; + } break; } + j++; } if (!nzproto) { printk(KERN_WARNING "HiSax: Warning - no protocol specified\n"); - printk(KERN_WARNING "HiSax: Note! module load syntax has changed.\n"); printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME); } #endif @@ -1576,15 +1474,8 @@ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", nrcards, (nrcards > 1) ? "s" : ""); - CallcNew(); - Isdnl3New(); - Isdnl2New(); - TeiNew(); - Isdnl1New(); if (HiSax_inithardware(NULL)) { /* Install only, if at least one card found */ -#ifdef MODULE -#endif /* MODULE */ return (0); } else { Isdnl1Free(); @@ -1596,9 +1487,7 @@ } } -#ifdef MODULE -void -cleanup_module(void) +static void HiSax_exit(void) { int cardnr = nrcards -1; long flags; @@ -1615,17 +1504,55 @@ restore_flags(flags); printk(KERN_INFO "HiSax module removed\n"); } -#endif #ifdef CONFIG_HISAX_ELSA int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) { #ifdef MODULE int i; + + nrcards = 0; + /* Initialize all structs, even though we only accept + two pcmcia cards + */ + for (i = 0; i < HISAX_MAX_CARDS; i++) { + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + cards[i].typ = type[i]; + if (protocol[i]) { + cards[i].protocol = protocol[i]; + } + } + cards[0].para[0] = pcm_irq; + cards[0].para[1] = (int)pcm_iob; + cards[0].protocol = prot; + cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA; + + if (!HiSax_id) + HiSax_id = HiSaxID; + if (!HiSaxID[0]) + strcpy(HiSaxID, "HiSax"); + for (i = 0; i < HISAX_MAX_CARDS; i++) + if (cards[i].typ > 0) + nrcards++; + printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", + nrcards, (nrcards > 1) ? "s" : ""); + + HiSax_inithardware(busy_flag); + printk(KERN_NOTICE "HiSax: module installed\n"); +#endif + return (0); +} +#endif + +#ifdef CONFIG_HISAX_HFC_SX +int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) +{ +#ifdef MODULE + int i; int nzproto = 0; nrcards = 0; - HiSaxVersion(); /* Initialize all structs, even though we only accept two pcmcia cards */ @@ -1641,7 +1568,7 @@ cards[0].para[0] = pcm_irq; cards[0].para[1] = (int)pcm_iob; cards[0].protocol = prot; - cards[0].typ = 10; + cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA; nzproto = 1; if (!HiSax_id) @@ -1654,11 +1581,6 @@ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", nrcards, (nrcards > 1) ? "s" : ""); - Isdnl1New(); - CallcNew(); - Isdnl3New(); - Isdnl2New(); - TeiNew(); HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif @@ -1674,7 +1596,6 @@ int nzproto = 0; nrcards = 0; - HiSaxVersion(); /* Initialize all structs, even though we only accept two pcmcia cards */ @@ -1703,11 +1624,6 @@ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", nrcards, (nrcards > 1) ? "s" : ""); - CallcNew(); - Isdnl3New(); - Isdnl2New(); - Isdnl1New(); - TeiNew(); HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif @@ -1723,7 +1639,6 @@ int nzproto = 0; nrcards = 0; - HiSaxVersion(); /* Initialize all structs, even though we only accept two pcmcia cards */ @@ -1752,14 +1667,31 @@ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", nrcards, (nrcards > 1) ? "s" : ""); - Isdnl1New(); - CallcNew(); - Isdnl3New(); - Isdnl2New(); - TeiNew(); HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif return (0); } #endif + +int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) +{ + u_char ids[16]; + int ret = -1; + + cards[nrcards] = *card; + if (nrcards) + sprintf(ids, "HiSax%d", nrcards); + else + sprintf(ids, "HiSax"); + if (!checkcard(nrcards, ids, busy_flag)) { + return(-1); + } + ret = nrcards; + nrcards++; + return (ret); +} + + +module_init(HiSax_init); +module_exit(HiSax_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.2.18/drivers/isdn/hisax/diva.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/diva.c Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ -/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $ - +/* $Id: diva.c,v 1.25.6.3 2001/02/13 10:33:58 kai Exp $ + * * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * * Author Karsten Keil (keil@isdn4linux.de) @@ -10,70 +10,10 @@ * * Thanks to Eicon Technology for documents and informations * - * - * $Log: diva.c,v $ - * Revision 1.18 1999/12/19 13:09:41 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.17 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.16 1999/08/11 21:01:25 keil - * new PCI codefix - * - * Revision 1.15 1999/08/10 16:01:49 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.14 1999/08/07 17:35:08 keil - * approval for Eicon Technology Diva 2.01 PCI - * - * Revision 1.13 1999/07/21 14:46:07 keil - * changes from EICON certification - * - * Revision 1.12 1999/07/12 21:05:04 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.11 1999/07/01 08:11:29 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.10 1998/11/15 23:54:31 keil - * changes from 2.0 - * - * Revision 1.9 1998/06/27 22:52:03 keil - * support for Diva 2.01 - * - * Revision 1.8 1998/05/25 12:57:46 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.7 1998/04/15 16:42:36 keil - * new init code - * new PCI init (2.1.94) - * - * Revision 1.6 1998/03/07 22:56:57 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 1.5 1998/02/02 13:29:38 keil - * fast io - * - * Revision 1.4 1997/11/08 21:35:44 keil - * new l1 init - * - * Revision 1.3 1997/11/06 17:13:33 keil - * New 2.1 init code - * - * Revision 1.2 1997/10/29 18:55:55 keil - * changes for 2.1.60 (irq2dev_map) - * - * Revision 1.1 1997/09/18 17:11:20 keil - * first version - * - * */ #define __NO_VERSION__ +#include #include #include "hisax.h" #include "isac.h" @@ -81,10 +21,11 @@ #include "ipac.h" #include "isdnl1.h" #include +#include extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.18 $"; +const char *Diva_revision = "$Revision: 1.25.6.3 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -107,14 +48,6 @@ #define DIVA_IPAC_ISA 3 #define DIVA_IPAC_PCI 4 -/* PCI stuff */ -#define PCI_VENDOR_EICON_DIEHL 0x1133 -#define PCI_DIVA20PRO_ID 0xe001 -#define PCI_DIVA20_ID 0xe002 -#define PCI_DIVA20PRO_U_ID 0xe003 -#define PCI_DIVA20_U_ID 0xe004 -#define PCI_DIVA_201 0xe005 - /* CTRL (Read) */ #define DIVA_IRQ_STAT 0x01 #define DIVA_EEPROM_SDA 0x02 @@ -131,10 +64,16 @@ /* Siemens PITA */ #define PITA_MISC_REG 0x1c +#ifdef __BIG_ENDIAN +#define PITA_PARA_SOFTRESET 0x00000001 +#define PITA_PARA_MPX_MODE 0x00000004 +#define PITA_INT0_ENABLE 0x00000200 +#else #define PITA_PARA_SOFTRESET 0x01000000 #define PITA_PARA_MPX_MODE 0x04000000 #define PITA_INT0_ENABLE 0x00020000 -#define PITA_INT0_STATUS 0x00000002 +#endif +#define PITA_INT0_STATUS 0x02 static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -183,7 +122,7 @@ static inline u_char memreadreg(unsigned long adr, u_char off) { - return(0xff & *((unsigned int *) + return(*((unsigned char *) (((unsigned int *)adr) + off))); } @@ -754,30 +693,30 @@ sti(); if (cs->subtyp == DIVA_IPAC_ISA) { writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); } else if (cs->subtyp == DIVA_IPAC_PCI) { unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + PITA_MISC_REG); *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); *ireg = PITA_PARA_MPX_MODE; - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0); } else { /* DIVA 2.0 */ cs->hw.diva.ctrl_reg = 0; /* Reset On */ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->subtyp == DIVA_ISA) cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; @@ -882,12 +821,12 @@ return(0); } -static struct pci_dev *dev_diva __initdata = NULL; -static struct pci_dev *dev_diva_u __initdata = NULL; -static struct pci_dev *dev_diva201 __initdata = NULL; +static struct pci_dev *dev_diva __initdata = NULL; +static struct pci_dev *dev_diva_u __initdata = NULL; +static struct pci_dev *dev_diva201 __initdata = NULL; -__initfunc(int -setup_diva(struct IsdnCard *card)) +int __init +setup_diva(struct IsdnCard *card) { int bytecnt; u_char val; @@ -931,28 +870,30 @@ } cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_ID, dev_diva))) { + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { + if (pci_enable_device(dev_diva)) + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = dev_diva->base_address[ 2] - & PCI_BASE_ADDRESS_IO_MASK; - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_U_ID, dev_diva_u))) { + cs->hw.diva.cfg_reg = dev_diva->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { + if (pci_enable_device(dev_diva_u)) + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = dev_diva_u->base_address[ 2] - & PCI_BASE_ADDRESS_IO_MASK; - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA_201, dev_diva201))) { + cs->hw.diva.cfg_reg = dev_diva_u->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { + if (pci_enable_device(dev_diva201)) + return(0); cs->subtyp = DIVA_IPAC_PCI; cs->irq = dev_diva201->irq; cs->hw.diva.pci_cfg = - (ulong) ioremap((dev_diva201->base_address[ 0] - & PCI_BASE_ADDRESS_IO_MASK), 4096); + (ulong) ioremap(dev_diva201->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK, 4096); cs->hw.diva.cfg_reg = - (ulong) ioremap((dev_diva201->base_address[ 1] - & PCI_BASE_ADDRESS_IO_MASK), 4096); + (ulong) ioremap(dev_diva201->base_address[ 1] & PCI_BASE_ADDRESS_MEM_MASK, 4096); } else { printk(KERN_WARNING "Diva: No PCI card found\n"); return(0); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.2.18/drivers/isdn/hisax/elsa.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/elsa.c Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ -/* $Id: elsa.c,v 2.20 1999/12/19 13:09:42 keil Exp $ - +/* $Id: elsa.c,v 2.26.6.2 2001/02/13 10:33:58 kai Exp $ + * * elsa.c low level stuff for Elsa isdn cards * * Author Karsten Keil (keil@isdn4linux.de) @@ -13,83 +13,10 @@ * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE) * for ELSA PCMCIA support * - * $Log: elsa.c,v $ - * Revision 2.20 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 2.19 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 2.18 1999/08/25 16:50:54 keil - * Fix bugs which cause 2.3.14 hangs (waitqueue init) - * - * Revision 2.17 1999/08/11 20:57:40 keil - * bugfix IPAC version 1.1 - * new PCI codefix - * - * Revision 2.16 1999/08/10 16:01:51 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 2.15 1999/08/09 19:25:21 keil - * Support (alpha version) for the '98 model of ELSA Microlink ISDN/MC - * by Christer Weinigel, Cendio Systems AB - * Add support for IPAC 1.2 - * - * Revision 2.14 1999/07/12 21:05:07 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.13 1999/07/01 08:11:31 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.12 1998/11/15 23:54:35 keil - * changes from 2.0 - * - * Revision 2.11 1998/08/20 13:50:34 keil - * More support for hybrid modem (not working yet) - * - * Revision 2.10 1998/08/13 23:36:22 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.9 1998/05/25 12:57:48 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.8 1998/04/15 16:41:42 keil - * QS3000 PCI support - * new init code - * new PCI init (2.1.94) - * - * Revision 2.7 1998/03/07 22:56:58 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 2.6 1998/02/02 13:29:40 keil - * fast io - * - * Revision 2.5 1998/01/31 21:41:45 keil - * changes for newer 2.1 kernels - * - * Revision 2.4 1997/11/08 21:35:46 keil - * new l1 init - * - * Revision 2.3 1997/11/06 17:15:09 keil - * New 2.1 init; PCMCIA wrapper changes - * - * Revision 2.2 1997/10/29 18:57:09 keil - * changes for 2.1.60, arcofi support - * - * Revision 2.1 1997/07/27 21:47:08 keil - * new interface structures - * - * Revision 2.0 1997/06/26 11:02:40 keil - * New Layer and card interface - * - * old changes removed KKe - * */ #define __NO_VERSION__ +#include #include #include "hisax.h" #include "arcofi.h" @@ -98,15 +25,16 @@ #include "hscx.h" #include "isdnl1.h" #include +#include #include #include extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.20 $"; +const char *Elsa_revision = "$Revision: 2.26.6.2 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", + "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", "PCMCIA-IPAC" }; const char *ITACVer[] = @@ -140,9 +68,6 @@ #define ELSA_PCMCIA_IPAC 11 /* PCI stuff */ -#define PCI_VENDOR_ELSA 0x1048 -#define PCI_QS1000_ID 0x1000 -#define PCI_QS3000_ID 0x3000 #define ELSA_PCI_IRQ_MASK 0x04 /* ITAC Registeradressen (only Microlink PC) */ @@ -582,10 +507,10 @@ save_flags(flags); sti(); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ restore_flags(flags); @@ -789,7 +714,7 @@ cs->hw.elsa.status |= ELSA_TIMER_AKTIV; byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); byteout(cs->hw.elsa.timer, 0); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((110*HZ)/1000); restore_flags(flags); cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; @@ -797,7 +722,8 @@ cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", cs->hw.elsa.counter); - if (abs(cs->hw.elsa.counter - 13) < 3) { + if ((cs->hw.elsa.counter > 10) && + (cs->hw.elsa.counter < 16)) { printk(KERN_INFO "Elsa: timer and irq OK\n"); ret = 0; } else { @@ -932,10 +858,10 @@ return (CARD_portlist[i]); } -static struct pci_dev *dev_qs1000 __initdata = NULL; -static struct pci_dev *dev_qs3000 __initdata = NULL; +static struct pci_dev *dev_qs1000 = NULL; +static struct pci_dev *dev_qs3000 = NULL; -int +int setup_elsa(struct IsdnCard *card) { long flags; @@ -1056,22 +982,22 @@ return(0); } cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID, - dev_qs1000))) { - cs->subtyp = ELSA_QS1000PCI; + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { + if (pci_enable_device(dev_qs1000)) + return(0); + cs->subtyp = ELSA_QS1000PCI; cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = dev_qs1000->base_address[ 1] & - PCI_BASE_ADDRESS_IO_MASK; - cs->hw.elsa.base = dev_qs1000->base_address[ 3] & - PCI_BASE_ADDRESS_IO_MASK; - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA, - PCI_QS3000_ID, dev_qs3000))) { + cs->hw.elsa.cfg = dev_qs1000->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.base = dev_qs1000->base_address[ 3] & PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) + return(0); cs->subtyp = ELSA_QS3000PCI; cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = dev_qs3000->base_address[ 1] & - PCI_BASE_ADDRESS_IO_MASK; - cs->hw.elsa.base = dev_qs3000->base_address[ 3] & - PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.cfg = dev_qs3000->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.base = dev_qs3000->base_address[ 3] & PCI_BASE_ADDRESS_IO_MASK; } else { printk(KERN_WARNING "Elsa: No PCI card found\n"); return(0); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/elsa_ser.c linux/drivers/isdn/hisax/elsa_ser.c --- v2.2.18/drivers/isdn/hisax/elsa_ser.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/elsa_ser.c Sun Mar 25 11:37:32 2001 @@ -1,3 +1,10 @@ +/* $Id: elsa_ser.c,v 2.10 2000/11/19 17:02:47 kai Exp $ + * + * stuff for the serial modem on ELSA cards + * + * This file is (c) under GNU PUBLIC LICENSE + * + */ #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c --- v2.2.18/drivers/isdn/hisax/fsm.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/fsm.c Sun Mar 25 11:37:32 2001 @@ -1,58 +1,22 @@ -/* $Id: fsm.c,v 1.11 1999/12/23 15:09:32 keil Exp $ - +/* $Id: fsm.c,v 1.14 2000/11/24 17:05:37 kai Exp $ + * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * Thanks to Jan den Ouden * Fritz Elfert * - * $Log: fsm.c,v $ - * Revision 1.11 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.10 1998/11/15 23:54:39 keil - * changes from 2.0 - * - * Revision 1.9 1998/03/26 07:10:02 paul - * The jumpmatrix table in struct Fsm was an array of "int". This is not - * large enough for pointers to functions on Linux/Alpha (instant crash - * on "insmod hisax). Now there is a typedef for the pointer to function. - * This also prevents warnings about "incompatible pointer types". - * - * Revision 1.8 1998/03/07 22:56:59 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 1.7 1997/11/06 17:09:13 keil - * New 2.1 init code - * - * Revision 1.6 1997/07/27 21:42:25 keil - * proof Fsm routines - * - * Revision 1.5 1997/06/26 11:10:05 keil - * Restart timer function added - * - * Revision 1.4 1997/04/06 22:56:42 keil - * Some cosmetic changes - * - * Revision 1.3 1997/02/16 01:04:08 fritz - * Bugfix: Changed timer handling caused hang with 2.1.X - * - * Revision 1.2 1997/01/09 20:57:27 keil - * cleanup & FSM_TIMER_DEBUG - * - * Revision 1.1 1996/10/13 20:04:52 keil - * Initial revision - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #define FSM_TIMER_DEBUG 0 -HISAX_INITFUNC(void -FsmNew(struct Fsm *fsm, - struct FsmNode *fnlist, int fncount)) +void __init +FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount) { int i; @@ -156,7 +120,7 @@ (long) ft, millisec, where); #endif - if (ft->tl.next || ft->tl.prev) { + if (timer_pending(&ft->tl)) { printk(KERN_WARNING "FsmAddTimer: timer already active!\n"); ft->fi->printdebug(ft->fi, "FsmAddTimer already active!"); return -1; @@ -180,7 +144,7 @@ (long) ft, millisec, where); #endif - if (ft->tl.next || ft->tl.prev) + if (timer_pending(&ft->tl)) del_timer(&ft->tl); init_timer(&ft->tl); ft->event = event; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c --- v2.2.18/drivers/isdn/hisax/gazel.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/gazel.c Sun Mar 25 11:37:32 2001 @@ -1,35 +1,15 @@ -/* $Id: gazel.c,v 2.6 1999/08/22 20:27:03 calle Exp $ - +/* $Id: gazel.c,v 2.11.6.3 2001/02/13 10:33:58 kai Exp $ + * * gazel.c low level stuff for Gazel isdn cards * * Author BeWan Systems * based on source code from Karsten Keil * - * $Log: gazel.c,v $ - * Revision 2.6 1999/08/22 20:27:03 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 2.5 1999/08/11 21:01:26 keil - * new PCI codefix - * - * Revision 2.4 1999/08/10 16:01:54 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 2.3 1999/07/12 21:05:09 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.1 1999/07/08 21:26:17 keil - * new card - * - * Revision 1.0 1999/28/06 - * Initial revision + * This file is (c) under GNU PUBLIC LICENSE * */ #include +#include #define __NO_VERSION__ #include "hisax.h" #include "isac.h" @@ -37,21 +17,16 @@ #include "isdnl1.h" #include "ipac.h" #include +#include extern const char *CardType[]; -const char *gazel_revision = "$Revision: 2.6 $"; +const char *gazel_revision = "$Revision: 2.11.6.3 $"; #define R647 1 #define R685 2 #define R753 3 #define R742 4 -/* Gazel R685 stuff */ -#define GAZEL_MANUFACTURER 0x10b5 -#define GAZEL_R685 0x1030 -#define GAZEL_R753 0x1152 -#define GAZEL_DJINN_ITOO 0x1151 - #define PLX_CNTRL 0x50 /* registre de controle PLX */ #define RESET_GAZEL 0x4 #define RESET_9050 0x40000000 @@ -586,24 +561,25 @@ printk(KERN_WARNING "Gazel: No PCI bus present\n"); return 1; } - seekcard = GAZEL_R685; + seekcard = PCI_DEVICE_ID_PLX_R685; for (nbseek = 0; nbseek < 3; nbseek++) { - if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) { - + if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) { + if (pci_enable_device(dev_tel)) + return 1; pci_irq = dev_tel->irq; - pci_ioaddr0 = dev_tel->base_address[ 1]; - pci_ioaddr1 = dev_tel->base_address[ 2]; + pci_ioaddr0 = dev_tel->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr1 = dev_tel->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK; found = 1; } if (found) break; else { switch (seekcard) { - case GAZEL_R685: - seekcard = GAZEL_R753; + case PCI_DEVICE_ID_PLX_R685: + seekcard = PCI_DEVICE_ID_PLX_R753; break; - case GAZEL_R753: - seekcard = GAZEL_DJINN_ITOO; + case PCI_DEVICE_ID_PLX_R753: + seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO; break; } } @@ -632,7 +608,7 @@ cs->irq_flags |= SA_SHIRQ; switch (seekcard) { - case GAZEL_R685: + case PCI_DEVICE_ID_PLX_R685: printk(KERN_INFO "Gazel: Card PCI R685 found\n"); cs->subtyp = R685; cs->dc.isac.adf2 = 0x87; @@ -643,8 +619,8 @@ "Gazel: hscx A:0x%X hscx B:0x%X\n", cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); break; - case GAZEL_R753: - case GAZEL_DJINN_ITOO: + case PCI_DEVICE_ID_PLX_R753: + case PCI_DEVICE_ID_PLX_DJINN_ITOO: printk(KERN_INFO "Gazel: Card PCI R753 found\n"); cs->subtyp = R753; test_and_set_bit(HW_IPAC, &cs->HW_Flags); @@ -657,8 +633,8 @@ return (0); } -__initfunc(int - setup_gazel(struct IsdnCard *card)) +int __init +setup_gazel(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c --- v2.2.18/drivers/isdn/hisax/hfc_2bds0.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfc_2bds0.c Sun Mar 25 11:37:32 2001 @@ -1,46 +1,14 @@ -/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.15 2000/11/24 17:05:37 kai Exp $ * * specific routines for CCD's HFC 2BDS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: hfc_2bds0.c,v $ - * Revision 1.11 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.10 1999/10/14 20:25:28 keil - * add a statistic for error monitoring - * - * Revision 1.9 1999/07/01 08:11:35 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.8 1998/11/15 23:54:40 keil - * changes from 2.0 - * - * Revision 1.7 1998/09/30 22:24:45 keil - * Fix missing line in setstack* - * - * Revision 1.6 1998/08/13 23:36:26 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 1.5 1998/06/27 22:52:58 keil - * make 16.3c working with 3.0 - * - * Revision 1.4 1998/05/25 12:57:52 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.3 1998/02/12 23:07:22 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.2 1998/02/02 13:26:13 keil - * New - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "hfc_2bds0.h" #include "isdnl1.h" @@ -1137,8 +1105,8 @@ { } -__initfunc(unsigned int -*init_send_hfcd(int cnt)) +unsigned int __init +*init_send_hfcd(int cnt) { int i, *send; @@ -1152,8 +1120,8 @@ return(send); } -__initfunc(void -init2bds0(struct IsdnCardState *cs)) +void __init +init2bds0(struct IsdnCardState *cs) { cs->setstack_d = setstack_hfcd; cs->dbusytimer.function = (void *) hfc_dbusy_timer; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_2bds0.h linux/drivers/isdn/hisax/hfc_2bds0.h --- v2.2.18/drivers/isdn/hisax/hfc_2bds0.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfc_2bds0.h Sun Mar 25 11:37:32 2001 @@ -1,18 +1,10 @@ -/* $Id: hfc_2bds0.h,v 1.3 1999/12/23 15:09:32 keil Exp $ - +/* $Id: hfc_2bds0.h,v 1.4 2000/06/26 08:59:12 keil Exp $ + * * specific defines for CCD's HFC 2BDS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: hfc_2bds0.h,v $ - * Revision 1.3 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.2 1998/02/02 13:26:15 keil - * New - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c --- v2.2.18/drivers/isdn/hisax/hfc_2bs0.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfc_2bs0.c Sun Mar 25 11:37:32 2001 @@ -1,53 +1,15 @@ -/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $ - +/* $Id: hfc_2bs0.c,v 1.17 2000/11/24 17:05:37 kai Exp $ + * * specific routines for CCD's HFC 2BS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: hfc_2bs0.c,v $ - * Revision 1.12 1999/12/19 14:17:12 keil - * fix compiler warning - * - * Revision 1.11 1999/11/21 12:41:18 werner - * - * Implemented full audio support - * - * Revision 1.10 1999/10/14 20:25:28 keil - * add a statistic for error monitoring - * - * Revision 1.9 1999/07/01 08:11:36 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.8 1998/11/15 23:54:43 keil - * changes from 2.0 - * - * Revision 1.7 1998/09/30 22:24:46 keil - * Fix missing line in setstack* - * - * Revision 1.6 1998/08/13 23:36:28 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 1.5 1998/05/25 12:57:54 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.4 1998/02/12 23:07:29 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.3 1997/11/06 17:13:35 keil - * New 2.1 init code - * - * Revision 1.2 1997/10/29 19:04:47 keil - * changes for 2.1 - * - * Revision 1.1 1997/09/11 17:31:33 keil - * Common part for HFC 2BS0 based cards - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "hfc_2bs0.h" #include "isac.h" @@ -242,7 +204,7 @@ ptr = skb_put(skb, count); idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx < count - 3) && WaitNoBusy(cs)) { + while ((idx < count) && WaitNoBusy(cs)) { *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } @@ -609,8 +571,8 @@ return (0); } -__initfunc(void -init_send(struct BCState *bcs)) +void __init +init_send(struct BCState *bcs) { int i; @@ -623,8 +585,8 @@ bcs->hw.hfc.send[i] = 0x1fff; } -__initfunc(void -inithfc(struct IsdnCardState *cs)) +void __init +inithfc(struct IsdnCardState *cs) { init_send(&cs->bcs[0]); init_send(&cs->bcs[1]); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_2bs0.h linux/drivers/isdn/hisax/hfc_2bs0.h --- v2.2.18/drivers/isdn/hisax/hfc_2bs0.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfc_2bs0.h Sun Mar 25 11:37:32 2001 @@ -1,17 +1,10 @@ -/* $Id: hfc_2bs0.h,v 1.2 1999/12/23 15:09:32 keil Exp $ - +/* $Id: hfc_2bs0.h,v 1.3 2000/06/26 08:59:13 keil Exp $ + * * specific defines for CCD's HFC 2BS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: hfc_2bs0.h,v $ - * Revision 1.2 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.1 1997/09/11 17:31:34 keil - * Common part for HFC 2BS0 based cards - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.2.18/drivers/isdn/hisax/hfc_pci.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/hisax/hfc_pci.c Sun Mar 25 11:37:32 2001 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.27 2000/02/26 00:35:12 keil Exp $ +/* $Id: hfc_pci.c,v 1.34.6.4 2001/02/13 10:33:58 kai Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -22,114 +22,21 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: hfc_pci.c,v $ - * Revision 1.27 2000/02/26 00:35:12 keil - * Fix skb freeing in interrupt context - * - * Revision 1.26 2000/02/09 20:22:55 werner - * - * Updated PCI-ID table - * - * Revision 1.25 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.24 1999/11/17 23:59:55 werner - * - * removed unneeded data - * - * Revision 1.23 1999/11/07 17:01:55 keil - * fix for 2.3 pci structs - * - * Revision 1.22 1999/10/10 20:14:27 werner - * - * Correct B2-chan usage in conjuntion with echo mode. First implementation of NT-leased line mode. - * - * Revision 1.21 1999/10/02 17:47:49 werner - * - * Changed init order, added correction for page alignment with shared mem - * - * Revision 1.20 1999/09/07 06:18:55 werner - * - * Added io parameter for HFC-PCI based cards. Needed only with multiple cards - * when initialisation/selection order needs to be set. - * - * Revision 1.19 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.18 1999/08/29 17:05:44 werner - * corrected tx_lo line setup. Datasheet is not correct. - * - * Revision 1.17 1999/08/28 21:04:27 werner - * Implemented full audio support (transparent mode) - * - * Revision 1.16 1999/08/25 17:01:27 keil - * Use new LL->HL auxcmd call - * - * Revision 1.15 1999/08/22 20:27:05 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.14 1999/08/12 18:59:45 werner - * Added further manufacturer and device ids to PCI list - * - * Revision 1.13 1999/08/11 21:01:28 keil - * new PCI codefix - * - * Revision 1.12 1999/08/10 16:01:58 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.11 1999/08/09 19:13:32 werner - * moved constant pci ids to pci id table - * - * Revision 1.10 1999/08/08 10:17:34 werner - * added new PCI vendor and card ids for Manufacturer 0x1043 - * - * Revision 1.9 1999/08/07 21:09:10 werner - * Fixed another memcpy problem in fifo handling. - * Thanks for debugging aid by Olaf Kordwittenborg. - * - * Revision 1.8 1999/07/23 14:25:15 werner - * Some smaller bug fixes and prepared support for GCI/IOM bus - * - * Revision 1.7 1999/07/14 21:24:20 werner - * fixed memcpy problem when using E-channel feature - * - * Revision 1.6 1999/07/13 21:08:08 werner - * added echo channel logging feature. - * - * Revision 1.5 1999/07/12 21:05:10 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.4 1999/07/04 21:51:39 werner - * Changes to solve problems with irq sharing and smp machines - * Thanks to Karsten Keil and Alex Holden for giving aid with - * testing and debugging - * - * Revision 1.3 1999/07/01 09:43:19 keil - * removed additional schedules in timeouts - * - * Revision 1.2 1999/07/01 08:07:51 keil - * Initial version - * - * - * */ +#include #include #define __NO_VERSION__ #include "hisax.h" #include "hfc_pci.h" #include "isdnl1.h" #include +#include #include extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.27 $"; +static const char *hfcpci_revision = "$Revision: 1.34.6.4 $"; /* table entry in the PCI devices list */ typedef struct { @@ -139,26 +46,32 @@ char *card_name; } PCI_ENTRY; -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ +#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ static const PCI_ENTRY id_list[] = { - {0x1397, 0x2BD0, "CCD/Billion/Asuscom", "2BD0"}, - {0x1397, 0xB000, "Billion", "B000"}, - {0x1397, 0xB006, "Billion", "B006"}, - {0x1397, 0xB007, "Billion", "B007"}, - {0x1397, 0xB008, "Billion", "B008"}, - {0x1397, 0xB009, "Billion", "B009"}, - {0x1397, 0xB00A, "Billion", "B00A"}, - {0x1397, 0xB00B, "Billion", "B00B"}, - {0x1397, 0xB00C, "Billion", "B00C"}, - {0x1043, 0x0675, "Asuscom/Askey", "675"}, - {0x0871, 0xFFA2, "German telekom", "T-Concept"}, - {0x0871, 0xFFA1, "German telekom", "A1T"}, - {0x1051, 0x0100, "Motorola MC145575", "MC145575"}, - {0x1397, 0xB100, "Seyeon", "B100"}, - {0x15B0, 0x2BD0, "Zoltrix", "2BD0"}, - {0x114f, 0x71, "Digi intl.","Digicom"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"}, + {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"}, + {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"}, + {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"}, + {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"}, + {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"}, + {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"}, + {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"}, {0, 0, NULL, NULL}, }; @@ -180,7 +93,7 @@ restore_flags(flags); Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ #if CONFIG_PCI @@ -211,10 +124,10 @@ pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */ Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ if (Read_hfc(cs, HFCPCI_STATUS) & 2) printk(KERN_WARNING "HFC-PCI init bit busy\n"); @@ -225,7 +138,7 @@ cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */ cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE; Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */ cs->hw.hfcpci.bswapped = 0; /* no exchange */ @@ -349,6 +262,9 @@ (*(bdata + (zp->z1 - B_SUB_VAL)))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); +#ifdef ERROR_STATISTIC + bcs->err_inv++; +#endif bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ skb = NULL; @@ -415,6 +331,9 @@ (df->data[zp->z1])) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); } else if ((skb = dev_alloc_skb(rcnt - 3))) { @@ -601,6 +520,9 @@ if (fcnt > (MAX_D_FRAMES - 1)) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif return; } /* now determine free bytes in FIFO buffer */ @@ -835,6 +757,7 @@ (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { save_flags(flags); cli(); + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */ Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ udelay(10); cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT; @@ -1650,8 +1573,8 @@ /********************************/ /* called for card init message */ /********************************/ -__initfunc(void - inithfcpci(struct IsdnCardState *cs)) +void __init +inithfcpci(struct IsdnCardState *cs) { cs->setstack_d = setstack_hfcpci; cs->dbusytimer.function = (void *) hfcpci_dbusy_timer; @@ -1690,7 +1613,7 @@ inithfcpci(cs); save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ /* now switch timer interrupt off */ cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; @@ -1711,26 +1634,23 @@ #endif /* CONFIG_PCI */ -__initfunc(int - setup_hfcpci(struct IsdnCard *card)) +int __init setup_hfcpci(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; - unsigned short cmd; char tmp[64]; int i; struct pci_dev *tmp_hfcpci = NULL; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); -#if CONFIG_PCI +#ifdef CONFIG_PCI cs->hw.hfcpci.int_s1 = 0; cs->dc.hfcpci.ph_state = 0; cs->hw.hfcpci.fifo = 255; if (cs->typ == ISDN_CTYPE_HFC_PCI) { - if (!pci_present()) { - printk(KERN_ERR "HFC-PCI: no PCI bus present\n"); - return (0); - } i = 0; while (id_list[i].vendor_id) { tmp_hfcpci = pci_find_device(id_list[i].vendor_id, @@ -1738,6 +1658,8 @@ dev_hfcpci); i++; if (tmp_hfcpci) { + if (pci_enable_device(tmp_hfcpci)) + continue; if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK))) continue; else @@ -1761,41 +1683,6 @@ printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); return (0); } -#ifdef notdef - if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) { - printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n"); - pcibios_write_config_word(cs->hw.hfcpci.pci_bus, - cs->hw.hfcpci.pci_device_fn, - PCI_COMMAND, - 0x0103); /* set SERR */ - pcibios_read_config_word(cs->hw.hfcpci.pci_bus, - cs->hw.hfcpci.pci_device_fn, - PCI_COMMAND, - &cmd); - pcibios_write_config_word(cs->hw.hfcpci.pci_bus, - cs->hw.hfcpci.pci_device_fn, - PCI_COMMAND, - cmd & ~2); - (int) cs->hw.hfcpci.pci_io &= ~(PAGE_SIZE - 1); - pcibios_write_config_dword(cs->hw.hfcpci.pci_bus, - cs->hw.hfcpci.pci_device_fn, - PCI_BASE_ADDRESS_1, - (int) cs->hw.hfcpci.pci_io); - pcibios_write_config_word(cs->hw.hfcpci.pci_bus, - cs->hw.hfcpci.pci_device_fn, - PCI_COMMAND, - cmd); - pcibios_read_config_dword(cs->hw.hfcpci.pci_bus, - cs->hw.hfcpci.pci_device_fn, - PCI_BASE_ADDRESS_1, - (void *) &cs->hw.hfcpci.pci_io); - if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) { - printk(KERN_WARNING "HFC-PCI unable to align address %x\n", (unsigned) cs->hw.hfcpci.pci_io); - return (0); - } - dev_hfcpci->base_address[1] = (int) cs->hw.hfcpci.pci_io; - } -#endif if (!cs->hw.hfcpci.pci_io) { printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); return (0); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_pci.h linux/drivers/isdn/hisax/hfc_pci.h --- v2.2.18/drivers/isdn/hisax/hfc_pci.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfc_pci.h Sun Mar 25 11:37:32 2001 @@ -1,5 +1,5 @@ -/* $Id: hfc_pci.h,v 1.7 1999/10/10 20:13:06 werner Exp $ - +/* $Id: hfc_pci.h,v 1.8 2000/06/26 08:59:13 keil Exp $ + * * specific defines for CCD's HFC 2BDS0 PCI chips * * Author Werner Cornelius (werner@isdn4linux.de) @@ -19,28 +19,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Log: hfc_pci.h,v $ - * Revision 1.7 1999/10/10 20:13:06 werner - * - * Corrected timer constant - * - * Revision 1.6 1999/08/28 21:04:29 werner - * Implemented full audio support (transparent mode) - * - * Revision 1.5 1999/08/09 19:13:34 werner - * moved constant pci ids to pci id table - * - * Revision 1.4 1999/08/08 10:17:33 werner - * added new PCI vendor and card ids for Manufacturer 0x1043 - * - * Revision 1.3 1999/07/14 12:39:34 werner - * Added changes for echo handling. - * - * Revision 1.2 1999/07/01 08:07:52 keil - * Initial version - * - * * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_sx.c linux/drivers/isdn/hisax/hfc_sx.c --- v2.2.18/drivers/isdn/hisax/hfc_sx.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfc_sx.c Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $ +/* $Id: hfc_sx.c,v 1.9 2000/11/24 17:05:37 kai Exp $ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards * @@ -21,25 +21,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: hfc_sx.c,v $ - * Revision 1.3 2000/01/20 19:49:36 keil - * Support teles 13.3c vendor version 2.1 - * - * Revision 1.2 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.1 1999/11/18 00:09:18 werner - * - * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM. - * Audio and Echo are supported. - * - * - * */ -#include #define __NO_VERSION__ +#include #include "hisax.h" #include "hfc_sx.h" #include "isdnl1.h" @@ -47,7 +32,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.3 $"; +static const char *hfcsx_revision = "$Revision: 1.9 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -361,7 +346,7 @@ restore_flags(flags); Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */ sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */ del_timer(&cs->hw.hfcsx.timer); @@ -408,10 +393,10 @@ while (1) { Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */ sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ if (Read_hfc(cs, HFCSX_STATUS) & 2) printk(KERN_WARNING "HFC-SX init bit busy\n"); @@ -1431,8 +1416,8 @@ /********************************/ /* called for card init message */ /********************************/ -__initfunc(void - inithfcsx(struct IsdnCardState *cs)) +void +inithfcsx(struct IsdnCardState *cs) { cs->setstack_d = setstack_hfcsx; cs->dbusytimer.function = (void *) hfcsx_dbusy_timer; @@ -1471,7 +1456,7 @@ inithfcsx(cs); save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ /* now switch timer interrupt off */ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; @@ -1488,8 +1473,8 @@ -__initfunc(int - setup_hfcsx(struct IsdnCard *card)) +int +setup_hfcsx(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -1502,7 +1487,8 @@ cs->hw.hfcsx.int_s1 = 0; cs->dc.hfcsx.ph_state = 0; cs->hw.hfcsx.fifo = 255; - if (cs->typ == ISDN_CTYPE_HFC_SX) { + if ((cs->typ == ISDN_CTYPE_HFC_SX) || + (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) { if ((!cs->hw.hfcsx.base) || check_region((cs->hw.hfcsx.base), 2)) { printk(KERN_WARNING diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfc_sx.h linux/drivers/isdn/hisax/hfc_sx.h --- v2.2.18/drivers/isdn/hisax/hfc_sx.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfc_sx.h Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: hfc_sx.h,v 1.1 1999/11/18 00:09:18 werner Exp $ - +/* $Id: hfc_sx.h,v 1.2 2000/06/26 08:59:13 keil Exp $ + * * specific defines for CCD's HFC 2BDS0 S+,SP chips * * Author Werner Cornelius (werner@isdn4linux.de) @@ -19,14 +19,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Log: hfc_sx.h,v $ - * Revision 1.1 1999/11/18 00:09:18 werner - * - * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM. - * Audio and Echo are supported. - * - * * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c --- v2.2.18/drivers/isdn/hisax/hfcscard.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hfcscard.c Sun Mar 25 11:37:33 2001 @@ -1,40 +1,22 @@ -/* $Id: hfcscard.c,v 1.6 1999/12/19 13:09:42 keil Exp $ - +/* $Id: hfcscard.c,v 1.8 2000/11/24 17:05:37 kai Exp $ + * * hfcscard.c low level stuff for hfcs based cards (Teles3c, ACER P10) * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: hfcscard.c,v $ - * Revision 1.6 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.5 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.4 1999/08/09 18:59:59 keil - * Fix S0 init - Thanks to Stefan Gybas - * - * Revision 1.3 1999/07/12 21:05:12 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.2 1999/07/01 08:16:03 keil - * teles3c ---> hfcscard - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "hfc_2bds0.h" #include "isdnl1.h" extern const char *CardType[]; -static const char *hfcs_revision = "$Revision: 1.6 $"; +static const char *hfcs_revision = "$Revision: 1.8 $"; static void hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs) @@ -89,13 +71,13 @@ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); cs->hw.hfcD.cirm = 0; if (cs->typ == ISDN_CTYPE_TELES3C) cs->hw.hfcD.cirm |= HFCD_MEM8K; cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->typ == ISDN_CTYPE_TELES3C) cs->hw.hfcD.cirm |= HFCD_INTB; @@ -142,7 +124,7 @@ init2bds0(cs); save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((80*HZ)/1000); cs->hw.hfcD.ctmt |= HFCD_TIM800; cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); @@ -155,8 +137,8 @@ return(0); } -__initfunc(int -setup_hfcs(struct IsdnCard *card)) +int __init +setup_hfcs(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.2.18/drivers/isdn/hisax/hisax.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hisax.h Sun Mar 25 11:37:33 2001 @@ -1,143 +1,8 @@ -/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $ - - * Basic declarations, defines and prototypes - * - * $Log: hisax.h,v $ - * Revision 2.41 2000/02/26 00:35:13 keil - * Fix skb freeing in interrupt context - * - * Revision 2.40 2000/01/20 19:51:46 keil - * Fix AddTimer message - * Change CONFIG defines - * - * Revision 2.39 1999/11/18 00:00:43 werner - * - * Added support for HFC-S+ and HFC-SP cards - * - * Revision 2.38 1999/11/14 23:37:03 keil - * new ISA memory mapped IO - * - * Revision 2.37 1999/10/14 20:25:28 keil - * add a statistic for error monitoring - * - * Revision 2.36 1999/10/10 20:16:15 werner - * - * Added variable to hfcpci union. - * - * Revision 2.35 1999/09/04 06:35:09 keil - * Winbond W6692 support - * - * Revision 2.34 1999/08/25 17:00:04 keil - * Make ISAR V32bis modem running - * Make LL->HL interface open for additional commands - * - * Revision 2.33 1999/08/05 20:43:16 keil - * ISAR analog modem support - * - * Revision 2.31 1999/07/21 14:46:11 keil - * changes from EICON certification - * - * Revision 2.30 1999/07/14 12:38:38 werner - * Added changes for echo channel handling - * - * Revision 2.29 1999/07/12 21:05:14 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.28 1999/07/05 23:51:46 werner - * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl - * hisaxctrl id 10 - * - * Revision 2.27 1999/07/01 08:11:38 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.26 1998/11/15 23:54:45 keil - * changes from 2.0 - * - * Revision 2.25 1998/09/30 22:28:42 keil - * More work for ISAR support - * - * Revision 2.24 1998/08/20 13:50:39 keil - * More support for hybrid modem (not working yet) - * - * Revision 2.23 1998/08/13 23:36:31 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.22 1998/07/15 15:01:28 calle - * Support for AVM passive PCMCIA cards: - * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 - * - * Revision 2.21 1998/05/25 14:10:05 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.20 1998/05/25 12:57:57 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.19 1998/04/15 16:39:15 keil - * Add S0Box and Teles PCI support - * - * Revision 2.18 1998/03/26 07:10:04 paul - * The jumpmatrix table in struct Fsm was an array of "int". This is not - * large enough for pointers to functions on Linux/Alpha (instant crash - * on "insmod hisax). Now there is a typedef for the pointer to function. - * This also prevents warnings about "incompatible pointer types". - * - * Revision 2.17 1998/03/19 13:18:43 keil - * Start of a CAPI like interface for supplementary Service - * first service: SUSPEND - * - * Revision 2.16 1998/03/09 23:19:25 keil - * Changes for PCMCIA - * - * Revision 2.14 1998/02/11 17:28:04 keil - * Niccy PnP/PCI support - * - * Revision 2.13 1998/02/09 18:46:02 keil - * Support for Sedlbauer PCMCIA (Marcus Niemann) - * - * Revision 2.12 1998/02/03 23:31:30 keil - * add AMD7930 support - * - * Revision 2.11 1998/02/02 13:33:00 keil - * New card support - * - * Revision 2.10 1997/11/08 21:37:52 keil - * new l1 init;new Compaq card - * - * Revision 2.9 1997/11/06 17:09:09 keil - * New 2.1 init code - * - * Revision 2.8 1997/10/29 19:04:13 keil - * new L1; changes for 2.1 - * - * Revision 2.7 1997/10/10 20:56:47 fritz - * New HL interface. - * - * Revision 2.6 1997/09/11 17:25:51 keil - * Add new cards - * - * Revision 2.5 1997/08/03 14:36:31 keil - * Implement RESTART procedure - * - * Revision 2.4 1997/07/31 19:25:20 keil - * PTP_DATA_LINK support +/* $Id: hisax.h,v 2.52.6.2 2001/02/10 14:41:22 kai Exp $ * - * Revision 2.3 1997/07/31 11:50:17 keil - * ONE TEI and FIXED TEI handling - * - * Revision 2.2 1997/07/30 17:13:02 keil - * more changes for 'One TEI per card' - * - * Revision 2.1 1997/07/27 21:45:13 keil - * new main structures - * - * Revision 2.0 1997/06/26 11:06:27 keil - * New card and L1 interface. - * Eicon.Diehl Diva and Dynalink IS64PH support + * Basic declarations, defines and prototypes * - * old changes removed KKe + * This file is (c) under GNU PUBLIC LICENSE * */ #include @@ -151,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -173,8 +38,11 @@ #define HW_POWERUP 0x0008 #define HW_ACTIVATE 0x0010 #define HW_DEACTIVATE 0x0018 + +#define HW_INFO1 0x0010 #define HW_INFO2 0x0020 #define HW_INFO3 0x0030 +#define HW_INFO4 0x0040 #define HW_INFO4_P8 0x0040 #define HW_INFO4_P10 0x0048 #define HW_RSYNC 0x0060 @@ -224,6 +92,7 @@ #define CC_SUSPEND 0x0370 #define CC_PROCEED_SEND 0x0374 #define CC_REDIR 0x0378 +#define CC_T302 0x0382 #define CC_T303 0x0383 #define CC_T304 0x0384 #define CC_T305 0x0385 @@ -234,6 +103,7 @@ #define CC_T313 0x0393 #define CC_T318 0x0398 #define CC_T319 0x0399 +#define CC_TSPID 0x03A0 #define CC_NOSETUP_RSP 0x03E0 #define CC_SETUP_ERR 0x03E1 #define CC_SUSPEND_ERR 0x03E2 @@ -242,6 +112,7 @@ #define CC_RELEASE_ERR 0x03E5 #define CC_RESTART 0x03F4 #define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */ +#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */ /* define maximum number of possible waiting incoming calls */ #define MAX_WAITING_CALLS 2 @@ -249,13 +120,19 @@ #ifdef __KERNEL__ -/* include only l3dss1 specific process structures, but no other defines */ +/* include l3dss1 & ni1 specific process structures, but no other defines */ #ifdef CONFIG_HISAX_EURO #define l3dss1_process #include "l3dss1.h" #undef l3dss1_process #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + #define l3ni1_process + #include "l3ni1.h" + #undef l3ni1_process +#endif CONFIG_HISAX_NI1 + #define MAX_DFRAME_LEN 260 #define MAX_DFRAME_LEN_L1 300 #define HSCX_BUFMAX 4096 @@ -318,12 +195,13 @@ #define FLG_L1_ACTTIMER 4 #define FLG_L1_T3RUN 5 #define FLG_L1_PULL_REQ 6 +#define FLG_L1_UINT 7 struct Layer1 { void *hardware; struct BCState *bcs; struct PStack **stlistp; - int Flags; + long Flags; struct FsmInst l1m; struct FsmTimer timer; void (*l1l2) (struct PStack *, int, void *); @@ -362,7 +240,7 @@ int tei; int sap; int maxlen; - unsigned int flag; + unsigned long flag; unsigned int vs, va, vr; int rc; unsigned int window; @@ -432,7 +310,7 @@ struct Layer3 l3; struct LLInterface lli; struct Management ma; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ /* protocol specific data fields */ union @@ -440,6 +318,9 @@ #ifdef CONFIG_HISAX_EURO dss1_stk_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_stk_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -461,6 +342,9 @@ #ifdef CONFIG_HISAX_EURO dss1_proc_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_proc_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -481,7 +365,7 @@ }; struct isar_reg { - unsigned int Flags; + unsigned long Flags; volatile u_char bstat; volatile u_char iis; volatile u_char cmsb; @@ -499,6 +383,7 @@ u_char mod; u_char newcmd; u_char newmod; + char try_mod; struct timer_list ftimer; u_char *rcvbuf; /* B-Channel receive Buffer */ u_char conmsg[16]; @@ -506,10 +391,17 @@ }; struct hdlc_stat_reg { +#ifdef __BIG_ENDIAN + u_char fill __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char cmd __attribute__((packed)); +#else u_char cmd __attribute__((packed)); u_char xml __attribute__((packed)); u_char mode __attribute__((packed)); u_char fill __attribute__((packed)); +#endif }; struct hdlc_hw { @@ -583,6 +475,7 @@ #define L1_MODE_TRANS 1 #define L1_MODE_HDLC 2 #define L1_MODE_EXTRN 3 +#define L1_MODE_HDLC_56K 4 #define L1_MODE_MODEM 7 #define L1_MODE_V32 8 #define L1_MODE_FAX 9 @@ -590,7 +483,7 @@ struct BCState { int channel; int mode; - int Flag; + long Flag; /* long req'd for set_bit --RR */ struct IsdnCardState *cs; int tx_cnt; /* B-Channel transmit counter */ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ @@ -635,7 +528,8 @@ int data_open; struct l3_process *proc; setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - int Flags; /* for remembering action done in l4 */ + long Flags; /* for remembering action done in l4 */ + /* long req'd for set_bit --RR */ int leased; }; @@ -894,8 +788,8 @@ unsigned char *sfifo_e; int sfifo_cnt; unsigned int stat; - struct wait_queue *rwaitq; - struct wait_queue *swaitq; + wait_queue_head_t rwaitq; + wait_queue_head_t swaitq; }; #endif @@ -915,7 +809,7 @@ int mon_rxp; struct arcofi_msg *arcofi_list; struct timer_list arcofitimer; - struct wait_queue *arcofi_wait; + wait_queue_head_t arcofi_wait; u_char arcofi_bc; u_char arcofi_state; u_char mocr; @@ -938,6 +832,22 @@ int ph_state; }; +struct icc_chip { + int ph_state; + u_char *mon_tx; + u_char *mon_rx; + int mon_txp; + int mon_txc; + int mon_rxp; + struct arcofi_msg *arcofi_list; + struct timer_list arcofitimer; + wait_queue_head_t arcofi_wait; + u_char arcofi_bc; + u_char arcofi_state; + u_char mocr; + u_char adf2; +}; + #define HW_IOM1 0 #define HW_IPAC 1 #define HW_ISAR 2 @@ -948,6 +858,7 @@ #define FLG_LOCK_ATOMIC 7 #define FLG_ARCOFI_TIMER 8 #define FLG_ARCOFI_ERROR 9 +#define FLG_HW_L1_UINT 10 struct IsdnCardState { unsigned char typ; @@ -955,7 +866,7 @@ int protocol; unsigned int irq; unsigned long irq_flags; - int HW_Flags; + long HW_Flags; int *busy_flag; int chanlimit; /* limited number of B-chans to use */ int logecho; /* log echo if supported by card */ @@ -1016,12 +927,13 @@ struct hfcpci_chip hfcpci; struct hfcsx_chip hfcsx; struct w6692_chip w6692; + struct icc_chip icc; } dc; u_char *rcvbuf; int rcvidx; struct sk_buff *tx_skb; int tx_cnt; - int event; + long event; struct tq_struct tqueue; struct timer_list dbusytimer; #ifdef ERROR_STATISTIC @@ -1057,7 +969,7 @@ #define ISDN_CTYPE_MIC 17 #define ISDN_CTYPE_ELSA_PCI 18 #define ISDN_CTYPE_COMPAQ_ISA 19 -#define ISDN_CTYPE_NETJET 20 +#define ISDN_CTYPE_NETJET_S 20 #define ISDN_CTYPE_TELESPCI 21 #define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 #define ISDN_CTYPE_AMD7930 23 @@ -1075,24 +987,15 @@ #define ISDN_CTYPE_HFC_PCI 35 #define ISDN_CTYPE_W6692 36 #define ISDN_CTYPE_HFC_SX 37 -#define ISDN_CTYPE_COUNT 37 +#define ISDN_CTYPE_NETJET_U 38 +#define ISDN_CTYPE_HFC_SP_PCMCIA 39 +#define ISDN_CTYPE_COUNT 39 #ifdef ISDN_CHIP_ISAC #undef ISDN_CHIP_ISAC #endif -#ifndef __initfunc -#define __initfunc(__arginit) __arginit -#endif - -#ifndef __initdata -#define __initdata -#endif - -#define HISAX_INITFUNC(__arginit) __initfunc(__arginit) -#define HISAX_INITDATA __initdata - #ifdef CONFIG_HISAX_16_0 #define CARD_TELES0 1 #ifndef ISDN_CHIP_ISAC @@ -1152,10 +1055,6 @@ #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif -#undef HISAX_INITFUNC -#define HISAX_INITFUNC(__arginit) __arginit -#undef HISAX_INITDATA -#define HISAX_INITDATA #else #define CARD_ELSA 0 #endif @@ -1224,12 +1123,12 @@ #endif #ifdef CONFIG_HISAX_NETJET -#define CARD_NETJET 1 +#define CARD_NETJET_S 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif #else -#define CARD_NETJET 0 +#define CARD_NETJET_S 0 #endif #ifdef CONFIG_HISAX_HFCS @@ -1337,17 +1236,19 @@ #define CARD_W6692 0 #endif -#define TEI_PER_CARD 0 - -#ifdef CONFIG_HISAX_1TR6 -#undef TEI_PER_CARD -#define TEI_PER_CARD 1 +#ifdef CONFIG_HISAX_NETJET_U +#define CARD_NETJET_U 1 +#ifndef ISDN_CHIP_ICC +#define ISDN_CHIP_ICC 1 +#endif +#ifndef HISAX_UINTERFACE +#define HISAX_UINTERFACE 1 +#endif +#else +#define CARD_NETJET_U 0 #endif -#ifdef CONFIG_HISAX_EURO -#undef TEI_PER_CARD #define TEI_PER_CARD 1 -#endif /* L1 Debug */ #define L1_DEB_WARN 0x01 @@ -1371,7 +1272,7 @@ struct IsdnCard { int typ; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ unsigned int para[4]; struct IsdnCardState *cs; }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c --- v2.2.18/drivers/isdn/hisax/hscx.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hscx.c Sun Mar 25 11:37:33 2001 @@ -1,77 +1,27 @@ -/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $ - +/* $Id: hscx.c,v 1.21 2000/11/24 17:05:37 kai Exp $ + * * hscx.c HSCX specific routines * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: hscx.c,v $ - * Revision 1.17 1999/07/01 08:11:41 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.16 1998/11/15 23:54:48 keil - * changes from 2.0 - * - * Revision 1.15 1998/08/20 13:50:42 keil - * More support for hybrid modem (not working yet) - * - * Revision 1.14 1998/08/13 23:36:33 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 1.13 1998/06/26 22:03:28 keil - * send flags between hdlc frames - * - * Revision 1.12 1998/06/09 18:26:01 keil - * PH_DEACTIVATE B-channel every time signaled to higher layer - * - * Revision 1.11 1998/05/25 14:10:07 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 1.10 1998/05/25 12:57:59 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.9 1998/04/15 16:45:33 keil - * new init code - * - * Revision 1.8 1998/03/19 13:16:24 keil - * fix the correct release of the hscx - * - * Revision 1.7 1998/02/12 23:07:36 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.6 1998/02/02 13:41:12 keil - * new init - * - * Revision 1.5 1997/11/06 17:09:34 keil - * New 2.1 init code - * - * Revision 1.4 1997/10/29 19:01:06 keil - * changes for 2.1 - * - * Revision 1.3 1997/07/27 21:38:34 keil - * new B-channel interface - * - * Revision 1.2 1997/06/26 11:16:17 keil - * first version - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "hscx.h" #include "isac.h" #include "isdnl1.h" #include -static char *HSCXVer[] HISAX_INITDATA = +static char *HSCXVer[] __initdata = {"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; -HISAX_INITFUNC(int -HscxVersion(struct IsdnCardState *cs, char *s)) +int __init +HscxVersion(struct IsdnCardState *cs, char *s) { int verA, verB; @@ -269,8 +219,8 @@ return (0); } -HISAX_INITFUNC(void -clear_pending_hscx_ints(struct IsdnCardState *cs)) +void __init +clear_pending_hscx_ints(struct IsdnCardState *cs) { int val, eval; @@ -295,8 +245,8 @@ cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF); } -HISAX_INITFUNC(void -inithscx(struct IsdnCardState *cs)) +void __init +inithscx(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_hscx; cs->bcs[1].BC_SetStack = setstack_hscx; @@ -312,8 +262,8 @@ modehscx(cs->bcs + 1, 0, 0); } -HISAX_INITFUNC(void -inithscxisac(struct IsdnCardState *cs, int part)) +void __init +inithscxisac(struct IsdnCardState *cs, int part) { if (part & 1) { clear_pending_isac_ints(cs); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hscx.h linux/drivers/isdn/hisax/hscx.h --- v2.2.18/drivers/isdn/hisax/hscx.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hscx.h Sun Mar 25 11:37:33 2001 @@ -1,23 +1,10 @@ -/* $Id: hscx.h,v 1.5 1999/12/23 15:09:32 keil Exp $ - +/* $Id: hscx.h,v 1.6 2000/06/26 08:59:13 keil Exp $ + * * hscx.h HSCX specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: hscx.h,v $ - * Revision 1.5 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.4 1998/04/15 16:45:34 keil - * new init code - * - * Revision 1.3 1997/07/27 21:38:35 keil - * new B-channel interface - * - * Revision 1.2 1997/06/26 11:16:18 keil - * first version - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/hscx_irq.c linux/drivers/isdn/hisax/hscx_irq.c --- v2.2.18/drivers/isdn/hisax/hscx_irq.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/hscx_irq.c Sun Mar 25 11:37:33 2001 @@ -1,50 +1,12 @@ -/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $ - +/* $Id: hscx_irq.c,v 1.16 2000/11/19 17:02:47 kai Exp $ + * * hscx_irq.c low level b-channel stuff for Siemens HSCX * * Author Karsten Keil (keil@isdn4linux.de) * * This is an include file for fast inline IRQ stuff * - * $Log: hscx_irq.c,v $ - * Revision 1.13 1999/10/14 20:25:28 keil - * add a statistic for error monitoring - * - * Revision 1.12 1999/07/01 08:11:42 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.11 1998/11/15 23:54:49 keil - * changes from 2.0 - * - * Revision 1.10 1998/08/13 23:36:35 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 1.9 1998/06/24 14:44:51 keil - * Fix recovery of TX IRQ loss - * - * Revision 1.8 1998/04/10 10:35:22 paul - * fixed (silly?) warnings from egcs on Alpha. - * - * Revision 1.7 1998/02/12 23:07:37 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.6 1997/10/29 19:01:07 keil - * changes for 2.1 - * - * Revision 1.5 1997/10/01 09:21:35 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.4 1997/08/15 17:48:02 keil - * cosmetic - * - * Revision 1.3 1997/07/27 21:38:36 keil - * new B-channel interface - * - * Revision 1.2 1997/06/26 11:16:19 keil - * first version - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/icc.c linux/drivers/isdn/hisax/icc.c --- v2.2.18/drivers/isdn/hisax/icc.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hisax/icc.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,686 @@ +// $Id: icc.c,v 1.5 2000/11/24 17:05:37 kai Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.6.25 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#define __NO_VERSION__ +#include +#include "hisax.h" +#include "icc.h" +// #include "arcofi.h" +#include "isdnl1.h" +#include + +#define DBUSY_TIMER_VALUE 80 +#define ARCOFI_USE 0 + +static char *ICCVer[] __initdata = +{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; + +void +ICCVersion(struct IsdnCardState *cs, char *s) +{ + int val; + + val = cs->readisac(cs, ICC_RBCH); + printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]); +} + +static void +ph_command(struct IsdnCardState *cs, unsigned int command) +{ + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_command %x", command); + cs->writeisac(cs, ICC_CIX0, (command << 2) | 3); +} + + +static void +icc_new_ph(struct IsdnCardState *cs) +{ + switch (cs->dc.icc.ph_state) { + case (ICC_IND_EI1): + ph_command(cs, ICC_CMD_DI); + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + case (ICC_IND_DC): + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); + break; + case (ICC_IND_DR): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + case (ICC_IND_PU): + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + case (ICC_IND_FJ): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + case (ICC_IND_AR): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + case (ICC_IND_AI): + l1_msg(cs, HW_INFO4 | INDICATION, NULL); + break; + default: + break; + } +} + +static void +icc_bh(struct IsdnCardState *cs) +{ + struct PStack *stptr; + + if (!cs) + return; + if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { + if (cs->debug) + debugl1(cs, "D-Channel Busy cleared"); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr = stptr->next; + } + } + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) + icc_new_ph(cs); + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) + DChannel_proc_rcv(cs); + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) + DChannel_proc_xmt(cs); +#if ARCOFI_USE + if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) + return; + if (test_and_clear_bit(D_RX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_RX_END, NULL); + if (test_and_clear_bit(D_TX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_TX_END, NULL); +#endif +} + +void +icc_empty_fifo(struct IsdnCardState *cs, int count) +{ + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_empty_fifo"); + + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_empty_fifo overrun %d", + cs->rcvidx + count); + cs->writeisac(cs, ICC_CMDR, 0x80); + cs->rcvidx = 0; + return; + } + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + save_flags(flags); + cli(); + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, 0x80); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +static void +icc_fill_fifo(struct IsdnCardState *cs) +{ + int count, more; + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_fill_fifo"); + + if (!cs->tx_skb) + return; + + count = cs->tx_skb->len; + if (count <= 0) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + save_flags(flags); + cli(); + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); + if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + debugl1(cs, "icc_fill_fifo dbusytimer running"); + del_timer(&cs->dbusytimer); + } + init_timer(&cs->dbusytimer); + cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&cs->dbusytimer); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +void +icc_sched_event(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + queue_task(&cs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +void +icc_interrupt(struct IsdnCardState *cs, u_char val) +{ + u_char exval, v1; + struct sk_buff *skb; + unsigned int count; + long flags; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC interrupt %x", val); + if (val & 0x80) { /* RME */ + exval = cs->readisac(cs, ICC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RDO"); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif + } + if (!(exval & 0x20)) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC CRC error"); +#ifdef ERROR_STATISTIC + cs->err_crc++; +#endif + } + cs->writeisac(cs, ICC_CMDR, 0x80); + } else { + count = cs->readisac(cs, ICC_RBCL) & 0x1f; + if (count == 0) + count = 32; + icc_empty_fifo(cs, count); + save_flags(flags); + cli(); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "HiSax: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } + restore_flags(flags); + } + cs->rcvidx = 0; + icc_sched_event(cs, D_RCVBUFREADY); + } + if (val & 0x40) { /* RPF */ + icc_empty_fifo(cs, 32); + } + if (val & 0x20) { /* RSC */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + icc_fill_fifo(cs); + goto afterXPR; + } else { + dev_kfree_skb(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else + icc_sched_event(cs, D_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + exval = cs->readisac(cs, ICC_CIR0); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR0 %02X", exval ); + if (exval & 2) { + cs->dc.icc.ph_state = (exval >> 2) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); + icc_sched_event(cs, D_L1STATECHANGE); + } + if (exval & 1) { + exval = cs->readisac(cs, ICC_CIR1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR1 %02X", exval ); + } + } + if (val & 0x02) { /* SIN */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = cs->readisac(cs, ICC_EXIR); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC EXIR %02x", exval); + if (exval & 0x80) { /* XMR */ + debugl1(cs, "ICC XMR"); + printk(KERN_WARNING "HiSax: ICC XMR\n"); + } + if (exval & 0x40) { /* XDU */ + debugl1(cs, "ICC XDU"); + printk(KERN_WARNING "HiSax: ICC XDU\n"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); + debugl1(cs, "ICC XDU no skb"); + } + } + if (exval & 0x04) { /* MOS */ + v1 = cs->readisac(cs, ICC_MOSR); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOSR %02x", v1); +#if ARCOFI_USE + if (v1 & 0x08) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR0; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR0; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + if (cs->dc.icc.mon_rxp == 1) { + cs->dc.icc.mocr |= 0x04; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + } + afterMONR0: + if (v1 & 0x80) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR1; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR1; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + cs->dc.icc.mocr |= 0x40; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + afterMONR1: + if (v1 & 0x04) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON0); + } + if (v1 & 0x40) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON1); + } + if (v1 & 0x02) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x08))) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + cs->writeisac(cs, ICC_MOX0, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX0: + if (v1 & 0x20) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x80))) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + cs->writeisac(cs, ICC_MOX1, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX1: +#endif + } + } +} + +static void +ICC_l1hw(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + int val; + + switch (pr) { + case (PH_DATA |REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + icc_fill_fifo(cs); + } + break; + case (PH_PULL |INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + icc_fill_fifo(cs); + break; + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (HW_RESET | REQUEST): + if ((cs->dc.icc.ph_state == ICC_IND_EI1) || + (cs->dc.icc.ph_state == ICC_IND_DR)) + ph_command(cs, ICC_CMD_DI); + else + ph_command(cs, ICC_CMD_RES); + break; + case (HW_ENABLE | REQUEST): + ph_command(cs, ICC_CMD_DI); + break; + case (HW_INFO1 | REQUEST): + ph_command(cs, ICC_CMD_AR); + break; + case (HW_INFO3 | REQUEST): + ph_command(cs, ICC_CMD_AI); + break; + case (HW_TESTLOOP | REQUEST): + val = 0; + if (1 & (long) arg) + val |= 0x0c; + if (2 & (long) arg) + val |= 0x3; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + if (!val) { + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + } else { + cs->writeisac(cs, ICC_SPCR, val); + cs->writeisac(cs, ICC_ADF1, 0xa); + } + } else { + /* IOM 2 Mode */ + cs->writeisac(cs, ICC_SPCR, val); + if (val) + cs->writeisac(cs, ICC_ADF1, 0x8); + else + cs->writeisac(cs, ICC_ADF1, 0x0); + } + break; + case (HW_DEACTIVATE | RESPONSE): + discard_queue(&cs->rq); + discard_queue(&cs->sq); + if (cs->tx_skb) { + dev_kfree_skb(cs->tx_skb); + cs->tx_skb = NULL; + } + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + break; + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_l1hw unknown %04x", pr); + break; + } +} + +void +setstack_icc(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = ICC_l1hw; +} + +void +DC_Close_icc(struct IsdnCardState *cs) { + if (cs->dc.icc.mon_rx) { + kfree(cs->dc.icc.mon_rx); + cs->dc.icc.mon_rx = NULL; + } + if (cs->dc.icc.mon_tx) { + kfree(cs->dc.icc.mon_tx); + cs->dc.icc.mon_tx = NULL; + } +} + +static void +dbusy_timer_handler(struct IsdnCardState *cs) +{ + struct PStack *stptr; + int rbch, star; + + if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + rbch = cs->readisac(cs, ICC_RBCH); + star = cs->readisac(cs, ICC_STAR); + if (cs->debug) + debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", + rbch, star); + if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */ + test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); + stptr = stptr->next; + } + } else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); + if (cs->tx_skb) { + dev_kfree_skb(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } else { + printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n"); + debugl1(cs, "D-Channel Busy no skb"); + } + cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ + cs->irq_func(cs->irq, cs, NULL); + } + } +} + +void __init +initicc(struct IsdnCardState *cs) +{ + cs->tqueue.routine = (void *) (void *) icc_bh; + cs->setstack_d = setstack_icc; + cs->DC_Close = DC_Close_icc; + cs->dc.icc.mon_tx = NULL; + cs->dc.icc.mon_rx = NULL; + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + cs->writeisac(cs, ICC_MASK, 0xff); + cs->dc.icc.mocr = 0xaa; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + cs->writeisac(cs, ICC_ADF2, 0x0); + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xc9); + } else { + /* IOM 2 Mode */ + if (!cs->dc.icc.adf2) + cs->dc.icc.adf2 = 0x80; + cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); + cs->writeisac(cs, ICC_SQXR, 0xa0); + cs->writeisac(cs, ICC_SPCR, 0x20); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xca); + cs->writeisac(cs, ICC_TIMR, 0x00); + cs->writeisac(cs, ICC_ADF1, 0x20); + } + ph_command(cs, ICC_CMD_RES); + cs->writeisac(cs, ICC_MASK, 0x0); + ph_command(cs, ICC_CMD_DI); +} + +void __init +clear_pending_icc_ints(struct IsdnCardState *cs) +{ + int val, eval; + + val = cs->readisac(cs, ICC_STAR); + debugl1(cs, "ICC STAR %x", val); + val = cs->readisac(cs, ICC_MODE); + debugl1(cs, "ICC MODE %x", val); + val = cs->readisac(cs, ICC_ADF2); + debugl1(cs, "ICC ADF2 %x", val); + val = cs->readisac(cs, ICC_ISTA); + debugl1(cs, "ICC ISTA %x", val); + if (val & 0x01) { + eval = cs->readisac(cs, ICC_EXIR); + debugl1(cs, "ICC EXIR %x", eval); + } + val = cs->readisac(cs, ICC_CIR0); + debugl1(cs, "ICC CIR0 %x", val); + cs->dc.icc.ph_state = (val >> 2) & 0xf; + icc_sched_event(cs, D_L1STATECHANGE); + /* Disable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0xFF); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/icc.h linux/drivers/isdn/hisax/icc.h --- v2.2.18/drivers/isdn/hisax/icc.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hisax/icc.h Sun Mar 25 11:37:33 2001 @@ -0,0 +1,73 @@ +// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.7.14 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + + +/* All Registers original Siemens Spec */ + +#define ICC_MASK 0x20 +#define ICC_ISTA 0x20 +#define ICC_STAR 0x21 +#define ICC_CMDR 0x21 +#define ICC_EXIR 0x24 +#define ICC_ADF2 0x39 +#define ICC_SPCR 0x30 +#define ICC_ADF1 0x38 +#define ICC_CIR0 0x31 +#define ICC_CIX0 0x31 +#define ICC_CIR1 0x33 +#define ICC_CIX1 0x33 +#define ICC_STCR 0x37 +#define ICC_MODE 0x22 +#define ICC_RSTA 0x27 +#define ICC_RBCL 0x25 +#define ICC_RBCH 0x2A +#define ICC_TIMR 0x23 +#define ICC_SQXR 0x3b +#define ICC_MOSR 0x3a +#define ICC_MOCR 0x3a +#define ICC_MOR0 0x32 +#define ICC_MOX0 0x32 +#define ICC_MOR1 0x34 +#define ICC_MOX1 0x34 + +#define ICC_RBCH_XAC 0x80 + +#define ICC_CMD_TIM 0x0 +#define ICC_CMD_RES 0x1 +#define ICC_CMD_DU 0x3 +#define ICC_CMD_EI1 0x4 +#define ICC_CMD_SSP 0x5 +#define ICC_CMD_DT 0x6 +#define ICC_CMD_AR 0x8 +#define ICC_CMD_ARL 0xA +#define ICC_CMD_AI 0xC +#define ICC_CMD_DI 0xF + +#define ICC_IND_DR 0x0 +#define ICC_IND_FJ 0x2 +#define ICC_IND_EI1 0x4 +#define ICC_IND_INT 0x6 +#define ICC_IND_PU 0x7 +#define ICC_IND_AR 0x8 +#define ICC_IND_ARL 0xA +#define ICC_IND_AI 0xC +#define ICC_IND_AIL 0xE +#define ICC_IND_DC 0xF + +extern void ICCVersion(struct IsdnCardState *cs, char *s); +extern void initicc(struct IsdnCardState *cs); +extern void icc_interrupt(struct IsdnCardState *cs, u_char val); +extern void clear_pending_icc_ints(struct IsdnCardState *cs); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/ipac.h linux/drivers/isdn/hisax/ipac.h --- v2.2.18/drivers/isdn/hisax/ipac.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/ipac.h Sun Mar 25 11:37:33 2001 @@ -1,24 +1,10 @@ -/* $Id: ipac.h,v 1.4 1999/12/23 15:09:32 keil Exp $ - +/* $Id: ipac.h,v 1.5 2000/06/26 08:59:13 keil Exp $ + * * ipac.h IPAC specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: ipac.h,v $ - * Revision 1.4 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.3 1998/04/15 16:48:09 keil - * IPAC_ATX added - * - * Revision 1.2 1997/10/29 18:51:21 keil - * New files - * - * Revision 1.1.2.1 1997/10/17 22:10:48 keil - * new files on 2.0 - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c --- v2.2.18/drivers/isdn/hisax/isac.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isac.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $ - +/* $Id: isac.c,v 1.28 2000/11/24 17:05:37 kai Exp $ + * * isac.c ISAC specific routines * * Author Karsten Keil (keil@isdn4linux.de) @@ -7,82 +7,6 @@ * This file is (c) under GNU PUBLIC LICENSE * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert - * - * $Log: isac.c,v $ - * Revision 1.24 1999/10/14 20:25:28 keil - * add a statistic for error monitoring - * - * Revision 1.23 1999/08/25 16:50:52 keil - * Fix bugs which cause 2.3.14 hangs (waitqueue init) - * - * Revision 1.22 1999/08/09 19:04:40 keil - * Fix race condition - Thanks to Christer Weinigel - * - * Revision 1.21 1999/07/12 21:05:17 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.20 1999/07/09 08:23:06 keil - * Fix ISAC lost TX IRQ handling - * - * Revision 1.19 1999/07/01 08:11:43 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.18 1998/11/15 23:54:51 keil - * changes from 2.0 - * - * Revision 1.17 1998/08/13 23:36:37 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 1.16 1998/05/25 12:58:01 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.15 1998/04/15 16:45:32 keil - * new init code - * - * Revision 1.14 1998/04/10 10:35:26 paul - * fixed (silly?) warnings from egcs on Alpha. - * - * Revision 1.13 1998/03/07 22:57:01 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 1.12 1998/02/12 23:07:40 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.11 1998/02/09 10:54:49 keil - * fixes for leased mode - * - * Revision 1.10 1998/02/02 13:37:37 keil - * new init - * - * Revision 1.9 1997/11/06 17:09:07 keil - * New 2.1 init code - * - * Revision 1.8 1997/10/29 19:00:03 keil - * new layer1,changes for 2.1 - * - * Revision 1.7 1997/10/01 09:21:37 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.6 1997/08/15 17:47:08 keil - * avoid oops because a uninitialised timer - * - * Revision 1.5 1997/08/07 17:48:49 keil - * fix wrong parenthesis - * - * Revision 1.4 1997/07/30 17:11:59 keil - * fixed Timer3 - * - * Revision 1.3 1997/07/27 21:37:40 keil - * T3 implemented; supervisor l1timer; B-channel TEST_LOOP - * - * Revision 1.2 1997/06/26 11:16:15 keil - * first version - * - * */ #define __NO_VERSION__ @@ -91,11 +15,12 @@ #include "arcofi.h" #include "isdnl1.h" #include +#include #define DBUSY_TIMER_VALUE 80 #define ARCOFI_USE 1 -static char *ISACVer[] HISAX_INITDATA = +static char *ISACVer[] = {"2086/2186 V1.1", "2085 B1", "2085 B2", "2085 V2.3"}; @@ -696,8 +621,8 @@ } } -HISAX_INITFUNC(void -initisac(struct IsdnCardState *cs)) +void +initisac(struct IsdnCardState *cs) { cs->tqueue.routine = (void *) (void *) isac_bh; cs->setstack_d = setstack_isac; @@ -732,8 +657,8 @@ cs->writeisac(cs, ISAC_MASK, 0x0); } -HISAX_INITFUNC(void -clear_pending_isac_ints(struct IsdnCardState *cs)) +void +clear_pending_isac_ints(struct IsdnCardState *cs) { int val, eval; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isac.h linux/drivers/isdn/hisax/isac.h --- v2.2.18/drivers/isdn/hisax/isac.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isac.h Sun Mar 25 11:37:33 2001 @@ -1,27 +1,10 @@ -/* $Id: isac.h,v 1.6 1999/12/23 15:09:32 keil Exp $ - +/* $Id: isac.h,v 1.7 2000/06/26 08:59:13 keil Exp $ + * * isac.h ISAC specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: isac.h,v $ - * Revision 1.6 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.5 1998/05/25 12:58:03 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.4 1997/10/29 19:09:34 keil - * new L1 - * - * Revision 1.3 1997/07/27 21:37:41 keil - * T3 implemented; supervisor l1timer; B-channel TEST_LOOP - * - * Revision 1.2 1997/06/26 11:16:16 keil - * first version - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.2.18/drivers/isdn/hisax/isar.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isar.c Sun Mar 25 11:37:33 2001 @@ -1,43 +1,15 @@ -/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $ - +/* $Id: isar.c,v 1.17 2000/11/24 17:05:37 kai Exp $ + * * isar.c ISAR (Siemens PSB 7110) specific routines * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: isar.c,v $ - * Revision 1.9 2000/01/20 19:47:45 keil - * Add Fax Class 1 support - * - * Revision 1.8 1999/12/19 13:00:56 keil - * Fix races in setting a new mode - * - * Revision 1.7 1999/10/14 20:25:29 keil - * add a statistic for error monitoring - * - * Revision 1.6 1999/08/31 11:20:20 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.5 1999/08/25 16:59:55 keil - * Make ISAR V32bis modem running - * Make LL->HL interface open for additional commands - * - * Revision 1.4 1999/08/05 20:43:18 keil - * ISAR analog modem support - * - * Revision 1.3 1999/07/01 08:11:45 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.2 1998/11/15 23:54:53 keil - * changes from 2.0 - * - * Revision 1.1 1998/08/13 23:33:47 keil - * First version, only init - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isar.h" #include "isdnl1.h" @@ -272,6 +244,14 @@ printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); goto reterror; } +#ifdef __BIG_ENDIAN + sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256; + blk_head.sadr = sadr; + sadr = (blk_head.len & 0xff)*256 + blk_head.len/256; + blk_head.len = sadr; + sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256; + blk_head.d_key = sadr; +#endif /* __BIG_ENDIAN */ cnt += BLK_HEAD_SIZE; p += BLK_HEAD_SIZE; printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", @@ -313,8 +293,13 @@ #endif sadr += noc; while(noc) { +#ifdef __BIG_ENDIAN + *mp++ = *sp % 256; + *mp++ = *sp / 256; +#else *mp++ = *sp / 256; *mp++ = *sp % 256; +#endif /* __BIG_ENDIAN */ sp++; noc--; } @@ -557,8 +542,9 @@ rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { @@ -567,6 +553,7 @@ skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); } + bcs->hw.isar.rcvidx = 0; } } break; @@ -635,13 +622,16 @@ bcs->hw.isar.rcvidx += ireg->clsb; rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { + int len = bcs->hw.isar.rcvidx + + dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { - memcpy(skb_put(skb, bcs->hw.isar.rcvidx), + insert_dle((u_char *)skb_put(skb, len), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); skb_queue_tail(&bcs->rqueue, skb); @@ -649,8 +639,20 @@ send_DLE_ETX(bcs); isar_sched_event(bcs, B_LL_OK); } + bcs->hw.isar.rcvidx = 0; } } + if (ireg->cmsb & SART_NMD) { /* ABORT */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: no more data"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + send_DLE_ETX(bcs); + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + bcs->hw.isar.state = STFAX_ESCAPE; + isar_sched_event(bcs, B_LL_NOCARRIER); + } break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); @@ -1073,6 +1075,9 @@ debugl1(cs, "pump stev RSP_DISC"); if (bcs->hw.isar.state == STFAX_ESCAPE) { switch(bcs->hw.isar.newcmd) { + case 0: + bcs->hw.isar.state = STFAX_READY; + break; case PCTRL_CMD_FTH: case PCTRL_CMD_FTM: p1 = 10; @@ -1082,13 +1087,14 @@ break; case PCTRL_CMD_FRH: case PCTRL_CMD_FRM: - p1 = bcs->hw.isar.newmod; + p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; bcs->hw.isar.newmod = 0; bcs->hw.isar.cmd = bcs->hw.isar.newcmd; bcs->hw.isar.newcmd = 0; sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, bcs->hw.isar.cmd, 1, &p1); bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.try_mod = 3; break; default: if (cs->debug & L1_DEB_HSCX) @@ -1114,13 +1120,14 @@ if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev RSP_SILDET"); if (bcs->hw.isar.state == STFAX_SILDET) { - p1 = bcs->hw.isar.newmod; + p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; bcs->hw.isar.newmod = 0; bcs->hw.isar.cmd = bcs->hw.isar.newcmd; bcs->hw.isar.newcmd = 0; sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, bcs->hw.isar.cmd, 1, &p1); bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.try_mod = 3; } break; case PSEV_RSP_SILOFF: @@ -1128,6 +1135,17 @@ debugl1(cs, "pump stev RSP_SILOFF"); break; case PSEV_RSP_FCERR: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_FCERR try %d", + bcs->hw.isar.try_mod); + if (bcs->hw.isar.try_mod--) { + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + bcs->hw.isar.cmd, 1, + &bcs->hw.isar.mod); + break; + } + } if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev RSP_FCERR"); bcs->hw.isar.state = STFAX_ESCAPE; @@ -1438,6 +1456,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FTM) && (bcs->hw.isar.mod == para)) { @@ -1460,6 +1479,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FTH) && (bcs->hw.isar.mod == para)) { @@ -1482,6 +1502,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FRM) && (bcs->hw.isar.mod == para)) { @@ -1504,6 +1525,7 @@ bcs->hw.isar.mod = para; bcs->hw.isar.newmod = 0; bcs->hw.isar.newcmd = 0; + bcs->hw.isar.try_mod = 3; } else if ((bcs->hw.isar.state == STFAX_ACTIV) && (bcs->hw.isar.cmd == PCTRL_CMD_FRH) && (bcs->hw.isar.mod == para)) { @@ -1761,8 +1783,8 @@ return(0); } -HISAX_INITFUNC(void -initisar(struct IsdnCardState *cs)) +void +initisar(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_isar; cs->bcs[1].BC_SetStack = setstack_isar; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h --- v2.2.18/drivers/isdn/hisax/isar.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isar.h Sun Mar 25 11:37:33 2001 @@ -1,32 +1,10 @@ -/* $Id: isar.h,v 1.7 2000/01/20 19:47:45 keil Exp $ +/* $Id: isar.h,v 1.9 2000/06/26 08:59:13 keil Exp $ + * * isar.h ISAR (Siemens PSB 7110) specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: isar.h,v $ - * Revision 1.7 2000/01/20 19:47:45 keil - * Add Fax Class 1 support - * - * Revision 1.6 1999/10/14 20:25:29 keil - * add a statistic for error monitoring - * - * Revision 1.5 1999/08/25 16:59:59 keil - * Make ISAR V32bis modem running - * Make LL->HL interface open for additional commands - * - * Revision 1.4 1999/08/05 20:43:20 keil - * ISAR analog modem support - * - * Revision 1.3 1999/07/01 08:11:46 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.2 1998/11/15 23:54:54 keil - * changes from 2.0 - * - * Revision 1.1 1998/08/13 23:33:48 keil - * First version, only init - * + * This file is (c) under GNU PUBLIC LICENSE * */ @@ -208,7 +186,7 @@ #define HDLC_ERROR 0x1c #define HDLC_ERR_FAD 0x10 #define HDLC_ERR_RER 0x08 -#define HDLC_ERR_CER 0x01 +#define HDLC_ERR_CER 0x04 #define SART_NMD 0x01 #define BSTAT_RDM0 0x1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c --- v2.2.18/drivers/isdn/hisax/isdnl1.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isdnl1.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: isdnl1.c,v 2.37 2000/01/20 19:51:46 keil Exp $ - +/* $Id: isdnl1.c,v 2.41.6.1 2000/12/10 22:01:04 kai Exp $ + * * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards * based on the teles driver from Jan den Ouden * @@ -13,150 +13,19 @@ * Fritz Elfert * Beat Doebeli * - * - * $Log: isdnl1.c,v $ - * Revision 2.37 2000/01/20 19:51:46 keil - * Fix AddTimer message - * Change CONFIG defines - * - * Revision 2.36 1999/08/25 16:50:57 keil - * Fix bugs which cause 2.3.14 hangs (waitqueue init) - * - * Revision 2.35 1999/08/22 20:27:07 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 2.34 1999/07/09 13:50:15 keil - * remove unused variable - * - * Revision 2.33 1999/07/09 13:34:33 keil - * remove debug code - * - * Revision 2.32 1999/07/01 08:11:47 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.31 1998/11/15 23:54:56 keil - * changes from 2.0 - * - * Revision 2.30 1998/09/30 22:27:00 keil - * Add init of l1.Flags - * - * Revision 2.29 1998/09/27 23:54:43 keil - * cosmetics - * - * Revision 2.28 1998/09/27 12:52:23 keil - * Fix against segfault, if the driver cannot allocate an IRQ channel - * - * Revision 2.27 1998/08/13 23:36:39 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.26 1998/07/15 15:01:31 calle - * Support for AVM passive PCMCIA cards: - * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 - * - * Revision 2.25 1998/05/25 14:10:09 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.24 1998/05/25 12:58:04 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.22 1998/04/15 16:40:13 keil - * Add S0Box and Teles PCI support - * Fix cardnr overwrite bug - * - * Revision 2.21 1998/04/10 10:35:28 paul - * fixed (silly?) warnings from egcs on Alpha. - * - * Revision 2.20 1998/03/09 23:19:27 keil - * Changes for PCMCIA - * - * Revision 2.18 1998/02/12 23:07:42 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 2.17 1998/02/11 17:28:07 keil - * Niccy PnP/PCI support - * - * Revision 2.16 1998/02/09 18:46:08 keil - * Support for Sedlbauer PCMCIA (Marcus Niemann) - * - * Revision 2.15 1998/02/09 10:54:51 keil - * fixes for leased mode - * - * Revision 2.14 1998/02/03 23:31:31 keil - * add AMD7930 support - * - * Revision 2.13 1998/02/02 13:33:02 keil - * New card support - * - * Revision 2.12 1998/01/31 21:41:48 keil - * changes for newer 2.1 kernels - * - * Revision 2.11 1997/11/12 15:01:23 keil - * COMPAQ_ISA changes - * - * Revision 2.10 1997/11/08 21:35:48 keil - * new l1 init - * - * Revision 2.9 1997/11/06 17:09:18 keil - * New 2.1 init code - * - * Revision 2.8 1997/10/29 19:00:05 keil - * new layer1,changes for 2.1 - * - * Revision 2.7 1997/10/10 20:56:50 fritz - * New HL interface. - * - * Revision 2.6 1997/09/12 10:05:16 keil - * ISDN_CTRL_DEBUG define - * - * Revision 2.5 1997/09/11 17:24:45 keil - * Add new cards - * - * Revision 2.4 1997/08/15 17:47:09 keil - * avoid oops because a uninitialised timer - * - * Revision 2.3 1997/08/01 11:16:40 keil - * cosmetics - * - * Revision 2.2 1997/07/30 17:11:08 keil - * L1deactivated exported - * - * Revision 2.1 1997/07/27 21:35:38 keil - * new layer1 interface - * - * Revision 2.0 1997/06/26 11:02:53 keil - * New Layer and card interface - * - * Revision 1.15 1997/05/27 15:17:55 fritz - * Added changes for recent 2.1.x kernels: - * changed return type of isdn_close - * queue_task_* -> queue_task - * clear/set_bit -> test_and_... where apropriate. - * changed type of hard_header_cache parameter. - * - * old changes removed KKe - * */ -const char *l1_revision = "$Revision: 2.37 $"; +const char *l1_revision = "$Revision: 2.41.6.1 $"; #define __NO_VERSION__ +#include #include "hisax.h" #include "isdnl1.h" #define TIMER3_VALUE 7000 -static -struct Fsm l1fsm_b = -{NULL, 0, 0, NULL, NULL}; - -static -struct Fsm l1fsm_d = -{NULL, 0, 0, NULL, NULL}; +static struct Fsm l1fsm_b; +static struct Fsm l1fsm_s; enum { ST_L1_F2, @@ -168,9 +37,9 @@ ST_L1_F8, }; -#define L1D_STATE_COUNT (ST_L1_F8+1) +#define L1S_STATE_COUNT (ST_L1_F8+1) -static char *strL1DState[] = +static char *strL1SState[] = { "ST_L1_F2", "ST_L1_F3", @@ -181,6 +50,29 @@ "ST_L1_F8", }; +#ifdef HISAX_UINTERFACE +static +struct Fsm l1fsm_u = +{NULL, 0, 0, NULL, NULL}; + +enum { + ST_L1_RESET, + ST_L1_DEACT, + ST_L1_SYNC2, + ST_L1_TRANS, +}; + +#define L1U_STATE_COUNT (ST_L1_TRANS+1) + +static char *strL1UState[] = +{ + "ST_L1_RESET", + "ST_L1_DEACT", + "ST_L1_SYNC2", + "ST_L1_TRANS", +}; +#endif + enum { ST_L1_NULL, ST_L1_WAIT_ACT, @@ -451,7 +343,6 @@ bcs->cs = cs; bcs->channel = bc; - bcs->tqueue.next = 0; bcs->tqueue.sync = 0; bcs->tqueue.routine = (void *) (void *) BChannel_bh; bcs->tqueue.data = bcs; @@ -559,7 +450,7 @@ } static void -l1_deact_req(struct FsmInst *fi, int event, void *arg) +l1_deact_req_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -569,7 +460,7 @@ } static void -l1_power_up(struct FsmInst *fi, int event, void *arg) +l1_power_up_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -599,7 +490,12 @@ { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F6); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_SYNC2); + else +#endif + FsmChangeState(fi, ST_L1_F6); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); } @@ -608,7 +504,12 @@ { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F7); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_TRANS); + else +#endif + FsmChangeState(fi, ST_L1_F7); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) FsmDelTimer(&st->l1.timer, 4); @@ -628,6 +529,10 @@ test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) L1deactivated(st->l1.hardware); + +#ifdef HISAX_UINTERFACE + if (!test_bit(FLG_L1_UINT, &st->l1.Flags)) +#endif if (st->l1.l1m.state != ST_L1_F6) { FsmChangeState(fi, ST_L1_F3); st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); @@ -656,7 +561,7 @@ } static void -l1_activate(struct FsmInst *fi, int event, void *arg) +l1_activate_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -674,9 +579,9 @@ } } -static struct FsmNode L1DFnList[] HISAX_INITDATA = +static struct FsmNode L1SFnList[] __initdata = { - {ST_L1_F3, EV_PH_ACTIVATE, l1_activate}, + {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F3, EV_RESET_IND, l1_reset}, @@ -691,10 +596,10 @@ {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F7, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F8, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F3, EV_POWER_UP, l1_power_up}, + {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, {ST_L1_F4, EV_RSYNC_IND, l1_go_F5}, {ST_L1_F6, EV_RSYNC_IND, l1_go_F8}, {ST_L1_F7, EV_RSYNC_IND, l1_go_F8}, @@ -722,7 +627,68 @@ {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode)) +#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) + +#ifdef HISAX_UINTERFACE +static void +l1_deact_req_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_RESET); + FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); + test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); +} + +static void +l1_power_up_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); +} + +static void +l1_info0_ind(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_DEACT); +} + +static void +l1_activate_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL); +} + +static struct FsmNode L1UFnList[] __initdata = +{ + {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u}, + {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u}, + {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind}, + {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_DEACT, EV_TIMER3, l1_timer3}, + {ST_L1_SYNC2, EV_TIMER3, l1_timer3}, + {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act}, + {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, +}; + +#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) + +#endif static void l1b_activate(struct FsmInst *fi, int event, void *arg) @@ -760,7 +726,7 @@ st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); } -static struct FsmNode L1BFnList[] HISAX_INITDATA = +static struct FsmNode L1BFnList[] __initdata = { {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate}, {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act}, @@ -770,13 +736,21 @@ #define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) -HISAX_INITFUNC(void Isdnl1New(void)) +void __init +Isdnl1New(void) { - l1fsm_d.state_count = L1D_STATE_COUNT; - l1fsm_d.event_count = L1_EVENT_COUNT; - l1fsm_d.strEvent = strL1Event; - l1fsm_d.strState = strL1DState; - FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT); +#ifdef HISAX_UINTERFACE + l1fsm_u.state_count = L1U_STATE_COUNT; + l1fsm_u.event_count = L1_EVENT_COUNT; + l1fsm_u.strEvent = strL1Event; + l1fsm_u.strState = strL1UState; + FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); +#endif + l1fsm_s.state_count = L1S_STATE_COUNT; + l1fsm_s.event_count = L1_EVENT_COUNT; + l1fsm_s.strEvent = strL1Event; + l1fsm_s.strState = strL1SState; + FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); l1fsm_b.state_count = L1B_STATE_COUNT; l1fsm_b.event_count = L1_EVENT_COUNT; l1fsm_b.strEvent = strL1Event; @@ -786,7 +760,10 @@ void Isdnl1Free(void) { - FsmFree(&l1fsm_d); +#ifdef HISAX_UINTERFACE + FsmFree(&l1fsm_u); +#endif + FsmFree(&l1fsm_s); FsmFree(&l1fsm_b); } @@ -804,7 +781,7 @@ case (PH_ACTIVATE | REQUEST): if (cs->debug) debugl1(cs, "PH_ACTIVATE_REQ %s", - strL1DState[st->l1.l1m.state]); + st->l1.l1m.fsm->strState[st->l1.l1m.state]); if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else { @@ -884,8 +861,16 @@ { st->l1.hardware = cs; st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm_d; + st->l1.l1m.fsm = &l1fsm_s; st->l1.l1m.state = ST_L1_F3; + st->l1.Flags = 0; +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) { + st->l1.l1m.fsm = &l1fsm_u; + st->l1.l1m.state = ST_L1_RESET; + st->l1.Flags = FLG_L1_UINT; + } +#endif st->l1.l1m.debug = cs->debug; st->l1.l1m.userdata = st; st->l1.l1m.userint = 0; @@ -895,7 +880,6 @@ setstack_manager(st); st->l1.stlistp = &(cs->stlist); st->l2.l2l1 = dch_l2l1; - st->l1.Flags = 0; cs->setstack_d(st, cs); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h --- v2.2.18/drivers/isdn/hisax/isdnl1.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isdnl1.h Sun Mar 25 11:37:33 2001 @@ -1,34 +1,8 @@ -/* $Id: isdnl1.h,v 2.8 1998/11/15 23:54:59 keil Exp $ - - * $Log: isdnl1.h,v $ - * Revision 2.8 1998/11/15 23:54:59 keil - * changes from 2.0 +/* $Id: isdnl1.h,v 2.9 2000/06/26 08:59:13 keil Exp $ * - * Revision 2.7 1998/09/30 22:21:55 keil - * cosmetics - * - * Revision 2.6 1998/05/25 12:58:06 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.5 1998/02/02 13:36:58 keil - * more debug - * - * Revision 2.4 1997/11/08 21:35:49 keil - * new l1 init - * - * Revision 2.3 1997/10/29 19:07:53 keil - * changes for 2.1 - * - * Revision 2.2 1997/07/30 17:11:09 keil - * L1deactivated exported - * - * Revision 2.1 1997/07/27 21:43:58 keil - * new l1 interface - * - * Revision 2.0 1997/06/26 11:02:55 keil - * New Layer and card interface + * Layer 1 defines * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c --- v2.2.18/drivers/isdn/hisax/isdnl2.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isdnl2.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: isdnl2.c,v 2.20 1999/08/25 16:52:04 keil Exp $ - +/* $Id: isdnl2.c,v 2.25 2000/11/24 17:05:38 kai Exp $ + * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * @@ -10,86 +10,17 @@ * Thanks to Jan den Ouden * Fritz Elfert * - * $Log: isdnl2.c,v $ - * Revision 2.20 1999/08/25 16:52:04 keil - * Make gcc on AXP happy - * - * Revision 2.19 1999/08/05 20:40:26 keil - * Fix interlayer communication - * - * Revision 2.18 1999/07/21 14:46:16 keil - * changes from EICON certification - * - * Revision 2.17 1999/07/01 08:11:50 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.16 1998/11/15 23:55:01 keil - * changes from 2.0 - * - * Revision 2.15 1998/08/13 23:36:42 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.14 1998/06/19 15:19:18 keil - * fix LAPB tx_cnt for none I-frames - * - * Revision 2.13 1998/06/18 23:17:20 keil - * LAPB bugfix - * - * Revision 2.12 1998/05/25 14:10:12 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.11 1998/05/25 12:58:08 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.9 1998/04/10 10:35:30 paul - * fixed (silly?) warnings from egcs on Alpha. - * - * Revision 2.8 1998/03/07 22:57:04 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 2.7 1998/02/12 23:07:47 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 2.6 1998/02/02 13:36:15 keil - * bugfix X.75 win calculation - * - * Revision 2.5 1997/11/06 17:09:22 keil - * New 2.1 init code - * - * Revision 2.4 1997/10/29 19:02:01 keil - * new LL interface - * - * Revision 2.3 1997/10/01 09:21:39 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 2.2 1997/07/31 11:49:05 keil - * Error handling for no TEI assign - * - * Revision 2.1 1997/07/27 21:34:38 keil - * cosmetics - * - * Revision 2.0 1997/06/26 11:07:29 keil - * New q.921 and X.75 Layer2 - * - * - * Old log removed KKe - * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.20 $"; +const char *l2_revision = "$Revision: 2.25 $"; static void l2m_debug(struct FsmInst *fi, char *fmt, ...); -static -struct Fsm l2fsm = -{NULL, 0, 0, NULL, NULL}; +static struct Fsm l2fsm; enum { ST_L2_1, @@ -361,7 +292,7 @@ int iframe_error(struct PStack *st, struct sk_buff *skb) { - int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 1 : 0); + int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1); int rsp = *skb->data & 0x2; if (test_bit(FLG_ORIG, &st->l2.flag)) @@ -371,7 +302,7 @@ return 'L'; - if (skb->len <= i) + if (skb->len < i) return 'N'; if ((skb->len - i) > st->l2.maxlen) @@ -1603,7 +1534,7 @@ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } -static struct FsmNode L2FnList[] HISAX_INITDATA = +static struct FsmNode L2FnList[] __initdata = { {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, @@ -1900,8 +1831,8 @@ { } -HISAX_INITFUNC(void -Isdnl2New(void)) +void __init +Isdnl2New(void) { l2fsm.state_count = L2_STATE_COUNT; l2fsm.event_count = L2_EVENT_COUNT; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h --- v2.2.18/drivers/isdn/hisax/isdnl2.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isdnl2.h Sun Mar 25 11:37:33 2001 @@ -1,4 +1,10 @@ -/* isdnl2.h */ +/* $Id: isdnl2.h,v 1.3 2000/06/26 08:59:13 keil Exp $ + * + * Layer 2 defines + * + * This file is (c) under GNU PUBLIC LICENSE + * + */ #define RR 0x01 #define RNR 0x05 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c --- v2.2.18/drivers/isdn/hisax/isdnl3.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isdnl3.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: isdnl3.c,v 2.10 1999/07/21 14:46:19 keil Exp $ - +/* $Id: isdnl3.c,v 2.17.6.1 2001/01/08 17:09:20 kai Exp $ + * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * @@ -10,69 +10,17 @@ * Thanks to Jan den Ouden * Fritz Elfert * - * $Log: isdnl3.c,v $ - * Revision 2.10 1999/07/21 14:46:19 keil - * changes from EICON certification - * - * Revision 2.9 1999/07/01 08:11:53 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.8 1998/11/15 23:55:04 keil - * changes from 2.0 - * - * Revision 2.7 1998/05/25 14:10:15 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.6 1998/05/25 12:58:11 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.5 1998/02/12 23:07:52 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 2.4 1997/11/06 17:09:25 keil - * New 2.1 init code - * - * Revision 2.3 1997/10/29 19:07:53 keil - * changes for 2.1 - * - * Revision 2.2 1997/10/01 09:21:41 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 2.1 1997/08/03 14:36:32 keil - * Implement RESTART procedure - * - * Revision 2.0 1997/07/27 21:15:42 keil - * New Callref based layer3 - * - * Revision 1.11 1997/06/26 11:11:44 keil - * SET_SKBFREE now on creation of a SKB - * - * Revision 1.10 1997/04/06 22:54:16 keil - * Using SKB's - * - * Revision 1.9 1997/03/25 23:11:25 keil - * US NI-1 protocol - * - * Revision 1.8 1997/03/21 18:53:44 keil - * Report no protocol error to syslog too - * - * Remove old logs /KKe - * */ + #define __NO_VERSION__ +#include #include "hisax.h" #include "isdnl3.h" #include -const char *l3_revision = "$Revision: 2.10 $"; +const char *l3_revision = "$Revision: 2.17.6.1 $"; -static -struct Fsm l3fsm = -{NULL, 0, 0, NULL, NULL}; +static struct Fsm l3fsm; enum { ST_L3_LC_REL, @@ -234,7 +182,7 @@ L3AddTimer(struct L3Timer *t, int millisec, int event) { - if (t->tl.next || t->tl.prev) { + if (timer_pending(&t->tl)) { printk(KERN_WARNING "L3AddTimer: timer already active!\n"); return -1; } @@ -286,7 +234,7 @@ extern void setstack_dss1(struct PStack *st); #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 extern void setstack_ni1(struct PStack *st); #endif @@ -355,7 +303,10 @@ if (!skb_queue_len(&p->st->l3.squeue)) { if (p->debug) l3_debug(p->st, "release_l3_process: release link"); - FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL); + if (p->st->protocol != ISDN_PTYPE_NI1) + FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL); + else + FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL); } else { if (p->debug) l3_debug(p->st, "release_l3_process: not release link"); @@ -375,10 +326,13 @@ l3ml3p(struct PStack *st, int pr) { struct l3_process *p = st->l3.proc; + struct l3_process *np; while (p) { + /* p might be kfreed under us, so we need to save where we want to go on */ + np = p->next; st->l3.l3ml3(st, pr, p); - p = p->next; + p = np; } } @@ -405,7 +359,7 @@ setstack_dss1(st); } else #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 if (st->protocol == ISDN_PTYPE_NI1) { setstack_ni1(st); } else @@ -532,6 +486,18 @@ } static void +lc_start_delay_check(struct FsmInst *fi, int event, void *arg) +/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */ +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L3_LC_REL_DELAY); + /* 19/09/00 - GE timer not user for NI-1 */ + if (st->protocol != ISDN_PTYPE_NI1) + FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); +} + +static void lc_release_req(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -570,7 +536,7 @@ /* *INDENT-OFF* */ -static struct FsmNode L3FnList[] HISAX_INITDATA = +static struct FsmNode L3FnList[] __initdata = { {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate}, {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect}, @@ -579,7 +545,7 @@ {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay}, {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind}, {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind}, - {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay}, + {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check}, {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind}, {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected}, {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req}, @@ -593,7 +559,6 @@ void l3_msg(struct PStack *st, int pr, void *arg) { - switch (pr) { case (DL_DATA | REQUEST): if (st->l3.l3m.state == ST_L3_LC_ESTAB) { @@ -601,7 +566,7 @@ } else { struct sk_buff *skb = arg; - skb_queue_head(&st->l3.squeue, skb); + skb_queue_tail(&st->l3.squeue, skb); FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); } break; @@ -626,8 +591,8 @@ } } -HISAX_INITFUNC(void -Isdnl3New(void)) +void __init +Isdnl3New(void) { l3fsm.state_count = L3_STATE_COUNT; l3fsm.event_count = L3_EVENT_COUNT; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h --- v2.2.18/drivers/isdn/hisax/isdnl3.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isdnl3.h Sun Mar 25 11:37:33 2001 @@ -1,38 +1,6 @@ -/* $Id: isdnl3.h,v 2.5 1999/07/25 16:18:32 keil Exp $ - - * $Log: isdnl3.h,v $ - * Revision 2.5 1999/07/25 16:18:32 keil - * Fix Suspend/Resume - * - * Revision 2.4 1999/07/01 08:11:54 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.3 1998/11/15 23:55:06 keil - * changes from 2.0 - * - * Revision 2.2 1998/05/25 14:10:17 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.1 1998/05/25 12:58:13 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.0 1997/07/27 21:15:42 keil - * New Callref based layer3 - * - * Revision 1.4 1997/06/26 11:20:57 keil - * ? - * - * Revision 1.3 1997/04/06 22:54:17 keil - * Using SKB's - * - * Revision 1.2 1997/01/21 22:31:28 keil - * new statemachine; L3 timers - * - * Revision 1.1 1996/10/13 20:03:47 keil - * Initial revision +/* $Id: isdnl3.h,v 2.6 2000/06/26 08:59:13 keil Exp $ * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c --- v2.2.18/drivers/isdn/hisax/isurf.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/isurf.c Sun Mar 25 11:37:33 2001 @@ -1,42 +1,15 @@ -/* $Id: isurf.c,v 1.8 1999/12/19 13:09:42 keil Exp $ - +/* $Id: isurf.c,v 1.10 2000/11/24 17:05:38 kai Exp $ + * * isurf.c low level stuff for Siemens I-Surf/I-Talk cards * * Author Karsten Keil (keil@isdn4linux.de) * - * $Log: isurf.c,v $ - * Revision 1.8 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.7 1999/11/14 23:37:03 keil - * new ISA memory mapped IO - * - * Revision 1.6 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.5 1999/08/25 17:00:02 keil - * Make ISAR V32bis modem running - * Make LL->HL interface open for additional commands - * - * Revision 1.4 1999/08/22 20:27:09 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.3 1999/07/12 21:05:18 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.2 1999/07/01 08:07:56 keil - * Initial version - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "isar.h" @@ -44,7 +17,7 @@ extern const char *CardType[]; -static const char *ISurf_revision = "$Revision: 1.8 $"; +static const char *ISurf_revision = "$Revision: 1.10 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -164,10 +137,10 @@ byteout(cs->hw.isurf.reset, chips); /* Reset On */ save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } @@ -216,8 +189,8 @@ return(isar_auxcmd(cs, ic)); } -__initfunc(int -setup_isurf(struct IsdnCard *card)) +int __init +setup_isurf(struct IsdnCard *card) { int ver; struct IsdnCardState *cs = card->cs; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c --- v2.2.18/drivers/isdn/hisax/ix1_micro.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/ix1_micro.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: ix1_micro.c,v 2.8 1999/07/12 21:05:19 keil Exp $ - +/* $Id: ix1_micro.c,v 2.10 2000/11/24 17:05:38 kai Exp $ + * * ix1_micro.c low level stuff for ITK ix1-micro Rev.2 isdn cards * derived from the original file teles3.c from Karsten Keil * @@ -10,45 +10,6 @@ * Fritz Elfert * Beat Doebeli * - * $Log: ix1_micro.c,v $ - * Revision 2.8 1999/07/12 21:05:19 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.7 1998/04/15 16:44:31 keil - * new init code - * - * Revision 2.6 1998/02/11 17:28:09 keil - * Niccy PnP/PCI support - * - * Revision 2.5 1998/02/02 13:29:42 keil - * fast io - * - * Revision 2.4 1997/11/08 21:35:50 keil - * new l1 init - * - * Revision 2.3 1997/11/06 17:09:35 keil - * New 2.1 init code - * - * Revision 2.2 1997/10/29 18:55:51 keil - * changes for 2.1.60 (irq2dev_map) - * - * Revision 2.1 1997/07/27 21:47:09 keil - * new interface structures - * - * Revision 2.0 1997/06/26 11:02:50 keil - * New Layer and card interface - * - * Revision 1.3 1997/04/13 19:54:02 keil - * Change in IRQ check delay for SMP - * - * Revision 1.2 1997/04/06 22:54:21 keil - * Using SKB's - * - * Revision 1.1 1997/01/27 15:43:10 keil - * first version - * - * */ /* @@ -82,13 +43,14 @@ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -const char *ix1_revision = "$Revision: 2.8 $"; +const char *ix1_revision = "$Revision: 2.10 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -282,8 +244,8 @@ } -__initfunc(int -setup_ix1micro(struct IsdnCard *card)) +int __init +setup_ix1micro(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c --- v2.2.18/drivers/isdn/hisax/jade.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/jade.c Sun Mar 25 11:37:33 2001 @@ -1,18 +1,16 @@ -/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $ +/* $Id: jade.c,v 1.6 2000/11/24 17:05:38 kai Exp $ * * jade.c JADE stuff (derived from original hscx.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * $Log: jade.c,v $ - * Revision 1.2 1999/07/01 08:07:57 keil - * Initial version - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "hscx.h" #include "jade.h" @@ -20,8 +18,8 @@ #include -HISAX_INITFUNC(int -JadeVersion(struct IsdnCardState *cs, char *s)) +int __init +JadeVersion(struct IsdnCardState *cs, char *s) { int ver,i; int to = 50; @@ -265,8 +263,8 @@ return (0); } -HISAX_INITFUNC(void -clear_pending_jade_ints(struct IsdnCardState *cs)) +void __init +clear_pending_jade_ints(struct IsdnCardState *cs) { int val; char tmp[64]; @@ -291,8 +289,8 @@ cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8); } -HISAX_INITFUNC(void -initjade(struct IsdnCardState *cs)) +void __init +initjade(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_jade; cs->bcs[1].BC_SetStack = setstack_jade; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/jade.h linux/drivers/isdn/hisax/jade.h --- v2.2.18/drivers/isdn/hisax/jade.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/jade.h Sun Mar 25 11:37:33 2001 @@ -1,13 +1,9 @@ -/* $Id: jade.h,v 1.2 1999/07/01 08:07:58 keil Exp $ +/* $Id: jade.h,v 1.3 2000/06/26 08:59:14 keil Exp $ * jade.h JADE specific defines * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * - * $Log: jade.h,v $ - * Revision 1.2 1999/07/01 08:07:58 keil - * Initial version - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/jade_irq.c linux/drivers/isdn/hisax/jade_irq.c --- v2.2.18/drivers/isdn/hisax/jade_irq.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/jade_irq.c Sun Mar 25 11:37:33 2001 @@ -1,13 +1,10 @@ -/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $ +/* $Id: jade_irq.c,v 1.5 2000/11/19 17:02:48 kai Exp $ * * jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * $Log: jade_irq.c,v $ - * Revision 1.2 1999/07/01 08:07:59 keil - * Initial version - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c --- v2.2.18/drivers/isdn/hisax/l3_1tr6.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/l3_1tr6.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: l3_1tr6.c,v 2.10 2000/01/20 19:42:01 keil Exp $ - +/* $Id: l3_1tr6.c,v 2.13 2000/11/19 17:02:48 kai Exp $ + * * German 1TR6 D-channel protocol * * Author Karsten Keil (keil@isdn4linux.de) @@ -8,51 +8,6 @@ * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * - * - * $Log: l3_1tr6.c,v $ - * Revision 2.10 2000/01/20 19:42:01 keil - * Fixed uninitialiesed location - * - * Revision 2.9 1999/07/01 08:11:55 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.8 1998/11/15 23:55:08 keil - * changes from 2.0 - * - * Revision 2.7 1998/08/13 23:36:45 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.6 1998/05/25 14:10:18 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.5 1998/05/25 12:58:14 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.4 1998/02/12 23:07:57 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 2.3 1997/11/06 17:12:24 keil - * KERN_NOTICE --> KERN_INFO - * - * Revision 2.2 1997/10/29 19:03:00 keil - * changes for 2.1 - * - * Revision 2.1 1997/08/03 15:28:09 keil - * release L3 empty processes - * - * Revision 2.0 1997/07/27 21:15:45 keil - * New Callref based layer3 - * - * Revision 1.12 1997/06/26 11:11:45 keil - * SET_SKBFREE now on creation of a SKB - * - * Revision 1.11 1997/04/06 22:54:18 keil - * Using SKB's - * - * Old Log removed /KKe - * */ #define __NO_VERSION__ @@ -62,7 +17,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.10 $"; +const char *l3_1tr6_revision = "$Revision: 2.13 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -928,7 +883,7 @@ } else { proc->chan = chan; chan->proc = proc; - proc->para.setup = chan->setup; + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/l3_1tr6.h linux/drivers/isdn/hisax/l3_1tr6.h --- v2.2.18/drivers/isdn/hisax/l3_1tr6.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/l3_1tr6.h Sun Mar 25 11:37:33 2001 @@ -1,16 +1,8 @@ -/* $Id: l3_1tr6.h,v 2.1 1998/08/13 23:36:48 keil Exp $ +/* $Id: l3_1tr6.h,v 2.2 2000/06/26 08:59:14 keil Exp $ * * German 1TR6 D-channel protocol defines * - * $Log: l3_1tr6.h,v $ - * Revision 2.1 1998/08/13 23:36:48 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.0 1997/07/27 21:15:47 keil - * New Callref based layer3 - * - * Revision 1.1 1996/10/13 20:03:48 keil - * Initial revision + * This file is (c) under GNU PUBLIC LICENSE * */ #ifndef l3_1tr6 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.2.18/drivers/isdn/hisax/l3dss1.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/l3dss1.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $ - +/* $Id: l3dss1.c,v 2.30 2000/11/19 17:02:48 kai Exp $ + * * EURO/DSS1 D-channel protocol * * Author Karsten Keil (keil@isdn4linux.de) @@ -12,91 +12,6 @@ * Thanks to Jan den Ouden * Fritz Elfert * - * $Log: l3dss1.c,v $ - * Revision 2.23 2000/02/26 01:38:14 keil - * Fixes for V.110 encoding LLC from Jens Jakobsen - * - * Revision 2.22 2000/01/20 19:44:20 keil - * Fixed uninitialiesed location - * Fixed redirecting number IE in Setup - * Changes from certification - * option for disabling use of KEYPAD protocol - * - * Revision 2.21 1999/12/19 20:25:17 keil - * fixed LLC for outgoing analog calls - * IE Signal is valid on older local switches - * - * Revision 2.20 1999/10/11 22:16:27 keil - * Suspend/Resume is possible without explicit ID too - * - * Revision 2.19 1999/08/25 16:55:23 keil - * Fix for test case TC10011 - * - * Revision 2.18 1999/08/11 20:54:39 keil - * High layer compatibility is valid in SETUP - * - * Revision 2.17 1999/07/25 16:18:25 keil - * Fix Suspend/Resume - * - * Revision 2.16 1999/07/21 14:46:23 keil - * changes from EICON certification - * - * Revision 2.14 1999/07/09 08:30:08 keil - * cosmetics - * - * Revision 2.13 1999/07/01 08:11:58 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.12 1998/11/15 23:55:10 keil - * changes from 2.0 - * - * Revision 2.11 1998/08/13 23:36:51 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 2.10 1998/05/25 14:10:20 keil - * HiSax 3.0 - * X.75 and leased are working again. - * - * Revision 2.9 1998/05/25 12:58:17 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.8 1998/03/19 13:18:47 keil - * Start of a CAPI like interface for supplementary Service - * first service: SUSPEND - * - * Revision 2.7 1998/02/12 23:08:01 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 2.6 1998/02/03 23:26:35 keil - * V110 extensions from Thomas Pfeiffer - * - * Revision 2.5 1998/02/02 13:34:28 keil - * Support australian Microlink net and german AOCD - * - * Revision 2.4 1997/11/06 17:12:25 keil - * KERN_NOTICE --> KERN_INFO - * - * Revision 2.3 1997/10/29 19:03:01 keil - * changes for 2.1 - * - * Revision 2.2 1997/08/07 17:44:36 keil - * Fix RESTART - * - * Revision 2.1 1997/08/03 14:36:33 keil - * Implement RESTART procedure - * - * Revision 2.0 1997/07/27 21:15:43 keil - * New Callref based layer3 - * - * Revision 1.17 1997/06/26 11:11:46 keil - * SET_SKBFREE now on creation of a SKB - * - * Revision 1.15 1997/04/17 11:50:48 keil - * pa->loc was undefined, if it was not send by the exchange - * - * Old log removed /KKe - * */ #define __NO_VERSION__ @@ -107,7 +22,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.23 $"; +const char *dss1_revision = "$Revision: 2.30 $"; #define EXT_BEARER_CAPS 1 @@ -806,6 +721,9 @@ u_char *p, ie; int l, newpos, oldpos; int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; p = skb->data; /* skip cr */ @@ -814,20 +732,34 @@ p += l; mt = *p++; oldpos = 0; -/* shift codeset procedure not implemented in the moment */ while ((p - skb->data) < skb->len) { - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; else - oldpos = newpos; + err_ureg++; } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; } ie = *p++; if (ie & 0x80) { @@ -837,12 +769,19 @@ p += l; l += 2; } - if (l > getmax_ie_len(ie)) + if (!codeset && (l > getmax_ie_len(ie))) err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } } if (err_compr | err_ureg | err_len | err_seq) { if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d", + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", mt, err_compr, err_ureg, err_len, err_seq); if (err_compr) return(ERR_IE_COMPREHENSION); @@ -1044,7 +983,7 @@ #if EXT_BEARER_CAPS -u_char * +static u_char * EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb @@ -1109,7 +1048,7 @@ return p + 3; } -u_char +static u_char EncodeSyncParams(u_char si2, u_char ai) { @@ -1313,39 +1252,31 @@ /* * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 */ - if (!send_keypad) - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = 0x4; /* BC-IE-code */ - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = 0x4; /* BC-IE-code */ - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - else { *p++ = 0x4; /* assumptions for bearer services with keypad */ - *p++ = 0x3; - *p++ = 0x80; - *p++ = 0x90; - *p++ = 0xa3; - *p++ = 0x18; /* no specific channel */ - *p++ = 0x01; - *p++ = 0x83; - *p++ = 0x2C; /* IE keypad */ + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_BEARER; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_BEARER; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + + if (send_keypad) { + *p++ = IE_KEYPAD; *p++ = strlen(teln); while (*teln) - *p++ = (*teln++) & 0x7F; - } + *p++ = (*teln++) & 0x7F; + } - /* * What about info2? Mapping to High-Layer-Compatibility? */ @@ -1394,7 +1325,7 @@ sp++; } if (*msn) { - *p++ = 0x6c; + *p++ = IE_CALLING_PN; *p++ = strlen(msn) + (screen ? 2 : 1); /* Classify as AnyPref. */ if (screen) { @@ -1407,7 +1338,7 @@ } if (sub) { *sub++ = '.'; - *p++ = 0x6d; /* Calling party subaddress */ + *p++ = IE_CALLING_SUB; *p++ = strlen(sub) + 2; *p++ = 0x80; /* NSAP coded */ *p++ = 0x50; /* local IDI format */ @@ -1425,33 +1356,27 @@ } if (!send_keypad) { - *p++ = 0x70; - *p++ = strlen(teln) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - if (sub) { - *sub++ = '.'; - *p++ = 0x71; /* Called party subaddress */ - *p++ = strlen(sub) + 2; - *p++ = 0x80; /* NSAP coded */ - *p++ = 0x50; /* local IDI format */ - while (*sub) - *p++ = *sub++ & 0x7f; - } + *p++ = IE_CALLED_PN; + *p++ = strlen(teln) + 1; + /* Classify as AnyPref. */ + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + while (*teln) + *p++ = *teln++ & 0x7f; + + if (sub) { + *sub++ = '.'; + *p++ = IE_CALLED_SUB; + *p++ = strlen(sub) + 2; + *p++ = 0x80; /* NSAP coded */ + *p++ = 0x50; /* local IDI format */ + while (*sub) + *p++ = *sub++ & 0x7f; + } } #if EXT_BEARER_CAPS - if (send_keypad) { /* special handling independant of si2 */ - *p++ = 0x7c; - *p++ = 0x03; - *p++ = 0x80; - *p++ = 0x90; - *p++ = 0xa3; - } else if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 - *p++ = 0x7c; + *p++ = IE_LLC; *p++ = 0x04; *p++ = 0x88; *p++ = 0x90; @@ -1459,7 +1384,7 @@ *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 - *p++ = 0x7c; + *p++ = IE_LLC; *p++ = 0x05; *p++ = 0x88; *p++ = 0x90; @@ -1468,7 +1393,7 @@ *p++ = 0x82; } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 - *p++ = 0x7c; + *p++ = IE_LLC; *p++ = 0x06; *p++ = 0x88; *p++ = 0x90; @@ -1477,18 +1402,18 @@ #ifndef CONFIG_HISAX_NO_LLC } else { switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = 0x7c; /* BC-IE-code */ - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ + case 1: /* Telephony */ + *p++ = IE_LLC; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ default: - *p++ = 0x7c; /* BC-IE-code */ - *p++ = 0x2; /* Length */ + *p++ = IE_LLC; + *p++ = 0x2; /* Length */ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ *p++ = 0x90; /* Circuit-Mode 64kbps */ break; @@ -1988,6 +1913,16 @@ pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); } +static void +l3dss1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + /********************************************/ /* deliver a incoming display message to HL */ /********************************************/ @@ -2025,7 +1960,7 @@ if (p[1] != 2) { err = 1; pc->para.cause = 100; - } else if (p[2] & 0x60) { + } else if (!(p[2] & 0x70)) { switch (p[2]) { case 0x80: case 0x81: @@ -2129,9 +2064,22 @@ { int ret; struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; ret = check_infoelements(pc, skb, ie_INFORMATION); - l3dss1_std_ie_err(pc, ret); + if (ret) + l3dss1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } } /******************************/ @@ -2357,6 +2305,16 @@ } static void +l3dss1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3dss1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { @@ -2375,6 +2333,7 @@ l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2414,6 +2373,7 @@ l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2423,6 +2383,7 @@ l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); @@ -2812,32 +2773,36 @@ CC_SETUP | REQUEST, l3dss1_setup_req}, {SBIT(0), CC_RESUME | REQUEST, l3dss1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(12), CC_RELEASE | REQUEST, l3dss1_release_req}, {ALL_STATES, CC_RESTART | REQUEST, l3dss1_restart}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_IGNORE | REQUEST, l3dss1_reset}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_REJECT | REQUEST, l3dss1_reject_req}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(6) | SBIT(9), + {SBIT(6), + CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3dss1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), CC_ALERTING | REQUEST, l3dss1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9), + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), CC_SETUP | RESPONSE, l3dss1_setup_rsp}, {SBIT(10), CC_SUSPEND | REQUEST, l3dss1_suspend_req}, - {SBIT(6), - CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(7) | SBIT(9), + {SBIT(7) | SBIT(9) | SBIT(25), CC_REDIR | REQUEST, l3dss1_redir_req}, {SBIT(6), CC_REDIR | REQUEST, l3dss1_redir_req_early}, {SBIT(9) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, + {SBIT(25), + CC_T302, l3dss1_t302}, {SBIT(1), CC_T303, l3dss1_t303}, {SBIT(2), @@ -3180,7 +3145,7 @@ if ((proc = dss1_new_l3_process(st, cr))) { proc->chan = chan; chan->proc = proc; - proc->para.setup = chan->setup; + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/l3dss1.h linux/drivers/isdn/hisax/l3dss1.h --- v2.2.18/drivers/isdn/hisax/l3dss1.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/l3dss1.h Sun Mar 25 11:37:33 2001 @@ -1,39 +1,14 @@ -/* $Id: l3dss1.h,v 1.8 2000/01/20 19:46:15 keil Exp $ +/* $Id: l3dss1.h,v 1.10 2000/06/26 08:59:14 keil Exp $ * * DSS1 (Euro) D-channel protocol defines * - * $Log: l3dss1.h,v $ - * Revision 1.8 2000/01/20 19:46:15 keil - * Changes from certification - * - * Revision 1.7 1999/07/01 08:12:02 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.6 1998/03/19 13:18:50 keil - * Start of a CAPI like interface for supplementary Service - * first service: SUSPEND - * - * Revision 1.5 1998/02/02 13:34:30 keil - * Support australian Microlink net and german AOCD - * - * Revision 1.4 1997/10/29 19:07:54 keil - * changes for 2.1 - * - * Revision 1.3 1997/08/07 17:44:37 keil - * Fix RESTART - * - * Revision 1.2 1997/08/03 14:36:34 keil - * Implement RESTART procedure - * - * Revision 1.1 1997/07/27 21:08:38 keil - * new - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ #ifndef l3dss1_process +#define T302 15000 #define T303 4000 #define T304 30000 #define T305 30000 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/l3ni1.c linux/drivers/isdn/hisax/l3ni1.c --- v2.2.18/drivers/isdn/hisax/l3ni1.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hisax/l3ni1.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,3199 @@ +// $Id: l3ni1.c,v 2.5.6.1 2000/12/06 16:59:19 kai Exp $ +// +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Authors: +// Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. +// NI-1 Hall of Fame - Thanks to.... +// Ragnar Paulson - for some handy code fragments +// Will Scales - beta tester extraordinaire +// Brett Whittacre - beta tester and remote devel system in Vegas +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- +#define __NO_VERSION__ +#include "hisax.h" +#include "isdnl3.h" +#include "l3ni1.h" +#include + +extern char *HiSax_getrev(const char *revision); +const char *ni1_revision = "$Revision: 2.5.6.1 $"; + +#define EXT_BEARER_CAPS 1 + +#define MsgHead(ptr, cref, mty) \ + *ptr++ = 0x8; \ + if (cref == -1) { \ + *ptr++ = 0x0; \ + } else { \ + *ptr++ = 0x1; \ + *ptr++ = cref^0x80; \ + } \ + *ptr++ = mty + + +/**********************************************/ +/* get a new invoke id for remote operations. */ +/* Only a return value != 0 is valid */ +/**********************************************/ +static unsigned char new_invoke_id(struct PStack *p) +{ + unsigned char retval; + int flags,i; + + i = 32; /* maximum search depth */ + + save_flags(flags); + cli(); + + retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ + while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { + p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; + i--; + } + if (i) { + while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7))) + retval++; + } else + retval = 0; + p->prot.ni1.last_invoke_id = retval; + p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); + restore_flags(flags); + + return(retval); +} /* new_invoke_id */ + +/*************************/ +/* free a used invoke id */ +/*************************/ +static void free_invoke_id(struct PStack *p, unsigned char id) +{ int flags; + + if (!id) return; /* 0 = invalid value */ + + save_flags(flags); + cli(); + p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); + restore_flags(flags); +} /* free_invoke_id */ + + +/**********************************************************/ +/* create a new l3 process and fill in ni1 specific data */ +/**********************************************************/ +static struct l3_process +*ni1_new_l3_process(struct PStack *st, int cr) +{ struct l3_process *proc; + + if (!(proc = new_l3_process(st, cr))) + return(NULL); + + proc->prot.ni1.invoke_id = 0; + proc->prot.ni1.remote_operation = 0; + proc->prot.ni1.uus1_data[0] = '\0'; + + return(proc); +} /* ni1_new_l3_process */ + +/************************************************/ +/* free a l3 process and all ni1 specific data */ +/************************************************/ +static void +ni1_release_l3_process(struct l3_process *p) +{ + free_invoke_id(p->st,p->prot.ni1.invoke_id); + release_l3_process(p); +} /* ni1_release_l3_process */ + +/********************************************************/ +/* search a process with invoke id id and dummy callref */ +/********************************************************/ +static struct l3_process * +l3ni1_search_dummy_proc(struct PStack *st, int id) +{ struct l3_process *pc = st->l3.proc; /* start of processes */ + + if (!id) return(NULL); + + while (pc) + { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id)) + return(pc); + pc = pc->next; + } + return(NULL); +} /* l3ni1_search_dummy_proc */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return result is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_RES; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen); +} /* l3ni1_dummy_return_result */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return error is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_error_return(struct PStack *st, int id, ulong error) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= error; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error); +} /* l3ni1_error_return */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a invoke is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_invoke(struct PStack *st, int cr, int id, + int ident, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + + l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", + (cr == -1) ? "local" : "broadcast",id,ident,nlen); + if (cr >= -1) return; /* ignore local data */ + + cs = st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_BRD; + ic.parm.ni1_io.hl_id = id; + ic.parm.ni1_io.ll_id = 0; + ic.parm.ni1_io.proc = ident; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + + cs->iif.statcallb(&ic); +} /* l3ni1_dummy_invoke */ + +static void +l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, + int cr, u_char * p) +{ + int qd_len = 0; + unsigned char nlen = 0, ilen, cp_tag; + int ident, id; + ulong err_ret; + + if (pc) + st = pc->st; /* valid Stack */ + else + if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ + + p++; + qd_len = *p++; + if (qd_len == 0) { + l3_debug(st, "qd_len == 0"); + return; + } + if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ + l3_debug(st, "supplementary service != 0x11"); + return; + } + while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ + p++; + qd_len--; + } + if (qd_len < 2) { + l3_debug(st, "qd_len < 2"); + return; + } + p++; + qd_len--; + if ((*p & 0xE0) != 0xA0) { /* class and form */ + l3_debug(st, "class and form != 0xA0"); + return; + } + + cp_tag = *p & 0x1F; /* remember tag value */ + + p++; + qd_len--; + if (qd_len < 1) + { l3_debug(st, "qd_len < 1"); + return; + } + if (*p & 0x80) + { /* length format indefinite or limited */ + nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ + if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || + (nlen > 1)) + { l3_debug(st, "length format error or not implemented"); + return; + } + if (nlen == 1) + { nlen = *p++; /* complete length */ + qd_len--; + } + else + { qd_len -= 2; /* trailing null bytes */ + if ((*(p+qd_len)) || (*(p+qd_len+1))) + { l3_debug(st,"length format indefinite error"); + return; + } + nlen = qd_len; + } + } + else + { nlen = *p++; + qd_len--; + } + if (qd_len < nlen) + { l3_debug(st, "qd_len < nlen"); + return; + } + qd_len -= nlen; + + if (nlen < 2) + { l3_debug(st, "nlen < 2"); + return; + } + if (*p != 0x02) + { /* invoke identifier tag */ + l3_debug(st, "invoke identifier tag !=0x02"); + return; + } + p++; + nlen--; + if (*p & 0x80) + { /* length format */ + l3_debug(st, "invoke id length format 2"); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + id = 0; + while (ilen > 0) + { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ + ilen--; + } + + switch (cp_tag) { /* component tag */ + case 1: /* invoke */ + if (nlen < 2) { + l3_debug(st, "nlen < 2 22"); + return; + } + if (*p != 0x02) { /* operation value */ + l3_debug(st, "operation value !=0x02"); + return; + } + p++; + nlen--; + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) { + l3_debug(st, "ilen > nlen || ilen == 0 22"); + return; + } + nlen -= ilen; + ident = 0; + while (ilen > 0) { + ident = (ident << 8) | (*p++ & 0xFF); + ilen--; + } + + if (!pc) + { + l3ni1_dummy_invoke(st, cr, id, ident, p, nlen); + return; + } + l3_debug(st, "invoke break"); + break; + case 2: /* return result */ + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_return_result(st, id, p, nlen); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Diversion successfull */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = 0; /* success */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */ + else + l3_debug(st,"return error unknown identifier"); + break; + case 3: /* return error */ + err_ret = 0; + if (nlen < 2) + { l3_debug(st, "return error nlen < 2"); + return; + } + if (*p != 0x02) + { /* result tag */ + l3_debug(st, "invoke error tag !=0x02"); + return; + } + p++; + nlen--; + if (*p > 4) + { /* length format */ + l3_debug(st, "invoke return errlen > 4 "); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "error return ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + while (ilen > 0) + { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ + ilen--; + } + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_error_return(st, id, err_ret); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Deflection error */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = err_ret; /* result */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); + } /* Deflection error */ + else + l3_debug(st,"return result unknown identifier"); + break; + default: + l3_debug(st, "facility default break tag=0x%02x",cp_tag); + break; + } +} + +static void +l3ni1_message(struct l3_process *pc, u_char mt) +{ + struct sk_buff *skb; + u_char *p; + + if (!(skb = l3_alloc_skb(4))) + return; + p = skb_put(skb, 4); + MsgHead(p, pc->callref, mt); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_message_plus_chid(struct l3_process *pc, u_char mt) +/* sends an l3 messages plus channel id - added GE 05/09/00 */ +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + u_char chid; + + chid = (u_char)(pc->para.bchannel & 0x03) | 0x88; + MsgHead(p, pc->callref, mt); + *p++ = IE_CHANNEL_ID; + *p++ = 0x01; + *p++ = chid; + + if (!(skb = l3_alloc_skb(7))) + return; + memcpy(skb_put(skb, 7), tmp, 7); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, mt); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + MsgHead(p, pc->callref, MT_STATUS); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + + *p++ = IE_CALL_STATE; + *p++ = 0x1; + *p++ = pc->state & 0x3f; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) +{ + /* This routine is called if here was no SETUP made (checks in ni1up and in + * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code + * MT_STATUS_ENQUIRE in the NULL state is handled too + */ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + switch (pc->para.cause) { + case 81: /* invalid callreference */ + case 88: /* incomp destination */ + case 96: /* mandory IE missing */ + case 100: /* invalid IE contents */ + case 101: /* incompatible Callstate */ + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + break; + default: + printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n", + pc->para.cause); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + ni1_release_l3_process(pc); +} + +static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, + IE_USER_USER, -1}; +static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; +static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, + IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, + IE_CALLED_PN, -1}; +static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | + IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; +static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, + IE_SIGNAL, IE_USER_USER, -1}; +/* a RELEASE_COMPLETE with errors don't require special actions +static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +*/ +static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, + IE_DISPLAY, -1}; +static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, + IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS, + IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, + IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, + IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | + IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; +static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; +static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +/* not used + * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, + * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; + * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; + * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | + * IE_MANDATORY, -1}; + */ +static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; +static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1}; +static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1}; + +struct ie_len { + int ie; + int len; +}; + +static +struct ie_len max_ie_len[] = { + {IE_SEGMENT, 4}, + {IE_BEARER, 12}, + {IE_CAUSE, 32}, + {IE_CALL_ID, 10}, + {IE_CALL_STATE, 3}, + {IE_CHANNEL_ID, 34}, + {IE_FACILITY, 255}, + {IE_PROGRESS, 4}, + {IE_NET_FAC, 255}, + {IE_NOTIFY, 3}, + {IE_DISPLAY, 82}, + {IE_DATE, 8}, + {IE_KEYPAD, 34}, + {IE_SIGNAL, 3}, + {IE_INFORATE, 6}, + {IE_E2E_TDELAY, 11}, + {IE_TDELAY_SEL, 5}, + {IE_PACK_BINPARA, 3}, + {IE_PACK_WINSIZE, 4}, + {IE_PACK_SIZE, 4}, + {IE_CUG, 7}, + {IE_REV_CHARGE, 3}, + {IE_CALLING_PN, 24}, + {IE_CALLING_SUB, 23}, + {IE_CALLED_PN, 24}, + {IE_CALLED_SUB, 23}, + {IE_REDIR_NR, 255}, + {IE_TRANS_SEL, 255}, + {IE_RESTART_IND, 3}, + {IE_LLC, 18}, + {IE_HLC, 5}, + {IE_USER_USER, 131}, + {-1,0}, +}; + +static int +getmax_ie_len(u_char ie) { + int i = 0; + while (max_ie_len[i].ie != -1) { + if (max_ie_len[i].ie == ie) + return(max_ie_len[i].len); + i++; + } + return(255); +} + +static int +ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { + int ret = 1; + + while (*checklist != -1) { + if ((*checklist & 0xff) == ie) { + if (ie & 0x80) + return(-ret); + else + return(ret); + } + ret++; + checklist++; + } + return(0); +} + +static int +check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) +{ + int *cl = checklist; + u_char mt; + u_char *p, ie; + int l, newpos, oldpos; + int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; + + p = skb->data; + /* skip cr */ + p++; + l = (*p++) & 0xf; + p += l; + mt = *p++; + oldpos = 0; + while ((p - skb->data) < skb->len) { + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; + else + err_ureg++; + } + } + ie = *p++; + if (ie & 0x80) { + l = 1; + } else { + l = *p++; + p += l; + l += 2; + } + if (!codeset && (l > getmax_ie_len(ie))) + err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } + } + if (err_compr | err_ureg | err_len | err_seq) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", + mt, err_compr, err_ureg, err_len, err_seq); + if (err_compr) + return(ERR_IE_COMPREHENSION); + if (err_ureg) + return(ERR_IE_UNRECOGNIZED); + if (err_len) + return(ERR_IE_LENGTH); + if (err_seq) + return(ERR_IE_SEQUENCE); + } + return(0); +} + +/* verify if a message type exists and contain no IE error */ +static int +l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) +{ + switch (mt) { + case MT_ALERTING: + case MT_CALL_PROCEEDING: + case MT_CONNECT: + case MT_CONNECT_ACKNOWLEDGE: + case MT_DISCONNECT: + case MT_INFORMATION: + case MT_FACILITY: + case MT_NOTIFY: + case MT_PROGRESS: + case MT_RELEASE: + case MT_RELEASE_COMPLETE: + case MT_SETUP: + case MT_SETUP_ACKNOWLEDGE: + case MT_RESUME_ACKNOWLEDGE: + case MT_RESUME_REJECT: + case MT_SUSPEND_ACKNOWLEDGE: + case MT_SUSPEND_REJECT: + case MT_USER_INFORMATION: + case MT_RESTART: + case MT_RESTART_ACKNOWLEDGE: + case MT_CONGESTION_CONTROL: + case MT_STATUS: + case MT_STATUS_ENQUIRY: + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt); + break; + case MT_RESUME: /* RESUME only in user->net */ + case MT_SUSPEND: /* SUSPEND only in user->net */ + default: + if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt); + pc->para.cause = 97; + l3ni1_status_send(pc, 0, NULL); + return(1); + } + return(0); +} + +static void +l3ni1_std_ie_err(struct l3_process *pc, int ret) { + + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check_infoelements ret %d", ret); + switch(ret) { + case 0: + break; + case ERR_IE_COMPREHENSION: + pc->para.cause = 96; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_UNRECOGNIZED: + pc->para.cause = 99; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_LENGTH: + pc->para.cause = 100; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_SEQUENCE: + default: + break; + } +} + +static int +l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { + u_char *p; + + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + p++; + if (*p != 1) { /* len for BRI = 1 */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid len %d", *p); + return (-2); + } + p++; + if (*p & 0x60) { /* only base rate interface */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid %x", *p); + return (-3); + } + return(*p & 0x3); + } else + return(-1); +} + +static int +l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { + u_char l, i=0; + u_char *p; + + p = skb->data; + pc->para.cause = 31; + pc->para.loc = 0; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + p++; + l = *p++; + if (l>30) + return(1); + if (l) { + pc->para.loc = *p++; + l--; + } else { + return(2); + } + if (l && !(pc->para.loc & 0x80)) { + l--; + p++; /* skip recommendation */ + } + if (l) { + pc->para.cause = *p++; + l--; + if (!(pc->para.cause & 0x80)) + return(3); + } else + return(4); + while (l && (i<6)) { + pc->para.diag[i++] = *p++; + l--; + } + } else + return(-1); + return(0); +} + +static void +l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, cmd); + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_msg_with_uus */ + +static void +l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) +{ + StopAllL3Timer(pc); + newl3state(pc, 19); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_RELEASE); + else + l3ni1_msg_with_uus(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret); + } else if (ret < 0) + pc->para.cause = NO_CAUSE; + StopAllL3Timer(pc); + newl3state(pc, 0); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); + ni1_release_l3_process(pc); +} + +#if EXT_BEARER_CAPS + +static u_char * +EncodeASyncParams(u_char * p, u_char si2) +{ // 7c 06 88 90 21 42 00 bb + + p[0] = 0; + p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 + p[2] = 0x80; + if (si2 & 32) // 7 data bits + + p[2] += 16; + else // 8 data bits + + p[2] += 24; + + if (si2 & 16) // 2 stop bits + + p[2] += 96; + else // 1 stop bit + + p[2] += 32; + + if (si2 & 8) // even parity + + p[2] += 2; + else // no parity + + p[2] += 3; + + switch (si2 & 0x07) { + case 0: + p[0] = 66; // 1200 bit/s + + break; + case 1: + p[0] = 88; // 1200/75 bit/s + + break; + case 2: + p[0] = 87; // 75/1200 bit/s + + break; + case 3: + p[0] = 67; // 2400 bit/s + + break; + case 4: + p[0] = 69; // 4800 bit/s + + break; + case 5: + p[0] = 72; // 9600 bit/s + + break; + case 6: + p[0] = 73; // 14400 bit/s + + break; + case 7: + p[0] = 75; // 19200 bit/s + + break; + } + return p + 3; +} + +static u_char +EncodeSyncParams(u_char si2, u_char ai) +{ + + switch (si2) { + case 0: + return ai + 2; // 1200 bit/s + + case 1: + return ai + 24; // 1200/75 bit/s + + case 2: + return ai + 23; // 75/1200 bit/s + + case 3: + return ai + 3; // 2400 bit/s + + case 4: + return ai + 5; // 4800 bit/s + + case 5: + return ai + 8; // 9600 bit/s + + case 6: + return ai + 9; // 14400 bit/s + + case 7: + return ai + 11; // 19200 bit/s + + case 8: + return ai + 14; // 48000 bit/s + + case 9: + return ai + 15; // 56000 bit/s + + case 15: + return ai + 40; // negotiate bit/s + + default: + break; + } + return ai; +} + + +static u_char +DecodeASyncParams(u_char si2, u_char * p) +{ + u_char info; + + switch (p[5]) { + case 66: // 1200 bit/s + + break; // si2 don't change + + case 88: // 1200/75 bit/s + + si2 += 1; + break; + case 87: // 75/1200 bit/s + + si2 += 2; + break; + case 67: // 2400 bit/s + + si2 += 3; + break; + case 69: // 4800 bit/s + + si2 += 4; + break; + case 72: // 9600 bit/s + + si2 += 5; + break; + case 73: // 14400 bit/s + + si2 += 6; + break; + case 75: // 19200 bit/s + + si2 += 7; + break; + } + + info = p[7] & 0x7f; + if ((info & 16) && (!(info & 8))) // 7 data bits + + si2 += 32; // else 8 data bits + + if ((info & 96) == 96) // 2 stop bits + + si2 += 16; // else 1 stop bit + + if ((info & 2) && (!(info & 1))) // even parity + + si2 += 8; // else no parity + + return si2; +} + + +static u_char +DecodeSyncParams(u_char si2, u_char info) +{ + info &= 0x7f; + switch (info) { + case 40: // bit/s negotiation failed ai := 165 not 175! + + return si2 + 15; + case 15: // 56000 bit/s failed, ai := 0 not 169 ! + + return si2 + 9; + case 14: // 48000 bit/s + + return si2 + 8; + case 11: // 19200 bit/s + + return si2 + 7; + case 9: // 14400 bit/s + + return si2 + 6; + case 8: // 9600 bit/s + + return si2 + 5; + case 5: // 4800 bit/s + + return si2 + 4; + case 3: // 2400 bit/s + + return si2 + 3; + case 23: // 75/1200 bit/s + + return si2 + 2; + case 24: // 1200/75 bit/s + + return si2 + 1; + default: // 1200 bit/s + + return si2; + } +} + +static u_char +DecodeSI2(struct sk_buff *skb) +{ + u_char *p; //, *pend=skb->data + skb->len; + + if ((p = findie(skb->data, skb->len, 0x7c, 0))) { + switch (p[4] & 0x0f) { + case 0x01: + if (p[1] == 0x04) // sync. Bitratenadaption + + return DecodeSyncParams(160, p[5]); // V.110/X.30 + + else if (p[1] == 0x06) // async. Bitratenadaption + + return DecodeASyncParams(192, p); // V.110/X.30 + + break; + case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption + if (p[1] > 3) + return DecodeSyncParams(176, p[5]); // V.120 + break; + } + } + return 0; +} + +#endif + + +static void +l3ni1_setup_req(struct l3_process *pc, u_char pr, + void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + + u_char *teln; + u_char *sub; + u_char *sp; + int l; + + MsgHead(p, pc->callref, MT_SETUP); + + teln = pc->para.setup.phone; + + *p++ = 0xa1; /* complete indicator */ + /* + * Set Bearer Capability, Map info from 1TR6-convention to NI1 + */ + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_BEARER; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* 3.1khz Audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa2; /* u-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_BEARER; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + + sub = NULL; + sp = teln; + while (*sp) { + if ('.' == *sp) { + sub = sp; + *sp = 0; + } else + sp++; + } + + *p++ = IE_KEYPAD; + *p++ = strlen(teln); + while (*teln) + *p++ = (*teln++) & 0x7F; + + if (sub) + *sub++ = '.'; + +#if EXT_BEARER_CAPS + if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x04; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); + } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 + + *p++ = IE_LLC; + *p++ = 0x05; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x28; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); + *p++ = 0x82; + } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x06; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + p = EncodeASyncParams(p, pc->para.setup.si2 - 192); + } else { + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_LLC; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa2; /* u-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_LLC; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + } +#endif + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) +{ + return; +} + memcpy(skb_put(skb, l), tmp, l); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T303, CC_T303); + newl3state(pc, 1); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 3); + L3AddTimer(&pc->timer, T310, CC_T310); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); +} + +static void +l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 2); + L3AddTimer(&pc->timer, T304, CC_T304); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); +} + +static void +l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret; + u_char cause = 0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "DISC get_cause ret(%d)", ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + ret = check_infoelements(pc, skb, ie_DISCONNECT); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) + cause = 99; + ret = pc->state; + newl3state(pc, 12); + if (cause) + newl3state(pc, 19); + if (11 != ret) + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); + else if (!cause) + l3ni1_release_req(pc, pr, NULL); + if (cause) { + l3ni1_message_cause(pc, MT_RELEASE, cause); + L3AddTimer(&pc->timer, T308, CC_T308_1); + } +} + +static void +l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T310 */ + newl3state(pc, 10); + pc->para.chargeinfo = 0; + /* here should inserted COLP handling KKe */ + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); +} + +static void +l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_ALERTING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T304 */ + newl3state(pc, 4); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); +} + +static void +l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + int bcfound = 0; + char tmp[80]; + struct sk_buff *skb = arg; + int id; + int err = 0; + + /* + * Bearer Capabilities + */ + p = skb->data; + /* only the first occurence 'll be detected ! */ + if ((p = findie(p, skb->len, 0x04, 0))) { + if ((p[1] < 2) || (p[1] > 11)) + err = 1; + else { + pc->para.setup.si2 = 0; + switch (p[2] & 0x7f) { + case 0x00: /* Speech */ + case 0x10: /* 3.1 Khz audio */ + pc->para.setup.si1 = 1; + break; + case 0x08: /* Unrestricted digital information */ + pc->para.setup.si1 = 7; +/* JIM, 05.11.97 I wanna set service indicator 2 */ +#if EXT_BEARER_CAPS + pc->para.setup.si2 = DecodeSI2(skb); +#endif + break; + case 0x09: /* Restricted digital information */ + pc->para.setup.si1 = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + pc->para.setup.si1 = 3; + break; + case 0x18: /* Video */ + pc->para.setup.si1 = 4; + break; + default: + err = 2; + break; + } + switch (p[3] & 0x7f) { + case 0x40: /* packed mode */ + pc->para.setup.si1 = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + pc->para.moderate = p[3] & 0x7f; + break; + default: + err = 3; + break; + } + } + if (pc->debug & L3_DEB_SI) + l3_debug(pc->st, "SI=%d, AI=%d", + pc->para.setup.si1, pc->para.setup.si2); + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", + p[1], p[2], p[3]); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bearer capabilities"); + /* ETS 300-104 1.3.3 */ + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* + * Channel Identification + */ + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((pc->para.bchannel = id)) { + if ((3 == id) && (0x10 == pc->para.moderate)) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid %x", + id); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + bcfound++; + } else + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bchannel, call waiting"); + bcfound++; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid ret %d", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_SETUP); + if (ERR_IE_COMPREHENSION == err) { + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) + iecpy(pc->para.setup.eazmsn, p, 1); + else + pc->para.setup.eazmsn[0] = 0; + + p = skb->data; + if ((p = findie(p, skb->len, 0x71, 0))) { + /* Called party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.eazmsn, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong called subaddress"); + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6c, 0))) { + pc->para.setup.plan = p[2]; + if (p[2] & 0x80) { + iecpy(pc->para.setup.phone, p, 1); + pc->para.setup.screen = 0; + } else { + iecpy(pc->para.setup.phone, p, 2); + pc->para.setup.screen = p[3]; + } + } else { + pc->para.setup.phone[0] = 0; + pc->para.setup.plan = 0; + pc->para.setup.screen = 0; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6d, 0))) { + /* Calling party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.phone, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong calling subaddress"); + } + newl3state(pc, 6); + if (err) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, err); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); +} + +static void +l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) +{ + ni1_release_l3_process(pc); +} + +static void +l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + u_char cause = 16; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + StopAllL3Timer(pc); + + MsgHead(p, pc->callref, MT_DISCONNECT); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 11); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T305, CC_T305); +} + +static void +l3ni1_setup_rsp(struct l3_process *pc, u_char pr, + void *arg) +{ + if (!pc->para.bchannel) + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "D-chan connect for waiting call"); + l3ni1_disconnect_req(pc, pr, arg); + return; + } + newl3state(pc, 8); + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "D-chan connect for waiting call"); + l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */ + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T313, CC_T313); +} + +static void +l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + newl3state(pc, 10); + L3DelTimer(&pc->timer); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); +} + +static void +l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char cause = 21; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_release(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret, cause=0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "REL get_cause ret(%d)", ret); + } else if (ret<0) + pc->para.cause = NO_CAUSE; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } + if ((ret<0) && (pc->state != 11)) + cause = 96; + else if (ret>0) + cause = 100; + ret = check_infoelements(pc, skb, ie_RELEASE); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) + cause = 99; + if (cause) + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); + else + l3ni1_message(pc, MT_RELEASE_COMPLETE); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_alert_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 7); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_ALERTING); + else + l3ni1_msg_with_uus(pc, MT_ALERTING); +} + +static void +l3ni1_proceed_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 9); + l3ni1_message(pc, MT_CALL_PROCEEDING); + pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); +} + +static void +l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + +/********************************************/ +/* deliver a incoming display message to HL */ +/********************************************/ +static void +l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) +{ u_char len; + isdn_ctrl ic; + struct IsdnCardState *cs; + char *p; + + if (*infp++ != IE_DISPLAY) return; + if ((len = *infp++) > 80) return; /* total length <= 82 */ + if (!pc->chan) return; + + p = ic.parm.display; + while (len--) + *p++ = *infp++; + *p = '\0'; + ic.command = ISDN_STAT_DISPLAY; + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.arg = pc->chan->chan; + cs->iif.statcallb(&ic); +} /* l3ni1_deliver_display */ + + +static void +l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { + if (p[1] != 2) { + err = 1; + pc->para.cause = 100; + } else if (!(p[2] & 0x70)) { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + case 0x84: + case 0x85: + case 0x87: + case 0x8a: + switch (p[3]) { + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x88: + break; + default: + err = 2; + pc->para.cause = 100; + break; + } + break; + default: + err = 3; + pc->para.cause = 100; + break; + } + } + } else { + pc->para.cause = 96; + err = 4; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "progress error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_PROGRESS); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); +} + +static void +l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { + if (p[1] != 1) { + err = 1; + pc->para.cause = 100; + } else { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + break; + default: + pc->para.cause = 100; + err = 2; + break; + } + } + } else { + pc->para.cause = 96; + err = 3; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "notify error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_NOTIFY); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); +} + +static void +l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + + ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); + l3ni1_std_ie_err(pc, ret); + pc->para.cause = 30; /* response to STATUS_ENQUIRY */ + l3ni1_status_send(pc, pr, NULL); +} + +static void +l3ni1_information(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; + + ret = check_infoelements(pc, skb, ie_INFORMATION); + if (ret) + l3ni1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } +} + +/******************************/ +/* handle deflection requests */ +/******************************/ +static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + u_char *subp; + u_char len_phone = 0; + u_char len_sub = 0; + int l; + + + strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */ + if (!pc->chan->setup.phone[0]) + { pc->para.cause = -1; + l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */ + return; + } /* only uus */ + + if (pc->prot.ni1.invoke_id) + free_invoke_id(pc->st,pc->prot.ni1.invoke_id); + + if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st))) + return; + + MsgHead(p, pc->callref, MT_FACILITY); + + for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ + if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ + + *p++ = 0x1c; /* Facility info element */ + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ + *p++ = 0x91; /* remote operations protocol */ + *p++ = 0xa1; /* invoke component */ + + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ + *p++ = 0x02; /* invoke id tag, integer */ + *p++ = 0x01; /* length */ + *p++ = pc->prot.ni1.invoke_id; /* invoke id */ + *p++ = 0x02; /* operation value tag, integer */ + *p++ = 0x01; /* length */ + *p++ = 0x0D; /* Call Deflect */ + + *p++ = 0x30; /* sequence phone number */ + *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ + + *p++ = 0x30; /* Deflected to UserNumber */ + *p++ = len_phone+2+len_sub; /* length */ + *p++ = 0x80; /* NumberDigits */ + *p++ = len_phone; /* length */ + for (l = 0; l < len_phone; l++) + *p++ = pc->chan->setup.phone[l]; + + if (len_sub) + { *p++ = 0x04; /* called party subadress */ + *p++ = len_sub - 2; + while (*subp) *p++ = *subp++; + } + + *p++ = 0x01; /* screening identifier */ + *p++ = 0x01; + *p++ = pc->chan->setup.screen; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) return; + memcpy(skb_put(skb, l), tmp, l); + + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_redir_req */ + +/********************************************/ +/* handle deflection request in early state */ +/********************************************/ +static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) +{ + l3ni1_proceed_req(pc,pr,arg); + l3ni1_redir_req(pc,pr,arg); +} /* l3ni1_redir_req_early */ + +/***********************************************/ +/* handle special commands for this protocol. */ +/* Examples are call independant services like */ +/* remote operations with dummy callref. */ +/***********************************************/ +static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) +{ u_char id; + u_char temp[265]; + u_char *p = temp; + int i, l, proc_len; + struct sk_buff *skb; + struct l3_process *pc = NULL; + + switch (ic->arg) + { case NI1_CMD_INVOKE: + if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */ + + for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++) + i = i >> 8; /* add one byte */ + l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */ + if (l > 255) + return(-2); /* too long */ + + if (!(id = new_invoke_id(st))) + return(0); /* first get a invoke id -> return if no available */ + + i = -1; + MsgHead(p, i, MT_FACILITY); /* build message head */ + *p++ = 0x1C; /* Facility IE */ + *p++ = l; /* length of ie */ + *p++ = 0x91; /* remote operations */ + *p++ = 0xA1; /* invoke */ + *p++ = l - 3; /* length of invoke */ + *p++ = 0x02; /* invoke id tag */ + *p++ = 0x01; /* length is 1 */ + *p++ = id; /* invoke id */ + *p++ = 0x02; /* operation */ + *p++ = proc_len; /* length of operation */ + + for (i = proc_len; i; i--) + *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF; + memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */ + l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */ + + if (ic->parm.ni1_io.timeout > 0) + if (!(pc = ni1_new_l3_process(st, -1))) + { free_invoke_id(st, id); + return(-2); + } + pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */ + pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */ + + if (!(skb = l3_alloc_skb(l))) + { free_invoke_id(st, id); + if (pc) ni1_release_l3_process(pc); + return(-2); + } + memcpy(skb_put(skb, l), temp, l); + + if (pc) + { pc->prot.ni1.invoke_id = id; /* remember id */ + L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST); + } + + l3_msg(st, DL_DATA | REQUEST, skb); + ic->parm.ni1_io.hl_id = id; /* return id */ + return(0); + + case NI1_CMD_INVOKE_ABORT: + if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id))) + { L3DelTimer(&pc->timer); /* remove timer */ + ni1_release_l3_process(pc); + return(0); + } + else + { l3_debug(st, "l3ni1_cmd_global abort unknown id"); + return(-2); + } + break; + + default: + l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg); + return(-1); + } /* switch ic-> arg */ + return(-1); +} /* l3ni1_cmd_global */ + +static void +l3ni1_io_timer(struct l3_process *pc) +{ isdn_ctrl ic; + struct IsdnCardState *cs = pc->st->l1.hardware; + + L3DelTimer(&pc->timer); /* remove timer */ + + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= -1; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + + ni1_release_l3_process(pc); +} /* l3ni1_io_timer */ + +static void +l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int callState = 0; + p = skb->data; + + if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) + callState = *p; + } + if (callState == 0) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 + * set down layer 3 without sending any message + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } else { + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); + } +} + +static void +l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) +{ +} + +static void +l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) +{ + if (pc->N303 > 0) { + pc->N303--; + L3DelTimer(&pc->timer); + l3ni1_setup_req(pc, pr, arg); + } else { + L3DelTimer(&pc->timer); + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); + +} + +static void +l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + u_char cause = 16; + + L3DelTimer(&pc->timer); + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 19); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); +} + +static void +l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 19); + L3DelTimer(&pc->timer); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_2); +} + +static void +l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 19); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); +} + +static void +l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_status(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int ret; + u_char cause = 0, callState = 0; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS get_cause ret(%d)",ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) { + callState = *p; + if (!ie_in_set(pc, *p, l3_valid_states)) + cause = 100; + } else + cause = 100; + } else + cause = 96; + if (!cause) { /* no error before */ + ret = check_infoelements(pc, skb, ie_STATUS); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if (ERR_IE_UNRECOGNIZED == ret) + cause = 99; + } + if (cause) { + u_char tmp; + + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); + tmp = pc->para.cause; + pc->para.cause = cause; + l3ni1_status_send(pc, 0, NULL); + if (cause == 99) + pc->para.cause = tmp; + else + return; + } + cause = pc->para.cause; + if (((cause & 0x7f) == 111) && (callState == 0)) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... + * if received MT_STATUS with cause == 111 and call + * state == 0, then we must set down layer 3 + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_FACILITY); + l3ni1_std_ie_err(pc, ret); + { + u_char *p; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } +} + +static void +l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->chan->setup.phone; + + MsgHead(p, pc->callref, MT_SUSPEND); + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 15); + L3AddTimer(&pc->timer, T319, CC_T319); +} + +static void +l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + L3DelTimer(&pc->timer); + newl3state(pc, 0); + pc->para.cause = NO_CAUSE; + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); + /* We don't handle suspend_ack for IE errors now */ + if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSPACK check ie(%d)",ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->para.setup.phone; + + MsgHead(p, pc->callref, MT_RESUME); + + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "RES wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 17); + L3AddTimer(&pc->timer, T318, CC_T318); +} + +static void +l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) > 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack without chid (ret %d)", id); + pc->para.cause = 96; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 0); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[32]; + u_char *p; + u_char ri, ch = 0, chan = 0; + int l; + struct sk_buff *skb = arg; + struct l3_process *up; + + newl3state(pc, 2); + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { + ri = p[2]; + l3_debug(pc->st, "Restart %x", ri); + } else { + l3_debug(pc->st, "Restart without restart IE"); + ri = 0x86; + } + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + chan = p[2] & 3; + ch = p[2]; + if (pc->st->l3.debug) + l3_debug(pc->st, "Restart for channel %d", chan); + } + newl3state(pc, 2); + up = pc->st->l3.proc; + while (up) { + if ((ri & 7) == 7) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + else if (up->para.bchannel == chan) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + + up = up->next; + } + p = tmp; + MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); + if (chan) { + *p++ = IE_CHANNEL_ID; + *p++ = 1; + *p++ = ch | 0x80; + } + *p++ = 0x79; /* RESTART Ind */ + *p++ = 1; + *p++ = ri; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 0); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) +{ + pc->para.cause = 0x29; /* Temporary failure */ + pc->para.loc = 0; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 0); + pc->para.cause = 0x1b; /* Destination out of order */ + pc->para.loc = 0; + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + release_l3_process(pc); +} + +static void +l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T309, CC_T309); + l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); +} + +static void +l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + + pc->para.cause = 0x1F; /* normal, unspecified */ + l3ni1_status_send(pc, 0, NULL); +} + +static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState ) +{ + u_char * p; + char * pSPID; + struct Channel * pChan = pc->st->lli.userdata; + int l; + + if ( skb ) + dev_kfree_skb( skb); + + if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) ) + { + printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + return; + } + + l = strlen( ++pSPID ); + if ( !( skb = l3_alloc_skb( 5+l ) ) ) + { + printk( KERN_ERR "HiSax can't get memory to send SPID\n" ); + return; + } + + p = skb_put( skb, 5 ); + *p++ = PROTO_DIS_EURO; + *p++ = 0; + *p++ = MT_INFORMATION; + *p++ = IE_SPID; + *p++ = l; + + memcpy( skb_put( skb, l ), pSPID, l ); + + newl3state( pc, iNewState ); + + L3DelTimer( &pc->timer ); + L3AddTimer( &pc->timer, TSPID, CC_TSPID ); + + pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb ); +} + +static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg ) +{ + l3ni1_SendSpid( pc, pr, arg, 20 ); +} + +void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) +{ + struct sk_buff *skb = arg; + + if ( skb->data[ 1 ] == 0 ) + if ( skb->data[ 3 ] == IE_ENDPOINT_ID ) + { + L3DelTimer( &pc->timer ); + newl3state( pc, 0 ); + l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL ); + } + dev_kfree_skb( skb); +} + +static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg ) +{ + if ( pc->state < 22 ) + l3ni1_SendSpid( pc, pr, arg, pc->state+1 ); + else + { + L3DelTimer( &pc->timer ); + dev_kfree_skb( arg); + + printk( KERN_ERR "SPID not accepted\n" ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + } +} + +/* *INDENT-OFF* */ +static struct stateentry downstatelist[] = +{ + {SBIT(0), + CC_SETUP | REQUEST, l3ni1_setup_req}, + {SBIT(0), + CC_RESUME | REQUEST, l3ni1_resume_req}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(12), + CC_RELEASE | REQUEST, l3ni1_release_req}, + {ALL_STATES, + CC_RESTART | REQUEST, l3ni1_restart}, + {SBIT(6) | SBIT(25), + CC_IGNORE | REQUEST, l3ni1_reset}, + {SBIT(6) | SBIT(25), + CC_REJECT | REQUEST, l3ni1_reject_req}, + {SBIT(6) | SBIT(25), + CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req}, + {SBIT(6), + CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3ni1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), + CC_ALERTING | REQUEST, l3ni1_alert_req}, + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), + CC_SETUP | RESPONSE, l3ni1_setup_rsp}, + {SBIT(10), + CC_SUSPEND | REQUEST, l3ni1_suspend_req}, + {SBIT(7) | SBIT(9) | SBIT(25), + CC_REDIR | REQUEST, l3ni1_redir_req}, + {SBIT(6), + CC_REDIR | REQUEST, l3ni1_redir_req_early}, + {SBIT(9) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(25), + CC_T302, l3ni1_t302}, + {SBIT(1), + CC_T303, l3ni1_t303}, + {SBIT(2), + CC_T304, l3ni1_t304}, + {SBIT(3), + CC_T310, l3ni1_t310}, + {SBIT(8), + CC_T313, l3ni1_t313}, + {SBIT(11), + CC_T305, l3ni1_t305}, + {SBIT(15), + CC_T319, l3ni1_t319}, + {SBIT(17), + CC_T318, l3ni1_t318}, + {SBIT(19), + CC_T308_1, l3ni1_t308_1}, + {SBIT(19), + CC_T308_2, l3ni1_t308_2}, + {SBIT(10), + CC_T309, l3ni1_dl_release}, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), + CC_TSPID, l3ni1_spid_tout }, +}; + +#define DOWNSLLEN \ + (sizeof(downstatelist) / sizeof(struct stateentry)) + +static struct stateentry datastatelist[] = +{ + {ALL_STATES, + MT_STATUS_ENQUIRY, l3ni1_status_enq}, + {ALL_STATES, + MT_FACILITY, l3ni1_facility}, + {SBIT(19), + MT_STATUS, l3ni1_release_ind}, + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_SETUP, l3ni1_setup}, + {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | + SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_SETUP, l3ni1_dummy}, + {SBIT(1) | SBIT(2), + MT_CALL_PROCEEDING, l3ni1_call_proc}, + {SBIT(1), + MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack}, + {SBIT(2) | SBIT(3), + MT_ALERTING, l3ni1_alerting}, + {SBIT(2) | SBIT(3), + MT_PROGRESS, l3ni1_progress}, + {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_INFORMATION, l3ni1_information}, + {SBIT(10) | SBIT(11) | SBIT(15), + MT_NOTIFY, l3ni1_notify}, + {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_RELEASE_COMPLETE, l3ni1_release_cmpl}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), + MT_RELEASE, l3ni1_release}, + {SBIT(19), MT_RELEASE, l3ni1_release_ind}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), + MT_DISCONNECT, l3ni1_disconnect}, + {SBIT(19), + MT_DISCONNECT, l3ni1_dummy}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), + MT_CONNECT, l3ni1_connect}, + {SBIT(8), + MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack}, + {SBIT(15), + MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack}, + {SBIT(15), + MT_SUSPEND_REJECT, l3ni1_suspend_rej}, + {SBIT(17), + MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack}, + {SBIT(17), + MT_RESUME_REJECT, l3ni1_resume_rej}, +}; + +#define DATASLLEN \ + (sizeof(datastatelist) / sizeof(struct stateentry)) + +static struct stateentry globalmes_list[] = +{ + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_RESTART, l3ni1_global_restart}, +/* {SBIT(1), + MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack}, +*/ + { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, +}; +#define GLOBALM_LEN \ + (sizeof(globalmes_list) / sizeof(struct stateentry)) + +static struct stateentry manstatelist[] = +{ + {SBIT(2), + DL_ESTABLISH | INDICATION, l3ni1_dl_reset}, + {SBIT(10), + DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status}, + {SBIT(10), + DL_RELEASE | INDICATION, l3ni1_dl_reestablish}, + {ALL_STATES, + DL_RELEASE | INDICATION, l3ni1_dl_release}, +}; + +#define MANSLLEN \ + (sizeof(manstatelist) / sizeof(struct stateentry)) +/* *INDENT-ON* */ + + +static void +global_handler(struct PStack *st, int mt, struct sk_buff *skb) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + int i; + struct l3_process *proc = st->l3.global; + + if ( skb ) + proc->callref = skb->data[2]; /* cr flag */ + else + proc->callref = 0; + for (i = 0; i < GLOBALM_LEN; i++) + if ((mt == globalmes_list[i].primitive) && + ((1 << proc->state) & globalmes_list[i].state)) + break; + if (i == GLOBALM_LEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global state %d mt %x unhandled", + proc->state, mt); + } + MsgHead(p, proc->callref, MT_STATUS); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = 81 |0x80; /* invalid cr */ + *p++ = 0x14; /* CallState */ + *p++ = 0x1; + *p++ = proc->state & 0x3f; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(proc->st, DL_DATA | REQUEST, skb); + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global %d mt %x", + proc->state, mt); + } + globalmes_list[i].rout(proc, mt, skb); + } +} + +static void +ni1up(struct PStack *st, int pr, void *arg) +{ + int i, mt, cr, cause, callState; + char *ptr; + u_char *p; + struct sk_buff *skb = arg; + struct l3_process *proc; + + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + + case (DL_ESTABLISH | CONFIRM): + global_handler( st, MT_DL_ESTABLISHED, NULL ); + return; + + default: + printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr); + return; + } + if (skb->len < 3) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + + if (skb->data[0] != PROTO_DIS_EURO) { + if (st->l3.debug & L3_DEB_PROTERR) { + l3_debug(st, "ni1up%sunexpected discriminator %x message len %d", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + skb->data[0], skb->len); + } + dev_kfree_skb(skb); + return; + } + cr = getcallref(skb->data); + if (skb->len < ((skb->data[1] & 0x0f) + 3)) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + mt = skb->data[skb->data[1] + 2]; + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up cr %d", cr); + if (cr == -2) { /* wrong Callref */ + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up wrong Callref"); + dev_kfree_skb(skb); + return; + } else if (cr == -1) { /* Dummy Callref */ + if (mt == MT_FACILITY) + { + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(st, NULL, + (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); + dev_kfree_skb(skb); + return; + } + } + else + { + global_handler(st, mt, skb); + return; + } + + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up dummy Callref (no facility msg or ie)"); + dev_kfree_skb(skb); + return; + } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) || + (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up Global CallRef"); + global_handler(st, mt, skb); + dev_kfree_skb(skb); + return; + } else if (!(proc = getl3proc(st, cr))) { + /* No transaction process exist, that means no call with + * this callreference is active + */ + if (mt == MT_SETUP) { + /* Setup creates a new transaction process */ + if (skb->data[2] & 0x80) { + /* Setup with wrong CREF flag */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up wrong CRef flag"); + dev_kfree_skb(skb); + return; + } + if (!(proc = ni1_new_l3_process(st, cr))) { + /* May be to answer with RELEASE_COMPLETE and + * CAUSE 0x2f "Resource unavailable", but this + * need a new_l3_process too ... arghh + */ + dev_kfree_skb(skb); + return; + } + } else if (mt == MT_STATUS) { + cause = 0; + if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + cause = *ptr & 0x7f; + } + callState = 0; + if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + callState = *ptr; + } + /* ETS 300-104 part 2.4.1 + * if setup has not been made and a message type + * MT_STATUS is received with call state == 0, + * we must send nothing + */ + if (callState != 0) { + /* ETS 300-104 part 2.4.2 + * if setup has not been made and a message type + * MT_STATUS is received with call state != 0, + * we must send MT_RELEASE_COMPLETE cause 101 + */ + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 101; + l3ni1_msg_without_setup(proc, 0, NULL); + } + } + dev_kfree_skb(skb); + return; + } else if (mt == MT_RELEASE_COMPLETE) { + dev_kfree_skb(skb); + return; + } else { + /* ETS 300-104 part 2 + * if setup has not been made and a message type + * (except MT_SETUP and RELEASE_COMPLETE) is received, + * we must send MT_RELEASE_COMPLETE cause 81 */ + dev_kfree_skb(skb); + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 81; + l3ni1_msg_without_setup(proc, 0, NULL); + } + return; + } + } + if (l3ni1_check_messagetype_validity(proc, mt, skb)) { + dev_kfree_skb(skb); + return; + } + if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) + l3ni1_deliver_display(proc, pr, p); /* Display IE included */ + for (i = 0; i < DATASLLEN; i++) + if ((mt == datastatelist[i].primitive) && + ((1 << proc->state) & datastatelist[i].state)) + break; + if (i == DATASLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %#x unhandled", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { + proc->para.cause = 101; + l3ni1_status_send(proc, pr, skb); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %x", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + datastatelist[i].rout(proc, pr, skb); + } + dev_kfree_skb(skb); + return; +} + +static void +ni1down(struct PStack *st, int pr, void *arg) +{ + int i, cr; + struct l3_process *proc; + struct Channel *chan; + + if ((DL_ESTABLISH | REQUEST) == pr) { + l3_msg(st, pr, NULL); + return; + } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { + chan = arg; + cr = newcallref(); + cr |= 0x80; + if ((proc = ni1_new_l3_process(st, cr))) { + proc->chan = chan; + chan->proc = proc; + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); + proc->callref = cr; + } + } else { + proc = arg; + } + if (!proc) { + printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr); + return; + } + + if ( pr == (CC_TNI1_IO | REQUEST)) { + l3ni1_io_timer(proc); /* timer expires */ + return; + } + + for (i = 0; i < DOWNSLLEN; i++) + if ((pr == downstatelist[i].primitive) && + ((1 << proc->state) & downstatelist[i].state)) + break; + if (i == DOWNSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x unhandled", + proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x", + proc->state, pr); + } + downstatelist[i].rout(proc, pr, arg); + } +} + +static void +ni1man(struct PStack *st, int pr, void *arg) +{ + int i; + struct l3_process *proc = arg; + + if (!proc) { + printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); + return; + } + for (i = 0; i < MANSLLEN; i++) + if ((pr == manstatelist[i].primitive) && + ((1 << proc->state) & manstatelist[i].state)) + break; + if (i == MANSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", + proc->callref & 0x7f, proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x", + proc->callref & 0x7f, proc->state, pr); + } + manstatelist[i].rout(proc, pr, arg); + } +} + +void +setstack_ni1(struct PStack *st) +{ + char tmp[64]; + int i; + + st->lli.l4l3 = ni1down; + st->lli.l4l3_proto = l3ni1_cmd_global; + st->l2.l2l3 = ni1up; + st->l3.l3ml3 = ni1man; + st->l3.N303 = 1; + st->prot.ni1.last_invoke_id = 0; + st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ + i = 1; + while (i < 32) + st->prot.ni1.invoke_used[i++] = 0; + + if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { + printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n"); + } else { + st->l3.global->state = 0; + st->l3.global->callref = 0; + st->l3.global->next = NULL; + st->l3.global->debug = L3_DEB_WARN; + st->l3.global->st = st; + st->l3.global->N303 = 1; + st->l3.global->prot.ni1.invoke_id = 0; + + L3InitTimer(st->l3.global, &st->l3.global->timer); + } + strcpy(tmp, ni1_revision); + printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp)); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/l3ni1.h linux/drivers/isdn/hisax/l3ni1.h --- v2.2.18/drivers/isdn/hisax/l3ni1.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hisax/l3ni1.h Sun Mar 25 11:37:33 2001 @@ -0,0 +1,137 @@ +// $Id: l3ni1.h,v 2.3 2000/11/16 13:50:43 keil Exp $ +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. Thanks also for the +// code provided by Ragnar Paulson. +// +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#ifndef l3ni1_process + +#define T302 15000 +#define T303 4000 +#define T304 30000 +#define T305 30000 +#define T308 4000 +/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ +/* This makes some tests easier and quicker */ +#define T309 40000 +#define T310 30000 +#define T313 4000 +#define T318 4000 +#define T319 4000 +#define TSPID 5000 /* was 2000 - Guy Ellis */ + +/* + * Message-Types + */ + +#define MT_ALERTING 0x01 +#define MT_CALL_PROCEEDING 0x02 +#define MT_CONNECT 0x07 +#define MT_CONNECT_ACKNOWLEDGE 0x0f +#define MT_PROGRESS 0x03 +#define MT_SETUP 0x05 +#define MT_SETUP_ACKNOWLEDGE 0x0d +#define MT_RESUME 0x26 +#define MT_RESUME_ACKNOWLEDGE 0x2e +#define MT_RESUME_REJECT 0x22 +#define MT_SUSPEND 0x25 +#define MT_SUSPEND_ACKNOWLEDGE 0x2d +#define MT_SUSPEND_REJECT 0x21 +#define MT_USER_INFORMATION 0x20 +#define MT_DISCONNECT 0x45 +#define MT_RELEASE 0x4d +#define MT_RELEASE_COMPLETE 0x5a +#define MT_RESTART 0x46 +#define MT_RESTART_ACKNOWLEDGE 0x4e +#define MT_SEGMENT 0x60 +#define MT_CONGESTION_CONTROL 0x79 +#define MT_INFORMATION 0x7b +#define MT_FACILITY 0x62 +#define MT_NOTIFY 0x6e +#define MT_STATUS 0x7d +#define MT_STATUS_ENQUIRY 0x75 +#define MT_DL_ESTABLISHED 0xfe + +#define IE_SEGMENT 0x00 +#define IE_BEARER 0x04 +#define IE_CAUSE 0x08 +#define IE_CALL_ID 0x10 +#define IE_CALL_STATE 0x14 +#define IE_CHANNEL_ID 0x18 +#define IE_FACILITY 0x1c +#define IE_PROGRESS 0x1e +#define IE_NET_FAC 0x20 +#define IE_NOTIFY 0x27 +#define IE_DISPLAY 0x28 +#define IE_DATE 0x29 +#define IE_KEYPAD 0x2c +#define IE_SIGNAL 0x34 +#define IE_SPID 0x3a +#define IE_ENDPOINT_ID 0x3b +#define IE_INFORATE 0x40 +#define IE_E2E_TDELAY 0x42 +#define IE_TDELAY_SEL 0x43 +#define IE_PACK_BINPARA 0x44 +#define IE_PACK_WINSIZE 0x45 +#define IE_PACK_SIZE 0x46 +#define IE_CUG 0x47 +#define IE_REV_CHARGE 0x4a +#define IE_CONNECT_PN 0x4c +#define IE_CONNECT_SUB 0x4d +#define IE_CALLING_PN 0x6c +#define IE_CALLING_SUB 0x6d +#define IE_CALLED_PN 0x70 +#define IE_CALLED_SUB 0x71 +#define IE_REDIR_NR 0x74 +#define IE_TRANS_SEL 0x78 +#define IE_RESTART_IND 0x79 +#define IE_LLC 0x7c +#define IE_HLC 0x7d +#define IE_USER_USER 0x7e +#define IE_ESCAPE 0x7f +#define IE_SHIFT 0x90 +#define IE_MORE_DATA 0xa0 +#define IE_COMPLETE 0xa1 +#define IE_CONGESTION 0xb0 +#define IE_REPEAT 0xd0 + +#define IE_MANDATORY 0x0100 +/* mandatory not in every case */ +#define IE_MANDATORY_1 0x0200 + +#define ERR_IE_COMPREHENSION 1 +#define ERR_IE_UNRECOGNIZED -1 +#define ERR_IE_LENGTH -2 +#define ERR_IE_SEQUENCE -3 + +#else /* only l3ni1_process */ + +/* l3ni1 specific data in l3 process */ +typedef struct + { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ + ulong ll_id; /* remebered ll id */ + u_char remote_operation; /* handled remote operation, 0 = not active */ + int proc; /* rememered procedure */ + ulong remote_result; /* result of remote operation for statcallb */ + char uus1_data[35]; /* data send during alerting or disconnect */ + } ni1_proc_priv; + +/* l3dni1 specific data in protocol stack */ +typedef struct + { unsigned char last_invoke_id; /* last used value for invoking */ + unsigned char invoke_used[32]; /* 256 bits for 256 values */ + } ni1_stk_priv; + +#endif /* only l3dni1_process */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/lmgr.c linux/drivers/isdn/hisax/lmgr.c --- v2.2.18/drivers/isdn/hisax/lmgr.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/lmgr.c Sun Mar 25 11:37:33 2001 @@ -1,30 +1,10 @@ -/* $Id: lmgr.c,v 1.6 1999/07/01 08:12:04 keil Exp $ - - * Author Karsten Keil (keil@isdn4linux.de) +/* $Id: lmgr.c,v 1.7 2000/06/26 08:59:14 keil Exp $ * + * Author Karsten Keil (keil@isdn4linux.de) * * Layermanagement module * - * $Log: lmgr.c,v $ - * Revision 1.6 1999/07/01 08:12:04 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.5 1998/11/15 23:55:12 keil - * changes from 2.0 - * - * Revision 1.4 1998/05/25 12:58:19 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.3 1998/03/07 22:57:06 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 1.2 1997/10/29 19:09:34 keil - * new L1 - * - * Revision 1.1 1997/06/26 11:17:25 keil - * first version - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc --- v2.2.18/drivers/isdn/hisax/md5sums.asc Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/md5sums.asc Sun Mar 25 11:37:33 2001 @@ -2,30 +2,32 @@ # This are valid md5sums for certificated HiSax driver. # The certification is valid only if the md5sums of all files match. -# The certification is valid only for ELSA QuickStep cards and -# Eicon Technology Diva 2.01 PCI cards in the moment. +# The certification is valid only for ELSA Microlink PCI, +# Eicon Technology Diva 2.01 PCI and Sedlbauer SpeedFax + +# cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -3c2b1c96274cba97a8261d1cecc662b8 isac.c -dd3955847bbf680b41233478fe521d88 isdnl1.c -bb51bd223040b511c18f091da5ab6456 isdnl2.c -b7aa7f97b2374967a4aca7c52991142c isdnl3.c -a23fbf8879c1432b04640b8b04bdf419 tei.c -ce248e56c2e1326012d0b25f92bbf99b callc.c -bf9605b36429898f7be6630034e83230 cert.c -6ce0a184127be1a44747e2017ed24ad9 l3dss1.c -a3a570781f828b6d59e6b231653133de l3_1tr6.c -8188deeb4a1b34c574cd51638cd214d0 elsa.c -a3c2b8e9d2c623658888b5f1d4317c2a diva.c +4131693d878d465faf0a4a4b4c6b811e isac.c +a29f5270c0c89626d8d6fa5dd09e7005 isdnl1.c +fbe41751c8130a8c3c607bfe1b41cb4e isdnl2.c +7915b7e802b98f6f4f05b931c4736ad4 isdnl3.c +7c31c12b3c2cfde33596bd2c406f775c tei.c +f1fbd532016f005e01decf36e5197d8f callc.c +a1834e9b2ec068440cff2e899eff4710 cert.c +a1f908f8b4f225c5c2f2a13842549b72 l3dss1.c +3d0a3f88fe48f3151813fafb22ea6119 l3_1tr6.c +6f3420dca0f50084f82471a238545a95 elsa.c +65da7b33bbfa454df2f99636b83f0610 diva.c +4bdb7e35627b7e25f17fccb669fda835 sedlbauer.c # end of md5sums -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv -iQCVAwUBONEHHTpxHvX/mS9tAQG/pAP/UyLx23V9mOgiYaId1Gm6xthyM8TP4bfE -ov4cNmUHQtHINLXtkAP+eacw/kCiiYhdxBIrNaUC+KQkyiFPOs8frx6espxTfDte -VZDhKDY5NYch2n3OKPLX26pNNJeu7DELMpFR6vvGByokv1RRYVs2wBk0Q5dnfPaq -WsW0HeL/vBA= -=fSCb +iQCVAwUBOVctcDpxHvX/mS9tAQFOhAP+OpOSxDz46cEHjy4jLsYz44/yKZzFAXz4 +s0tYmixrFbbS5XoT1GZqzEF0n/EycO9jsp6d0eanDCg25UX7ehu9dtOJw0o6qRr2 +4M/EbloHK2G1aW4gI8W2eWRNRqTZQJ2cjPJD/V/27jDbxBBP31NvOSYvVxrbBzJG +qZHWUDiQxRo= +=mYrg -----END PGP SIGNATURE----- diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c --- v2.2.18/drivers/isdn/hisax/mic.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/mic.c Sun Mar 25 11:37:33 2001 @@ -1,42 +1,17 @@ -/* $Id: mic.c,v 1.8 1999/07/12 21:05:20 keil Exp $ - +/* $Id: mic.c,v 1.10 2000/11/24 17:05:38 kai Exp $ + * * mic.c low level stuff for mic cards * * Copyright (C) 1997 * * Author Stephan von Krawczynski * - * - * $Log: mic.c,v $ - * Revision 1.8 1999/07/12 21:05:20 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.7 1998/04/15 16:44:32 keil - * new init code - * - * Revision 1.6 1998/02/17 15:39:57 keil - * fix reset problem - * - * Revision 1.5 1998/02/02 13:29:43 keil - * fast io - * - * Revision 1.4 1997/11/08 21:35:51 keil - * new l1 init - * - * Revision 1.3 1997/11/06 17:09:11 keil - * New 2.1 init code - * - * Revision 1.2 1997/10/29 18:51:17 keil - * New files - * - * Revision 1.1.2.1 1997/10/17 22:10:54 keil - * new files on 2.0 - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" @@ -44,7 +19,7 @@ extern const char *CardType[]; -const char *mic_revision = "$Revision: 1.8 $"; +const char *mic_revision = "$Revision: 1.10 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -224,8 +199,8 @@ return(0); } -__initfunc(int -setup_mic(struct IsdnCard *card)) +int __init +setup_mic(struct IsdnCard *card) { int bytecnt; struct IsdnCardState *cs = card->cs; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.2.18/drivers/isdn/hisax/netjet.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/netjet.c Sun Mar 25 11:37:33 2001 @@ -1,143 +1,32 @@ -/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $ - +/* $Id: netjet.c,v 1.24.6.3 2001/02/13 10:33:58 kai Exp $ + * * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Traverse Technologie Australia for documents and informations * - * $Log: netjet.c,v $ - * Revision 1.17 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.16 1999/10/14 20:25:29 keil - * add a statistic for error monitoring - * - * Revision 1.15 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.14 1999/08/31 11:20:25 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.13 1999/08/11 21:01:31 keil - * new PCI codefix - * - * Revision 1.12 1999/08/10 16:02:00 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.11 1999/08/07 17:32:00 keil - * Asymetric buffers for improved ping times. Interframe spacing - * fix for NJ<->NJ thoughput. Matt Henderson - www.traverse.com.au - * - * - * Revision 1.10 1999/07/12 21:05:22 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.9 1999/07/01 08:12:05 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.8 1998/11/15 23:55:14 keil - * changes from 2.0 - * - * Revision 1.7 1998/09/30 22:24:48 keil - * Fix missing line in setstack* - * - * Revision 1.6 1998/08/13 23:36:54 keil - * HiSax 3.1 - don't work stable with current LinkLevel - * - * Revision 1.5 1998/05/25 12:58:21 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 1.4 1998/04/15 16:42:35 keil - * new init code - * new PCI init (2.1.94) - * - * Revision 1.3 1998/02/12 23:08:05 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.2 1998/02/02 13:32:06 keil - * New - * - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ -#include +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" -#include #include #include +#include +#include "netjet.h" -#ifndef bus_to_virt -#define bus_to_virt (u_int *) -#endif - -#ifndef virt_to_bus -#define virt_to_bus (u_int) -#endif - -extern const char *CardType[]; - -const char *NETjet_revision = "$Revision: 1.17 $"; - -#define byteout(addr,val) outb(val,addr) -#define bytein(addr) inb(addr) - -/* PCI stuff */ -#define PCI_VENDOR_TRAVERSE_TECH 0xe159 -#define PCI_NETJET_ID 0x0001 - -#define NETJET_CTRL 0x00 -#define NETJET_DMACTRL 0x01 -#define NETJET_AUXCTRL 0x02 -#define NETJET_AUXDATA 0x03 -#define NETJET_IRQMASK0 0x04 -#define NETJET_IRQMASK1 0x05 -#define NETJET_IRQSTAT0 0x06 -#define NETJET_IRQSTAT1 0x07 -#define NETJET_DMA_READ_START 0x08 -#define NETJET_DMA_READ_IRQ 0x0c -#define NETJET_DMA_READ_END 0x10 -#define NETJET_DMA_READ_ADR 0x14 -#define NETJET_DMA_WRITE_START 0x18 -#define NETJET_DMA_WRITE_IRQ 0x1c -#define NETJET_DMA_WRITE_END 0x20 -#define NETJET_DMA_WRITE_ADR 0x24 -#define NETJET_PULSE_CNT 0x28 - -#define NETJET_ISAC_OFF 0xc0 -#define NETJET_ISACIRQ 0x10 -#define NETJET_IRQM0_READ 0x0c -#define NETJET_IRQM0_READ_1 0x04 -#define NETJET_IRQM0_READ_2 0x08 -#define NETJET_IRQM0_WRITE 0x03 -#define NETJET_IRQM0_WRITE_1 0x01 -#define NETJET_IRQM0_WRITE_2 0x02 - -#define NETJET_DMA_TXSIZE 512 -#define NETJET_DMA_RXSIZE 128 - -#define HDLC_ZERO_SEARCH 0 -#define HDLC_FLAG_SEARCH 1 -#define HDLC_FLAG_FOUND 2 -#define HDLC_FRAME_FOUND 3 -#define HDLC_NULL 4 -#define HDLC_PART 5 -#define HDLC_FULL 6 - -#define HDLC_FLAG_VALUE 0x7e +const char *NETjet_revision = "$Revision: 1.24.6.3 $"; /* Interface functions */ -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) +u_char +NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) { long flags; u_char ret; @@ -152,8 +41,8 @@ return(ret); } -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +void +NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) { long flags; @@ -166,8 +55,8 @@ restore_flags(flags); } -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -210,8 +99,8 @@ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -265,7 +154,8 @@ break; case (L1_MODE_TRANS): break; - case (L1_MODE_HDLC): + case (L1_MODE_HDLC_56K): + case (L1_MODE_HDLC): fill_mem(bcs, bcs->hw.tiger.send, NETJET_DMA_TXSIZE, bc, 0xff); bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH; @@ -280,7 +170,8 @@ cs->hw.njet.dmactrl = 1; byteout(cs->hw.njet.base + NETJET_DMACTRL, cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x3f); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f); + /* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */ } bcs->hw.tiger.sendp = bcs->hw.tiger.send; bcs->hw.tiger.free = NETJET_DMA_TXSIZE; @@ -297,15 +188,6 @@ bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); } -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return(5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { char tmp[128]; char *t = tmp; @@ -327,6 +209,8 @@ } } +// macro for 64k + #define MAKE_RAW_BYTE for (j=0; j<8; j++) { \ bitcnt++;\ s_val >>= 1;\ @@ -355,6 +239,7 @@ } static int make_raw_data(struct BCState *bcs) { +// this make_raw is for 64k register u_int i,s_cnt=0; register u_char j; register u_char val; @@ -410,6 +295,113 @@ return(0); } +// macro for 56k + +#define MAKE_RAW_BYTE_56K for (j=0; j<8; j++) { \ + bitcnt++;\ + s_val >>= 1;\ + if (val & 1) {\ + s_one++;\ + s_val |= 0x80;\ + } else {\ + s_one = 0;\ + s_val &= 0x7f;\ + }\ + if (bitcnt==7) {\ + s_val >>= 1;\ + s_val |= 0x80;\ + bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\ + bitcnt = 0;\ + }\ + if (s_one == 5) {\ + s_val >>= 1;\ + s_val &= 0x7f;\ + bitcnt++;\ + s_one = 0;\ + }\ + if (bitcnt==7) {\ + s_val >>= 1;\ + s_val |= 0x80;\ + bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\ + bitcnt = 0;\ + }\ + val >>= 1;\ + } + +static int make_raw_data_56k(struct BCState *bcs) { +// this make_raw is for 56k + register u_int i,s_cnt=0; + register u_char j; + register u_char val; + register u_char s_one = 0; + register u_char s_val = 0; + register u_char bitcnt = 0; + u_int fcs; + + if (!bcs->tx_skb) { + debugl1(bcs->cs, "tiger make_raw_56k: NULL skb"); + return(1); + } + val = HDLC_FLAG_VALUE; + for (j=0; j<8; j++) { + bitcnt++; + s_val >>= 1; + if (val & 1) + s_val |= 0x80; + else + s_val &= 0x7f; + if (bitcnt==7) { + s_val >>= 1; + s_val |= 0x80; + bcs->hw.tiger.sendbuf[s_cnt++] = s_val; + bitcnt = 0; + } + val >>= 1; + }; + fcs = PPP_INITFCS; + for (i=0; itx_skb->len; i++) { + val = bcs->tx_skb->data[i]; + fcs = PPP_FCS (fcs, val); + MAKE_RAW_BYTE_56K; + } + fcs ^= 0xffff; + val = fcs & 0xff; + MAKE_RAW_BYTE_56K; + val = (fcs>>8) & 0xff; + MAKE_RAW_BYTE_56K; + val = HDLC_FLAG_VALUE; + for (j=0; j<8; j++) { + bitcnt++; + s_val >>= 1; + if (val & 1) + s_val |= 0x80; + else + s_val &= 0x7f; + if (bitcnt==7) { + s_val >>= 1; + s_val |= 0x80; + bcs->hw.tiger.sendbuf[s_cnt++] = s_val; + bitcnt = 0; + } + val >>= 1; + } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger make_raw_56k: in %ld out %d.%d", + bcs->tx_skb->len, s_cnt, bitcnt); + if (bitcnt) { + while (8>bitcnt++) { + s_val >>= 1; + s_val |= 0x80; + } + bcs->hw.tiger.sendbuf[s_cnt++] = s_val; + bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix + } + bcs->hw.tiger.sendcnt = s_cnt; + bcs->tx_cnt -= bcs->tx_skb->len; + bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; + return(0); +} + static void got_frame(struct BCState *bcs, int count) { struct sk_buff *skb; @@ -439,20 +431,30 @@ register u_char r_val = bcs->hw.tiger.r_val; register u_int bitcnt = bcs->hw.tiger.r_bitcnt; u_int *p = buf; - + int bits; + u_char mask; + + if (bcs->mode == L1_MODE_HDLC) { // it's 64k + mask = 0xff; + bits = 8; + } + else { // it's 56K + mask = 0x7f; + bits = 7; + }; for (i=0;ichannel ? ((*p>>8) & 0xff) : (*p & 0xff); p++; if (p > pend) p = bcs->hw.tiger.rec; - if (val == 0xff) { + if ((val & mask) == mask) { state = HDLC_ZERO_SEARCH; bcs->hw.tiger.r_tot++; bitcnt = 0; r_one = 0; continue; } - for (j=0;j<8;j++) { + for (j=0;jhw.tiger.r_bitcnt = bitcnt; } -static void read_tiger(struct IsdnCardState *cs) { +void read_tiger(struct IsdnCardState *cs) { u_int *p; int cnt = NETJET_DMA_RXSIZE/2; @@ -618,16 +620,17 @@ p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1; else p = cs->bcs[0].hw.tiger.rec + cnt - 1; - if (cs->bcs[0].mode == L1_MODE_HDLC) + if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) read_raw(cs->bcs, p, cnt); - if (cs->bcs[1].mode == L1_MODE_HDLC) + + if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) read_raw(cs->bcs + 1, p, cnt); cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ; } static void write_raw(struct BCState *bcs, u_int *buf, int cnt); -static void fill_dma(struct BCState *bcs) +void netjet_fill_dma(struct BCState *bcs) { register u_int *p, *sp; register int cnt; @@ -639,8 +642,14 @@ bcs->Flag); if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) return; - if (make_raw_data(bcs)) - return; + if (bcs->mode == L1_MODE_HDLC) { // it's 64k + if (make_raw_data(bcs)) + return; + } + else { // it's 56k + if (make_raw_data_56k(bcs)) + return; + }; if (bcs->cs->debug & L1_DEB_HSCX) debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel, bcs->Flag); @@ -742,7 +751,7 @@ test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - fill_dma(bcs); + netjet_fill_dma(bcs); } else { mask ^= 0xffffffff; if (s_cnt < cnt) { @@ -774,7 +783,7 @@ } } -static void write_tiger(struct IsdnCardState *cs) { +void write_tiger(struct IsdnCardState *cs) { u_int *p, cnt = NETJET_DMA_TXSIZE/2; if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { @@ -795,9 +804,9 @@ p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; else p = cs->bcs[0].hw.tiger.send + cnt - 1; - if (cs->bcs[0].mode == L1_MODE_HDLC) + if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) write_raw(cs->bcs, p, cnt); - if (cs->bcs[1].mode == L1_MODE_HDLC) + if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) write_raw(cs->bcs + 1, p, cnt); cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE; } @@ -920,8 +929,8 @@ } -__initfunc(void -inittiger(struct IsdnCardState *cs)) +void __init +inittiger(struct IsdnCardState *cs) { if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int), GFP_KERNEL | GFP_DMA))) { @@ -990,88 +999,6 @@ } } -static void -netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - long flags; - - if (!cs) { - printk(KERN_WARNING "NETjet: Spurious interrupt!\n"); - return; - } - if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & - NETJET_ISACIRQ)) { - val = ReadISAC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", sval, val); - if (val) { - isac_interrupt(cs, val); - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - } - } - save_flags(flags); - cli(); - if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - restore_flags(flags); - return; - } - cs->hw.njet.irqstat0 = sval; - restore_flags(flags); -/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", - sval, - bytein(cs->hw.njet.base + NETJET_DMACTRL), - bytein(cs->hw.njet.base + NETJET_IRQMASK0), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); -*/ -/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; -*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); -/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); -*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) - read_tiger(cs); - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) - write_tiger(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - restore_flags(flags); - -/* if (!testcnt--) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } -*/ -} - -static void -reset_netjet(struct IsdnCardState *cs) -{ - long flags; - - save_flags(flags); - sti(); - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - restore_flags(flags); - cs->hw.njet.auxd = 0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - void release_io_netjet(struct IsdnCardState *cs) { @@ -1081,99 +1008,3 @@ release_region(cs->hw.njet.base, 256); } - -static int -NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - switch (mt) { - case CARD_RESET: - reset_netjet(cs); - return(0); - case CARD_RELEASE: - release_io_netjet(cs); - return(0); - case CARD_INIT: - inittiger(cs); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - return(0); - case CARD_TEST: - return(0); - } - return(0); -} - -static struct pci_dev *dev_netjet __initdata = NULL; - -__initfunc(int -setup_netjet(struct IsdnCard *card)) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - char tmp[64]; -#if CONFIG_PCI -#endif - strcpy(tmp, NETjet_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET) - return(0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "Netjet: no PCI bus present\n"); - return(0); - } - if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH, - PCI_NETJET_ID, dev_netjet))) { - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.njet.base = dev_netjet->base_address[ 0] - & PCI_BASE_ADDRESS_IO_MASK; - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); - return(0); - } - } else { - printk(KERN_WARNING "NETjet: No PCI card found\n"); - return(0); - } - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - bytecnt = 256; -#else - printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n"); - printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - printk(KERN_INFO - "NETjet: PCI card configured at 0x%x IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (check_region(cs->hw.njet.base, bytecnt)) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } else { - request_region(cs->hw.njet.base, bytecnt, "netjet isdn"); - } - reset_netjet(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &fill_dma; - cs->cardmsg = &NETjet_card_msg; - cs->irq_func = &netjet_interrupt; - cs->irq_flags |= SA_SHIRQ; - ISACVersion(cs, "NETjet:"); - return (1); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/netjet.h linux/drivers/isdn/hisax/netjet.h --- v2.2.18/drivers/isdn/hisax/netjet.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hisax/netjet.h Sun Mar 25 11:37:33 2001 @@ -0,0 +1,70 @@ +// $Id: netjet.h,v 2.5.6.1 2000/11/28 12:02:46 kai Exp $ +//----------------------------------------------------------------------------- +// +// NETjet common header file +// +// Author Kerstern Keil repackaged by +// Matt Henderson - Traverse Technologies P/L www.traverse.com.au +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +extern const char *CardType[]; + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +#define NETJET_CTRL 0x00 +#define NETJET_DMACTRL 0x01 +#define NETJET_AUXCTRL 0x02 +#define NETJET_AUXDATA 0x03 +#define NETJET_IRQMASK0 0x04 +#define NETJET_IRQMASK1 0x05 +#define NETJET_IRQSTAT0 0x06 +#define NETJET_IRQSTAT1 0x07 +#define NETJET_DMA_READ_START 0x08 +#define NETJET_DMA_READ_IRQ 0x0c +#define NETJET_DMA_READ_END 0x10 +#define NETJET_DMA_READ_ADR 0x14 +#define NETJET_DMA_WRITE_START 0x18 +#define NETJET_DMA_WRITE_IRQ 0x1c +#define NETJET_DMA_WRITE_END 0x20 +#define NETJET_DMA_WRITE_ADR 0x24 +#define NETJET_PULSE_CNT 0x28 + +#define NETJET_ISAC_OFF 0xc0 +#define NETJET_ISACIRQ 0x10 +#define NETJET_IRQM0_READ 0x0c +#define NETJET_IRQM0_READ_1 0x04 +#define NETJET_IRQM0_READ_2 0x08 +#define NETJET_IRQM0_WRITE 0x03 +#define NETJET_IRQM0_WRITE_1 0x01 +#define NETJET_IRQM0_WRITE_2 0x02 + +#define NETJET_DMA_TXSIZE 512 +#define NETJET_DMA_RXSIZE 128 + +#define HDLC_ZERO_SEARCH 0 +#define HDLC_FLAG_SEARCH 1 +#define HDLC_FLAG_FOUND 2 +#define HDLC_FRAME_FOUND 3 +#define HDLC_NULL 4 +#define HDLC_PART 5 +#define HDLC_FULL 6 + +#define HDLC_FLAG_VALUE 0x7e + +u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset); +void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value); +void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size); +void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size); + +void read_tiger(struct IsdnCardState *cs); +void write_tiger(struct IsdnCardState *cs); + +void netjet_fill_dma(struct BCState *bcs); +void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs); +void inittiger(struct IsdnCardState *cs); +void release_io_netjet(struct IsdnCardState *cs); + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.2.18/drivers/isdn/hisax/niccy.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/niccy.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: niccy.c,v 1.8 1999/08/11 21:01:33 keil Exp $ - +/* $Id: niccy.c,v 1.15.6.3 2001/02/13 10:33:58 kai Exp $ + * * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and * compatible (SAGEM cybermodem) * @@ -7,42 +7,23 @@ * * Thanks to Dr. Neuhaus and SAGEM for informations * - * $Log: niccy.c,v $ - * Revision 1.8 1999/08/11 21:01:33 keil - * new PCI codefix - * - * Revision 1.7 1999/08/10 16:02:04 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.6 1999/07/12 21:05:23 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.5 1999/07/01 08:12:07 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.4 1998/04/16 19:16:48 keil - * need config.h - * - * Revision 1.3 1998/04/15 16:42:59 keil - * new init code - * - * Revision 1.2 1998/02/11 17:31:04 keil - * new file + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ #include +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" #include +#include extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.8 $"; +const char *niccy_revision = "$Revision: 1.15.6.3 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -59,8 +40,6 @@ #define NICCY_PCI 2 /* PCI stuff */ -#define PCI_VENDOR_DR_NEUHAUS 0x1267 -#define PCI_NICCY_ID 0x1016 #define PCI_IRQ_CTRL_REG 0x38 #define PCI_IRQ_ENABLE 0x1f00 #define PCI_IRQ_DISABLE 0xff0000 @@ -228,12 +207,13 @@ static void niccy_reset(struct IsdnCardState *cs) { - int val, nval; - - val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - nval = val | PCI_IRQ_ENABLE; - outl(nval, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + if (cs->subtyp == NICCY_PCI) { + int val; + val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + val |= PCI_IRQ_ENABLE; + outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + } inithscxisac(cs, 3); } @@ -256,10 +236,10 @@ return(0); } -static struct pci_dev *niccy_dev __initdata = NULL; +static struct pci_dev *niccy_dev __initdata = NULL; -__initfunc(int -setup_niccy(struct IsdnCard *card)) +int __init +setup_niccy(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -304,24 +284,26 @@ return(0); } cs->subtyp = 0; - if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS, - PCI_NICCY_ID, niccy_dev))) { + if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, + PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) { + if (pci_enable_device(niccy_dev)) + return(0); /* get IRQ */ if (!niccy_dev->irq) { printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); return(0); } cs->irq = niccy_dev->irq; - if (!niccy_dev->base_address[ 0]) { + cs->hw.niccy.cfg_reg = niccy_dev->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.niccy.cfg_reg) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); return(0); } - cs->hw.niccy.cfg_reg = niccy_dev->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK; - if (!niccy_dev->base_address[ 1]) { + pci_ioaddr = niccy_dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; + if (!pci_ioaddr) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr = niccy_dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; cs->subtyp = NICCY_PCI; } else { printk(KERN_WARNING "Niccy: No PCI card found\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/nj_s.c linux/drivers/isdn/hisax/nj_s.c --- v2.2.18/drivers/isdn/hisax/nj_s.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hisax/nj_s.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,269 @@ +// $Id: nj_s.c,v 2.7.6.3 2001/02/13 10:33:58 kai Exp $ +// +// This file is (c) under GNU PUBLIC LICENSE +// + +#define __NO_VERSION__ +#include +#include +#include "hisax.h" +#include "isac.h" +#include "isdnl1.h" +#include +#include +#include +#include +#include "netjet.h" + +const char *NETjet_S_revision = "$Revision: 2.7.6.3 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETjet-S: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ISAC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + isac_interrupt(cs, val); + NETjet_WriteIC(cs, ISAC_MASK, 0xFF); + NETjet_WriteIC(cs, ISAC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + /* start new code 13/07/00 GE */ + /* set bits in sval to indicate which page is free */ + if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < + inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) + /* the 2nd write page is free */ + sval = 0x08; + else /* the 1st write page is free */ + sval = 0x04; + if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < + inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) + /* the 2nd read page is free */ + sval = sval | 0x02; + else /* the 1st read page is free */ + sval = sval | 0x01; + if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */ + { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); + if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != + (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) + /* we have a read dma int */ + read_tiger(cs); + if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != + (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) + /* we have a write dma int */ + write_tiger(cs); + /* end new code 13/07/00 GE */ + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_s(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ + /* now edge triggered for TJ320 GE 13/07/00 */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_s(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_isac_ints(cs); + initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +int __init +setup_netjet_s(struct IsdnCard *card) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; + +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_S_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_S) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + +#if CONFIG_PCI + + for ( ;; ) + { + if (!pci_present()) { + printk(KERN_ERR "Netjet: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + pci_set_master(dev_netjet); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = dev_netjet->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETjet-S: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) ) + { + case 0 : + break; + + case 3 : + printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETjet-S: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETjet-S: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn"); + } + reset_netjet_s(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_S_card_msg; + cs->irq_func = &netjet_s_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "NETjet-S:"); + return (1); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/nj_u.c linux/drivers/isdn/hisax/nj_u.c --- v2.2.18/drivers/isdn/hisax/nj_u.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hisax/nj_u.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,273 @@ +/* $Id: nj_u.c,v 2.8.6.3 2001/02/13 10:33:58 kai Exp $ + * + * This file is (c) under GNU PUBLIC LICENSE + * + */ + +#define __NO_VERSION__ +#include +#include +#include "hisax.h" +#include "icc.h" +#include "isdnl1.h" +#include +#include +#include +#include +#include "netjet.h" + +const char *NETjet_U_revision = "$Revision: 2.8.6.3 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETspider-U: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ICC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + icc_interrupt(cs, val); + NETjet_WriteIC(cs, ICC_MASK, 0xFF); + NETjet_WriteIC(cs, ICC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + /* start new code 13/07/00 GE */ + /* set bits in sval to indicate which page is free */ + if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < + inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) + /* the 2nd write page is free */ + sval = 0x08; + else /* the 1st write page is free */ + sval = 0x04; + if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < + inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) + /* the 2nd read page is free */ + sval = sval | 0x02; + else /* the 1st read page is free */ + sval = sval | 0x01; + if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */ + { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); + if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != + (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) + /* we have a read dma int */ + read_tiger(cs); + if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != + (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) + /* we have a write dma int */ + write_tiger(cs); + /* end new code 13/07/00 GE */ + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_u(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ + /* now edge triggered for TJ320 GE 13/07/00 */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_u(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_icc_ints(cs); + initicc(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +int __init +setup_netjet_u(struct IsdnCard *card) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; +#if CONFIG_PCI +#endif +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_U_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_U) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + +#if CONFIG_PCI + + for ( ;; ) + { + if (!pci_present()) { + printk(KERN_ERR "Netjet: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + pci_set_master(dev_netjet); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = dev_netjet->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETspider-U: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) ) + { + case 3 : + break; + + case 0 : + printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETspider-U: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETspider-U: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn"); + } + reset_netjet_u(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_U_card_msg; + cs->irq_func = &netjet_u_interrupt; + cs->irq_flags |= SA_SHIRQ; + ICCVersion(cs, "NETspider-U:"); + return (1); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c --- v2.2.18/drivers/isdn/hisax/q931.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/q931.c Sun Mar 25 11:37:33 2001 @@ -1,9 +1,11 @@ -/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $ - +/* $Id: q931.c,v 1.10 2000/06/26 08:59:14 keil Exp $ + * * q931.c code to decode ITU Q.931 call control messages * * Author Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * * Changelog * * Pauline Middelink general improvements @@ -12,30 +14,6 @@ * * Karsten Keil cause texts, display information element for 1TR6 * - * - * $Log: q931.c,v $ - * Revision 1.7 1998/11/15 23:55:17 keil - * changes from 2.0 - * - * Revision 1.6 1997/07/27 21:09:44 keil - * move functions to isdnl3.c - * - * Revision 1.5 1997/04/06 22:56:43 keil - * Some cosmetic changes - * - * Revision 1.4 1997/02/09 00:29:11 keil - * new interface handling, one interface per card - * - * Revision 1.3 1997/01/21 22:24:59 keil - * cleanups - * - * Revision 1.2 1996/10/27 22:12:45 keil - * reporting unknown level 3 protocol ids - * - * Revision 1.1 1996/10/13 20:04:56 keil - * Initial revision - * - * */ @@ -87,6 +65,24 @@ 0xd, "SETUP ACKNOWLEDGE" }, { + 0x24, "HOLD" + }, + { + 0x28, "HOLD ACKNOWLEDGE" + }, + { + 0x30, "HOLD REJECT" + }, + { + 0x31, "RETRIEVE" + }, + { + 0x33, "RETRIEVE ACKNOWLEDGE" + }, + { + 0x37, "RETRIEVE REJECT" + }, + { 0x26, "RESUME" }, { @@ -201,29 +197,6 @@ #define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) -static struct MessageType fac_1tr6[] = -{ - {FAC_Sperre, "Sperre"}, - {FAC_Forward1, "Forward 1"}, - {FAC_Forward2, "Forward 2"}, - {FAC_Konferenz, "Konferenz"}, - {FAC_GrabBchan, "Grab Bchannel"}, - {FAC_Reactivate, "Reactivate"}, - {FAC_Konferenz3, "Dreier Konferenz"}, - {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"}, - {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"}, - {FAC_NummernIdent, "Rufnummer-Identifizierung"}, - {FAC_GBG, "GBG"}, - {FAC_DisplayUebergeben, "Display Uebergeben"}, - {FAC_DisplayUmgeleitet, "Display Umgeleitet"}, - {FAC_Unterdruecke, "Unterdruecke Rufnummer"}, - {FAC_Deactivate, "Deactivate"}, - {FAC_Activate, "Activate"}, - {FAC_SPV, "SPV"}, - {FAC_Rueckwechsel, "Rueckwechsel"}, - {FAC_Umleitung, "Umleitung"} -}; -#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType)) static int prbits(char *dest, u_char b, int start, int len) @@ -683,6 +656,65 @@ return (dp - dest); } + +static +int +prbearer_ni1(char *dest, u_char * p) +{ + char *dp = dest; + u_char len; + + p++; + len = *p++; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x80: + dp += sprintf(dp, " Speech"); + break; + case 0x88: + dp += sprintf(dp, " Unrestricted digital information"); + break; + case 0x90: + dp += sprintf(dp, " 3.1 kHz audio"); + break; + default: + dp += sprintf(dp, " Unknown information-transfer capability"); + } + *dp++ = '\n'; + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x90: + dp += sprintf(dp, " 64 kbps, circuit mode"); + break; + case 0xc0: + dp += sprintf(dp, " Packet mode"); + break; + default: + dp += sprintf(dp, " Unknown transfer mode"); + } + *dp++ = '\n'; + if (len > 2) { + dp += sprintf(dp, " octet 5 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x21: + dp += sprintf(dp, " Rate adaption\n"); + dp += sprintf(dp, " octet 5a "); + dp += prbits(dp, *p, 8, 8); + break; + case 0xa2: + dp += sprintf(dp, " u-law"); + break; + default: + dp += sprintf(dp, " Unknown UI layer 1 protocol"); + } + *dp++ = '\n'; + } + return (dp - dest); +} + static int general(char *dest, u_char * p) { @@ -711,6 +743,33 @@ } static int +general_ni1(char *dest, u_char * p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the information element */ + while (l--) { + dp += sprintf(dp, " octet %d%c ", octet, ch); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + + /* last octet in group? */ + if (*p++ & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + else + ch++; + } + return (dp - dest); +} + +static int prcharge(char *dest, u_char * p) { char *dp = dest; @@ -742,6 +801,112 @@ *dp++ = '\n'; return (dp - dest); } + +static int +prfeatureind(char *dest, u_char * p) +{ + char *dp = dest; + + p += 2; /* skip id, len */ + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (!(*p++ & 80)) { + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + dp += sprintf(dp, " Status: "); + switch (*p) { + case 0: + dp += sprintf(dp, "Idle"); + break; + case 1: + dp += sprintf(dp, "Active"); + break; + case 2: + dp += sprintf(dp, "Prompt"); + break; + case 3: + dp += sprintf(dp, "Pending"); + break; + default: + dp += sprintf(dp, "(Reserved)"); + break; + } + *dp++ = '\n'; + return (dp - dest); +} + +static +struct DTag { /* Display tags */ + u_char nr; + char *descr; +} dtaglist[] = { + { 0x82, "Continuation" }, + { 0x83, "Called address" }, + { 0x84, "Cause" }, + { 0x85, "Progress indicator" }, + { 0x86, "Notification indicator" }, + { 0x87, "Prompt" }, + { 0x88, "Accumlated digits" }, + { 0x89, "Status" }, + { 0x8a, "Inband" }, + { 0x8b, "Calling address" }, + { 0x8c, "Reason" }, + { 0x8d, "Calling party name" }, + { 0x8e, "Called party name" }, + { 0x8f, "Orignal called name" }, + { 0x90, "Redirecting name" }, + { 0x91, "Connected name" }, + { 0x92, "Originating restrictions" }, + { 0x93, "Date & time of day" }, + { 0x94, "Call Appearance ID" }, + { 0x95, "Feature address" }, + { 0x96, "Redirection name" }, + { 0x9e, "Text" }, +}; +#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) + +static int +disptext_ni1(char *dest, u_char * p) +{ + char *dp = dest; + int l, tag, len, i; + + p++; + l = *p++ - 1; + if (*p++ != 0x80) { + dp += sprintf(dp, " Unknown display type\n"); + return (dp - dest); + } + /* Iterate over all tag,length,text fields */ + while (l > 0) { + tag = *p++; + len = *p++; + l -= len + 2; + /* Don't space or skip */ + if ((tag == 0x80) || (tag == 0x81)) p++; + else { + for (i = 0; i < DTAGSIZE; i++) + if (tag == dtaglist[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != DTAGSIZE) { + dp += sprintf(dp, " %s: ", dtaglist[i].descr); + while (len--) + *dp++ = *p++; + } else { + dp += sprintf(dp, " (unknown display tag %2x): ", tag); + while (len--) + *dp++ = *p++; + } + dp += sprintf(dp, "\n"); + } + } + return (dp - dest); +} static int display(char *dest, u_char * p) { @@ -912,6 +1077,49 @@ #define IESIZE sizeof(ielist)/sizeof(struct InformationElement) +static +struct InformationElement ielist_ni1[] = { + { 0x04, "Bearer Capability", prbearer_ni1 }, + { 0x08, "Cause", prcause }, + { 0x14, "Call State", general_ni1 }, + { 0x18, "Channel Identification", prchident }, + { 0x1e, "Progress Indicator", general_ni1 }, + { 0x27, "Notification Indicator", general_ni1 }, + { 0x2c, "Keypad Facility", prtext }, + { 0x32, "Information Request", general_ni1 }, + { 0x34, "Signal", general_ni1 }, + { 0x38, "Feature Activation", general_ni1 }, + { 0x39, "Feature Indication", prfeatureind }, + { 0x3a, "Service Profile Identification (SPID)", prtext }, + { 0x3b, "Endpoint Identifier", general_ni1 }, + { 0x6c, "Calling Party Number", prcalling }, + { 0x6d, "Calling Party Subaddress", general_ni1 }, + { 0x70, "Called Party Number", prcalled }, + { 0x71, "Called Party Subaddress", general_ni1 }, + { 0x74, "Redirecting Number", general_ni1 }, + { 0x78, "Transit Network Selection", general_ni1 }, + { 0x7c, "Low Layer Compatibility", general_ni1 }, + { 0x7d, "High Layer Compatibility", general_ni1 }, +}; + + +#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs5[] = { + { 0x1d, "Operator system access", general_ni1 }, + { 0x2a, "Display text", disptext_ni1 }, +}; + +#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs6[] = { + { 0x7b, "Call appearance", general_ni1 }, +}; + +#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) + static struct InformationElement we_0[] = { {WE0_cause, "Cause", prcause_1tr6}, @@ -1152,7 +1360,93 @@ } buf += buf[1] + 2; } - } else if (buf[0] == 8) { /* EURO */ + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ + /* locate message type */ + buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == mt) + break; + + /* display message type if it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mtlist[i].descr); + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cset; + cset = *buf & 7; + cs_fest = *buf & 8; + break; + default: + dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cset == 0) { + for (i = 0; i < IESIZE; i++) + if (*buf == ielist_ni1[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE) { + dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); + dp += ielist_ni1[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 5) { + for (i = 0; i < IESIZE_NI1_CS5; i++) + if (*buf == ielist_ni1_cs5[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS5) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); + dp += ielist_ni1_cs5[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < IESIZE_NI1_CS6; i++) + if (*buf == ielist_ni1_cs6[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS6) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); + dp += ielist_ni1_cs6[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + + /* Skip to next element */ + if (cs_fest == 8) { + cset = cs_old; + cs_old = 0; + cs_fest = 0; + } + buf += buf[1] + 2; + } + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ /* locate message type */ buf++; cr_l = *buf++; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/rawhdlc.c linux/drivers/isdn/hisax/rawhdlc.c --- v2.2.18/drivers/isdn/hisax/rawhdlc.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/rawhdlc.c Sun Mar 25 11:37:33 2001 @@ -1,10 +1,11 @@ -/* $Id: rawhdlc.c,v 1.4 1999/12/23 15:09:32 keil Exp $ - +/* $Id: rawhdlc.c,v 1.5 2000/06/26 08:59:14 keil Exp $ + * * rawhdlc.c support routines for cards that don't support HDLC * * Author Karsten Keil (keil@isdn4linux.de) * Brent Baccala * + * This file is (c) under GNU PUBLIC LICENSE * * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930, * don't perform HDLC encapsulation over the B channel. Drivers for diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/rawhdlc.h linux/drivers/isdn/hisax/rawhdlc.h --- v2.2.18/drivers/isdn/hisax/rawhdlc.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/rawhdlc.h Sun Mar 25 11:37:33 2001 @@ -1,8 +1,10 @@ -/* $Id: rawhdlc.h,v 1.2 1998/02/09 10:53:53 keil Exp $ - +/* $Id: rawhdlc.h,v 1.3 2000/06/26 08:59:14 keil Exp $ + * * rawhdlc.h support routines for cards that don't support HDLC * * Author Brent Baccala + * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c --- v2.2.18/drivers/isdn/hisax/s0box.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/s0box.c Sun Mar 25 11:37:33 2001 @@ -1,19 +1,21 @@ -/* $Id: s0box.c,v 2.2 1999/07/12 21:05:25 keil Exp $ - +/* $Id: s0box.c,v 2.4 2000/11/24 17:05:38 kai Exp $ + * * s0box.c low level stuff for Creatix S0BOX * * Author S0BOX specific stuff: Enrik Berkhan (enrik@starfleet.inka.de) * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -const char *s0box_revision = "$Revision: 2.2 $"; +const char *s0box_revision = "$Revision: 2.4 $"; static inline void writereg(unsigned int padr, signed int addr, u_char off, u_char val) { @@ -212,8 +214,8 @@ return(0); } -__initfunc(int -setup_s0box(struct IsdnCard *card)) +int __init +setup_s0box(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c --- v2.2.18/drivers/isdn/hisax/saphir.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/saphir.c Sun Mar 25 11:37:33 2001 @@ -1,39 +1,25 @@ -/* $Id: saphir.c,v 1.5 1999/12/19 13:09:42 keil Exp $ - +/* $Id: saphir.c,v 1.8 2000/11/24 17:05:38 kai Exp $ + * * saphir.c low level stuff for HST Saphir 1 * * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to HST High Soft Tech GmbH * - * - * $Log: saphir.c,v $ - * Revision 1.5 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.4 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.3 1999/07/12 21:05:26 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.2 1999/07/01 08:07:55 keil - * Initial version - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -static char *saphir_rev = "$Revision: 1.5 $"; +static char *saphir_rev = "$Revision: 1.8 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -173,11 +159,9 @@ goto Start_ISAC; } /* Watchdog */ - if (cs->hw.saphir.timer.function) { - del_timer(&cs->hw.saphir.timer); - cs->hw.saphir.timer.expires = jiffies + 1*HZ; - add_timer(&cs->hw.saphir.timer); - } else + if (cs->hw.saphir.timer.function) + mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ); + else printk(KERN_WARNING "saphir: Spurious timer!\n"); writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF); writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF); @@ -192,9 +176,7 @@ { /* 5 sec WatchDog, so read at least every 4 sec */ cs->readisac(cs, ISAC_RBCH); - del_timer(&cs->hw.saphir.timer); - cs->hw.saphir.timer.expires = jiffies + 1*HZ; - add_timer(&cs->hw.saphir.timer); + mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ); } void @@ -241,10 +223,10 @@ save_flags(flags); sti(); byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ restore_flags(flags); byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); @@ -272,8 +254,8 @@ } -__initfunc(int -setup_saphir(struct IsdnCard *card)) +int __init +setup_saphir(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.2.18/drivers/isdn/hisax/sedlbauer.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/sedlbauer.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: sedlbauer.c,v 1.20 2000/01/20 19:47:45 keil Exp $ - +/* $Id: sedlbauer.c,v 1.25.6.3 2001/02/13 10:33:58 kai Exp $ + * * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), * support for the Sedlbauer speed fax+, @@ -16,71 +16,7 @@ * Sedlbauer AG for informations * Edgar Toernig * - * $Log: sedlbauer.c,v $ - * Revision 1.20 2000/01/20 19:47:45 keil - * Add Fax Class 1 support - * - * Revision 1.19 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.18 1999/11/13 21:25:03 keil - * Support for Speedfax+ PCI - * - * Revision 1.17 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.16 1999/08/29 18:23:01 niemann - * Fixed typo in errormsg - * - * Revision 1.15 1999/08/25 17:00:00 keil - * Make ISAR V32bis modem running - * Make LL->HL interface open for additional commands - * - * Revision 1.14 1999/08/11 20:59:22 keil - * new PCI codefix - * fix IRQ problem while unload - * - * Revision 1.13 1999/08/10 16:02:08 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.12 1999/08/05 20:43:22 keil - * ISAR analog modem support - * - * Revision 1.11 1999/07/12 21:05:27 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.10 1999/07/01 08:12:09 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.9 1998/11/15 23:55:20 keil - * changes from 2.0 - * - * Revision 1.8 1998/08/13 23:34:51 keil - * starting speedfax+ (ISAR) support - * - * Revision 1.7 1998/04/15 16:44:33 keil - * new init code - * - * Revision 1.6 1998/02/09 18:46:06 keil - * Support for Sedlbauer PCMCIA (Marcus Niemann) - * - * Revision 1.5 1998/02/02 13:29:45 keil - * fast io - * - * Revision 1.4 1997/11/08 21:35:52 keil - * new l1 init - * - * Revision 1.3 1997/11/06 17:09:28 keil - * New 2.1 init code - * - * Revision 1.2 1997/10/29 18:55:52 keil - * changes for 2.1.60 (irq2dev_map) - * - * Revision 1.1 1997/09/11 17:32:04 keil - * new - * + * This file is (c) under GNU PUBLIC LICENSE * */ @@ -103,9 +39,8 @@ * For example: hisaxctrl 9 ISAR.BIN */ -#define SEDLBAUER_PCI 1 - #define __NO_VERSION__ +#include #include #include "hisax.h" #include "isac.h" @@ -114,22 +49,21 @@ #include "isar.h" #include "isdnl1.h" #include +#include extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.20 $"; +const char *Sedlbauer_revision = "$Revision: 1.25.6.3 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", "speed win II / ISDN PC/104", "speed star II", "speed pci", - "speed fax+ pci"}; + "speed fax+ pyramid", "speed fax+ pci"}; -#ifdef SEDLBAUER_PCI -#define PCI_VENDOR_SEDLBAUER 0xe159 -#define PCI_SPEEDPCI_ID 0x02 -#define PCI_SUBVENDOR_SEDLBAUER 0x51 -#define PCI_SUB_ID_SPEEDFAXP 0x01 -#endif +#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 +#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 +#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 +#define PCI_SUB_ID_SEDLBAUER 0x01 #define SEDL_SPEED_CARD_WIN 1 #define SEDL_SPEED_STAR 2 @@ -137,7 +71,8 @@ #define SEDL_SPEED_WIN2_PC104 4 #define SEDL_SPEED_STAR2 5 #define SEDL_SPEED_PCI 6 -#define SEDL_SPEEDFAX_PCI 7 +#define SEDL_SPEEDFAX_PYRAMID 7 +#define SEDL_SPEEDFAX_PCI 8 #define SEDL_CHIP_TEST 0 #define SEDL_CHIP_ISAC_HSCX 1 @@ -349,10 +284,10 @@ } if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - printk(KERN_WARNING "Sedlbauer: card not available!\n"); - return; + /* The card tends to generate interrupts while being removed + causing us to just crash the kernel. bad. */ + printk(KERN_WARNING "Sedlbauer: card not available!\n"); + return; } val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); @@ -424,7 +359,8 @@ goto Start_IPAC; } if (!icnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); } @@ -462,7 +398,8 @@ goto Start_ISAC; } if (!cnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); @@ -497,10 +434,10 @@ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20); save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff); @@ -523,10 +460,10 @@ byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } @@ -572,7 +509,7 @@ case CARD_TEST: return(0); case MDL_INFO_CONN: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; @@ -581,7 +518,7 @@ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); break; case MDL_INFO_REL: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; @@ -593,12 +530,10 @@ return(0); } -#ifdef SEDLBAUER_PCI -static struct pci_dev *dev_sedl __initdata = NULL; -#endif +static struct pci_dev *dev_sedl = NULL; -__initfunc(int -setup_sedlbauer(struct IsdnCard *card)) +int +setup_sedlbauer(struct IsdnCard *card) { int bytecnt, ver, val; struct IsdnCardState *cs = card->cs; @@ -633,42 +568,50 @@ } } else { /* Probe for Sedlbauer speed pci */ -#if SEDLBAUER_PCI #if CONFIG_PCI if (!pci_present()) { printk(KERN_ERR "Sedlbauer: no PCI bus present\n"); return(0); } - if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER, - PCI_SPEEDPCI_ID, dev_sedl))) { + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { + if (pci_enable_device(dev_sedl)) + return(0); cs->irq = dev_sedl->irq; if (!cs->irq) { printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); return(0); } - cs->hw.sedl.cfg_reg = dev_sedl->base_address[ 0] & - PCI_BASE_ADDRESS_IO_MASK; + cs->hw.sedl.cfg_reg = dev_sedl->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK; } else { printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); return(0); } cs->irq_flags |= SA_SHIRQ; cs->hw.sedl.bus = SEDL_BUS_PCI; - pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID, - &sub_vendor_id); - pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID, - &sub_id); + pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id); + pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID, &sub_id); printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", sub_vendor_id, sub_id); printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", cs->hw.sedl.cfg_reg); - if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) && - (sub_id == PCI_SUB_ID_SPEEDFAXP)) { + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; cs->subtyp = SEDL_SPEEDFAX_PCI; - } else { + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { cs->hw.sedl.chip = SEDL_CHIP_IPAC; cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); } bytecnt = 256; cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; @@ -688,7 +631,6 @@ printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); return (0); #endif /* CONFIG_PCI */ -#endif /* SEDLBAUER_PCI */ } /* In case of the sedlbauer pcmcia card, this region is in use, @@ -748,7 +690,6 @@ if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - /* IPAC */ if (cs->hw.sedl.bus == SEDL_BUS_PCI) { cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c --- v2.2.18/drivers/isdn/hisax/sportster.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/sportster.c Sun Mar 25 11:37:33 2001 @@ -1,59 +1,23 @@ -/* $Id: sportster.c,v 1.12 1999/12/23 15:09:32 keil Exp $ - +/* $Id: sportster.c,v 1.14 2000/11/24 17:05:38 kai Exp $ + * * sportster.c low level stuff for USR Sportster internal TA * * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation * - * $Log: sportster.c,v $ - * Revision 1.12 1999/12/23 15:09:32 keil - * change email - * - * Revision 1.11 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.10 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.9 1999/07/12 21:05:29 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.8 1999/07/01 08:12:10 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.7 1998/11/15 23:55:22 keil - * changes from 2.0 - * - * Revision 1.6 1998/04/15 16:44:35 keil - * new init code - * - * Revision 1.5 1998/02/02 13:29:46 keil - * fast io - * - * Revision 1.4 1997/11/08 21:35:52 keil - * new l1 init - * - * Revision 1.3 1997/11/06 17:09:29 keil - * New 2.1 init code - * - * Revision 1.2 1997/10/29 18:51:18 keil - * New files - * - * Revision 1.1.2.1 1997/10/17 22:10:58 keil - * new files on 2.0 + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -const char *sportster_revision = "$Revision: 1.12 $"; +const char *sportster_revision = "$Revision: 1.14 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -187,11 +151,11 @@ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } @@ -218,8 +182,8 @@ return(0); } -__initfunc(int -get_io_range(struct IsdnCardState *cs)) +static int __init +get_io_range(struct IsdnCardState *cs) { int i, j, adr; @@ -244,8 +208,8 @@ } } -__initfunc(int -setup_sportster(struct IsdnCard *card)) +int __init +setup_sportster(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c --- v2.2.18/drivers/isdn/hisax/tei.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/tei.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: tei.c,v 2.13 1999/07/21 14:46:28 keil Exp $ - +/* $Id: tei.c,v 2.17 2000/11/24 17:05:38 kai Exp $ + * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * @@ -10,75 +10,14 @@ * Thanks to Jan den Ouden * Fritz Elfert * - * $Log: tei.c,v $ - * Revision 2.13 1999/07/21 14:46:28 keil - * changes from EICON certification - * - * Revision 2.12 1999/07/01 08:12:11 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.11 1998/11/15 23:55:24 keil - * changes from 2.0 - * - * Revision 2.10 1998/05/25 14:08:10 keil - * HiSax 3.0 - * fixed X.75 and leased line to work again - * Point2Point and fixed TEI are runtime options now: - * hisaxctrl 7 1 set PTP - * hisaxctrl 8 - * set fixed TEI to TEIVALUE (0-63) - * - * Revision 2.9 1998/05/25 12:58:23 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.8 1998/03/07 22:57:07 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 2.7 1998/02/12 23:08:11 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 2.6 1998/02/02 13:41:42 keil - * fix MDL_ASSIGN for PtP - * - * Revision 2.5 1997/11/06 17:09:12 keil - * New 2.1 init code - * - * Revision 2.4 1997/10/29 19:04:46 keil - * changes for 2.1 - * - * Revision 2.3 1997/10/01 09:21:43 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 2.2 1997/07/31 19:24:39 keil - * fixed a warning - * - * Revision 2.1 1997/07/31 11:50:16 keil - * ONE TEI and FIXED TEI handling - * - * Revision 2.0 1997/07/27 21:13:30 keil - * New TEI managment - * - * Revision 1.9 1997/06/26 11:18:02 keil - * New managment - * - * Revision 1.8 1997/04/07 22:59:08 keil - * GFP_KERNEL --> GFP_ATOMIC - * - * Revision 1.7 1997/04/06 22:54:03 keil - * Using SKB's - * - * Old log removed/ KKe - * */ #define __NO_VERSION__ #include "hisax.h" #include "isdnl2.h" +#include #include -const char *tei_revision = "$Revision: 2.13 $"; +const char *tei_revision = "$Revision: 2.17 $"; #define ID_REQUEST 1 #define ID_ASSIGNED 2 @@ -90,9 +29,7 @@ #define TEI_ENTITY_ID 0xf -static -struct Fsm teifsm = -{NULL, 0, 0, NULL, NULL}; +static struct Fsm teifsm; void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb); @@ -216,7 +153,7 @@ if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ + if ((ost = findtei(st, tei))) { /* same tei is in use */ if (ri != ost->ma.ri) { st->ma.tei_m.printdebug(&st->ma.tei_m, "possible duplicate assignment tei %d", tei); @@ -243,10 +180,12 @@ if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "foreign identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + if ((ost = findtei(st, tei))) { /* same tei is in use */ + if (ri != ost->ma.ri) { /* and it wasn't our request */ + st->ma.tei_m.printdebug(&st->ma.tei_m, + "possible duplicate assignment tei %d", tei); + FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + } } } @@ -490,7 +429,7 @@ } } -static struct FsmNode TeiFnList[] HISAX_INITDATA = +static struct FsmNode TeiFnList[] __initdata = { {ST_TEI_NOP, EV_IDREQ, tei_id_request}, {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, @@ -507,8 +446,8 @@ #define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode)) -HISAX_INITFUNC(void -TeiNew(void)) +void __init +TeiNew(void) { teifsm.state_count = TEI_STATE_COUNT; teifsm.event_count = TEI_EVENT_COUNT; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c --- v2.2.18/drivers/isdn/hisax/teleint.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/teleint.c Sun Mar 25 11:37:33 2001 @@ -1,53 +1,15 @@ -/* $Id: teleint.c,v 1.12 1999/12/19 13:09:42 keil Exp $ - +/* $Id: teleint.c,v 1.14 2000/11/24 17:05:38 kai Exp $ + * * teleint.c low level stuff for TeleInt isdn cards * * Author Karsten Keil (keil@isdn4linux.de) * - * - * $Log: teleint.c,v $ - * Revision 1.12 1999/12/19 13:09:42 keil - * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for - * signal proof delays - * - * Revision 1.11 1999/09/04 06:20:06 keil - * Changes from kernel set_current_state() - * - * Revision 1.10 1999/08/31 11:20:27 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.9 1999/07/12 21:05:30 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 1.8 1999/07/01 08:12:12 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 1.7 1998/11/15 23:55:26 keil - * changes from 2.0 - * - * Revision 1.6 1998/04/15 16:45:31 keil - * new init code - * - * Revision 1.5 1998/02/02 13:40:47 keil - * fast io - * - * Revision 1.4 1997/11/08 21:35:53 keil - * new l1 init - * - * Revision 1.3 1997/11/06 17:09:30 keil - * New 2.1 init code - * - * Revision 1.2 1997/10/29 18:55:53 keil - * changes for 2.1.60 (irq2dev_map) - * - * Revision 1.1 1997/09/11 17:32:32 keil - * new - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hfc_2bs0.h" @@ -55,7 +17,7 @@ extern const char *CardType[]; -const char *TeleInt_revision = "$Revision: 1.12 $"; +const char *TeleInt_revision = "$Revision: 1.14 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -264,11 +226,11 @@ byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */ save_flags(flags); sti(); - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); cs->hw.hfc.cirm &= ~HFC_RESET; byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } @@ -299,8 +261,8 @@ return(0); } -__initfunc(int -setup_TeleInt(struct IsdnCard *card)) +int __init +setup_TeleInt(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.2.18/drivers/isdn/hisax/teles0.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/teles0.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: teles0.c,v 2.11 1999/12/23 15:09:32 keil Exp $ - +/* $Id: teles0.c,v 2.13 2000/11/24 17:05:38 kai Exp $ + * * teles0.c low level stuff for Teles Memory IO isdn cards * based on the teles driver from Jan den Ouden * @@ -9,54 +9,11 @@ * Fritz Elfert * Beat Doebeli * - * $Log: teles0.c,v $ - * Revision 2.11 1999/12/23 15:09:32 keil - * change email - * - * Revision 2.10 1999/11/14 23:37:03 keil - * new ISA memory mapped IO - * - * Revision 2.9 1999/07/12 21:05:31 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.8 1998/04/15 16:44:28 keil - * new init code - * - * Revision 2.7 1998/03/07 22:57:08 tsbogend - * made HiSax working on Linux/Alpha - * - * Revision 2.6 1998/02/03 23:27:47 keil - * IRQ 9 - * - * Revision 2.5 1998/02/02 13:29:47 keil - * fast io - * - * Revision 2.4 1997/11/08 21:35:54 keil - * new l1 init - * - * Revision 2.3 1997/11/06 17:09:31 keil - * New 2.1 init code - * - * Revision 2.2 1997/10/29 18:55:57 keil - * changes for 2.1.60 (irq2dev_map) - * - * Revision 2.1 1997/07/27 21:47:10 keil - * new interface structures - * - * Revision 2.0 1997/06/26 11:02:43 keil - * New Layer and card interface - * - * Revision 1.8 1997/04/13 19:54:04 keil - * Change in IRQ check delay for SMP - * - * Revision 1.7 1997/04/06 22:54:04 keil - * Using SKB's - * - * removed old log info /KKe + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isdnl1.h" #include "isac.h" @@ -64,7 +21,7 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.11 $"; +const char *teles0_revision = "$Revision: 2.13 $"; #define TELES_IOMEM_SIZE 0x400 #define byteout(addr,val) outb(val,addr) @@ -302,8 +259,8 @@ return(0); } -__initfunc(int -setup_teles0(struct IsdnCard *card)) +int __init +setup_teles0(struct IsdnCard *card) { u_char val; struct IsdnCardState *cs = card->cs; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.2.18/drivers/isdn/hisax/teles3.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/teles3.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: teles3.c,v 2.15 2000/02/03 16:40:10 keil Exp $ - +/* $Id: teles3.c,v 2.17 2000/11/24 17:05:38 kai Exp $ + * * teles3.c low level stuff for Teles 16.3 & PNP isdn cards * * based on the teles driver from Jan den Ouden @@ -10,91 +10,18 @@ * Fritz Elfert * Beat Doebeli * - * $Log: teles3.c,v $ - * Revision 2.15 2000/02/03 16:40:10 keil - * Fix teles pcmcia - * - * Revision 2.14 1999/12/23 15:09:32 keil - * change email - * - * Revision 2.13 1999/08/30 12:01:28 keil - * HW version v1.3 support - * - * Revision 2.12 1999/07/12 21:05:32 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.11 1999/07/01 08:12:14 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.10 1999/02/15 14:37:15 cpetig - * oops, missed something in last commit - * - * Revision 2.9 1999/02/15 14:11:02 cpetig - * fixed a bug with Teles PCMCIA, it doesn't have a config register - * - * Revision 2.8 1998/04/15 16:44:30 keil - * new init code - * - * Revision 2.7 1998/02/02 13:29:48 keil - * fast io - * - * Revision 2.6 1997/11/13 16:22:44 keil - * COMPAQ_ISA reset - * - * Revision 2.5 1997/11/12 15:01:25 keil - * COMPAQ_ISA changes - * - * Revision 2.4 1997/11/08 21:35:56 keil - * new l1 init - * - * Revision 2.3 1997/11/06 17:09:33 keil - * New 2.1 init code - * - * Revision 2.2 1997/10/29 18:55:59 keil - * changes for 2.1.60 (irq2dev_map) - * - * Revision 2.1 1997/07/27 21:47:12 keil - * new interface structures - * - * Revision 2.0 1997/06/26 11:02:46 keil - * New Layer and card interface - * - * Revision 1.11 1997/04/13 19:54:05 keil - * Change in IRQ check delay for SMP - * - * Revision 1.10 1997/04/06 22:54:05 keil - * Using SKB's - * - * Revision 1.9 1997/03/22 02:01:07 fritz - * -Reworked toplevel Makefile. From now on, no different Makefiles - * for standalone- and in-kernel-compilation are needed any more. - * -Added local Rules.make for above reason. - * -Experimental changes in teles3.c for enhanced IRQ-checking with - * 2.1.X and SMP kernels. - * -Removed diffstd-script, same functionality is in stddiff -r. - * -Enhanced scripts std2kern and stddiff. - * - * Revision 1.8 1997/02/23 18:43:55 fritz - * Added support for Teles-Vision. - * - * Revision 1.7 1997/01/28 22:48:33 keil - * fixes for Teles PCMCIA (Christof Petig) - * - * Revision 1.6 1997/01/27 15:52:55 keil - * SMP proof,cosmetics, PCMCIA added - * - * removed old log info /KKe + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.15 $"; +const char *teles3_revision = "$Revision: 2.17 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -327,8 +254,8 @@ return(0); } -__initfunc(int -setup_teles3(struct IsdnCard *card)) +int +setup_teles3(struct IsdnCard *card) { u_char val; struct IsdnCardState *cs = card->cs; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c --- v2.2.18/drivers/isdn/hisax/telespci.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/telespci.c Sun Mar 25 11:37:33 2001 @@ -1,56 +1,25 @@ -/* $Id: telespci.c,v 2.11 1999/12/23 15:09:32 keil Exp $ - +/* $Id: telespci.c,v 2.16.6.3 2001/02/13 10:33:58 kai Exp $ + * * telespci.c low level stuff for Teles PCI isdn cards * * Author Ton van Rosmalen * Karsten Keil (keil@isdn4linux.de) * - * - * $Log: telespci.c,v $ - * Revision 2.11 1999/12/23 15:09:32 keil - * change email - * - * Revision 2.10 1999/11/15 14:20:05 keil - * 64Bit compatibility - * - * Revision 2.9 1999/08/11 21:01:34 keil - * new PCI codefix - * - * Revision 2.8 1999/08/10 16:02:10 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 2.7 1999/07/12 21:05:34 keil - * fix race in IRQ handling - * added watchdog for lost IRQs - * - * Revision 2.6 1999/07/01 08:12:15 keil - * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel - * - * Revision 2.5 1998/11/15 23:55:28 keil - * changes from 2.0 - * - * Revision 2.4 1998/10/05 09:38:08 keil - * Fix register addressing - * - * Revision 2.3 1998/05/25 12:58:26 keil - * HiSax golden code from certification, Don't use !!! - * No leased lines, no X75, but many changes. - * - * Revision 2.1 1998/04/15 16:38:23 keil - * Add S0Box and Teles PCI support - * + * This file is (c) under GNU PUBLIC LICENSE * */ #define __NO_VERSION__ +#include #include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" #include +#include extern const char *CardType[]; -const char *telespci_revision = "$Revision: 2.11 $"; +const char *telespci_revision = "$Revision: 2.16.6.3 $"; #define ZORAN_PO_RQ_PEN 0x02000000 #define ZORAN_PO_WR 0x00800000 @@ -307,14 +276,17 @@ return(0); } -static struct pci_dev *dev_tel __initdata = NULL; +static struct pci_dev *dev_tel __initdata = NULL; -__initfunc(int -setup_telespci(struct IsdnCard *card)) +int __init +setup_telespci(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) @@ -324,16 +296,18 @@ printk(KERN_ERR "TelesPCI: no PCI bus present\n"); return(0); } - if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) { + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { + if (pci_enable_device(dev_tel)) + return(0); cs->irq = dev_tel->irq; if (!cs->irq) { printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); return(0); } - cs->hw.teles0.membase = (u_long) ioremap(dev_tel->base_address[ 0], + cs->hw.teles0.membase = (u_long) ioremap(dev_tel->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK, PAGE_SIZE); printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n", - dev_tel->base_address[ 0], dev_tel->irq); + dev_tel->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK, dev_tel->irq); } else { printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c --- v2.2.18/drivers/isdn/hisax/w6692.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/w6692.c Sun Mar 25 11:37:33 2001 @@ -1,5 +1,5 @@ -/* $Id: w6692.c,v 1.4 2000/03/16 23:24:11 werner Exp $ - +/* $Id: w6692.c,v 1.12.6.3 2001/02/13 10:33:58 kai Exp $ + * * w6692.c Winbond W6692 specific routines * * Author Petr Novak @@ -7,39 +7,17 @@ * * This file is (c) under GNU PUBLIC LICENSE * - * $Log: w6692.c,v $ - * Revision 1.4 2000/03/16 23:24:11 werner - * - * Fixed an additional location - * - * Revision 1.3 2000/03/16 22:41:36 werner - * - * Tried to fix second B-channel problem (still not tested) - * - * Revision 1.2 2000/02/26 00:35:13 keil - * Fix skb freeing in interrupt context - * - * Revision 1.1 1999/09/04 06:28:58 keil - * first revision - * - * - * */ #include +#include #define __NO_VERSION__ #include "hisax.h" #include "w6692.h" #include "isdnl1.h" #include #include - -#define PCI_VEND_ASUSCOM 0x675 -#define PCI_DEV_ASUSCOMPCI1 0x1702 -#ifndef PCI_VENDOR_ID_WINBOND2 -#define PCI_VENDOR_ID_WINBOND2 0x1050 -#endif -#define PCI_DEVICE_W6692 0x6692 +#include /* table entry in the PCI devices list */ typedef struct { @@ -51,18 +29,18 @@ static const PCI_ENTRY id_list[] = { - {PCI_VEND_ASUSCOM, PCI_DEV_ASUSCOMPCI1, "AsusCom", "TA XXX"}, - {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_W6692, "Winbond", "W6692"}, + {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"}, + {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"}, {0, 0, NULL, NULL} }; extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.4 $"; +const char *w6692_revision = "$Revision: 1.12.6.3 $"; #define DBUSY_TIMER_VALUE 80 -static char *W6692Ver[] HISAX_INITDATA = +static char *W6692Ver[] __initdata = {"W6692 V00", "W6692 V01", "W6692 V10", "W6692 V11"}; @@ -256,7 +234,7 @@ if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692B_empty_fifo: incoming packet too large"); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); bcs->hw.w6692.rcvidx = 0; return; } @@ -264,14 +242,14 @@ bcs->hw.w6692.rcvidx += count; save_flags(flags); cli(); - READW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + READW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_empty_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -307,14 +285,14 @@ skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.w6692.count += count; - WRITEW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); + WRITEW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_fill_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -325,13 +303,11 @@ { u_char val; u_char r; - struct BCState *bcs = cs->bcs; + struct BCState *bcs; struct sk_buff *skb; int count; - if (bcs->channel != bchan) - bcs++; /* hardware bchan must match ! */ - + bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1); val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); @@ -418,7 +394,7 @@ bcs->tx_cnt += bcs->hw.w6692.count; bcs->hw.w6692.count = 0; } - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B EXIR %x Lost TX", val); } @@ -732,18 +708,16 @@ } static void -W6692Bmode(struct BCState *bcs, int mode, int bc) +W6692Bmode(struct BCState *bcs, int mode, int bchan) { struct IsdnCardState *cs = bcs->cs; - int bchan = bc; - - bcs->hw.w6692.bchan = bc; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "w6692 %c mode %d ichan %d", - '1' + bchan, mode, bc); + '1' + bchan, mode, bchan); bcs->mode = mode; - bcs->channel = bc; + bcs->channel = bchan; + bcs->hw.w6692.bchan = bchan; switch (mode) { case (L1_MODE_NULL): @@ -885,7 +859,7 @@ return (0); } -HISAX_INITFUNC(void initW6692(struct IsdnCardState *cs, int part)) +void __init initW6692(struct IsdnCardState *cs, int part) { if (part & 1) { cs->tqueue.routine = (void *) (void *) W6692_bh; @@ -912,8 +886,6 @@ cs->bcs[1].BC_SetStack = setstack_w6692; cs->bcs[0].BC_Close = close_w6692state; cs->bcs[1].BC_Close = close_w6692state; - cs->bcs[0].hw.w6692.bchan = 0; - cs->bcs[1].hw.w6692.bchan = 1; W6692Bmode(cs->bcs, 0, 0); W6692Bmode(cs->bcs + 1, 0, 0); } @@ -984,11 +956,12 @@ return (0); } -static int id_idx = 0; +static int id_idx ; static struct pci_dev *dev_w6692 __initdata = NULL; -__initfunc(int setup_w6692(struct IsdnCard *card)) +int __init +setup_w6692(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -996,6 +969,9 @@ u_char pci_irq = 0; u_int pci_ioaddr = 0; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, w6692_revision); printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) @@ -1009,8 +985,11 @@ dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, dev_w6692); - if (dev_w6692) + if (dev_w6692) { + if (pci_enable_device(dev_w6692)) + continue; break; + } id_idx++; } if (dev_w6692) { @@ -1018,7 +997,7 @@ pci_irq = dev_w6692->irq; /* I think address 0 is allways the configuration area */ /* and address 1 is the real IO space KKe 03.09.99 */ - pci_ioaddr = dev_w6692->base_address[ 1]; + pci_ioaddr = dev_w6692->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; } if (!found) { printk(KERN_WARNING "W6692: No PCI card found\n"); @@ -1029,7 +1008,6 @@ printk(KERN_WARNING "W6692: No IRQ for PCI card found\n"); return (0); } - pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK; if (!pci_ioaddr) { printk(KERN_WARNING "W6692: NO I/O Base Address found\n"); return (0); @@ -1069,6 +1047,7 @@ cs->BC_Send_Data = &W6692B_fill_fifo; cs->cardmsg = &w6692_card_msg; cs->irq_func = &W6692_interrupt; + cs->irq_flags |= SA_SHIRQ; W6692Version(cs, "W6692:"); printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA)); printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK)); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hisax/w6692.h linux/drivers/isdn/hisax/w6692.h --- v2.2.18/drivers/isdn/hisax/w6692.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/hisax/w6692.h Sun Mar 25 11:37:33 2001 @@ -1,18 +1,10 @@ -/* $Id: w6692.h,v 1.1 1999/09/04 06:28:58 keil Exp $ - +/* $Id: w6692.h,v 1.2 2000/06/26 08:59:15 keil Exp $ + * * w6692.h Winbond W6692 specific defines * * Author Petr Novak * - * - * $Log: w6692.h,v $ - * Revision 1.1 1999/09/04 06:28:58 keil - * first revision - * - * - * Revision 1.0 1999/08/28 21:58:00 pnovak - * first version - * + * This file is (c) under GNU PUBLIC LICENSE * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/Makefile linux/drivers/isdn/hysdn/Makefile --- v2.2.18/drivers/isdn/hysdn/Makefile Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/Makefile Sun Mar 25 11:37:33 2001 @@ -0,0 +1,29 @@ +# Makefile for the hysdn ISDN device driver + +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Multipart objects. + +list-multi := hysdn.o +hysdn-objs := hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o \ + hysdn_sched.o hysdn_net.o hysdn_init.o + +# Optional parts of multipart objects. + +hysdn-objs-$(CONFIG_HYSDN_CAPI) += hycapi.o + +hysdn-objs += $(hysdn-objs-y) + +# Each configuration option enables a list of files. + +obj-$(CONFIG_HYSDN) += hysdn.o + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +hysdn.o: $(hysdn-objs) + $(LD) -r -o $@ $(hysdn-objs) + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c --- v2.2.18/drivers/isdn/hysdn/boardergo.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/boardergo.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,466 @@ +/* $Id: boardergo.c,v 1.5.6.1 2000/12/10 22:01:04 kai Exp $ + + * Linux driver for HYSDN cards, specific routines for ergo type boards. + * + * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same + * DPRAM interface and layout with only minor differences all related + * stuff is done here, not in separate modules. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" +#include "boardergo.h" + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +/***************************************************/ +/* The cards interrupt handler. Called from system */ +/***************************************************/ +static void +ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + hysdn_card *card = dev_id; /* parameter from irq */ + tErgDpram *dpr; + ulong flags; + uchar volatile b; + + if (!card) + return; /* error -> spurious interrupt */ + if (!card->irq_enabled) + return; /* other device interrupting or irq switched off */ + + save_flags(flags); + cli(); /* no further irqs allowed */ + + if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) { + restore_flags(flags); /* restore old state */ + return; /* no interrupt requested by E1 */ + } + /* clear any pending ints on the board */ + dpr = card->dpram; + b = dpr->ToPcInt; /* clear for ergo */ + b |= dpr->ToPcIntMetro; /* same for metro */ + b |= dpr->ToHyInt; /* and for champ */ + + /* start kernel task immediately after leaving all interrupts */ + if (!card->hw_lock) { + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + restore_flags(flags); +} /* ergo_interrupt */ + +/******************************************************************************/ +/* ergo_irq_bh is the function called by the immediate kernel task list after */ +/* being activated with queue_task and no interrupts active. This task is the */ +/* only one handling data transfer from or to the card after booting. The task */ +/* may be queued from everywhere (interrupts included). */ +/******************************************************************************/ +static void +ergo_irq_bh(hysdn_card * card) +{ + tErgDpram *dpr; + int again; + ulong flags; + + if (card->state != CARD_STATE_RUN) + return; /* invalid call */ + + dpr = card->dpram; /* point to DPRAM */ + + save_flags(flags); + cli(); + if (card->hw_lock) { + restore_flags(flags); /* hardware currently unavailable */ + return; + } + card->hw_lock = 1; /* we now lock the hardware */ + + do { + sti(); /* reenable other ints */ + again = 0; /* assume loop not to be repeated */ + + if (!dpr->ToHyFlag) { + /* we are able to send a buffer */ + + if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel, + ERG_TO_HY_BUF_SIZE)) { + dpr->ToHyFlag = 1; /* enable tx */ + again = 1; /* restart loop */ + } + } /* we are able to send a buffer */ + if (dpr->ToPcFlag) { + /* a message has arrived for us, handle it */ + + if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) { + dpr->ToPcFlag = 0; /* we worked the data */ + again = 1; /* restart loop */ + } + } /* a message has arrived for us */ + cli(); /* no further ints */ + if (again) { + dpr->ToHyInt = 1; + dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ + } else + card->hw_lock = 0; /* free hardware again */ + } while (again); /* until nothing more to do */ + + restore_flags(flags); +} /* ergo_irq_bh */ + + +/*********************************************************/ +/* stop the card (hardware reset) and disable interrupts */ +/*********************************************************/ +static void +ergo_stopcard(hysdn_card * card) +{ + ulong flags; + uchar val; + + hysdn_net_release(card); /* first release the net device if existing */ +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_stop(card); +#endif /* CONFIG_HYSDN_CAPI */ + save_flags(flags); + cli(); + val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ + val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */ + byteout(card->iobase + PCI9050_INTR_REG, val); + card->irq_enabled = 0; + byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */ + card->state = CARD_STATE_UNUSED; + card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */ + + restore_flags(flags); +} /* ergo_stopcard */ + +/**************************************************************************/ +/* enable or disable the cards error log. The event is queued if possible */ +/**************************************************************************/ +static void +ergo_set_errlog_state(hysdn_card * card, int on) +{ + ulong flags; + + if (card->state != CARD_STATE_RUN) { + card->err_log_state = ERRLOG_STATE_OFF; /* must be off */ + return; + } + save_flags(flags); + cli(); + + if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) || + ((card->err_log_state == ERRLOG_STATE_ON) && on)) { + restore_flags(flags); + return; /* nothing to do */ + } + if (on) + card->err_log_state = ERRLOG_STATE_START; /* request start */ + else + card->err_log_state = ERRLOG_STATE_STOP; /* request stop */ + + restore_flags(flags); + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} /* ergo_set_errlog_state */ + +/******************************************/ +/* test the cards RAM and return 0 if ok. */ +/******************************************/ +static const char TestText[36] = "This Message is filler, why read it"; + +static int +ergo_testram(hysdn_card * card) +{ + tErgDpram *dpr = card->dpram; + + memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */ + dpr->ToHyInt = 1; /* E1 INTR state forced */ + + memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText)); + if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText))) + return (-1); + + memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText)); + if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText))) + return (-1); + + return (0); +} /* ergo_testram */ + +/*****************************************************************************/ +/* this function is intended to write stage 1 boot image to the cards buffer */ +/* this is done in two steps. First the 1024 hi-words are written (offs=0), */ +/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */ +/* PCI-write-buffers flushed and the card is taken out of reset. */ +/* The function then waits for a reaction of the E1 processor or a timeout. */ +/* Negative return values are interpreted as errors. */ +/*****************************************************************************/ +static int +ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs) +{ + uchar *dst; + tErgDpram *dpram; + int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */ + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs); + + dst = card->dpram; /* pointer to start of DPRAM */ + dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */ + while (cnt--) { + *dst++ = *(buf + 1); /* high byte */ + *dst++ = *buf; /* low byte */ + dst += 2; /* point to next longword */ + buf += 2; /* buffer only filled with words */ + } + + /* if low words (offs = 2) have been written, clear the rest of the DPRAM, */ + /* flush the PCI-write-buffer and take the E1 out of reset */ + if (offs) { + memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */ + dpram = card->dpram; /* get pointer to dpram structure */ + dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */ + while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */ + + byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */ + /* the interrupts are still masked */ + + sti(); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + + if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) { + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write bootldr no answer"); + return (-ERR_BOOTIMG_FAIL); + } + } /* start_boot_img */ + return (0); /* successfull */ +} /* ergo_writebootimg */ + +/********************************************************************************/ +/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */ +/* using the boot spool mechanism. If everything works fine 0 is returned. In */ +/* case of errors a negative error value is returned. */ +/********************************************************************************/ +static int +ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len) +{ + tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram; + uchar *dst; + uchar buflen; + int nr_write; + uchar tmp_rdptr; + uchar wr_mirror; + int i; + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write boot seq len=%d ", len); + + dst = sp->Data; /* point to data in spool structure */ + buflen = sp->Len; /* maximum len of spooled data */ + wr_mirror = sp->WrPtr; /* only once read */ + sti(); + + /* try until all bytes written or error */ + i = 0x1000; /* timeout value */ + while (len) { + + /* first determine the number of bytes that may be buffered */ + do { + tmp_rdptr = sp->RdPtr; /* first read the pointer */ + i--; /* decrement timeout */ + } while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */ + + if (!i) { + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write boot seq timeout"); + return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */ + } + if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0) + nr_write += buflen; /* now we got number of free bytes - 1 in buffer */ + + if (!nr_write) + continue; /* no free bytes in buffer */ + + if (nr_write > len) + nr_write = len; /* limit if last few bytes */ + i = 0x1000; /* reset timeout value */ + + /* now we know how much bytes we may put in the puffer */ + len -= nr_write; /* we savely could adjust len before output */ + while (nr_write--) { + *(dst + wr_mirror) = *buf++; /* output one byte */ + if (++wr_mirror >= buflen) + wr_mirror = 0; + sp->WrPtr = wr_mirror; /* announce the next byte to E1 */ + } /* while (nr_write) */ + + } /* while (len) */ + return (0); +} /* ergo_writebootseq */ + +/***********************************************************************************/ +/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */ +/* boot process. If the process has been successfull 0 is returned otherwise a */ +/* negative error code is returned. */ +/***********************************************************************************/ +static int +ergo_waitpofready(struct HYSDN_CARD *card) +{ + tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */ + int timecnt = 10000 / 50; /* timeout is 10 secs max. */ + ulong flags; + int msg_size; + int i; + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: waiting for pof ready"); + while (timecnt--) { + /* wait until timeout */ + + if (dpr->ToPcFlag) { + /* data has arrived */ + + if ((dpr->ToPcChannel != CHAN_SYSTEM) || + (dpr->ToPcSize < MIN_RDY_MSG_SIZE) || + (dpr->ToPcSize > MAX_RDY_MSG_SIZE) || + ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC)) + break; /* an error occured */ + + /* Check for additional data delivered during SysReady */ + msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE; + if (msg_size > 0) + if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size)) + break; + + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "ERGO: pof boot success"); + save_flags(flags); + cli(); + + card->state = CARD_STATE_RUN; /* now card is running */ + /* enable the cards interrupt */ + byteout(card->iobase + PCI9050_INTR_REG, + bytein(card->iobase + PCI9050_INTR_REG) | + (PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1)); + card->irq_enabled = 1; /* we are ready to receive interrupts */ + + dpr->ToPcFlag = 0; /* reset data indicator */ + dpr->ToHyInt = 1; + dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ + + restore_flags(flags); + if ((i = hysdn_net_create(card))) { + ergo_stopcard(card); + card->state = CARD_STATE_BOOTERR; + return (i); + } +#ifdef CONFIG_HYSDN_CAPI + if((i = hycapi_capi_create(card))) { + printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n"); + } +#endif /* CONFIG_HYSDN_CAPI */ + return (0); /* success */ + } /* data has arrived */ + sti(); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((50 * HZ) / 1000); /* Timeout 50ms */ + } /* wait until timeout */ + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: pof boot ready timeout"); + return (-ERR_POF_TIMEOUT); +} /* ergo_waitpofready */ + + + +/************************************************************************************/ +/* release the cards hardware. Before releasing do a interrupt disable and hardware */ +/* reset. Also unmap dpram. */ +/* Use only during module release. */ +/************************************************************************************/ +static void +ergo_releasehardware(hysdn_card * card) +{ + ergo_stopcard(card); /* first stop the card if not already done */ + free_irq(card->irq, card); /* release interrupt */ + release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */ + release_region(card->iobase + PCI9050_USER_IO, 1); + vfree(card->dpram); + card->dpram = NULL; /* release shared mem */ +} /* ergo_releasehardware */ + + +/*********************************************************************************/ +/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */ +/* value is returned. */ +/* Use only during module init. */ +/*********************************************************************************/ +int +ergo_inithardware(hysdn_card * card) +{ + if (check_region(card->iobase + PCI9050_INTR_REG, 1) || + check_region(card->iobase + PCI9050_USER_IO, 1)) + return (-1); /* ports already in use */ + + card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1; + if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE))) + return (-1); + + request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN"); + request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN"); + ergo_stopcard(card); /* disable interrupts */ + if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) { + ergo_releasehardware(card); /* return the acquired hardware */ + return (-1); + } + /* success, now setup the function pointers */ + card->stopcard = ergo_stopcard; + card->releasehardware = ergo_releasehardware; + card->testram = ergo_testram; + card->writebootimg = ergo_writebootimg; + card->writebootseq = ergo_writebootseq; + card->waitpofready = ergo_waitpofready; + card->set_errlog_state = ergo_set_errlog_state; + card->irq_queue.sync = 0; + card->irq_queue.data = card; /* init task queue for interrupt */ + card->irq_queue.routine = (void *) (void *) ergo_irq_bh; + + return (0); +} /* ergo_inithardware */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/boardergo.h linux/drivers/isdn/hysdn/boardergo.h --- v2.2.18/drivers/isdn/hysdn/boardergo.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/boardergo.h Sun Mar 25 11:37:33 2001 @@ -0,0 +1,112 @@ +/* $Id: boardergo.h,v 1.2 2000/11/13 22:51:47 kai Exp $ + + * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..). + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +/************************************************/ +/* defines for the dual port memory of the card */ +/************************************************/ +#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */ +#define BOOT_IMG_SIZE 4096 +#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE) + +#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */ +#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */ + +/* following DPRAM layout copied from OS2-driver boarderg.h */ +typedef struct ErgDpram_tag { +/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE]; +/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE]; + + /*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART]; + /* size 0x1B0 */ + + /*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64]; + /* size 64 bytes */ + /*1DB0 ulong ulErrType; */ + /*1DB4 ulong ulErrSubtype; */ + /*1DB8 ulong ucTextSize; */ + /*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */ + /*1DF0 */ + +/*1DF0 */ word volatile ToHyChannel; +/*1DF2 */ word volatile ToHySize; + /*1DF4 */ uchar volatile ToHyFlag; + /* !=0: msg for Hy waiting */ + /*1DF5 */ uchar volatile ToPcFlag; + /* !=0: msg for PC waiting */ +/*1DF6 */ word volatile ToPcChannel; +/*1DF8 */ word volatile ToPcSize; + /*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA]; + /* 6 bytes */ + +/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00]; +/*1F00 */ ulong TrapTable[62]; + /*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8]; + /* low part of reset vetor */ +/*1FFB */ uchar ToPcIntMetro; + /* notes: + * - metro has 32-bit boot ram - accessing + * ToPcInt and ToHyInt would be the same; + * so we moved ToPcInt to 1FFB. + * Because on the PC side both vars are + * readonly (reseting on int from E1 to PC), + * we can read both vars on both cards + * without destroying anything. + * - 1FFB is the high byte of the reset vector, + * so E1 side should NOT change this byte + * when writing! + */ +/*1FFC */ uchar volatile ToHyNoDpramErrLog; + /* note: ToHyNoDpramErrLog is used to inform + * boot loader, not to use DPRAM based + * ErrLog; when DOS driver is rewritten + * this becomes obsolete + */ +/*1FFD */ uchar bRes1FFD; + /*1FFE */ uchar ToPcInt; + /* E1_intclear; on CHAMP2: E1_intset */ + /*1FFF */ uchar ToHyInt; + /* E1_intset; on CHAMP2: E1_intclear */ +} tErgDpram; + +/**********************************************/ +/* PCI9050 controller local register offsets: */ +/* copied from boarderg.c */ +/**********************************************/ +#define PCI9050_INTR_REG 0x4C /* Interrupt register */ +#define PCI9050_USER_IO 0x51 /* User I/O register */ + + /* bitmask for PCI9050_INTR_REG: */ +#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */ +#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */ +#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */ +#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */ + + /* bitmask for PCI9050_USER_IO: */ +#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */ +#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */ +#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */ + +#define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */ +#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c --- v2.2.18/drivers/isdn/hysdn/hycapi.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hycapi.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,839 @@ +/* $Id: hycapi.c,v 1.8 2000/11/22 17:13:13 kai Exp $ + * + * Linux driver for HYSDN cards, CAPI2.0-Interface. + * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH + * + * Copyright 2000 by Hypercope GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include + + +#define VER_DRIVER 0 +#define VER_CARDTYPE 1 +#define VER_HWID 2 +#define VER_SERIAL 3 +#define VER_OPTION 4 +#define VER_PROTO 5 +#define VER_PROFILE 6 +#define VER_CAPI 7 + +#include "hysdn_defs.h" +#include + +static char hycapi_revision[]="$Revision: 1.8 $"; + +typedef struct _hycapi_appl { + unsigned int ctrl_mask; + capi_register_params rp; + struct sk_buff *listen_req[CAPI_MAXCONTR]; +} hycapi_appl; + +static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; + +static inline int _hycapi_appCheck(int app_id, int ctrl_no) +{ + if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || + (app_id > CAPI_MAXAPPL)) + { + printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no); + return -1; + } + return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0); +} + +struct capi_driver_interface *hy_di = NULL; + +/****************************** +Kernel-Capi callback reset_ctr +******************************/ + +void +hycapi_reset_ctr(struct capi_ctr *ctrl) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); +#endif + ctrl->reseted(ctrl); +} + +/****************************** +Kernel-Capi callback remove_ctr +******************************/ + +void +hycapi_remove_ctr(struct capi_ctr *ctrl) +{ + int i; + hycapictrl_info *cinfo = NULL; + hysdn_card *card = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n"); +#endif + if(!hy_di) { + printk(KERN_ERR "No capi_driver_interface set!"); + return; + } + cinfo = (hycapictrl_info *)(ctrl->driverdata); + if(!cinfo) { + printk(KERN_ERR "No hycapictrl_info set!"); + return; + } + card = cinfo->card; + ctrl->suspend_output(ctrl); + for(i=0; icnr-1]) { + kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]); + hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL; + } + } + hy_di->detach_ctr(ctrl); + ctrl->driverdata = 0; + kfree(card->hyctrlinfo); + + + card->hyctrlinfo = NULL; +} + +/*********************************************************** + +Queue a CAPI-message to the controller. + +***********************************************************/ + +static void +hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + + spin_lock_irq(&cinfo->lock); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_send_message\n"); +#endif + cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */ + if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->in_idx = 0; /* wrap around */ + cinfo->sk_count++; /* adjust counter */ + if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) { + /* inform upper layers we're full */ + printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n", + card->myid); + ctrl->suspend_output(ctrl); + } + cinfo->tx_skb = skb; + spin_unlock_irq(&cinfo->lock); + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/*********************************************************** +hycapi_register_internal + +Send down the CAPI_REGISTER-Command to the controller. +This functions will also be used if the adapter has been rebooted to +re-register any applications in the private list. + +************************************************************/ + +static void +hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*"; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa0, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; + __u16 MessageBufferSize = 0; + int slen = strlen(ExtFeatureDefaults); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_register_appl\n"); +#endif + MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen; + + len = CAPI_MSG_BASELEN + 8 + slen + 1; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16)); + memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen); + hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1)); + hycapi_send_message(ctrl, skb); +} + +/************************************************************ +hycapi_restart_internal + +After an adapter has been rebootet, re-register all applications and +send a LISTEN_REQ (if there has been such a thing ) + +*************************************************************/ + +static void hycapi_restart_internal(struct capi_ctr *ctrl) +{ + int i; + struct sk_buff *skb; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_WARNING "HYSDN: hycapi_restart_internal"); +#endif + for(i=0; icnr) == 1) { + hycapi_register_internal(ctrl, i+1, + &hycapi_applications[i].rp); + if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { + skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC); + hycapi_sendmsg_internal(ctrl, skb); + } + } + } +} + +/************************************************************* +Register an application. +Error-checking is done for CAPI-compliance. + +The application is recorded in the internal list. +*************************************************************/ + +void +hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk < 0) { + return; + } + if(chk == 1) { + printk(KERN_INFO "HYSDN: apl %d allready registered\n", appl); + return; + } + MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt; + rp->datablkcnt = MaxBDataBlocks; + MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ; + rp->datablklen = MaxBDataLen; + + MaxLogicalConnections = rp->level3cnt; + if (MaxLogicalConnections < 0) { + MaxLogicalConnections = card->bchans * -MaxLogicalConnections; + } + if (MaxLogicalConnections == 0) { + MaxLogicalConnections = card->bchans; + } + + rp->level3cnt = MaxLogicalConnections; + memcpy(&hycapi_applications[appl-1].rp, + rp, sizeof(capi_register_params)); + +/* MOD_INC_USE_COUNT; */ + ctrl->appl_registered(ctrl, appl); +} + +/********************************************************************* + +hycapi_release_internal + +Send down a CAPI_RELEASE to the controller. +*********************************************************************/ + +static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa1, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_release_appl\n"); +#endif + len = CAPI_MSG_BASELEN; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + hycapi_send_message(ctrl, skb); + hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1)); +} + +/****************************************************************** +hycapi_release_appl + +Release the application from the internal list an remove it's +registration at controller-level +******************************************************************/ + +void +hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + int chk; + + chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk<0) { + printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr); + return; + } + if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) { + kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL; + } + if(chk == 1) + { + hycapi_release_internal(ctrl, appl); + } + ctrl->appl_released(ctrl, appl); +/* MOD_DEC_USE_COUNT; */ +} + + +/************************************************************** +Kill a single controller. +**************************************************************/ + +int hycapi_capi_release(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_release\n"); +#endif + if(cinfo) { + ctrl = cinfo->capi_ctrl; + hycapi_remove_ctr(ctrl); + } + return 0; +} + +/************************************************************** +hycapi_capi_stop + +Stop CAPI-Output on a card. (e.g. during reboot) +***************************************************************/ + +int hycapi_capi_stop(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_stop\n"); +#endif + if(cinfo) { + if(cinfo->capi_ctrl) { + ctrl = cinfo->capi_ctrl; +/* ctrl->suspend_output(ctrl); */ + ctrl->reseted(ctrl); + + } else { + printk(KERN_NOTICE "hycapi_capi_stop: cinfo but no capi_ctrl\n"); + } + } + return 0; +} + +/*************************************************************** +hycapi_send_message + +Send a message to the controller. + +Messages are parsed for their Command/Subcommand-type, and appropriate +action's are performed. + +Note that we have to muck around with a 64Bit-DATA_REQ as there are +firmware-releases that do not check the MsgLen-Indication! + +***************************************************************/ + +void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + __u16 appl_id; + int _len, _len2; + __u8 msghead[64]; + + appl_id = CAPIMSG_APPID(skb->data); + switch(_hycapi_appCheck(appl_id, ctrl->cnr)) + { + case 0: +/* printk(KERN_INFO "Need to register\n"); */ + hycapi_register_internal(ctrl, + appl_id, + &(hycapi_applications[appl_id-1].rp)); + break; + case 1: + break; + default: + printk(KERN_ERR "HYCAPI: Controller mixup!\n"); + return; + } + switch(CAPIMSG_CMD(skb->data)) { + case CAPI_DISCONNECT_B3_RESP: + ctrl->free_ncci(ctrl, appl_id, + CAPIMSG_NCCI(skb->data)); + break; + case CAPI_DATA_B3_REQ: + _len = CAPIMSG_LEN(skb->data); + if (_len > 22) { + _len2 = _len - 22; + memcpy(msghead, skb->data, 22); + memcpy(skb->data + _len2, msghead, 22); + skb_pull(skb, _len2); + CAPIMSG_SETLEN(skb->data, 22); + } + break; + case CAPI_LISTEN_REQ: + if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]) + { + kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL; + } + if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC))) + { + printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n"); + } + break; + default: + break; + } + hycapi_sendmsg_internal(ctrl, skb); +} + +/********************************************************************* +hycapi_read_proc + +Informations provided in the /proc/capi-entries. + +*********************************************************************/ + +int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int len = 0; + char *s; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_read_proc\n"); +#endif + len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + + switch (card->brdtype) { + case BD_PCCARD: s = "HYSDN Hycard"; break; + case BD_ERGO: s = "HYSDN Ergo2"; break; + case BD_METRO: s = "HYSDN Metro4"; break; + case BD_CHAMP2: s = "HYSDN Champ2"; break; + case BD_PLEXUS: s = "HYSDN Plexus30"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if ((s = cinfo->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = cinfo->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = cinfo->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/************************************************************** +hycapi_load_firmware + +This does NOT load any firmware, but the callback somehow is needed +on capi-interface registration. + +**************************************************************/ + +int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_load_firmware\n"); +#endif + return 0; +} + + +char *hycapi_procinfo(struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_proc_info\n"); +#endif + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d %s", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->iobase : 0x0, + cinfo->card ? cinfo->card->irq : 0, + hycapi_revision + ); + return cinfo->infobuf; +} + +/****************************************************************** +hycapi_rx_capipkt + +Recieve a capi-message. + +All B3_DATA_IND are converted to 64K-extension compatible format. +New nccis are created if neccessary. +*******************************************************************/ + +void +hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len) +{ + struct sk_buff *skb; + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; + __u16 ApplId; + __u16 MsgLen, info; + __u16 len2, CapiCmd; + __u32 CP64[2] = {0,0}; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_rx_capipkt\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no HYCAPI-controller!\n", + card->myid); + return; + } + ctrl = cinfo->capi_ctrl; + if(!ctrl) + { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (1)!\n", + card->myid); + return; + } + if(len < CAPI_MSG_BASELEN) { + printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n", + card->myid, len); + return; + } + MsgLen = CAPIMSG_LEN(buf); + ApplId = CAPIMSG_APPID(buf); + CapiCmd = CAPIMSG_CMD(buf); + + if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) { + len2 = len + (30 - MsgLen); + if (!(skb = alloc_skb(len2, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, MsgLen), buf, MsgLen); + memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32)); + memcpy(skb_put(skb, len - MsgLen), buf + MsgLen, + len - MsgLen); + CAPIMSG_SETLEN(skb->data, 30); + } else { + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, len), buf, len); + } + switch(CAPIMSG_CMD(skb->data)) + { + case CAPI_CONNECT_B3_CONF: +/* Check info-field for error-indication: */ + info = CAPIMSG_U16(skb->data, 12); + switch(info) + { + case 0: + ctrl->new_ncci(ctrl, ApplId, CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + + break; + case 0x0001: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current " + "protocol. NCPI ignored.\n", card->myid); + break; + case 0x2001: + printk(KERN_ERR "HYSDN Card%d: Message not supported in" + " current state\n", card->myid); + break; + case 0x2002: + printk(KERN_ERR "HYSDN Card%d: illegal PLCI\n", card->myid); + break; + case 0x2004: + printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid); + break; + case 0x3008: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n", + card->myid); + break; + default: + printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n", + card->myid, info); + break; + } + break; + case CAPI_CONNECT_B3_IND: + ctrl->new_ncci(ctrl, ApplId, + CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + break; + default: + break; + } + ctrl->handle_capimsg(ctrl, ApplId, skb); +} + +/****************************************************************** +hycapi_tx_capiack + +Internally acknowledge a msg sent. This will remove the msg from the +internal queue. + +*******************************************************************/ + +void hycapi_tx_capiack(hysdn_card * card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_tx_capiack\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (2)!\n", + card->myid); + return; + } + spin_lock_irq(&cinfo->lock); + kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */ + cinfo->skbs[cinfo->out_idx++] = NULL; + if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->out_idx = 0; /* wrap around */ + + if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */ + cinfo->capi_ctrl->resume_output(cinfo->capi_ctrl); + spin_unlock_irq(&cinfo->lock); +} + +/*************************************************************** +hycapi_tx_capiget(hysdn_card *card) + +This is called when polling for messages to SEND. + +****************************************************************/ + +struct sk_buff * +hycapi_tx_capiget(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller! (3)\n", + card->myid); + return (struct sk_buff *)NULL; + } + if (!cinfo->sk_count) + return (struct sk_buff *)NULL; /* nothing available */ + + return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */ +} + + +static struct capi_driver hycapi_driver = { + "hysdn", + "0.0", + hycapi_load_firmware, + hycapi_reset_ctr, + hycapi_remove_ctr, + hycapi_register_appl, + hycapi_release_appl, + hycapi_send_message, + hycapi_procinfo, + hycapi_read_proc, + 0, /* use standard driver_read_proc */ + 0, /* no add_card function */ +}; + + +/********************************************************** +int hycapi_init() + +attach the capi-driver to the kernel-capi. + +***********************************************************/ + +int hycapi_init() +{ + struct capi_driver *driver; + int i; + if(hy_di) { + printk(KERN_NOTICE "HyDI allready set\n"); + return 0; + } + driver = &hycapi_driver; + printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n"); + hy_di = attach_capi_driver(driver); + if (!hy_di) { + printk(KERN_ERR "HYCAPI: failed to attach capi_driver\n"); + return(-1); + } + for(i=0;ihyctrlinfo; + if(!cinfo) return; + ctrl = cinfo->capi_ctrl; + if(!ctrl) return; + strcpy(ctrl->manu, "Hypercope"); + ctrl->version.majorversion = 2; + ctrl->version.minorversion = 0; + ctrl->version.majormanuversion = 3; + ctrl->version.minormanuversion = 2; + ctrl->profile.ncontroller = card->myid; + ctrl->profile.nbchannel = card->bchans; + ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER | + GLOBAL_OPTION_B_CHANNEL_OPERATION; + ctrl->profile.support1 = B1_PROT_64KBIT_HDLC | + (card->faxchans ? B1_PROT_T30 : 0) | + B1_PROT_64KBIT_TRANSPARENT; + ctrl->profile.support2 = B2_PROT_ISO7776 | + (card->faxchans ? B2_PROT_T30 : 0) | + B2_PROT_TRANSPARENT; + ctrl->profile.support3 = B3_PROT_TRANSPARENT | + B3_PROT_T90NL | + (card->faxchans ? B3_PROT_T30 : 0) | + (card->faxchans ? B3_PROT_T30EXT : 0) | + B3_PROT_ISO8208; +} + +int +hycapi_capi_create(hysdn_card *card) +{ + hycapictrl_info *cinfo = NULL; + struct capi_ctr *ctrl = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_create\n"); +#endif + if (!card->hyctrlinfo) { + cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n"); + return -ENOMEM; + } + memset(cinfo, 0, sizeof(hycapictrl_info)); + card->hyctrlinfo = cinfo; + cinfo->card = card; + spin_lock_init(&cinfo->lock); + + switch (card->brdtype) { + case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break; + case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break; + case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break; + case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break; + case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break; + default: strcpy(cinfo->cardname,"HYSDN ???"); break; + } + + cinfo->capi_ctrl = hy_di->attach_ctr(&hycapi_driver, + cinfo->cardname, cinfo); + ctrl = cinfo->capi_ctrl; + if (!ctrl) { + printk(KERN_ERR "%s: attach controller failed.\n", + hycapi_driver.name); + return -EBUSY; + } + /* fill in the blanks: */ + hycapi_fill_profile(card); + ctrl->ready(ctrl); + } else { + /* resume output on stopped ctrl */ + ctrl = card->hyctrlinfo->capi_ctrl; + if(ctrl) { + hycapi_fill_profile(card); + ctrl->ready(ctrl); + hycapi_restart_internal(ctrl); +/* ctrl->resume_output(ctrl); */ + } else { + printk(KERN_WARNING "HYSDN: No ctrl???? How come?\n"); + } + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_boot.c linux/drivers/isdn/hysdn/hysdn_boot.c --- v2.2.18/drivers/isdn/hysdn/hysdn_boot.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_boot.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,413 @@ +/* $Id: hysdn_boot.c,v 1.4.6.1 2001/02/10 14:41:22 kai Exp $ + + * Linux driver for HYSDN cards, specific routines for booting and pof handling. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" +#include "hysdn_pof.h" + +/********************************/ +/* defines for pof read handler */ +/********************************/ +#define POF_READ_FILE_HEAD 0 +#define POF_READ_TAG_HEAD 1 +#define POF_READ_TAG_DATA 2 + +/************************************************************/ +/* definition of boot specific data area. This data is only */ +/* needed during boot and so allocated dynamically. */ +/************************************************************/ +struct boot_data { + word Cryptor; /* for use with Decrypt function */ + word Nrecs; /* records remaining in file */ + uchar pof_state; /* actual state of read handler */ + uchar is_crypted; /* card data is crypted */ + int BufSize; /* actual number of bytes bufferd */ + int last_error; /* last occured error */ + word pof_recid; /* actual pof recid */ + ulong pof_reclen; /* total length of pof record data */ + ulong pof_recoffset; /* actual offset inside pof record */ + union { + uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */ + tPofRecHdr PofRecHdr; /* header for actual record/chunk */ + tPofFileHdr PofFileHdr; /* header from POF file */ + tPofTimeStamp PofTime; /* time information */ + } buf; +}; + +/*****************************************************/ +/* start decryption of sucessive POF file chuncks. */ +/* */ +/* to be called at start of POF file reading, */ +/* before starting any decryption on any POF record. */ +/*****************************************************/ +void +StartDecryption(struct boot_data *boot) +{ + boot->Cryptor = CRYPT_STARTTERM; +} /* StartDecryption */ + + +/***************************************************************/ +/* decrypt complete BootBuf */ +/* NOTE: decryption must be applied to all or none boot tags - */ +/* to HI and LO boot loader and (all) seq tags, because */ +/* global Cryptor is started for whole POF. */ +/***************************************************************/ +void +DecryptBuf(struct boot_data *boot, int cnt) +{ + uchar *bufp = boot->buf.BootBuf; + + while (cnt--) { + boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0); + *bufp++ ^= (uchar) boot->Cryptor; + } +} /* DecryptBuf */ + +/********************************************************************************/ +/* pof_handle_data executes the required actions dependant on the active record */ +/* id. If successfull 0 is returned, a negative value shows an error. */ +/********************************************************************************/ +static int +pof_handle_data(hysdn_card * card, int datlen) +{ + struct boot_data *boot = card->boot; /* pointer to boot specific data */ + long l; + uchar *imgp; + int img_len; + + /* handle the different record types */ + switch (boot->pof_recid) { + + case TAG_TIMESTMP: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText); + break; + + case TAG_CBOOTDTA: + DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ + case TAG_BOOTDTA: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", + (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA", + datlen, boot->pof_recoffset); + + if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) { + boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */ + return (boot->last_error); + } + imgp = boot->buf.BootBuf; /* start of buffer */ + img_len = datlen; /* maximum length to transfer */ + + l = POF_BOOT_LOADER_OFF_IN_PAGE - + (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1)); + if (l > 0) { + /* buffer needs to be truncated */ + imgp += l; /* advance pointer */ + img_len -= l; /* adjust len */ + } + /* at this point no special handling for data wrapping over buffer */ + /* is necessary, because the boot image always will be adjusted to */ + /* match a page boundary inside the buffer. */ + /* The buffer for the boot image on the card is filled in 2 cycles */ + /* first the 1024 hi-words are put in the buffer, then the low 1024 */ + /* word are handled in the same way with different offset. */ + + if (img_len > 0) { + /* data available for copy */ + if ((boot->last_error = + card->writebootimg(card, imgp, + (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0) + return (boot->last_error); + } + break; /* end of case boot image hi/lo */ + + case TAG_CABSDATA: + DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ + case TAG_ABSDATA: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", + (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA", + datlen, boot->pof_recoffset); + + if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0)) + return (boot->last_error); /* error writing data */ + + if (boot->pof_recoffset + datlen >= boot->pof_reclen) + return (card->waitpofready(card)); /* data completely spooled, wait for ready */ + + break; /* end of case boot seq data */ + + default: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid, + datlen, boot->pof_recoffset); + + break; /* simply skip record */ + } /* switch boot->pof_recid */ + + return (0); +} /* pof_handle_data */ + + +/******************************************************************************/ +/* pof_write_buffer is called when the buffer has been filled with the needed */ +/* number of data bytes. The number delivered is additionally supplied for */ +/* verification. The functions handles the data and returns the needed number */ +/* of bytes for the next action. If the returned value is 0 or less an error */ +/* occured and booting must be aborted. */ +/******************************************************************************/ +int +pof_write_buffer(hysdn_card * card, int datlen) +{ + struct boot_data *boot = card->boot; /* pointer to boot specific data */ + + if (!boot) + return (-EFAULT); /* invalid call */ + if (boot->last_error < 0) + return (boot->last_error); /* repeated error */ + + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: got %d bytes ", datlen); + + switch (boot->pof_state) { + case POF_READ_FILE_HEAD: + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: checking file header"); + + if (datlen != sizeof(tPofFileHdr)) { + boot->last_error = -EPOF_INTERNAL; + break; + } + if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) { + boot->last_error = -EPOF_BAD_MAGIC; + break; + } + /* Setup the new state and vars */ + boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */ + boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ + boot->last_error = sizeof(tPofRecHdr); /* new length */ + break; + + case POF_READ_TAG_HEAD: + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: checking tag header"); + + if (datlen != sizeof(tPofRecHdr)) { + boot->last_error = -EPOF_INTERNAL; + break; + } + boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */ + boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */ + boot->pof_recoffset = 0; /* no starting offset */ + + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ", + boot->pof_recid, boot->pof_reclen); + + boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */ + if (boot->pof_reclen < BOOT_BUF_SIZE) + boot->last_error = boot->pof_reclen; /* limit size */ + else + boot->last_error = BOOT_BUF_SIZE; /* maximum */ + + if (!boot->last_error) { /* no data inside record */ + boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ + boot->last_error = sizeof(tPofRecHdr); /* new length */ + } + break; + + case POF_READ_TAG_DATA: + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: getting tag data"); + + if (datlen != boot->last_error) { + boot->last_error = -EPOF_INTERNAL; + break; + } + if ((boot->last_error = pof_handle_data(card, datlen)) < 0) + return (boot->last_error); /* an error occured */ + boot->pof_recoffset += datlen; + if (boot->pof_recoffset >= boot->pof_reclen) { + boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ + boot->last_error = sizeof(tPofRecHdr); /* new length */ + } else { + if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE) + boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */ + else + boot->last_error = BOOT_BUF_SIZE; /* maximum */ + } + break; + + default: + boot->last_error = -EPOF_INTERNAL; /* unknown state */ + break; + } /* switch (boot->pof_state) */ + + return (boot->last_error); +} /* pof_write_buffer */ + + +/*******************************************************************************/ +/* pof_write_open is called when an open for boot on the cardlog device occurs. */ +/* The function returns the needed number of bytes for the next operation. If */ +/* the returned number is less or equal 0 an error specified by this code */ +/* occurred. Additionally the pointer to the buffer data area is set on success */ +/*******************************************************************************/ +int +pof_write_open(hysdn_card * card, uchar ** bufp) +{ + struct boot_data *boot; /* pointer to boot specific data */ + + if (card->boot) { + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF open: already opened for boot"); + return (-ERR_ALREADY_BOOT); /* boot already active */ + } + /* error no mem available */ + if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) { + if (card->debug_flags & LOG_MEM_ERR) + hysdn_addlog(card, "POF open: unable to allocate mem"); + return (-EFAULT); + } + card->boot = boot; + card->state = CARD_STATE_BOOTING; + memset(boot, 0, sizeof(struct boot_data)); + + card->stopcard(card); /* first stop the card */ + if (card->testram(card)) { + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF open: DPRAM test failure"); + boot->last_error = -ERR_BOARD_DPRAM; + card->state = CARD_STATE_BOOTERR; /* show boot error */ + return (boot->last_error); + } + boot->BufSize = 0; /* Buffer is empty */ + boot->pof_state = POF_READ_FILE_HEAD; /* read file header */ + StartDecryption(boot); /* if POF File should be encrypted */ + + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF open: success"); + + *bufp = boot->buf.BootBuf; /* point to buffer */ + return (sizeof(tPofFileHdr)); +} /* pof_write_open */ + +/********************************************************************************/ +/* pof_write_close is called when an close of boot on the cardlog device occurs. */ +/* The return value must be 0 if everything has happened as desired. */ +/********************************************************************************/ +int +pof_write_close(hysdn_card * card) +{ + struct boot_data *boot = card->boot; /* pointer to boot specific data */ + + if (!boot) + return (-EFAULT); /* invalid call */ + + card->boot = NULL; /* no boot active */ + kfree(boot); + + if (card->state == CARD_STATE_RUN) + card->set_errlog_state(card, 1); /* activate error log */ + + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF close: success"); + + return (0); +} /* pof_write_close */ + +/*********************************************************************************/ +/* EvalSysrTokData checks additional records delivered with the Sysready Message */ +/* when POF has been booted. A return value of 0 is used if no error occured. */ +/*********************************************************************************/ +int +EvalSysrTokData(hysdn_card * card, uchar * cp, int len) +{ + u_char *p; + u_char crc; + + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "SysReady Token data length %d", len); + + if (len < 2) { + hysdn_addlog(card, "SysReady Token Data to short"); + return (1); + } + for (p = cp, crc = 0; p < (cp + len - 2); p++) + if ((crc & 0x80)) + crc = (((u_char) (crc << 1)) + 1) + *p; + else + crc = ((u_char) (crc << 1)) + *p; + crc = ~crc; + if (crc != *(cp + len - 1)) { + hysdn_addlog(card, "SysReady Token Data invalid CRC"); + return (1); + } + len--; /* dont check CRC byte */ + while (len > 0) { + + if (*cp == SYSR_TOK_END) + return (0); /* End of Token stream */ + + if (len < (*(cp + 1) + 2)) { + hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1)); + return (1); + } + switch (*cp) { + case SYSR_TOK_B_CHAN: /* 1 */ + if (*(cp + 1) != 1) + return (1); /* length invalid */ + card->bchans = *(cp + 2); + break; + + case SYSR_TOK_FAX_CHAN: /* 2 */ + if (*(cp + 1) != 1) + return (1); /* length invalid */ + card->faxchans = *(cp + 2); + break; + + case SYSR_TOK_MAC_ADDR: /* 3 */ + if (*(cp + 1) != 6) + return (1); /* length invalid */ + memcpy(card->mac_addr, cp + 2, 6); + break; + + default: + hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1)); + break; + } + len -= (*(cp + 1) + 2); /* adjust len */ + cp += (*(cp + 1) + 2); /* and pointer */ + } + + hysdn_addlog(card, "no end token found"); + return (1); +} /* EvalSysrTokData */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_defs.h linux/drivers/isdn/hysdn/hysdn_defs.h --- v2.2.18/drivers/isdn/hysdn/hysdn_defs.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_defs.h Sun Mar 25 11:37:33 2001 @@ -0,0 +1,307 @@ +/* $Id: hysdn_defs.h,v 1.5.6.1 2000/11/28 12:02:47 kai Exp $ + + * Linux driver for HYSDN cards, global definitions and exported vars and functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef HYSDN_DEFS_H +#define HYSDN_DEFS_H + +#include +#include +#include +#include +#include +#include + +/****************************/ +/* storage type definitions */ +/****************************/ +#define uchar unsigned char +#define uint unsigned int +#define ulong unsigned long +#define word unsigned short + +#include "ince1pc.h" + +#ifdef CONFIG_HYSDN_CAPI +#include +#include "../avmb1/capicmd.h" +#include "../avmb1/capiutil.h" +#include "../avmb1/capilli.h" + +/***************************/ +/* CAPI-Profile values. */ +/***************************/ + +#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001 +#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002 +#define GLOBAL_OPTION_HANDSET 0x0004 +#define GLOBAL_OPTION_DTMF 0x0008 +#define GLOBAL_OPTION_SUPPL_SERVICES 0x0010 +#define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020 +#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040 + +#define B1_PROT_64KBIT_HDLC 0x0001 +#define B1_PROT_64KBIT_TRANSPARENT 0x0002 +#define B1_PROT_V110_ASYNCH 0x0004 +#define B1_PROT_V110_SYNCH 0x0008 +#define B1_PROT_T30 0x0010 +#define B1_PROT_64KBIT_INV_HDLC 0x0020 +#define B1_PROT_56KBIT_TRANSPARENT 0x0040 + +#define B2_PROT_ISO7776 0x0001 +#define B2_PROT_TRANSPARENT 0x0002 +#define B2_PROT_SDLC 0x0004 +#define B2_PROT_LAPD 0x0008 +#define B2_PROT_T30 0x0010 +#define B2_PROT_PPP 0x0020 +#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040 + +#define B3_PROT_TRANSPARENT 0x0001 +#define B3_PROT_T90NL 0x0002 +#define B3_PROT_ISO8208 0x0004 +#define B3_PROT_X25_DCE 0x0008 +#define B3_PROT_T30 0x0010 +#define B3_PROT_T30EXT 0x0020 + +#define HYSDN_MAXVERSION 8 + +/* Number of sendbuffers in CAPI-queue */ +#define HYSDN_MAX_CAPI_SKB 20 + +#endif /* CONFIG_HYSDN_CAPI*/ + +/************************************************/ +/* constants and bits for debugging/log outputs */ +/************************************************/ +#define LOG_MAX_LINELEN 120 +#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */ +#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */ +#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */ +#define LOG_POF_RECORD 0x00000020 /* log pof record parser */ +#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */ +#define LOG_POF_CARD 0x00000080 /* log pof related card functions */ +#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */ +#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */ +#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */ +#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */ +#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */ +#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */ +#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */ + +#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */ + +/**********************************/ +/* proc filesystem name constants */ +/**********************************/ +#define PROC_SUBDIR_NAME "hysdn" +#define PROC_CONF_BASENAME "cardconf" +#define PROC_LOG_BASENAME "cardlog" + +/***********************************/ +/* PCI 32 bit parms for IO and MEM */ +/***********************************/ +#define PCI_REG_PLX_MEM_BASE 0 +#define PCI_REG_PLX_IO_BASE 1 +#define PCI_REG_MEMORY_BASE 3 + +/**************/ +/* card types */ +/**************/ +#define BD_NONE 0U +#define BD_PERFORMANCE 1U +#define BD_VALUE 2U +#define BD_PCCARD 3U +#define BD_ERGO 4U +#define BD_METRO 5U +#define BD_CHAMP2 6U +#define BD_PLEXUS 7U + +/******************************************************/ +/* defined states for cards shown by reading cardconf */ +/******************************************************/ +#define CARD_STATE_UNUSED 0 /* never been used or booted */ +#define CARD_STATE_BOOTING 1 /* booting is in progress */ +#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */ +#define CARD_STATE_RUN 3 /* card is active */ + +/*******************************/ +/* defines for error_log_state */ +/*******************************/ +#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */ +#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */ +#define ERRLOG_STATE_START 2 /* start error logging */ +#define ERRLOG_STATE_STOP 3 /* stop error logging */ + +/*******************************/ +/* data structure for one card */ +/*******************************/ +typedef struct HYSDN_CARD { + + /* general variables for the cards */ + int myid; /* own driver card id */ + uchar bus; /* pci bus the card is connected to */ + uchar devfn; /* slot+function bit encoded */ + word subsysid; /* PCI subsystem id */ + uchar brdtype; /* type of card */ + uint bchans; /* number of available B-channels */ + uint faxchans; /* number of available fax-channels */ + uchar mac_addr[6]; /* MAC Address read from card */ + uint irq; /* interrupt number */ + uint iobase; /* IO-port base address */ + ulong plxbase; /* PLX memory base */ + ulong membase; /* DPRAM memory base */ + ulong memend; /* DPRAM memory end */ + void *dpram; /* mapped dpram */ + int state; /* actual state of card -> CARD_STATE_** */ + struct HYSDN_CARD *next; /* pointer to next card */ + + /* data areas for the /proc file system */ + void *proclog; /* pointer to proclog filesystem specific data */ + void *procconf; /* pointer to procconf filesystem specific data */ + + /* debugging and logging */ + uchar err_log_state; /* actual error log state of the card */ + ulong debug_flags; /* tells what should be debugged and where */ + void (*set_errlog_state) (struct HYSDN_CARD *, int); + + /* interrupt handler + interrupt synchronisation */ + struct tq_struct irq_queue; /* interrupt task queue */ + uchar volatile irq_enabled; /* interrupt enabled if != 0 */ + uchar volatile hw_lock; /* hardware is currently locked -> no access */ + + /* boot process */ + void *boot; /* pointer to boot private data */ + int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong); + int (*writebootseq) (struct HYSDN_CARD *, uchar *, int); + int (*waitpofready) (struct HYSDN_CARD *); + int (*testram) (struct HYSDN_CARD *); + + /* scheduler for data transfer (only async parts) */ + uchar async_data[256]; /* async data to be sent (normally for config) */ + word volatile async_len; /* length of data to sent */ + word volatile async_channel; /* channel number for async transfer */ + int volatile async_busy; /* flag != 0 sending in progress */ + int volatile net_tx_busy; /* a network packet tx is in progress */ + + /* network interface */ + void *netif; /* pointer to network structure */ + + /* init and deinit stopcard for booting, too */ + void (*stopcard) (struct HYSDN_CARD *); + void (*releasehardware) (struct HYSDN_CARD *); +#ifdef CONFIG_HYSDN_CAPI + struct hycapictrl_info { + char cardname[32]; + spinlock_t lock; + int versionlen; + char versionbuf[1024]; + char *version[HYSDN_MAXVERSION]; + + char infobuf[128]; /* for function procinfo */ + + struct HYSDN_CARD *card; + struct capi_ctr *capi_ctrl; + struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB]; + int in_idx, out_idx; /* indexes to buffer ring */ + int sk_count; /* number of buffers currently in ring */ + struct sk_buff *tx_skb; /* buffer for tx operation */ + } *hyctrlinfo; +#endif /* CONFIG_HYSDN_CAPI */ +} hysdn_card; + +#ifdef CONFIG_HYSDN_CAPI +typedef struct hycapictrl_info hycapictrl_info; +#endif /* CONFIG_HYSDN_CAPI */ + + +/*****************/ +/* exported vars */ +/*****************/ +extern int cardmax; /* number of found cards */ +extern hysdn_card *card_root; /* pointer to first card */ + + + +/*************************/ +/* im/exported functions */ +/*************************/ +extern int printk(const char *fmt,...); +extern char *hysdn_getrev(const char *); + +/* hysdn_procconf.c */ +extern int hysdn_procconf_init(void); /* init proc config filesys */ +extern void hysdn_procconf_release(void); /* deinit proc config filesys */ + +/* hysdn_proclog.c */ +extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */ +extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */ +extern void put_log_buffer(hysdn_card *, char *); /* output log data */ +extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */ +extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */ + +/* boardergo.c */ +extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */ + +/* hysdn_boot.c */ +extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */ +extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */ +extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */ +extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */ + +/* hysdn_sched.c */ +extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *, + word); +extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word); +extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */ + +/* hysdn_net.c */ +extern char *hysdn_net_revision; +extern int hysdn_net_create(hysdn_card *); /* create a new net device */ +extern int hysdn_net_release(hysdn_card *); /* delete the device */ +extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */ +extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */ +extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */ +extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */ + +#ifdef CONFIG_HYSDN_CAPI +extern struct capi_driver_interface *hy_di; +extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ +extern int hycapi_capi_release(hysdn_card *); /* delete the device */ +extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ +extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *); +extern void hycapi_reset_ctr(struct capi_ctr *); +extern void hycapi_remove_ctr(struct capi_ctr *); +extern void hycapi_register_appl(struct capi_ctr *, __u16 appl, + capi_register_params *); +extern void hycapi_release_appl(struct capi_ctr *, __u16 appl); +extern void hycapi_send_message(struct capi_ctr *, struct sk_buff *skb); +extern char *hycapi_procinfo(struct capi_ctr *); +extern int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *card); +extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len); +extern void hycapi_tx_capiack(hysdn_card * card); +extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); +extern int hycapi_init(void); +extern void hycapi_cleanup(void); +#endif /* CONFIG_HYSDN_CAPI */ + +#endif /* HYSDN_DEFS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_init.c linux/drivers/isdn/hysdn/hysdn_init.c --- v2.2.18/drivers/isdn/hysdn/hysdn_init.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_init.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,257 @@ +/* $Id: hysdn_init.c,v 1.6.6.4 2001/02/10 14:41:22 kai Exp $ + + * Linux driver for HYSDN cards, init functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +static char *hysdn_init_revision = "$Revision: 1.6.6.4 $"; +int cardmax; /* number of found cards */ +hysdn_card *card_root = NULL; /* pointer to first card */ + +/**********************************************/ +/* table assigning PCI-sub ids to board types */ +/* the last entry contains all 0 */ +/**********************************************/ +static struct { + word subid; /* PCI sub id */ + uchar cardtyp; /* card type assigned */ +} pci_subid_map[] = { + + { + PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO + }, + { + PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 + }, + { + PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO + }, + { + PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO + }, + { + 0, 0 + } /* terminating entry */ +}; + + +/*********************************************************************/ +/* search_cards searches for available cards in the pci config data. */ +/* If a card is found, the card structure is allocated and the cards */ +/* ressources are reserved. cardmax is incremented. */ +/*********************************************************************/ +static void +search_cards(void) +{ + struct pci_dev *akt_pcidev = NULL; + hysdn_card *card, *card_last; + int i; + + card_root = NULL; + card_last = NULL; + while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + akt_pcidev)) != NULL) { + if (pci_enable_device(akt_pcidev)) + continue; + + if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) { + printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); + return; + } + memset(card, 0, sizeof(hysdn_card)); + card->myid = cardmax; /* set own id */ + card->bus = akt_pcidev->bus->number; + card->devfn = akt_pcidev->devfn; /* slot + function */ + pci_read_config_word(akt_pcidev, PCI_SUBSYSTEM_ID, &card->subsysid); + card->irq = akt_pcidev->irq; + card->iobase = akt_pcidev->base_address[ PCI_REG_PLX_IO_BASE] & PCI_BASE_ADDRESS_IO_MASK; + card->plxbase = akt_pcidev->base_address[ PCI_REG_PLX_MEM_BASE] & PCI_BASE_ADDRESS_MEM_MASK; + card->membase = akt_pcidev->base_address[ PCI_REG_MEMORY_BASE] & PCI_BASE_ADDRESS_MEM_MASK; + card->brdtype = BD_NONE; /* unknown */ + card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ + card->faxchans = 0; /* default no fax channels */ + card->bchans = 2; /* and 2 b-channels */ + for (i = 0; pci_subid_map[i].subid; i++) + if (pci_subid_map[i].subid == card->subsysid) { + card->brdtype = pci_subid_map[i].cardtyp; + break; + } + if (card->brdtype != BD_NONE) { + if (ergo_inithardware(card)) { + printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); + kfree(card); + continue; + } + } else { + printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); + kfree(card); /* release mem */ + continue; + } + cardmax++; + card->next = NULL; /*end of chain */ + if (card_last) + card_last->next = card; /* pointer to next card */ + else + card_root = card; + card_last = card; /* new chain end */ + } /* device found */ +} /* search_cards */ + +/************************************************************************************/ +/* free_resources frees the acquired PCI resources and returns the allocated memory */ +/************************************************************************************/ +static void +free_resources(void) +{ + hysdn_card *card; + + while (card_root) { + card = card_root; + if (card->releasehardware) + card->releasehardware(card); /* free all hardware resources */ + card_root = card_root->next; /* remove card from chain */ + kfree(card); /* return mem */ + + } /* while card_root */ +} /* free_resources */ + +/**************************************************************************/ +/* stop_cards disables (hardware resets) all cards and disables interrupt */ +/**************************************************************************/ +static void +stop_cards(void) +{ + hysdn_card *card; + + card = card_root; /* first in chain */ + while (card) { + if (card->stopcard) + card->stopcard(card); + card = card->next; /* remove card from chain */ + } /* while card */ +} /* stop_cards */ + + +/****************************************************************************/ +/* The module startup and shutdown code. Only compiled when used as module. */ +/* Using the driver as module is always advisable, because the booting */ +/* image becomes smaller and the driver code is only loaded when needed. */ +/* Additionally newer versions may be activated without rebooting. */ +/****************************************************************************/ + +/******************************************************/ +/* extract revision number from string for log output */ +/******************************************************/ +char * +hysdn_getrev(const char *revision) +{ + char *rev; + char *p; + + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; +} + + +/****************************************************************************/ +/* init_module is called once when the module is loaded to do all necessary */ +/* things like autodetect... */ +/* If the return value of this function is 0 the init has been successfull */ +/* and the module is added to the list in /proc/modules, otherwise an error */ +/* is assumed and the module will not be kept in memory. */ +/****************************************************************************/ +static int __init +hysdn_init(void) +{ + char tmp[50]; + + strcpy(tmp, hysdn_init_revision); + printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); + strcpy(tmp, hysdn_net_revision); + printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); + if (!pci_present()) { + printk(KERN_ERR "HYSDN: no PCI bus present, module not loaded\n"); + return (-1); + } + search_cards(); + printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); + + if (hysdn_procconf_init()) { + free_resources(); /* proc file_sys not created */ + return (-1); + } +#ifdef CONFIG_HYSDN_CAPI + if(cardmax > 0) { + if(hycapi_init()) { + printk(KERN_ERR "HYCAPI: init failed\n"); + return(-1); + } + } +#endif /* CONFIG_HYSDN_CAPI */ + return (0); /* no error */ +} /* init_module */ + + +/***********************************************************************/ +/* cleanup_module is called when the module is released by the kernel. */ +/* The routine is only called if init_module has been successfull and */ +/* the module counter has a value of 0. Otherwise this function will */ +/* not be called. This function must release all resources still allo- */ +/* cated as after the return from this function the module code will */ +/* be removed from memory. */ +/***********************************************************************/ +static void +hysdn_exit(void) +{ +#ifdef CONFIG_HYSDN_CAPI + hysdn_card *card; +#endif /* CONFIG_HYSDN_CAPI */ + stop_cards(); +#ifdef CONFIG_HYSDN_CAPI + card = card_root; /* first in chain */ + while (card) { + hycapi_capi_release(card); + card = card->next; /* remove card from chain */ + } /* while card */ + hycapi_cleanup(); +#endif /* CONFIG_HYSDN_CAPI */ + hysdn_procconf_release(); + free_resources(); + printk(KERN_NOTICE "HYSDN: module unloaded\n"); +} /* cleanup_module */ + +module_init(hysdn_init); +module_exit(hysdn_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c --- v2.2.18/drivers/isdn/hysdn/hysdn_net.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_net.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,336 @@ +/* $Id: hysdn_net.c,v 1.8 2000/11/13 22:51:47 kai Exp $ + + * Linux driver for HYSDN cards, net (ethernet type) handling routines. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This net module has been inspired by the skeleton driver from + * Donald Becker (becker@CESDIS.gsfc.nasa.gov) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +/* store the actual version for log reporting */ +char *hysdn_net_revision = "$Revision: 1.8 $"; + +#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ + +/****************************************************************************/ +/* structure containing the complete network data. The structure is aligned */ +/* in a way that both, the device and statistics are kept inside it. */ +/* for proper access, the device structure MUST be the first var/struct */ +/* inside the definition. */ +/****************************************************************************/ +struct net_local { + struct device netdev; /* the network device */ + struct net_device_stats stats; + /* additional vars may be added here */ + char dev_name[9]; /* our own device name */ + + struct sk_buff *tx_skb; /* buffer for tx operation */ + +}; /* net_local */ + + +/*****************************************************/ +/* Get the current statistics for this card. */ +/* This may be called with the card open or closed ! */ +/*****************************************************/ +static struct net_device_stats * +net_get_stats(struct device *dev) +{ + return (&((struct net_local *) dev)->stats); +} /* net_device_stats */ + +/*********************************************************************/ +/* Open/initialize the board. This is called (in the current kernel) */ +/* sometime after booting when the 'ifconfig' program is run. */ +/* This routine should set everything up anew at each open, even */ +/* registers that "should" only need to be set once at boot, so that */ +/* there is non-reboot way to recover if something goes wrong. */ +/*********************************************************************/ +static int +net_open(struct device *dev) +{ + struct in_device *in_dev; + hysdn_card *card = dev->priv; + int i; + + dev->tbusy = 0; /* non busy state */ + dev->interrupt = 0; + if (!dev->start) + MOD_INC_USE_COUNT; /* increment only if device is down */ + dev->start = 1; /* and started */ + + /* Fill in the MAC-level header (if not already set) */ + if (!card->mac_addr[0]) { + for (i = 0; i < ETH_ALEN - sizeof(ulong); i++) + dev->dev_addr[i] = 0xfc; + if ((in_dev = dev->ip_ptr) != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa != NULL) + memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong)); + } + } else + memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN); + + return (0); +} /* net_open */ + + + +/*********************************************************************/ +/* close/decativate the device. The device is not removed, but only */ +/* deactivated. */ +/*********************************************************************/ +static int +net_close(struct device *dev) +{ + + dev->tbusy = 1; /* we are busy */ + + if (dev->start) + MOD_DEC_USE_COUNT; /* dec only if device has been active */ + + dev->start = 0; /* and not started */ + + return (0); /* success */ +} /* net_close */ + +/************************************/ +/* send a packet on this interface. */ +/* only for kernel versions < 2.3.33 */ +/************************************/ +static int +net_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct net_local *lp = (struct net_local *) dev; + + if (dev->tbusy) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + * As ISDN may have higher timeouts than real ethernet 10s timeout + */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < (10000 * HZ) / 1000) + return 1; + printk(KERN_WARNING "%s: transmit timed out. \n", dev->name); + dev->tbusy = 0; + dev->trans_start = jiffies; + } + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + + else { + lp->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + lp->tx_skb = skb; /* remember skb pointer */ + queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + + return (0); /* success */ +} /* net_send_packet */ + + + +/***********************************************************************/ +/* acknowlegde a packet send. The network layer will be informed about */ +/* completion */ +/***********************************************************************/ +void +hysdn_tx_netack(hysdn_card * card) +{ + struct net_local *lp = card->netif; + + if (!lp) + return; /* non existing device */ + + if (lp->tx_skb) + dev_kfree_skb(lp->tx_skb); /* free tx pointer */ + lp->tx_skb = NULL; /* reset pointer */ + + lp->stats.tx_packets++; + lp->netdev.tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ +} /* hysdn_tx_netack */ + +/*****************************************************/ +/* we got a packet from the network, go and queue it */ +/*****************************************************/ +void +hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len) +{ + struct net_local *lp = card->netif; + struct sk_buff *skb; + + if (!lp) + return; /* non existing device */ + + lp->stats.rx_bytes += len; + + skb = dev_alloc_skb(len); + if (skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", + lp->netdev.name); + lp->stats.rx_dropped++; + return; + } + skb->dev = &lp->netdev; + + /* copy the data */ + memcpy(skb_put(skb, len), buf, len); + + /* determine the used protocol */ + skb->protocol = eth_type_trans(skb, &lp->netdev); + + netif_rx(skb); + lp->stats.rx_packets++; /* adjust packet count */ + +} /* hysdn_rx_netpkt */ + +/*****************************************************/ +/* return the pointer to a network packet to be send */ +/*****************************************************/ +struct sk_buff * +hysdn_tx_netget(hysdn_card * card) +{ + struct net_local *lp = card->netif; + + if (!lp) + return (NULL); /* non existing device */ + + return (lp->tx_skb); /* return packet pointer */ + +} /* hysdn_tx_netget */ + + +/*******************************************/ +/* init function called by register device */ +/*******************************************/ +static int +net_init(struct device *dev) +{ + /* setup the function table */ + dev->open = net_open; + dev->stop = net_close; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + return (0); /* success */ +} /* net_init */ + +/*****************************************************************************/ +/* hysdn_net_create creates a new net device for the given card. If a device */ +/* already exists, it will be deleted and created a new one. The return value */ +/* 0 announces success, else a negative error code will be returned. */ +/*****************************************************************************/ +int +hysdn_net_create(hysdn_card * card) +{ + struct device *dev; + int i; + if(!card) { + printk(KERN_WARNING "No card-pt in hysdn_net_create!\n"); + return (-ENOMEM); + } + hysdn_net_release(card); /* release an existing net device */ + if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); + if (card->debug_flags & LOG_NET_INIT) + return (-ENOMEM); + } + memset(dev, 0, sizeof(struct net_local)); /* clean the structure */ + + + /* initialise necessary or informing fields */ + dev->base_addr = card->iobase; /* IO address */ + dev->irq = card->irq; /* irq */ + dev->init = net_init; /* the init function of the device */ + dev->name = ((struct net_local *) dev)->dev_name; /* device name */ + if ((i = register_netdev(dev))) { + printk(KERN_WARNING "HYSDN: unable to create network device\n"); + kfree(dev); + return (i); + } + dev->priv = card; /* remember pointer to own data structure */ + card->netif = dev; /* setup the local pointer */ + + if (card->debug_flags & LOG_NET_INIT) + hysdn_addlog(card, "network device created"); + return (0); /* and return success */ +} /* hysdn_net_create */ + +/***************************************************************************/ +/* hysdn_net_release deletes the net device for the given card. The return */ +/* value 0 announces success, else a negative error code will be returned. */ +/***************************************************************************/ +int +hysdn_net_release(hysdn_card * card) +{ + struct device *dev = card->netif; + + if (!dev) + return (0); /* non existing */ + + card->netif = NULL; /* clear out pointer */ + dev->stop(dev); /* close the device */ + + + unregister_netdev(dev); /* release the device */ + kfree(dev); /* release the memory allocated */ + if (card->debug_flags & LOG_NET_INIT) + hysdn_addlog(card, "network device deleted"); + + return (0); /* always successfull */ +} /* hysdn_net_release */ + +/*****************************************************************************/ +/* hysdn_net_getname returns a pointer to the name of the network interface. */ +/* if the interface is not existing, a "-" is returned. */ +/*****************************************************************************/ +char * +hysdn_net_getname(hysdn_card * card) +{ + struct device *dev = card->netif; + + if (!dev) + return ("-"); /* non existing */ + + return (dev->name); +} /* hysdn_net_getname */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_pof.h linux/drivers/isdn/hysdn/hysdn_pof.h --- v2.2.18/drivers/isdn/hysdn/hysdn_pof.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_pof.h Sun Mar 25 11:37:33 2001 @@ -0,0 +1,89 @@ +/* $Id: hysdn_pof.h,v 1.2 2000/11/13 22:51:47 kai Exp $ + + * Linux driver for HYSDN cards, definitions used for handling pof-files. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/************************/ +/* POF specific defines */ +/************************/ +#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */ +#define CRYPT_FEEDTERM 0x8142 +#define CRYPT_STARTTERM 0x81a5 + /* max. timeout time in seconds + * from end of booting to POF is ready + */ +#define POF_READY_TIME_OUT_SEC 10 + +/**********************************/ +/* defines for 1.stage boot image */ +/**********************************/ + +/* the POF file record containing the boot loader image + * has 2 pages a 16KB: + * 1. page contains the high 16-bit part of the 32-bit E1 words + * 2. page contains the low 16-bit part of the 32-bit E1 words + * + * In each 16KB page we assume the start of the boot loader code + * in the highest 2KB part (at offset 0x3800); + * the rest (0x0000..0x37FF) is assumed to contain 0 bytes. + */ + +#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */ +#define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE) + +#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */ + + /* offset in boot page, where loader code may start */ + /* =0x3800= 14336U */ +#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE) + + +/*--------------------------------------POF file record structs------------*/ +typedef struct PofFileHdr_tag { /* Pof file header */ +/*00 */ ulong Magic __attribute__((packed)); +/*04 */ ulong N_PofRecs __attribute__((packed)); +/*08 */ +} tPofFileHdr; + +typedef struct PofRecHdr_tag { /* Pof record header */ +/*00 */ word PofRecId __attribute__((packed)); +/*02 */ ulong PofRecDataLen __attribute__((packed)); +/*06 */ +} tPofRecHdr; + +typedef struct PofTimeStamp_tag { +/*00 */ ulong UnixTime __attribute__((packed)); + /*04 */ uchar DateTimeText[0x28] __attribute__((packed)); + /* =40 */ +/*2C */ +} tPofTimeStamp; + + /* tPofFileHdr.Magic value: */ +#define TAGFILEMAGIC 0x464F501AUL + /* tPofRecHdr.PofRecId values: */ +#define TAG_ABSDATA 0x1000 /* abs. data */ +#define TAG_BOOTDTA 0x1001 /* boot data */ +#define TAG_COMMENT 0x0020 +#define TAG_SYSCALL 0x0021 +#define TAG_FLOWCTRL 0x0022 +#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */ +#define TAG_CABSDATA 0x1100 /* crypted abs. data */ +#define TAG_CBOOTDTA 0x1101 /* crypted boot data */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c --- v2.2.18/drivers/isdn/hysdn/hysdn_procconf.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_procconf.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,467 @@ +/* $Id: hysdn_procconf.c,v 1.8 2000/11/13 22:51:47 kai Exp $ + + * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +static char *hysdn_procconf_revision = "$Revision: 1.8 $"; + +#define INFO_OUT_LEN 80 /* length of info line including lf */ + +/********************************************************/ +/* defines and data structure for conf write operations */ +/********************************************************/ +#define CONF_STATE_DETECT 0 /* waiting for detect */ +#define CONF_STATE_CONF 1 /* writing config data */ +#define CONF_STATE_POF 2 /* writing pof data */ +#define CONF_LINE_LEN 80 /* 80 chars max */ + +struct conf_writedata { + hysdn_card *card; /* card the device is connected to */ + int buf_size; /* actual number of bytes in the buffer */ + int needed_size; /* needed size when reading pof */ + int state; /* actual interface states from above constants */ + uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */ + word channel; /* active channel number */ + uchar *pof_buffer; /* buffer when writing pof */ +}; + +/***********************************************************************/ +/* process_line parses one config line and transfers it to the card if */ +/* necessary. */ +/* if the return value is negative an error occured. */ +/***********************************************************************/ +static int +process_line(struct conf_writedata *cnf) +{ + uchar *cp = cnf->conf_line; + int i; + + if (cnf->card->debug_flags & LOG_CNF_LINE) + hysdn_addlog(cnf->card, "conf line: %s", cp); + + if (*cp == '-') { /* option */ + cp++; /* point to option char */ + + if (*cp++ != 'c') + return (0); /* option unknown or used */ + i = 0; /* start value for channel */ + while ((*cp <= '9') && (*cp >= '0')) + i = i * 10 + *cp++ - '0'; /* get decimal number */ + if (i > 65535) { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "conf channel invalid %d", i); + return (-ERR_INV_CHAN); /* invalid channel */ + } + cnf->channel = i & 0xFFFF; /* set new channel number */ + return (0); /* success */ + } /* option */ + if (*cp == '*') { /* line to send */ + if (cnf->card->debug_flags & LOG_CNF_DATA) + hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp); + return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1, + cnf->channel)); /* send the line without * */ + } /* line to send */ + return (0); +} /* process_line */ + +/*************************/ +/* dummy file operations */ +/*************************/ +static loff_t +hysdn_dummy_lseek(struct file *file, loff_t offset, int orig) +{ + return -ESPIPE; +} /* hysdn_dummy_lseek */ + +/***********************************/ +/* conf file operations and tables */ +/***********************************/ + +/****************************************************/ +/* write conf file -> boot or send cfg line to card */ +/****************************************************/ +static ssize_t +hysdn_conf_write(struct file *file, const char *buf, size_t count, loff_t * off) +{ + struct conf_writedata *cnf; + int i; + uchar ch, *cp; + + if (&file->f_pos != off) /* fs error check */ + return (-ESPIPE); + if (!count) + return (0); /* nothing to handle */ + + if (!(cnf = file->private_data)) + return (-EFAULT); /* should never happen */ + + if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */ + if (copy_from_user(&ch, buf, 1)) /* get first char for detect */ + return (-EFAULT); + + if (ch == 0x1A) { + /* we detected a pof file */ + if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0) + return (cnf->needed_size); /* an error occured -> exit */ + cnf->buf_size = 0; /* buffer is empty */ + cnf->state = CONF_STATE_POF; /* new state */ + } else { + /* conf data has been detected */ + cnf->buf_size = 0; /* buffer is empty */ + cnf->state = CONF_STATE_CONF; /* requested conf data write */ + if (cnf->card->state != CARD_STATE_RUN) + return (-ERR_NOT_BOOTED); + cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */ + cnf->channel = 4098; /* default channel for output */ + } + } /* state was auto detect */ + if (cnf->state == CONF_STATE_POF) { /* pof write active */ + i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */ + if (i <= 0) + return (-EINVAL); /* size error handling pof */ + + if (i < count) + count = i; /* limit requested number of bytes */ + if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count)) + return (-EFAULT); /* error while copying */ + cnf->buf_size += count; + + if (cnf->needed_size == cnf->buf_size) { + cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */ + if (cnf->needed_size <= 0) { + cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */ + return (cnf->needed_size); /* an error occured */ + } + cnf->buf_size = 0; /* buffer is empty again */ + } + } + /* pof write active */ + else { /* conf write active */ + + if (cnf->card->state != CARD_STATE_RUN) { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "cnf write denied -> not booted"); + return (-ERR_NOT_BOOTED); + } + i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */ + if (i > 0) { + /* copy remaining bytes into buffer */ + + if (count > i) + count = i; /* limit transfer */ + if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count)) + return (-EFAULT); /* error while copying */ + + i = count; /* number of chars in buffer */ + cp = cnf->conf_line + cnf->buf_size; + while (i) { + /* search for end of line */ + if ((*cp < ' ') && (*cp != 9)) + break; /* end of line found */ + cp++; + i--; + } /* search for end of line */ + + if (i) { + /* delimiter found */ + *cp++ = 0; /* string termination */ + count -= (i - 1); /* subtract remaining bytes from count */ + while ((i) && (*cp < ' ') && (*cp != 9)) { + i--; /* discard next char */ + count++; /* mark as read */ + cp++; /* next char */ + } + cnf->buf_size = 0; /* buffer is empty after transfer */ + if ((i = process_line(cnf)) < 0) /* handle the line */ + count = i; /* return the error */ + } + /* delimiter found */ + else { + cnf->buf_size += count; /* add chars to string */ + if (cnf->buf_size >= CONF_LINE_LEN - 1) { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count); + return (-ERR_CONF_LONG); + } + } /* not delimited */ + + } + /* copy remaining bytes into buffer */ + else { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "cnf line too long"); + return (-ERR_CONF_LONG); + } + } /* conf write active */ + + return (count); +} /* hysdn_conf_write */ + +/*******************************************/ +/* read conf file -> output card info data */ +/*******************************************/ +static ssize_t +hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off) +{ + char *cp; + int i; + + if (off != &file->f_pos) /* fs error check */ + return -ESPIPE; + + if (file->f_mode & FMODE_READ) { + if (!(cp = file->private_data)) + return (-EFAULT); /* should never happen */ + i = strlen(cp); /* get total string length */ + if (*off < i) { + /* still bytes to transfer */ + cp += *off; /* point to desired data offset */ + i -= *off; /* remaining length */ + if (i > count) + i = count; /* limit length to transfer */ + if (copy_to_user(buf, cp, i)) + return (-EFAULT); /* copy error */ + *off += i; /* adjust offset */ + } else + return (0); + } else + return (-EPERM); /* no permission to read */ + + return (i); +} /* hysdn_conf_read */ + +/******************/ +/* open conf file */ +/******************/ +static int +hysdn_conf_open(struct inode *ino, struct file *filep) +{ + hysdn_card *card; + struct proc_dir_entry *pd; + struct conf_writedata *cnf; + char *cp, *tmp; + + /* now search the addressed card */ + MOD_INC_USE_COUNT; + card = card_root; + while (card) { + pd = card->procconf; + if (pd->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (!card) { + MOD_DEC_USE_COUNT; + return (-ENODEV); /* device is unknown/invalid */ + } + if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) + hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x", + filep->f_uid, filep->f_gid, filep->f_mode); + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write boot file or conf line */ + + if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) { + MOD_DEC_USE_COUNT; + return (-EFAULT); + } + cnf->card = card; + cnf->buf_size = 0; /* nothing buffered */ + cnf->state = CONF_STATE_DETECT; /* start auto detect */ + filep->private_data = cnf; + + } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + /* read access -> output card info data */ + + if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) { + MOD_DEC_USE_COUNT; + return (-EFAULT); /* out of memory */ + } + filep->private_data = tmp; /* start of string */ + + /* first output a headline */ + sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device"); + cp = tmp; /* start of string */ + while (*cp) + cp++; + while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) + *cp++ = ' '; + *cp++ = '\n'; + + /* and now the data */ + sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s", + card->myid, + card->bus, + PCI_SLOT(card->devfn), + card->brdtype, + card->irq, + card->iobase, + card->membase, + card->bchans, + card->faxchans, + card->state, + hysdn_net_getname(card)); + while (*cp) + cp++; + while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) + *cp++ = ' '; + *cp++ = '\n'; + *cp = 0; /* end of string */ + } else { /* simultaneous read/write access forbidden ! */ + MOD_DEC_USE_COUNT; + return (-EPERM); /* no permission this time */ + } + return (0); +} /* hysdn_conf_open */ + +/***************************/ +/* close a config file. */ +/***************************/ +static int +hysdn_conf_close(struct inode *ino, struct file *filep) +{ + hysdn_card *card; + struct conf_writedata *cnf; + int retval = 0; + struct proc_dir_entry *pd; + + /* search the addressed card */ + card = card_root; + while (card) { + pd = card->procconf; + if (pd->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (!card) { + return (-ENODEV); /* device is unknown/invalid */ + } + if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) + hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x", + filep->f_uid, filep->f_gid, filep->f_mode); + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write boot file or conf line */ + if (filep->private_data) { + cnf = filep->private_data; + + if (cnf->state == CONF_STATE_POF) + retval = pof_write_close(cnf->card); /* close the pof write */ + kfree(filep->private_data); /* free allocated memory for buffer */ + + } /* handle write private data */ + } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + /* read access -> output card info data */ + + if (filep->private_data) + kfree(filep->private_data); /* release memory */ + } + MOD_DEC_USE_COUNT; + return (retval); +} /* hysdn_conf_close */ + +/******************************************************/ +/* table for conf filesystem functions defined above. */ +/******************************************************/ +static struct file_operations conf_fops = +{ + llseek: hysdn_dummy_lseek, + read: hysdn_conf_read, + write: hysdn_conf_write, + open: hysdn_conf_open, + release: hysdn_conf_close, +}; + +static struct inode_operations conf_inode_operations; +/*****************************/ +/* hysdn subdir in /proc/net */ +/*****************************/ +struct proc_dir_entry *hysdn_proc_entry = NULL; + +/*******************************************************************************/ +/* hysdn_procconf_init is called when the module is loaded and after the cards */ +/* have been detected. The needed proc dir and card config files are created. */ +/* The log init is called at last. */ +/*******************************************************************************/ +int +hysdn_procconf_init(void) +{ + hysdn_card *card; + uchar conf_name[20]; + + hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net); + if (!hysdn_proc_entry) { + printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); + return (-1); + } + card = card_root; /* point to first card */ + while (card) { + + sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); + if ((card->procconf = (void *) create_proc_entry(conf_name, + S_IFREG | S_IRUGO | S_IWUSR, + hysdn_proc_entry)) != NULL) { + memset(&conf_inode_operations, 0, sizeof(struct inode_operations)); + conf_inode_operations.default_file_ops = &conf_fops; + + ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations; + hysdn_proclog_init(card); /* init the log file entry */ + } + card = card->next; /* next entry */ + } + + printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision)); + return (0); +} /* hysdn_procconf_init */ + +/*************************************************************************************/ +/* hysdn_procconf_release is called when the module is unloaded and before the cards */ +/* resources are released. The module counter is assumed to be 0 ! */ +/*************************************************************************************/ +void +hysdn_procconf_release(void) +{ + hysdn_card *card; + uchar conf_name[20]; + + card = card_root; /* start with first card */ + while (card) { + + sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); + if (card->procconf) + remove_proc_entry(conf_name, hysdn_proc_entry); + + hysdn_proclog_release(card); /* init the log file entry */ + + card = card->next; /* point to next card */ + } + + remove_proc_entry(PROC_SUBDIR_NAME, proc_net); +} /* hysdn_procfs_release */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_proclog.c linux/drivers/isdn/hysdn/hysdn_proclog.c --- v2.2.18/drivers/isdn/hysdn/hysdn_proclog.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_proclog.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,464 @@ +/* $Id: hysdn_proclog.c,v 1.9 2000/11/25 17:01:01 kai Exp $ + + * Linux driver for HYSDN cards, /proc/net filesystem log functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +/* the proc subdir for the interface is defined in the procconf module */ +extern struct proc_dir_entry *hysdn_proc_entry; + +/*************************************************/ +/* structure keeping ascii log for device output */ +/*************************************************/ +struct log_data { + struct log_data *next; + ulong usage_cnt; /* number of files still to work */ + void *proc_ctrl; /* pointer to own control procdata structure */ + char log_start[2]; /* log string start (final len aligned by size) */ +}; + +/**********************************************/ +/* structure holding proc entrys for one card */ +/**********************************************/ +struct procdata { + struct proc_dir_entry *log; /* log entry */ + char log_name[15]; /* log filename */ + struct log_data *log_head, *log_tail; /* head and tail for queue */ + int if_used; /* open count for interface */ + int volatile del_lock; /* lock for delete operations */ + uchar logtmp[LOG_MAX_LINELEN]; + wait_queue_head_t rd_queue; +}; + + +/**********************************************/ +/* log function for cards error log interface */ +/**********************************************/ +void +hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize) +{ + char buf[ERRLOG_TEXT_SIZE + 40]; + + sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText); + put_log_buffer(card, buf); /* output the string */ +} /* hysdn_card_errlog */ + +/***************************************************/ +/* Log function using format specifiers for output */ +/***************************************************/ +void +hysdn_addlog(hysdn_card * card, char *fmt,...) +{ + struct procdata *pd = card->proclog; + char *cp; + va_list args; + + if (!pd) + return; /* log structure non existent */ + + cp = pd->logtmp; + cp += sprintf(cp, "HYSDN: card %d ", card->myid); + + va_start(args, fmt); + cp += vsprintf(cp, fmt, args); + va_end(args); + *cp++ = '\n'; + *cp = 0; + + if (card->debug_flags & DEB_OUT_SYSLOG) + printk(KERN_INFO "%s", pd->logtmp); + else + put_log_buffer(card, pd->logtmp); + +} /* hysdn_addlog */ + +/********************************************/ +/* put an log buffer into the log queue. */ +/* This buffer will be kept until all files */ +/* opened for read got the contents. */ +/* Flushes buffers not longer in use. */ +/********************************************/ +void +put_log_buffer(hysdn_card * card, char *cp) +{ + struct log_data *ib; + struct procdata *pd = card->proclog; + int i, flags; + + if (!pd) + return; + if (!cp) + return; + if (!*cp) + return; + if (pd->if_used <= 0) + return; /* no open file for read */ + + if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC))) + return; /* no memory */ + strcpy(ib->log_start, cp); /* set output string */ + ib->next = NULL; + ib->proc_ctrl = pd; /* point to own control structure */ + save_flags(flags); + cli(); + ib->usage_cnt = pd->if_used; + if (!pd->log_head) + pd->log_head = ib; /* new head */ + else + pd->log_tail->next = ib; /* follows existing messages */ + pd->log_tail = ib; /* new tail */ + i = pd->del_lock++; /* get lock state */ + restore_flags(flags); + + /* delete old entrys */ + if (!i) + while (pd->log_head->next) { + if ((pd->log_head->usage_cnt <= 0) && + (pd->log_head->next->usage_cnt <= 0)) { + ib = pd->log_head; + pd->log_head = pd->log_head->next; + kfree(ib); + } else + break; + } /* pd->log_head->next */ + pd->del_lock--; /* release lock level */ + wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */ +} /* put_log_buffer */ + + +/*************************/ +/* dummy file operations */ +/*************************/ +static loff_t +hysdn_dummy_lseek(struct file *file, loff_t offset, int orig) +{ + return -ESPIPE; +} /* hysdn_dummy_lseek */ + +/******************************/ +/* file operations and tables */ +/******************************/ + +/****************************************/ +/* write log file -> set log level bits */ +/****************************************/ +static ssize_t +hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off) +{ + ulong u = 0; + int found = 0; + uchar *cp, valbuf[128]; + long base = 10; + hysdn_card *card = (hysdn_card *) file->private_data; + + if (&file->f_pos != off) /* fs error check */ + return (-ESPIPE); + + if (count > (sizeof(valbuf) - 1)) + count = sizeof(valbuf) - 1; /* limit length */ + if (copy_from_user(valbuf, buf, count)) + return (-EFAULT); /* copy failed */ + + valbuf[count] = 0; /* terminating 0 */ + cp = valbuf; + if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) { + cp += 2; /* pointer after hex modifier */ + base = 16; + } + /* scan the input for debug flags */ + while (*cp) { + if ((*cp >= '0') && (*cp <= '9')) { + found = 1; + u *= base; /* adjust to next digit */ + u += *cp++ - '0'; + continue; + } + if (base != 16) + break; /* end of number */ + + if ((*cp >= 'a') && (*cp <= 'f')) { + found = 1; + u *= base; /* adjust to next digit */ + u += *cp++ - 'a' + 10; + continue; + } + break; /* terminated */ + } + + if (found) { + card->debug_flags = u; /* remember debug flags */ + hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); + } + return (count); +} /* hysdn_log_write */ + +/******************/ +/* read log file */ +/******************/ +static ssize_t +hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off) +{ + struct log_data *inf; + int len; + word ino; + struct procdata *pd; + hysdn_card *card; + + if (!*((struct log_data **) file->private_data)) { + if (file->f_flags & O_NONBLOCK) + return (-EAGAIN); + + /* sorry, but we need to search the card */ + ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == ino) + break; + card = card->next; /* search next entry */ + } + if (card) + interruptible_sleep_on(&(pd->rd_queue)); + else + return (-EAGAIN); + + } + if (!(inf = *((struct log_data **) file->private_data))) + return (0); + + inf->usage_cnt--; /* new usage count */ + (struct log_data **) file->private_data = &inf->next; /* next structure */ + if ((len = strlen(inf->log_start)) <= count) { + if (copy_to_user(buf, inf->log_start, len)) + return -EFAULT; + file->f_pos += len; + return (len); + } + return (0); +} /* hysdn_log_read */ + +/******************/ +/* open log file */ +/******************/ +static int +hysdn_log_open(struct inode *ino, struct file *filep) +{ + hysdn_card *card; + struct procdata *pd; + ulong flags; + + MOD_INC_USE_COUNT; + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (!card) { + MOD_DEC_USE_COUNT; + return (-ENODEV); /* device is unknown/invalid */ + } + filep->private_data = card; /* remember our own card */ + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write log level only */ + } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + + /* read access -> log/debug read */ + save_flags(flags); + cli(); + pd->if_used++; + if (pd->log_head) + (struct log_data **) filep->private_data = &(pd->log_tail->next); + else + (struct log_data **) filep->private_data = &(pd->log_head); + restore_flags(flags); + } else { /* simultaneous read/write access forbidden ! */ + MOD_DEC_USE_COUNT; + return (-EPERM); /* no permission this time */ + } + return (0); +} /* hysdn_log_open */ + +/*******************************************************************************/ +/* close a cardlog file. If the file has been opened for exclusive write it is */ +/* assumed as pof data input and the pof loader is noticed about. */ +/* Otherwise file is handled as log output. In this case the interface usage */ +/* count is decremented and all buffers are noticed of closing. If this file */ +/* was the last one to be closed, all buffers are freed. */ +/*******************************************************************************/ +static int +hysdn_log_close(struct inode *ino, struct file *filep) +{ + struct log_data *inf; + struct procdata *pd; + hysdn_card *card; + int flags, retval = 0; + + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write debug level written */ + retval = 0; /* success */ + } else { + /* read access -> log/debug read, mark one further file as closed */ + + pd = NULL; + save_flags(flags); + cli(); + inf = *((struct log_data **) filep->private_data); /* get first log entry */ + if (inf) + pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ + else { + /* no info available -> search card */ + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (card) + pd = card->proclog; /* pointer to procfs log */ + } + if (pd) + pd->if_used--; /* decrement interface usage count by one */ + + while (inf) { + inf->usage_cnt--; /* decrement usage count for buffers */ + inf = inf->next; + } + restore_flags(flags); + + if (pd) + if (pd->if_used <= 0) /* delete buffers if last file closed */ + while (pd->log_head) { + inf = pd->log_head; + pd->log_head = pd->log_head->next; + kfree(inf); + } + } /* read access */ + MOD_DEC_USE_COUNT; + + return (retval); +} /* hysdn_log_close */ + +/*************************************************/ +/* select/poll routine to be able using select() */ +/*************************************************/ +static unsigned int +hysdn_log_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = 0; + word ino; + hysdn_card *card; + struct procdata *pd; + + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) + return (mask); /* no polling for write supported */ + + /* we need to search the card */ + ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == ino) + break; + card = card->next; /* search next entry */ + } + if (!card) + return (mask); /* card not found */ + + poll_wait(file, &(pd->rd_queue), wait); + + if (*((struct log_data **) file->private_data)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} /* hysdn_log_poll */ + +/**************************************************/ +/* table for log filesystem functions defined above. */ +/**************************************************/ +static struct file_operations log_fops = +{ + llseek: hysdn_dummy_lseek, + read: hysdn_log_read, + write: hysdn_log_write, + poll: hysdn_log_poll, + open: hysdn_log_open, + release: hysdn_log_close, +}; + +struct inode_operations log_inode_operations; + +/***********************************************************************************/ +/* hysdn_proclog_init is called when the module is loaded after creating the cards */ +/* conf files. */ +/***********************************************************************************/ +int +hysdn_proclog_init(hysdn_card * card) +{ + struct procdata *pd; + + /* create a cardlog proc entry */ + + if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { + memset(pd, 0, sizeof(struct procdata)); + memset(&log_inode_operations, 0, sizeof(struct inode_operations)); + log_inode_operations.default_file_ops = &log_fops; + sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); + if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { + pd->log->ops = &log_inode_operations; /* set new operations table */ + } + + init_waitqueue_head(&(pd->rd_queue)); + + card->proclog = (void *) pd; /* remember procfs structure */ + } + return (0); +} /* hysdn_proclog_init */ + +/************************************************************************************/ +/* hysdn_proclog_release is called when the module is unloaded and before the cards */ +/* conf file is released */ +/* The module counter is assumed to be 0 ! */ +/************************************************************************************/ +void +hysdn_proclog_release(hysdn_card * card) +{ + struct procdata *pd; + + if ((pd = (struct procdata *) card->proclog) != NULL) { + if (pd->log) + remove_proc_entry(pd->log_name, hysdn_proc_entry); + kfree(pd); /* release memory */ + card->proclog = NULL; + } +} /* hysdn_proclog_release */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c --- v2.2.18/drivers/isdn/hysdn/hysdn_sched.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/hysdn_sched.c Sun Mar 25 11:37:33 2001 @@ -0,0 +1,213 @@ +/* $Id: hysdn_sched.c,v 1.5 2000/11/22 17:13:13 kai Exp $ + + * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +/*****************************************************************************/ +/* hysdn_sched_rx is called from the cards handler to announce new data is */ +/* available from the card. The routine has to handle the data and return */ +/* with a nonzero code if the data could be worked (or even thrown away), if */ +/* no room to buffer the data is available a zero return tells the card */ +/* to keep the data until later. */ +/*****************************************************************************/ +int +hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan) +{ + + switch (chan) { + case CHAN_NDIS_DATA: + hysdn_rx_netpkt(card, buf, len); /* give packet to network handler */ + break; + + case CHAN_ERRLOG: + hysdn_card_errlog(card, (tErrLogEntry *) buf, len); + if (card->err_log_state == ERRLOG_STATE_ON) + card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ + break; +#ifdef CONFIG_HYSDN_CAPI + case CHAN_CAPI: +/* give packet to CAPI handler */ + hycapi_rx_capipkt(card, buf, len); + break; +#endif /* CONFIG_HYSDN_CAPI */ + default: + printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); + break; + + } /* switch rx channel */ + + return (1); /* always handled */ +} /* hysdn_sched_rx */ + +/*****************************************************************************/ +/* hysdn_sched_tx is called from the cards handler to announce that there is */ +/* room in the tx-buffer to the card and data may be sent if needed. */ +/* If the routine wants to send data it must fill buf, len and chan with the */ +/* appropriate data and return a nonzero value. With a zero return no new */ +/* data to send is assumed. maxlen specifies the buffer size available for */ +/* sending. */ +/*****************************************************************************/ +int +hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen) +{ + struct sk_buff *skb; + + if (card->net_tx_busy) { + card->net_tx_busy = 0; /* reset flag */ + hysdn_tx_netack(card); /* acknowledge packet send */ + } /* a network packet has completely been transferred */ + /* first of all async requests are handled */ + if (card->async_busy) { + if (card->async_len <= maxlen) { + memcpy(buf, card->async_data, card->async_len); + *len = card->async_len; + *chan = card->async_channel; + card->async_busy = 0; /* reset request */ + return (1); + } + card->async_busy = 0; /* in case of length error */ + } /* async request */ + if ((card->err_log_state == ERRLOG_STATE_START) && + (maxlen >= ERRLOG_CMD_REQ_SIZE)) { + strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */ + *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */ + *chan = CHAN_ERRLOG; /* and channel */ + card->err_log_state = ERRLOG_STATE_ON; /* new state is on */ + return (1); /* tell that data should be send */ + } /* error log start and able to send */ + if ((card->err_log_state == ERRLOG_STATE_STOP) && + (maxlen >= ERRLOG_CMD_STOP_SIZE)) { + strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */ + *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */ + *chan = CHAN_ERRLOG; /* and channel */ + card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */ + return (1); /* tell that data should be send */ + } /* error log start and able to send */ + /* now handle network interface packets */ + if ((skb = hysdn_tx_netget(card)) != NULL) { + if (skb->len <= maxlen) { + memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */ + *len = skb->len; + *chan = CHAN_NDIS_DATA; + card->net_tx_busy = 1; /* we are busy sending network data */ + return (1); /* go and send the data */ + } else + hysdn_tx_netack(card); /* aknowledge packet -> throw away */ + } /* send a network packet if available */ +#ifdef CONFIG_HYSDN_CAPI + if((skb = hycapi_tx_capiget(card)) != NULL) { + if (skb->len <= maxlen) { + memcpy(buf, skb->data, skb->len); + *len = skb->len; + *chan = CHAN_CAPI; + hycapi_tx_capiack(card); + return (1); /* go and send the data */ + } + } +#endif /* CONFIG_HYSDN_CAPI */ + return (0); /* nothing to send */ +} /* hysdn_sched_tx */ + + +/*****************************************************************************/ +/* send one config line to the card and return 0 if successfull, otherwise a */ +/* negative error code. */ +/* The function works with timeouts perhaps not giving the greatest speed */ +/* sending the line, but this should be meaningless beacuse only some lines */ +/* are to be sent and this happens very seldom. */ +/*****************************************************************************/ +int +hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan) +{ + int cnt = 50; /* timeout intervalls */ + ulong flags; + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1); + + save_flags(flags); + cli(); + while (card->async_busy) { + sti(); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg delayed"); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + if (!--cnt) { + restore_flags(flags); + return (-ERR_ASYNC_TIME); /* timed out */ + } + cli(); + } /* wait for buffer to become free */ + + strcpy(card->async_data, line); + card->async_len = strlen(line) + 1; + card->async_channel = chan; + card->async_busy = 1; /* request transfer */ + + /* now queue the task */ + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + sti(); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg data queued"); + + cnt++; /* short delay */ + cli(); + + while (card->async_busy) { + sti(); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg waiting for tx-ready"); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + if (!--cnt) { + restore_flags(flags); + return (-ERR_ASYNC_TIME); /* timed out */ + } + cli(); + } /* wait for buffer to become free again */ + + restore_flags(flags); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg data send"); + + return (0); /* line send correctly */ +} /* hysdn_tx_cfgline */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/hysdn/ince1pc.h linux/drivers/isdn/hysdn/ince1pc.h --- v2.2.18/drivers/isdn/hysdn/ince1pc.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/isdn/hysdn/ince1pc.h Sun Mar 25 11:37:33 2001 @@ -0,0 +1,132 @@ +#ifndef __INCE1PC_H__ +#define __INCE1PC_H__ + +/**************************************************************************** + + FILE: ince1pc.h + + AUTHOR: M.Steinkopf + + PURPOSE: common definitions for both sides of the bus: + - conventions both spoolers must know + - channel numbers agreed upon + +*****************************************************************************/ + +/* basic scalar definitions have same meanning, + * but their declaration location depends on environment + */ + +/*--------------------------------------channel numbers---------------------*/ +#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ +#define CHAN_ERRLOG 0x0005 /* error logger */ +#define CHAN_CAPI 0x0064 /* CAPI interface */ +#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ + +/*--------------------------------------POF ready msg-----------------------*/ + /* NOTE: after booting POF sends system ready message to PC: */ +#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ +#define RDY_MAGIC_SIZE 4 /* size in bytes */ + +#define MAX_N_TOK_BYTES 255 + +#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE +#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + +#define SYSR_TOK_END 0 +#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ +#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ +#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ +#define SYSR_TOK_ESC 255 /* undefined data size yet */ + /* default values, if not corrected by token: */ +#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ +#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ + +/* syntax of new SYSR token stream: + * channel: CHAN_SYSTEM + * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE + * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + * msg : 0 1 2 3 {4 5 6 ..} + * S Y S R MAX_N_TOK_BYTES bytes of TokenStream + * + * TokenStream := empty + * | {NonEndTokenChunk} EndToken RotlCRC + * NonEndTokenChunk:= NonEndTokenId DataLen [Data] + * NonEndTokenId := 0x01 .. 0xFE 1 BYTE + * DataLen := 0x00 .. 0xFF 1 BYTE + * Data := DataLen bytes + * EndToken := 0x00 + * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes + * s. RotlCRC algorithm + * + * RotlCRC algorithm: + * ucSum= 0 1 uchar + * for all NonEndTokenChunk bytes: + * ROTL(ucSum,1) rotate left by 1 + * ucSum += Char; add current byte with swap around + * RotlCRC= ~ucSum; invert all bits for result + * + * note: + * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! + */ + +/*--------------------------------------error logger------------------------*/ + /* note: pof needs final 0 ! */ +#define ERRLOG_CMD_REQ "ERRLOG ON" +#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ +#define ERRLOG_CMD_STOP "ERRLOG OFF" +#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ + +#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ + /* remaining text size = 55 */ +#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1) + +typedef struct ErrLogEntry_tag { + +/*00 */ ulong ulErrType; + +/*04 */ ulong ulErrSubtype; + +/*08 */ uchar ucTextSize; + + /*09 */ uchar ucText[ERRLOG_TEXT_SIZE]; + /* ASCIIZ of len ucTextSize-1 */ + +/*40 */ +} tErrLogEntry; + + +#if defined(__TURBOC__) +#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE +#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE +#endif /* */ +#endif /* */ + +/*--------------------------------------DPRAM boot spooler------------------*/ + /* this is the struture used between pc and + * hyperstone to exchange boot data + */ +#define DPRAM_SPOOLER_DATA_SIZE 0x20 +typedef struct DpramBootSpooler_tag { + +/*00 */ uchar Len; + +/*01 */ volatile uchar RdPtr; + +/*02 */ uchar WrPtr; + +/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE]; + +/*23 */ +} tDpramBootSpooler; + + +#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ +#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ + +/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ + /* at DPRAM offset 0x1C00: */ +#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ + + +#endif /* __INCE1PC_H__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/icn/Makefile linux/drivers/isdn/icn/Makefile --- v2.2.18/drivers/isdn/icn/Makefile Sun Mar 25 11:13:06 2001 +++ linux/drivers/isdn/icn/Makefile Sun Mar 25 11:37:33 2001 @@ -1,8 +1,11 @@ -ifeq ($(CONFIG_ISDN_DRV_ICN),y) - O_TARGET := icn_obj.o - O_OBJS := icn.o -else - M_OBJS := icn.o -endif +# Makefile for the act2000 ISDN device driver -include $(TOPDIR)/Rules.make +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_ICN) += icn.o + +include $(TOPDIR)/drivers/isdn/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.2.18/drivers/isdn/icn/icn.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/icn/icn.c Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.65 2000/11/13 22:51:48 kai Exp $ +/* $Id: icn.c,v 1.65.6.2 2000/12/17 22:45:13 kai Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -21,6 +21,7 @@ */ #include "icn.h" +#include /* * Verbose bootcode- and protocol-downloading. @@ -33,7 +34,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.65 $"; +*revision = "$Revision: 1.65.6.2 $"; static int icn_addcard(int, char *, char *); @@ -1638,9 +1639,7 @@ return 0; } -#ifdef MODULE -#define icn_init init_module -#else +#ifndef MODULE void icn_setup(char *str, int *ints) { @@ -1661,10 +1660,9 @@ } } } -#endif /* MODULES */ +#endif /* MODULE */ -int -icn_init(void) +static int __init icn_init(void) { char *p; char rev[10]; @@ -1675,9 +1673,6 @@ dev.mcard = NULL; dev.firstload = 1; - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; - if ((p = strchr(revision, ':'))) { strcpy(rev, p + 1); p = strchr(rev, '$'); @@ -1689,9 +1684,7 @@ return (icn_addcard(portbase, icn_id, icn_id2)); } -#ifdef MODULE -void -cleanup_module(void) +static void icn_exit(void) { isdn_ctrl cmd; icn_card *card = cards; @@ -1725,4 +1718,6 @@ release_shmem((ulong) dev.shmem, 0x4000); printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n"); } -#endif + +module_init(icn_init); +module_exit(icn_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.2.18/drivers/isdn/icn/icn.h Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/icn/icn.h Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.30 2000/11/13 22:51:48 kai Exp $ +/* $Id: icn.h,v 1.30.6.1 2001/02/10 14:41:23 kai Exp $ * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -55,7 +55,7 @@ #include #include #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c --- v2.2.18/drivers/isdn/isdn_bsdcomp.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/isdn_bsdcomp.c Sun Mar 25 11:37:33 2001 @@ -47,12 +47,8 @@ * SUCH DAMAGE. */ -#ifndef MODULE -#error This file must be compiled as a module. -#endif - #include - +#include #include #include #include @@ -61,7 +57,7 @@ #include #include #include -#include +#include #include #include #include /* used in new tty drivers */ @@ -919,7 +915,7 @@ * Module support routines *************************************************************/ -int init_module(void) +static int __init isdn_bsdcomp_init(void) { int answer = isdn_ppp_register_compressor (&ippp_bsd_compress); if (answer == 0) @@ -927,7 +923,10 @@ return answer; } -void cleanup_module(void) +static void isdn_bsdcomp_exit(void) { isdn_ppp_unregister_compressor (&ippp_bsd_compress); } + +module_init(isdn_bsdcomp_init); +module_exit(isdn_bsdcomp_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v2.2.18/drivers/isdn/isdn_cards.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_cards.c Wed Dec 31 19:00:00 1969 @@ -1,73 +0,0 @@ -/* $Id: isdn_cards.c,v 1.13 2000/10/28 23:03:38 kai Exp $ - - * Linux ISDN subsystem, initialization for non-modularized drivers. - * - * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include - -#ifdef CONFIG_ISDN_DRV_ICN -extern void icn_init(void); -#endif - -#ifdef CONFIG_ISDN_DRV_HISAX -extern void HiSax_init(void); -#endif - -#ifdef CONFIG_ISDN_DRV_PCBIT -extern void pcbit_init(void); -#endif - -#ifdef CONFIG_ISDN_DRV_EICON -extern void eicon_init(void); -#endif - -#ifdef CONFIG_ISDN_DRV_AVMB1 -extern void kcapi_init(void); -extern void capi_init(void); -extern void capidrv_init(void); -#endif -#if CONFIG_ISDN_DRV_ACT2000 -extern void act2000_init(void); -#endif - -void -isdn_cards_init(void) -{ -#if CONFIG_ISDN_DRV_ICN - icn_init(); -#endif -#ifdef CONFIG_ISDN_DRV_HISAX - HiSax_init(); -#endif -#if CONFIG_ISDN_DRV_PCBIT - pcbit_init(); -#endif -#ifdef CONFIG_ISDN_DRV_AVMB1 - kcapi_init(); - capi_init(); - capidrv_init(); -#endif -#if CONFIG_ISDN_DRV_ACT2000 - act2000_init(); -#endif -#if CONFIG_ISDN_DRV_EICON - eicon_init(); -#endif -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_cards.h linux/drivers/isdn/isdn_cards.h --- v2.2.18/drivers/isdn/isdn_cards.h Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_cards.h Wed Dec 31 19:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: isdn_cards.h,v 1.4 2000/05/11 22:29:20 kai Exp $ - - * Linux ISDN subsystem, initialization for non-modularized drivers. - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -extern void isdn_cards_init(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.2.18/drivers/isdn/isdn_common.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_common.c Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.113 2000/11/01 17:54:00 detabc Exp $ +/* $Id: isdn_common.c,v 1.114.6.7 2001/02/10 14:41:19 kai Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -24,10 +24,12 @@ #include #include +#include #include #include #include #include +#include #include "isdn_common.h" #include "isdn_tty.h" #include "isdn_net.h" @@ -35,18 +37,20 @@ #ifdef CONFIG_ISDN_AUDIO #include "isdn_audio.h" #endif +#ifdef CONFIG_ISDN_DIVERSION_MODULE +#define CONFIG_ISDN_DIVERSION +#endif #ifdef CONFIG_ISDN_DIVERSION #include #endif CONFIG_ISDN_DIVERSION #include "isdn_v110.h" -#include "isdn_cards.h" /* Debugflags */ #undef ISDN_DEBUG_STATCALLB isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.113 $"; +static char *isdn_revision = "$Revision: 1.114.6.7 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -63,7 +67,7 @@ extern char *isdn_v110_revision; #ifdef CONFIG_ISDN_DIVERSION -isdn_divert_if *divert_if; /* interface to diversion module */ +static isdn_divert_if *divert_if; /* = NULL */ #endif CONFIG_ISDN_DIVERSION @@ -72,11 +76,10 @@ static int isdn_wildmat(char *s, char *p); void -isdn_MOD_INC_USE_COUNT(void) +isdn_lock_drivers(void) { int i; - MOD_INC_USE_COUNT; for (i = 0; i < dev->drivers; i++) { isdn_ctrl cmd; @@ -89,11 +92,17 @@ } void -isdn_MOD_DEC_USE_COUNT(void) +isdn_MOD_INC_USE_COUNT(void) +{ + MOD_INC_USE_COUNT; + isdn_lock_drivers(); +} + +void +isdn_unlock_drivers(void) { int i; - MOD_DEC_USE_COUNT; for (i = 0; i < dev->drivers; i++) if (dev->drv[i]->locks > 0) { isdn_ctrl cmd; @@ -106,6 +115,13 @@ } } +void +isdn_MOD_DEC_USE_COUNT(void) +{ + MOD_DEC_USE_COUNT; + isdn_unlock_drivers(); +} + #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) void isdn_dumppkt(char *s, u_char * p, int len, int dumplen) @@ -437,6 +453,7 @@ int r; int retval = 0; isdn_ctrl cmd; + isdn_net_dev *p; di = c->driver; i = isdn_dc2minor(di, c->arg); @@ -515,9 +532,16 @@ cmd.driver = di; cmd.arg = c->arg; cmd.command = ISDN_CMD_ACCEPTD; - isdn_command(&cmd); - retval = 1; + for ( p = dev->netdev; p; p = p->next ) + if ( p->local->isdn_channel == cmd.arg ) + { + strcpy( cmd.parm.setup.eazmsn, p->local->msn ); + isdn_command(&cmd); + retval = 1; + break; + } break; + case 2: /* For calling back, first reject incoming call ... */ case 3: /* Interface found, but down, reject call actively */ retval = 2; @@ -719,7 +743,6 @@ isdn_free_queue(&dev->drv[di]->rpqueue[i]); kfree(dev->drv[di]->rpqueue); kfree(dev->drv[di]->rcv_waitq); - kfree(dev->drv[di]->snd_waitq); kfree(dev->drv[di]); dev->drv[di] = NULL; dev->drvid[di][0] = '\0'; @@ -782,7 +805,7 @@ * of the mapping (di,ch)<->minor, happen during the sleep? --he */ int -isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep) +isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep) { int left; int count; @@ -966,6 +989,7 @@ ulong flags; int drvidx; int chidx; + int retval; char *p; if (off != &file->f_pos) @@ -973,47 +997,69 @@ if (minor == ISDN_MINOR_STATUS) { if (!file->private_data) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } interruptible_sleep_on(&(dev->info_waitq)); } p = isdn_statstr(); file->private_data = 0; if ((len = strlen(p)) <= count) { - if (copy_to_user(buf, p, len)) - return -EFAULT; + if (copy_to_user(buf, p, len)) { + retval = -EFAULT; + goto out; + } *off += len; - return len; + retval = len; + goto out; } - return 0; + retval = 0; + goto out; + } + if (!dev->drivers) { + retval = -ENODEV; + goto out; } - if (!dev->drivers) - return -ENODEV; if (minor < ISDN_MINOR_CTRL) { + printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return -ENODEV; - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { + retval = -ENODEV; + goto out; + } chidx = isdn_minor2chan(minor); - if( ! (p = kmalloc(count,GFP_KERNEL)) ) return -ENOMEM; + if (!(p = kmalloc(count, GFP_KERNEL))) { + retval = -ENOMEM; + goto out; + } save_flags(flags); cli(); len = isdn_readbchan(drvidx, chidx, p, 0, count, &dev->drv[drvidx]->rcv_waitq[chidx]); *off += len; restore_flags(flags); - if( copy_to_user(buf,p,len) ) len = -EFAULT; + if (copy_to_user(buf,p,len)) + len = -EFAULT; kfree(p); - return len; + retval = len; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } if (!dev->drv[drvidx]->stavail) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); } if (dev->drv[drvidx]->interface->readstat) @@ -1030,13 +1076,18 @@ dev->drv[drvidx]->stavail = 0; restore_flags(flags); *off += len; - return len; + retval = len; + goto out; } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count)); + if (minor <= ISDN_MINOR_PPPMAX) { + retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count); + goto out; + } #endif - return -ENODEV; + retval = -ENODEV; + out: + return retval; } static loff_t @@ -1051,6 +1102,7 @@ uint minor = MINOR(file->f_dentry->d_inode->i_rdev); int drvidx; int chidx; + int retval; if (off != &file->f_pos) return -ESPIPE; @@ -1059,21 +1111,30 @@ return -EPERM; if (!dev->drivers) return -ENODEV; + if (minor < ISDN_MINOR_CTRL) { + printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return -ENODEV; - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { + retval = -ENODEV; + goto out; + } chidx = isdn_minor2chan(minor); while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); - return count; + retval = count; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } /* * We want to use the isdnctrl device to load the firmware * @@ -1081,16 +1142,21 @@ return -ENODEV; */ if (dev->drv[drvidx]->interface->writecmd) - return (dev->drv[drvidx]->interface-> - writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor))); + retval = dev->drv[drvidx]->interface-> + writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)); else - return count; + retval = count; + goto out; } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count)); + if (minor <= ISDN_MINOR_PPPMAX) { + retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count); + goto out; + } #endif - return -ENODEV; + retval = -ENODEV; + out: + return retval; } static unsigned int @@ -1106,26 +1172,30 @@ if (file->private_data) { mask |= POLLIN | POLLRDNORM; } - return mask; + goto out; } if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { if (drvidx < 0) { /* driver deregistered while file open */ - return POLLHUP; + mask = POLLHUP; + goto out; } poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); mask = POLLOUT | POLLWRNORM; if (dev->drv[drvidx]->stavail) { mask |= POLLIN | POLLRDNORM; } - return mask; + goto out; } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_poll(file, wait)); + if (minor <= ISDN_MINOR_PPPMAX) { + mask = isdn_ppp_poll(file, wait); + goto out; + } #endif - printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n"); - return POLLERR; + mask = POLLERR; + out: + return mask; } @@ -1432,7 +1502,7 @@ int i; if ((ret = verify_area(VERIFY_READ, (void *) arg, - (ISDN_MODEM_NUMREG + ISDN_MSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; @@ -1441,6 +1511,9 @@ ISDN_MODEM_NUMREG)) return -EFAULT; p += ISDN_MODEM_NUMREG; + if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) + return -EFAULT; + p += ISDN_LMSNLEN; if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; @@ -1576,8 +1649,6 @@ /* * Open the device code. - * MOD_INC_USE_COUNT make sure that the driver memory is not freed - * while the device is in use. */ static int isdn_open(struct inode *ino, struct file *filep) @@ -1585,51 +1656,62 @@ uint minor = MINOR(ino->i_rdev); int drvidx; int chidx; + int retval = -ENODEV; + + MOD_INC_USE_COUNT; if (minor == ISDN_MINOR_STATUS) { infostruct *p; if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) { - MOD_INC_USE_COUNT; p->next = (char *) dev->infochain; p->private = (char *) &(filep->private_data); dev->infochain = p; /* At opening we allow a single update */ filep->private_data = (char *) 1; - return 0; - } else - return -ENOMEM; + retval = 0; + goto out; + } else { + retval = -ENOMEM; + goto out; + } } if (!dev->channels) - return -ENODEV; + goto out; if (minor < ISDN_MINOR_CTRL) { + printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) - return -ENODEV; + goto out; chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + goto out; if (!(dev->drv[drvidx]->online & (1 << chidx))) - return -ENODEV; - isdn_MOD_INC_USE_COUNT(); - return 0; + goto out; + isdn_lock_drivers(); + retval = 0; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) - return -ENODEV; - isdn_MOD_INC_USE_COUNT(); - return 0; + goto out; + isdn_lock_drivers(); + retval = 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { - int ret; - if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) - isdn_MOD_INC_USE_COUNT(); - return ret; + retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); + if (retval == 0) + isdn_lock_drivers(); + goto out; } #endif - return -ENODEV; + out: + if (retval) + MOD_DEC_USE_COUNT; + return retval; } static int @@ -1641,7 +1723,6 @@ infostruct *p = dev->infochain; infostruct *q = NULL; - MOD_DEC_USE_COUNT; while (p) { if (p->private == (char *) &(filep->private_data)) { if (q) @@ -1649,26 +1730,29 @@ else dev->infochain = (infostruct *) (p->next); kfree(p); - return 0; + goto out; } q = p; p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - return 0; + goto out; } - isdn_MOD_DEC_USE_COUNT(); + isdn_unlock_drivers(); if (minor < ISDN_MINOR_CTRL) - return 0; + goto out; if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) dev->profd = NULL; - return 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); #endif + + out: + MOD_DEC_USE_COUNT; return 0; } @@ -1911,21 +1995,12 @@ } int -register_isdn_module(isdn_module *m) { - return 0; -} - -int -unregister_isdn_module(isdn_module *m) { - return 0; -} - -int isdn_add_channels(driver *d, int drvidx, int n, int adding) { int j, k, m; ulong flags; + init_waitqueue_head(&d->st_waitq); if (d->flags & DRV_FLAG_RUNNING) return -1; if (n < 1) return 0; @@ -1975,8 +2050,9 @@ if ((adding) && (d->rcv_waitq)) kfree(d->rcv_waitq); - if (!(d->rcv_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) { + d->rcv_waitq = (wait_queue_head_t *) + kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); + if (!d->rcv_waitq) { printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); if (!adding) { kfree(d->rpqueue); @@ -1985,22 +2061,11 @@ } return -1; } - memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * m); - - if ((adding) && (d->snd_waitq)) - kfree(d->snd_waitq); - if (!(d->snd_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n"); - if (!adding) { - kfree(d->rcv_waitq); - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - } - return -1; + d->snd_waitq = d->rcv_waitq + m; + for (j = 0; j < m; j++) { + init_waitqueue_head(&d->rcv_waitq[j]); + init_waitqueue_head(&d->snd_waitq[j]); } - memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * m); dev->channels += n; save_flags(flags); @@ -2036,7 +2101,6 @@ } #ifdef CONFIG_ISDN_DIVERSION -extern isdn_divert_if *divert_if; static char *map_drvname(int di) { @@ -2089,8 +2153,6 @@ EXPORT_SYMBOL(register_isdn); -EXPORT_SYMBOL(register_isdn_module); -EXPORT_SYMBOL(unregister_isdn_module); #ifdef CONFIG_ISDN_PPP EXPORT_SYMBOL(isdn_ppp_register_compressor); EXPORT_SYMBOL(isdn_ppp_unregister_compressor); @@ -2158,12 +2220,6 @@ ***************************************************************************** */ -extern int printk(const char *fmt,...); - -#ifdef MODULE -#define isdn_init init_module -#endif - static char * isdn_getrev(const char *revision) { @@ -2183,8 +2239,7 @@ /* * Allocate and initialize all data, register modem-devices */ -int -isdn_init(void) +static int __init isdn_init(void) { int i; char tmprev[50]; @@ -2196,12 +2251,15 @@ memset((char *) dev, 0, sizeof(isdn_dev)); init_timer(&dev->timer); dev->timer.function = isdn_timer_funct; - dev->sem = MUTEX; + init_MUTEX(&dev->sem); + init_waitqueue_head(&dev->info_waitq); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; dev->m_idx[i] = -1; strcpy(dev->num[i], "???"); + init_waitqueue_head(&dev->mdm.info[i].open_wait); + init_waitqueue_head(&dev->mdm.info[i].close_wait); } if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { printk(KERN_WARNING "isdn: Could not register control devices\n"); @@ -2248,18 +2306,15 @@ printk(" loaded\n"); #else printk("\n"); - isdn_cards_init(); #endif isdn_info_update(); return 0; } -#ifdef MODULE /* * Unload module */ -void -cleanup_module(void) +static void isdn_exit(void) { int flags; int i; @@ -2293,11 +2348,15 @@ } if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) { printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n"); + restore_flags(flags); } else { del_timer(&dev->timer); + restore_flags(flags); + /* call vfree with interrupts enabled, else it will hang */ vfree(dev); printk(KERN_NOTICE "ISDN-subsystem unloaded\n"); } - restore_flags(flags); } -#endif + +module_init(isdn_init); +module_exit(isdn_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h --- v2.2.18/drivers/isdn/isdn_common.h Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_common.h Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.h,v 1.20 2000/06/16 13:00:27 keil Exp $ +/* $Id: isdn_common.h,v 1.21 2000/11/25 17:00:59 kai Exp $ * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel). * @@ -46,7 +46,7 @@ extern void isdn_timer_ctrl(int tf, int onoff); extern void isdn_unexclusive_channel(int di, int ch); extern int isdn_getnum(char **); -extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**); +extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); extern int isdn_get_free_channel(int, int, int, int, int, char *); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_concap.c linux/drivers/isdn/isdn_concap.c --- v2.2.18/drivers/isdn/isdn_concap.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_concap.c Sun Mar 25 11:37:33 2001 @@ -52,15 +52,19 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) { - int tmp; struct device *ndev = concap -> net_dev; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev; + isdn_net_local *lp = isdn_net_get_locked_lp(nd); IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name); + if (!lp) { + IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 1); + return 1; + } lp->huptimer = 0; - tmp=isdn_net_send_skb(ndev, lp, skb); - IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp); - return tmp; + isdn_net_writebuf_skb(lp, skb); + IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 0); + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.2.18/drivers/isdn/isdn_net.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_net.c Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.137 2000/09/12 19:43:47 kai Exp $ +/* $Id: isdn_net.c,v 1.140.6.3 2001/02/07 11:31:30 kai Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -30,6 +30,7 @@ #include #include #include +#include #include "isdn_common.h" #include "isdn_net.h" #ifdef CONFIG_ISDN_PPP @@ -72,7 +73,7 @@ * Find out if the netdevice has been ifup-ed yet. * For slaves, look at the corresponding master. */ -static int __inline__ isdn_net_started(isdn_net_dev *n) +static __inline__ int isdn_net_device_started(isdn_net_dev *n) { isdn_net_local *lp = n->local; struct device *dev; @@ -88,7 +89,7 @@ * wake up the network -> net_device queue. * For slaves, wake the corresponding master interface. */ -static void __inline__ isdn_net_lp_xon(isdn_net_local * lp) +static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) { if (lp->master) netif_wake_queue(lp->master); @@ -96,6 +97,76 @@ netif_wake_queue(&lp->netdev->dev); } +/* + * stop the network -> net_device queue. + * For slaves, stop the corresponding master interface. + */ +static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) +{ + if (lp->master) + netif_stop_queue(lp->master); + else + netif_stop_queue(&lp->netdev->dev); +} + +/* + * find out if the net_device which this lp belongs to (lp can be + * master or slave) is busy. It's busy iff all (master and slave) + * queues are busy + */ +static __inline__ int isdn_net_device_busy(isdn_net_local *lp) +{ + isdn_net_local *nlp; + isdn_net_dev *nd; + unsigned long flags; + + if (!isdn_net_lp_busy(lp)) + return 0; + + if (lp->master) + nd = ((isdn_net_local *) lp->master->priv)->netdev; + else + nd = lp->netdev; + + spin_lock_irqsave(&nd->queue_lock, flags); + nlp = lp->next; + while (nlp != lp) { + if (!isdn_net_lp_busy(nlp)) { + spin_unlock_irqrestore(&nd->queue_lock, flags); + return 0; + } + nlp = nlp->next; + } + spin_unlock_irqrestore(&nd->queue_lock, flags); + return 1; +} + +static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp) +{ + atomic_inc(&lp->frame_cnt); + if (isdn_net_device_busy(lp)) + isdn_net_device_stop_queue(lp); +} + +static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp) +{ + atomic_dec(&lp->frame_cnt); + + if (!(isdn_net_device_busy(lp))) { + if (!skb_queue_empty(&lp->super_tx_queue)) { + queue_task(&lp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } else { + isdn_net_device_wake_queue(lp); + } + } +} + +static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) +{ + atomic_set(&lp->frame_cnt, 0); +} + /* For 2.2.x we leave the transmitter busy timeout at 2 secs, just * to be safe. * For 2.3.x we push it up to 20 secs, because call establishment @@ -111,9 +182,8 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct device *); -static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.114 $"; +char *isdn_net_revision = "$Revision: 1.140.6.3 $"; /* * Code for raw-networking over ISDN @@ -122,7 +192,6 @@ static void isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason) { - if(skb) { u_short proto = ntohs(skb->protocol); @@ -225,16 +294,12 @@ isdn_net_unbind_channel(isdn_net_local * lp) { ulong flags; + struct sk_buff *skb; save_flags(flags); cli(); - if (lp->first_skb) { - dev_kfree_skb(lp->first_skb); - lp->first_skb = NULL; - } - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - lp->sav_skb = NULL; + while ((skb = skb_dequeue(&lp->super_tx_queue))) { + kfree_skb(skb); } if (!lp->master) { /* reset only master device */ /* Moral equivalent of dev_purge_queues(): @@ -331,6 +396,11 @@ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore); } +static void isdn_net_lp_disconnected(isdn_net_local *lp) +{ + isdn_net_rm_from_bundle(lp); +} + /* * Handle status-messages from ISDN-interfacecard. * This function is called from within the main-status-dispatcher @@ -354,28 +424,9 @@ /* A packet has successfully been sent out */ if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { + isdn_net_dec_frame_cnt(lp); lp->stats.tx_packets++; lp->stats.tx_bytes += c->parm.length; - /* some HL drivers deliver - ISDN_STAT_BSENT from hw interrupt. - Output routines in isdn_ppp are now - called with irq disabled such that - dequeueing the sav_skb while another - frame is sent will not occur. - */ - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) { - struct device *mdev; - if (lp->master) - mdev = lp->master; - else - mdev = &lp->netdev->dev; - if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) { - lp->sav_skb = NULL; - } else { - return 1; - } - } - isdn_net_lp_xon(lp); } return 1; case ISDN_STAT_DCONN: @@ -405,8 +456,10 @@ #endif /* CONFIG_ISDN_X25 */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { #ifdef CONFIG_ISDN_PPP - isdn_ppp_free(lp); + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); #endif + isdn_net_lp_disconnected(lp); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); printk(KERN_INFO "%s: remote hangup\n", lp->name); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, @@ -429,6 +482,7 @@ #endif /* CONFIG_ISDN_X25 */ case ISDN_STAT_BCONN: /* B-Channel is up */ + isdn_net_zero_frame_cnt(lp); switch (lp->dialstate) { case 5: case 6: @@ -446,13 +500,17 @@ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1); + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { + if (lp->master) { /* is lp a slave? */ + isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; + isdn_net_add_to_bundle(nd, lp); + } + } printk(KERN_INFO "isdn_net: %s connected\n", lp->name); /* If first Chargeinfo comes before B-Channel connect, * we correct the timestamp here. */ lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n", - lp->name, lp->chargetime); /* reset dial-timeout */ lp->dialstarted = 0; @@ -468,13 +526,9 @@ if( pops->connect_ind) pops->connect_ind(cprot); #endif /* CONFIG_ISDN_X25 */ - /* Immediately send first skb to speed up arp */ - if (lp->first_skb) { - - if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb))) - lp->first_skb = NULL; - } - if(! lp->first_skb) isdn_net_lp_xon(lp); + /* ppp needs to do negotiations first */ + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) + isdn_net_device_wake_queue(lp); return 1; } break; @@ -584,7 +638,7 @@ s = "dial suppressed: isdn system stopped"; else s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(&p->dev, lp->first_skb, s); + isdn_net_unreachable(&p->dev, 0, s); isdn_net_hangup(&p->dev); break; } @@ -617,7 +671,7 @@ restore_flags(flags); lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out"); + isdn_net_unreachable(&p->dev, 0, "dial: timed out"); isdn_net_hangup(&p->dev); break; } @@ -635,7 +689,7 @@ if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times"); + isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times"); } isdn_net_hangup(&p->dev); break; @@ -651,6 +705,7 @@ i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel); if (i >= 0) { strcpy(dev->num[i], cmd.parm.setup.phone); + dev->usage[i] |= ISDN_USAGE_OUTGOING; isdn_info_update(); } printk(KERN_INFO "%s: dialing %d %s...\n", lp->name, @@ -795,10 +850,21 @@ #endif if (lp->flags & ISDN_NET_CONNECTED) { + if (lp->slave != NULL) { + isdn_net_local *slp = (isdn_net_local *)lp->slave->priv; + if (slp->flags & ISDN_NET_CONNECTED) { + printk(KERN_INFO + "isdn_net: hang up slave %s before %s\n", + slp->name, lp->name); + isdn_net_hangup(lp->slave); + } + } printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); #ifdef CONFIG_ISDN_PPP - isdn_ppp_free(lp); + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); #endif + isdn_net_lp_disconnected(lp); #ifdef CONFIG_ISDN_X25 /* try if there are generic encap protocol receiver routines and signal the closure of @@ -911,31 +977,82 @@ } /* - * Generic routine to send out an skbuf. - * If lowlevel-device does not support support skbufs, use - * standard send-routine, else send directly. - * - * Return: 0 on success, !0 on failure. + * this function is used to send supervisory data, i.e. data which was + * not received from the network layer, but e.g. frames from ipppd, CCP + * reset frames etc. + */ +void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) +{ + if (in_interrupt()) { + // we can't grab the lock from irq context, + // so we just queue the packet + skb_queue_tail(&lp->super_tx_queue, skb); + queue_task(&lp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + } + + if (!isdn_net_lp_busy(lp)) { + isdn_net_writebuf_skb(lp, skb); + } else { + skb_queue_tail(&lp->super_tx_queue, skb); + } +} + +/* + * called from tq_immediate */ -int isdn_net_send_skb - (struct device *ndev, isdn_net_local * lp,struct sk_buff *skb) +static void isdn_net_softint(void *private) +{ + isdn_net_local *lp = private; + struct sk_buff *skb; + + while (!isdn_net_lp_busy(lp)) { + skb = skb_dequeue(&lp->super_tx_queue); + if (!skb) + break; + isdn_net_writebuf_skb(lp, skb); + } +} + +/* + * all frames sent from the (net) LL to a HL driver should go via this function + * it's serialized by the caller holding the lp->xmit_lock spinlock + */ +void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb) { int ret; int len = skb->len; /* save len */ - ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); - if (ret == len) { - lp->transcount += len; - return 0; + /* before obtaining the lock the caller should have checked that + the lp isn't busy */ + if (isdn_net_lp_busy(lp)) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + goto error; } - if (ret < 0) { - dev_kfree_skb(skb); - lp->stats.tx_errors++; - return 0; + + if (!(lp->flags & ISDN_NET_CONNECTED)) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + goto error; } - return 1; + ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); + if (ret != len) { + /* we should never get here */ + printk(KERN_WARNING "%s: HL driver queue full\n", lp->name); + goto error; + } + + lp->transcount += len; + isdn_net_inc_frame_cnt(lp); + return; + + error: + dev_kfree_skb(skb); + lp->stats.tx_errors++; + } + /* * Helper function for isdn_net_start_xmit. * When called, the connection is already established. @@ -948,9 +1065,18 @@ */ static int -isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb) +isdn_net_xmit(struct device *ndev, struct sk_buff *skb) { - int ret; + isdn_net_dev *nd; + isdn_net_local *slp; + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + int retv = 0; + + if (((isdn_net_local *) (ndev->priv))->master) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + dev_kfree_skb(skb); + return 0; + } /* For the other encaps the header has already been built */ #ifdef CONFIG_ISDN_PPP @@ -958,31 +1084,24 @@ return isdn_ppp_xmit(skb, ndev); } #endif + nd = ((isdn_net_local *) ndev->priv)->netdev; + lp = isdn_net_get_locked_lp(nd); + if (!lp) { + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); + return 1; + } + /* we have our lp locked from now on */ + /* Reset hangup-timeout */ - lp->huptimer = 0; - if (lp->cps > lp->triggercps) { - /* Device overloaded */ + lp->huptimer = 0; // FIXME? + isdn_net_writebuf_skb(lp, skb); - /* - * Packet-delivery via round-robin over master - * and all connected slaves. - */ - if (lp->master) - /* Slaves always deliver themselves */ - ret = isdn_net_send_skb(ndev, lp, skb); - else { - isdn_net_local *slp = (isdn_net_local *) (lp->srobin->priv); - /* Master delivers via srobin and maintains srobin */ - if (lp->srobin == ndev) - ret = isdn_net_send_skb(ndev, lp, skb); - else - ret = isdn_net_start_xmit(skb, lp->srobin); - lp->srobin = (slp->slave) ? slp->slave : ndev; - slp = (isdn_net_local *) (lp->srobin->priv); - if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0))) - lp->srobin = ndev; - } - /* Slave-startup using delay-variable */ + /* the following stuff is here for backwards compatibility. + * in future, start-up and hangup of slaves (based on current load) + * should move to userspace and get based on an overall cps + * calculation + */ + if (lp->cps > lp->triggercps) { if (lp->slave) { if (!lp->sqfull) { /* First time overload: set timestamp only */ @@ -990,17 +1109,24 @@ lp->sqfull_stamp = jiffies; } else { /* subsequent overload: if slavedelay exceeded, start dialing */ - if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) - isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); + if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) { + slp = lp->slave->priv; + if (!(slp->flags & ISDN_NET_CONNECTED)) { + isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); + } + } } } } else { - /* Not overloaded, deliver locally */ - ret = isdn_net_send_skb(ndev, lp, skb); - if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) + if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) { lp->sqfull = 0; + } + /* this is a hack to allow auto-hangup for slaves on moderate loads */ + nd->queue = nd->local; } - return ret; + + return retv; + } static void @@ -1078,6 +1204,7 @@ buf = skb->data; isdn_dumppkt("S:", buf, skb->len, 40); #endif + if (!(lp->flags & ISDN_NET_CONNECTED)) { int chi; /* only do autodial if allowed by config */ @@ -1150,19 +1277,11 @@ return 1; /* let upper layer requeue skb packet */ } #endif - /* remember first skb to speed up arp - * when using encap ETHER - */ - if (lp->first_skb) { - printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n"); - dev_kfree_skb(lp->first_skb); - lp->first_skb = NULL; - } - lp->first_skb = skb; /* Initiate dialing */ restore_flags(flags); isdn_net_dial(); - return 0; + isdn_net_device_stop_queue(lp); + return 1; } else { isdn_net_unreachable(ndev, skb, "No phone number"); @@ -1175,14 +1294,7 @@ if (!lp->dialstate) { /* ISDN connection is established, try sending */ int ret; - if (lp->first_skb) { - if (isdn_net_xmit(ndev, lp, lp->first_skb)){ - netif_stop_queue(ndev); - return 1; -} - lp->first_skb = NULL; - } - ret = (isdn_net_xmit(ndev, lp, skb)); + ret = (isdn_net_xmit(ndev, skb)); if(ret) netif_stop_queue(ndev); return ret; } else @@ -1231,7 +1343,7 @@ /* * Get statistics */ -static struct enet_statistics * +static struct net_device_stats * isdn_net_get_stats(struct device *dev) { isdn_net_local *lp = (isdn_net_local *) dev->priv; @@ -1297,7 +1409,6 @@ unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC); unsigned long t = (jiffies / HZ * 1000000); - int len; cisco_hdr *ch; cisco_slarp *s; @@ -1325,9 +1436,7 @@ s->rel = 0xffff; s->t1 = t >> 16; s->t0 = t & 0xffff; - len = skb->len; - if (isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 0, skb) != len) - dev_kfree_skb(skb); + isdn_net_write_super(lp, skb); } static void @@ -1411,7 +1520,6 @@ lp->stats.rx_packets++; lp->stats.rx_bytes += skb->len; } - skb->dev = ndev; skb->pkt_type = PACKET_HOST; skb->mac.raw = skb->data; @@ -1494,6 +1602,7 @@ isdn_ppp_receive(lp->netdev, olp, skb); return; #endif + default: #ifdef CONFIG_ISDN_X25 /* try if there are generic sync_device receiver routines */ @@ -1960,7 +2069,7 @@ * Is the interface up? * If not, reject the call actively. */ - if (!isdn_net_started(p)) { + if (!isdn_net_device_started(p)) { restore_flags(flags); printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", lp->name); @@ -2051,6 +2160,7 @@ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_free(lp); #endif + isdn_net_lp_disconnected(lp); isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); } @@ -2205,6 +2315,7 @@ memset(netdev, 0, sizeof(isdn_net_dev)); if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) { printk(KERN_WARNING "isdn_net: Could not allocate device locals\n"); + kfree(netdev); return NULL; } memset(netdev->local, 0, sizeof(isdn_net_local)); @@ -2240,10 +2351,17 @@ netdev->local->magic = ISDN_NET_MAGIC; netdev->queue = netdev->local; + spin_lock_init(&netdev->queue_lock); + netdev->local->last = netdev->local; netdev->local->netdev = netdev; netdev->local->next = netdev->local; + netdev->local->tqueue.sync = 0; + netdev->local->tqueue.routine = isdn_net_softint; + netdev->local->tqueue.data = netdev->local; + spin_lock_init(&netdev->local->xmit_lock); + netdev->local->isdn_device = -1; netdev->local->isdn_channel = -1; netdev->local->pre_device = -1; @@ -2251,13 +2369,11 @@ netdev->local->exclusive = -1; netdev->local->ppp_slot = -1; netdev->local->pppbind = -1; - netdev->local->sav_skb = NULL; - netdev->local->first_skb = NULL; + skb_queue_head_init(&netdev->local->super_tx_queue); netdev->local->l2_proto = ISDN_PROTO_L2_X75I; netdev->local->l3_proto = ISDN_PROTO_L3_TRANS; netdev->local->triggercps = 6000; netdev->local->slavedelay = 10 * HZ; - netdev->local->srobin = &netdev->dev; netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ netdev->local->onhtime = 10; /* Default hangup-time for saving costs of those who forget configuring this */ @@ -2295,7 +2411,7 @@ if (n->local->master) return NULL; /* Master must not be started yet */ - if (isdn_net_started(n)) + if (isdn_net_device_started(n)) return NULL; return (isdn_net_new(newname, &(n->dev))); } @@ -2338,7 +2454,7 @@ #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = p -> cprot; #endif - if (isdn_net_started(p)) { + if (isdn_net_device_started(p)) { printk(KERN_WARNING "%s: cannot change encap when if is up\n", lp->name); return -EBUSY; @@ -2771,8 +2887,7 @@ save_flags(flags); cli(); - - if (isdn_net_started(p)) { + if (isdn_net_device_started(p)) { restore_flags(flags); return -EBUSY; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v2.2.18/drivers/isdn/isdn_net.h Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_net.h Sun Mar 25 11:37:33 2001 @@ -82,8 +82,87 @@ extern int isdn_net_force_hangup(char *); extern int isdn_net_force_dial(char *); extern isdn_net_dev *isdn_net_findif(char *); -extern int isdn_net_send_skb(struct device *, isdn_net_local *, - struct sk_buff *); extern int isdn_net_rcv_skb(int, struct sk_buff *); extern void isdn_net_slarp_out(void); extern int isdn_net_dial_req(isdn_net_local *); +extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb); +extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); + +#define ISDN_NET_MAX_QUEUE_LENGTH 2 + +/* + * is this particular channel busy? + */ +static __inline__ int isdn_net_lp_busy(isdn_net_local *lp) +{ + if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH) + return 0; + else + return 1; +} + +/* + * For the given net device, this will get a non-busy channel out of the + * corresponding bundle. The returned channel is locked. + */ +static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd) +{ + unsigned long flags; + isdn_net_local *lp; + + spin_lock_irqsave(&nd->queue_lock, flags); + lp = nd->queue; /* get lp on top of queue */ + while (isdn_net_lp_busy(nd->queue)) { + nd->queue = nd->queue->next; + if (nd->queue == lp) { /* not found -- should never happen */ + lp = NULL; + goto errout; + } + } + lp = nd->queue; + nd->queue = nd->queue->next; +errout: + spin_unlock_irqrestore(&nd->queue_lock, flags); + return lp; +} + +/* + * add a channel to a bundle + */ +static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp) +{ + isdn_net_local *lp; + unsigned long flags; + + spin_lock_irqsave(&nd->queue_lock, flags); + + lp = nd->queue; + nlp->last = lp->last; + lp->last->next = nlp; + lp->last = nlp; + nlp->next = lp; + nd->queue = nlp; + + spin_unlock_irqrestore(&nd->queue_lock, flags); +} +/* + * remove a channel from the bundle it belongs to + */ +static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) +{ + isdn_net_local *master_lp = lp; + unsigned long flags; + + if (lp->master) + master_lp = (isdn_net_local *) lp->master->priv; + + spin_lock_irqsave(&master_lp->netdev->queue_lock, flags); + lp->last->next = lp->next; + lp->next->last = lp->last; + if (master_lp->netdev->queue == lp) + master_lp->netdev->queue = lp->next; + lp->next = lp->last = lp; /* (re)set own pointers */ + spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.2.18/drivers/isdn/isdn_ppp.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_ppp.c Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.63 2000/03/16 15:46:37 kai Exp $ +/* $Id: isdn_ppp.c,v 1.85.6.2 2001/01/23 17:45:02 kai Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -20,8 +20,6 @@ * */ -#define CONFIG_ISDN_CCP 1 - #include #define __NO_VERSION__ #include @@ -29,6 +27,7 @@ #include #include #include +#include #include "isdn_common.h" #include "isdn_ppp.h" @@ -38,8 +37,6 @@ #define PPP_IPX 0x002b #endif -/* set this if you use dynamic addressing */ - /* Prototypes */ static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); static int isdn_ppp_closewait(int slot); @@ -48,7 +45,7 @@ static int isdn_ppp_if_get_unit(char *namebuf); static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *); static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, - struct ippp_struct *,struct ippp_struct *,int proto); + struct ippp_struct *,struct ippp_struct *,int *proto); static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb,int proto); static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, @@ -85,11 +82,9 @@ static void isdn_ppp_mp_cleanup( isdn_net_local * lp ); static int isdn_ppp_bundle(struct ippp_struct *, int unit); - -#define MP_UNLOCK(b) up(&(b)->lock) #endif /* CONFIG_ISDN_MPP */ -char *isdn_ppp_revision = "$Revision: 1.63 $"; +char *isdn_ppp_revision = "$Revision: 1.85.6.2 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; @@ -124,55 +119,28 @@ int isdn_ppp_free(isdn_net_local * lp) { -#ifdef CONFIG_ISDN_MPP - isdn_net_local *master_lp = NULL; -#endif unsigned long flags; struct ippp_struct *is; - isdn_net_local * nlp; if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) return 0; - is = ippp_table[lp->ppp_slot]; - save_flags(flags); cli(); -#ifdef CONFIG_ISDN_MPP - spin_lock(&lp->netdev->pb->lock); // irq_save not necessary - - if (lp->master) - master_lp = (isdn_net_local *) lp->master->priv; - - - /* make sure none of the queue pointers will point to the - * interface being removed */ - for (nlp=lp->next; nlp != lp; nlp=nlp->next) - if (nlp->netdev->queue == lp ) - nlp->netdev->queue = lp->next; - lp->last->next = lp->next; - lp->next->last = lp->last; - - if (master_lp && master_lp->netdev->queue == lp) - master_lp->netdev->queue = lp->next; -/* - if (lp->next->netdev->queue == lp) - lp->next->netdev->queue = lp->next; - if (lp->last->netdev->queue == lp) - lp->last->netdev->queue = lp->last; -*/ +#ifdef CONFIG_ISDN_MPP + spin_lock(&lp->netdev->pb->lock); +#endif + isdn_net_rm_from_bundle(lp); +#ifdef CONFIG_ISDN_MPP if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ - isdn_ppp_mp_cleanup(lp); - - lp->next = lp->last = lp; /* (re)set own pointers */ - lp->netdev->queue = lp; - - spin_unlock(&lp->netdev->pb->lock); + isdn_ppp_mp_cleanup(lp); + lp->netdev->pb->ref_ct--; - + spin_unlock(&lp->netdev->pb->lock); #endif /* CONFIG_ISDN_MPP */ + is = ippp_table[lp->ppp_slot]; if ((is->state & IPPP_CONNECT)) isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ else if (is->state & IPPP_ASSIGNED) @@ -183,8 +151,8 @@ is->lp = NULL; /* link is down .. set lp to NULL */ lp->ppp_slot = -1; /* is this OK ?? */ - restore_flags(flags); + restore_flags(flags); return 0; } @@ -199,12 +167,8 @@ long flags; struct ippp_struct *is; - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) - return -1; - save_flags(flags); cli(); - if (lp->pppbind < 0) { /* device bounded to ippp device ? */ isdn_net_dev *net_dev = dev->netdev; char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ @@ -243,7 +207,6 @@ } lp->ppp_slot = i; - is = ippp_table[i]; is->lp = lp; is->unit = unit; @@ -270,8 +233,7 @@ return; ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; - - if (ippp_table[lp->ppp_slot]->wq) + wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); } @@ -289,7 +251,7 @@ return 0; is = ippp_table[slot]; - if (is->state && is->wq) + if (is->state) wake_up_interruptible(&is->wq); is->state = IPPP_CLOSEWAIT; @@ -350,7 +312,7 @@ is->mru = 1524; /* MRU, default 1524 */ is->maxcid = 16; /* VJ: maxcid */ is->tk = current; - is->wq = NULL; /* read() wait queue */ + init_waitqueue_head(&is->wq); is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ is->last = is->rq; is->minor = min; @@ -714,7 +676,6 @@ is->last = bl->next; restore_flags(flags); - if (is->wq) wake_up_interruptible(&is->wq); return len; @@ -805,8 +766,6 @@ lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { unsigned short hl; - unsigned long flags; - int cnt; struct sk_buff *skb; /* * we need to reserve enought space in front of @@ -829,17 +788,7 @@ isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */ - save_flags(flags); - cli(); - if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) { - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count); - } else - printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count); - lp->sav_skb = skb; - } - restore_flags(flags); + isdn_net_write_super(lp, skb); } } return count; @@ -899,15 +848,49 @@ } /* + * check for address/control field and skip if allowed + * retval != 0 -> discard packet silently + */ +static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) +{ + if (skb->len < 1) + return -1; + + if (skb->data[0] == 0xff) { + if (skb->len < 2) + return -1; + + if (skb->data[1] != 0x03) + return -1; + + // skip address/control (AC) field + skb_pull(skb, 2); + } else { + if (is->pppcfg & SC_REJ_COMP_AC) + // if AC compression was not negotiated, but used, discard packet + return -1; + } + return 0; +} + +/* * get the PPP protocol header and pull skb + * retval < 0 -> discard packet silently */ static int isdn_ppp_strip_proto(struct sk_buff *skb) { int proto; + + if (skb->len < 1) + return -1; + if (skb->data[0] & 0x1) { + // protocol field is compressed proto = skb->data[0]; - skb_pull(skb, 1); /* protocol ID is only 8 bit */ + skb_pull(skb, 1); } else { + if (skb->len < 2) + return -1; proto = ((int) skb->data[0] << 8) + skb->data[1]; skb_pull(skb, 2); } @@ -924,6 +907,9 @@ int slot; int proto; + if (net_dev->local->master) + BUG(); // we're called with the master device always + slot = lp->ppp_slot; if (slot < 0 || slot > ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot); @@ -937,135 +923,95 @@ (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len); isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } - if (net_dev->local->master) { - printk(KERN_WARNING "isdn_ppp_receive: net_dev != master\n"); - net_dev = ((isdn_net_local *) net_dev->local->master->priv)->netdev; - } - if (skb->data[0] == 0xff && skb->data[1] == 0x03) - skb_pull(skb, 2); - else if (is->pppcfg & SC_REJ_COMP_AC) { - dev_kfree_skb(skb); - return; /* discard it silently */ - } - - proto = isdn_ppp_strip_proto(skb); + if (isdn_ppp_skip_ac(is, skb) < 0) { + kfree_skb(skb); + return; + } + proto = isdn_ppp_strip_proto(skb); + if (proto < 0) { + kfree_skb(skb); + return; + } + #ifdef CONFIG_ISDN_MPP - if (!(is->mpppcfg & SC_REJ_MP_PROT)) { - - if(is->compflags & SC_LINK_DECOMP_ON) { - if(proto == PPP_LINK_COMP) { - if(is->debug & 0x10) - printk(KERN_DEBUG "received single link compressed frame\n"); - skb = isdn_ppp_decompress(skb,is,NULL,proto); - if(!skb) { - printk(KERN_DEBUG "ippp: dropping LINK_COMP frame!\n"); - return; - } - proto = isdn_ppp_strip_proto(skb); - } else { - skb = isdn_ppp_decompress(skb,is,NULL,proto); - if(!skb) { - printk(KERN_DEBUG "ippp: dropping uncompressed frame!\n"); - return; - } - } - } - - if (proto == PPP_MP) { - isdn_ppp_mp_receive(net_dev, lp, skb); - } - else - isdn_ppp_push_higher(net_dev, lp, skb, proto); - } else -#endif /* CONFIG_ISDN_MPP */ - isdn_ppp_push_higher(net_dev, lp, skb, proto); + if (is->compflags & SC_LINK_DECOMP_ON) { + skb = isdn_ppp_decompress(skb, is, NULL, &proto); + if (!skb) // decompression error + return; + } + + if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP + if (proto == PPP_MP) { + isdn_ppp_mp_receive(net_dev, lp, skb); + return; + } + } +#endif + isdn_ppp_push_higher(net_dev, lp, skb, proto); } /* - * push frame to higher layers + * we receive a reassembled frame, MPPP has been taken care of before. + * address/control and protocol have been stripped from the skb * note: net_dev has to be master net_dev */ static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto) { struct device *dev = &net_dev->dev; - struct ippp_struct *is; + struct ippp_struct *is, *mis; int slot; slot = lp->ppp_slot; if (slot < 0 || slot > ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot); - kfree_skb(skb); - return; + goto drop_packet; } is = ippp_table[slot]; + + if (lp->master) { // FIXME? + slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot); + goto drop_packet; + } + } + mis = ippp_table[slot]; if (is->debug & 0x10) { printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } - - if(proto == PPP_COMP) { - if(!lp->master) { - skb = isdn_ppp_decompress(skb,is,is,proto); - } else { - skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); - } - if(!skb) { - printk(KERN_DEBUG "ippp: compressed frame discarded!\n"); - return; - } - - proto = isdn_ppp_strip_proto(skb); - if (is->debug & 0x10) { - printk(KERN_DEBUG "RPostDecomp, skb %d %04x\n", (int) skb->len, proto); - isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot); - } - } - else if (is->compflags & SC_DECOMP_ON) { /* If decomp is ON */ - if(!lp->master) { - skb = isdn_ppp_decompress(skb,is,is,proto); - } else { - skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); - } - - if(!skb) { - printk(KERN_DEBUG "ippp: compressed frame discarded!\n"); - return; - } - } - + if (is->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_decompress(skb, is, mis, &proto); + if (!skb) // decompression error + return; + } switch (proto) { case PPP_IPX: /* untested */ if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: IPX\n"); - skb->dev = dev; - skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IPX); break; + case PPP_IP: + if (is->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: IP\n"); + skb->protocol = htons(ETH_P_IP); + break; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); - net_dev->local->stats.rx_dropped++; - dev_kfree_skb(skb); - return; + goto drop_packet; } -#endif - case PPP_IP: - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: IP\n"); - skb->dev = dev; - skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IP); break; case PPP_VJC_COMP: if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); -#ifdef CONFIG_ISDN_PPP_VJ { struct sk_buff *skb_old = skb; int pkt_len; @@ -1073,34 +1019,24 @@ if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - net_dev->local->stats.rx_dropped++; - dev_kfree_skb(skb_old); - return; + skb = skb_old; + goto drop_packet; } - skb->dev = dev; skb_put(skb, skb_old->len + 128); memcpy(skb->data, skb_old->data, skb_old->len); - skb->mac.raw = skb->data; pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb_old->len); - dev_kfree_skb(skb_old); - if (pkt_len < 0) { - dev_kfree_skb(skb); - lp->stats.rx_dropped++; - return; - } + kfree_skb(skb_old); + if (pkt_len < 0) + goto drop_packet; + skb_trim(skb, pkt_len); skb->protocol = htons(ETH_P_IP); } -#else - printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n"); - lp->stats.rx_dropped++; - dev_kfree_skb(skb); - return; -#endif break; +#endif case PPP_CCP: - case PPP_LINK_CCP: + case PPP_CCPFRAG: isdn_ppp_receive_ccp(net_dev,lp,skb,proto); /* Dont pop up ResetReq/Ack stuff to the daemon any longer - the job is done already */ @@ -1110,21 +1046,27 @@ /* fall through */ default: isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ - dev_kfree_skb(skb); + kfree_skb(skb); return; } /* Reset hangup-timer */ lp->huptimer = 0; - netif_rx(skb); - /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ return; + + drop_packet: + net_dev->local->stats.rx_dropped++; + kfree_skb(skb); } /* * isdn_ppp_skb_push .. - * checks whether we have enough space at the beginning of the SKB + * checks whether we have enough space at the beginning of the skb * and allocs a new SKB if necessary */ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len) @@ -1159,20 +1101,13 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev) { - struct device *mdev = ((isdn_net_local *) (netdev->priv))->master; /* get master (for redundancy) */ isdn_net_local *lp,*mlp; isdn_net_dev *nd; unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt,*ipts; - unsigned long flags; int slot; - if (mdev) - mlp = (isdn_net_local *) (mdev->priv); - else { - mdev = netdev; - mlp = (isdn_net_local *) (netdev->priv); - } + mlp = (isdn_net_local *) (netdev->priv); nd = mlp->netdev; /* get master lp */ slot = mlp->ppp_slot; @@ -1197,22 +1132,19 @@ proto = PPP_IPX; /* untested */ break; default: + printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", + skb->protocol); dev_kfree_skb(skb); - printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocol: %#x.\n", skb->protocol); return 0; } - lp = nd->queue; /* get lp on top of queue */ - - if (lp->sav_skb) { /* find a non-busy device */ - isdn_net_local *nlp = lp->next; - while (nlp->sav_skb) { - if (lp == nlp) - return 1; - nlp = nd->queue = nd->queue->next; - } - lp = nlp; + lp = isdn_net_get_locked_lp(nd); + if (!lp) { + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); + return 1; } + /* we have our lp locked from now on */ + slot = lp->ppp_slot; if (slot < 0 || slot > ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot); @@ -1227,8 +1159,8 @@ */ /* Pull off the fake header we stuck on earlier to keep - * the fragemntation code happy. - */ + * the fragmentation code happy. + */ skb_pull(skb,IPPP_MAX_HEADER); if (ipt->debug & 0x4) @@ -1301,11 +1233,10 @@ /* we get mp_seqno from static isdn_net_local */ long mp_seqno = ipts->mp_seqno; ipts->mp_seqno++; - nd->queue = nd->queue->next; if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) { unsigned char *data = isdn_ppp_skb_push(&skb, 3); if(!data) - return 0; + goto unlock; mp_seqno &= 0xfff; data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */ data[1] = mp_seqno & 0xff; @@ -1313,7 +1244,7 @@ } else { unsigned char *data = isdn_ppp_skb_push(&skb, 5); if(!data) - return 0; + goto unlock; data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ data[2] = (mp_seqno >> 8) & 0xff; @@ -1333,20 +1264,20 @@ if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { unsigned char *data = isdn_ppp_skb_push(&skb,1); if(!data) - return 0; + goto unlock; data[0] = proto & 0xff; } else { unsigned char *data = isdn_ppp_skb_push(&skb,2); if(!data) - return 0; + goto unlock; data[0] = (proto >> 8) & 0xff; data[1] = proto & 0xff; } if(!(ipt->pppcfg & SC_COMP_AC)) { unsigned char *data = isdn_ppp_skb_push(&skb,2); if(!data) - return 0; + goto unlock; data[0] = 0xff; /* All Stations */ data[1] = 0x03; /* Unnumbered information */ } @@ -1357,16 +1288,10 @@ printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot); } - save_flags(flags); - cli(); - if (isdn_net_send_skb(netdev, lp, skb)) { - if (lp->sav_skb) { /* should never happen as sav_skb are sent with disabled IRQs) */ - printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name); - dev_kfree_skb(skb); - } else - lp->sav_skb = skb; - } - restore_flags(flags); + + isdn_net_writebuf_skb(lp, skb); + + unlock: return 0; } @@ -1397,8 +1322,8 @@ static int isdn_ppp_mp_bundle_array_init(void) { - int i; - int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); + int i; + int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz, GFP_KERNEL)) == NULL ) return -ENOMEM; @@ -1410,7 +1335,7 @@ static ippp_bundle * isdn_ppp_mp_bundle_alloc(void) { - int i; + int i; for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) if (isdn_ppp_bundle_arr[i].ref_ct <= 0) return (isdn_ppp_bundle_arr + i); @@ -1419,7 +1344,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) { - struct ippp_struct * is = ippp_table[lp->ppp_slot]; + struct ippp_struct * is = ippp_table[lp->ppp_slot]; if (add_to) { if( lp->netdev->pb ) @@ -1442,9 +1367,9 @@ static u32 isdn_ppp_mp_get_seq( int short_seq, struct sk_buff * skb, u32 last_seq ); -struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, +static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, struct sk_buff * from, struct sk_buff * to ); -void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, +static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff * from, struct sk_buff * to ); static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); @@ -1452,18 +1377,27 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { - struct ippp_struct *is = ippp_table[lp->ppp_slot]; + struct ippp_struct *is; isdn_net_local * lpq; ippp_bundle * mp; isdn_mppp_stats * stats; struct sk_buff * newfrag, * frag, * start, *nextf; u32 newseq, minseq, thisseq; unsigned long flags; - - spin_lock_irqsave(&net_dev->pb->lock, flags); + int slot; + + spin_lock_irqsave(&net_dev->pb->lock, flags); mp = net_dev->pb; stats = &mp->stats; - + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot); + stats->frame_drops++; + dev_kfree_skb(skb); + spin_unlock_irqrestore(&mp->lock, flags); + return; + } + is = ippp_table[slot]; if( ++mp->frames > stats->max_queue_len ) stats->max_queue_len = mp->frames; @@ -1491,9 +1425,14 @@ /* find the minimum received sequence number over all links */ is->last_link_seqno = minseq = newseq; for (lpq = net_dev->queue;;) { - u32 lls = ippp_table[lpq->ppp_slot]->last_link_seqno; - if (MP_LT(lls, minseq)) - minseq = lls; + slot = lpq->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot); + } else { + u32 lls = ippp_table[slot]->last_link_seqno; + if (MP_LT(lls, minseq)) + minseq = lls; + } if ((lpq = lpq->next) == net_dev->queue) break; } @@ -1645,20 +1584,19 @@ * queue overflow */ if (mp->frames > MP_MAX_QUEUE_LEN) { stats->overflows++; - while (mp->frames < MP_MAX_QUEUE_LEN) { + while (mp->frames > MP_MAX_QUEUE_LEN) { frag = mp->frags->next; isdn_ppp_mp_free_skb(mp, mp->frags); mp->frags = frag; } } - spin_unlock_irqrestore(&mp->lock, flags); } static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) { - struct sk_buff * frag = lp->netdev->pb->frags; - struct sk_buff * nextfrag; + struct sk_buff * frag = lp->netdev->pb->frags; + struct sk_buff * nextfrag; while( frag ) { nextfrag = frag->next; isdn_ppp_mp_free_skb(lp->netdev->pb, frag); @@ -1670,8 +1608,8 @@ static u32 isdn_ppp_mp_get_seq( int short_seq, struct sk_buff * skb, u32 last_seq ) { - u32 seq; - int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG); + u32 seq; + int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG); if( !short_seq ) { @@ -1716,46 +1654,40 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff * from, struct sk_buff * to ) { - ippp_bundle * mp = net_dev->pb; - int proto; - struct sk_buff * skb; - unsigned int tot_len; - - if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) - { + ippp_bundle * mp = net_dev->pb; + int proto; + struct sk_buff * skb; + unsigned int tot_len; + + if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { if( ippp_table[lp->ppp_slot]->debug & 0x40 ) printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, " "len %d\n", MP_SEQ(from), from->len ); skb = from; skb_pull(skb, MP_HEADER_LEN); mp->frames--; - } - else - { - struct sk_buff * frag; - int n; - - for( tot_len=0, frag=from, n = 0; frag != to; - frag=frag->next, n++ ) + } else { + struct sk_buff * frag; + int n; + + for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++) tot_len += frag->len - MP_HEADER_LEN; - + if( ippp_table[lp->ppp_slot]->debug & 0x40 ) printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " "to %d, len %d\n", MP_SEQ(from), (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len ); - - if( (skb = dev_alloc_skb(tot_len)) == NULL ) - { - printk(KERN_ERR"isdn_mppp: cannot allocate sk buff " + if( (skb = dev_alloc_skb(tot_len)) == NULL ) { + printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " "of size %d\n", tot_len); isdn_ppp_mp_discard(mp, from, to); return; } - - while( from != to ) - { - unsigned int len = from->len - MP_HEADER_LEN; - memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len); + + while( from != to ) { + unsigned int len = from->len - MP_HEADER_LEN; + + memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len); frag = from->next; isdn_ppp_mp_free_skb(mp, from); from = frag; @@ -1784,15 +1716,13 @@ { char ifn[IFNAMSIZ + 1]; isdn_net_dev *p; - isdn_net_local *lp, - *nlp; + isdn_net_local *lp, *nlp; int rc; unsigned long flags; sprintf(ifn, "ippp%d", unit); p = isdn_net_findif(ifn); - if (!p) - { + if (!p) { printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn); return -EINVAL; } @@ -1800,38 +1730,29 @@ spin_lock_irqsave(&p->pb->lock, flags); nlp = is->lp; - lp = p->queue; - if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS || - lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) - { - spin_unlock_irqrestore(&p->pb->lock, flags); + lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) { printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n", - nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? - nlp->ppp_slot : lp->ppp_slot ); - return -EINVAL; - } - - nlp->last = lp->last; - lp->last->next = nlp; - lp->last = nlp; - nlp->next = lp; - p->queue = nlp; + nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? + nlp->ppp_slot : lp->ppp_slot ); + rc = -EINVAL; + goto out; + } + + isdn_net_add_to_bundle(p, nlp); ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; -/* maybe also SC_CCP stuff */ - ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & - (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); + /* maybe also SC_CCP stuff */ + ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & + (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & - (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); - - rc = isdn_ppp_mp_init(nlp, p->pb); - + (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); + rc = isdn_ppp_mp_init(nlp, p->pb); +out: spin_unlock_irqrestore(&p->pb->lock, flags); - - return rc; + return rc; } #endif /* CONFIG_ISDN_MPP */ @@ -2051,8 +1972,7 @@ { struct sk_buff *skb; unsigned char *p; - int count, hl; - unsigned long flags; + int hl; int cnt = 0; isdn_net_local *lp = is->lp; @@ -2093,26 +2013,7 @@ printk(KERN_DEBUG "Sending CCP Frame:\n"); isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); - /* Just ripped from isdn_ppp_write. Dunno whether it makes sense, - especially dunno what the sav_skb stuff is good for. */ - - count = skb->len; - save_flags(flags); - cli(); - if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, - 1, skb)) != count) { - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - printk(KERN_INFO - "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", - cnt, count); - } else - printk(KERN_INFO - "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", - cnt, count); - lp->sav_skb = skb; - } - restore_flags(flags); + isdn_net_write_super(lp, skb); } /* Allocate the reset state vector */ @@ -2359,17 +2260,21 @@ is->reset->lastid++; } +/* + * decompress packet + * + * if master = 0, we're trying to uncompress an per-link compressed packet, + * as opposed to an compressed reconstructed-from-MPPP packet. + * proto is updated to protocol field of uncompressed packet. + * + * retval: decompressed packet, + * same packet if uncompressed, + * NULL if decompression error + */ + static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master, - int proto) + int *proto) { -#ifndef CONFIG_ISDN_CCP - if(proto == PPP_COMP || proto == PPP_LINK_COMP) { - printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n"); - dev_kfree_skb(skb); - return NULL; - } - return skb; -#else void *stat = NULL; struct isdn_ppp_compressor *ipc = NULL; struct sk_buff *skb_out; @@ -2379,83 +2284,65 @@ unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; if(!master) { - /* - * single link decompression - */ - if(!is->link_decompressor) { - printk(KERN_DEBUG "ippp: no link decompressor defined!\n"); - return skb; - } - if(!is->link_decomp_stat) { - printk(KERN_DEBUG "ippp: no link decompressor data allocated\n"); - return skb; - } + // per-link decompression stat = is->link_decomp_stat; ipc = is->link_decompressor; ri = is; - } - else { - /* - * 'normal' or bundle-compression - */ - if(!master->decompressor) { - printk(KERN_DEBUG "ippp: no decompressor defined!\n"); - return skb; - } - if(!master->decomp_stat) { - printk(KERN_DEBUG "ippp: no decompressor data allocated\n"); - return skb; - } + } else { stat = master->decomp_stat; ipc = master->decompressor; ri = master; } - /* - printk(KERN_DEBUG "ippp: Decompress valid!\n"); - */ + if (!ipc) { + // no decompressor -> we can't decompress. + printk(KERN_DEBUG "ippp: no decompressor defined!\n"); + return skb; + } + if (!stat) // if we have a compressor, stat has been set as well + BUG(); - if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) { - /* Set up reset params for the decompressor */ - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) { + // compressed packets are compressed by their protocol type -/* !!!HACK,HACK,HACK!!! 2048 is only assumed */ - skb_out = dev_alloc_skb(2048); - len = ipc->decompress(stat,skb,skb_out, &rsparm); - dev_kfree_skb(skb); - if(len <= 0) { - /* Ok, some error */ - switch(len) { - case DECOMP_ERROR: - ri->pppcfg |= SC_DC_ERROR; - printk(KERN_INFO "ippp: decomp wants reset %s params\n", - rsparm.valid ? "with" : "without"); - - isdn_ppp_ccp_reset_trans(ri, &rsparm); - - break; - case DECOMP_FATALERROR: - ri->pppcfg |= SC_DC_FERROR; - /* Kick ipppd to recognize the error */ - isdn_ppp_ccp_kickup(ri); - break; - } - /* Did I see a leak here ? */ - dev_kfree_skb(skb_out); - return NULL; + // Set up reset params for the decompressor + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + + skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN); + len = ipc->decompress(stat, skb, skb_out, &rsparm); + kfree_skb(skb); + if (len <= 0) { + switch(len) { + case DECOMP_ERROR: + ri->pppcfg |= SC_DC_ERROR; + printk(KERN_INFO "ippp: decomp wants reset %s params\n", + rsparm.valid ? "with" : "without"); + + isdn_ppp_ccp_reset_trans(ri, &rsparm); + break; + case DECOMP_FATALERROR: + ri->pppcfg |= SC_DC_FERROR; + /* Kick ipppd to recognize the error */ + isdn_ppp_ccp_kickup(ri); + break; + } + kfree_skb(skb_out); + return NULL; + } + *proto = isdn_ppp_strip_proto(skb_out); + if (*proto < 0) { + kfree_skb(skb_out); + return NULL; } return skb_out; - } - else { - /* - printk(KERN_DEBUG "isdn_ppp: [%d] Calling incomp with this frame!\n",is->unit); - */ - ipc->incomp(stat,skb,proto); + } else { + // uncompressed packets are fed through the decompressor to + // update the decompressor state + ipc->incomp(stat, skb, *proto); return skb; } -#endif } /* @@ -2474,13 +2361,9 @@ void *stat; struct sk_buff *skb_out; -#ifdef CONFIG_ISDN_CCP /* we do not compress control protocols */ if(*proto < 0 || *proto > 0x3fff) { -#else - { -#endif - return skb_in; + return skb_in; } if(type) { /* type=1 => Link compression */ @@ -2681,7 +2564,7 @@ } proto = ((int)data[0]<<8)+data[1]; - if(proto != PPP_CCP && proto != PPP_LINK_CCP) + if(proto != PPP_CCP && proto != PPP_CCPFRAG) return; printk(KERN_DEBUG "Received CCP frame from daemon:\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.2.18/drivers/isdn/isdn_tty.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_tty.c Sun Mar 25 11:37:33 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.93 2000/08/05 09:58:26 armin Exp $ +/* $Id: isdn_tty.c,v 1.94 2000/11/25 17:00:59 kai Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -53,14 +53,20 @@ #define MODEM_PARANOIA_CHECK #define MODEM_DO_RESTART +#ifdef CONFIG_DEVFS_FS +static char *isdn_ttyname_ttyI = "isdn/ttyI%d"; +static char *isdn_ttyname_cui = "isdn/cui%d"; +#else static char *isdn_ttyname_ttyI = "ttyI"; static char *isdn_ttyname_cui = "cui"; +#endif + static int bit2si[8] = {1, 5, 7, 7, 7, 7, 7, 7}; static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.84 $"; +char *isdn_tty_revision = "$Revision: 1.94 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -1177,6 +1183,7 @@ int c; int total = 0; modem_info *info = (modem_info *) tty->driver_data; + atemu *m = &info->emu; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write")) return 0; @@ -1197,8 +1204,6 @@ || (info->vonline & 3) #endif ) { - atemu *m = &info->emu; - #ifdef CONFIG_ISDN_AUDIO if (!info->vonline) #endif @@ -1256,7 +1261,9 @@ isdn_command(&c); } info->vonline = 0; - printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c); +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c); +#endif info->xmit_count += cc; } else #endif @@ -1278,9 +1285,14 @@ count -= c; total += c; } - if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); atomic_dec(&info->xmit_lock); + if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) { + if (m->mdmreg[REG_DXMT] & BIT_DXMT) { + isdn_tty_senddown(info); + isdn_tty_tint(info); + } + isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); + } if (from_user) up(&info->write_sem); return total; @@ -1621,8 +1633,7 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info) { - struct wait_queue wait = - {current, NULL}; + DECLARE_WAITQUEUE(wait, NULL); int do_clocal = 0; unsigned long flags; int retval; @@ -1700,7 +1711,7 @@ restore_flags(flags); info->blocked_open++; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ISDN_ASYNC_INITIALIZED)) { #ifdef MODEM_DO_RESTART @@ -1873,7 +1884,7 @@ */ timeout = jiffies + HZ; while (!(info->lsr & UART_LSR_TEMT)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(20); if (time_after(jiffies,timeout)) break; @@ -1889,7 +1900,7 @@ info->ncarrier = 0; tty->closing = 0; if (info->blocked_open) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(50); wake_up_interruptible(&info->open_wait); } @@ -2091,7 +2102,7 @@ return -3; } #endif - info->write_sem = MUTEX; + init_MUTEX(&info->write_sem); sprintf(info->last_cause, "0000"); sprintf(info->last_num, "none"); info->last_dir = 0; @@ -2108,8 +2119,8 @@ info->blocked_open = 0; info->callout_termios = m->cua_modem.init_termios; info->normal_termios = m->tty_modem.init_termios; - info->open_wait = 0; - info->close_wait = 0; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); info->isdn_driver = -1; info->isdn_channel = -1; info->drv_index = -1; @@ -2364,11 +2375,21 @@ #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line); #endif + /* Wake up any processes waiting + * for incoming call of this device when + * DCD follow the state of incoming carrier + */ + if (info->blocked_open && + (info->emu.mdmreg[REG_DCD] & BIT_DCD)) { + wake_up_interruptible(&info->open_wait); + } + /* Schedule CONNECT-Message to any tty * waiting for it and * set DCD-bit of its modem-status. */ - if (TTY_IS_ACTIVE(info)) { + if (TTY_IS_ACTIVE(info) || + (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { info->msr |= UART_MSR_DCD; info->emu.charge = 0; if (info->dialing & 0xf) @@ -2609,7 +2630,7 @@ if ((jiffies - *lastplus) < PLUSWAIT2) *pluscount = 0; } - if ((*pluscount == 3) && (count = 1)) + if ((*pluscount == 3) && (count == 1)) isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1); if (*pluscount > 3) *pluscount = 1; @@ -2822,8 +2843,8 @@ int limit = ISDN_MSNLEN - 1; while (((*p[0] >= '0' && *p[0] <= '9') || - /* Why a comma ??? */ - (*p[0] == ',')) && + /* Why a comma ??? */ + (*p[0] == ',') || (*p[0] == ':')) && (limit--)) *n++ = *p[0]++; *n = '\0'; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h --- v2.2.18/drivers/isdn/isdn_tty.h Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_tty.h Sun Mar 25 11:37:34 2001 @@ -57,6 +57,8 @@ #define REG_CPPP 12 #define BIT_CPPP 128 +#define REG_DXMT 13 +#define BIT_DXMT 1 #define REG_T70 13 #define BIT_T70 2 #define BIT_T70_EXT 32 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_v110.c linux/drivers/isdn/isdn_v110.c --- v2.2.18/drivers/isdn/isdn_v110.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdn_v110.c Sun Mar 25 11:37:34 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_v110.c,v 1.5 2000/05/11 22:29:21 kai Exp $ +/* $Id: isdn_v110.c,v 1.5.6.2 2001/02/10 14:41:19 kai Exp $ * Linux ISDN subsystem, V.110 related functions (linklevel). * @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -30,7 +30,7 @@ #undef ISDN_V110_DEBUG -char *isdn_v110_revision = "$Revision: 1.5 $"; +char *isdn_v110_revision = "$Revision: 1.5.6.2 $"; #define V110_38400 255 #define V110_19200 15 @@ -102,7 +102,7 @@ int i; isdn_v110_stream *v; - if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_KERNEL)) == NULL) + if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL) return NULL; memset(v, 0, sizeof(isdn_v110_stream)); v->key = key; @@ -134,7 +134,7 @@ v->b = 0; v->skbres = hdrlen; v->maxsize = maxsize - hdrlen; - if ((v->encodebuf = kmalloc(maxsize, GFP_KERNEL)) == NULL) { + if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) { kfree(v); return NULL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdnloop/Makefile linux/drivers/isdn/isdnloop/Makefile --- v2.2.18/drivers/isdn/isdnloop/Makefile Sun Mar 25 11:13:08 2001 +++ linux/drivers/isdn/isdnloop/Makefile Sun Mar 25 11:37:34 2001 @@ -1,11 +1,14 @@ -L_OBJS := -M_OBJS := +# +# Makefile for the isdnloop ISDN device driver +# -ifeq ($(CONFIG_ISDN_DRV_LOOP),y) - L_OBJS += isdnloop.o -else - M_OBJS += isdnloop.o -endif +# The target object and module list name. -include $(TOPDIR)/Rules.make +O_TARGET := vmlinux-obj.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop.o + +include $(TOPDIR)/drivers/isdn/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c --- v2.2.18/drivers/isdn/isdnloop/isdnloop.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdnloop/isdnloop.c Sun Mar 25 11:37:34 2001 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.c,v 1.11 2000/11/13 22:51:50 kai Exp $ +/* $Id: isdnloop.c,v 1.11.6.1 2000/12/17 16:47:18 kai Exp $ * ISDN low-level module implementing a dummy loop driver. * @@ -21,10 +21,12 @@ */ #include +#include +#include #include "isdnloop.h" static char -*revision = "$Revision: 1.11 $"; +*revision = "$Revision: 1.11.6.1 $"; static int isdnloop_addcard(char *); @@ -1534,22 +1536,7 @@ return 0; } -#ifdef MODULE -#define isdnloop_init init_module -#else -void -isdnloop_setup(char *str, int *ints) -{ - static char sid[20]; - - if (strlen(str)) { - strcpy(sid, str); - isdnloop_id = sid; - } -} -#endif - -int +static int __init isdnloop_init(void) { char *p; @@ -1568,9 +1555,8 @@ return (isdnloop_addcard(isdnloop_id)); } -#ifdef MODULE -void -cleanup_module(void) +static void +isdnloop_exit(void) { isdn_ctrl cmd; isdnloop_card *card = cards; @@ -1598,4 +1584,6 @@ } printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n"); } -#endif + +module_init(isdnloop_init); +module_exit(isdnloop_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h --- v2.2.18/drivers/isdn/isdnloop/isdnloop.h Sun Mar 25 11:28:24 2001 +++ linux/drivers/isdn/isdnloop/isdnloop.h Sun Mar 25 11:37:34 2001 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.h,v 1.5 2000/11/13 22:51:50 kai Exp $ +/* $Id: isdnloop.h,v 1.5.6.1 2001/02/10 14:41:23 kai Exp $ * Loopback lowlevel module for testing of linklevel. * @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/Makefile linux/drivers/isdn/pcbit/Makefile --- v2.2.18/drivers/isdn/pcbit/Makefile Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/Makefile Sun Mar 25 11:37:34 2001 @@ -1,15 +1,21 @@ -L_OBJS := -M_OBJS := -O_OBJS := module.o edss1.o drv.o layer2.o capi.o callbacks.o - -O_TARGET := -ifeq ($(CONFIG_ISDN_DRV_PCBIT),y) - O_TARGET += pcbit.o -else - ifeq ($(CONFIG_ISDN_DRV_PCBIT),m) - O_TARGET += pcbit.o - M_OBJS += pcbit.o - endif -endif +# Makefile for the pcbit ISDN device driver -include $(TOPDIR)/Rules.make +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Multipart objects. + +list-multi := pcbit.o +pcbit-objs := module.o edss1.o drv.o layer2.o capi.o callbacks.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit.o + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +pcbit.o: $(pcbit-objs) + $(LD) -r -o $@ $(pcbit-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c --- v2.2.18/drivers/isdn/pcbit/callbacks.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/callbacks.c Sun Mar 25 11:37:34 2001 @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c --- v2.2.18/drivers/isdn/pcbit/capi.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/capi.c Sun Mar 25 11:37:34 2001 @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.2.18/drivers/isdn/pcbit/drv.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/drv.c Sun Mar 25 11:37:34 2001 @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include @@ -86,6 +86,7 @@ dev_pcbit[board] = dev; memset(dev, 0, sizeof(struct pcbit_dev)); + init_waitqueue_head(&dev->set_running_wq); if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) { dev->ph_mem = mem_base; @@ -118,8 +119,6 @@ memset(dev->b2, 0, sizeof(struct pcbit_chan)); dev->b2->id = 1; - - dev->qdelivery.next = NULL; dev->qdelivery.sync = 0; dev->qdelivery.routine = pcbit_deliver; dev->qdelivery.data = dev; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/edss1.c linux/drivers/isdn/pcbit/edss1.c --- v2.2.18/drivers/isdn/pcbit/edss1.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/edss1.c Sun Mar 25 11:37:34 2001 @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c --- v2.2.18/drivers/isdn/pcbit/layer2.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/layer2.c Sun Mar 25 11:37:34 2001 @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c --- v2.2.18/drivers/isdn/pcbit/module.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/module.c Sun Mar 25 11:37:34 2001 @@ -12,7 +12,7 @@ */ #include - +#include #include #include #include @@ -26,21 +26,12 @@ static int irq[MAX_PCBIT_CARDS] = {0, }; static int num_boards; -struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0}; - -int init_module(void); -void cleanup_module(void); +struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, }; extern void pcbit_terminate(int board); extern int pcbit_init_dev(int board, int mem_base, int irq); -#ifdef MODULE -MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); -#define pcbit_init init_module -#endif - -int pcbit_init(void) +static int __init pcbit_init(void) { int board; @@ -83,15 +74,10 @@ else return -EIO; } - - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; - return 0; } -#ifdef MODULE -void cleanup_module(void) +static void pcbit_exit(void) { int board; @@ -101,7 +87,7 @@ "PCBIT-D module unloaded\n"); } -#else +#ifndef MODULE void pcbit_setup(char *str, int *ints) { int i, j, argc; @@ -126,5 +112,9 @@ } #endif +MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); +module_init(pcbit_init); +module_exit(pcbit_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/pcbit/pcbit.h linux/drivers/isdn/pcbit/pcbit.h --- v2.2.18/drivers/isdn/pcbit/pcbit.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/pcbit/pcbit.h Sun Mar 25 11:37:34 2001 @@ -69,7 +69,7 @@ struct frame_buf *write_queue; /* Protocol start */ - struct wait_queue *set_running_wq; + wait_queue_head_t set_running_wq; struct timer_list set_running_timer; struct timer_list error_recover_timer; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/sc/Makefile linux/drivers/isdn/sc/Makefile --- v2.2.18/drivers/isdn/sc/Makefile Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/sc/Makefile Sun Mar 25 11:37:34 2001 @@ -1,44 +1,22 @@ -# -# $Id: Makefile,v 1.1 1997/03/22 02:01:22 fritz Exp $ -# Copyright (C) 1996 SpellCaster Telecommunications Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# For more information, please contact gpl-info@spellcast.com or write: -# -# SpellCaster Telecommunications Inc. -# 5621 Finch Avenue East, Unit #3 -# Scarborough, Ontario Canada -# M1B 2T9 -# +1 (416) 297-8565 -# +1 (416) 297-6433 Facsimile -# - -L_OBJS := -M_OBJS := -O_OBJS := shmem.o init.o debug.o packet.o command.o event.o \ - ioctl.o interrupt.o message.o timer.o - -O_TARGET := -ifeq ($(CONFIG_ISDN_DRV_SC),y) - O_TARGET += sc.o -else - ifeq ($(CONFIG_ISDN_DRV_SC),m) - O_TARGET += sc.o - M_OBJS += sc.o - endif -endif +# Makefile for the sc ISDN device driver -include $(TOPDIR)/Rules.make +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Multipart objects. + +list-multi := sc.o +sc-objs := shmem.o init.o debug.o packet.o command.o event.o \ + ioctl.o interrupt.o message.o timer.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_SC) += sc.o + +include $(TOPDIR)/drivers/isdn/Rules.make + +# Link rules for multi-part drivers. + +sc.o: $(sc-objs) + $(LD) -r -o $@ $(sc-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/sc/debug.c linux/drivers/isdn/sc/debug.c --- v2.2.18/drivers/isdn/sc/debug.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/sc/debug.c Sun Mar 25 11:37:34 2001 @@ -1,5 +1,5 @@ /* - * $Id: debug.c,v 1.3 1997/10/01 09:22:20 fritz Exp $ + * $Id: debug.c,v 1.5 2000/11/12 15:29:37 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify @@ -27,11 +27,6 @@ */ #include -#define NULL 0x0 - -#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) -#define FREE_IRQ(a,b) free_irq(a,b) - inline char *strcpy(char *, const char *); int dbg_level = 0; @@ -61,7 +56,7 @@ *i = *j; i++; j++; } - *(++i) = NULL; + *(++i) = 0; return dest; } @@ -70,6 +65,6 @@ int i = 0; while(dn[i] != ',') - str[i] = dn[i++]; + str[i] = dn[i], i++; str[i] = 0x0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/sc/debug.h linux/drivers/isdn/sc/debug.h --- v2.2.18/drivers/isdn/sc/debug.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/sc/debug.h Sun Mar 25 11:37:34 2001 @@ -1,5 +1,5 @@ /* - * $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $ + * $Id: debug.h,v 1.2 2000/02/26 01:00:53 keil Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify @@ -26,10 +26,5 @@ * +1 (416) 297-6433 Facsimile */ -#if LINUX_VERSION_CODE < 131072 - #error You cant use this driver on kernels older than 2.0 -#else - #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) - #define FREE_IRQ(a,b) free_irq(a,b) -#endif - +#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) +#define FREE_IRQ(a,b) free_irq(a,b) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/sc/includes.h linux/drivers/isdn/sc/includes.h --- v2.2.18/drivers/isdn/sc/includes.h Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/sc/includes.h Sun Mar 25 11:37:34 2001 @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/sc/init.c linux/drivers/isdn/sc/init.c --- v2.2.18/drivers/isdn/sc/init.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/sc/init.c Sun Mar 25 11:37:34 2001 @@ -1,3 +1,5 @@ +#include +#include #include "includes.h" #include "hardware.h" #include "card.h" @@ -37,23 +39,12 @@ return 0; } -#ifdef MODULE MODULE_PARM(io, "1-4i"); MODULE_PARM(irq, "1-4i"); MODULE_PARM(ram, "1-4i"); MODULE_PARM(do_reset, "i"); -#define init_sc init_module -#else -/* -Initialization code for non-module version to be included -void sc_setup(char *str, int *ints) -{ -} -*/ -#endif - -int init_sc(void) +static int __init sc_init(void) { int b = -1; int i, j; @@ -164,7 +155,7 @@ if(do_reset) { pr_debug("Doing a SAFE probe reset\n"); outb(0xFF, io[b] + RESET_OFFSET); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(milliseconds(10000)); } pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b], @@ -302,7 +293,7 @@ /* * No interrupt could be used */ - pr_debug("Failed to aquire an IRQ line\n"); + pr_debug("Failed to acquire an IRQ line\n"); continue; } @@ -410,8 +401,7 @@ return status; } -#ifdef MODULE -void cleanup_module(void) +static void sc_exit(void) { int i, j; @@ -463,7 +453,6 @@ } pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n"); } -#endif int identify_board(unsigned long rambase, unsigned int iobase) { @@ -512,7 +501,7 @@ * Try to identify a PRI card */ outb(PRI_BASEPG_VAL, pgport); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); sig = readl(rambase + SIG_OFFSET); pr_debug("Looking for a signature, got 0x%x\n", sig); @@ -523,7 +512,7 @@ * Try to identify a PRI card */ outb(BRI_BASEPG_VAL, pgport); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); sig = readl(rambase + SIG_OFFSET); pr_debug("Looking for a signature, got 0x%x\n", sig); @@ -555,7 +544,7 @@ */ x = 0; while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); x++; } @@ -579,3 +568,6 @@ return -1; } + +module_init(sc_init); +module_exit(sc_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c --- v2.2.18/drivers/isdn/sc/message.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/sc/message.c Sun Mar 25 11:37:34 2001 @@ -266,7 +266,7 @@ tries = 0; /* wait for the response */ while (tries < timeout) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); pr_debug("SAR waiting..\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/sc/timer.c linux/drivers/isdn/sc/timer.c --- v2.2.18/drivers/isdn/sc/timer.c Sun Mar 25 11:13:07 2001 +++ linux/drivers/isdn/sc/timer.c Sun Mar 25 11:37:34 2001 @@ -1,5 +1,5 @@ /* - * $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $ + * $Id: timer.c,v 1.3 2000/05/06 00:52:39 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify @@ -91,9 +91,7 @@ else { pr_debug("%s: No signature yet, waiting another %d jiffies.\n", adapter[card]->devicename, CHECKRESET_TIME); - del_timer(&adapter[card]->reset_timer); - adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME; - add_timer(&adapter[card]->reset_timer); + mod_timer(&adapter[card]->reset_timer, jiffies+CHECKRESET_TIME); } restore_flags(flags); @@ -138,9 +136,7 @@ /* Reinitialize the timer */ save_flags(flags); cli(); - del_timer(&adapter[card]->stat_timer); - adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME; - add_timer(&adapter[card]->stat_timer); + mod_timer(&adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME); restore_flags(flags); /* Send a new cePhyStatus message */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/macintosh/mac_hid.c linux/drivers/macintosh/mac_hid.c --- v2.2.18/drivers/macintosh/mac_hid.c Sun Mar 25 11:28:24 2001 +++ linux/drivers/macintosh/mac_hid.c Sun Mar 25 11:37:34 2001 @@ -184,8 +184,6 @@ int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode); -static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp); char mac_hid_kbd_unexpected_up(unsigned char keycode); static int keyboard_lock_keycodes = 0; @@ -194,6 +192,8 @@ int keyboard_sends_linux_keycodes = 1; #endif /* CONFIG_MAC_ADBKEYCODES */ +static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp); static unsigned char e0_keys[128] = { 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ @@ -225,22 +225,25 @@ extern void pckbd_init_hw(void); -#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) +#ifdef CONFIG_SYSCTL /* file(s) in /proc/sys/dev/mac_hid */ ctl_table mac_hid_files[] = { -#ifdef CONFIG_MAC_ADBKEYCODES { + /* Leave it available when ADB keycodes are disabled for the sanity of + * distro installers... + */ DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES, "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int), 0644, NULL, &mac_hid_sysctl_keycodes }, +#ifdef CONFIG_MAC_ADBKEYCODES { DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES, "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int), 0644, NULL, &proc_dointvec }, -#endif +#endif /* CONFIG_MAC_ADBKEYCODES */ #ifdef CONFIG_MAC_EMUMOUSEBTN { DEV_MAC_HID_MOUSE_BUTTON_EMULATION, @@ -257,7 +260,7 @@ "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int), 0644, NULL, &proc_dointvec }, -#endif +#endif /* CONFIG_MAC_EMUMOUSEBTN */ { 0 } }; @@ -277,11 +280,13 @@ static struct ctl_table_header *mac_hid_sysctl_header; -#ifdef CONFIG_MAC_ADBKEYCODES static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp) { +#ifndef CONFIG_MAC_ADBKEYCODES + return write ? 0 : proc_dointvec(ctl, write, filp, buffer, lenp); +#else /* CONFIG_MAC_ADBKEYCODES */ int val = keyboard_sends_linux_keycodes; int ret = 0; @@ -293,14 +298,14 @@ && keyboard_sends_linux_keycodes != val) { if (!keyboard_sends_linux_keycodes) { #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + ppc_md.sysrq_xlate = mac_hid_kbd_sysrq_xlate; SYSRQ_KEY = 0x69; #endif memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); } else { #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; SYSRQ_KEY = 0x54; #endif memcpy(mac_key_maps_save, key_maps, sizeof(key_maps)); @@ -309,8 +314,8 @@ } return ret; +#endif /* CONFIG_MAC_ADBKEYCODES */ } -#endif #endif /* endif CONFIG_SYSCTL */ int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, @@ -486,7 +491,7 @@ pckbd_init_hw(); #endif -#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) +#ifdef CONFIG_SYSCTL mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); #endif /* CONFIG_SYSCTL */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/3c527.c linux/drivers/net/3c527.c --- v2.2.18/drivers/net/3c527.c Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/3c527.c Sun Mar 25 11:37:34 2001 @@ -1,9 +1,8 @@ - -/* 3c527.c: 3Com Etherlink/MC32 driver for Linux +/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.2 * * (c) Copyright 1998 Red Hat Software Inc - * Written by Alan Cox. - * Further debugging by Carl Drougge. + * Written by Alan Cox. + * Modified by Richard Procter (rnp@netlink.co.nz) * * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c * (for the MCA stuff) written by Wim Dumon. @@ -12,26 +11,70 @@ * documentation. * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. * */ static const char *version = - "3c527.c:v0.08 2000/02/22 Alan Cox (alan@redhat.com)\n"; + "3c527.c:v0.5 1999/09/16 Alan Cox (alan@redhat.com)\n"; -/* - * Things you need - * o The databook. - * - * Traps for the unwary +/** + * DOC: Traps for the unwary * * The diagram (Figure 1-1) and the POS summary disagree with the * "Interrupt Level" section in the manual. * + * The manual contradicts itself when describing the minimum number + * buffers in the 'configure lists' command. + * My card accepts a buffer config of 4/4. + * + * Setting the SAV BP bit does not save bad packets, but + * only enables RX on-card stats collection. + * * The documentation in places seems to miss things. In actual fact * I've always eventually found everything is documented, it just * requires careful study. - */ + * + * DOC: Theory Of Operation + * + * The 3com 3c527 is a 32bit MCA bus mastering adapter with a large + * amount of on board intelligence that housekeeps a somewhat dumber + * Intel NIC. For performance we want to keep the transmit queue deep + * as the card can transmit packets while fetching others from main + * memory by bus master DMA. Transmission and reception are driven by + * circular buffer queues. + * + * The mailboxes can be used for controlling how the card traverses + * its buffer rings, but are used only for inital setup in this + * implementation. The exec mailbox allows a variety of commands to + * be executed. Each command must complete before the next is + * executed. Primarily we use the exec mailbox for controlling the + * multicast lists. We have to do a certain amount of interesting + * hoop jumping as the multicast list changes can occur in interrupt + * state when the card has an exec command pending. We defer such + * events until the command completion interrupt. + * + * A copy break scheme (taken from 3c59x.c) is employed whereby + * received frames exceeding a configurable length are passed + * directly to the higher networking layers without incuring a copy, + * in what amounts to a time/space trade-off. + * + * The card also keeps a large amount of statistical information + * on-board. In a perfect world, these could be used safely at no + * cost. However, lacking information to the contrary, processing + * them without races would involve so much extra complexity as to + * make it unworthwhile to do so. In the end, a hybrid SW/HW + * implementation was made necessary --- see mc32_update_stats(). + * + * DOC: Notes + * + * It should be possible to use two or more cards, but at this stage + * only by loading two copies of the same module. + * + * The on-board 82586 NIC has trouble receiving multiple + * back-to-back frames and so is likely to drop packets from fast + * senders. +**/ #include @@ -56,6 +99,7 @@ #include #include #include +#include #include "3c527.h" @@ -69,23 +113,36 @@ #ifndef NET_DEBUG #define NET_DEBUG 2 #endif + +#undef DEBUG_IRQ + static unsigned int mc32_debug = NET_DEBUG; /* The number of low I/O ports used by the ethercard. */ -#define NETCARD_IO_EXTENT 8 +#define MC32_IO_EXTENT 8 +/* As implemented, values must be a power-of-2 -- 4/8/16/32 */ +#define TX_RING_LEN 32 /* Typically the card supports 37 */ +#define RX_RING_LEN 8 /* " " " */ + +/* Copy break point, see above for details. + * Setting to > 1512 effectively disables this feature. */ +#define RX_COPYBREAK 200 /* Value from 3c59x.c */ + +/* Issue the 82586 workaround command - this is for "busy lans", but + * basically means for all lans now days - has a performance (latency) + * cost, but best set. */ +static const int WORKAROUND_82586=1; -struct mc32_mailbox +/* Pointers to buffers and their on-card records */ +struct mc32_ring_desc { - u16 mbox __attribute((packed)); - u16 data[1] __attribute((packed)); + volatile struct skb_header *p; + struct sk_buff *skb; }; -/* Information that need to be kept for each board. */ - -#define TX_RING_MAX 16 /* Typically the card supports 37 */ -#define RX_RING_MAX 32 /* " " " */ +/* Information that needs to be kept for each board. */ struct mc32_local { struct net_device_stats net_stats; @@ -93,25 +150,28 @@ volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; - volatile u16 *stats; - u16 tx_chain; - u16 rx_chain; - u16 tx_len; - u16 rx_len; + volatile struct mc32_stats *stats; /* Start of on-card statistics */ + u16 tx_chain; /* Transmit list start offset */ + u16 rx_chain; /* Receive list start offset */ + u16 tx_len; /* Transmit list count */ + u16 rx_len; /* Receive list count */ + u32 base; - u16 rx_halted; - u16 tx_halted; - u16 rx_pending; /* ring due a service */ u16 exec_pending; u16 mc_reload_wait; /* a multicast load request is pending */ - atomic_t tx_count; /* buffers left */ + u32 mc_list_valid; /* True when the mclist is set */ + u16 xceiver_state; /* Current transceiver state. bitmapped */ + u16 desired_state; /* The state we want the transceiver to be in */ + atomic_t tx_count; /* buffers left */ struct wait_queue *event; - struct sk_buff *tx_skb[TX_RING_MAX]; /* Transmit ring */ - u16 tx_skb_top; - u16 tx_skb_end; - struct sk_buff *rx_skb[RX_RING_MAX]; /* Receive ring */ - void *rx_ptr[RX_RING_MAX]; /* Data pointers */ - u32 mc_list_valid; /* True when the mclist is set */ + + struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */ + struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */ + + u16 tx_ring_tail; /* index to tx de-queue end */ + u16 tx_ring_head; /* index to tx en-queue end */ + + u16 rx_ring_tail; /* index to rx de-queue end */ }; /* The station (ethernet) address prefix, used for a sanity check. */ @@ -124,18 +184,25 @@ char *name; }; -static struct mca_adapters_t mc32_adapters[] __initdata = { +const struct mca_adapters_t mc32_adapters[] = { { 0x0041, "3COM EtherLink MC/32" }, { 0x8EF5, "IBM High Performance Lan Adapter" }, { 0x0000, NULL } }; -/* Index to functions, as function prototypes. */ +/* Macros for ring index manipulations */ +static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); }; +static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); }; +static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); }; + + +/* Index to functions, as function prototypes. */ extern int mc32_probe(struct device *dev); static int mc32_probe1(struct device *dev, int ioaddr); +static int mc32_command(struct device *dev, u16 cmd, void *data, int len); static int mc32_open(struct device *dev); static int mc32_send_packet(struct sk_buff *skb, struct device *dev); static void mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -144,12 +211,14 @@ static void mc32_set_multicast_list(struct device *dev); static void mc32_reset_multicast_list(struct device *dev); -/* - * Check for a network adaptor of this type, and return '0' iff one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). +/** + * mc32_probe: + * @dev: device to probe + * + * Because MCA bus is a real bus and we can scan for cards we could do a + * single scan for all boards here. Right now we use the passed in device + * structure and scan for only one board. This needs fixing for modules + * in paticular. */ __initfunc(int mc32_probe(struct device *dev)) @@ -183,15 +252,21 @@ return -ENODEV; } -/* - * This is the real probe routine. Linux has a history of friendly device - * probes on the ISA bus. A good device probes avoids doing writes, and - * verifies that the correct device exists and functions. +/** + * mc32_probe1: + * @dev: Device structure to fill in + * @slot: The MCA bus slot being used by this card + * + * Decode the slot data and configure the card structures. Having done this we + * can reset the card and configure it. The card does a full self test cycle + * in firmware so we have to wait for it to return and post us either a + * failure case or some addresses we use to find the board internals. */ + __initfunc(static int mc32_probe1(struct device *dev, int slot)) { static unsigned version_printed = 0; - int i; + int i, err; u8 POS; u32 base; struct mc32_local *lp; @@ -224,7 +299,7 @@ "82586 initialisation failure", "Adapter list configuration error" }; - + /* Time to play MCA games */ if (mc32_debug && version_printed++ == 0) @@ -327,20 +402,21 @@ * Grab the IRQ */ - if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev)) - { - printk("%s: unable to get IRQ %d.\n", - dev->name, dev->irq); - return -EAGAIN; + i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); + if(i) { + printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return i; } + request_region(dev->base_addr, MC32_IO_EXTENT, cardname); + /* Initialize the device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); - if (dev->priv == NULL) + if (dev->priv == NULL) { - free_irq(dev->irq, dev); - return -ENOMEM; + err = -ENOMEM; + goto err_exit_irq; } } @@ -358,8 +434,8 @@ if(i==1000) { printk("%s: failed to boot adapter.\n", dev->name); - free_irq(dev->irq, dev); - return -ENODEV; + err = -ENODEV; + goto err_exit_free; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) @@ -373,8 +449,8 @@ base<0x0A?" test failure":""); else printk("%s: unknown failure %d.\n", dev->name, base); - free_irq(dev->irq, dev); - return -ENODEV; + err = -ENODEV; + goto err_exit_free; } base=0; @@ -389,8 +465,8 @@ if(n>100) { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); - free_irq(dev->irq, dev); - return -ENODEV; + err = -ENODEV; + goto err_exit_free; } } @@ -399,11 +475,11 @@ lp->exec_box=bus_to_virt(dev->mem_start+base); - base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; + base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; lp->base = dev->mem_start+base; - lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); + lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]); lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]); @@ -412,74 +488,77 @@ * Descriptor chains (card relative) */ - lp->tx_chain = lp->exec_box->data[8]; - lp->rx_chain = lp->exec_box->data[10]; - lp->tx_len = lp->exec_box->data[9]; - lp->rx_len = lp->exec_box->data[11]; - - printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n", - dev->name, lp->rx_len, lp->tx_len, lp->base); + lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ + lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ + lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ + lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ - if(lp->tx_len >TX_RING_MAX) - lp->tx_len = TX_RING_MAX; - + printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", + dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); + dev->open = mc32_open; dev->stop = mc32_close; dev->hard_start_xmit = mc32_send_packet; dev->get_stats = mc32_get_stats; dev->set_multicast_list = mc32_set_multicast_list; - lp->rx_halted = 1; - lp->tx_halted = 1; - lp->rx_pending = 0; + lp->xceiver_state = HALTED; + + lp->tx_ring_tail=lp->tx_ring_head=0; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); + return 0; + +err_exit_free: + kfree(dev->priv); +err_exit_irq: + free_irq(dev->irq, dev); + release_region(dev->base_addr, MC32_IO_EXTENT); + return err; } -/* - * Polled command stuff +/** + * mc32_ready_poll: + * @dev: The device to wait for + * + * Wait until the card becomes ready to accept a command via the + * command register. This tells us nothing about the completion + * status of any pending commands and takes very little time at all. */ -static void mc32_ring_poll(struct device *dev) +static void mc32_ready_poll(struct device *dev) { int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); } -/* - * Send exec commands. This requires a bit of explaining. +/** + * mc32_command_nowait: + * @dev: The 3c527 to issue the command to + * @cmd: The command word to write to the mailbox + * @data: A data block if the command expects one + * @len: Length of the data block * - * You feed the card a command, you wait, it interrupts you get a - * reply. All well and good. The complication arises because you use - * commands for filter list changes which come in at bh level from things - * like IPV6 group stuff. - * - * We have a simple state machine - * - * 0 - nothing issued - * 1 - command issued, wait reply - * 2 - reply waiting - reader then goes to state 0 - * 3 - command issued, trash reply. In which case the irq - * takes it back to state 0 - */ - - -/* - * Send command from interrupt state + * Send a command from interrupt state. If there is a command + * currently being executed then we return an error of -1. It simply + * isn't viable to wait around as commands may be slow. Providing we + * get in, we busy wait for the board to become ready to accept the + * command and issue it. We do not wait for the command to complete + * --- the card will interrupt us when it's done. */ static int mc32_command_nowait(struct device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - + if(lp->exec_pending) return -1; - + lp->exec_pending=3; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; @@ -493,9 +572,35 @@ } -/* - * Send command and block for results. On completion spot and reissue - * multicasts +/** + * mc32_command: + * @dev: The 3c527 card to issue the command to + * @cmd: The command word to write to the mailbox + * @data: A data block if the command expects one + * @len: Length of the data block + * + * Sends exec commands in a user context. This permits us to wait around + * for the replies and also to wait for the command buffer to complete + * from a previous command before we execute our command. After our + * command completes we will complete any pending multicast reload + * we blocked off by hogging the exec buffer. + * + * You feed the card a command, you wait, it interrupts you get a + * reply. All well and good. The complication arises because you use + * commands for filter list changes which come in at bh level from things + * like IPV6 group stuff. + * + * We have a simple state machine + * + * 0 - nothing issued + * + * 1 - command issued, wait reply + * + * 2 - reply waiting - reader then goes to state 0 + * + * 3 - command issued, trash reply. In which case the irq + * takes it back to state 0 + * */ static int mc32_command(struct device *dev, u16 cmd, void *data, int len) @@ -531,207 +636,311 @@ /* Send the command */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(1<<6, ioaddr+HOST_CMD); - + save_flags(flags); cli(); + while(lp->exec_pending!=2) sleep_on(&lp->event); lp->exec_pending=0; restore_flags(flags); - - if(lp->exec_box->data[0]&(1<<13)) + if(lp->exec_box->mbox&(1<<13)) ret = -1; + /* * A multicast set got blocked - do it now */ if(lp->mc_reload_wait) + { mc32_reset_multicast_list(dev); + } return ret; } -/* - * RX abort - */ - -static void mc32_rx_abort(struct device *dev) -{ - struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; +/** + * mc32_start_transceiver: + * @dev: The 3c527 card to issue the command to + * + * This may be called from the interrupt state, where it is used + * to restart the rx ring if the card runs out of rx buffers. + * + * First, we check if it's ok to start the transceiver. We then show + * the card where to start in the rx ring and issue the + * commands to start reception and transmission. We don't wait + * around for these to complete. + */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - - lp->rx_box->mbox=0; - outb(3<<3, ioaddr+HOST_CMD); /* Suspend reception */ -} +static void mc32_start_transceiver(struct device *dev) { - -/* - * RX enable - */ - -static void mc32_rx_begin(struct device *dev) -{ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - - lp->rx_box->mbox=0; - outb(1<<3, ioaddr+HOST_CMD); /* GO */ - mc32_ring_poll(dev); - - lp->rx_halted=0; - lp->rx_pending=0; -} -static void mc32_tx_abort(struct device *dev) -{ - struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - + /* Ignore RX overflow on device closure */ + if (lp->desired_state==HALTED) + return; + + mc32_ready_poll(dev); + lp->tx_box->mbox=0; - outb(3, ioaddr+HOST_CMD); /* Suspend */ - - /* Ring empty */ - - atomic_set(&lp->tx_count, lp->tx_len); + lp->rx_box->mbox=0; + + /* Give the card the offset to the post-EOL-bit RX descriptor */ + lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; + + outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); + + mc32_ready_poll(dev); + outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */ - /* Flush */ - if(lp->tx_skb_top!=lp->tx_skb_end) - { - int i; - if(lp->tx_skb_top<=lp->tx_skb_end) - { - for(i=lp->tx_skb_top;itx_skb_end;i++) - { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i]=NULL; - } - } - else - { - for(i=lp->tx_skb_end;itx_skb[i]); - lp->tx_skb[i]=NULL; - } - for(i=0;itx_skb_top;i++) - { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i]=NULL; - } - } - } - lp->tx_skb_top=lp->tx_skb_end=0; + /* We are not interrupted on start completion */ + lp->xceiver_state=RUNNING; } -/* - * TX enable - */ - -static void mc32_tx_begin(struct device *dev) + +/** + * mc32_halt_transceiver: + * @dev: The 3c527 card to issue the command to + * + * We issue the commands to halt the card's transceiver. In fact, + * after some experimenting we now simply tell the card to + * suspend. When issuing aborts occasionally odd things happened. + * + * We then sleep until the card has notified us that both rx and + * tx have been suspended. + */ + +static void mc32_halt_transceiver(struct device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - + unsigned long flags; + + mc32_ready_poll(dev); + lp->tx_box->mbox=0; -#if 0 - outb(5, ioaddr+HOST_CMD); /* GO */ - printk("TX=>5\n"); - mc32_ring_poll(dev); - if(lp->tx_box->mbox&(1<<13)) - printk("TX begin error!\n"); -#endif - lp->tx_halted=0; -} + lp->rx_box->mbox=0; - -/* - * Load the rx ring + outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD); + mc32_ready_poll(dev); + outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD); + + save_flags(flags); + cli(); + + while(lp->xceiver_state!=HALTED) + sleep_on(&lp->event); + + restore_flags(flags); +} + + +/** + * mc32_load_rx_ring: + * @dev: 3c527 to build the ring for + * + * This initalises the on-card and driver datastructures to + * the point where mc32_start_transceiver() can be called. + * + * The card sets up the receive ring for us. We are required to use the + * ring it provides although we can change the size of the ring. + * + * We allocate an sk_buff for each ring entry in turn and + * initalise its house-keeping info. At the same time, we read + * each 'next' pointer in our rx_ring array. This reduces slow + * shared-memory reads and makes it easy to access predecessor + * descriptors. + * + * We then set the end-of-list bit for the last entry so that the + * card will know when it has run out of buffers. */ - + static int mc32_load_rx_ring(struct device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int i; - u16 base; + u16 rx_base; volatile struct skb_header *p; - base = lp->rx_box->data[0]; - - /* Fix me - should use card size - also fix flush ! */ + rx_base=lp->rx_chain; - for(i=0;irx_skb[i]=alloc_skb(1532, GFP_KERNEL); - if(lp->rx_skb[i]==NULL) + lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); + skb_reserve(lp->rx_ring[i].skb, 18); + + if(lp->rx_ring[i].skb==NULL) { for(;i>=0;i--) - kfree_skb(lp->rx_skb[i]); + kfree_skb(lp->rx_ring[i].skb); return -ENOBUFS; } - lp->rx_ptr[i]=lp->rx_skb[i]->data+18; - p=bus_to_virt(lp->base+base); + p=bus_to_virt(lp->base+rx_base); + p->control=0; - p->data = virt_to_bus(lp->rx_ptr[i]); + p->data=virt_to_bus(lp->rx_ring[i].skb->data); p->status=0; - p->length = 1532; - base = p->next; + p->length=1532; + + lp->rx_ring[i].p=p; + rx_base=p->next; } - p->control = (1<<6); - lp->rx_box->mbox = 0; + + lp->rx_ring[i-1].p->control |= CONTROL_EOL; + + lp->rx_ring_tail=0; + return 0; } -static void mc32_flush_rx_ring(struct mc32_local *lp) -{ - int i; - for(i=0;irx_skb[i]); -} -static void mc32_flush_tx_ring(struct mc32_local *lp) +/** + * mc32_flush_rx_ring: + * @lp: Local data of 3c527 to flush the rx ring of + * + * Free the buffer for each ring slot. This may be called + * before mc32_load_rx_ring(), eg. on error in mc32_open(). + */ + +static void mc32_flush_rx_ring(struct device *dev) { - int i; + struct mc32_local *lp = (struct mc32_local *)dev->priv; - if(lp->tx_skb_top <= lp->tx_skb_end) + struct sk_buff *skb; + int i; + + for(i=0; i < RX_RING_LEN; i++) + { + skb = lp->rx_ring[i].skb; + if (skb!=NULL) { + kfree_skb(skb); + skb=NULL; + } + lp->rx_ring[i].p=NULL; + } +} + + +/** + * mc32_load_tx_ring: + * @dev: The 3c527 card to issue the command to + * + * This sets up the host transmit data-structures. + * + * First, we obtain from the card it's current postion in the tx + * ring, so that we will know where to begin transmitting + * packets. + * + * Then, we read the 'next' pointers from the on-card tx ring into + * our tx_ring array to reduce slow shared-mem reads. Finally, we + * intitalise the tx house keeping variables. + * + */ + +static void mc32_load_tx_ring(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + volatile struct skb_header *p; + int i; + u16 tx_base; + + tx_base=lp->tx_box->data[0]; + + for(i=0;itx_len;i++) { - for(i=lp->tx_skb_top;itx_skb_end;i++) - dev_kfree_skb(lp->tx_skb[i]); + p=bus_to_virt(lp->base+tx_base); + lp->tx_ring[i].p=p; + lp->tx_ring[i].skb=NULL; + + tx_base=p->next; } - else + + /* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */ + /* which would be bad news for mc32_tx_ring as cur. implemented */ + + atomic_set(&lp->tx_count, TX_RING_LEN-1); + lp->tx_ring_head=lp->tx_ring_tail=0; +} + + +/** + * mc32_flush_tx_ring: + * @lp: Local data of 3c527 to flush the tx ring of + * + * We have to consider two cases here. We want to free the pending + * buffers only. If the ring buffer head is past the start then the + * ring segment we wish to free wraps through zero. The tx ring + * house-keeping variables are then reset. + */ + +static void mc32_flush_tx_ring(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + + if(lp->tx_ring_tail!=lp->tx_ring_head) { - for(i=0;itx_skb_end;i++) - dev_kfree_skb(lp->tx_skb[i]); - for(i=lp->tx_skb_top;itx_skb[i]); + int i; + if(lp->tx_ring_tail < lp->tx_ring_head) + { + for(i=lp->tx_ring_tail;itx_ring_head;i++) + { + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + } + else + { + for(i=lp->tx_ring_tail; itx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + for(i=0; itx_ring_head; i++) + { + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + } } + + atomic_set(&lp->tx_count, 0); + lp->tx_ring_tail=lp->tx_ring_head=0; } -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. + +/** + * mc32_open + * @dev: device to open + * + * The user is trying to bring the card into ready state. This requires + * a brief dialogue with the card. Firstly we enable interrupts and then + * 'indications'. Without these enabled the card doesn't bother telling + * us what it has done. This had me puzzled for a week. + * + * We configure the number of card descriptors, then load the network + * address and multicast filters. Turn on the workaround mode. This + * works around a bug in the 82586 - it asks the firmware to do + * so. It has a performance (latency) hit but is needed on busy + * [read most] lans. We load the ring with buffers then we kick it + * all off. */ static int mc32_open(struct device *dev) { int ioaddr = dev->base_addr; - u16 zero_word=0; + struct mc32_local *lp = (struct mc32_local *)dev->priv; u8 one=1; u8 regs; - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN}; + + MOD_INC_USE_COUNT; /* * Interrupts enabled @@ -748,49 +957,84 @@ mc32_command(dev, 4, &one, 2); - /* - * Send the command sequence "abort, resume" for RX and TX. - * The abort cleans up the buffer chains if needed. + * Poke it to make sure it's really dead. */ - mc32_rx_abort(dev); - mc32_tx_abort(dev); - + mc32_halt_transceiver(dev); + mc32_flush_tx_ring(dev); + + /* + * Ask card to set up on-card descriptors to our spec + */ + + if(mc32_command(dev, 8, descnumbuffs, 4)) { + printk("%s: %s rejected our buffer configuration!\n", + dev->name, cardname); + mc32_close(dev); + return -ENOBUFS; + } + + /* Report new configuration */ + mc32_command(dev, 6, NULL, 0); + + lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ + lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ + lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ + lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ + /* Set Network Address */ mc32_command(dev, 1, dev->dev_addr, 6); /* Set the filters */ mc32_set_multicast_list(dev); + + if (WORKAROUND_82586) { + u16 zero_word=0; + mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ + } + + mc32_load_tx_ring(dev); - /* Issue the 82586 workaround command - this is for "busy lans", - but basically means for all lans now days - has a performance - cost but best set */ - - mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ - - /* Load the ring we just initialised */ - - if(mc32_load_rx_ring(dev)) + if(mc32_load_rx_ring(dev)) { mc32_close(dev); return -ENOBUFS; } + + lp->desired_state = RUNNING; - /* And the resume command goes last */ - - mc32_rx_begin(dev); - mc32_tx_begin(dev); - - MOD_INC_USE_COUNT; + /* And finally, set the ball rolling... */ + + mc32_start_transceiver(dev); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; return 0; } + +/** + * mc32_send_packet: + * @skb: buffer to transmit + * @dev: 3c527 to send it out of + * + * Transmit a buffer. This normally means throwing the buffer onto + * the transmit queue as the queue is quite large. If the queue is + * full then we set tx_busy and return. Once the interrupt handler + * gets messages telling it to reclaim transmit queue entries we will + * clear tx_busy and the kernel will start calling this again. + * + * We use cli rather than spinlocks. Since I have no access to an SMP + * MCA machine I don't plan to change it. It is probably the top + * performance hit for this driver on SMP however. + */ + static int mc32_send_packet(struct sk_buff *skb, struct device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; if (dev->tbusy) { /* @@ -817,9 +1061,7 @@ } else { - unsigned long flags; - - u16 tx_head; + unsigned long flags; volatile struct skb_header *p, *np; save_flags(flags); @@ -832,159 +1074,303 @@ return 1; } - tx_head = lp->tx_box->data[0]; - atomic_dec(&lp->tx_count); + atomic_dec(&lp->tx_count); - /* We will need this to flush the buffer out */ - - lp->tx_skb[lp->tx_skb_end] = skb; - lp->tx_skb_end++; - lp->tx_skb_end&=(TX_RING_MAX-1); - - /* TX suspend - shouldnt be needed but apparently is. - This is a research item ... */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->tx_box->mbox=0; - outb(3, ioaddr+HOST_CMD); - - /* Transmit now stopped */ /* P is the last sending/sent buffer as a pointer */ - p=(struct skb_header *)bus_to_virt(lp->base+tx_head); + p=lp->tx_ring[lp->tx_ring_head].p; + lp->tx_ring_head=next_tx(lp->tx_ring_head); + /* NP is the buffer we will be loading */ - np=(struct skb_header *)bus_to_virt(lp->base+p->next); - - np->control |= (1<<6); /* EOL */ - wmb(); - - np->length = skb->len; + np=lp->tx_ring[lp->tx_ring_head].p; - if(np->length < 60) - np->length = 60; + /* We will need this to flush the buffer out */ + lp->tx_ring[lp->tx_ring_head].skb=skb; + + np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->data = virt_to_bus(skb->data); - np->status = 0; - np->control = (1<<7)|(1<<6); /* EOP EOL */ - wmb(); - - p->status = 0; - p->control &= ~(1<<6); + np->status = 0; + np->control = CONTROL_EOP | CONTROL_EOL; + wmb(); - dev->tbusy = 0; /* Keep feeding me */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->tx_box->mbox=0; - outb(5, ioaddr+HOST_CMD); /* Restart TX */ - restore_flags(flags); + p->control &= ~CONTROL_EOL; /* Clear EOL on p */ + + dev->tbusy = 0; /* Keep feeding me */ + + restore_flags(flags); } return 0; } + +/** + * mc32_update_stats: + * @dev: 3c527 to service + * + * + * Query and reset the on-card stats. There's the small possibility + * of a race here, which would result in an underestimation of + * actual errors. As such, we'd prefer to keep all our stats + * collection in software. As a rule, we do. However it can't be + * used for rx errors and collisions as, by default, the card discards + * bad rx packets. + * + * Setting the SAV BP in the rx filter command supposedly + * stops this behaviour. However, testing shows that it only seems to + * enable the collation of on-card rx statistics --- the driver + * never sees an RX descriptor with an error status set. + * + */ + static void mc32_update_stats(struct device *dev) { -} + struct mc32_local *lp = (struct mc32_local *)dev->priv; + volatile struct mc32_stats *st = lp->stats; + + u32 rx_errors=0; + + rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors; + st->rx_crc_errors=0; + rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors; + st->rx_overrun_errors=0; + rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; + st->rx_alignment_errors=0; + rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; + st->rx_tooshort_errors=0; + rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors; + st->rx_outofresource_errors=0; + lp->net_stats.rx_errors=rx_errors; + + /* Number of packets which saw one collision */ + lp->net_stats.collisions+=st->dataC[10]; + st->dataC[10]=0; + + /* Number of packets which saw 2--15 collisions */ + lp->net_stats.collisions+=st->dataC[11]; + st->dataC[11]=0; +} +/** + * mc32_rx_ring: + * @dev: 3c527 that needs its receive ring processing + * + * + * We have received one or more indications from the card that a + * receive has completed. The buffer ring thus contains dirty + * entries. We walk the ring by iterating over the circular rx_ring + * array, starting at the next dirty buffer (which happens to be the + * one we finished up at last time around). + * + * For each completed packet, we will either copy it and pass it up + * the stack or, if the packet is near MTU sized, we allocate + * another buffer and flip the old one up the stack. + * + * We must succeed in keeping a buffer on the ring. If neccessary we + * will toss a received packet rather than lose a ring entry. Once + * the first uncompleted descriptor is found, we move the + * End-Of-List bit to include the buffers just processed. + * + */ + static void mc32_rx_ring(struct device *dev) { - struct mc32_local *lp=dev->priv; - int ioaddr = dev->base_addr; - int x=0; + struct mc32_local *lp=dev->priv; volatile struct skb_header *p; - u16 base; - u16 top; + u16 rx_ring_tail = lp->rx_ring_tail; + u16 rx_old_tail = rx_ring_tail; + + int x=0; - top = base = lp->rx_box->data[0]; do - { - p=(struct skb_header *)bus_to_virt(base+lp->base); - if(!(p->status & (1<<7))) + { + p=lp->rx_ring[rx_ring_tail].p; + + if(!(p->status & (1<<7))) { /* Not COMPLETED */ break; - if(p->status & (1<<6)) - { - u16 length = p->length; - struct sk_buff *skb=dev_alloc_skb(length+2); - if(skb!=NULL) + } + if(p->status & (1<<6)) /* COMPLETED_OK */ + { + + u16 length=p->length; + struct sk_buff *skb; + struct sk_buff *newskb; + + /* Try to save time by avoiding a copy on big frames */ + + if ((length > RX_COPYBREAK) + && ((newskb=dev_alloc_skb(1532)) != NULL)) + { + skb=lp->rx_ring[rx_ring_tail].skb; + skb_put(skb, length); + + skb_reserve(newskb,18); + lp->rx_ring[rx_ring_tail].skb=newskb; + p->data=virt_to_bus(newskb->data); + } + else { + skb=dev_alloc_skb(length+2); + + if(skb==NULL) { + lp->net_stats.rx_dropped++; + goto dropped; + } + skb_reserve(skb,2); - /*printk("Frame at %p\n", bus_to_virt(p->data)); */ memcpy(skb_put(skb, length), - bus_to_virt(p->data), length); - skb->protocol=eth_type_trans(skb,dev); - skb->dev=dev; - lp->net_stats.rx_packets++; - lp->net_stats.rx_bytes+=skb->len; - netif_rx(skb); - } - else - lp->net_stats.rx_dropped++; - } - else - { - lp->net_stats.rx_errors++; - switch(p->status&0x0F) - { - case 1: - lp->net_stats.rx_crc_errors++;break; - case 2: - lp->net_stats.rx_fifo_errors++;break; - case 3: - lp->net_stats.rx_frame_errors++;break; - case 4: - lp->net_stats.rx_missed_errors++;break; - case 5: - lp->net_stats.rx_length_errors++;break; + lp->rx_ring[rx_ring_tail].skb->data, length); } + + skb->protocol=eth_type_trans(skb,dev); + skb->dev=dev; + lp->net_stats.rx_packets++; + lp->net_stats.rx_bytes+=skb->len; + netif_rx(skb); } - p->length = 1532; - p->control &= ~(1<<6); + + dropped: + p->length = 1532; p->status = 0; - base = p->next; + + rx_ring_tail=next_rx(rx_ring_tail); + } + while(x++<48); + + /* If there was actually a frame to be processed, place the EOL bit */ + /* at the descriptor prior to the one to be filled next */ + + if (rx_ring_tail != rx_old_tail) + { + lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL; + lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL; + + lp->rx_ring_tail=rx_ring_tail; } - while(x++<48); - - /* - * Restart ring processing - */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->rx_box->mbox=0; - lp->rx_box->data[0] = top; - outb(1<<3, ioaddr+HOST_CMD); - lp->rx_halted = 0; } -/* - * The typical workload of the driver: - * Handle the network interface interrupts. +/** + * mc32_tx_ring: + * @dev: 3c527 that needs its transmit ring processing + * + * + * This operates in a similar fashion to mc32_rx_ring. We iterate + * over the transmit ring. For each descriptor which has been + * processed by the card, we free its associated buffer and note + * any errors. This continues until the transmit ring is emptied + * or we reach a descriptor that hasn't yet been processed by the + * card. + * + */ + +static void mc32_tx_ring(struct device *dev) { + + struct mc32_local *lp=(struct mc32_local *)dev->priv; + volatile struct skb_header *np; + + /* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */ + + while (lp->tx_ring_tail != lp->tx_ring_head) + { + u16 t; + + t=next_tx(lp->tx_ring_tail); + np=lp->tx_ring[t].p; + + if(!(np->status & (1<<7))) { /* Not COMPLETED */ + break; + } + + lp->net_stats.tx_packets++; + + if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ + { + lp->net_stats.tx_errors++; + + switch(np->status&0x0F) + { + case 1: + lp->net_stats.tx_aborted_errors++;break; /* Max collisions */ + case 2: + lp->net_stats.tx_fifo_errors++;break; + case 3: + lp->net_stats.tx_carrier_errors++;break; + case 4: + lp->net_stats.tx_window_errors++;break; /* CTS Lost */ + case 5: + lp->net_stats.tx_aborted_errors++;break; /* Transmit timeout */ + } + } + + + /* Packets are sent in order - this is + basically a FIFO queue of buffers matching + the card ring */ + lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len; + dev_kfree_skb(lp->tx_ring[t].skb); + lp->tx_ring[t].skb=NULL; + atomic_inc(&lp->tx_count); + dev->tbusy=0; + mark_bh(NET_BH); + + lp->tx_ring_tail=t; + } + +} + + +/** + * mc32_interrupt: + * @irq: Interrupt number + * @dev_id: 3c527 that requires servicing + * @regs: Registers (unused) + * + * + * An interrupt is raised whenever the 3c527 writes to the command + * register. This register contains the message it wishes to send us + * packed into a single byte field. We keep reading status entries + * until we have processed all the control items, but simply count + * transmit and receive reports. When all reports are in we empty the + * transceiver rings as appropriate. This saves the overhead of + * multiple command requests. + * + * Because MCA is level-triggered, we shouldn't miss indications. + * Therefore, we needn't ask the card to suspend interrupts within + * this handler. The card receives an implicit acknowledgment of the + * current interrupt when we read the command register. + * */ + static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct device *dev = dev_id; struct mc32_local *lp; int ioaddr, status, boguscount = 0; + int rx_event = 0; + int tx_event = 0; if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); return; } - dev->interrupt = 1; + dev->interrupt = 1; + ioaddr = dev->base_addr; lp = (struct mc32_local *)dev->priv; /* See whats cooking */ - - while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000) + + while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000) { status=inb(ioaddr+HOST_CMD); #ifdef DEBUG_IRQ - printk("Status TX%d RX%d EX%d OV%d\n", + printk("Status TX%d RX%d EX%d OV%d BC%d\n", (status&7), (status>>3)&7, (status>>6)&1, - (status>>7)&1); + (status>>7)&1, boguscount); #endif switch(status&7) @@ -992,33 +1378,16 @@ case 0: break; case 6: /* TX fail */ - lp->net_stats.tx_errors++; case 2: /* TX ok */ - lp->net_stats.tx_packets++; - /* Packets are sent in order - this is - basically a FIFO queue of buffers matching - the card ring */ - lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len; - dev_kfree_skb(lp->tx_skb[lp->tx_skb_top]); - lp->tx_skb[lp->tx_skb_top]=NULL; - lp->tx_skb_top++; - lp->tx_skb_top&=(TX_RING_MAX-1); - atomic_inc(&lp->tx_count); - dev->tbusy=0; - mark_bh(NET_BH); + tx_event = 1; break; case 3: /* Halt */ case 4: /* Abort */ - lp->tx_halted=1; - wake_up(&lp->event); - break; - case 5: - lp->tx_halted=0; + lp->xceiver_state |= TX_HALTED; wake_up(&lp->event); break; default: - printk("%s: strange tx ack %d\n", - dev->name, status&7); + printk("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) @@ -1026,155 +1395,199 @@ case 0: break; case 2: /* RX */ - lp->rx_pending=1; - if(!lp->rx_halted) - { - /* - * Halt ring receive - */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(3<<3, ioaddr+HOST_CMD); - } + rx_event=1; break; - case 3: - case 4: - lp->rx_halted=1; - wake_up(&lp->event); - break; - case 5: - lp->rx_halted=0; + case 3: /* Halt */ + case 4: /* Abort */ + lp->xceiver_state |= RX_HALTED; wake_up(&lp->event); break; case 6: /* Out of RX buffers stat */ + /* Must restart rx */ lp->net_stats.rx_dropped++; - lp->rx_pending=1; - /* Must restart */ - lp->rx_halted=1; + mc32_rx_ring(dev); + mc32_start_transceiver(dev); break; default: printk("%s: strange rx ack %d\n", - dev->name, status&7); - + dev->name, status&7); } status>>=3; if(status&1) { + /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */ - if(lp->exec_pending!=3) + + if(lp->exec_pending!=3) { lp->exec_pending=2; - else - lp->exec_pending=0; - wake_up(&lp->event); + wake_up(&lp->event); + } + else + { + lp->exec_pending=0; + + /* A new multicast set may have been + blocked while the old one was + running. If so, do it now. */ + + if (lp->mc_reload_wait) + mc32_reset_multicast_list(dev); + else + wake_up(&lp->event); + } } if(status&2) { /* - * Update the stats as soon as - * we have it flagged and can - * send an immediate reply (CRR set) + * We get interrupted once per + * counter that is about to overflow. */ - - if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR) - { - mc32_update_stats(dev); - outb(0, ioaddr+HOST_CMD); - } + + mc32_update_stats(dev); } } - + + /* - * Process and restart the receive ring. This has some state - * as we must halt the ring to process it and halting the ring - * might not occur in the same IRQ handling loop as we issue - * the halt. - */ + * Process the transmit and receive rings + */ + + if(tx_event) + mc32_tx_ring(dev); - if(lp->rx_pending && lp->rx_halted) - { + if(rx_event) mc32_rx_ring(dev); - lp->rx_pending = 0; - } - dev->interrupt = 0; + + dev->interrupt = 0; + return; } -/* The inverse routine to mc32_open(). */ +/** + * mc32_close: + * @dev: 3c527 card to shut down + * + * The 3c527 is a bus mastering device. We must be careful how we + * shut it down. It may also be running shared interrupt so we have + * to be sure to silence it properly + * + * We indicate that the card is closing to the rest of the + * driver. Otherwise, it is possible that the card may run out + * of receive buffers and restart the transceiver while we're + * trying to close it. + * + * We abort any receive and transmits going on and then wait until + * any pending exec commands have completed in other code threads. + * In theory we can't get here while that is true, in practice I am + * paranoid + * + * We turn off the interrupt enable for the board to be sure it can't + * intefere with other devices. + */ static int mc32_close(struct device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; u8 regs; u16 one=1; + dev->tbusy = 1; + dev->start = 0; + + lp->desired_state = HALTED; + /* * Send the indications on command (handy debug check) */ mc32_command(dev, 4, &one, 2); - /* Abort RX and Abort TX */ - - mc32_rx_abort(dev); - mc32_tx_abort(dev); + /* Shut down the transceiver */ + + mc32_halt_transceiver(dev); /* Catch any waiting commands */ while(lp->exec_pending==1) sleep_on(&lp->event); - + /* Ok the card is now stopping */ regs=inb(ioaddr+HOST_CTRL); regs&=~HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); - mc32_flush_rx_ring(lp); - mc32_flush_tx_ring(lp); - - dev->tbusy = 1; - dev->start = 0; - - /* Update the statistics here. */ + mc32_flush_rx_ring(dev); + mc32_flush_tx_ring(dev); + + mc32_update_stats(dev); MOD_DEC_USE_COUNT; return 0; - } -/* - * Get the current statistics. - * This may be called with the card open or closed. + +/** + * mc32_get_stats: + * @dev: The 3c527 card to handle + * + * We've collected all the stats we can in software already. Now + * it's time to update those kept on-card and return the lot. + * */ static struct net_device_stats *mc32_get_stats(struct device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp; + + mc32_update_stats(dev); + + lp = (struct mc32_local *)dev->priv; + return &lp->net_stats; } -/* - * Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. + +/** + * do_mc32_set_multicast_list: + * @dev: 3c527 device to load the list on + * @retry: indicates this is not the first call. + * + * + * Actually set or clear the multicast filter for this adaptor. The + * locking issues are handled by this routine. We have to track + * state as it may take multiple calls to get the command sequence + * completed. We just keep trying to schedule the loads until we + * manage to process them all. + * + * num_addrs == -1 Promiscuous mode, receive all packets + * + * num_addrs == 0 Normal mode, clear multicast list + * + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + * + * See mc32_update_stats() regards setting the SAV BP bit. + * */ + static void do_mc32_set_multicast_list(struct device *dev, int retry) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - u16 filt; + u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ if (dev->flags&IFF_PROMISC) /* Enable promiscuous mode */ - filt = 1; + filt |= 1; else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10) { dev->flags|=IFF_PROMISC; - filt = 1; + filt |= 1; } else if(dev->mc_count) { @@ -1183,9 +1596,7 @@ struct dev_mc_list *dmc=dev->mc_list; int i; - - filt = 0; - + if(retry==0) lp->mc_list_valid = 0; if(!lp->mc_list_valid) @@ -1208,21 +1619,41 @@ lp->mc_list_valid=1; } } - else - { - filt = 0; - } - if(mc32_command_nowait(dev, 0, &filt, 2)==-1) + + if(mc32_command_nowait(dev, 0, &filt, 2)==-1) { lp->mc_reload_wait = 1; + } + else { + lp->mc_reload_wait = 0; } } + +/** + * mc32_set_multicast_list: + * @dev: The 3c527 to use + * + * Commence loading the multicast list. This is called when the kernel + * changes the lists. It will override any pending list we are trying to + * load. + */ + static void mc32_set_multicast_list(struct device *dev) { do_mc32_set_multicast_list(dev,0); } + +/** + * mc32_reset_multicast_list: + * @dev: The 3c527 to use + * + * Attempt the next step in loading the multicast lists. If this attempt + * fails to complete then it will be scheduled and this function called + * again later from elsewhere. + */ + static void mc32_reset_multicast_list(struct device *dev) { do_mc32_set_multicast_list(dev,1); @@ -1237,6 +1668,14 @@ 0, 0, /* I/O address, IRQ */ 0, 0, 0, NULL, mc32_probe }; +/** + * init_module: + * + * Probe and locate a 3c527 card. This really should probe and locate + * all the 3c527 cards in the machine not just one of them. Yes you can + * insmod multiple modules for now but it's a hack. + */ + int init_module(void) { int result; @@ -1247,6 +1686,17 @@ return 0; } +/** + * cleanup_module: + * + * Unloading time. We release the MCA bus resources and the interrupt + * at which point everything is ready to unload. The card must be stopped + * at this point or we would not have been called. When we unload we + * leave the card stopped but not totally shut down. When the card is + * initialized it must be rebooted or the rings reloaded before any + * transmit operations are allowed to start scribbling into memory. + */ + void cleanup_module(void) { int slot; @@ -1256,8 +1706,6 @@ /* * If we don't do this, we can't re-insmod it later. - * Release irq/dma here, when you have jumpered versions and - * allocate them in mc32_probe1(). */ if (this_device.priv) @@ -1269,6 +1717,7 @@ kfree_s(this_device.priv, sizeof(struct mc32_local)); } free_irq(this_device.irq, &this_device); + release_region(this_device.base_addr, MC32_IO_EXTENT); } #endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/3c527.h linux/drivers/net/3c527.h --- v2.2.18/drivers/net/3c527.h Sun Mar 25 11:12:53 2001 +++ linux/drivers/net/3c527.h Sun Mar 25 11:37:34 2001 @@ -7,11 +7,19 @@ */ #define HOST_CMD 0 +#define HOST_CMD_START_RX (1<<3) +#define HOST_CMD_SUSPND_RX (3<<3) +#define HOST_CMD_RESTRT_RX (5<<3) + +#define HOST_CMD_SUSPND_TX 3 +#define HOST_CMD_RESTRT_TX 5 + #define HOST_STATUS 2 #define HOST_STATUS_CRR (1<<6) #define HOST_STATUS_CWR (1<<5) + #define HOST_CTRL 6 #define HOST_CTRL_ATTN (1<<7) #define HOST_CTRL_RESET (1<<6) @@ -19,6 +27,17 @@ #define HOST_RAMPAGE 8 +#define RX_HALTED (1<<0) +#define TX_HALTED (1<<1) +#define HALTED (RX_HALTED | TX_HALTED) +#define RUNNING 0 + +struct mc32_mailbox +{ + u16 mbox __attribute((packed)); + u16 data[1] __attribute((packed)); +}; + struct skb_header { u8 status __attribute((packed)); @@ -28,13 +47,37 @@ u32 data __attribute((packed)); }; -#define STATUS_MASK 0x0F -#define COMPLETED 0x80 -#define COMPLETED_OK 0x40 -#define BUFFER_BUSY 0x20 +struct mc32_stats +{ + /* RX Errors */ + u32 rx_crc_errors __attribute((packed)); + u32 rx_alignment_errors __attribute((packed)); + u32 rx_overrun_errors __attribute((packed)); + u32 rx_tooshort_errors __attribute((packed)); + u32 rx_toolong_errors __attribute((packed)); + u32 rx_outofresource_errors __attribute((packed)); + + u32 rx_discarded __attribute((packed)); /* via card pattern match filter */ + + /* TX Errors */ + u32 tx_max_collisions __attribute((packed)); + u32 tx_carrier_errors __attribute((packed)); + u32 tx_underrun_errors __attribute((packed)); + u32 tx_cts_errors __attribute((packed)); + u32 tx_timeout_errors __attribute((packed)) ; + + /* various cruft */ + u32 dataA[6] __attribute((packed)); + u16 dataB[5] __attribute((packed)); + u32 dataC[14] __attribute((packed)); +}; -#define CONTROL_EOP 0x80 /* End Of Packet */ -#define CONTROL_EL 0x40 /* End of List */ +#define STATUS_MASK 0x0F +#define COMPLETED (1<<7) +#define COMPLETED_OK (1<<6) +#define BUFFER_BUSY (1<<5) +#define CONTROL_EOP (1<<7) /* End Of Packet */ +#define CONTROL_EOL (1<<6) /* End of List */ -#define MCA_MC32_ID 0x0041 /* Our MCA ident */ \ No newline at end of file +#define MCA_MC32_ID 0x0041 /* Our MCA ident */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.2.18/drivers/net/3c59x.c Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/3c59x.c Sun Mar 25 11:37:34 2001 @@ -60,14 +60,42 @@ - In vortex_open(), set vp->tx_full to zero (else we get errors if the device was closed with a full Tx ring). - 15Sep00 <2.2.18-pre3> andrewm + 17Oct00 <2.2.18-pre16> andrewm - Added support for the 3c556B Laptop Hurricane (Louis Gerbarg) + - Backported transceiver options handling from 2.4. This changes the semantics + of forcing full duplex in the `options' parm! (It's better to use + `full_duplex' anyway). See Documentation/vortex.txt (Maciej Rozycki). + - Set PCI latency timer to maximum for the 3c590 (From Donald's driver) + - Removed all the CARDBUS code (it's never used). + - Added INVERT_MII_PWR, EEPROM_8BIT, EEPROM_OFFSET. Use them. + - Use EEPROM_8BIT for the 3c555 + - Merged ACPI WOL support from Donald's drivers. + - Sort-of backported Donald's new medialock code. Called it duplexlock + and we now prefer to use `full_duplex=[-1,0,1]' to force duplex mode. + - Merged the rx_oom_timer from 2.4. This gives better handling of OOM + conditions. Backed out the previous way of handling this. + - Replace suser() with capable(CAP_NET_ADMIN) in ioctl(). + + 07Jan01 <2.2.19-pre6> andrewm + - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO" + - Added and used wait_for_completion(). 3c905CX problems. + - Removed the code for older kernel versions. + - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger) + - Search for phy 24 first for 3c905CX. (D Becker) + - Don't free skbs we don't own on oom path in vortex_open(). + - Added explicit `medialock' flag so we can truly + lock the media type down with `options'. + - In vortex_error(), only reset the up/down load engine, not all the + interface stuff. + - Added and used EEPROM_NORESET for 3c556B PM resumes. + - Enable WOL with the `enable_wol' module parm + - Give the 3c980 HAS_NWAY - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.2 for more details. */ static char version[] = -"3c59x.c 15Sep00 Donald Becker and others http://www.scyld.com/network/vortex.html\n"; +"3c59x.c 18Feb01 Donald Becker and others http://www.scyld.com/network/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -101,16 +129,6 @@ #include #include -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif -#include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include @@ -124,9 +142,8 @@ #include #include #include -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -#include -#endif +#include +#include #include /* For NR_IRQS only. */ #include #include @@ -136,48 +153,18 @@ #define RUN_AT(x) (jiffies + (x)) -#include - -#if (LINUX_VERSION_CODE <= 0x20100) -#ifndef __alpha__ -#define ioremap(a,b) \ - (((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b)) -#define iounmap(v) \ - do { if ((u_long)(v) > 0x100000) vfree(v); } while (0) -#endif -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20138 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#define le32_to_cpu(val) (val) -#define cpu_to_le32(val) (val) -#endif -#if LINUX_VERSION_CODE < 0x20155 -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE); -#else /* Grrr, unneeded incompatible change. */ -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); -#endif -#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 -MODULE_AUTHOR("Donald Becker "); +MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); -#endif /* Operational parameter that usually are not changed. */ @@ -286,7 +273,9 @@ }; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, - HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; + HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, + INVERT_MII_PWR=0x100, EEPROM_8BIT=0x200, EEPROM_OFFSET=0x400, + EEPROM_NORESET=0x800}; static struct device *vortex_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr, int irq, int dev_id, int card_idx); @@ -316,7 +305,7 @@ {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, {"3c900 Cyclone 10Mbps TPO", 0x10B7, 0x9004, 0xffff, /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, {"3c900 Cyclone 10Mbps TPC", 0x10B7, 0x9006, 0xffff, /* AKPM: from Don's 0.99M */ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff, @@ -332,15 +321,15 @@ {"3c905C Tornado", 0x10B7, 0x9200, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, vortex_probe1}, {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, vortex_probe1}, {"3c556 10/100 Mini PCI Adapter", 0x10B7, 0x6055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_CB_FNS, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, vortex_probe1}, {"3c556B Laptop Hurricane", 0x10B7, 0x6056, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_CB_FNS, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|EEPROM_NORESET, 128, vortex_probe1}, {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, @@ -501,7 +490,7 @@ }; /* Chip features we care about in vp->capabilities, read from the EEPROM. */ -enum ChipCaps { CapBusMaster=0x20 }; +enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 }; struct vortex_private { /* The Rx and Tx rings should be quad-word-aligned. */ @@ -515,23 +504,27 @@ unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ + struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ /* PCI configuration space information. */ - u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ - char *cb_fn_base; /* CardBus function status addr space. */ + u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ + char *cb_fn_base; /* CardBus function status addr space. */ int chip_id; /* The remainder are related to chip state, mostly media selection. */ - struct timer_list timer; /* Media selection timer. */ - int options; /* User-settable misc. driver options. */ - unsigned int media_override:3, /* Passed-in media type. */ + struct timer_list timer; /* Media selection timer. */ + struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ + int options; /* User-settable misc. driver options. */ + unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, force_fd:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ + full_duplex:1, /* User wants FD (or we're running at FD) */ + duplexlock:1, /* User has forced duplex */ + autoselect:1, /* Can use NWAY negotiation */ + bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ - tx_full:1; + tx_full:1, + enable_wol:1, + medialock:1; u16 status_enable; u16 intr_enable; u16 available_media; /* From Wn3_Options. */ @@ -571,14 +564,13 @@ { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifndef CARDBUS static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]); -#endif static int vortex_open(struct device *dev); static void mdio_sync(long ioaddr, int bits); static int mdio_read(long ioaddr, int phy_id, int location); static void mdio_write(long ioaddr, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); +static void rx_oom_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev); static int vortex_rx(struct device *dev); @@ -590,116 +582,33 @@ static struct net_device_stats *vortex_get_stats(struct device *dev); static void set_rx_mode(struct device *dev); static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static void acpi_wake(int pci_bus, int pci_devfn); +static void acpi_set_WOL(struct device *dev); -/* #define dev_alloc_skb dev_alloc_skb_debug */ +#if 0 +#warning dev_alloc_skb_debug is defined! +#define dev_alloc_skb dev_alloc_skb_debug +#endif /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Option count limit only -- unlimited interfaces are supported. */ #define MAX_UNITS 8 -static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* A list of all installed Vortex devices, for removing the driver module. */ static struct device *root_vortex_dev = NULL; #ifdef MODULE -#ifndef CARDBUS /* Variables to work-around the Compaq PCI BIOS32 problem. */ static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900; -#endif - -#ifdef CARDBUS - -#include - -static dev_node_t *vortex_attach(dev_locator_t *loc) -{ - u16 dev_id, vendor_id; - u32 io; - u8 bus, devfn, irq; - struct device *dev; - int chip_idx; - - if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); - pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); - pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id); - pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); - printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", - bus, devfn, dev_id); - io &= ~3; - if (io == 0 || irq == 0) { - printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " - "assigned an %s.\n" KERN_ERR " It will not be activated.\n", - io == 0 ? "I/O address" : "IRQ"); - return NULL; - } - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor_id == pci_tbl[chip_idx].vendor_id - && (dev_id & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */ - printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in " - "vortex_attach().\n", vendor_id, dev_id); - return NULL; - } - dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1); - if (dev) { - dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - if (!node) - return NULL; - strcpy(node->dev_name, dev->name); - node->major = node->minor = 0; - node->next = NULL; - MOD_INC_USE_COUNT; - return node; - } - return NULL; -} - -static void vortex_detach(dev_node_t *node) -{ - struct device **devp, **next; - printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name); - for (devp = &root_vortex_dev; *devp; devp = next) { - next = &((struct vortex_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; - } - if (*devp) { - struct device *dev = *devp; - struct vortex_private *vp = dev->priv; - if (dev->flags & IFF_UP) - vortex_close(dev); - dev->flags &= ~(IFF_UP|IFF_RUNNING); - unregister_netdev(dev); - if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - kfree(dev); - *devp = *next; - kfree(vp); - kfree(node); - MOD_DEC_USE_COUNT; - } -} - -struct driver_operations vortex_ops = { - "3c575_cb", vortex_attach, NULL, NULL, vortex_detach -}; - -#endif /* Cardbus support */ - int init_module(void) { if (vortex_debug) printk(KERN_INFO "%s", version); -#ifdef CARDBUS - register_driver(&vortex_ops); - return 0; -#else return vortex_scan(0, pci_tbl); -#endif } #else @@ -713,7 +622,30 @@ } #endif /* not MODULE */ -#ifndef CARDBUS +static void wait_for_completion(struct device *dev, int cmd) +{ + int i; + + outw(cmd, dev->base_addr + EL3_CMD); + for (i = 0; i < 2000; i++) { + if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) + return; + } + + /* OK, that didn't work. Do it the slow way. One second */ + for (i = 0; i < 100000; i++) { + if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) { + if (vortex_debug > 1) + printk(KERN_INFO "%s: command 0x%04x took %d usecs!\n", + dev->name, cmd, i * 10); + return; + } + udelay(10); + } + printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", + dev->name, cmd, inw(dev->base_addr + EL3_STATUS)); +} + static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) { int cards_found = 0; @@ -734,8 +666,7 @@ long ioaddr; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) + &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) break; pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); @@ -749,21 +680,13 @@ if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ continue; + /* The Cyclone requires config space re-write if powered down. */ + acpi_wake(pci_bus, pci_device_fn); + { -#if LINUX_VERSION_CODE >= 0x20155 struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[0] & ~3; irq = pdev->irq; -#else - u32 pci_ioaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - ioaddr = pci_ioaddr & ~3;; - irq = pci_irq_line; -#endif } /* Power-up the card. */ @@ -811,21 +734,21 @@ chip_idx, cards_found); if (dev) { - /* Get and check the latency values. On the 3c590 series - the latency timer must be set to the maximum value to avoid - data corruption that occurs when the timer expires during - a transfer -- a bug in the Vortex chip only. */ - u8 pci_latency; - u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32; - - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", - dev->name, pci_latency, new_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, new_latency); + if ((device & 0xff00) == 0x5900) { + /* Get and check the latency values. On the 3c590 series + the latency timer must be set to the maximum value to avoid + data corruption that occurs when the timer expires during + a transfer -- a bug in the Vortex chip only. */ + u8 pci_latency; + u8 new_latency = 248; + + pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < new_latency) { + printk(KERN_INFO "%s: Overriding PCI latency" + " timer (CFLT) setting of %d, new value is %d.\n", + dev->name, pci_latency, new_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, new_latency); + } } dev = 0; cards_found++; @@ -866,7 +789,6 @@ return cards_found ? 0 : -ENODEV; } -#endif /* ! Cardbus */ static struct device *vortex_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr, @@ -878,6 +800,10 @@ int i; dev = init_etherdev(dev, 0); + if (dev == NULL) { + printk(KERN_EMERG "3c59x: init_etherdev failed\n"); + return NULL; + } printk(KERN_INFO "%s: 3Com %s at 0x%lx, ", dev->name, pci_tbl[chip_idx].name, ioaddr); @@ -889,12 +815,16 @@ /* Make certain the descriptor lists are aligned. */ { void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL); - if (!mem) + if (!mem) { + printk(KERN_EMERG "3c59x: out of memory for dev->priv\n"); + unregister_netdev(dev); + kfree(dev); return NULL; + } vp = (void *)(((long)mem + 15) & ~15); + memset(vp, 0, sizeof(*vp)); vp->priv_addr = mem; } - memset(vp, 0, sizeof(*vp)); dev->priv = vp; vp->next_module = root_vortex_dev; @@ -906,51 +836,68 @@ vp->pci_devfn = pci_devfn; /* The lower four bits are the media type. */ + option = -1; if (dev->mem_start) option = dev->mem_start; else if (card_idx < MAX_UNITS) option = options[card_idx]; - else - option = -1; if (option >= 0) { - vp->media_override = ((option & 7) == 2) ? 0 : option & 7; - vp->full_duplex = (option & 8) ? 1 : 0; + vp->media_override = ((option & 7) == 2) ? 0 : option & 15; + if (vp->media_override != 7) + vp->medialock = 1; + if (option & 0x200) { + vp->full_duplex = 1; + vp->duplexlock = 1; + printk( "\n" KERN_WARNING + "%s: forcing duplex via options is deprecated - use `full_duplex'.\n", + dev->name); + } vp->bus_master = (option & 16) ? 1 : 0; } else { vp->media_override = 7; vp->full_duplex = 0; vp->bus_master = 0; } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - vp->full_duplex = 1; - - vp->force_fd = vp->full_duplex; + if (card_idx < MAX_UNITS) { + if (enable_wol[card_idx] > 0) + vp->enable_wol = 1; + if (full_duplex[card_idx] == 0) { /* full_duplex=0 : force half duplex */ + vp->duplexlock = 1; + } + if (full_duplex[card_idx] > 0) { /* full_duplex=1: force full duplex */ + vp->duplexlock = 1; + vp->full_duplex = 1; + } + /* full_duplex=-1: duplex is not forced */ + } vp->options = option; /* Read the station address from the EEPROM. */ EL3WINDOW(0); - for (i = 0; i < 0x40; i++) { - int timer; -#ifdef CARDBUS - outw(0x230 + i, ioaddr + Wn0EepromCmd); -#else - if (pci_tbl[chip_idx].device_id == 0x6055) { - outw(0x230 + i, ioaddr + Wn0EepromCmd); - } else if (pci_tbl[chip_idx].device_id == 0x6056) { - outw(EEPROM_Read + 0x30 + i, ioaddr + Wn0EepromCmd); - } else { - outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); - } -#endif - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 10; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) - break; + { + int base; + + if (pci_tbl[chip_idx].drv_flags & EEPROM_8BIT) + base = 0x230; + else if (pci_tbl[chip_idx].drv_flags & EEPROM_OFFSET) + base = EEPROM_Read + 0x30; + else + base = EEPROM_Read; + + for (i = 0; i < 0x40; i++) { + int timer; + outw(base + i, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 10; timer >= 0; timer--) { + udelay(162); + if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) + break; + } + eeprom[i] = inw(ioaddr + Wn0EepromData); } - eeprom[i] = inw(ioaddr + Wn0EepromData); } + for (i = 0; i < 0x18; i++) checksum ^= eeprom[i]; checksum = (checksum ^ (checksum >> 8)) & 0xff; @@ -978,6 +925,7 @@ if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ + u16 n; pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2, &fn_st_addr); if (fn_st_addr) @@ -985,11 +933,12 @@ printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee" " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base); EL3WINDOW(2); - if (pci_tbl[chip_idx].device_id == 0x6055) { - outw(0x4010 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); - } else { - outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); - } + + n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + n |= 0x10; + if (pci_tbl[chip_idx].drv_flags & INVERT_MII_PWR) + n |= 0x4000; + outw(n, ioaddr + Wn2_ResetOptions); } /* Extract our information from the EEPROM data. */ @@ -997,7 +946,7 @@ vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; - if (vp->info1 & 0x8000) + if (!vp->duplexlock && (vp->info1 & 0x8000)) vp->full_duplex = 1; { @@ -1035,8 +984,19 @@ mii_preamble_required++; mii_preamble_required++; mdio_read(ioaddr, 24, 1); - for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { - int mii_status, phyx = phy & 0x1f; + for (phy = 0; phy < 32 && phy_idx < 1; phy++) { + int mii_status, phyx; + + /* + * For the 3c905CX we look at index 24 first, because it bogusly + * reports an external PHY at all indices + */ + if (phy == 0) + phyx = 24; + else if (phy <= 24) + phyx = phy - 1; + else + phyx = phy; mii_status = mdio_read(ioaddr, phyx, 1); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; @@ -1060,6 +1020,9 @@ } } + if (vp->enable_wol && (vp->capabilities & CapPwrMgmt)) + acpi_set_WOL(dev); + if (vp->capabilities & CapBusMaster) { vp->full_bus_master_tx = 1; printk(KERN_INFO" Enabling bus-master transmits and %s receives.\n", @@ -1093,6 +1056,9 @@ MOD_INC_USE_COUNT; + if (vp->enable_wol) + acpi_wake(vp->pci_bus, vp->pci_devfn); + /* Before initializing select the active media port. */ EL3WINDOW(3); config = inl(ioaddr + Wn3_Config); @@ -1104,7 +1070,9 @@ media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) { - dev->if_port = XCVR_NWAY; + if (vortex_debug > 1) + printk(KERN_INFO "%s: using NWAY from config\n", dev->name); + dev->if_port = XCVR_NWAY; } else if (vp->autoselect) { /* Find first available media type, starting with 100baseTx. */ dev->if_port = XCVR_100baseTx; @@ -1113,11 +1081,11 @@ } else dev->if_port = vp->default_media; - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); + printk(KERN_INFO "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); + + if (!vp->duplexlock && (vp->info1 & 0x8000)) + vp->full_duplex = 1; - vp->full_duplex = vp->force_fd; config = BFINS(config, dev->if_port, 20, 4); outl(config, ioaddr + Wn3_Config); @@ -1129,35 +1097,25 @@ mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) ; /* No MII device or no link partner report */ - else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ - || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ + else if (!vp->duplexlock && + ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ + || (mii_reg5 & 0x00C0) == 0x0040)) /* 10T-FD, but not 100-HD */ vp->full_duplex = 1; - if (vortex_debug > 1) - printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," - " setting %s-duplex.\n", dev->name, vp->phys[0], - mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); + printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," + " setting %s-duplex.\n", dev->name, vp->phys[0], + mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); EL3WINDOW(3); } /* Set the full-duplex bit. */ - outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); + outb((vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", - dev->name, config); + printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", dev->name, config); } - outw(TxReset, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - - outw(RxReset, ioaddr + EL3_CMD); - /* Wait a few ticks for the RxReset command to complete. */ - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TxReset); + wait_for_completion(dev, RxReset); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); @@ -1224,18 +1182,15 @@ if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ -#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail)); -#else - vp->rx_ring[i].addr = virt_to_bus(skb->data); -#endif } if (i != RX_RING_SIZE) { int j; - for (j = 0; j < RX_RING_SIZE; j++) { + printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name); + for (j = 0; j < i; j++) { if (vp->rx_skbuff[j]) - DEV_FREE_SKB(vp->rx_skbuff[j]); + dev_kfree_skb(vp->rx_skbuff[j]); } retval = -ENOMEM; goto out_free_irq; @@ -1285,6 +1240,10 @@ vp->timer.function = &vortex_timer; /* timer handler */ add_timer(&vp->timer); + init_timer(&vp->rx_oom_timer); + vp->rx_oom_timer.data = (unsigned long)dev; + vp->rx_oom_timer.function = rx_oom_timer; + return 0; out_free_irq: @@ -1306,6 +1265,8 @@ printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); + if (vp->medialock) + goto leave_media_alone; disable_irq(dev->irq); old_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); @@ -1332,7 +1293,7 @@ dev->name, mii_status); if (mii_status & 0x0004) { int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); - if (! vp->force_fd && mii_reg5 != 0xffff) { + if (!vp->duplexlock && mii_reg5 != 0xffff) { int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; if (vp->full_duplex != duplex) { @@ -1342,7 +1303,7 @@ dev->name, vp->full_duplex ? "full" : "half", vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ - EL3WINDOW(3); /* AKPM */ + EL3WINDOW(3); outb((vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); @@ -1392,6 +1353,7 @@ EL3WINDOW(old_window); enable_irq(dev->irq); +leave_media_alone: if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1407,7 +1369,6 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - int j; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), @@ -1435,12 +1396,7 @@ __restore_flags(flags); } } - outw(TxReset, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; -#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300 if (vp->full_bus_master_tx) { int i; printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d " @@ -1456,7 +1412,7 @@ le32_to_cpu(vp->tx_ring[i].status)); } } -#endif + wait_for_completion(dev, TxReset); vp->stats.tx_errors++; if (vp->full_bus_master_tx) { if (vortex_debug > 0) @@ -1494,7 +1450,6 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; int do_tx_reset = 0; - int i; if (status & TxComplete) { /* Really "TxError" for us. */ unsigned char tx_status = inb(ioaddr + TxStatus); @@ -1545,20 +1500,14 @@ dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { - outw(TotalReset | 0xff, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TotalReset|0xff); /* Re-enable the receiver. */ outw(RxEnable, ioaddr + EL3_CMD); outw(TxEnable, ioaddr + EL3_CMD); } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { - outw(RxReset, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, RxReset); /* Set the Rx filter to the current state. */ set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ @@ -1566,11 +1515,7 @@ } } if (do_tx_reset) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j = 4000; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); if (!vp->full_bus_master_tx) { clear_bit(0, (void*)&dev->tbusy); @@ -1580,7 +1525,6 @@ } - static int vortex_start_xmit(struct sk_buff *skb, struct device *dev) { @@ -1609,7 +1553,7 @@ #else outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); #endif - DEV_FREE_SKB(skb); + dev_kfree_skb(skb); if (inw(ioaddr + TxFree) > 1536) { clear_bit(0, (void*)&dev->tbusy); } else @@ -1631,13 +1575,8 @@ dev->name, tx_status); if (tx_status & 0x04) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; - if (tx_status & 0x30) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - } + if (tx_status & 0x30) + wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); } outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ @@ -1663,7 +1602,6 @@ struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; unsigned long flags; - int i; if (vortex_debug > 3) printk(KERN_DEBUG "%s: Trying to send a boomerang packet, Tx index %d.\n", @@ -1681,11 +1619,7 @@ vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); spin_lock_irqsave(&vp->lock, flags); - outw(DownStall, ioaddr + EL3_CMD); - /* Wait for the stall to complete. */ - for (i = 4000; i >= 0; i--) - if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) - break; + wait_for_completion(dev, DownStall); prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry])); if (inl(ioaddr + DownListPtr) == 0) { outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); @@ -1761,7 +1695,7 @@ if (status & DMADone) { if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */ + dev_kfree_skb(vp->tx_skb); /* Release the transfered buffer */ if (inw(ioaddr + TxFree) > 1536) { clear_bit(0, (void*)&dev->tbusy); mark_bh(NET_BH); @@ -1854,7 +1788,7 @@ virt_to_bus(&vp->tx_ring[entry])) break; /* It still hasn't been processed. */ if (vp->tx_skbuff[entry]) { - DEV_FREE_SKB(vp->tx_skbuff[entry]); + dev_kfree_skb(vp->tx_skbuff[entry]); vp->tx_skbuff[entry] = 0; } /* vp->stats.tx_packets++; Counted below. */ @@ -1898,14 +1832,6 @@ } while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch); - /* - * If we have totally run out to rx skb's due to persistent OOM, - * we can use the Tx interrupt to retry the allocation. Dirty - * but expedient - */ - if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) - boomerang_rx(dev); - if (vortex_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, status); @@ -1980,12 +1906,8 @@ printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " "size %d.\n", dev->name, pkt_len); } - outw(RxDiscard, ioaddr + EL3_CMD); vp->stats.rx_dropped++; - /* Wait a limited time to skip this packet. */ - for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, RxDiscard); } return 0; @@ -2074,8 +1996,16 @@ entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) + if (skb == NULL) { + static unsigned long last_jif; + if ((jiffies - last_jif) > 10 * HZ) { + printk(KERN_WARNING "%s: memory shortage\n", dev->name); + last_jif = jiffies; + } + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) + mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1)); break; /* Bad news! */ + } skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail)); @@ -2087,6 +2017,26 @@ return 0; } +/* + * If we've hit a total OOM refilling the Rx ring we poll once a second + * for some memory. Otherwise there is no way to restart the rx process. + */ +static void +rx_oom_timer(unsigned long arg) +{ + struct device *dev = (struct device *)arg; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + + spin_lock_irq(&vp->lock); + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ + boomerang_rx(dev); + if (vortex_debug > 1) { + printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, + ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); + } + spin_unlock_irq(&vp->lock); +} + static int vortex_close(struct device *dev) { @@ -2106,6 +2056,7 @@ } del_timer(&vp->timer); + del_timer(&vp->rx_oom_timer); /* Turn off statistics ASAP. We update vp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -2127,10 +2078,7 @@ outl(0, ioaddr + UpListPtr); for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - vp->rx_skbuff[i]->free = 1; -#endif - DEV_FREE_SKB(vp->rx_skbuff[i]); + dev_kfree_skb(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } @@ -2138,11 +2086,13 @@ outl(0, ioaddr + DownListPtr); for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { - DEV_FREE_SKB(vp->tx_skbuff[i]); + dev_kfree_skb(vp->tx_skbuff[i]); vp->tx_skbuff[i] = 0; } } + if (vp->enable_wol && (vp->capabilities & CapPwrMgmt)) + acpi_set_WOL(dev); MOD_DEC_USE_COUNT; return 0; @@ -2219,7 +2169,7 @@ retval = 0; break; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) { + if (!capable(CAP_NET_ADMIN)) { retval = -EPERM; } else { EL3WINDOW(4); @@ -2349,22 +2299,66 @@ return; } +/* ACPI: Advanced Configuration and Power Interface. */ +/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ +static void acpi_set_WOL(struct device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + + /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ + EL3WINDOW(7); + outw(2, ioaddr + 0x0c); + /* The RxFilter must accept the WOL frames. */ + outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); + outw(RxEnable, ioaddr + EL3_CMD); + /* Change the power state to D3; RxEnable doesn't take effect. */ + pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103); +} + +/* Change from D3 (sleep) to D0 (active). + Problem: The Cyclone forgets all PCI config info during the transition! */ +static void acpi_wake(int bus, int devfn) +{ + u32 base0, base1, romaddr; + u16 pci_command, pwr_command; + u8 pci_latency, pci_cacheline, irq; + + pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command); + if ((pwr_command & 3) == 0) + return; + pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command); + pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0); + pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1); + pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr); + pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency); + pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline); + pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq); + + pcibios_write_config_word( bus, devfn, 0xe0, 0x0000); + pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0); + pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1); + pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr); + pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq); + pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency); + pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline); + pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5); +} + #ifdef MODULE void cleanup_module(void) { struct device *next_dev; -#ifdef CARDBUS - unregister_driver(&vortex_ops); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_vortex_dev) { struct vortex_private *vp=(void *)(root_vortex_dev->priv); + int drv_flags = pci_tbl[vp->chip_id].drv_flags; next_dev = vp->next_module; unregister_netdev(root_vortex_dev); - outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); + outw((drv_flags & EEPROM_NORESET) ? (TotalReset|0x10) : TotalReset, + root_vortex_dev->base_addr + EL3_CMD); release_region(root_vortex_dev->base_addr, pci_tbl[vp->chip_id].io_size); kfree(root_vortex_dev); @@ -2377,9 +2371,6 @@ /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.2.18/drivers/net/8139too.c Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/8139too.c Sun Mar 25 11:37:34 2001 @@ -5,12 +5,12 @@ Maintained by Jeff Garzik Much code comes from Donald Becker's rtl8139.c driver, - versions 1.11 and older. This driver was originally based - on rtl8139.c version 1.07. Header of rtl8139.c version 1.11: + versions 1.13 and older. This driver was originally based + on rtl8139.c version 1.07. Header of rtl8139.c version 1.13: ---------- - Written 1997-2000 by Donald Becker. + Written 1997-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Drivers based on or derived from this @@ -45,7 +45,7 @@ Tigran Aivazian - bug fixes, skbuff free cleanup Martin Mares - suggestions for PCI cleanup - + David S. Miller - PCI DMA and softnet updates Ernst Gill - fixes ported from BSD driver @@ -54,12 +54,12 @@ posted MMIO write bugginess Gerard Sharp - bug fix, testing and feedback - + David Ford - Rx ring wrap fix - + Dan DeMaggio - swapped RTL8139 cards with me, and allowed me to find and fix a crucial bug on older chipsets. - + Donald Becker/Chris Butterworth/Marcus Westergren - Noticed various Rx packet size-related buglets. @@ -70,6 +70,13 @@ Martin Dennett - incredibly helpful insight on undocumented features of the 8139 chips + Jean-Jacques Michel - bug fix + + Tobias Ringström - Rx interrupt status checking suggestion + + Andrew Morton - Clear blocked signals, avoid + buffer overrun setting current->comm. + Submitting bug reports: "rtl8139-diag -mmmaaavvveefN" output @@ -130,6 +137,7 @@ */ +#include #include #include #include @@ -137,19 +145,22 @@ #include #include #include +#include #include #include -#define RTL8139_VERSION "0.9.10-2.2" -#define RTL8139_MODULE_NAME "8139too" -#define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " FastEthernet driver " RTL8139_VERSION +#define RTL8139_VERSION "0.9.14-2.2" +#define MODNAME "8139too" +#define RTL8139_DRIVER_NAME MODNAME " FastEthernet driver " RTL8139_VERSION #define RTL8139_AUTHOR "Jeff Garzik " -#define PFX RTL8139_MODULE_NAME ": " +#define PFX MODNAME ": " -/* define to 1 to enable PIO instead of MMIO */ -#undef USE_IO_OPS +/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */ +#ifdef CONFIG_8139TOO_PIO +#define USE_IO_OPS 1 +#endif /* define to 1 to enable copious debugging info */ #undef RTL8139_DEBUG @@ -215,7 +226,7 @@ #define PCI_USES_MEM 2 #define PCI_USES_MASTER 4 -static inline unsigned int pci_calc_resource_flags(unsigned int flags) +static inline unsigned int rtl8139_pci_calc_resource_flags(unsigned int flags) { if (flags & PCI_BASE_ADDRESS_SPACE_IO) return IORESOURCE_IO; @@ -256,27 +267,28 @@ sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; } res->end = res->start + (unsigned long) sz; - res->flags |= (l & 0xf) | pci_calc_resource_flags(l); + res->flags |= (l & 0xf) | rtl8139_pci_calc_resource_flags(l); } } -#define pci_resource_start(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].start) -#define pci_resource_end(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].end) -#define pci_resource_flags(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].flags) -#define pci_resource_len(dev_priv,bar) \ - ((pci_resource_start((dev_priv),(bar)) == 0 && \ - pci_resource_end((dev_priv),(bar)) == \ - pci_resource_start((dev_priv),(bar))) ? 0 : \ +#define rtl8139_pci_resource_start(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].start) +#define rtl8139_pci_resource_end(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].end) +#define rtl8139_pci_resource_flags(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].flags) +#define rtl8139_pci_resource_len(dev_priv,bar) \ + ((rtl8139_pci_resource_start((dev_priv),(bar)) == 0 && \ + rtl8139_pci_resource_end((dev_priv),(bar)) == \ + rtl8139_pci_resource_start((dev_priv),(bar))) ? 0 : \ \ - (pci_resource_end((dev_priv),(bar)) - \ - pci_resource_start((dev_priv),(bar)) + 1)) - -#define arraysize(x) (sizeof(x)/sizeof(*(x))) + (rtl8139_pci_resource_end((dev_priv),(bar)) - \ + rtl8139_pci_resource_start((dev_priv),(bar)) + 1)) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* A few user-configurable values. */ /* media options */ -static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#define MAX_UNITS 8 +static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -295,8 +307,11 @@ /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 +/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ +#define MAX_ETH_FRAME_SIZE 1536 + /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE 1536 +#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE #define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) /* PCI Tuning Parameters @@ -315,6 +330,7 @@ enum { + HAS_MII_XCVR = 0x010000, HAS_CHIP_XCVR = 0x020000, HAS_LNK_CHNG = 0x040000, }; @@ -322,26 +338,34 @@ #define RTL_MIN_IO_SIZE 0x80 #define RTL8139B_IO_SIZE 256 +#define RTL8129_CAPS HAS_MII_XCVR #define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG typedef enum { RTL8139 = 0, RTL8139_CB, SMC1211TX, + /*MPX5030,*/ DELTA8139, ADDTRON8139, + DFE538TX, + RTL8129, } board_t; /* indexed by board_t, above */ static struct { const char *name; + u32 hw_flags; } board_info[] = { - { "RealTek RTL8139 Fast Ethernet" }, - { "RealTek RTL8139B PCI/CardBus" }, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" }, - { "Delta Electronics 8139 10/100BaseTX" }, - { "Addtron Technolgy 8139 10/100BaseTX" }, + { "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS }, + { "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS }, + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS }, +/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/ + { "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS }, + { "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS }, + { "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS }, + { "RealTek RTL8129", RTL8129_CAPS }, }; struct pci_device_id { @@ -353,8 +377,11 @@ {0x10ec, 0x8139, RTL8139 }, {0x10ec, 0x8138, RTL8139_CB }, {0x1113, 0x1211, SMC1211TX }, +/* {0x1113, 0x1211, MPX5030 },*/ {0x1500, 0x1360, DELTA8139 }, {0x4033, 0x1360, ADDTRON8139 }, + {0x1186, 0x1300, DFE538TX }, + {0x10ec, 0x8129, RTL8129 }, {0,} }; @@ -561,17 +588,17 @@ 0x40, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ }, - + { "RTL-8139 rev K", 0x60, 0xf0fe0040, }, - + { "RTL-8139A", 0x70, 0xf0fe0040, }, - + { "RTL-8139B", 0x78, 0xf0fc0040 @@ -591,18 +618,16 @@ struct rtl8139_private { - board_t board; void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; struct resource rtl8139_pci_resource[4]; struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ unsigned int tx_flag; - atomic_t cur_tx; - atomic_t dirty_tx; + unsigned long cur_tx; + unsigned long dirty_tx; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ @@ -610,6 +635,7 @@ dma_addr_t rx_ring_dma; dma_addr_t tx_bufs_dma; char phys[4]; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; @@ -619,6 +645,9 @@ unsigned int mediasense:1; /* Media sensing in progress. */ spinlock_t lock; chip_t chipset; + pid_t thr_pid; + wait_queue_head_t thr_wait; + struct semaphore thr_exited; }; @@ -628,7 +657,7 @@ static int mdio_read (struct device *dev, int phy_id, int location); static void mdio_write (struct device *dev, int phy_id, int location, int val); -static void rtl8139_timer (unsigned long data); +static int rtl8139_thread (void *data); static void rtl8139_tx_timeout (struct device *dev); static void rtl8139_init_ring (struct device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, @@ -642,12 +671,11 @@ static void rtl8139_set_rx_mode (struct device *dev); static void rtl8139_hw_start (struct device *dev); - #ifdef USE_IO_OPS #define RTL_R8(reg) inb (((unsigned long)ioaddr) + (reg)) #define RTL_R16(reg) inw (((unsigned long)ioaddr) + (reg)) -#define RTL_R32(reg) inl (((unsigned long)ioaddr) + (reg)) +#define RTL_R32(reg) ((unsigned long) inl (((unsigned long)ioaddr) + (reg))) #define RTL_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg)) #define RTL_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg)) #define RTL_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg)) @@ -695,12 +723,12 @@ /* read MMIO register */ #define RTL_R8(reg) readb (ioaddr + (reg)) #define RTL_R16(reg) readw (ioaddr + (reg)) -#define RTL_R32(reg) readl (ioaddr + (reg)) +#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) #endif /* USE_IO_OPS */ -static const u16 rtl8139_intr_mask = +static const u16 rtl8139_intr_mask = PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; @@ -742,15 +770,15 @@ rtl8139_read_pci_resources(pdev, &tp->rtl8139_pci_resource[0]); - pio_start = pci_resource_start (tp, 0); - pio_end = pci_resource_end (tp, 0); - pio_flags = pci_resource_flags (tp, 0); - pio_len = pci_resource_len (tp, 0); - - mmio_start = pci_resource_start (tp, 1); - mmio_end = pci_resource_end (tp, 1); - mmio_flags = pci_resource_flags (tp, 1); - mmio_len = pci_resource_len (tp, 1); + pio_start = rtl8139_pci_resource_start (tp, 0); + pio_end = rtl8139_pci_resource_end (tp, 0); + pio_flags = rtl8139_pci_resource_flags (tp, 0); + pio_len = rtl8139_pci_resource_len (tp, 0); + + mmio_start = rtl8139_pci_resource_start (tp, 1); + mmio_end = rtl8139_pci_resource_end (tp, 1); + mmio_flags = rtl8139_pci_resource_flags (tp, 1); + mmio_len = rtl8139_pci_resource_len (tp, 1); /* set this immediately, we need to know before * we talk to the chip directly */ @@ -765,17 +793,16 @@ rc = -ENODEV; goto err_out; } - + /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); rc = -ENODEV; goto err_out; } - + /* check for weird/broken PCI region reporting */ - if ((pio_len != mmio_len) || - (pio_len < RTL_MIN_IO_SIZE) || + if ((pio_len < RTL_MIN_IO_SIZE) || (mmio_len < RTL_MIN_IO_SIZE)) { printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); rc = -ENODEV; @@ -831,14 +858,6 @@ RTL_W8 (Config1, 0); } -#ifndef USE_IO_OPS - /* sanity checks -- ensure PIO and MMIO registers agree */ - assert (inb (pio_start+Config0) == readb (ioaddr+Config0)); - assert (inb (pio_start+Config1) == readb (ioaddr+Config1)); - assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig)); - assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); -#endif /* !USE_IO_OPS */ - /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { @@ -851,10 +870,10 @@ rc = -EIO; goto err_out_iounmap; } - + /* identify chip attached to board */ tmp = RTL_R8 (ChipVersion); - for (i = arraysize (rtl_chip_info) - 1; i >= 0; i--) + for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--) if (tmp == rtl_chip_info[i].version) { tp->chipset = i; goto match; @@ -863,7 +882,7 @@ /* if unknown chip, assume array element #0, original RTL-8139 in this case */ printk (KERN_DEBUG PFX "PCI device %08lX: unknown chip version, assuming RTL-8139\n", (unsigned long) pdev); - printk (KERN_DEBUG PFX "PCI device %08lX: TxConfig = 0x%x\n", (unsigned long) pdev, RTL_R32 (TxConfig)); + printk (KERN_DEBUG PFX "PCI device %08lX: TxConfig = 0x%lx\n", (unsigned long) pdev, RTL_R32 (TxConfig)); tp->chipset = 0; match: @@ -871,11 +890,11 @@ tmp, tp->chipset, rtl_chip_info[tp->chipset].name); - + DPRINTK ("EXIT, returning 0\n"); *ioaddr_out = ioaddr; *dev_out = dev; - return 0; + return 0; err_out_iounmap: assert (ioaddr > 0); @@ -901,7 +920,7 @@ u8 tmp; DPRINTK ("ENTER\n"); - + assert (pdev != NULL); assert (ent != NULL); @@ -912,9 +931,9 @@ DPRINTK ("EXIT, returning %d\n", i); return i; } - + tp = dev->priv; - + assert (ioaddr != NULL); assert (dev != NULL); assert (tp != NULL); @@ -939,14 +958,12 @@ tp = dev->priv; /* note: tp->chipset set in rtl8139_init_board */ - tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | RTL8139_CAPS; + tp->drv_flags = board_info[ent->board].hw_flags; tp->pci_dev = pdev; - tp->board = ent->board; tp->mmio_addr = ioaddr; - tp->lock = SPIN_LOCK_UNLOCKED; - - tp->phys[0] = 32; + spin_lock_init (&tp->lock); + init_waitqueue_head (&tp->thr_wait); + init_MUTEX_LOCKED (&tp->thr_exited); if (rtl8139_device_count == 0) { printk (KERN_INFO "%s: " RTL8139_DRIVER_NAME " " RTL8139_AUTHOR "\n", dev->name); @@ -964,6 +981,30 @@ dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + if (tp->drv_flags & HAS_MII_XCVR) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + tp->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " + "advertising %4.4x.\n", + dev->name, phy, mii_status, tp->advertising); + } + } + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " + "transceiver.\n", + dev->name); + tp->phys[0] = 32; + } + } else + tp->phys[0] = 32; + /* Put the chip into low-power mode. */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -974,21 +1015,29 @@ RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ /* The lower four bits are the media type. */ - option = (board_idx > 7) ? 0 : media[board_idx]; + option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; if (option > 0) { - tp->full_duplex = (option & 0x200) ? 1 : 0; - tp->default_port = option & 15; + tp->full_duplex = (option & 0x210) ? 1 : 0; + tp->default_port = option & 0xFF; if (tp->default_port) tp->medialock = 1; } - + if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) + tp->full_duplex = full_duplex[board_idx]; if (tp->full_duplex) { - printk (KERN_INFO - "%s: Media type forced to Full Duplex.\n", - dev->name); - mdio_write (dev, tp->phys[0], 4, 0x141); + printk (KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); + /* Changing the MII-advertised media because might prevent + re-connection. */ tp->duplex_lock = 1; } + if (tp->default_port) { + printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", + (option & 0x20 ? 100 : 10), + (option & 0x10 ? "full" : "half")); + mdio_write(dev, tp->phys[0], 0, + ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + } rtl8139_device_tab[rtl8139_device_count++] = dev; @@ -1017,8 +1066,8 @@ iounmap (np->mmio_addr); #endif /* !USE_IO_OPS */ - release_region (pci_resource_start (np, 0), - pci_resource_len (np, 0)); + release_region (rtl8139_pci_resource_start (np, 0), + rtl8139_pci_resource_len (np, 0)); #ifndef RTL8139_NDEBUG /* poison memory before freeing */ memset (dev, 0xBC, @@ -1108,7 +1157,7 @@ #define MDIO_WRITE0 (MDIO_DIR) #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) -#define mdio_delay() readb(mdio_addr) +#define mdio_delay(mdio_addr) readb(mdio_addr) static char mii_2_8139_map[8] = { @@ -1132,9 +1181,9 @@ for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } DPRINTK ("EXIT\n"); @@ -1143,7 +1192,7 @@ static int mdio_read (struct device *dev, int phy_id, int location) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; @@ -1162,20 +1211,18 @@ int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; writeb (MDIO_DIR | dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); - retval = - (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 - : 0); + mdio_delay (mdio_addr); + retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); @@ -1186,21 +1233,21 @@ static void mdio_write (struct device *dev, int phy_id, int location, int value) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; - int mii_cmd = - (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i; DPRINTK ("ENTER\n"); if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - if (location < 8 && mii_2_8139_map[location]) { - writew (value, - tp->mmio_addr + mii_2_8139_map[location]); - readw (tp->mmio_addr + mii_2_8139_map[location]); - } - DPRINTK ("EXIT after directly using 8139 internal regs\n"); + void *ioaddr = tp->mmio_addr; + if (location == 0) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W16_F (BasicModeCtrl, value); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } else if (location < 8 && mii_2_8139_map[location]) + RTL_W16_F (mii_2_8139_map[location], value); return; } mdio_sync (mdio_addr); @@ -1210,26 +1257,25 @@ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; writeb (dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } - - DPRINTK ("EXIT\n"); + return; } static int rtl8139_open (struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; int retval; #ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; @@ -1260,11 +1306,12 @@ DPRINTK ("EXIT, returning -ENOMEM\n"); MOD_DEC_USE_COUNT; return -ENOMEM; - + } - + tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; + tp->twistie = 1; rtl8139_init_ring (dev); rtl8139_hw_start (dev); @@ -1275,13 +1322,10 @@ dev->irq, RTL_R8 (MediaStatus), tp->full_duplex ? "full" : "half"); - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer (&tp->timer); - tp->timer.expires = jiffies + 3 * HZ; - tp->timer.data = (unsigned long) dev; - tp->timer.function = &rtl8139_timer; - add_timer (&tp->timer); + tp->thr_pid = kernel_thread (rtl8139_thread, dev, CLONE_FS | CLONE_FILES); + if (tp->thr_pid < 0) + printk (KERN_WARNING "%s: unable to start kernel thread\n", + dev->name); DPRINTK ("EXIT, returning 0\n"); return 0; @@ -1291,13 +1335,13 @@ /* Start the hardware at open or resume. */ static void rtl8139_hw_start (struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 i; u8 tmp; DPRINTK ("ENTER\n"); - + /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); udelay (100); @@ -1307,6 +1351,8 @@ if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; + /* unlock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); @@ -1322,12 +1368,23 @@ /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); - /* unlock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - udelay (10); - tp->cur_rx = 0; + /* This is check_duplex() */ + if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) { + u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); + if (mii_reg5 == 0xffff) + ; /* Not there */ + else if ((mii_reg5 & 0x0100) == 0x0100 + || (mii_reg5 & 0x00C0) == 0x0040) + tp->full_duplex = 1; + printk(KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability %4.4x.\n", dev->name, + mii_reg5 == 0 ? "" : + (mii_reg5 & 0x0180) ? "100Mbps " : "10Mbps ", + tp->full_duplex ? "full" : "half", mii_reg5); + } + if (tp->chipset >= CH_8139A) { tmp = RTL_R8 (Config1) & Config1Clear; tmp |= Cfg1_Driver_Load; @@ -1341,9 +1398,9 @@ if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ - tmp |= (1<<7); + tmp |= (1<<7); RTL_W8 (Config4, tmp); - + /* disable magic packet scanning, which is enabled * when PM is enabled above (Config1) */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); @@ -1383,14 +1440,14 @@ /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void rtl8139_init_ring (struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; int i; DPRINTK ("ENTER\n"); tp->cur_rx = 0; - atomic_set (&tp->cur_tx, 0); - atomic_set (&tp->dirty_tx, 0); + tp->cur_tx = 0; + tp->dirty_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { tp->tx_info[i].skb = NULL; @@ -1401,7 +1458,10 @@ } -#ifndef RTL_TUNE_TWISTER +/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */ +static int next_tick = 3 * HZ; + +#ifndef CONFIG_8139TOO_TUNE_TWISTER static inline void rtl8139_tune_twister (struct device *dev, struct rtl8139_private *tp) {} #else @@ -1409,6 +1469,7 @@ struct rtl8139_private *tp) { int linkcase; + void *ioaddr = tp->mmio_addr; DPRINTK ("ENTER\n"); @@ -1492,15 +1553,13 @@ DPRINTK ("EXIT\n"); } -#endif /* RTL_TUNE_TWISTER */ +#endif /* CONFIG_8139TOO_TUNE_TWISTER */ -static void rtl8139_timer (unsigned long data) +static inline void rtl8139_thread_iter (struct device *dev, + struct rtl8139_private *tp, + void *ioaddr) { - struct device *dev = (struct device *) data; - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; - void *ioaddr = tp->mmio_addr; - int next_tick = 60 * HZ; int mii_reg5; mii_reg5 = mdio_read (dev, tp->phys[0], 5); @@ -1521,30 +1580,82 @@ } } + next_tick = HZ * 60; + rtl8139_tune_twister (dev, tp); DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", dev->name, RTL_R16 (NWayLPAR)); DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4x.\n", dev->name, + " RxStatus %4.4lx.\n", dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus), RTL_R32 (RxEarlyStatus)); DPRINTK ("%s: Chip config %2.2x %2.2x.\n", dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); +} + - tp->timer.expires = jiffies + next_tick; - add_timer (&tp->timer); +static int rtl8139_thread (void *data) +{ + struct device *dev = (struct device *) data; + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + unsigned long timeout; + + daemonize (); + spin_lock_irq(¤t->sigmask_lock); + sigemptyset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + strncpy (current->comm, dev->name, sizeof(current->comm) - 1); + current->comm[sizeof(current->comm) - 1] = '\0'; + + while (1) { + timeout = next_tick; + do { + timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); + } while (!signal_pending (current) && (timeout > 0)); + + if (signal_pending (current)) + break; + + rtnl_lock (); + rtl8139_thread_iter (dev, tp, tp->mmio_addr); + rtnl_unlock (); + } + + up (&tp->thr_exited); + return 0; +} + + +static void rtl8139_tx_clear (struct rtl8139_private *tp) +{ + int i; + + tp->cur_tx = 0; + tp->dirty_tx = 0; + + /* Dump the unsent Tx packets. */ + for (i = 0; i < NUM_TX_DESC; i++) { + struct ring_info *rp = &tp->tx_info[i]; + if (rp->skb) { + dev_kfree_skb (rp->skb); + rp->skb = NULL; + tp->stats.tx_dropped++; + } + } } static void rtl8139_tx_timeout (struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int i; - unsigned long flags; + u8 tmp8; DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1552,46 +1663,36 @@ RTL_R16 (IntrStatus), RTL_R8 (MediaStatus)); + /* disable Tx ASAP, if not already */ + tmp8 = RTL_R8 (ChipCmd); + if (tmp8 & CmdTxEnb) + RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb); + /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", - dev->name, atomic_read (&tp->cur_tx), - atomic_read (&tp->dirty_tx)); + printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", + dev->name, tp->cur_tx, tp->dirty_tx); for (i = 0; i < NUM_TX_DESC; i++) - printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n", + printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), - i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? + i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); - spin_lock_irqsave (&tp->lock, flags); - /* Stop a shared interrupt from scavenging while we are. */ - atomic_set (&tp->cur_tx, 0); - atomic_set (&tp->dirty_tx, 0); - - /* Dump the unsent Tx packets. */ - for (i = 0; i < NUM_TX_DESC; i++) { - struct ring_info *rp = &tp->tx_info[i]; - if (rp->skb) { - dev_kfree_skb (rp->skb); - rp->skb = NULL; - tp->stats.tx_dropped++; - } - } - - spin_unlock_irqrestore (&tp->lock, flags); + spin_lock_irq (&tp->lock); + rtl8139_tx_clear (tp); + spin_unlock_irq (&tp->lock); /* ...and finally, reset everything */ rtl8139_hw_start (dev); } - static int rtl8139_start_xmit (struct sk_buff *skb, struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry; @@ -1602,22 +1703,34 @@ } /* Calculate the next Tx descriptor entry. */ - entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC; + entry = tp->cur_tx % NUM_TX_DESC; assert (tp->tx_info[entry].skb == NULL); tp->tx_info[entry].skb = skb; - memcpy (tp->tx_buf[entry], skb->data, skb->len); + if ((long) skb->data & 3) { /* Must use alignment buffer. */ + /* tp->tx_info[entry].mapping = 0 */ + memcpy (tp->tx_buf[entry], skb->data, skb->len); + RTL_W32 (TxAddr0 + (entry * 4), + tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs)); + } else { + RTL_W32 (TxAddr0 + (entry * 4), virt_to_bus(skb->data)); + } /* Note: the chip doesn't have auto-pad! */ RTL_W32 (TxStatus0 + (entry * sizeof(u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; - atomic_inc (&tp->cur_tx); - if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC) + + spin_lock_irq (&tp->lock); + + tp->cur_tx++; + if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); + spin_unlock_irq (&tp->lock); + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); @@ -1625,24 +1738,24 @@ } -static inline void rtl8139_tx_interrupt (struct device *dev, +static void rtl8139_tx_interrupt (struct device *dev, struct rtl8139_private *tp, void *ioaddr) { - unsigned int dirty_tx; + unsigned long dirty_tx, tx_left; assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - - dirty_tx = atomic_read (&tp->dirty_tx); - while ((atomic_read (&tp->cur_tx) - dirty_tx) > 0) { + dirty_tx = tp->dirty_tx; + tx_left = tp->cur_tx - dirty_tx; + while (tx_left > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus; txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32))); - + if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted))) break; /* It still hasn't been Txed */ @@ -1675,26 +1788,27 @@ tp->stats.tx_bytes += txstatus & 0x7ff; tp->stats.tx_packets++; } - dev_kfree_skb_irq (tp->tx_info[entry].skb); tp->tx_info[entry].skb = NULL; + dirty_tx++; - if (netif_queue_stopped (dev) && - (atomic_read (&tp->cur_tx) - dirty_tx < NUM_TX_DESC)) - netif_wake_queue (dev); - mark_bh(NET_BH); + tx_left--; } #ifndef RTL8139_NDEBUG - if (atomic_read (&tp->cur_tx) - dirty_tx > NUM_TX_DESC) { - printk (KERN_ERR - "%s: Out-of-sync dirty pointer, %d vs. %d.\n", - dev->name, dirty_tx, atomic_read (&tp->cur_tx)); + if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { + printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", + dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } #endif /* RTL8139_NDEBUG */ - atomic_set (&tp->dirty_tx, dirty_tx); + /* only wake the queue if we did work, and the queue is stopped */ + if (tp->dirty_tx != dirty_tx) { + tp->dirty_tx = dirty_tx; + if (netif_queue_stopped (dev)) + netif_wake_queue (dev); + } } /* TODO: clean this up! Rx reset need not be this intensive */ @@ -1769,10 +1883,15 @@ while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { int ring_offset = cur_rx % RX_BUF_LEN; - u32 rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); - int rx_size = rx_status >> 16; + u32 rx_status; + unsigned int rx_size; + unsigned int pkt_size; struct sk_buff *skb; - int pkt_size = rx_size - 4; + + /* read size+status of next frame from DMA ring buffer */ + rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); + rx_size = rx_status >> 16; + pkt_size = rx_size - 4; DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, @@ -1800,11 +1919,13 @@ if (rx_size == 0xfff0) break; - /* if Rx err received, Rx process gets reset, so - * we abort any further Rx processing + /* If Rx err or invalid rx_size/rx_status received + * (which happens if we get lost in the ring), + * Rx process gets reset, so we abort any further + * Rx processing. */ - if (rx_status & - (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | RxBadAlign)) { + if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || + (!(rx_status & RxStatusOK))) { rtl8139_rx_err (rx_status, dev, tp, ioaddr); return; } @@ -1819,24 +1940,24 @@ */ skb = dev_alloc_skb (pkt_size + 2); - if (skb == NULL) { + if (skb) { + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align the IP fields. */ + + eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); + skb_put (skb, pkt_size); + + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); + mark_bh(NET_BH); + tp->stats.rx_bytes += pkt_size ; + tp->stats.rx_packets++; + } else { printk (KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); tp->stats.rx_dropped++; - break; } - skb->dev = dev; - skb_reserve (skb, 2); /* 16 byte align the IP fields. */ - - eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); - skb_put (skb, pkt_size); - - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); - mark_bh(NET_BH); - tp->stats.rx_bytes += pkt_size ; - tp->stats.rx_packets++; cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; RTL_W16_F (RxBufPtr, cur_rx - 16); @@ -1858,11 +1979,11 @@ { printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n", dev->name, status); - + assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - + /* Update the error count. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); @@ -1877,9 +1998,12 @@ tp->full_duplex = duplex; RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + RTL_W8 (Cfg9346, Cfg9346_Lock); } status &= ~RxUnderrun; } + + /* XXX along with rtl8139_rx_err, are we double-counting errors? */ if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) tp->stats.rx_errors++; @@ -1909,20 +2033,18 @@ struct pt_regs *regs) { struct device *dev = (struct device *) dev_instance; - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ - spin_lock (&tp->lock); - do { status = RTL_R16 (IntrStatus); /* h/w no longer present (hotplug?) or major error, bail */ if (status == 0xFFFF) break; - + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -1966,8 +2088,11 @@ if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ rtl8139_rx_interrupt (dev, tp, ioaddr); - if (status & (TxOK | TxErr)) + if (status & (TxOK | TxErr)) { + spin_lock (&tp->lock); rtl8139_tx_interrupt (dev, tp, ioaddr); + spin_unlock (&tp->lock); + } boguscnt--; } while (boguscnt > 0); @@ -1982,8 +2107,6 @@ RTL_W16 (IntrStatus, 0xffff); } - spin_unlock (&tp->lock); - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -1991,41 +2114,51 @@ static int rtl8139_close (struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int i; - unsigned long flags; + int ret = 0; DPRINTK ("ENTER\n"); netif_stop_queue (dev); dev->start = 0; + if (tp->thr_pid >= 0) { + ret = kill_proc (tp->thr_pid, SIGTERM, 1); + if (ret) { + printk (KERN_ERR "%s: unable to signal thread\n", dev->name); + return ret; + } + down (&tp->thr_exited); + } DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); - del_timer (&tp->timer); - - spin_lock_irqsave (&tp->lock, flags); - - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16 (IntrMask, 0x0000); + spin_lock_irq(&tp->lock); /* Stop the chip's Tx and Rx DMA processes. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear)); + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0x0000); + /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); - spin_unlock_irqrestore (&tp->lock, flags); - + spin_unlock_irq (&tp->lock); + + synchronize_irq (); + /* snooze for a small bit */ if (current->need_resched) schedule (); free_irq (dev->irq, dev); + rtl8139_tx_clear (tp); + for (i = 0; i < NUM_TX_DESC; i++) { struct sk_buff *skb = tp->tx_info[i].skb; @@ -2055,9 +2188,8 @@ static int mii_ioctl (struct device *dev, struct ifreq *rq, int cmd) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; u16 *data = (u16 *) & rq->ifr_data; - unsigned long flags; int rc = 0; DPRINTK ("ENTER\n"); @@ -2068,9 +2200,7 @@ /* Fall Through */ case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ - spin_lock_irqsave (&tp->lock, flags); data[3] = mdio_read (dev, data[0], data[1] & 0x1f); - spin_unlock_irqrestore (&tp->lock, flags); break; case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ @@ -2079,10 +2209,20 @@ break; } - spin_lock_irqsave (&tp->lock, flags); - mdio_write (dev, data[0], data[1] & 0x1f, data[2]); - spin_unlock_irqrestore (&tp->lock, flags); - break; + if (data[0] == tp->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + tp->medialock = (value & 0x9000) ? 0 : 1; + if (tp->medialock) + tp->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: tp->advertising = value; break; + } + } + mdio_write(dev, data[0], data[1] & 0x1f, data[2]); + break; default: rc = -EOPNOTSUPP; @@ -2096,22 +2236,16 @@ static struct net_device_stats *rtl8139_get_stats (struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; DPRINTK ("ENTER\n"); - assert (tp != NULL); - if (netif_running(dev)) { - unsigned long flags; - - spin_lock_irqsave (&tp->lock, flags); - + spin_lock_irq(&tp->lock); tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); - - spin_unlock_irqrestore (&tp->lock, flags); + spin_unlock_irq(&tp->lock); } DPRINTK ("EXIT\n"); @@ -2134,8 +2268,7 @@ unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? + crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } @@ -2146,15 +2279,16 @@ static void rtl8139_set_rx_mode (struct device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; u32 tmp; DPRINTK ("ENTER\n"); - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", + DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, dev->flags, RTL_R32 (RxConfig)); /* Note: do not reorder, GCC is clever about common statements. */ @@ -2180,8 +2314,8 @@ set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); } - - spin_lock_irq (&tp->lock); + + spin_lock_irqsave (&tp->lock, flags); /* We can safely update without stopping the chip. */ tmp = rtl8139_rx_config | rx_mode | @@ -2190,7 +2324,7 @@ RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } @@ -2231,8 +2365,8 @@ MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver"); MODULE_PARM (multicast_filter_limit, "i"); MODULE_PARM (max_interrupt_work, "i"); -MODULE_PARM (debug, "i"); -MODULE_PARM (media, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); int init_module(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/Config.in linux/drivers/net/Config.in --- v2.2.18/drivers/net/Config.in Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/Config.in Sun Mar 25 11:37:34 2001 @@ -101,7 +101,11 @@ tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'RealTek 8139too driver support' CONFIG_RTL8139TOO + tristate 'Alternative RealTek 8139 driver (8139too) support' CONFIG_RTL8139TOO + if [ "$CONFIG_RTL8139TOO" != "n" ]; then + bool ' Use PIO instead of MMIO' CONFIG_8139TOO_PIO + bool ' Support for automatic channel equalization' CONFIG_8139TOO_TUNE_TWISTER + fi fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then @@ -132,9 +136,11 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT + tristate 'LP486E on board Ethernet' CONFIG_LP486E tristate 'CS89x0 support' CONFIG_CS89x0 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 @@ -182,7 +188,9 @@ tristate 'Packet Engines GNIC-II (Hamachi) support' CONFIG_HAMACHI tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN fi - tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN + if [ "$CONFIG_PCI" = "y" ]; then + tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN + fi endmenu bool 'FDDI driver support' CONFIG_FDDI @@ -305,7 +313,7 @@ # tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX - if [ "$CONFIG_COMX" != "n" ]; then +if [ "$CONFIG_COMX" != "n" ]; then dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX @@ -326,7 +334,7 @@ dep_tristate ' SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC dep_tristate ' Moxa C101 support' CONFIG_C101 $CONFIG_HDLC - if [ "$CONFIG_PCI" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then dep_tristate ' SBE wanXL support' CONFIG_WANXL $CONFIG_HDLC dep_tristate ' Cyclades-PC300 support' CONFIG_PC300 $CONFIG_HDLC if [ "$CONFIG_PC300" != "n" ]; then @@ -347,12 +355,13 @@ # Wan router core. # -if [ "$CONFIG_WAN_ROUTER" != "n" ]; then +# CONFIG_WAN_ROUTER is defined only when CONFIG_EXPERIMENTAL=y +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_WAN_ROUTER" != "n" ]; then bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then dep_tristate 'Sangoma WANPIPE(tm) multi-port cards: (select M not Y !)' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS if [ "$CONFIG_INET" != "n" ]; then - if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then + if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 #bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR @@ -366,17 +375,21 @@ # # Xpeed drivers # -tristate 'Xpeed X200/X300 DSL NIC support' CONFIG_XPEED +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Xpeed X200/X300 DSL NIC support' CONFIG_XPEED +fi endmenu # # X.25 network drivers # -if [ "$CONFIG_X25" != "n" ]; then -if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then + +# CONFIG_X25 is defined only when CONFIG_EXPERIMENTAL=y +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X25" != "n" ]; then + if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB -fi + fi fi tristate 'SBNI12-xx support' CONFIG_SBNI diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/Makefile linux/drivers/net/Makefile --- v2.2.18/drivers/net/Makefile Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/Makefile Sun Mar 25 11:37:34 2001 @@ -742,6 +742,14 @@ endif endif +ifeq ($(CONFIG_ADAPTEC_STARFIRE),y) +L_OBJS += starfire.o +else + ifeq ($(CONFIG_ADAPTEC_STARFIRE),m) + M_OBJS += starfire.o + endif +endif + ifeq ($(CONFIG_AC3200),y) L_OBJS += ac3200.o CONFIG_8390_BUILTIN = y @@ -774,6 +782,11 @@ ifeq ($(CONFIG_BVME6000_NET),m) CONFIG_82596_MODULE = y endif +endif + +# This is also a 82596 and should probably be merged +ifeq ($(CONFIG_LP486E),y) +L_OBJS += lp486e.o endif ifeq ($(CONFIG_DEC_ELCP),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/Space.c linux/drivers/net/Space.c --- v2.2.18/drivers/net/Space.c Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/Space.c Sun Mar 25 11:37:34 2001 @@ -64,6 +64,7 @@ extern int fmv18x_probe(struct device *); extern int eth16i_probe(struct device *); extern int depca_probe(struct device *); +extern int lp486e_probe(struct device *); extern int i82596_probe(struct device *); extern int ewrk3_probe(struct device *); extern int de4x5_probe(struct device *); @@ -126,6 +127,7 @@ extern int rcpci_probe(struct device *); extern int dmfe_probe(struct device *); extern int sktr_probe(struct device *dev); +extern int starfire_probe(struct device *dev); /* Gigabit Ethernet adapters */ extern int yellowfin_probe(struct device *dev); @@ -277,9 +279,12 @@ #ifdef CONFIG_VIA_RHINE {via_rhine_probe, 0}, #endif -#ifdef CONFI_NET_DM9102 +#ifdef CONFIG_NET_DM9102 {dmfe_probe, 0}, -#endif +#endif +#ifdef CONFIG_ADAPTEC_STARFIRE + {starfire_probe, 0}, +#endif {NULL, 0}, }; @@ -419,6 +424,9 @@ #endif #if defined(CONFIG_APRICOT) || defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET) /* Intel I82596 */ {i82596_probe, 0}, +#endif +#if defined(CONFIG_LP486E) + {lp486e_probe, 0}, #endif #ifdef CONFIG_EL1 /* 3c501 */ {el1_probe, 0}, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/cosa.c linux/drivers/net/cosa.c --- v2.2.18/drivers/net/cosa.c Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/cosa.c Sun Mar 25 11:37:34 2001 @@ -817,7 +817,7 @@ up(&chan->rsem); if (copy_to_user(buf, kbuf, count)) { - kfree(buf); + kfree(kbuf); return -EFAULT; } kfree(kbuf); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.2.18/drivers/net/cs89x0.c Sun Mar 25 11:12:50 2001 +++ linux/drivers/net/cs89x0.c Sun Mar 25 11:37:34 2001 @@ -27,6 +27,8 @@ : is running from all accounts. Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + Arnaldo Melo : release resources on failure in cs89x0_probe1 */ static char *version = @@ -249,13 +251,17 @@ struct net_local *lp; static unsigned version_printed = 0; int i; + char priv_alloced_here = 0; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; /* Initialize the device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); + priv_alloced_here = 1; } lp = (struct net_local *)dev->priv; @@ -265,12 +271,12 @@ if (ioaddr & 1) { ioaddr &= ~1; if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG) - return ENODEV; + goto err; outw(PP_ChipID, ioaddr + ADD_PORT); } if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) - return ENODEV; + goto err; /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; @@ -388,6 +394,11 @@ printk("\n"); return 0; +err: if (priv_alloced_here) { + kfree(dev->priv); + dev->priv = NULL; + } + return -ENODEV; } @@ -1007,16 +1018,15 @@ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(debug, "i"); -MODULE_PARM(media, "s"); +MODULE_PARM(media, "c8"); MODULE_PARM(duplex, "i"); EXPORT_NO_SYMBOLS; /* -* media=t - specify media type - or media=2 +* media=rj45 - specify media type + or media=bnc or media=aui - or medai=auto * duplex=0 - specify forced half/full/autonegotiate duplex * debug=# - debug level diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.2.18/drivers/net/eepro100.c Sun Mar 25 11:28:25 2001 +++ linux/drivers/net/eepro100.c Sun Mar 25 11:37:34 2001 @@ -751,6 +751,7 @@ This takes less than 10usec and will easily finish before the next action. */ outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); /* Honor PortReset timing. */ udelay(10); @@ -778,7 +779,7 @@ /* The self-test results must be paragraph aligned. */ s32 str[6], *volatile self_test_results; int boguscnt = 16000; /* Timeout for set-test. */ - if (eeprom[3] & 0x03) + if ((eeprom[3] & 0x03) != 0x03) printk(KERN_INFO " Receiver lock-up bug exists -- enabling" " work-around.\n"); printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical" @@ -839,6 +840,7 @@ #endif /* kernel_bloat */ outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); /* Honor PortReset timing. */ udelay(10); @@ -1062,6 +1064,9 @@ /* Set the segment registers to '0'. */ wait_for_cmd_done(ioaddr + SCBCmd); outl(0, ioaddr + SCBPointer); + /* impose a delay to avoid a bug */ + inl(ioaddr + SCBPointer); + udelay(10); outb(RxAddrLoad, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); outb(CUCmdBase, ioaddr + SCBCmd); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/gmac.c linux/drivers/net/gmac.c --- v2.2.18/drivers/net/gmac.c Sun Mar 25 11:28:26 2001 +++ linux/drivers/net/gmac.c Sun Mar 25 11:37:34 2001 @@ -9,7 +9,7 @@ * Changes: * Arnaldo Carvalho de Melo - 08/06/2000 * - check init_etherdev return in gmac_probe1 - * BenH - 03/09/2000 + * BenH - 03/09/2000 * - Add support for new PHYs * - Add some PowerBook sleep code * diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c --- v2.2.18/drivers/net/hamradio/scc.c Sun Mar 25 11:28:26 2001 +++ linux/drivers/net/hamradio/scc.c Sun Mar 25 11:37:34 2001 @@ -1,7 +1,7 @@ #define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $" #define VERSION "3.0" -#define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n" +#define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE / patch F6FBB\n" /* * Please use z8530drv-utils-3.0 with this version. @@ -417,6 +417,7 @@ { scc_tx_done(scc); Outb(scc->ctrl, RES_Tx_P); + del_timer(&scc->fs_wdog); /* Stop failsafe watchdog */ return; } @@ -426,6 +427,7 @@ scc->tx_buff = NULL; scc_tx_done(scc); Outb(scc->ctrl, RES_Tx_P); + del_timer(&scc->fs_wdog); /* Stop failsafe watchdog */ return; } @@ -451,6 +453,7 @@ dev_kfree_skb(skb); scc->tx_buff = NULL; scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */ + mod_timer(&scc->fs_wdog, jiffies + HZ*60); /* restart failsafe watchdog */ return; } @@ -823,6 +826,7 @@ { del_timer(&scc->tx_t); del_timer(&scc->tx_wdog); + del_timer(&scc->fs_wdog); disable_irq(scc->irq); @@ -1334,6 +1338,29 @@ } +/* FailSafe timeout + * + * Fall into this timeout if a buffer is waiting + * and nothing has been sent during 1 minute + */ + +static void t_failsafe(unsigned long channel) +{ + struct scc_channel *scc = (struct scc_channel *) channel; + + del_timer(&scc->fs_wdog); + + /* Kernel message */ + printk(KERN_ERR "z8530drv: scc port %s failed. Re-init done.\n", scc->dev->name); + + /* Add 1000 to the tx-underrun counter */ + scc->stat.tx_under += 1000; + + /* re-initialize the port */ + scc_net_close(scc->dev); + scc_net_open(scc->dev); +} + /* ******************************************************************** */ /* * Set/get L1 parameters * */ /* ******************************************************************** */ @@ -1687,6 +1714,7 @@ del_timer(&scc->tx_t); del_timer(&scc->tx_wdog); + del_timer(&scc->fs_wdog); restore_flags(flags); @@ -1726,6 +1754,7 @@ struct scc_channel *scc = (struct scc_channel *) dev->priv; unsigned long flags; char kisscmd; + int nbbuf; if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy) { @@ -1755,8 +1784,9 @@ save_flags(flags); cli(); - - if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) + + nbbuf = skb_queue_len(&scc->tx_queue); + if (nbbuf > scc->dev->tx_queue_len) { struct sk_buff *skb_del; skb_del = __skb_dequeue(&scc->tx_queue); @@ -1765,6 +1795,16 @@ __skb_queue_tail(&scc->tx_queue, skb); dev->trans_start = jiffies; + + if (nbbuf == 0) + { + del_timer(&scc->fs_wdog); + /* Arm the failsafe timer for 1 minute */ + scc->fs_wdog.data = (unsigned long) scc; + scc->fs_wdog.function = t_failsafe; + scc->fs_wdog.expires = jiffies + HZ*60; + add_timer(&scc->fs_wdog); + } /* * Start transmission if the trx state is idle or diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c --- v2.2.18/drivers/net/irda/irtty.c Sun Mar 25 11:12:53 2001 +++ linux/drivers/net/irda/irtty.c Sun Mar 25 11:37:34 2001 @@ -282,6 +282,11 @@ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); tty->disc_data = 0; + /* We are not using any dongle anymore! */ + if (self->dongle) + irda_device_dongle_cleanup(self->dongle); + self->dongle = NULL; + /* Remove netdevice */ if (self->netdev) { rtnl_lock(); @@ -291,11 +296,6 @@ kfree(self->netdev); } - /* We are not using any dongle anymore! */ - if (self->dongle) - irda_device_dongle_cleanup(self->dongle); - self->dongle = NULL; - /* Remove speed changing task if any */ if (self->task) irda_task_delete(self->task); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/lance.c linux/drivers/net/lance.c --- v2.2.18/drivers/net/lance.c Sun Mar 25 11:12:49 2001 +++ linux/drivers/net/lance.c Sun Mar 25 11:37:34 2001 @@ -926,6 +926,8 @@ lp->tx_ring[entry].misc = 0x0000; + lp->stats.tx_bytes += skb->len; + /* If any part of this buffer is >16M we must copy it to a low-memory buffer. */ if ((u32)virt_to_bus(skb->data) + skb->len > 0x01000000) { @@ -941,7 +943,6 @@ lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000; } lp->cur_tx++; - lp->stats.tx_bytes += skb->len; /* Trigger an immediate send poll. */ outw(0x0000, ioaddr+LANCE_ADDR); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/lanstreamer.c linux/drivers/net/lanstreamer.c --- v2.2.18/drivers/net/lanstreamer.c Sun Mar 25 11:12:55 2001 +++ linux/drivers/net/lanstreamer.c Sun Mar 25 11:37:34 2001 @@ -58,6 +58,7 @@ * First release to the public * 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing * malloc free checks, reviewed code. + * 12/18/00 - Made it SMP safe - George Staikos * * To Do: * @@ -108,6 +109,7 @@ #include #include +#include #include #include @@ -285,6 +287,8 @@ streamer_priv = (struct streamer_private *) dev->priv; streamer_mmio = streamer_priv->streamer_mmio; + streamer_priv->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + printk("%s \n", version); printk(KERN_INFO "%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, using irq %d\n", dev->name, (unsigned int) dev->base_addr, @@ -823,6 +827,7 @@ __u16 misr; __u16 sisrmask; + spin_lock(&(streamer_priv->lock)); sisrmask = SISR_MI; writew(~sisrmask, streamer_mmio + SISR_MASK_RUM); sisr = readw(streamer_mmio + SISR); @@ -831,6 +836,7 @@ writew(~misr, streamer_mmio + MISR_RUM); if (!sisr) { /* Interrupt isn't for us */ + spin_unlock(&(streamer_priv->lock)); return; } @@ -919,6 +925,7 @@ dev->interrupt = 0; writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); + spin_unlock(&(streamer_priv->lock)); } @@ -927,11 +934,14 @@ struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; __u8 *streamer_mmio = streamer_priv->streamer_mmio; + int flags; if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { return 1; } + spin_lock_irqsave(&(streamer_priv->lock), flags); + if (streamer_priv->free_tx_ring_entries) { streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len; @@ -956,8 +966,10 @@ streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); dev->tbusy = 0; + spin_unlock_irqrestore(&(streamer_priv->lock), flags); return 0; } else { + spin_unlock_irqrestore(&(streamer_priv->lock), flags); return 1; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/lanstreamer.h linux/drivers/net/lanstreamer.h --- v2.2.18/drivers/net/lanstreamer.h Sun Mar 25 11:12:55 2001 +++ linux/drivers/net/lanstreamer.h Sun Mar 25 11:37:34 2001 @@ -283,6 +283,7 @@ __u16 streamer_addr_table_addr, streamer_parms_addr; __u16 mac_rx_buffer; __u8 streamer_laa[6]; + spinlock_t lock; }; struct streamer_adapter_addr_table { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/lp486e.c linux/drivers/net/lp486e.c --- v2.2.18/drivers/net/lp486e.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/net/lp486e.c Sun Mar 25 11:37:34 2001 @@ -0,0 +1,1401 @@ +/* Intel Professional Workstation/panther ethernet driver */ +/* lp486e.c: A panther 82596 ethernet driver for linux. */ +/* + History and copyrights: + + Driver skeleton + Written 1993 by Donald Becker. + Copyright 1993 United States Government as represented by the Director, + National Security Agency. This software may only be used and + distributed according to the terms of the GNU Public License + as modified by SRC, incorporated herein by reference. + + The author may be reached as becker@super.org or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + + Apricot + Written 1994 by Mark Evans. + This driver is for the Apricot 82596 bus-master interface + + Modularised 12/94 Mark Evans + + Professional Workstation + Derived from apricot.c by Ard van Breemen + || + + Credits: + Thanks to Murphy Software BV for letting me write this in their time. + Well, actually, I get payed doing this... + (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for + more information on the Professional Workstation) + + Present version + aeb@cwi.nl +*/ +/* + There are currently two motherboards that I know of in the + professional workstation. The only one that I know is the + intel panther motherboard. -- ard +*/ +/* +The pws is equipped with an intel 82596. This is a very intelligent controller +which runs its own micro-code. Communication with the hostprocessor is done +through linked lists of commands and buffers in the hostprocessors memory. +A complete description of the 82596 is available from intel. Search for +a file called "29021806.pdf". It is a complete description of the chip itself. +To use it for the pws some additions are needed regarding generation of +the PORT and CA signal, and the interrupt glue needed for a pc. +I/O map: +PORT SIZE ACTION MEANING +0xCB0 2 WRITE Lower 16 bits for PORT command +0xCB2 2 WRITE Upper 16 bits for PORT command, and issue of PORT command +0xCB4 1 WRITE Generation of CA signal +0xCB8 1 WRITE Clear interrupt glue +All other communication is through memory! +*/ + +#define SLOW_DOWN_IO udelay(5); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define kkmalloc(typ, prio) (typ *)(kmalloc(sizeof(typ), prio)) + +#ifdef REALLY_OLD +#ifndef HAVE_PORTRESERVE +#define check_region(addr, size) 0 +#define request_region(addr, size,name) do ; while(0) +#endif + +#ifndef HAVE_ALLOC_SKB +#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) +#define kfree_skbmem(buff, size) kfree_s(buff,size) +#endif +#endif /* REALLY_OLD */ + +#define LOG_SRCDST 0x80000000 +#define LOG_STATINT 0x40000000 +#define LOG_STARTINT 0x20000000 + +#define i596_debug debug + +static int i596_debug = 0; + +static const char * const medianame[] = { + "10baseT", "AUI", + "10baseT-FD", "AUI-FD", +}; + +#define LP486E_TOTAL_SIZE 16 + +#define I596_NULL (0xffffffff) + +#define CMD_EOL 0x8000 /* The last command of the list, stop. */ +#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ +#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */ + +#define CMD_FLEX 0x0008 /* Enable flexible memory model */ + +enum commands { + CmdNOP = 0, + CmdIASetup = 1, + CmdConfigure = 2, + CmdMulticastList = 3, + CmdTx = 4, + CmdTDR = 5, + CmdDump = 6, + CmdDiagnose = 7 +}; + +char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList", + "Tx", "TDR", "Dump", "Diagnose" }; + +/* Status word bits */ +#define STAT_CX 0x8000 /* The CU finished executing a command + with the Interrupt bit set */ +#define STAT_FR 0x4000 /* The RU finished receiving a frame */ +#define STAT_CNA 0x2000 /* The CU left the active state */ +#define STAT_RNR 0x1000 /* The RU left the active state */ +#define STAT_ACK (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR) +#define STAT_CUS 0x0700 /* Status of CU: 0: idle, 1: suspended, + 2: active, 3-7: unused */ +#define STAT_RUS 0x00f0 /* Status of RU: 0: idle, 1: suspended, + 2: no resources, 4: ready, + 10: no resources due to no more RBDs, + 12: no more RBDs, other: unused */ +#define STAT_T 0x0008 /* Bus throttle timers loaded */ +#define STAT_ZERO 0x0807 /* Always zero */ + +char *CUstates[8] = { "idle", "suspended", "active", 0, 0, 0, 0, 0 }; +char *RUstates[16] = { "idle", "suspended", "no resources", 0, "ready", 0, + 0, 0, 0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0 }; + +#if 0 +static void +i596_out_status(int status) { + int bad = 0; + char *s; + + printk("status %4.4x:", status); + if (status == 0xffff) + printk(" strange..\n"); + else { + if (status & STAT_CX) + printk(" CU done"); + if (status & STAT_CNA) + printk(" CU stopped"); + if (status & STAT_FR) + printk(" got a frame"); + if (status & STAT_RNR) + printk(" RU stopped"); + if (status & STAT_T) + printk(" throttled"); + if (status & STAT_ZERO) + bad = 1; + s = CUstates[(status & STAT_CUS) >> 8]; + if (!s) + bad = 1; + else + printk(" CU(%s)", s); + s = RUstates[(status & STAT_RUS) >> 4]; + if (!s) + bad = 1; + else + printk(" RU(%s)", s); + if (bad) + printk(" bad status"); + printk("\n"); + } +} +#endif + +/* Command word bits */ +#define ACK_CX 0x8000 +#define ACK_FR 0x4000 +#define ACK_CNA 0x2000 +#define ACK_RNR 0x1000 + +#define CUC_START 0x0100 +#define CUC_RESUME 0x0200 +#define CUC_SUSPEND 0x0300 +#define CUC_ABORT 0x0400 + +#define RX_START 0x0010 +#define RX_RESUME 0x0020 +#define RX_SUSPEND 0x0030 +#define RX_ABORT 0x0040 + +typedef u32 phys_addr; + +static inline phys_addr +va_to_pa(volatile void *x) { + return x ? virt_to_bus(x) : I596_NULL; +} + +static inline void * +pa_to_va(phys_addr x) { + return (x == I596_NULL) ? NULL : bus_to_virt(x); +} + +/* status bits for cmd */ +#define CMD_STAT_C 0x8000 /* CU command complete */ +#define CMD_STAT_B 0x4000 /* CU command in progress */ +#define CMD_STAT_OK 0x2000 /* CU command completed without errors */ +#define CMD_STAT_A 0x1000 /* CU command abnormally terminated */ + +struct i596_cmd { /* 8 bytes */ + unsigned short status; + unsigned short command; + phys_addr pa_next; /* va_to_pa(struct i596_cmd *next) */ +}; + +#define EOF 0x8000 +#define SIZE_MASK 0x3fff + +struct i596_tbd { + unsigned short size; + unsigned short pad; + phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */ + phys_addr pa_data; /* va_to_pa(char *data) */ + struct sk_buff *skb; +}; + +struct tx_cmd { + struct i596_cmd cmd; + phys_addr pa_tbd; /* va_to_pa(struct i596_tbd *tbd) */ + unsigned short size; + unsigned short pad; +}; + +/* status bits for rfd */ +#define RFD_STAT_C 0x8000 /* Frame reception complete */ +#define RFD_STAT_B 0x4000 /* Frame reception in progress */ +#define RFD_STAT_OK 0x2000 /* Frame received without errors */ +#define RFD_STATUS 0x1fff +#define RFD_LENGTH_ERR 0x1000 +#define RFD_CRC_ERR 0x0800 +#define RFD_ALIGN_ERR 0x0400 +#define RFD_NOBUFS_ERR 0x0200 +#define RFD_DMA_ERR 0x0100 /* DMA overrun failure to acquire system bus */ +#define RFD_SHORT_FRAME_ERR 0x0080 +#define RFD_NOEOP_ERR 0x0040 +#define RFD_TRUNC_ERR 0x0020 +#define RFD_MULTICAST 0x0002 /* 0: destination had our address + 1: destination was broadcast/multicast */ +#define RFD_COLLISION 0x0001 + +/* receive frame descriptor */ +struct i596_rfd { + unsigned short stat; + unsigned short cmd; + phys_addr pa_next; /* va_to_pa(struct i596_rfd *next) */ + phys_addr pa_rbd; /* va_to_pa(struct i596_rbd *rbd) */ + unsigned short count; + unsigned short size; + char data[1532]; +}; + +#define RBD_EL 0x8000 +#define RBD_P 0x4000 +#define RBD_SIZEMASK 0x3fff +#define RBD_EOF 0x8000 +#define RBD_F 0x4000 + +/* receive buffer descriptor */ +struct i596_rbd { + unsigned short size; + unsigned short pad; + phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */ + phys_addr pa_data; /* va_to_pa(char *data) */ + phys_addr pa_prev; /* va_to_pa(struct i596_tbd *prev) */ + + /* Driver private part */ + struct sk_buff *skb; +}; + +#define RX_RING_SIZE 64 +#define RX_SKBSIZE (ETH_FRAME_LEN+10) +#define RX_RBD_SIZE 32 + +/* System Control Block - 40 bytes */ +struct i596_scb { + u16 status; /* 0 */ + u16 command; /* 2 */ + phys_addr pa_cmd; /* 4 - va_to_pa(struct i596_cmd *cmd) */ + phys_addr pa_rfd; /* 8 - va_to_pa(struct i596_rfd *rfd) */ + u32 crc_err; /* 12 */ + u32 align_err; /* 16 */ + u32 resource_err; /* 20 */ + u32 over_err; /* 24 */ + u32 rcvdt_err; /* 28 */ + u32 short_err; /* 32 */ + u16 t_on; /* 36 */ + u16 t_off; /* 38 */ +}; + +/* Intermediate System Configuration Pointer - 8 bytes */ +struct i596_iscp { + u32 busy; /* 0 */ + phys_addr pa_scb; /* 4 - va_to_pa(struct i596_scb *scb) */ +}; + +/* System Configuration Pointer - 12 bytes */ +struct i596_scp { + u32 sysbus; /* 0 */ + u32 pad; /* 4 */ + phys_addr pa_iscp; /* 8 - va_to_pa(struct i596_iscp *iscp) */ +}; + +/* Selftest and dump results - needs 16-byte alignment */ +/* + * The size of the dump area is 304 bytes. When the dump is executed + * by the Port command an extra word will be appended to the dump area. + * The extra word is a copy of the Dump status word (containing the + * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump] + */ +struct i596_dump { + u16 dump[153]; /* (304 = 130h) + 2 bytes */ +}; + +struct i596_private { /* aligned to a 16-byte boundary */ + struct i596_scp scp; /* 0 - needs 16-byte alignment */ + struct i596_iscp iscp; /* 12 */ + struct i596_scb scb; /* 20 */ + u32 dummy; /* 60 */ + struct i596_dump dump; /* 64 - needs 16-byte alignment */ + + struct i596_cmd set_add; + char eth_addr[8]; /* directly follows set_add */ + + struct i596_cmd set_conf; + char i596_config[16]; /* directly follows set_conf */ + + struct i596_cmd tdr; + unsigned long tdr_stat; /* directly follows tdr */ + + int last_restart; + volatile struct i596_rbd *rbd_list; + volatile struct i596_rbd *rbd_tail; + volatile struct i596_rfd *rx_tail; + volatile struct i596_cmd *cmd_tail; + volatile struct i596_cmd *cmd_head; + int cmd_backlog; + unsigned long last_cmd; + struct enet_statistics stats; +}; + +static char init_setup[14] = { + 0x8E, /* length 14 bytes, prefetch on */ + 0xC8, /* default: fifo to 8, monitor off */ + 0x40, /* default: don't save bad frames (apricot.c had 0x80) */ + 0x2E, /* (default is 0x26) + No source address insertion, 8 byte preamble */ + 0x00, /* default priority and backoff */ + 0x60, /* default interframe spacing */ + 0x00, /* default slot time LSB */ + 0xf2, /* default slot time and nr of retries */ + 0x00, /* default various bits + (0: promiscuous mode, 1: broadcast disable, + 2: encoding mode, 3: transmit on no CRS, + 4: no CRC insertion, 5: CRC type, + 6: bit stuffing, 7: padding) */ + 0x00, /* default carrier sense and collision detect */ + 0x40, /* default minimum frame length */ + 0xff, /* (default is 0xff, and that is what apricot.c has; + elp486.c has 0xfb: Enable crc append in memory.) */ + 0x00, /* default: not full duplex */ + 0x7f /* (default is 0x3f) multi IA */ +}; + +static int i596_open(struct device *dev); +static int i596_start_xmit(struct sk_buff *skb, struct device *dev); +static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int i596_close(struct device *dev); +static struct enet_statistics *i596_get_stats(struct device *dev); +static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd); +static void print_eth(char *); +static void set_multicast_list(struct device *dev); + +static int +i596_timeout(struct device *dev, char *msg, int ct) { + volatile struct i596_private *lp; + int boguscnt = ct; + + lp = (struct i596_private *) dev->priv; + while (lp->scb.command) { + if (--boguscnt == 0) { + printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n", + dev->name, msg, + lp->scb.status, lp->scb.command); + return 1; + } + udelay(5); + } + return 0; +} + +static inline int +init_rx_bufs(struct device *dev, int num) { + volatile struct i596_private *lp; + struct i596_rfd *rfd; + int i; + // struct i596_rbd *rbd; + + lp = (struct i596_private *) dev->priv; + lp->scb.pa_rfd = I596_NULL; + + for (i = 0; i < num; i++) { + rfd = kkmalloc(struct i596_rfd, GFP_KERNEL); + if (rfd == NULL) + break; + + rfd->stat = 0; + rfd->pa_rbd = I596_NULL; + rfd->count = 0; + rfd->size = 1532; + if (i == 0) { + rfd->cmd = CMD_EOL; + lp->rx_tail = rfd; + } else { + rfd->cmd = 0; + } + rfd->pa_next = lp->scb.pa_rfd; + lp->scb.pa_rfd = va_to_pa(rfd); + lp->rx_tail->pa_next = lp->scb.pa_rfd; + } + +#if 0 + for (i = 0; ipad = 0; + rbd->count = 0; + rbd->skb = dev_alloc_skb(RX_SKB_SIZE); + if (!rbd->skb) { + printk("dev_alloc_skb failed"); + } + rbd->next = rfd->rbd; + if (i) { + rfd->rbd->prev = rbd; + rbd->size = RX_SKB_SIZE; + } else { + rbd->size = (RX_SKB_SIZE | RBD_EL); + lp->rbd_tail = rbd; + } + + rfd->rbd = rbd; + } else { + printk("Could not kmalloc rbd\n"); + } + } + lp->rbd_tail->next = rfd->rbd; +#endif + return (i); +} + +static inline void +remove_rx_bufs(struct device *dev) { + struct i596_private *lp; + struct i596_rfd *rfd; + + lp = (struct i596_private *) dev->priv; + lp->rx_tail->pa_next = I596_NULL; + + do { + rfd = pa_to_va(lp->scb.pa_rfd); + lp->scb.pa_rfd = rfd->pa_next; + kfree(rfd); + } while (rfd != lp->rx_tail); + + lp->rx_tail = 0; + +#if 0 + for (lp->rbd_list) { + } +#endif +} + +#define PORT_RESET 0x00 /* reset 82596 */ +#define PORT_SELFTEST 0x01 /* selftest */ +#define PORT_ALTSCP 0x02 /* alternate SCB address */ +#define PORT_DUMP 0x03 /* dump */ + +#define IOADDR 0xcb0 +#define IRQ 10 /* default IRQ - can be changed by ECU */ + +/* The 82596 requires two 16-bit write cycles for a port command */ +static inline void +PORT(phys_addr a, unsigned int cmd) { + if (a & 0xf) + printk("lp486e.c: PORT: address not aligned\n"); + outw(((a & 0xffff) | cmd), IOADDR); + outw(((a>>16) & 0xffff), IOADDR+2); +} + +static inline void +CA(void) { + outb(0, IOADDR+4); + udelay(8); +} + +static inline void +CLEAR_INT(void) { + outb(0, IOADDR+8); +} + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#if 0 +/* selftest or dump */ +static void +i596_port_do(struct device *dev, int portcmd, char *cmdname) { + volatile struct i596_private *lp = (struct i596_private *)dev->priv; + volatile u16 *outp; + int i, m; + + memset((void *)&(lp->dump), 0, sizeof(struct i596_dump)); + outp = &(lp->dump.dump[0]); + + PORT(va_to_pa(outp), portcmd); + mdelay(30); /* random, unmotivated */ + + printk("lp486e i82596 %s result:\n", cmdname); + for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--) + ; + for (i = 0; i < m; i++) { + printk(" %04x", lp->dump.dump[i]); + if (i%8 == 7) + printk("\n"); + } + printk("\n"); +} +#endif + +static int +i596_scp_setup(struct device *dev) { + volatile struct i596_private *lp = (struct i596_private *)dev->priv; + int boguscnt; + + /* Setup SCP, ISCP, SCB */ + /* + * sysbus bits: + * only a single byte is significant - here 0x44 + * 0x80: big endian mode (details depend on stepping) + * 0x40: 1 + * 0x20: interrupt pin is active low + * 0x10: lock function disabled + * 0x08: external triggering of bus throttle timers + * 0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode + * 0x01: unused + */ + lp->scp.sysbus = 0x00440000; /* linear mode */ + lp->scp.pad = 0; /* must be zero */ + lp->scp.pa_iscp = va_to_pa(&(lp->iscp)); + + /* + * The CPU sets the ISCP to 1 before it gives the first CA() + */ + lp->iscp.busy = 0x0001; + lp->iscp.pa_scb = va_to_pa(&(lp->scb)); + + lp->scb.command = 0; + lp->scb.status = 0; + lp->scb.pa_cmd = I596_NULL; + /* lp->scb.pa_rfd has been initialised already */ + + lp->last_cmd = jiffies; + lp->cmd_backlog = 0; + lp->cmd_head = NULL; + + /* + * Reset the 82596. + * We need to wait 10 systemclock cycles, and + * 5 serial clock cycles. + */ + PORT(0, PORT_RESET); /* address part ignored */ + udelay(100); + + /* + * Before the CA signal is asserted, the default SCP address + * (0x00fffff4) can be changed to a 16-byte aligned value + */ + PORT(va_to_pa(&lp->scp), PORT_ALTSCP); /* change the scp address */ + + /* + * The initialization procedure begins when a + * Channel Attention signal is asserted after a reset. + */ + CA(); + + CLEAR_INT(); + + /* + * The ISCP busy is cleared by the 82596 after the SCB base + * and offset are read. + */ + boguscnt = 100; + while (lp->iscp.busy) { + if (--boguscnt == 0) { + /* No i82596 present? */ + printk("%s: i82596 initialization timed out\n", + dev->name); + return 1; + } + udelay(5); + } + /* I find here boguscnt==100, so no delay was required. */ + + return 0; +} + +static int +init_i596(struct device *dev) { + volatile struct i596_private *lp; + + if (i596_scp_setup(dev)) + return 1; + + lp = (struct i596_private *) dev->priv; + lp->scb.command = 0; + + memcpy ((void *)lp->i596_config, init_setup, 14); + lp->set_conf.command = CmdConfigure; + i596_add_cmd(dev, (void *)&lp->set_conf); + + memcpy ((void *)lp->eth_addr, dev->dev_addr, 6); + lp->set_add.command = CmdIASetup; + i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add); + + lp->tdr.command = CmdTDR; + i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr); + + if (lp->scb.command && i596_timeout(dev, "i82596 init", 200)) + return 1; + + lp->scb.command = RX_START; + CA(); + + if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100)) + return 1; + + return 0; +} + +/* Receive a single frame */ +static inline int +i596_rx_one(struct device *dev, volatile struct i596_private *lp, + struct i596_rfd *rfd, int *frames) { + + if (rfd->stat & RFD_STAT_OK) { + /* a good frame */ + int pkt_len = (rfd->count & 0x3fff); + struct sk_buff *skb = dev_alloc_skb(pkt_len); + + (*frames)++; + + if (rfd->cmd & CMD_EOL) + printk("Received on EOL\n"); + + if (skb == NULL) { + printk ("%s: i596_rx Memory squeeze, " + "dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + return 1; + } + + skb->dev = dev; + memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len); + + skb->protocol = eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + } else { +#if 0 + printk("Frame reception error status %04x\n", + rfd->stat); +#endif + lp->stats.rx_errors++; + if (rfd->stat & RFD_COLLISION) + lp->stats.collisions++; + if (rfd->stat & RFD_SHORT_FRAME_ERR) + lp->stats.rx_length_errors++; + if (rfd->stat & RFD_DMA_ERR) + lp->stats.rx_over_errors++; + if (rfd->stat & RFD_NOBUFS_ERR) + lp->stats.rx_fifo_errors++; + if (rfd->stat & RFD_ALIGN_ERR) + lp->stats.rx_frame_errors++; + if (rfd->stat & RFD_CRC_ERR) + lp->stats.rx_crc_errors++; + if (rfd->stat & RFD_LENGTH_ERR) + lp->stats.rx_length_errors++; + } + rfd->stat = rfd->count = 0; + return 0; +} + +static int +i596_rx(struct device *dev) { + volatile struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_rfd *rfd; + int frames = 0; + + while (1) { + rfd = pa_to_va(lp->scb.pa_rfd); + if (!rfd) { + printk("i596_rx: NULL rfd?\n"); + return 0; + } +#if 1 + if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B))) + printk("SF:%p-%04x\n", rfd, rfd->stat); +#endif + if (!(rfd->stat & RFD_STAT_C)) + break; /* next one not ready */ + if (i596_rx_one(dev, lp, rfd, &frames)) + break; /* out of memory */ + rfd->cmd = CMD_EOL; + lp->rx_tail->cmd = 0; + lp->rx_tail = rfd; + lp->scb.pa_rfd = rfd->pa_next; + } + + return frames; +} + +static void +i596_cleanup_cmd(struct device *dev) { + volatile struct i596_private *lp; + struct i596_cmd *cmd; + + lp = (struct i596_private *) dev->priv; + while (lp->cmd_head) { + cmd = (struct i596_cmd *)lp->cmd_head; + + lp->cmd_head = pa_to_va(lp->cmd_head->pa_next); + lp->cmd_backlog--; + + switch ((cmd->command) & 0x7) { + case CmdTx: { + struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd; + struct i596_tbd * tx_cmd_tbd; + tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd); + + dev_kfree_skb(tx_cmd_tbd->skb); + + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + + cmd->pa_next = I596_NULL; + kfree((unsigned char *)tx_cmd); + break; + } + case CmdMulticastList: { + // unsigned short count = *((unsigned short *) (ptr + 1)); + + cmd->pa_next = I596_NULL; + kfree((unsigned char *)cmd); + break; + } + default: { + cmd->pa_next = I596_NULL; + break; + } + } + } + + if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100)) + ; + + lp->scb.pa_cmd = va_to_pa(lp->cmd_head); +} + +static inline void +i596_reset(struct device *dev, volatile struct i596_private *lp, int ioaddr) { + + if (lp->scb.command && i596_timeout(dev, "i596_reset", 100)) + ; + + dev->start = 0; + dev->tbusy = 1; + + lp->scb.command = CUC_ABORT | RX_ABORT; + CA(); + + /* wait for shutdown */ + if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400)) + ; + + i596_cleanup_cmd(dev); + i596_rx(dev); + + dev->start = 1; + dev->tbusy = 0; + /*dev_kfree_skb(skb, FREE_WRITE);*/ + dev->interrupt = 0; + init_i596(dev); +} + +static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd) { + volatile struct i596_private *lp = (struct i596_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + + cmd->status = 0; + cmd->command |= (CMD_EOL | CMD_INTR); + cmd->pa_next = I596_NULL; + + save_flags(flags); + cli(); + if (lp->cmd_head) { + lp->cmd_tail->pa_next = va_to_pa(cmd); + } else { + lp->cmd_head = cmd; + if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100)) + ; + lp->scb.pa_cmd = va_to_pa(cmd); + lp->scb.command = CUC_START; + CA(); + } + lp->cmd_tail = cmd; + lp->cmd_backlog++; + + lp->cmd_head = pa_to_va(lp->scb.pa_cmd); + restore_flags(flags); + + if (lp->cmd_backlog > 16) { + int tickssofar = jiffies - lp->last_cmd; + if (tickssofar < 25) return; + + printk("%s: command unit timed out, status resetting.\n", + dev->name); + i596_reset(dev, lp, ioaddr); + } +} + +static int +i596_open(struct device *dev) { + int i; + + if (request_irq(dev->irq, &i596_interrupt, SA_SHIRQ, dev->name, dev)) { + printk("%s: IRQ %d not free\n", dev->name, dev->irq); + return -EAGAIN; + } + +// irq2dev_map[dev->irq] = dev; + + if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE) + printk("%s: only able to allocate %d receive buffers\n", + dev->name, i); + + if (i < 4) { +// release buffers + free_irq(dev->irq, dev); +// irq2dev_map[dev->irq] = 0; + return -EAGAIN; + } + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + MOD_INC_USE_COUNT; + + init_i596(dev); + + return 0; /* Always succeed */ +} + +static int +i596_start_xmit(struct sk_buff *skb, struct device *dev) { + volatile struct i596_private *lp = (struct i596_private *)dev->priv; + int ioaddr = dev->base_addr; + struct tx_cmd *tx_cmd; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) { + return 1; + } + printk("%s: transmit timed out, status resetting.\n", + dev->name); + lp->stats.tx_errors++; + /* Try to restart the adaptor */ + if (lp->last_restart == lp->stats.tx_packets) { + printk ("Resetting board.\n"); + + /* Shutdown and restart */ + i596_reset(dev,lp, ioaddr); + } else { + /* Issue a channel attention signal */ + printk ("Kicking board.\n"); + + lp->scb.command = (CUC_START | RX_START); + CA(); /*outw(0, ioaddr+4);*/ + + lp->last_restart = lp->stats.tx_packets; + } + dev->tbusy = 0; + dev->trans_start = jiffies; + } + + /* If some higher level thinks we've missed a tx-done interrupt + we are passed NULL. n.b. dev_tint handles the cli()/sti() + itself. */ + if (skb == NULL) { + printk("What about dev_tint\n"); + /*dev_tint(dev);*/ + return 0; + } + + /* shouldn't happen */ + if (skb->len <= 0) return 0; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + } else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + dev->trans_start = jiffies; + + tx_cmd = (struct tx_cmd *) + kmalloc ((sizeof (struct tx_cmd) + + sizeof (struct i596_tbd)), GFP_ATOMIC); + if (tx_cmd == NULL) { + printk ("%s: i596_xmit Memory squeeze, dropping packet.\n", + dev->name); + lp->stats.tx_dropped++; + + dev_kfree_skb(skb); + } else { + struct i596_tbd * tx_cmd_tbd; + tx_cmd_tbd = (struct i596_tbd *) (tx_cmd+1); + tx_cmd->pa_tbd = va_to_pa(tx_cmd_tbd); + tx_cmd_tbd->pa_next = I596_NULL; + + tx_cmd->cmd.command = (CMD_FLEX | CmdTx); + + tx_cmd->pad = 0; + tx_cmd->size = 0; + tx_cmd_tbd->pad = 0; + tx_cmd_tbd->size = (EOF | length); + + tx_cmd_tbd->pa_data = va_to_pa(skb->data); + tx_cmd_tbd->skb = skb; + + if (i596_debug & LOG_SRCDST) + print_eth(skb->data); + + i596_add_cmd(dev, (struct i596_cmd *)tx_cmd); + + lp->stats.tx_packets++; + } + } + + dev->tbusy = 0; + + return 0; +} + +static void +print_eth(char *add) { + int i; + + printk ("Dest "); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i]); + printk ("\n"); + + printk ("Source"); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i+6]); + printk ("\n"); + + printk ("type %2.2X%2.2X\n", + (unsigned char) add[12], (unsigned char) add[13]); +} + +int __init +lp486e_probe(struct device *dev) { + volatile struct i596_private *lp; + unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 }; + unsigned char *bios; + int i,j; + static int probed = 0; + + if (probed) + return -ENODEV; + probed++; + + if (check_region(IOADDR, LP486E_TOTAL_SIZE)) { + printk("lp486e: IO address 0x%x in use\n", IOADDR); + return -ENODEV; + } + + /* + * Allocate working memory, 16-byte aligned + */ + dev->mem_start = (unsigned long) + kmalloc(sizeof(struct i596_private) + 0x0f, GFP_KERNEL); + if (!dev->mem_start) + return -ENOMEM; + dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0); + lp = (struct i596_private *) dev->priv; + memset((void *)lp, 0, sizeof(struct i596_private)); + + /* + * Do we really have this thing? + */ + if (i596_scp_setup(dev)) { + kfree ((void *) dev->mem_start); + return -ENODEV; + } + + request_region(IOADDR, LP486E_TOTAL_SIZE, "lp486e"); + + dev->base_addr = IOADDR; + dev->irq = IRQ; + + ether_setup(dev); + + /* + * How do we find the ethernet address? I don't know. + * One possibility is to look at the EISA configuration area + * [0xe8000-0xe9fff]. This contains the ethernet address + * but not at a fixed address - things depend on setup options. + * + * If we find no address, or the wrong address, use + * ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6 + * with the value found in the BIOS setup. + */ + bios = bus_to_virt(0xe8000); + for (j = 0; j < 0x2000; j++) { + if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) { + printk("%s: maybe address at BIOS 0x%x:", + dev->name, 0xe8000+j); + for (i = 0; i < 6; i++) { + eth_addr[i] = bios[i+j]; + printk(" %2.2X", eth_addr[i]); + } + printk("\n"); + } + } + + printk("%s: lp486e 82596 at %#3x, IRQ %d,", dev->name, IOADDR, IRQ); + for (i = 0; i < 6; i++) + printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]); + printk("\n"); + + /* The LP486E-specific entries in the device structure. */ + dev->open = &i596_open; + dev->stop = &i596_close; + dev->hard_start_xmit = &i596_start_xmit; + dev->get_stats = &i596_get_stats; + dev->set_multicast_list = &set_multicast_list; + +#if 0 + /* selftest reports 0x320925ae - don't know what that means */ + i596_port_do(dev, PORT_SELFTEST, "selftest"); + i596_port_do(dev, PORT_DUMP, "dump"); +#endif + return 0; +} + +static void inline +i596_handle_CU_completion(struct device *dev, + volatile struct i596_private *lp, + unsigned short status, + unsigned short *ack_cmdp) { + volatile struct i596_cmd *cmd; + int frames_out = 0; + int commands_done = 0; + int cmd_val; + + cmd = lp->cmd_head; + + while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) { + cmd = lp->cmd_head; + + lp->cmd_head = pa_to_va(lp->cmd_head->pa_next); + lp->cmd_backlog--; + + commands_done++; + cmd_val = cmd->command & 0x7; +#if 0 + printk("finished CU %s command (%d)\n", + CUcmdnames[cmd_val], cmd_val); +#endif + switch (cmd_val) { + case CmdTx: + { + struct tx_cmd *tx_cmd; + struct i596_tbd *tx_cmd_tbd; + + tx_cmd = (struct tx_cmd *) cmd; + tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd); + + frames_out++; + if (cmd->status & CMD_STAT_OK) { + if (i596_debug) + print_eth(pa_to_va(tx_cmd_tbd->pa_data)); + } else { + lp->stats.tx_errors++; + if (i596_debug) + printk("transmission failure:%04x\n", + cmd->status); + if (cmd->status & 0x0020) + lp->stats.collisions++; + if (!(cmd->status & 0x0040)) + lp->stats.tx_heartbeat_errors++; + if (cmd->status & 0x0400) + lp->stats.tx_carrier_errors++; + if (cmd->status & 0x0800) + lp->stats.collisions++; + if (cmd->status & 0x1000) + lp->stats.tx_aborted_errors++; + } + dev_kfree_skb(tx_cmd_tbd->skb); + + cmd->pa_next = I596_NULL; + kfree((unsigned char *)tx_cmd); + break; + } + + case CmdMulticastList: + cmd->pa_next = I596_NULL; + kfree((unsigned char *)cmd); + break; + + case CmdTDR: + { + unsigned long status = *((unsigned long *) (cmd + 1)); + if (status & 0x8000) { + if (i596_debug) + printk("%s: link ok.\n", dev->name); + } else { + if (status & 0x4000) + printk("%s: Transceiver problem.\n", + dev->name); + if (status & 0x2000) + printk("%s: Termination problem.\n", + dev->name); + if (status & 0x1000) + printk("%s: Short circuit.\n", + dev->name); + printk("%s: Time %ld.\n", + dev->name, status & 0x07ff); + } + } + default: + cmd->pa_next = I596_NULL; + lp->last_cmd = jiffies; + + } + } + + cmd = lp->cmd_head; + while (cmd && (cmd != lp->cmd_tail)) { + cmd->command &= 0x1fff; + cmd = pa_to_va(cmd->pa_next); + } + + if (lp->cmd_head && dev->start) + *ack_cmdp |= CUC_START; + lp->scb.pa_cmd = va_to_pa(lp->cmd_head); +} + +static void +i596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { + struct device *dev = (struct device *) dev_instance; + volatile struct i596_private *lp; + unsigned short status, ack_cmd = 0; + int frames_in = 0; + + if (dev == NULL) { + printk ("i596_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + lp = (struct i596_private *) dev->priv; + + /* + * The 82596 examines the command, performs the required action, + * and then clears the SCB command word. + */ + if (lp->scb.command && i596_timeout(dev, "interrupt", 40)) + ; + + /* + * The status word indicates the status of the 82596. + * It is modified only by the 82596. + * + * [So, we must not clear it. I find often status 0xffff, + * which is not one of the values allowed by the docs.] + */ + status = lp->scb.status; +#if 0 + if (i596_debug) { + printk("%s: i596 interrupt, ", dev->name); + i596_out_status(status); + } +#endif + /* Impossible, but it happens - perhaps when we get + a receive interrupt but scb.pa_rfd is I596_NULL. */ + if (status == 0xffff) { + printk("%s: i596_interrupt: got status 0xffff\n", dev->name); + goto out; + } + + ack_cmd = (status & STAT_ACK); + + if (status & (STAT_CX | STAT_CNA)) + i596_handle_CU_completion(dev, lp, status, &ack_cmd); + + if (status & (STAT_FR | STAT_RNR)) { + /* Restart the receive unit when it got inactive somehow */ + if ((status & STAT_RNR) && dev->start) + ack_cmd |= RX_START; + + if (status & STAT_FR) { + frames_in = i596_rx(dev); + if (!frames_in) + printk("receive frame reported, but no frames\n"); + } + } + + /* acknowledge the interrupt */ + /* + if ((lp->scb.pa_cmd != I596_NULL) && dev->start) + ack_cmd |= CUC_START; + */ + + if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100)) + ; + + lp->scb.command = ack_cmd; + + CLEAR_INT(); + CA(); + + out: + dev->interrupt = 0; + return; +} + +static int i596_close(struct device *dev) { + volatile struct i596_private *lp = (struct i596_private *)dev->priv; + + dev->start = 0; + dev->tbusy = 1; + + if (i596_debug) + printk("%s: Shutting down ethercard, status was %4.4x.\n", + dev->name, lp->scb.status); + + lp->scb.command = (CUC_ABORT | RX_ABORT); + CA(); + + i596_cleanup_cmd(dev); + + if (lp->scb.command && i596_timeout(dev, "i596_close", 200)) + ; + + free_irq(dev->irq, dev); + remove_rx_bufs(dev); + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics * i596_get_stats(struct device *dev) { + struct i596_private *lp = (struct i596_private *)dev->priv; + + return &lp->stats; +} + +/* +* Set or clear the multicast filter for this adaptor. +*/ + +static void set_multicast_list(struct device *dev) { + volatile struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_cmd *cmd; + + if (i596_debug > 1) + printk ("%s: set multicast list %d\n", + dev->name, dev->mc_count); + + if (dev->mc_count > 0) { + struct dev_mc_list *dmi; + char *cp; + cmd = (struct i596_cmd *) + kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, + GFP_ATOMIC); + if (cmd == NULL) { + printk ("%s: set_multicast Memory squeeze.\n", + dev->name); + return; + } + cmd->command = CmdMulticastList; + *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; + cp = ((char *)(cmd + 1))+2; + for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { + memcpy(cp, dmi,6); + cp += 6; + } + if (i596_debug & LOG_SRCDST) + print_eth (((char *)(cmd + 1)) + 2); + i596_add_cmd(dev, cmd); + } else { + if (lp->set_conf.pa_next != I596_NULL) { + return; + } + if (dev->mc_count == 0 && + !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { + if (dev->flags & IFF_ALLMULTI) + dev->flags |= IFF_PROMISC; + lp->i596_config[8] &= ~0x01; + } else { + lp->i596_config[8] |= 0x01; + } + + i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf); + } +} + +#ifdef HAVE_DEVLIST +static unsigned int lp486e_portlist[] = {0xcb0, 0}; +struct netdev_entry lp486e_drv = { + "lp486e", + lp486e_probe, + LP486E_TOTAL_SIZE, + lp486e_portlist +}; +#endif + +#ifdef MODULE +MODULE_AUTHOR("Ard van Breemen "); +MODULE_DESCRIPTION("Intel Panther onboard i82596 driver"); +MODULE_PARM(debug, "i"); +//MODULE_PARM(max_interrupt_work, "i"); +//MODULE_PARM(reverse_probe, "i"); +//MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +static char devicename[9] = { 0, }; +static struct device dev_lp486e = { + devicename, /* device name inserted by /linux/drivers/net/net_init.c */ + 0, 0, 0, 0, + IOADDR, IRQ, + 0, 0, 0, NULL, NULL +}; + +static int full_duplex; +static int options; +static int io = IOADDR; +static int irq = IRQ; + +int init_module(void) { + struct device *dev = &dev_lp486e; + dev->name = devicename; + dev->irq = irq; + dev->base_addr = io; + dev->init = lp486e_probe; + if (register_netdev(dev) != 0) { + return -EIO; + } + full_duplex = 0; + options = 0; + return 0; +} + +void cleanup_module(void) { + unregister_netdev(&dev_lp486e); + kfree((void *)dev_lp486e.mem_start); + dev_lp486e.priv = NULL; + /* If we don't do this, we can't re-insmod it later. */ + release_region(dev_lp486e.base_addr, LP486E_TOTAL_SIZE); +} +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.2.18/drivers/net/ne2k-pci.c Sun Mar 25 11:12:52 2001 +++ linux/drivers/net/ne2k-pci.c Sun Mar 25 11:37:34 2001 @@ -12,19 +12,30 @@ This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + Issues remaining: People are making PCI ne2000 clones! Oh the horror, the horror... + Limited full-duplex support. - Issues remaining: - No full-duplex support. + ChangeLog: + + 12/15/2000 Merged Scyld v1.02 into 2.2.18 + J.A. Magallon */ -/* Our copyright info must remain in the binary. */ -static const char *version = -"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n"; +/* These identify the driver base version and may not be removed. */ +static const char* version = +"ne2k-pci.c: v1.02 for Linux 2.2, 10/19/2000, D. Becker/P. Gortmaker," +" http://www.scyld.com/network/ne2k-pci.html"; #include #include @@ -49,7 +60,18 @@ #endif /* Set statically or when loading the driver module. */ -static int debug = 1; +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +/* More are supported, limit only on options */ +#define MAX_UNITS 6 +/* Used to pass the full-duplex flag, etc. */ +static int full_duplex[MAX_UNITS] = {0, }; +static int options[MAX_UNITS] = {0, }; + +MODULE_AUTHOR("Donald Becker / Paul Gortmaker"); +MODULE_DESCRIPTION("PCI NE2000 clone driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); /* Some defines that people can play with if so inclined. */ @@ -62,12 +84,13 @@ /* Do we have a non std. amount of memory? (in units of 256 byte pages) */ /* #define PACKETBUF_MEMSIZE 0x40 */ -#define ne2k_flags reg0 /* Rename an existing field to store flags! */ - -/* Only the low 8 bits are usable for non-init-time flags! */ +/* Flags. We rename an existing ei_status field to store flags! */ +/* Thus only the low 8 bits are usable for non-init-time flags. */ +#define ne2k_flags reg0 enum { - HOLTEK_FDX=1, /* Full duplex -> set 0x80 at offset 0x20. */ - ONLY_16BIT_IO=2, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */ + ONLY_16BIT_IO=8, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */ + FORCE_FDX=0x20, /* User override. */ + REALTEK_FDX=0x40, HOLTEK_FDX=0x80, STOP_PG_0x60=0x100, }; @@ -79,18 +102,17 @@ int flags; } pci_clone_list[] __initdata = { - {0x10ec, 0x8029, "RealTek RTL-8029", 0}, - {0x1050, 0x0940, "Winbond 89C940", 0}, - {0x11f6, 0x1401, "Compex RL2000", 0}, - {0x8e2e, 0x3000, "KTI ET32P2", 0}, - {0x4a14, 0x5000, "NetVin NV5000SC", 0}, - {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO}, - {0x10bd, 0x0e34, "SureCom NE34", 0}, - {0x1050, 0x5a5a, "Winbond", 0}, - {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, - {0x12c3, 0x5598, "Holtek HT80229", - ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, - {0,} +{0x10ec, 0x8029, "RealTek RTL-8029", REALTEK_FDX}, +{0x1050, 0x0940, "Winbond 89C940", 0}, +{0x1050, 0x5a5a, "Winbond w89c940", 0}, +{0x8e2e, 0x3000, "KTI ET32P2", 0}, +{0x4a14, 0x5000, "NetVin NV5000SC", 0}, +{0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO}, +{0x10bd, 0x0e34, "SureCom NE34", 0}, +{0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO|HOLTEK_FDX}, +{0x12c3, 0x5598, "Holtek HT80229", ONLY_32BIT_IO|HOLTEK_FDX|STOP_PG_0x60 }, +{0x11f6, 0x1401, "Compex RL2000", 0}, +{0,} }; /* ---- No user-serviceable parts below ---- */ @@ -119,7 +141,7 @@ static void ne2k_pci_block_output(struct device *dev, const int count, const unsigned char *buf, const int start_page); - + /* No room in the standard 8390 structure for extra info we need. */ struct ne2k_pci_card { @@ -136,8 +158,7 @@ init_module(void) { /* We must emit version information. */ - if (debug) - printk(KERN_INFO "%s", version); + printk(KERN_INFO "%s\n", version); if (ne2k_pci_probe(0)) { printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n"); @@ -220,7 +241,7 @@ { static unsigned version_printed = 0; if (version_printed++ == 0) - printk(KERN_INFO "%s", version); + printk(KERN_INFO "%s\n", version); } #endif @@ -263,8 +284,8 @@ return cards_found ? 0 : -ENODEV; } -__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, long ioaddr, int irq, - int chip_idx)) +__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, + long ioaddr, int irq, int chip_idx)) { int i; unsigned char SA_prom[32]; @@ -291,6 +312,8 @@ dev = init_etherdev(dev, 0); + if (!dev) return 0; + /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; @@ -342,7 +365,7 @@ /* Note: all PCI cards have at least 16 bit access, so we don't have to check for 8 bit cards. Most cards permit 32 bit access. */ if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) { - for (i = 0; i < 4 ; i++) + for (i = 0; i < 8 ; i++) ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT)); } else for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++) @@ -379,6 +402,10 @@ ei_status.stop_page = stop_page; ei_status.word16 = 1; ei_status.ne2k_flags = pci_clone_list[chip_idx].flags; + if (chip_idx < MAX_UNITS) { + if (full_duplex[chip_idx] || (options[chip_idx] & FORCE_FDX)) + ei_status.ne2k_flags |= FORCE_FDX; + } ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE @@ -401,8 +428,17 @@ { if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) return -EAGAIN; - ei_open(dev); MOD_INC_USE_COUNT; + /* Set full duplex for the chips that we know about. */ + if (ei_status.ne2k_flags & FORCE_FDX) { + long ioaddr = dev->base_addr; + if (ei_status.ne2k_flags & REALTEK_FDX) { + outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */ + outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20); + } else if (ei_status.ne2k_flags & HOLTEK_FDX) + outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20); + } + ei_open(dev); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.2.18/drivers/net/sis900.c Sun Mar 25 11:28:26 2001 +++ linux/drivers/net/sis900.c Sun Mar 25 11:37:34 2001 @@ -1,6 +1,6 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.06.05 Aug 24 2000 + Revision: 1.06.07 Jan. 8 2001 Modified from the driver which is originally written by Donald Becker. @@ -18,6 +18,8 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.06.07 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support + Rev 1.06.06 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support Rev 1.06.05 Aug. 22 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E equalier workaroung rule Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed @@ -51,7 +53,7 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.06.05 08/24/00\n"; +"sis900.c: v1.06.07 01/08/01\n"; static int max_interrupt_work = 20; static int multicast_filter_limit = 128; @@ -82,6 +84,8 @@ static void sis900_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex); static void amd79c901_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex); +static void ics1893_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex); +static void rtl8201_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex); static struct mii_chip_info { const char * name; @@ -93,6 +97,8 @@ {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode}, {"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9, amd79c901_read_mode}, {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, amd79c901_read_mode}, + {"ICS 1893 Integrated PHYceiver" , 0x0015, 0xf441,ics1893_read_mode}, + {"RTL 8201 10/100Mbps Phyceiver" , 0x0000, 0x8201,rtl8201_read_mode}, {0,}, }; @@ -299,12 +305,10 @@ return NULL; pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_REV) + if (revision == SIS630E_REV || revision == SIS630EA1_REV) ret = sis630e_get_mac_addr(pci_dev, net_dev); - else if (revision == SIS630EA1_REV) { + else if (revision == SIS630S_REV) ret = sis630e_get_mac_addr(pci_dev, net_dev); - printk(KERN_INFO "using 630ea1\n"); - } else ret = sis900_get_mac_addr(pci_dev, net_dev); @@ -381,7 +385,8 @@ /* search our mii table for the current mii */ for (i = 0; mii_chip_table[i].phy_id1; i++) - if (phy_id0 == mii_chip_table[i].phy_id0) { + if (phy_id0 == mii_chip_table[i].phy_id0 && + phy_id1 == mii_chip_table[i].phy_id1) { struct mii_phy * mii_phy; printk(KERN_INFO @@ -956,6 +961,71 @@ printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); } } +/* ICS1893 PHY use Quick Poll Detailed Status Register to get its status */ +static void ics1893_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex) +{ + int i = 0; + u32 status; + + /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */ + for (i = 0; i < 2; i++) + status = mdio_read(net_dev, phy_addr, MII_QPDSTS); + + if (status & MII_STSICS_SPD) + *speed = HW_SPEED_100_MBPS; + else + *speed = HW_SPEED_10_MBPS; + + if (status & MII_STSICS_DPLX) + *duplex = FDX_CAPABLE_FULL_SELECTED; + else + *duplex = FDX_CAPABLE_HALF_SELECTED; + + if (status & MII_STSICS_LINKSTS) + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + else + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); +} + +static void rtl8201_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex) +{ + u32 status; + + status = mdio_read(net_dev, phy_addr, MII_STATUS); + + if (status & MII_STAT_CAN_TX_FDX) { + *speed = HW_SPEED_100_MBPS; + *duplex = FDX_CAPABLE_FULL_SELECTED; + } + else if (status & MII_STAT_CAN_TX) { + *speed = HW_SPEED_100_MBPS; + *duplex = FDX_CAPABLE_HALF_SELECTED; + } + else if (status & MII_STAT_CAN_T_FDX) { + *speed = HW_SPEED_10_MBPS; + *duplex = FDX_CAPABLE_FULL_SELECTED; + } + else if (status & MII_STAT_CAN_T) { + *speed = HW_SPEED_10_MBPS; + *duplex = FDX_CAPABLE_HALF_SELECTED; + } + + if (status & MII_STAT_LINK) + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + else + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); +} + static void sis900_tx_timeout(struct device *net_dev) { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/sis900.h linux/drivers/net/sis900.h --- v2.2.18/drivers/net/sis900.h Sun Mar 25 11:28:26 2001 +++ linux/drivers/net/sis900.h Sun Mar 25 11:37:34 2001 @@ -168,6 +168,12 @@ MII_MASK = 0x0013, MII_RESV = 0x0014 }; +/* mii registers specific to ICS 1893 */ +enum ics_mii_registers { + MII_EXTCTRL = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012, + MII_EXTCTRL2 = 0x0013 +}; + /* mii registers specific to AMD 79C901 */ enum amd_mii_registers { MII_STATUS_SUMMARY = 0x0018 @@ -212,13 +218,19 @@ MII_STSOUT_SPD = 0x0080, MII_STSOUT_DPLX = 0x0040 }; +enum mii_stsics_register_bits { + MII_STSICS_SPD = 0x8000, MII_STSICS_DPLX = 0x4000, + MII_STSICS_LINKSTS = 0x0001 +}; + enum mii_stssum_register_bits { MII_STSSUM_LINK = 0x0008, MII_STSSUM_DPLX = 0x0004, MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD = 0x0001 }; enum sis630_revision_id { - SIS630E_REV = 0x81, SIS630EA1_REV = 0x83 + SIS630E_REV = 0x81, SIS630EA1_REV = 0x83, + SIS630S_REV = 0x82 }; #define FDX_CAPABLE_DUPLEX_UNKNOWN 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.2.18/drivers/net/slhc.c Sun Mar 25 11:12:49 2001 +++ linux/drivers/net/slhc.c Sun Mar 25 11:37:35 2001 @@ -82,8 +82,6 @@ #include #include -int last_retran; - static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); @@ -257,8 +255,7 @@ ip = (struct iphdr *) icp; /* Bail if this packet isn't TCP, or is an IP fragment */ - if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || - (ip->frag_off & 32)){ + if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { /* Send as regular IP */ if(ip->protocol != IPPROTO_TCP) comp->sls_o_nontcp++; @@ -352,10 +349,9 @@ */ oth = &cs->cs_tcp; - if(last_retran - || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos - || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64) + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) || ip->ttl != cs->cs_ip.ttl || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.2.18/drivers/net/starfire.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/net/starfire.c Sun Mar 25 12:45:41 2001 @@ -0,0 +1,1854 @@ +/* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */ +/* + Written 1998-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support and updates available at + http://www.scyld.com/network/starfire.html + + ----------------------------------------------------------- + + Linux kernel-specific changes: + + LK1.1.1 (jgarzik): + - Use PCI driver interface + - Fix MOD_xxx races + - softnet fixups + + LK1.1.2 (jgarzik): + - Merge Becker version 0.15 + + LK1.1.3 (Andrew Morton) + - Timer cleanups + + LK1.1.4 (jgarzik): + - Merge Becker version 1.03 + + LK1.2.1 (Ion Badulescu ) + - Support hardware Rx/Tx checksumming + - Use the GFP firmware taken from Adaptec's Netware driver + + LK1.2.2 (Ion Badulescu) + - Backported to 2.2.x + + LK1.2.3 (Ion Badulescu) + - Fix the flaky mdio interface + - More compat clean-ups + + LK1.2.4 (Ion Badulescu) + - More 2.2.x initialization fixes + + LK1.2.5 (Ion Badulescu) + - Several fixes from Manfred Spraul + + LK1.2.6 (Ion Badulescu) + - Fixed ifup/ifdown/ifup problem in 2.4.x + + LK1.2.7 (Ion Badulescu) + - Removed unused code + - Made more functions static and __init + + LK1.2.8 (Ion Badulescu) + - Quell bogus error messages, inform about the Tx threshold + - Removed #ifdef CONFIG_PCI, this driver is PCI only + +TODO: + - implement tx_timeout() properly + - support ethtool +*/ + +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"starfire.c:v1.03 7/26/2000 Written by Donald Becker \n"; +static const char version2[] = +" Updates and info at http://www.scyld.com/network/starfire.html\n"; + +static const char version3[] = +" (unofficial 2.2.x kernel port, version 1.2.8, March 7, 2001)\n"; + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ + +/* + * Adaptec's license for their Novell drivers (which is where I got the + * firmware files) does not allow to redistribute them. Thus, we can't + * include them with this driver. + * + * However, an end-user is allowed to download and use them, after + * converting them to C header files using starfire_firmware.pl. + * Once that's done, the #undef must be changed into a #define + * for this driver to really use the firmware. Note that Rx/Tx + * hardware TCP checksumming is not possible without the firmware. + * + * I'm currently [Feb 2001] talking to Adaptec about this redistribution + * issue. Stay tuned... + */ +#undef HAS_FIRMWARE +/* + * The current frame processor firmware fails to checksum a fragment + * of length 1. If and when this is fixed, the #define below can be removed. + */ +#define HAS_BROKEN_FIRMWARE + +/* Used for tuning interrupt latency vs. overhead. */ +static int interrupt_mitigation = 0x0; + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +static int max_interrupt_work = 20; +static int mtu = 0; +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + The Starfire has a 512 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +/* + * Set the copy breakpoint for the copy-only-tiny-frames scheme. + * Setting to > 1518 effectively disables this feature. + * + * NOTE: + * The ia64 doesn't allow for unaligned loads even of integers being + * misaligned on a 2 byte boundary. Thus always force copying of + * packets as the starfire doesn't allow for misaligned DMAs ;-( + * 23/10/2000 - Jes + * + * Neither does the Alpha. -Ion + */ +#if defined(__ia64__) || defined(__alpha__) +static int rx_copybreak = PKT_BUF_SZ; +#else +static int rx_copybreak = 0; +#endif + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' exist for driver interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* The "native" ring sizes are either 256 or 2048. + However in some modes a descriptor may be marked to wrap the ring earlier. + The driver allocates a single page for each descriptor ring, constraining + the maximum size in an architecture-dependent way. +*/ +#define RX_RING_SIZE 256 +#define TX_RING_SIZE 32 +/* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */ +#define DONE_Q_SIZE 1024 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define skb_first_frag_len(skb) (skb->len) + +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +#ifdef HAS_FIRMWARE +#include "starfire_firmware.h" +#endif /* HAS_FIRMWARE */ + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(interrupt_mitigation, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is for the Adaptec 6915 "Starfire" 64 bit PCI Ethernet adapter. + +II. Board-specific settings + +III. Driver operation + +IIIa. Ring buffers + +The Starfire hardware uses multiple fixed-size descriptor queues/rings. The +ring sizes are set fixed by the hardware, but may optionally be wrapped +earlier by the END bit in the descriptor. +This driver uses that hardware queue size for the Rx ring, where a large +number of entries has no ill effect beyond increases the potential backlog. +The Tx ring is wrapped with the END bit, since a large hardware Tx queue +disables the queue layer priority ordering and we have no mechanism to +utilize the hardware two-level priority queue. When modifying the +RX/TX_RING_SIZE pay close attention to page sizes and the ring-empty warning +levels. + +IIIb/c. Transmit/Receive Structure + +See the Adaptec manual for the many possible structures, and options for +each structure. There are far too many to document here. + +For transmit this driver uses type 0/1 transmit descriptors (depending +on the presence of the zerocopy patches), and relies on automatic +minimum-length padding. It does not use the completion queue +consumer index, but instead checks for non-zero status entries. + +For receive this driver uses type 0 receive descriptors. The driver +allocates full frame size skbuffs for the Rx ring buffers, so all frames +should fit in a single descriptor. The driver does not use the completion +queue consumer index, but instead checks for non-zero status entries. + +When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuff +is allocated and the frame is copied to the new skbuff. When the incoming +frame is larger, the skbuff is passed directly up the protocol stack. +Buffers consumed this way are replaced by newly allocated skbuffs in a later +phase of receive. + +A notable aspect of operation is that unaligned buffers are not permitted by +the Starfire hardware. The IP header at offset 14 in an ethernet frame thus +isn't longword aligned, which may cause problems on some machine +e.g. Alphas and IA64. For these architectures, the driver is forced to copy +the frame into a new skbuff unconditionally. Copied frames are put into the +skbuff at an offset of "+2", thus 16-byte aligning the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +IVb. References + +The Adaptec Starfire manuals, available only from Adaptec. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html + +IVc. Errata + +*/ + + + +/* 2.2.x compatibility code */ +#if LINUX_VERSION_CODE < 0x20300 +#include + +static LIST_HEAD(pci_drivers); + +struct pci_driver_mapping { + struct pci_dev *dev; + struct pci_driver *drv; + void *driver_data; +}; + +struct pci_device_id { + unsigned int vendor, device; + unsigned int subvendor, subdevice; + unsigned int class, class_mask; + unsigned long driver_data; +}; + +struct pci_driver { + struct list_head node; + struct pci_dev *dev; + char *name; + const struct pci_device_id *id_table; /* NULL if wants all devices */ + int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ + void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ + void (*suspend)(struct pci_dev *dev); /* Device suspended */ + void (*resume)(struct pci_dev *dev); /* Device woken up */ +}; + +#define PCI_MAX_MAPPINGS 16 +static struct pci_driver_mapping drvmap [PCI_MAX_MAPPINGS] = { { NULL, } , }; + +#define __devinit __init +#define __devinitdata __initdata +#define __devexit +#define MODULE_DEVICE_TABLE(foo,bar) +#define SET_MODULE_OWNER(dev) +#define COMPAT_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define COMPAT_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#define PCI_ANY_ID (~0) +#define IORESOURCE_MEM 2 +#define PCI_DMA_FROMDEVICE 0 +#define PCI_DMA_TODEVICE 0 + +#define request_mem_region(addr, size, name) ((void *)1) +#define release_mem_region(addr, size) +#define del_timer_sync(timer) del_timer(timer) + +static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *virt_ptr; + + virt_ptr = kmalloc(size, GFP_KERNEL); + *dma_handle = virt_to_bus(virt_ptr); + return virt_ptr; +} +#define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr) +#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) +#define pci_unmap_single(cookie, address, size, dir) +#define pci_dma_sync_single(cookie, address, size, dir) +#undef pci_resource_flags +#define pci_resource_flags(dev, i) \ + ((dev->base_address[i] & IORESOURCE_IO) ? IORESOURCE_IO : IORESOURCE_MEM) + +static void * pci_get_drvdata (struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_MAX_MAPPINGS; i++) + if (drvmap[i].dev == dev) + return drvmap[i].driver_data; + + return NULL; +} + +static void pci_set_drvdata (struct pci_dev *dev, void *driver_data) +{ + int i; + + for (i = 0; i < PCI_MAX_MAPPINGS; i++) + if (drvmap[i].dev == dev) { + drvmap[i].driver_data = driver_data; + return; + } +} + +static const struct pci_device_id * __init +pci_compat_match_device(const struct pci_device_id *ids, struct pci_dev *dev) +{ + u16 subsystem_vendor, subsystem_device; + + pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); + pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subsystem_device); + + while (ids->vendor || ids->subvendor || ids->class_mask) { + if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) && + (ids->device == PCI_ANY_ID || ids->device == dev->device) && + (ids->subvendor == PCI_ANY_ID || ids->subvendor == subsystem_vendor) && + (ids->subdevice == PCI_ANY_ID || ids->subdevice == subsystem_device) && + !((ids->class ^ dev->class) & ids->class_mask)) + return ids; + ids++; + } + return NULL; +} + +static int __init +pci_announce_device(struct pci_driver *drv, struct pci_dev *dev) +{ + const struct pci_device_id *id; + int found, i; + + if (drv->id_table) { + id = pci_compat_match_device(drv->id_table, dev); + if (!id) + return 0; + } else + id = NULL; + + found = 0; + for (i = 0; i < PCI_MAX_MAPPINGS; i++) + if (!drvmap[i].dev) { + drvmap[i].dev = dev; + drvmap[i].drv = drv; + found = 1; + break; + } + + if (!found) + return 0; + + if (drv->probe(dev, id) >= 0) + return 1; + + /* clean up */ + drvmap[i].dev = NULL; + return 0; +} + +static int __init +pci_register_driver(struct pci_driver *drv) +{ + struct pci_dev *dev; + int count = 0, found, i; + list_add_tail(&drv->node, &pci_drivers); + for (dev = pci_devices; dev; dev = dev->next) { + found = 0; + for (i = 0; i < PCI_MAX_MAPPINGS && !found; i++) + if (drvmap[i].dev == dev) + found = 1; + if (!found) + count += pci_announce_device(drv, dev); + } + return count; +} + +static void +pci_unregister_driver(struct pci_driver *drv) +{ + struct pci_dev *dev; + int i, found; + list_del(&drv->node); + for (dev = pci_devices; dev; dev = dev->next) { + found = 0; + for (i = 0; i < PCI_MAX_MAPPINGS; i++) + if (drvmap[i].dev == dev) { + found = 1; + break; + } + if (found) { + if (drv->remove) + drv->remove(dev); + drvmap[i].dev = NULL; + } + } +} + +static inline int pci_module_init(struct pci_driver *drv) +{ + if (pci_register_driver(drv)) + return 0; + return -ENODEV; +} + +static struct pci_driver starfire_driver; + +int __init starfire_probe(struct net_device *dev) +{ + static int __initdata probed = 0; + + if (probed) + return -ENODEV; + probed++; + + return pci_module_init(&starfire_driver); +} + +#define init_tx_timer(dev, func, timeout) +#define kick_tx_timer(dev, func, timeout) \ + if (netif_queue_stopped(dev)) { \ + /* If this happens network layer tells us we're broken. */ \ + if (jiffies - dev->trans_start > timeout) \ + func(dev); \ + } + +#define netif_start_if(dev) dev->start = 1 +#define netif_stop_if(dev) dev->start = 0 + +#else /* LINUX_VERSION_CODE > 0x20300 */ + +#define COMPAT_MOD_INC_USE_COUNT +#define COMPAT_MOD_DEC_USE_COUNT + +#define init_tx_timer(dev, func, timeout) \ + dev->tx_timeout = func; \ + dev->watchdog_timeo = timeout; +#define kick_tx_timer(dev, func, timeout) + +#define netif_start_if(dev) +#define netif_stop_if(dev) + +#endif /* LINUX_VERSION_CODE > 0x20300 */ +/* end of compatibility code */ + + +enum chip_capability_flags {CanHaveMII=1, }; +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0) +#define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ + +#if 0 +#define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */ +#endif + +#define HAS_IP_COPYSUM 1 + +enum chipset { + CH_6915 = 0, +}; + +static struct pci_device_id starfire_pci_tbl[] __devinitdata = { + { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); + +/* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */ +static struct chip_info { + const char *name; + int io_size; + int drv_flags; +} netdrv_tbl[] __devinitdata = { + { "Adaptec Starfire 6915", MEM_ADDR_SZ, CanHaveMII }, +}; + + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. The name can only partially document the semantics and make + the driver longer and more difficult to read. + In general, only the important configuration values or bits changed + multiple times should be defined symbolically. +*/ +enum register_offsets { + PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074, + IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088, + MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000, + TxDescCtrl=0x50090, + TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */ + TxRingHiAddr=0x5009C, /* 64 bit address extension. */ + TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4, + TxThreshold=0x500B0, + CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8, + RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0, + CompletionQConsumerIdx=0x500C4, RxDMACtrl=0x500D0, + RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0, + RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4, + TxMode=0x55000, TxGfpMem=0x58000, RxGfpMem=0x5a000, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrLinkChange=0xf0000000, IntrStatsMax=0x08000000, + IntrAbnormalSummary=0x02000000, IntrGeneralTimer=0x01000000, + IntrSoftware=0x800000, IntrRxComplQ1Low=0x400000, + IntrTxComplQLow=0x200000, IntrPCI=0x100000, + IntrDMAErr=0x080000, IntrTxDataLow=0x040000, + IntrRxComplQ2Low=0x020000, IntrRxDescQ1Low=0x010000, + IntrNormalSummary=0x8000, IntrTxDone=0x4000, + IntrTxDMADone=0x2000, IntrTxEmpty=0x1000, + IntrEarlyRxQ2=0x0800, IntrEarlyRxQ1=0x0400, + IntrRxQ2Done=0x0200, IntrRxQ1Done=0x0100, + IntrRxGFPDead=0x80, IntrRxDescQ2Low=0x40, + IntrNoTxCsum=0x20, IntrTxBadID=0x10, + IntrHiPriTxBadID=0x08, IntrRxGfp=0x04, + IntrTxGfp=0x02, IntrPCIPad=0x01, + /* not quite bits */ + IntrRxDone=IntrRxQ2Done | IntrRxQ1Done, + IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low, + IntrNormalMask=0xf0, IntrAbnormalMask=0x3f0e, +}; + +/* Bits in the RxFilterMode register. */ +enum rx_mode_bits { + AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01, + AcceptMulticast=0x10, AcceptMyPhys=0xE040, +}; + +/* Bits in the TxDescCtrl register. */ +enum tx_ctrl_bits { + TxDescSpaceUnlim=0x00, TxDescSpace32=0x10, TxDescSpace64=0x20, + TxDescSpace128=0x30, TxDescSpace256=0x40, + TxDescType0=0x00, TxDescType1=0x01, TxDescType2=0x02, + TxDescType3=0x03, TxDescType4=0x04, + TxNoDMACompletion=0x08, TxDescQ64bit=0x80, + TxHiPriFIFOThreshShift=24, TxPadLenShift=16, + TxDMABurstSizeShift=8, +}; + +/* Bits in the RxDescQCtrl register. */ +enum rx_ctrl_bits { + RxBufferLenShift=16, RxMinDescrThreshShift=0, + RxPrefetchMode=0x8000, Rx2048QEntries=0x4000, + RxVariableQ=0x2000, RxDesc64bit=0x1000, + RxDescQAddr64bit=0x0100, + RxDescSpace4=0x000, RxDescSpace8=0x100, + RxDescSpace16=0x200, RxDescSpace32=0x300, + RxDescSpace64=0x400, RxDescSpace128=0x500, + RxConsumerWrEn=0x80, +}; + +/* Bits in the RxCompletionAddr register */ +enum rx_compl_bits { + RxComplQAddr64bit=0x80, TxComplProducerWrEn=0x40, + RxComplType0=0x00, RxComplType1=0x10, + RxComplType2=0x20, RxComplType3=0x30, + RxComplThreshShift=0, +}; + +/* The Rx and Tx buffer descriptors. */ +struct starfire_rx_desc { + u32 rxaddr; /* Optionally 64 bits. */ +}; +enum rx_desc_bits { + RxDescValid=1, RxDescEndRing=2, +}; + +/* Completion queue entry. + You must update the page allocation, init_ring and the shift count in rx() + if using a larger format. */ +#ifdef HAS_FIRMWARE +#define csum_rx_status +#endif /* HAS_FIRMWARE */ +struct rx_done_desc { + u32 status; /* Low 16 bits is length. */ +#ifdef csum_rx_status + u32 status2; /* Low 16 bits is csum */ +#endif /* csum_rx_status */ +#ifdef full_rx_status + u32 status2; + u16 vlanid; + u16 csum; /* partial checksum */ + u32 timestamp; +#endif /* full_rx_status */ +}; +enum rx_done_bits { + RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000, +}; + +/* Type 1 Tx descriptor. */ +struct starfire_tx_desc { + u32 status; /* Upper bits are status, lower 16 length. */ + u32 first_addr; +}; +enum tx_desc_bits { + TxDescID=0xB0000000, + TxCRCEn=0x01000000, TxDescIntr=0x08000000, + TxRingWrap=0x04000000, TxCalTCP=0x02000000, +}; +struct tx_done_report { + u32 status; /* timestamp, index. */ +#if 0 + u32 intrstatus; /* interrupt status */ +#endif +}; + +struct rx_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; +struct tx_ring_info { + struct sk_buff *skb; + dma_addr_t first_mapping; +}; + +#define MII_CNT 2 +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct starfire_rx_desc *rx_ring; + struct starfire_tx_desc *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + /* The addresses of rx/tx-in-place skbuffs. */ + struct rx_ring_info rx_info[RX_RING_SIZE]; + struct tx_ring_info tx_info[TX_RING_SIZE]; + /* Pointers to completion queues (full pages). I should cache line pad..*/ + u8 pad0[100]; + struct rx_done_desc *rx_done_q; + dma_addr_t rx_done_q_dma; + unsigned int rx_done; + struct tx_done_report *tx_done_q; + unsigned int tx_done; + dma_addr_t tx_done_q_dma; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + struct pci_dev *pci_dev; + /* Frequently used values: keep some adjacent for cache effect. */ + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1, /* Full-duplex operation requested. */ + medialock:1, /* Xcvr set to fixed speed/duplex. */ + rx_flowctrl:1, + tx_flowctrl:1; /* Use 802.3x flow control. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + u32 tx_mode; + u8 tx_threshold; + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[MII_CNT]; /* MII device addresses. */ +}; + +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev, int startup); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(struct net_device *dev); +static int start_tx(struct sk_buff *skb, struct net_device *dev); +static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + + +static int __devinit starfire_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct netdev_private *np; + int i, irq, option, chip_idx = ent->driver_data; + struct net_device *dev; + static int card_idx = -1; + static int printed_version = 0; + long ioaddr; + int drv_flags, io_size; + int boguscnt; + + card_idx++; + option = card_idx < MAX_UNITS ? options[card_idx] : 0; + + if (!printed_version++) + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); + + if (pci_enable_device (pdev)) + return -EIO; + + ioaddr = pci_resource_start (pdev, 0); + io_size = pci_resource_len (pdev, 0); + if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { + printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx); + return -ENODEV; + } + + dev = init_etherdev(NULL, sizeof(*np)); + if (!dev) { + printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx); + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + + irq = pdev->irq; + + if (request_mem_region (ioaddr, io_size, dev->name) == NULL) { + printk (KERN_ERR "starfire %d: resource 0x%x @ 0x%lx busy, aborting\n", + card_idx, io_size, ioaddr); + goto err_out_free_netdev; + } + + ioaddr = (long) ioremap (ioaddr, io_size); + if (!ioaddr) { + printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n", + card_idx, io_size, ioaddr); + goto err_out_free_res; + } + + pci_set_master (pdev); + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, netdrv_tbl[chip_idx].name, ioaddr); + + /* Serial EEPROM reads are hidden by the hardware. */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + +#if ! defined(final_version) /* Dump the EEPROM contents during development. */ + if (debug > 4) + for (i = 0; i < 0x20; i++) + printk("%2.2x%s", + (unsigned int)readb(ioaddr + EEPROMCtrl + i), + i % 16 != 15 ? " " : "\n"); +#endif + + /* Issue soft reset */ + writel(0x8000, ioaddr + TxMode); + udelay(1000); + writel(0, ioaddr + TxMode); + + /* Reset the chip to erase previous misconfiguration. */ + writel(1, ioaddr + PCIDeviceConfig); + boguscnt = 1000; + while (--boguscnt > 0) { + udelay(10); + if ((readl(ioaddr + PCIDeviceConfig) & 1) == 0) + break; + } + if (boguscnt == 0) + printk("%s: chipset reset never completed!\n", dev->name); + /* wait a little longer */ + udelay(1000); + + dev->base_addr = ioaddr; + dev->irq = irq; + + np = dev->priv; + pci_set_drvdata(pdev, dev); + + np->pci_dev = pdev; + drv_flags = netdrv_tbl[chip_idx].drv_flags; + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->medialock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + init_tx_timer(dev, tx_timeout, TX_TIMEOUT); + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + + if (mtu) + dev->mtu = mtu; + + if (drv_flags & CanHaveMII) { + int phy, phy_idx = 0; + int mii_status; + for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { + mdio_write(dev, phy, 0, 0x8000); + udelay(500); + boguscnt = 1000; + while (--boguscnt > 0) + if ((mdio_read(dev, phy, 0) & 0x8000) == 0) + break; + if (boguscnt == 0) { + printk("%s: PHY reset never completed!\n", dev->name); + continue; + } + mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->advertising); + /* there can be only one PHY on-board */ + break; + } + } + np->mii_cnt = phy_idx; + } + + return 0; + +err_out_free_res: + release_mem_region (ioaddr, io_size); +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; +} + + +/* Read the MII Management Data I/O (MDIO) interfaces. */ + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); + int result, boguscnt=1000; + /* ??? Should we add a busy-wait here? */ + do + result = readl(mdio_addr); + while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0); + if (boguscnt == 0) + return 0; + if ((result & 0xffff) == 0xffff) + return 0; + return result & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); + writel(value, mdio_addr); + /* The busy-wait will occur before a read. */ + return; +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + int i, retval; + + /* Do we ever need to reset the chip??? */ + + COMPAT_MOD_INC_USE_COUNT; + + retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); + if (retval) { + COMPAT_MOD_DEC_USE_COUNT; + return retval; + } + + /* Disable the Rx and Tx, and reset the chip. */ + writel(0, ioaddr + GenCtrl); + writel(1, ioaddr + PCIDeviceConfig); + if (debug > 1) + printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + dev->name, dev->irq); + /* Allocate the various queues, failing gracefully. */ + if (np->tx_done_q == 0) + np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma); + if (np->rx_done_q == 0) + np->rx_done_q = pci_alloc_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, &np->rx_done_q_dma); + if (np->tx_ring == 0) + np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma); + if (np->rx_ring == 0) + np->rx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_ring_dma); + if (np->tx_done_q == 0 || np->rx_done_q == 0 + || np->rx_ring == 0 || np->tx_ring == 0) { + if (np->tx_done_q) + pci_free_consistent(np->pci_dev, PAGE_SIZE, + np->tx_done_q, np->tx_done_q_dma); + if (np->rx_done_q) + pci_free_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, + np->rx_done_q, np->rx_done_q_dma); + if (np->tx_ring) + pci_free_consistent(np->pci_dev, PAGE_SIZE, + np->tx_ring, np->tx_ring_dma); + if (np->rx_ring) + pci_free_consistent(np->pci_dev, PAGE_SIZE, + np->rx_ring, np->rx_ring_dma); + COMPAT_MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + init_ring(dev); + /* Set the size of the Rx buffers. */ + writel((np->rx_buf_sz << RxBufferLenShift) | + (0 << RxMinDescrThreshShift) | + RxPrefetchMode | RxVariableQ | + RxDescSpace4, + ioaddr + RxDescQCtrl); + + /* Set Tx descriptor to type 1 and padding to 0 bytes. */ + writel((2 << TxHiPriFIFOThreshShift) | + (0 << TxPadLenShift) | + (4 << TxDMABurstSizeShift) | + TxDescSpaceUnlim | TxDescType1, + ioaddr + TxDescCtrl); + +#if defined(ADDR_64BITS) && defined(__alpha__) + /* XXX We really need a 64-bit PCI dma interfaces too... -DaveM */ + writel(np->rx_ring_dma >> 32, ioaddr + RxDescQHiAddr); + writel(np->tx_ring_dma >> 32, ioaddr + TxRingHiAddr); +#else + writel(0, ioaddr + RxDescQHiAddr); + writel(0, ioaddr + TxRingHiAddr); + writel(0, ioaddr + CompletionHiAddr); +#endif + writel(np->rx_ring_dma, ioaddr + RxDescQAddr); + writel(np->tx_ring_dma, ioaddr + TxRingPtr); + + writel(np->tx_done_q_dma, ioaddr + TxCompletionAddr); +#ifdef full_rx_status + writel(np->rx_done_q_dma | + RxComplType3 | + (0 << RxComplThreshShift), + ioaddr + RxCompletionAddr); +#else /* not full_rx_status */ +#ifdef csum_rx_status + writel(np->rx_done_q_dma | + RxComplType2 | + (0 << RxComplThreshShift), + ioaddr + RxCompletionAddr); +#else /* not csum_rx_status */ + writel(np->rx_done_q_dma | + RxComplType0 | + (0 << RxComplThreshShift), + ioaddr + RxCompletionAddr); +#endif /* not csum_rx_status */ +#endif /* not full_rx_status */ + + if (debug > 1) + printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name); + + /* Fill both the unused Tx SA register and the Rx perfect filter. */ + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i); + for (i = 0; i < 16; i++) { + u16 *eaddrs = (u16 *)dev->dev_addr; + long setup_frm = ioaddr + 0x56000 + i*16; + writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; + } + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + np->tx_mode = 0; /* Initialized when TxMode set. */ + np->tx_threshold = 4; + writel(np->tx_threshold, ioaddr + TxThreshold); + writel(interrupt_mitigation, ioaddr + IntrTimerCtrl); + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + netif_start_if(dev); + netif_start_queue(dev); + + if (debug > 1) + printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); + set_rx_mode(dev); + + np->advertising = mdio_read(dev, np->phys[0], 4); + check_duplex(dev, 1); + + /* Set the interrupt mask and enable PCI interrupts. */ + writel(IntrRxDone | IntrRxEmpty | IntrDMAErr | + IntrTxDone | IntrStatsMax | IntrLinkChange | + IntrNormalSummary | IntrAbnormalSummary | + IntrRxGFPDead | IntrNoTxCsum | IntrTxBadID, + ioaddr + IntrEnable); + writel(0x00800000 | readl(ioaddr + PCIDeviceConfig), + ioaddr + PCIDeviceConfig); + +#ifdef HAS_FIRMWARE + /* Load Rx/Tx firmware into the frame processors */ + for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++) + writel(cpu_to_le32(firmware_rx[i]), ioaddr + RxGfpMem + i * 4); + for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++) + writel(cpu_to_le32(firmware_tx[i]), ioaddr + TxGfpMem + i * 4); + /* Enable the Rx and Tx units, and the Rx/Tx frame processors. */ + writel(0x003F, ioaddr + GenCtrl); +#else /* not HAS_FIRMWARE */ + /* Enable the Rx and Tx units only. */ + writel(0x000F, ioaddr + GenCtrl); +#endif /* not HAS_FIRMWARE */ + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open().\n", + dev->name); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = jiffies + 3*HZ; + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev, int startup) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + int new_tx_mode ; + + new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) + | (np->rx_flowctrl ? 0x0400:0); + if (np->medialock) { + if (np->full_duplex) + new_tx_mode |= 2; + } else { + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; + int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (duplex) + new_tx_mode |= 2; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug > 1) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d" + " negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + } + } + if (new_tx_mode != np->tx_mode) { + np->tx_mode = new_tx_mode; + writel(np->tx_mode | 0x8000, ioaddr + TxMode); + writel(np->tx_mode, ioaddr + TxMode); + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; /* Check before driver release. */ + + if (debug > 3) { + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + } + check_duplex(dev, 0); +#if ! defined(final_version) + /* This is often falsely triggered. */ + if (readl(ioaddr + IntrStatus) & 1) { + int new_status = readl(ioaddr + IntrStatus); + /* Bogus hardware IRQ: Fake an interrupt handler call. */ + if (new_status & 1) { + printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n", + dev->name, new_status, (int)readl(ioaddr + IntrStatus)); + intr_handler(dev->irq, dev, 0); + } + } +#endif + + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)le32_to_cpu(np->rx_ring[i].rxaddr)); + printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", le32_to_cpu(np->tx_ring[i].status)); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + netif_wake_queue(dev); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->rx_done = np->dirty_tx = np->tx_done = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_info[i].skb = skb; + if (skb == NULL) + break; + np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->dev = dev; /* Mark as being used by this device. */ + /* Grrr, we cannot offset to correctly align the IP header. */ + np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid); + } + writew(i - 1, dev->base_addr + RxDescQIdx); + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* Clear the remainder of the Rx buffer ring. */ + for ( ; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rxaddr = 0; + np->rx_info[i].skb = NULL; + np->rx_info[i].mapping = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing); + + /* Clear the completion rings. */ + for (i = 0; i < DONE_Q_SIZE; i++) { + np->rx_done_q[i].status = 0; + np->tx_done_q[i].status = 0; + } + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_info[i].skb = NULL; + np->tx_info[i].first_mapping = 0; + np->tx_ring[i].status = 0; + } + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + unsigned int entry; + + kick_tx_timer(dev, tx_timeout, TX_TIMEOUT); + + /* Caution: the write order is important here, set the field + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + + np->tx_info[entry].skb = skb; + np->tx_info[entry].first_mapping = + pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE); + + np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping); + /* Add "| TxDescIntr" to generate Tx-done interrupts. */ + np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID | TxCRCEn | 1 << 16); + + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr); + + if (debug > 5) { + printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x.\n", + dev->name, np->cur_tx, entry, + le32_to_cpu(np->tx_ring[entry].status)); + } + + np->cur_tx++; + + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + entry = -1; + entry++; + + /* Non-x86: explicitly flush descriptor cache lines here. */ + /* Ensure everything is written back above before the transmit is + initiated. - Jes */ + wmb(); + + /* Update the producer index. */ + writel(entry * (sizeof(struct starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx); + + if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) { + np->tx_full = 1; + netif_stop_queue(dev); + } + + dev->trans_start = jiffies; + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np; + long ioaddr; + int boguscnt = max_interrupt_work; + int consumer; + int tx_status; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + np = dev->priv; + + do { + u32 intr_status = readl(ioaddr + IntrClear); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & IntrRxDone) + netdev_rx(dev); + + /* Scavenge the skbuff list based on the Tx-done queue. + There are redundant checks here that may be cleaned up + after the driver has proven to be reliable. */ + consumer = readl(ioaddr + TxConsumerIdx); + if (debug > 4) + printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n", + dev->name, consumer); +#if 0 + if (np->tx_done >= 250 || np->tx_done == 0) + printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, %d is %8.8x.\n", + dev->name, np->tx_done, + le32_to_cpu(np->tx_done_q[np->tx_done].status), + (np->tx_done+1) & (DONE_Q_SIZE-1), + le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status)); +#endif + + while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) { + if (debug > 4) + printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n", + dev->name, np->tx_done, tx_status); + if ((tx_status & 0xe0000000) == 0xa0000000) { + np->stats.tx_packets++; + } else if ((tx_status & 0xe0000000) == 0x80000000) { + struct sk_buff *skb; + u16 entry = tx_status; /* Implicit truncate */ + entry /= sizeof(struct starfire_tx_desc); + + skb = np->tx_info[entry].skb; + np->tx_info[entry].skb = NULL; + pci_unmap_single(np->pci_dev, + np->tx_info[entry].first_mapping, + skb_first_frag_len(skb), + PCI_DMA_TODEVICE); + np->tx_info[entry].first_mapping = 0; + + /* Scavenge the descriptor. */ + dev_kfree_skb_irq(skb); + + np->dirty_tx++; + } + np->tx_done_q[np->tx_done].status = 0; + np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1); + } + writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2); + + if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { + /* The ring is no longer full, wake the queue. */ + np->tx_full = 0; + netif_wake_queue(dev); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & IntrAbnormalSummary) + netdev_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (debug > 4) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Remove after testing.. */ + { + static int stopit = 10; + if (!netif_running(dev) && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + u32 desc_status; + + if (np->rx_done_q == 0) { + printk(KERN_ERR "%s: rx_done_q is NULL! rx_done is %d. %p.\n", + dev->name, np->rx_done, np->tx_done_q); + return 0; + } + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) { + struct sk_buff *skb; + u16 pkt_len; + int entry; + + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() status of %d was %8.8x.\n", np->rx_done, desc_status); + if (--boguscnt < 0) + break; + if ( ! (desc_status & RxOK)) { + /* There was a error. */ + if (debug > 2) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", desc_status); + np->stats.rx_errors++; + if (desc_status & RxFIFOErr) + np->stats.rx_fifo_errors++; + goto next_rx; + } + + pkt_len = desc_status; /* Implicitly Truncate */ + entry = (desc_status >> 16) & 0x7ff; + +#ifndef final_version + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d, bogus_cnt %d.\n", pkt_len, boguscnt); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single(np->pci_dev, + np->rx_info[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); +#if HAS_IP_COPYSUM /* Call copy + cksum if available. */ + eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail, pkt_len); +#endif + } else { + char *temp; + + pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb = np->rx_info[entry].skb; + temp = skb_put(skb, pkt_len); + np->rx_info[entry].skb = NULL; + np->rx_info[entry].mapping = 0; + } +#ifndef final_version /* Remove after testing. */ + /* You will want this info for the initial debug. */ + if (debug > 5) + printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" + "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " + "%d.%d.%d.%d.\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5], skb->data[6], skb->data[7], + skb->data[8], skb->data[9], skb->data[10], + skb->data[11], skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], + skb->data[17]); +#endif + skb->protocol = eth_type_trans(skb, dev); +#if defined(full_rx_status) || defined(csum_rx_status) + if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + /* + * This feature doesn't seem to be working, at least + * with the two firmware versions I have. If the GFP sees + * a fragment, it either ignores it completely, or reports + * "bad checksum" on it. + * + * Maybe I missed something -- corrections are welcome. + * Until then, the printk stays. :-) -Ion + */ + else if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x00400000) { + skb->ip_summed = CHECKSUM_HW; + skb->csum = le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0xffff; + printk(KERN_DEBUG "%s: checksum_hw, status2 = %x\n", dev->name, np->rx_done_q[np->rx_done].status2); + } +#endif + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; + +next_rx: + np->cur_rx++; + np->rx_done_q[np->rx_done].status = 0; + np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1); + } + writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx); + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_info[entry].skb == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_info[entry].skb = skb; + if (skb == NULL) + break; /* Better luck next round. */ + np->rx_info[entry].mapping = + pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[entry].rxaddr = + cpu_to_le32(np->rx_info[entry].mapping | RxDescValid); + } + if (entry == RX_RING_SIZE - 1) + np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing); + /* We could defer this until later... */ + writew(entry, dev->base_addr + RxDescQIdx); + } + + if (debug > 5 + || memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1)) + printk(KERN_DEBUG " exiting netdev_rx() status of %d was %8.8x %d.\n", + np->rx_done, desc_status, + memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1)); + + /* Restart Rx engine if stopped. */ + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + struct netdev_private *np = dev->priv; + + if (intr_status & IntrLinkChange) { + printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" + " %4.4x, partner %4.4x.\n", dev->name, + mdio_read(dev, np->phys[0], 4), + mdio_read(dev, np->phys[0], 5)); + check_duplex(dev, 0); + } + if (intr_status & IntrStatsMax) { + get_stats(dev); + } + /* Came close to underrunning the Tx FIFO, increase threshold. */ + if (intr_status & IntrTxDataLow) { + writel(++np->tx_threshold, dev->base_addr + TxThreshold); + printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n", + dev->name, np->tx_threshold * 16); + } + if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrPCIPad)) && debug) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* Hmmmmm, it's not clear how to recover from DMA faults. */ + if (intr_status & IntrDMAErr) + np->stats.tx_fifo_errors++; +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; + + /* This adapter architecture needs no SMP locks. */ + np->stats.tx_bytes = readl(ioaddr + 0x57010); + np->stats.rx_bytes = readl(ioaddr + 0x57044); + np->stats.tx_packets = readl(ioaddr + 0x57000); + np->stats.tx_aborted_errors = + readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028); + np->stats.tx_window_errors = readl(ioaddr + 0x57018); + np->stats.collisions = + readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008); + + /* The chip only need report frame silently dropped. */ + np->stats.rx_dropped += readw(ioaddr + RxDMAStatus); + writew(0, ioaddr + RxDMAStatus); + np->stats.rx_crc_errors = readl(ioaddr + 0x5703C); + np->stats.rx_frame_errors = readl(ioaddr + 0x57040); + np->stats.rx_length_errors = readl(ioaddr + 0x57058); + np->stats.rx_missed_errors = readl(ioaddr + 0x5707C); + + return &np->stats; +} + +/* The little-endian AUTODIN II ethernet CRC calculations. + A big-endian version is also available. + This is slow but compact code. Do not use this routine for bulk data, + use a table-based routine instead. + This is common code and should be moved to net/core/crc.c. + Chips may use the upper or lower CRC bits, and may reverse and/or invert + them. Select the endian-ness that results in minimal calculations. +*/ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + u32 rx_mode; + struct dev_mc_list *mclist; + int i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys; + } else if (dev->mc_count <= 15) { + /* Use the 16 element perfect filter. */ + long filter_addr = ioaddr + 0x56000 + 1*16; + for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count; + i++, mclist = mclist->next) { + u16 *eaddrs = (u16 *)mclist->dmi_addr; + writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; + } + while (i++ < 16) { + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 8; + } + rx_mode = AcceptBroadcast | AcceptMyPhys; + } else { + /* Must use a multicast hash table. */ + long filter_addr; + u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ + + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter); + } + /* Clear the perfect filter list. */ + filter_addr = ioaddr + 0x56000 + 1*16; + for (i = 1; i < 16; i++) { + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 8; + } + for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++) + writew(mc_filter[i], filter_addr); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + } + writel(rx_mode, ioaddr + RxFilterMode); +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct netdev_private *np = dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = np->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data[0] == np->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + if (value & 0x9000) /* Autonegotiation. */ + np->medialock = 0; + else { + np->full_duplex = (value & 0x0100) ? 1 : 0; + np->medialock = 1; + } + break; + case 4: np->advertising = value; break; + } + check_duplex(dev, 0); + } + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; + int i; + + netif_stop_queue(dev); + netif_stop_if(dev); + + del_timer_sync(&np->timer); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + writel(0, ioaddr + IntrEnable); + + /* Stop the chip's Tx and Rx processes. */ + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + np->tx_ring_dma); + for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++) + printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n", + i, le32_to_cpu(np->tx_ring[i].status), + le32_to_cpu(np->tx_ring[i].first_addr), + le32_to_cpu(np->tx_done_q[i].status)); + printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n", + np->rx_ring_dma, np->rx_done_q); + if (np->rx_done_q) + for (i = 0; i < 8 /* RX_RING_SIZE */; i++) { + printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n", + i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status)); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ + if (np->rx_info[i].skb != NULL) { + pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + dev_kfree_skb(np->rx_info[i].skb); + } + np->rx_info[i].skb = NULL; + np->rx_info[i].mapping = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + struct sk_buff *skb = np->tx_info[i].skb; + if (skb == NULL) + continue; + pci_unmap_single(np->pci_dev, + np->tx_info[i].first_mapping, + skb_first_frag_len(skb), PCI_DMA_TODEVICE); + np->tx_info[i].first_mapping = 0; + dev_kfree_skb(skb); + np->tx_info[i].skb = NULL; + } + + COMPAT_MOD_DEC_USE_COUNT; + + return 0; +} + + +static void __devexit starfire_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct netdev_private *np; + + if (!dev) + BUG(); + + np = dev->priv; + + unregister_netdev(dev); + iounmap((char *)dev->base_addr); + + release_mem_region(pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + + if (np->tx_done_q) + pci_free_consistent(np->pci_dev, PAGE_SIZE, + np->tx_done_q, np->tx_done_q_dma); + if (np->rx_done_q) + pci_free_consistent(np->pci_dev, PAGE_SIZE, + np->rx_done_q, np->rx_done_q_dma); + if (np->tx_ring) + pci_free_consistent(np->pci_dev, PAGE_SIZE, + np->tx_ring, np->tx_ring_dma); + if (np->rx_ring) + pci_free_consistent(np->pci_dev, PAGE_SIZE, + np->rx_ring, np->rx_ring_dma); + + kfree(dev); +} + + +static struct pci_driver starfire_driver = { + name: "starfire", + probe: starfire_init_one, + remove: starfire_remove_one, + id_table: starfire_pci_tbl, +}; + + +static int __init starfire_init (void) +{ + return pci_module_init (&starfire_driver); +} + + +static void __exit starfire_cleanup (void) +{ + pci_unregister_driver (&starfire_driver); +} + + +module_init(starfire_init); +module_exit(starfire_cleanup); + + +/* + * Local variables: + * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c" + * simple-compile-command: "gcc -DMODULE -O6 -c starfire.c" + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/starfire_firmware.pl linux/drivers/net/starfire_firmware.pl --- v2.2.18/drivers/net/starfire_firmware.pl Wed Dec 31 19:00:00 1969 +++ linux/drivers/net/starfire_firmware.pl Sun Mar 25 11:37:35 2001 @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +# This script can be used to generate a new starfire_firmware.h +# from GFP_RX.DAT and GFP_TX.DAT, files included with the DDK +# and also with the Novell drivers. + +open FW, "GFP_RX.DAT" || die; +open FWH, ">starfire_firmware.h" || die; + +printf(FWH "static u32 firmware_rx[] = {\n"); +$counter = 0; +while ($foo = ) { + chomp; + printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4)); + $counter++; +} + +close FW; +open FW, "GFP_TX.DAT" || die; + +printf(FWH "};\t/* %d Rx instructions */\n#define FIRMWARE_RX_SIZE %d\n\nstatic u32 firmware_tx[] = {\n", $counter, $counter); +$counter = 0; +while ($foo = ) { + chomp; + printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4)); + $counter++; +} + +close FW; +printf(FWH "};\t/* %d Tx instructions */\n#define FIRMWARE_TX_SIZE %d\n", $counter, $counter); +close(FWH); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/strip.c linux/drivers/net/strip.c --- v2.2.18/drivers/net/strip.c Sun Mar 25 11:12:49 2001 +++ linux/drivers/net/strip.c Sun Mar 25 11:37:35 2001 @@ -14,7 +14,7 @@ * for kernel-based devices like TTY. It interfaces between a * raw TTY, and the kernel's INET protocol layers (via DDI). * - * Version: @(#)strip.c 1.3 July 1997 + * Version: @(#)strip.c 1.4 September 2000 * * Author: Stuart Cheshire * @@ -66,12 +66,15 @@ * It is no longer necessarily to manually set the radio's * rate permanently to 115200 -- the driver handles setting * the rate automatically. + * + * v1.4 September 2000 (AB) + * Added support for long serial numbers. */ #ifdef MODULE -static const char StripVersion[] = "1.3-STUART.CHESHIRE-MODULAR"; +static const char StripVersion[] = "1.4-STUART.CHESHIRE-MODULAR"; #else -static const char StripVersion[] = "1.3-STUART.CHESHIRE"; +static const char StripVersion[] = "1.4-STUART.CHESHIRE"; #endif #define TICKLE_TIMERS 0 @@ -897,20 +900,37 @@ * Convert a string to a Metricom Address. */ -#define IS_RADIO_ADDRESS(p) ( \ +#define IS_RADIO_ADDRESS_1(p) ( \ isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ (p)[4] == '-' && \ isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) +#define IS_RADIO_ADDRESS_2(p) ( \ + isdigit((p)[0]) && isdigit((p)[1]) && \ + (p)[2] == '-' && \ + isdigit((p)[3]) && isdigit((p)[4]) && isdigit((p)[5]) && isdigit((p)[6]) && \ + (p)[7] == '-' && \ + isdigit((p)[8]) && isdigit((p)[9]) && isdigit((p)[10]) && isdigit((p)[11]) ) + static int string_to_radio_address(MetricomAddress *addr, __u8 *p) { - if (!IS_RADIO_ADDRESS(p)) return(1); + if (IS_RADIO_ADDRESS_2(p)) + { + addr->c[0] = 0; + addr->c[1] = (READHEX(p[0]) << 4 | READHEX(p[1])) ^ 0xFF; + addr->c[2] = READHEX(p[3]) << 4 | READHEX(p[4]); + addr->c[3] = READHEX(p[5]) << 4 | READHEX(p[6]); + addr->c[4] = READHEX(p[8]) << 4 | READHEX(p[9]); + addr->c[5] = READHEX(p[10]) << 4 | READHEX(p[11]); + }else{ + if(!IS_RADIO_ADDRESS_1(p)) return(1); addr->c[0] = 0; addr->c[1] = 0; addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); + } return(0); } @@ -920,6 +940,9 @@ static __u8 *radio_address_to_string(const MetricomAddress *addr, MetricomAddressString *p) { + if(addr->c[1]) + sprintf(p->c, "%02X-%02X%02X-%02X%02X", addr->c[1] ^ 0xFF, addr->c[2], addr->c[3], addr->c[4], addr->c[5]); + else sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], addr->c[4], addr->c[5]); return(p->c); } @@ -1481,6 +1504,12 @@ *ptr++ = 0x0D; *ptr++ = '*'; + if(haddr.c[1]) + { + *ptr++ = hextable[(haddr.c[1] >> 4) ^ 0xF]; + *ptr++ = hextable[(haddr.c[1] & 0xF) ^ 0xF]; + *ptr++ = '-'; + } *ptr++ = hextable[haddr.c[2] >> 4]; *ptr++ = hextable[haddr.c[2] & 0xF]; *ptr++ = hextable[haddr.c[3] >> 4]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.2.18/drivers/net/sunhme.c Sun Mar 25 11:12:51 2001 +++ linux/drivers/net/sunhme.c Sun Mar 25 11:37:35 2001 @@ -3523,6 +3523,7 @@ struct linux_sbus_device *sdev = 0; static int called = 0; int cards = 0, v; + char model[128]; if(called) return ENODEV; @@ -3534,7 +3535,13 @@ dev = NULL; if(!strcmp(sdev->prom_name, "SUNW,hme")) { cards++; - if((v = happy_meal_ether_init(dev, sdev, 0))) + prom_getstring(sdev->prom_node, "model", + model, sizeof(model)); + if (!strcmp(model, "SUNW,sbus-qfe")) + v = happy_meal_ether_init(dev, sdev, 1); + else + v = happy_meal_ether_init(dev, sdev, 0); + if(v) return v; } else if(!strcmp(sdev->prom_name, "qfe") || !strcmp(sdev->prom_name, "SUNW,qfe")) { @@ -3582,11 +3589,20 @@ cleanup_module(void) { struct happy_meal *sunshine; + struct quattro *last_seen_qfe = NULL; /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_happy_dev) { struct happy_meal *hp = root_happy_dev; sunshine = root_happy_dev->next_module; + + if (!(hp->happy_flags & HFLAG_PCI) && + (hp->happy_flags & HFLAG_QUATTRO)) { + if (hp->qfe_parent != last_seen_qfe) { + free_irq(hp->dev->irq, hp->qfe_parent); + last_seen_qfe = hp->qfe_parent; + } + } sparc_free_io(hp->gregs, sizeof(struct hmeal_gregs)); sparc_free_io(hp->etxregs, sizeof(struct hmeal_etxregs)); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.2.18/drivers/net/tulip.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/net/tulip.c Sun Mar 25 11:37:35 2001 @@ -15,10 +15,14 @@ Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html - + This driver also contains updates by Wolfgang Walter and others. For this specific driver variant please use linux-kernel for bug reports. + + Updated 12/17/2000 by Jim McQuillan to + include support for the Linksys LNE100TX card based on the + Admtek 985 Centaur-P chipset. */ #define SMP_CHECK @@ -26,9 +30,6 @@ /* A few user-configurable values. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 25; - #define MAX_UNITS 8 /* Used to pass the full-duplex flag, etc. */ static int full_duplex[MAX_UNITS] = {0, }; @@ -139,7 +140,6 @@ MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(reverse_probe, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(csr0, "i"); @@ -149,10 +149,6 @@ #define RUN_AT(x) (jiffies + (x)) -#if (LINUX_VERSION_CODE >= 0x20100) -static char kernel_version[] = UTS_RELEASE; -#endif - #if LINUX_VERSION_CODE < 0x20123 #define hard_smp_processor_id() smp_processor_id() #define test_and_set_bit(val, addr) set_bit(val, addr) @@ -398,6 +394,8 @@ HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, { "ADMtek Comet", 256, 0x0001abef, MC_HASH_ONLY, comet_timer }, + { "ADMtek Centaur-P", 256, 0x0001abef, + MC_HASH_ONLY, comet_timer }, { "Compex 9881 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, { "Intel DS21145 Tulip", 128, 0x0801fbff, @@ -411,8 +409,8 @@ /* This matches the table above. Note 21142 == 21143. */ enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, - LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881, - I21145, + LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMET5, + COMPEX9881, I21145, XIRCOM, }; /* A full-duplex map for media types. */ @@ -750,7 +748,7 @@ put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); sum += value & 0xffff; } - } else if (chip_idx == COMET) { + } else if ((chip_idx == COMET) || (chip_idx == COMET5)) { /* No need to read the EEPROM. */ put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); @@ -993,6 +991,7 @@ outl(0x00001000, ioaddr + CSR12); break; case COMET: + case COMET5: /* No initialization necessary. */ break; } @@ -1310,7 +1309,7 @@ return 0xffff; } - if (tp->chip_id == COMET) { + if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) { if (phy_id == 1) { if (location < 7) return inl(ioaddr + 0xB4 + (location<<2)); @@ -1367,7 +1366,7 @@ return; } - if (tp->chip_id == COMET) { + if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) { if (phy_id != 1) return; if (location < 7) @@ -1457,7 +1456,7 @@ outl(addr_low, ioaddr + CSR14); outl(1, ioaddr + CSR13); outl(addr_high, ioaddr + CSR14); - } else if (tp->chip_id == COMET) { + } else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) { outl(addr_low, ioaddr + 0xA4); outl(addr_high, ioaddr + 0xA8); outl(0, ioaddr + 0xAC); @@ -1572,7 +1571,7 @@ outl(0x0000, ioaddr + CSR13); outl(0x0000, ioaddr + CSR14); outl(0x0008, ioaddr + CSR15); - } else if (tp->chip_id == COMET) { + } else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) { dev->if_port = 0; tp->csr6 = 0x00040000; } else if (tp->chip_id == AX88140) { @@ -3012,7 +3011,7 @@ data[0] = phy; else if (tp->flags & HAS_NWAY143) data[0] = 32; - else if (tp->chip_id == COMET) + else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) data[0] = 1; else return -ENODEV; @@ -3139,7 +3138,9 @@ outl(mc_filter[0], ioaddr + CSR14); outl(3, ioaddr + CSR13); outl(mc_filter[1], ioaddr + CSR14); - } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + + /* Has a simple hash filter. */ + } else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) { outl(mc_filter[0], ioaddr + 0xAC); outl(mc_filter[1], ioaddr + 0xB0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.2.18/drivers/net/via-rhine.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/net/via-rhine.c Sun Mar 25 11:37:35 2001 @@ -1,35 +1,44 @@ /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */ /* - Written 1998-1999 by Donald Becker. + Written 1998-2000 by Donald Becker. - This software may be used and distributed according to the terms - of the GNU Public License (GPL), incorporated herein by reference. - Drivers derived from this code also fall under the GPL and must retain - this authorship and copyright notice. + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. This driver is designed for the VIA VT86c100A Rhine-II PCI Fast Ethernet controller. It also works with the older 3043 Rhine-I chip. - The author may be reached as becker@cesdis.edu, or - Donald Becker - 312 Severn Ave. #W302 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 Annapolis MD 21403 Support and updates available at - http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html + http://www.scyld.com/network/via-rhine.html + + + Linux kernel version history: + + LK1.0.0: + - Urban Widmark: merges from Beckers 1.08b version and 2.4.0 (VT6102) */ -static const char *versionA = -"via-rhine.c:v1.01 2/27/99 Written by Donald Becker\n"; -static const char *versionB = -" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"via-rhine.c:v1.08b-LK1.0.0 12/14/2000 Written by Donald Becker\n"; +static const char version2[] = +" http://www.scyld.com/network/via-rhine.html\n"; -/* A few user-configurable values. These may be modified when a driver - module is loaded.*/ +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; -static int min_pci_latency = 64; +static int min_pci_latency = 32; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ @@ -55,7 +64,8 @@ Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 8 +#define TX_RING_SIZE 16 +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define RX_RING_SIZE 16 /* Operational parameters that usually are not changed. */ @@ -64,9 +74,16 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include #include #include -#include #include #include #include @@ -82,15 +99,17 @@ #include #include -/* This driver was written to use PCI memory space, however some x86 - motherboards only configure I/O space accesses correctly. */ -#if defined(__i386__) && !defined(VIA_USE_MEMORY) -#define VIA_USE_IO -#endif -#if defined(__alpha__) -#define VIA_USE_IO -#endif -#ifdef VIA_USE_IO +/* Condensed bus+endian portability operations. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +/* This driver was written to use PCI memory space, however most versions + of the Rhine only work correctly with I/O space accesses. */ +#if defined(VIA_USE_MEMORY) +#warning Many adapters using the VIA Rhine chip are not configured to work +#warning with PCI memory space accesses. +#else +#define USE_IO_OPS #undef readb #undef readw #undef readl @@ -105,21 +124,7 @@ #define writel outl #endif -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - -#define RUN_AT(x) (jiffies + (x)) - -#if (LINUX_VERSION_CODE >= 0x20100) -static char kernel_version[] = UTS_RELEASE; -#else -#ifndef __alpha__ -#define ioremap vremap -#define iounmap vfree -#endif -#endif -#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 -MODULE_AUTHOR("Donald Becker "); +MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(min_pci_latency, "i"); @@ -127,28 +132,6 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#endif -#if LINUX_VERSION_CODE < 0x20123 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#else -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -/* Grrrr, the PCI code changed, but did not consider CardBus... */ -#include -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE); -#else -#define dev_free_skb(skb) dev_kfree_skb(skb); -#endif - /* Theory of Operation @@ -226,13 +209,13 @@ IVb. References Preliminary VT86C100A manual from http://www.via.com.tw/ -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata The VT86C100A manual is not reliable information. -The chip does not handle unaligned transmit or receive buffers, resulting +The 3043 chip does not handle unaligned transmit or receive buffers, resulting in significant performance degradation for bounce buffer copies on transmit and unaligned IP headers on receive. The chip does not pad to minimum transmit length. @@ -250,6 +233,15 @@ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; + +#if defined(VIA_USE_MEMORY) +#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR0) +#define RHINEII_IOSIZE 4096 +#else +#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR1) +#define RHINEII_IOSIZE 256 +#endif + struct pci_id_info { const char *name; u16 vendor_id, device_id, device_id_mask, flags; @@ -264,34 +256,41 @@ static struct pci_id_info pci_tbl[] __initdata = { { "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff, - PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1}, + RHINE_IOTYPE, 128, via_probe1}, + { "VIA VT6102 Rhine-II", 0x1106, 0x3065, 0xffff, + RHINE_IOTYPE, RHINEII_IOSIZE, via_probe1}, { "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff, - PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1}, + RHINE_IOTYPE, 128, via_probe1}, {0,}, /* 0 terminated list. */ }; /* A chip capabilities table, matching the entries in pci_tbl[] above. */ -enum chip_capability_flags {CanHaveMII=1, }; +enum chip_capability_flags { + CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, + ReqTxAlign=0x10, HasWOL=0x20, +}; + struct chip_info { int io_size; int flags; } static cap_tbl[] __initdata = { - {128, CanHaveMII, }, - {128, CanHaveMII, }, + {128, CanHaveMII | ReqTxAlign, }, + {128, CanHaveMII | HasWOL, }, + {128, CanHaveMII | ReqTxAlign, }, }; -/* Offsets to the device registers. -*/ +/* Offsets to the device registers. */ enum register_offsets { StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, IntrStatus=0x0C, IntrEnable=0x0E, MulticastFilter0=0x10, MulticastFilter1=0x14, RxRingPtr=0x18, TxRingPtr=0x1C, - MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E, + MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, - Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E, + Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E, + StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; /* Bits in the interrupt status/mask registers. */ @@ -303,21 +302,18 @@ IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, IntrTxAborted=0x2000, IntrLinkChange=0x4000, IntrRxWakeUp=0x8000, - IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260, + IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, }; - /* The Rx and Tx buffer descriptors. */ struct rx_desc { - u16 rx_status; - u16 rx_length; + s32 rx_status; u32 desc_length; u32 addr; u32 next_desc; }; struct tx_desc { - u16 tx_status; - u16 tx_own; + s32 tx_status; u32 desc_length; u32 addr; u32 next_desc; @@ -325,9 +321,10 @@ /* Bits in *_desc.status */ enum rx_status_bits { - RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F}; + RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F +}; enum desc_status_bits { - DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000, + DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000, }; /* Bits in ChipCmd. */ @@ -338,6 +335,7 @@ CmdNoTxPoll=0x0800, CmdReset=0x8000, }; +#define PRIV_ALIGN 15 /* Required alignment mask */ struct netdev_private { /* Descriptor rings first for alignment. */ struct rx_desc rx_ring[RX_RING_SIZE]; @@ -349,12 +347,12 @@ unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ struct device *next_module; /* Link for devices of this type. */ + void *priv_addr; /* Unaligned address for kfree */ struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ unsigned char pci_bus, pci_devfn; /* Frequently used values: keep some adjacent for cache effect. */ - int chip_id; - long in_interrupt; /* Word-long for SMP locks. */ + int chip_id, drv_flags; struct rx_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; @@ -388,6 +386,7 @@ static struct net_device_stats *get_stats(struct device *dev); static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct device *dev); +static inline void clear_tally_counters(long ioaddr); @@ -432,30 +431,13 @@ continue; { -#if defined(PCI_SUPPORT_VER2) struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); -#ifdef VIA_USE_IO +#ifdef USE_IO_OPS pciaddr = pdev->base_address[0]; #else pciaddr = pdev->base_address[1]; #endif irq = pdev->irq; -#else - u32 pci_memaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); -#ifdef VIA_USE_IO - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_memaddr); - pciaddr = pci_memaddr; -#else - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, &pci_memaddr); - pciaddr = pci_memaddr; -#endif - irq = pci_irq_line; -#endif } if (debug > 2) @@ -511,7 +493,7 @@ { static int did_version = 0; if (!did_version++) - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); + printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); return pci_etherdev_probe(dev, pci_tbl); } #endif @@ -521,6 +503,7 @@ int chip_id, int card_idx) { struct netdev_private *np; + void *priv_mem; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; dev = init_etherdev(dev, 0); @@ -528,14 +511,20 @@ printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_tbl[chip_id].name, ioaddr); - /* Ideally we would be read the EEPROM but access may be locked. */ - for (i = 0; i <6; i++) + /* We would prefer to read the EEPROM but access may be locked. */ + for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); -#ifdef VIA_USE_IO + /* Allocate driver private memory for descriptor lists. + Check for the very unlikely case of no memory. */ + priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL); + if (priv_mem == NULL) + return NULL; + +#ifdef USE_IO_OPS request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name); #endif @@ -546,9 +535,9 @@ dev->irq = irq; /* Make certain the descriptor lists are cache-aligned. */ - np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31); + dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN); memset(np, 0, sizeof(*np)); - dev->priv = np; + np->priv_addr = priv_mem; np->next_module = root_net_dev; root_net_dev = dev; @@ -556,6 +545,7 @@ np->pci_bus = pci_bus; np->pci_devfn = pci_devfn; np->chip_id = chip_id; + np->drv_flags = cap_tbl[chip_id].flags; if (dev->mem_start) option = dev->mem_start; @@ -582,7 +572,7 @@ dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; - if (cap_tbl[np->chip_id].flags & CanHaveMII) { + if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; np->phys[0] = 1; /* Standard for this chip. */ for (phy = 1; phy < 32 && phy_idx < 4; phy++) { @@ -625,9 +615,23 @@ static void mdio_write(struct device *dev, int phy_id, int regnum, int value) { + struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int boguscnt = 1024; + if (phy_id == np->phys[0]) { + switch (regnum) { + case 0: /* Is user forcing speed/duplex? */ + if (value & 0x9000) /* Autonegotiation. */ + np->duplex_lock = 0; + else + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: + np->advertising = value; + break; + } + } /* Wait for a previous command to complete. */ while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; @@ -649,15 +653,17 @@ /* Reset the chip. */ writew(CmdReset, ioaddr + ChipCmd); - if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; return -EAGAIN; + } if (debug > 1) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); - MOD_INC_USE_COUNT; - init_ring(dev); writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); @@ -667,7 +673,7 @@ writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ - writew(0x0006, ioaddr + PCIConfig); /* Tune configuration??? */ + writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ /* Configure the FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ np->tx_thresh = 0x20; @@ -678,7 +684,6 @@ dev->tbusy = 0; dev->interrupt = 0; - np->in_interrupt = 0; set_rx_mode(dev); @@ -696,6 +701,11 @@ writew(np->chip_cmd, ioaddr + ChipCmd); check_duplex(dev); + /* The LED outputs of various MII xcvrs should be configured. */ + /* For NS or Mison phys, turn on bit 1 in register 0x17 */ + /* For ESI phys, turn on bit 7 in register 0x17. */ + mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) | + (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001); if (debug > 2) printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x " @@ -705,7 +715,7 @@ /* Set the timer to check for link beat. */ init_timer(&np->timer); - np->timer.expires = RUN_AT(1); + np->timer.expires = jiffies + 2; np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); @@ -718,11 +728,12 @@ struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; int duplex; if (np->duplex_lock || mii_reg5 == 0xffff) return; - duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (np->full_duplex != duplex) { np->full_duplex = duplex; if (debug) @@ -748,9 +759,14 @@ printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); } + if (test_bit(0, (void*)&dev->tbusy) != 0 + && np->cur_tx - np->dirty_tx > 1 + && jiffies - dev->trans_start > TX_TIMEOUT) + tx_timeout(dev); + check_duplex(dev); - np->timer.expires = RUN_AT(next_tick); + np->timer.expires = jiffies + next_tick; add_timer(&np->timer); } @@ -764,15 +780,15 @@ dev->name, readw(ioaddr + IntrStatus), mdio_read(dev, np->phys[0], 1)); - /* Perhaps we should reinitialize the hardware here. */ - dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - - /* Trigger an immediate transmit demand. */ - - dev->trans_start = jiffies; - np->stats.tx_errors++; - return; + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; } @@ -791,35 +807,33 @@ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rx_status = 0; - np->rx_ring[i].rx_length = 0; - np->rx_ring[i].desc_length = np->rx_buf_sz; - np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]); + np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); + np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]); + np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); - /* Fill in the Rx buffers. */ + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[i] = skb; if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[i].addr = virt_to_bus(skb->tail); - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].rx_length = DescOwn; + np->rx_ring[i].addr = virt_to_le32desc(skb->tail); + np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; - np->tx_ring[i].tx_own = 0; - np->tx_ring[i].desc_length = 0x00e08000; - np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]); + np->tx_ring[i].tx_status = 0; + np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]); np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL); } - np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]); + np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]); return; } @@ -832,41 +846,45 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - tx_timeout(dev); + /* This watchdog code is redundant with the media monitor timer. */ + if (jiffies - dev->trans_start > TX_TIMEOUT) + tx_timeout(dev); return 1; } - /* Caution: the write order is important here, set the field - with the "ownership" bits last. */ + /* Explicitly flush packet data cache lines here. */ + + /* Caution: the write order is important here, set the descriptor word + with the "ownership" bit last. No SMP locking is needed if the + cur_tx is incremented after the descriptor is consistent. */ /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; np->tx_skbuff[entry] = skb; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ + if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) { + /* Must use alignment buffer. */ if (np->tx_buf[entry] == NULL && (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) return 1; memcpy(np->tx_buf[entry], skb->data, skb->len); - np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]); + np->tx_ring[entry].addr = virt_to_le32desc(np->tx_buf[entry]); } else - np->tx_ring[entry].addr = virt_to_bus(skb->data); + np->tx_ring[entry].addr = virt_to_le32desc(skb->data); - np->tx_ring[entry].desc_length = 0x00E08000 | - (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); - np->tx_ring[entry].tx_own = DescOwn; + np->tx_ring[entry].desc_length = + cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); np->cur_tx++; - /* Non-x86 Todo: explicitly flush cache lines here. */ + /* Explicitly flush descriptor cache lines here. */ /* Wake the potentially-idle transmit channel. */ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); - if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1) + if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1) clear_bit(0, (void*)&dev->tbusy); /* Typical path */ else np->tx_full = 1; @@ -884,26 +902,9 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct device *dev = (struct device *)dev_instance; - struct netdev_private *np; - long ioaddr, boguscnt = max_interrupt_work; - - ioaddr = dev->base_addr; - np = (struct netdev_private *)dev->priv; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif + struct netdev_private *np = (void *)dev->priv; + long ioaddr = dev->base_addr; + int boguscnt = max_interrupt_work; do { u32 intr_status = readw(ioaddr + IntrStatus); @@ -924,10 +925,9 @@ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; - int txstatus; - if (np->tx_ring[entry].tx_own) + int txstatus = le32_to_cpu(np->tx_ring[entry].tx_status); + if (txstatus & DescOwn) break; - txstatus = np->tx_ring[entry].tx_status; if (debug > 6) printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n", entry, txstatus); @@ -951,16 +951,16 @@ #endif np->stats.collisions += (txstatus >> 3) & 15; #if defined(NETSTATS_VER2) - np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; + np->stats.tx_bytes += np->tx_skbuff[entry]->len; #endif np->stats.tx_packets++; } /* Free the original skb. */ - dev_free_skb(np->tx_skbuff[entry]); + dev_kfree_skb(np->tx_skbuff[entry]); np->tx_skbuff[entry] = 0; } if (np->tx_full && dev->tbusy - && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { + && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { /* The ring is no longer full, clear tbusy. */ np->tx_full = 0; clear_bit(0, (void*)&dev->tbusy); @@ -984,11 +984,6 @@ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif return; } @@ -1001,15 +996,15 @@ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; if (debug > 4) { - printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", - entry, np->rx_head_desc->rx_length); + printk(KERN_DEBUG " In netdev_rx(), entry %d status %8.8x.\n", + entry, np->rx_head_desc->rx_status); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while ( ! (np->rx_head_desc->rx_length & DescOwn)) { + while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) { struct rx_desc *desc = np->rx_head_desc; - int data_size = desc->rx_length; - u16 desc_status = desc->rx_status; + u32 desc_status = le32_to_cpu(desc->rx_status); + int data_size = desc_status >> 16; if (debug > 4) printk(KERN_DEBUG " netdev_rx() status is %4.4x.\n", @@ -1039,7 +1034,7 @@ } else { struct sk_buff *skb; /* Length should omit the CRC */ - u16 pkt_len = data_size - 4; + int pkt_len = data_size - 4; /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ @@ -1047,21 +1042,23 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ -#if ! defined(__alpha__) || USE_IP_COPYSUM /* Avoid misaligned on Alpha */ - eth_copy_and_sum(skb, bus_to_virt(desc->addr), - pkt_len, 0); +#if HAS_IP_COPYSUM /* Call copy + cksum if available. */ + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len); + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); #endif } else { skb_put(skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); - np->stats.rx_bytes+=skb->len; netif_rx(skb); dev->last_rx = jiffies; +#if defined(NETSTATS_VER2) + np->stats.rx_bytes += skb->len; +#endif np->stats.rx_packets++; } entry = (++np->cur_rx) % RX_RING_SIZE; @@ -1078,10 +1075,9 @@ if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[entry].addr = virt_to_bus(skb->tail); + np->rx_ring[entry].addr = virt_to_le32desc(skb->tail); } - np->rx_ring[entry].rx_status = 0; - np->rx_ring[entry].rx_length = DescOwn; + np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } /* Pre-emptively restart Rx engine. */ @@ -1095,10 +1091,11 @@ long ioaddr = dev->base_addr; if (intr_status & (IntrMIIChange | IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) + if (readb(ioaddr + MIIStatus) & 0x02) { /* Link failed, restart autonegotiation. */ - mdio_write(dev, np->phys[0], 0, 0x3300); - else + if (np->drv_flags & HasDavicomPhy) + mdio_write(dev, np->phys[0], 0, 0x3300); + } else check_duplex(dev); if (debug) printk(KERN_ERR "%s: MII status changed: Autonegotiation " @@ -1109,7 +1106,7 @@ if (intr_status & IntrStatsMax) { np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); np->stats.rx_missed_errors += readw(ioaddr + RxMissed); - writel(0, RxMissed); + clear_tally_counters(ioaddr); } if (intr_status & IntrTxAbort) { /* Stats counted in Tx-done handler, just restart Tx. */ @@ -1122,7 +1119,8 @@ printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } - if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) { + if ((intr_status & ~(IntrLinkChange | IntrStatsMax | + IntrTxAbort|IntrTxAborted)) && debug) { printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Recovery for other fault sources not known. */ @@ -1140,28 +1138,39 @@ non-critical. */ np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); np->stats.rx_missed_errors += readw(ioaddr + RxMissed); - writel(0, RxMissed); + clear_tally_counters(ioaddr); return &np->stats; } +/* Clears the "tally counters" for CRC errors and missed frames(?). + It has been reported that some chips need a write of 0 to clear + these, for others the counters are set to 1 when written to and + instead cleared when read. So we clear them both ways ... */ +static inline void clear_tally_counters(const long ioaddr) +{ + writel(0, ioaddr + RxMissed); + readw(ioaddr + RxCRCErrs); + readw(ioaddr + RxMissed); +} + /* The big-endian AUTODIN II ethernet CRC calculation. N.B. Do not use for bulk data, use a table-based routine instead. This is common code and should be moved to net/core/crc.c */ static unsigned const ethernet_polynomial = 0x04c11db7U; static inline u32 ether_crc(int length, unsigned char *data) { - int crc = -1; + int crc = -1; - while(--length >= 0) { + while(--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) { crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } - } - return crc; + } + return crc; } static void set_rx_mode(struct device *dev) @@ -1178,6 +1187,8 @@ } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ + writel(0xffffffff, ioaddr + MulticastFilter0); + writel(0xffffffff, ioaddr + MulticastFilter1); rx_mode = 0x0C; } else { struct dev_mc_list *mclist; @@ -1190,7 +1201,7 @@ } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); - rx_mode = 0x08; + rx_mode = 0x0C; } writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig); } @@ -1207,7 +1218,7 @@ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; @@ -1229,32 +1240,39 @@ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", dev->name, readw(ioaddr + ChipCmd)); + del_timer(&np->timer); + + /* Switch to loopback mode to avoid hardware races. */ + writeb(np->tx_thresh | 0x01, ioaddr + TxConfig); + /* Disable interrupts by clearing the interrupt mask. */ writew(0x0000, ioaddr + IntrEnable); /* Stop the chip's Tx and Rx processes. */ writew(CmdStop, ioaddr + ChipCmd); - del_timer(&np->timer); - free_irq(dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_length = 0; + np->rx_ring[i].rx_status = 0; np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (np->rx_skbuff[i]) { #if LINUX_VERSION_CODE < 0x20100 np->rx_skbuff[i]->free = 1; #endif - dev_free_skb(np->rx_skbuff[i]); + dev_kfree_skb(np->rx_skbuff[i]); } np->rx_skbuff[i] = 0; } for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) - dev_free_skb(np->tx_skbuff[i]); + dev_kfree_skb(np->tx_skbuff[i]); np->tx_skbuff[i] = 0; + if (np->tx_buf[i]) { + kfree(np->tx_buf[i]); + np->tx_buf[i] = 0; + } } MOD_DEC_USE_COUNT; @@ -1267,37 +1285,28 @@ int init_module(void) { if (debug) /* Emit version even if no cards detected. */ - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); -#ifdef CARDBUS - register_driver(ðerdev_ops); - return 0; -#else + printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); return pci_etherdev_probe(NULL, pci_tbl); -#endif } void cleanup_module(void) { - -#ifdef CARDBUS - unregister_driver(ðerdev_ops); -#endif + struct device *next_dev; /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_net_dev) { - struct netdev_private *np = - (struct netdev_private *)(root_net_dev->priv); + struct netdev_private *np = (void *)(root_net_dev->priv); unregister_netdev(root_net_dev); -#ifdef VIA_USE_IO +#ifdef USE_IO_OPS release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size); #else iounmap((char *)(root_net_dev->base_addr)); #endif + next_dev = np->next_module; + if (np->priv_addr) + kfree(np->priv_addr); kfree(root_net_dev); - root_net_dev = np->next_module; -#if 0 - kfree(np); /* Assumption: no struct realignment. */ -#endif + root_net_dev = next_dev; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/Config.in linux/drivers/s390/Config.in --- v2.2.18/drivers/s390/Config.in Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/Config.in Sun Mar 25 11:37:35 2001 @@ -53,7 +53,7 @@ if [ "$CONFIG_NETDEVICES" = "y" ]; then comment 'S390 Network devices' tristate 'CTC device support' CONFIG_CTC - bool 'IUCV device support (VM only)' CONFIG_IUCV + tristate 'IUCV device support (VM only)' CONFIG_IUCV tristate 'Dummy net driver support' CONFIG_DUMMY bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET bool 'Token Ring driver support' CONFIG_TR diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/Makefile linux/drivers/s390/Makefile --- v2.2.18/drivers/s390/Makefile Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/Makefile Sun Mar 25 11:37:35 2001 @@ -11,12 +11,13 @@ CFLAGS += O_TARGET := io.o -O_OBJS := ccwcache.o idals.o +O_OBJS := idals.o +OX_OBJS := ccwcache.o M_OBJS := SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \ arch/s390/drivers/misc arch/s390/drivers/net -MOD_SUB_DIRS += ./net ./block +MOD_SUB_DIRS += ./net ./block ./char O_OBJS += block/s390-block.o \ char/s390-char.o \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile --- v2.2.18/drivers/s390/block/Makefile Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/Makefile Sun Mar 25 11:37:35 2001 @@ -4,10 +4,11 @@ O_TARGET := s390-block.o O_OBJS := M_OBJS := -D_OBJS := +MI_OBJS := +MIX_OBJS := ifeq ($(CONFIG_DASD),y) - O_OBJS += dasd.o + OX_OBJS += dasd.o ifeq ($(CONFIG_DASD_ECKD),y) O_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o endif @@ -17,26 +18,20 @@ ifeq ($(CONFIG_DASD_MDSK),y) O_OBJS += dasd_diag.o endif -# ifeq ($(CONFIG_DASD_CKD),y) -# O_OBJS += dasd_ckd.o -# endif endif ifeq ($(CONFIG_DASD),m) M_OBJS += dasd_mod.o - D_OBJS += dasd.o + MIX_OBJS += dasd.o ifeq ($(CONFIG_DASD_ECKD),y) - D_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o + MI_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o endif ifeq ($(CONFIG_DASD_FBA),y) - D_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o + MI_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o endif ifeq ($(CONFIG_DASD_MDSK),y) - D_OBJS += dasd_diag.o + MI_OBJS += dasd_diag.o endif -# ifeq ($(CONFIG_DASD_CKD),y) -# O_OBJS += dasd_ckd.o -# endif endif ifeq ($(CONFIG_MDISK),y) @@ -51,7 +46,7 @@ endif endif -dasd_mod.o: $(D_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ $(D_OBJS) +dasd_mod.o: $(MI_OBJS) $(MIX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c --- v2.2.18/drivers/s390/block/dasd.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/dasd.c Sun Mar 25 11:37:35 2001 @@ -1,9 +1,10 @@ /* * File...........: linux/drivers/s390/block/dasd.c * Author(s)......: Holger Smolinski + * Horst Hummel * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 - + * * History of changes (starts July 2000) * 07/03/00 Adapted code to compile with 2.2 and 2.4 kernels * 07/05/00 Added some missing cases when shutting down a device @@ -36,8 +37,14 @@ * 10/26/00 fixed ITPM PL010261EPA race condition when formatting are the fixes in dasd_do_chanq * 11/21/00 fixed BLKFLSBUF ioctl and dasd_release to flush the buffers + * 01/17/01 fixed PL020234MVE problem accessing DASD 68-127, 133-191,... + * 01/23/01 fixed sleep_on_request to terminate when signal_pending + * 01/25/01 added code for error recovery with PAC'0x1D' = long busy + * 02/08/01 fixed PL020237RMI + * 02/08/01 fixed PL020265TDI */ +#include #include #include #include @@ -96,12 +103,7 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct block_device_operations dasd_device_operations; #endif /* VERSION_CODE */ - -#ifdef MODULE -#define EXPORT_SYMTAB -#include -EXPORT_NO_SYMBOLS; MODULE_AUTHOR ("Holger Smolinski "); MODULE_DESCRIPTION ("Linux on S/390 DASD device driver, Copyright 2000 IBM Corporation"); MODULE_SUPPORTED_DEVICE("dasd"); @@ -113,13 +115,8 @@ EXPORT_SYMBOL (dasd_alloc_request); EXPORT_SYMBOL (dasd_free_request); -#else -#endif /* MODULE */ - /* SECTION: Constant definitions to be used within this file */ -#ifdef PRINTK_HEADER #undef PRINTK_HEADER -#endif #define PRINTK_HEADER DASD_NAME":" #define DASD_QUEUE_LIMIT 10 @@ -252,7 +249,7 @@ static char dasd_parm_string[1024] = {0,}; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17)) static int dasd_setup (char *str) { @@ -280,7 +277,7 @@ #endif /* LINUX_IS_24 */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17)) __setup("dasd=", dasd_setup); #endif /* LINUX_IS_24 */ @@ -476,7 +473,7 @@ * void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) */ -static void +void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) { if (q->head != NULL) { @@ -493,7 +490,7 @@ * void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) */ -static void +void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) { cqr->next = q->head; @@ -501,14 +498,17 @@ if (q->tail == NULL) q->tail = cqr; q->queued_requests++; - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED); + + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_FILLED, + CQR_STATUS_QUEUED); } /* * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) */ -static int +int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) { ccw_req_t *prev; @@ -776,9 +776,8 @@ int retries = DASD_SSCH_RETRIES; dasd_device_t *device = cqr->device; int irq, devno; - int devindex, partn; + int devindex; major_info_t *major_info; - struct request *req; if (!cqr) { printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function"); @@ -786,10 +785,9 @@ } irq = device->devinfo.irq; devno = device->devinfo.devno; - req = (struct request *) cqr->req; - devindex = devindex_from_kdev_t (req->rq_dev); + devindex = devindex_from_devno (devno); major_info = major_info_from_devindex (devindex); - partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1); + if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) { printk (KERN_WARNING PRINTK_HEADER "0x%04X on sch %d = /dev/%s (%d:%d)" @@ -801,10 +799,12 @@ cqr->magic, *(long *) device->discipline->name); return -EINVAL; } - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_QUEUED, + CQR_STATUS_IN_IO); do { asm volatile ("STCK %0":"=m" (cqr->startclk)); - rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options); + rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options); switch (rc) { case 0: if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) { @@ -848,7 +848,7 @@ if (rc) { atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, - CQR_STATUS_ERROR); + CQR_STATUS_FAILED); } return rc; } @@ -879,6 +879,10 @@ schedule (); s390irq_spin_lock_irqsave (device->devinfo.irq, flags); cs = atomic_read (&req->status); + if ( signal_pending(current) ) { + rc = -ERESTARTSYS; + break; + } } while ( ! (cs & CQR_STATUS_FINISHED) ); /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */ remove_wait_queue (&device->wait_q, &wait); @@ -1178,189 +1182,216 @@ printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Failing to start I/O operation with rc %d\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc); + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, rc); switch (rc) { case EBUSY: if (cqr->retries--) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:" " retrying ... %d retries left\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, cqr->retries); break; } default:{ /* Fallthrough ?? */ printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Giving up this request!\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_QUEUED, - CQR_STATUS_FAILED | CQR_STATUS_FINISHED); + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); break; } } } break; case CQR_STATUS_IN_IO:{ - unsigned long long now; - unsigned long long delta; - - asm volatile ("STCK %0":"=m" (now)); - if (cqr->expires && cqr->startclk && - cqr->expires < now) { - delta = cqr->expires - cqr->startclk; - printk (KERN_ERR PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr); - cqr->expires += delta; + unsigned long long now; + unsigned long long delta; + + asm volatile ("STCK %0":"=m" (now)); + if (cqr->expires && cqr->startclk && + cqr->expires < now) { + delta = cqr->expires - cqr->startclk; + printk (KERN_ERR PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " I/O operation outstanding longer than 0x%08lx%08lx usecs on req %p\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr); + cqr->expires += delta; #if 0 - if ( cqr->retries-- ) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " waiting %d more times\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); - cqr->expires += delta; - break; - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " You should disable that device by issueing '@#?!'\n", /* FIXME */ - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); - halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT); - break; - } + if ( cqr->retries-- ) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " waiting %d more times\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); + cqr->expires += delta; + break; + } else { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " You should disable that device by issueing '@#?!'\n", /* FIXME */ + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); + atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); + halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT); + break; + } #endif - } - break; + } + break; } case CQR_STATUS_ERROR:{ - dasd_erp_action_fn_t erp_action; - ccw_req_t *erp_cqr = NULL; - - if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) { - atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED); - next = cqr; - } else if ( cqr -> retries-- && - cqr -> refers == NULL && - discipline -> erp_action != NULL && - (erp_action = discipline->erp_action (cqr)) != NULL && - (erp_cqr = erp_action (cqr)) != NULL ) { + dasd_erp_action_fn_t erp_action; + ccw_req_t *erp_cqr = NULL; + + if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) { + atomic_compare_and_swap_debug(&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + next = cqr; + } else if (discipline -> erp_action != NULL && + (erp_action = discipline->erp_action (cqr)) != NULL && + (erp_cqr = erp_action (cqr)) != NULL ) { + + if (erp_cqr != cqr){ + dasd_chanq_enq_head (qp, erp_cqr); - next = erp_cqr; /* prefer execution of erp ccw */ - } else { - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - next = cqr; } - break; - } + cqr->retries--; + next = erp_cqr; /* prefer execution of erp ccw */ + + } else { + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + next = cqr; + } + break; + } case CQR_STATUS_DONE:{ - dasd_erp_postaction_fn_t erp_postaction; - next = cqr->next; - asm volatile ("STCK %0":"=m" (cqr->endclk)); - if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if ( discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing successful error recovery action using %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); - erp_postaction (cqr, 1); - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " No procedure to postprocess error recovery action" - " giving up request", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - } + dasd_erp_postaction_fn_t erp_postaction; + next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); + if (cqr->refers && cqr->function) { /* we deal with an ERP */ + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " postprocessing successful ERA using %p\n", + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, erp_postaction); + cqr = erp_postaction (cqr); + next = cqr; + } else { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " No procedure to postprocess ERA - " + " giving up request", + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + atomic_dec (&device->queue.dirty_requests); dasd_chanq_deq (&device->queue, cqr); dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else if ( cqr->req ) { - dasd_end_request (cqr->req, 1); + } + } else if ( cqr->req ) { + dasd_end_request (cqr->req, 1); #ifdef DASD_PROFILE - dasd_profile_add (cqr); + dasd_profile_add (cqr); #endif /* DASD_PROFILE */ - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else { - /* during format we don't have the request structure */ - /* notify sleeping task about finished postprocessing */ - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_DONE, - CQR_STATUS_DONE | CQR_STATUS_FINISHED); - dasd_chanq_deq (&device->queue, cqr); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ + } else { + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_DONE, + CQR_STATUS_DONE | CQR_STATUS_FINISHED); + dasd_chanq_deq (&device->queue, cqr); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - wake_up (&device->wait_q); + wake_up (&device->wait_q); #else - if (device->wait_q) { - wake_up (&device->wait_q); - } -#endif /* LINUX_IS_24 */ + if (device->wait_q) { + wake_up (&device->wait_q); } - break; - } +#endif /* LINUX_IS_24 */ + } + break; + } case CQR_STATUS_FAILED:{ - dasd_erp_postaction_fn_t erp_postaction; - next = cqr->next; - asm volatile ("STCK %0":"=m" (cqr->endclk)); - if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if ( discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing unsuccessful error recovery action using %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); - erp_postaction (cqr, 0); - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " No procedure to postprocess unsuccessful error recovery action" - " giving up request", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - } + dasd_erp_postaction_fn_t erp_postaction; + next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); + if (cqr->refers && cqr->function) { /* we deal with an ERP */ + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " postprocessing unsuccessful ERA using %p\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); + cqr = erp_postaction (cqr); + next = cqr; + } else { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " No procedure to postprocess unsuccessful ERA - " + " giving up request", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + atomic_dec (&device->queue.dirty_requests); dasd_chanq_deq (&device->queue, cqr); dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else if (cqr->req) { - dasd_end_request (cqr->req, 0); + } + } else if (cqr->req) { + dasd_end_request (cqr->req, 0); #ifdef DASD_PROFILE - dasd_profile_add (cqr); + dasd_profile_add (cqr); #endif /* DASD_PROFILE */ - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else { - /* during format we don't have the request structure */ - /* notify sleeping task about finished postprocessing */ - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_FAILED, - CQR_STATUS_FAILED | CQR_STATUS_FINISHED); - - dasd_chanq_deq (&device->queue, cqr); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ + } else { + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_FAILED, + CQR_STATUS_FAILED | CQR_STATUS_FINISHED); + + dasd_chanq_deq (&device->queue, cqr); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - wake_up (&device->wait_q); + wake_up (&device->wait_q); #else - if (device->wait_q) { - wake_up (&device->wait_q); - } + if (device->wait_q) { + wake_up (&device->wait_q); + } #endif /* LINUX_IS_24 */ - } - break; - } + } + break; + } - default:{ - printk (KERN_WARNING PRINTK_HEADER - "Internal error in " __FILE__ " on line %d." - " inconsistent content of ccw_req_t" - " cqrstatus = %d" - " Pls send this message and your System.map to" - " linux390@de.ibm.com\n", - __LINE__, cqrstatus); - } + case CQR_STATUS_PENDING: + /* just wait */ + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " CQR_STATUS_PENDING - just wait...\n", + devno, irq, device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + break; + + default: + printk (KERN_WARNING PRINTK_HEADER + "Internal error in " __FILE__ " on line %d." + " inconsistent content of ccw_req_t" + " cqrstatus = %d" + " Pls send this message and your System.map to" + " linux390@de.ibm.com\n", + __LINE__, cqrstatus); + } s390irq_spin_unlock_irqrestore (irq, flags); } while ((cqr = next) != NULL); @@ -1369,6 +1400,56 @@ return; } +/* + * DASD_HANDLE_STATE_CHANGE_PENDING + * + * DESCRIPTION + * Handles the state change pending interrupt. + * Search for the device related request queue and check if the first + * cqr in queue in in status 'CQR_STATUE_PENDING'. + * If so the status is set to 'CQR_STATUS_QUEUED' and the bh is + * scheduled. + * + * PARAMETER + * stat device status of state change pending interrupt. + */ +void +dasd_handle_state_change_pending (devstat_t *stat) +{ + dasd_device_t *device; + ccw_req_t *cqr; + int devindex; + + devindex = devindex_from_devno (stat->devno); + if (devindex < 0) { + return; + } + + device = find_dasd_device (devindex); + if (device == NULL) { + return; + } + + /* re-activate first request in queue */ + cqr = device->queue.head; + + if (cqr != NULL && + atomic_read(&cqr->status) == CQR_STATUS_PENDING ) { + dasd_device_t *device = cqr->device; + + DASD_MESSAGE (KERN_INFO, device, + "%s", + "device request queue restarted by " + "SCP interrupt\n"); + + del_timer(&device->timer); + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); + dasd_schedule_bh(); + } +} /* end dasd_handle_state_change_pending */ + void dasd_int_handler (int irq, void *ds, struct pt_regs *regs) { @@ -1380,8 +1461,7 @@ dasd_device_t *device; int devno = -1, devindex = -1; -#undef ERP_DEBUG -#ifdef ERP_DEBUG +#ifdef ERP_DEBUG /* #define ERP_DEBUG is done in dasd.h */ static int counter = 0; #endif @@ -1389,12 +1469,23 @@ PRINT_ERR ("handler called without devstat"); return; } + ip = stat->intparm; if (!ip) { /* no intparm: unsolicited interrupt */ PRINT_INFO ("%04X caught unsolicited interrupt\n", stat->devno); + + /* check for state change pending interrupt */ + if (stat->dstat & (DEV_STAT_ATTENTION | + DEV_STAT_DEV_END | + DEV_STAT_UNIT_EXCEP )) { + + dasd_handle_state_change_pending (stat); + } + return; } + if (ip & 0x80000001) { PRINT_INFO ("%04X caught spurious interrupt with parm %08x\n", stat->devno, ip); @@ -1436,20 +1527,63 @@ return; } asm volatile ("STCK %0":"=m" (cqr->stopclk)); - if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) && - stat->cstat == 0x00 && - stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || - (device->discipline->examine_error && - (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) { #ifdef ERP_DEBUG - if ( ++counter % 137 == 0 ) { - printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from\n"); + if ((++counter % 937 >= 100) && + ( counter % 937 <= 110) && + ( counter < 5000 ) && + ( counter > 2000 ) ){ + static int fake_count = 0; + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); + printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count); + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); era = dasd_era_recover; stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; stat->dstat |= 0x02; - goto error_fake_done; +// reset notification + { + char *sense = stat->ii.sense.data; + char buffer[100]; + memset(sense,0,32); + sprintf(buffer,"CPU ALL TR IO %X INST INT CCW", devno); + cpcmd(buffer,NULL,NULL); + sense[0]=0x10; + sense[4]=0x21; + sense[7]=0x9; + sense[15]=0x4; + sense[16]=0xe5; + sense[18]=0x43; + sense[19]=0xfb; + sense[20]=0x54; + sense[22]=0x0f; + sense[23]=0x09; + sense[26]=0x40; + sense[27]=0xe0; + } +// sense 32 +// { +// char *sense = stat->ii.sense.data; +// sense [25] = 0x1D; +// sense [27] = 0x00; +// //sense [25] = (fake_count % 256); //0x1B; +// //sense [27] = 0x00; +// } +// sense 24 +// { +// char *sense = stat->ii.sense.data; +// sense [0] = (counter % 0xFF); //0x1B; +// sense [1] = ((counter * 7) % 0xFF); //0x1B; +// sense [2] = (fake_count % 0xFF); //0x1B; +// sense [27] = 0x80; +// } } #endif + + if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) && + stat->cstat == 0x00 && + stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || + (device->discipline->examine_error && + (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) { + atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE); atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, @@ -1462,9 +1596,6 @@ } } } else { /* only visited in case of error ! */ -#ifdef ERP_DEBUG - error_fake_done: -#endif if (cqr->dstat == NULL) cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC); if (cqr->dstat) { @@ -1512,7 +1643,12 @@ ccw_req_t * default_erp_action (ccw_req_t * cqr) { - ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0); + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); + if ( !erp ) { + printk(KERN_WARNING PRINTK_HEADER + "unable to allocate ERP request\n"); + return NULL; + } erp->cpaddr->cmd_code = CCW_CMD_TIC; erp->cpaddr->cda = (__u32)cqr -> cpaddr; @@ -1528,30 +1664,97 @@ return erp; } -int -default_erp_postaction (ccw_req_t * cqr, int success) +/* + * DEFAULT_ERP_POSTACTION + * + * DESCRIPTION + * Frees all ERPs of the current ERP Chain and set the status + * of the original CQR either to CQR_STATUS_DONE if ERP was successful + * or to CQR_STATUS_FAILED if ERP was NOT successful. + * + * PARAMETER + * erp current erp_head + * + * RETURN VALUES + * cqr pointer to the original CQR + */ +ccw_req_t * +default_erp_postaction (ccw_req_t * erp) { - if (cqr->refers == NULL || cqr->function == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "ERP postaction called for non ERP cqr\n"); - return -EINVAL; + ccw_req_t *cqr = NULL, *free_erp = NULL; + dasd_device_t *device = NULL; + int success; + + device = (dasd_device_t *) (erp->device); + + if (atomic_read(&erp->status) == CQR_STATUS_DONE) + success = 1; + else + success = 0; + +#ifdef ERP_DEBUG + + /* print current erp_chain */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP postaction called for erp chain:\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p with erp function %p\n", + temp_erp, + temp_erp->refers, + temp_erp->function ); + } + } + +#endif /* ERP_DEBUG*/ + + if (erp->refers == NULL || erp->function == NULL) { + panic (PRINTK_HEADER "Programming error in ERP! Postaction called " + "for invalid ERPt\n"); + } + + /* free all ERPs - but NOT the original cqr */ + while (erp->refers != NULL) { + free_erp = erp; + erp = erp->refers; + /* remove the request from the device queue */ + dasd_chanq_deq (&device->queue, free_erp); + /* free the finished erp request */ + dasd_free_request (free_erp); + } + + /* save ptr to original cqr */ + cqr = erp; + + /* set corresponding status to original cqr */ + if (success) { + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + } else { + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); } - if (cqr->function != default_erp_action) { - printk (KERN_WARNING PRINTK_HEADER - "default ERP postaction called for non default ERP cqr\n"); - return -EINVAL; + +#ifdef ERP_DEBUG + /* print current erp_chain */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP postaction finished with remaining chain:\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { + printk (KERN_WARNING PRINTK_HEADER + " erp %p refers to %p \n", + temp_erp, temp_erp->refers); + } } - if ( success ) { - atomic_compare_and_swap_debug (&cqr->refers->status, - CQR_STATUS_ERROR, - CQR_STATUS_DONE); - } else { - atomic_compare_and_swap_debug (&cqr->refers->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); - } - return 0; -} +#endif /* ERP_DEBUG */ + + return cqr; +} /* end default_erp_postaction */ /* SECTION: The helpers of the struct file_operations */ @@ -1641,7 +1844,7 @@ while ((!rc ) && ((req = device->discipline->format_device (device, &temp)) != NULL ) ) { - if ( rc=sleep_on_req(req) ) { + if ( (rc=sleep_on_req(req)) != 0 ) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Formatting failed with rc = %d\n", @@ -1985,10 +2188,6 @@ major_info_t *major_info = NULL; major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL); if (major_info) { - major_info_t *temp = dasd_major_info; - while (temp->next) - temp = temp->next; - temp->next = major_info; memset (major_info, 0, sizeof (major_info_t)); major_info->read_ahead = 8; @@ -1998,7 +2197,8 @@ major_info->gendisk.minor_shift = DASD_PARTN_BITS; major_info->gendisk.max_p = 1 << DASD_PARTN_BITS; #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - major_info->gendisk.max_nr= 1 << DASD_PARTN_BITS; + /* HSM changed for PL020234MVE */ + major_info->gendisk.max_nr= DASD_PER_MAJOR; #endif /* LINUX_IS_24 */ major_info->gendisk.nr_real=DASD_PER_MAJOR; } @@ -2013,6 +2213,7 @@ #endif /* LINUX_IS_24 */ int rc = 0; int major; + int need_insert=0; if (major_info == NULL) { major_info = get_new_major_info (); @@ -2024,6 +2225,7 @@ printk (KERN_INFO PRINTK_HEADER "Created another major number\n"); } + need_insert=1; //insert new major info into dasd_major_info later } major = major_info->gendisk.major; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) @@ -2052,6 +2254,13 @@ } } + /* Insert the new major info into dasd_major_info if needed */ + if (need_insert) { + major_info_t *temp = dasd_major_info; + while (temp->next) + temp = temp->next; + temp->next = major_info; + } major_info->dasd_device = (dasd_device_t **) kmalloc( DASD_PER_MAJOR * sizeof(dasd_device_t*), GFP_ATOMIC); memset ( major_info->dasd_device ,0,DASD_PER_MAJOR * sizeof(dasd_device_t*)); @@ -2153,15 +2362,15 @@ index = devindex_from_kdev_t (MKDEV(hd->major,index<minor_shift)); } third = index % 26; - second = (index / 26) % 27; - first = ((index / 26) / 27) % 27; + second = ((index-26) / 26) % 26; + first = (((index-702) / 26) / 26) % 26; len = sprintf (str, "dasd"); - if (first) { - len += sprintf (str + len, "%c", first + 'a' - 1 ); + if (index>701) { + len += sprintf (str + len, "%c", first + 'a' ); } - if (second) { - len += sprintf (str + len, "%c", second + 'a' - 1 ); + if (index>25) { + len += sprintf (str + len, "%c", second + 'a' ); } len += sprintf (str + len, "%c", third + 'a' ); if (partition) { @@ -2307,6 +2516,7 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) init_waitqueue_head(&device->wait_q); #endif /* KERNEL_VERSION */ + init_timer(&device->timer); minor = MINOR(device->kdev); current_level = atomic_read (&device->level); if (desired_level > current_level) { @@ -2412,7 +2622,7 @@ if (major_info->blksize_size[minor + i] < 1024 ) major_info->blksize_size[minor + i] = 1024; - major_info->max_sectors[minor + i] = 200 << device->sizes.s2b_shift; /* FIXME !!! */ + major_info->max_sectors[minor + i] = device->discipline->max_blocks << device->sizes.s2b_shift; } atomic_compare_and_swap_debug (&device->level, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, @@ -2509,6 +2719,14 @@ int len; } tempinfo_t; +void dasd_fill_inode (struct inode* inode, int fill) { + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct proc_dir_entry *dasd_proc_root_entry = NULL; #else @@ -2521,7 +2739,8 @@ nlink:1, uid:0, gid:0, - size:0 + size:0, + fill_inode:dasd_fill_inode }; #endif /* KERNEL_VERSION */ static struct proc_dir_entry* dasd_devices_entry; @@ -2604,6 +2823,9 @@ temp = temp->next; } info->len=len; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return rc; } @@ -2661,6 +2883,9 @@ if ( p_info->data ) vfree(p_info->data); vfree(p_info); } +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif return rc; } @@ -2858,9 +3083,7 @@ dasd_unregister_major(major_info); } } - emergency_failed: dasd_cleanup_emergency_req(); - failed: printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n"); out: printk (KERN_INFO PRINTK_HEADER "initialization finished\n"); @@ -2924,9 +3147,7 @@ int init_module ( void ) { - int rc=0; return dasd_init(); - return rc; } void diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd.h linux/drivers/s390/block/dasd.h --- v2.2.18/drivers/s390/block/dasd.h Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/dasd.h Sun Mar 25 11:37:35 2001 @@ -1,9 +1,13 @@ ccw_req_t *default_erp_action (ccw_req_t *); -int default_erp_postaction ( ccw_req_t *, int); int dasd_start_IO (ccw_req_t * cqr); void dasd_int_handler (int , void *, struct pt_regs *); ccw_req_t * dasd_alloc_request (char *, int , int ) ; void dasd_free_request(ccw_req_t *); int (*genhd_dasd_name)(char*,int,int,struct gendisk*); int dasd_oper_handler ( int irq, devreg_t *devreg ); + +dasd_era_t dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat); +dasd_era_t dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat); +dasd_era_t dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat); +dasd_era_t dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_3370_erp.c linux/drivers/s390/block/dasd_3370_erp.c --- v2.2.18/drivers/s390/block/dasd_3370_erp.c Sun Mar 25 11:13:11 2001 +++ linux/drivers/s390/block/dasd_3370_erp.c Sun Mar 25 11:37:35 2001 @@ -5,6 +5,7 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 */ +#include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c --- v2.2.18/drivers/s390/block/dasd_3990_erp.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/dasd_3990_erp.c Sun Mar 25 11:37:35 2001 @@ -1,46 +1,31 @@ /* * File...........: linux/drivers/s390/block/dasd_3990_erp.c - * Author(s)......: Holger Smolinski - * Horst Hummel + * Author(s)......: Horst Hummel + * Holger Smolinski * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 */ +#include #include +#include #include +#include +#include +#include "dasd_eckd.h" +#include "dasd_3990_erp.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER -#define PRINTK_HEADER "dasd_erp(3990)" -#endif /* PRINTK_HEADER */ +#endif /* PRINTK_HEADER */ +#define PRINTK_HEADER "dasd_erp(3990): " + /* - * DASD_3990_ERP_EXAMINE_32 - * - * DESCRIPTION - * Checks only for fatal/no/recoverable error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for recoverable others. + ***************************************************************************** + * SECTION ERP EXAMINATION + ***************************************************************************** */ -dasd_era_t -dasd_3990_erp_examine_32 (char *sense) -{ - - switch (sense[25]) { - case 0x00: - return dasd_era_none; - case 0x01: - return dasd_era_fatal; - default: - return dasd_era_recover; - } - -} /* end dasd_3990_erp_examine_32 */ /* * DASD_3990_ERP_EXAMINE_24 @@ -52,7 +37,7 @@ * * Each bit configuration leading to an action code 2 (Exit with * programming error or unusual condition indication) - * and 10 (disabled interface) are handled as fatal error´s. + * are handled as fatal error´s. * * All other configurations are handled as recoverable errors. * @@ -64,31 +49,58 @@ dasd_3990_erp_examine_24 (char *sense) { - /* check for 'Command Recejct' whithout environmental data present */ - if (sense[0] & 0x80) { - if (sense[2] &0x10){ - return dasd_era_recover; - } else { - return dasd_era_fatal; - } - } - - /* check for 'Invalid Track Format' whithout environmental data present */ - if (sense[1] & 0x40) { - if (sense[2] &0x10){ - return dasd_era_recover; - } else { - return dasd_era_fatal; - } + /* check for 'Command Recejct' which is always a fatal error */ + if (sense[0] & SNS0_CMD_REJECT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } + } + /* check for 'Invalid Track Format' */ + if (sense[1] & SNS1_INV_TRACK_FORMAT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } } /* check for 'No Record Found' */ - if (sense[1] & 0x08) { + if (sense[1] & SNS1_NO_REC_FOUND) { return dasd_era_fatal; } /* return recoverable for all others */ return dasd_era_recover; -} /* END dasd_3990_erp_examine_24 */ +} /* END dasd_3990_erp_examine_24 */ + +/* + * DASD_3990_ERP_EXAMINE_32 + * + * DESCRIPTION + * Checks only for fatal/no/recoverable error. + * A detailed examination of the sense data is done later outside + * the interrupt handler. + * + * RETURN VALUES + * dasd_era_none no error + * dasd_era_fatal for all fatal (unrecoverable errors) + * dasd_era_recover for recoverable others. + */ +dasd_era_t +dasd_3990_erp_examine_32 (char *sense) +{ + + switch (sense[25]) { + case 0x00: + return dasd_era_none; + case 0x01: + return dasd_era_fatal; + default: + return dasd_era_recover; + } + +} /* end dasd_3990_erp_examine_32 */ /* * DASD_3990_ERP_EXAMINE @@ -118,19 +130,1134 @@ return dasd_era_none; /* distinguish between 24 and 32 byte sense data */ - if (sense[27] & 0x80) { + if (sense[27] & DASD_SENSE_BIT_0) { + + /* examine the 24 byte sense data */ + return dasd_3990_erp_examine_24 (sense); + + } else { /* examine the 32 byte sense data */ return dasd_3990_erp_examine_32 (sense); + } /* end distinguish between 24 and 32 byte sense data */ + +} /* END dasd_3990_erp_examine */ + +/* + ***************************************************************************** + * SECTION ERP HANDLING + ***************************************************************************** + */ +/* + ***************************************************************************** + * 24 and 32 byte sense ERP functions + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_BLOCK_QUEUE + * + * DESCRIPTION + * Block the given device request queue to prevent from further + * processing until the started timer has expired or an related + * interrupt was received. + * + * PARAMETER + * erp request to be blocked + * expires time to wait until restart (in seconds) + * + * RETURN VALUES + * void + */ +void +dasd_3990_erp_block_queue (ccw_req_t *erp, + unsigned long expires) +{ + + dasd_device_t *device = erp->device; + + DASD_MESSAGE (KERN_INFO, device, + "blocking request queue for %is", + (int) expires); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_PENDING); + + /* restart queue after some time */ + device->timer.function = dasd_3990_erp_restart_queue; + device->timer.data = (unsigned long) erp; + device->timer.expires = jiffies + (expires * HZ); + add_timer(&device->timer); + + /* restart queue using int handler routing - just for testing - TDB */ + /* insert "void dasd_handle_state_change_pending (devstat_t *stat);" to dasd.h */ +// device->timer.function = dasd_handle_state_change_pending; +// device->timer.data = (unsigned long) &device->dev_status; +// device->timer.expires = jiffies + (expires * HZ); +// add_timer(&device->timer); + +} /* end dasd_3990_erp_block_queue */ + +/* + * DASD_3990_ERP_RESTART_QUEUE + * + * DESCRIPTION + * Restarts request currently in status PENDING. + * This has to be done if either an related interrupt has received, or + * a timer has expired. + * + * + * PARAMETER + * erp pointer to the PENDING ERP + * + * RETURN VALUES + * void + * + */ +void +dasd_3990_erp_restart_queue (unsigned long erp) +{ + ccw_req_t *cqr = (void *) erp; + dasd_device_t *device = cqr->device; + unsigned long flags; + + /* TBD delete */ + DASD_MESSAGE (KERN_INFO, device, + "%s irq %d erp %p", + "dasd_3990_erp_restart_queue entered",device->devinfo.irq, erp); + /* get the needed locks to modify the request queue */ + s390irq_spin_lock_irqsave (device->devinfo.irq, + flags); + + /* 'restart' the device queue */ + if (atomic_read(&cqr->status) == CQR_STATUS_PENDING){ + + DASD_MESSAGE (KERN_INFO, device, + "%s", + "request queue restarted by MIH"); + + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); +} + + /* release the lock */ + s390irq_spin_unlock_irqrestore (device->devinfo.irq, + flags); + dasd_schedule_bh(); + +} /* end dasd_3990_erp_restart_queue */ + +/* + * DASD_3990_ERP_ALTERNATE_PATH + * + * DESCRIPTION + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp modified pointer to the ERP + * + */ +void +dasd_3990_erp_alternate_path (ccw_req_t *erp) +{ + + dasd_device_t *device = erp->device; + int irq = device->devinfo.irq; + + /* dissable current channel path - this causes the use of an other + channel path if there is one.. */ + + DASD_MESSAGE (KERN_WARNING, device, + "disable lpu %x", + erp->dstat->lpum); + + /* try alternate valid path */ + erp->lpm &= ~(erp->dstat->lpum); + erp->options |= DOIO_VALID_LPM; /* use LPM for DO_IO */ + + if ((erp->lpm & ioinfo[irq]->opm) != 0x00) { + + DASD_MESSAGE (KERN_WARNING, device, + "try alternate lpm %x", + erp->lpm); + + /* reset status to queued to handle the request again... */ + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + erp->retries = 1; + } else { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "No alternate channel path left -> " + "permanent error"); + + /* post request with permanent error */ + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); - /* examine the 24 byte sense data */ - return dasd_3990_erp_examine_24 (sense); + } + +} /* end dasd_3990_erp_alternate_path */ + +/* + * DASD_3990_ERP_ACTION_1 + * + * DESCRIPTION + * Setup ERP to do the ERP action 1 (see Reference manual). + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * Note: duplex handling is not implemented (yet). + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_1 (ccw_req_t * erp) +{ + + erp->function = dasd_3990_erp_action_1; + + // cpcmd ("TRACE IO 153 INST INT CCW", NULL, 0); + + dasd_3990_erp_alternate_path (erp); + + return erp; + +} /* end dasd_3990_erp_action_1 */ + +/* + * DASD_3990_ERP_ACTION_4 + * + * DESCRIPTION + * Setup ERP to do the ERP action 4 (see Reference manual). + * Set the current request to PENDING to block the CQR queue for that device + * until the state change interrupt appears. + * Use a timer (20 seconds) to retry the cqr if the interrupt is still missing. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_4 (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + /* first time set initial retry counter and erp_function */ + /* and retry once without waiting for state change pending */ + /* interrupt (this enables easier enqueing of the cqr) */ + if (erp->function != dasd_3990_erp_action_4) { + erp->retries = 255; /* TBD 255 */ + erp->function = dasd_3990_erp_action_4; + + } else { + + if (sense[25] & 0x1D) { /* state change pending */ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "waiting for state change pending " + "int"); + + dasd_3990_erp_block_queue (erp, + 60); /* TBD change to 30 */ + + } else { + /* no state change pending - retry */ + printk (KERN_WARNING PRINTK_HEADER + "no state change pending - retry\n"); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } + + return erp; + +} /* end dasd_3990_erp_action_4 */ + +/* + ***************************************************************************** + * 24 byte sense ERP functions (only) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_EQUIP_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Equipment Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_equip_check (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_equip_check; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment Check - environmental data present"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } + + return erp; + +} /* end dasd_3990_erp_equip_check */ + +/* + * DASD_3990_ERP_DATA_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Data Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_data_check (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_data_check; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check recovered secondary " + "addr of duplex pair"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } + + return erp; + +} /* end dasd_3990_erp_data_check */ + + +/* + * DASD_3990_ERP_INV_FORMAT + * + * DESCRIPTION + * Handles 24 byte 'Invalid Track Format' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_inv_format (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inv_format; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Track format error when destaging or " + "staging data"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } + + return erp; + +} /* end dasd_3990_erp_inv_format */ + +/* + * DASD_3990_ERP_ENV_DATA + * + * DESCRIPTION + * Handles 24 byte 'Environmental-Data Present' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_env_data (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_env_data; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Environmental data present"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + + return erp; + +} /* end dasd_3990_erp_env_data */ + +/* + * DASD_3990_ERP_INSPECT_24 + * + * DESCRIPTION + * Does a detailed inspection of the 24 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp pointer to the (addtitional) ERP + */ +ccw_req_t * +dasd_3990_erp_inspect_24 ( ccw_req_t * erp, + char *sense) +{ + ccw_req_t *erp_filled = NULL; + + /* Check sense for .... */ + /* 'Equipment Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_EQUIPMENT_CHECK)) { + erp_filled = dasd_3990_erp_equip_check (erp, + sense); + } + /* 'Data Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_DATA_CHECK)) { + erp_filled = dasd_3990_erp_data_check (erp, + sense); + } + /* 'Invalid Track Format' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_INV_TRACK_FORMAT)) { + erp_filled = dasd_3990_erp_inv_format (erp, + sense); + } + /* 'Environmental Data' */ + if ((erp_filled == NULL) && + (sense[2] & SNS2_ENV_DATA_PRESENT)) { + erp_filled = dasd_3990_erp_env_data (erp, + sense); + } + + /* other (unknown/not jet implemented) error - do default ERP */ + if (erp_filled == NULL) { + + printk (KERN_WARNING PRINTK_HEADER + "default ERP taken\n"); + + erp_filled = erp; + } + + return erp_filled; + +} /* END dasd_3990_erp_inspect_24 */ + +/* + ***************************************************************************** + * 32 byte sense ERP functions (only) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_ACTION_1B_32 + * + * DESCRIPTION + * Handles 32 byte 'Action 1B' of Single Program Action Codes. + * A write operation could not be finished because of an unexpected + * condition. + * The already created 'default erp' is used to get the link to + * the erp chain, but it can not be used for this recovery + * action because it contains no DE/LO data space. + * + * PARAMETER + * default_erp already created default erp. + * sense current sense data + * RETURN VALUES + * erp new erp or default_erp in case of error + */ +ccw_req_t * +dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, + char *sense) +{ + dasd_device_t *device = default_erp->device; + ccw_req_t *cqr; + ccw_req_t *erp; + __u32 cpa; + DE_eckd_data_t *DE_data; + char *LO_data; /* LO_eckd_data_t */ + ccw1_t *ccw; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write not finsihed because of unexpected condition"); + + /* determine the original cqr */ + cqr = default_erp; + while (cqr->refers != NULL){ + cqr = cqr->refers; + } + + /* determine the address of the CCW to be restarted */ + cpa = default_erp->refers->dstat->cpa; + + if (cpa == 0) { + cpa = (__u32) cqr->cpaddr; + } + + if (cpa == 0) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to determine address of the CCW " + "to be restarted"); + + atomic_compare_and_swap_debug (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* Build new ERP request including DE/LO */ + erp = dasd_alloc_request ((char *) &cqr->magic, + 2 + 1, /* DE/LO + TIC */ + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + if ( !erp ) { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to allocate ERP"); + + atomic_compare_and_swap_debug (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* use original DE */ + DE_data = erp->data; + memcpy (DE_data, + cqr->data, + sizeof (DE_eckd_data_t)); + + /* create LO */ + LO_data = erp->data + sizeof (DE_eckd_data_t); + + if ((sense[3] == 0x01) && + (LO_data[1] & 0x01) ){ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "BUG - this should not happen"); + //BUG(); /* check for read count suffixing n.a. */ + } + + LO_data[0] = sense[7]; /* operation */ + LO_data[1] = sense[8]; /* auxiliary */ + LO_data[2] = sense[9]; + LO_data[3] = sense[3]; /* count */ + LO_data[4] = sense[29]; /* seek_addr.cyl */ + LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ + LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ + + memcpy (&(LO_data[8]), &(sense[11]), 8); + + /* create DE ccw */ + ccw = erp->cpaddr; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + ccw->cda = (__u32) __pa (DE_data); + + /* create LO ccw */ + ccw++; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + ccw->cda = (__u32) __pa (LO_data); + + /* TIC to the failed ccw */ + ccw++; + ccw->cmd_code = CCW_CMD_TIC; + ccw->cda = cpa; + + /* fill erp related fields */ + erp->function = dasd_3990_erp_action_1B_32; + erp->refers = default_erp->refers; + erp->device = device; + erp->magic = default_erp->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 2; + + atomic_set(&erp->status, + CQR_STATUS_FILLED); + + /* remove the default erp */ + dasd_free_request (default_erp); + + return erp; + +} /* end dasd_3990_erp_action_1B_32 */ + + +/* + * DASD_3990_ERP_INSPECT_32 + * + * DESCRIPTION + * Does a detailed inspection of the 32 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp_filled pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_inspect_32 ( ccw_req_t *erp, + char *sense ) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inspect_32; + + if (sense[25] & DASD_SENSE_BIT_0) { + + /* compound program action codes (byte25 bit 0 == '1') */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP taken\n"); + + } else { + + /* single program action codes (byte25 bit 0 == '0') */ + switch (sense[25]) { + + case 0x1B: /* unexpected condition during write */ + + erp = dasd_3990_erp_action_1B_32 (erp, + sense); +#ifdef ERP_DEBUG + /* TBD */ +// cpcmd ("STOP", NULL, 0); +#endif + break; + + case 0x1D: /* state-change pending */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "A State change pending condition exists " + "for the subsystem or device"); + + erp = dasd_3990_erp_action_4 (erp, + sense); +// cpcmd ("STOP", NULL, 0); + break; + + default: /* all others errors */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP taken\n"); + } + } + + return erp; + +} /* end dasd_3990_erp_inspect_32 */ + +/* + ***************************************************************************** + * main ERP control fuctions (24 and 32 byte sense) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_INSPECT + * + * DESCRIPTION + * Does a detailed inspection for sense data by calling either + * the 24-byte or the 32-byte inspection routine. + * + * PARAMETER + * erp pointer to the currently created default ERP + * RETURN VALUES + * erp_new contens was possibly modified + */ +ccw_req_t * +dasd_3990_erp_inspect (ccw_req_t * erp) +{ + ccw_req_t *erp_new = NULL; + /* sense data are located in the refers record of the */ + /* already set up new ERP ! */ + char *sense = erp->refers->dstat->ii.sense.data; + + /* distinguish between 24 and 32 byte sense data */ + if (sense[27] & DASD_SENSE_BIT_0) { + + /* inspect the 24 byte sense data */ + erp_new = dasd_3990_erp_inspect_24 (erp, + sense); + + } else { + + /* inspect the 32 byte sense data */ + erp_new = dasd_3990_erp_inspect_32 (erp, + sense); + + } /* end distinguish between 24 and 32 byte sense data */ + + return erp_new; + +} /* END dasd_3990_erp_inspect */ + +/* + * DASD_3990_ERP_ADD_ERP + * + * DESCRIPTION + * This funtion adds an additional request block (ERP) to the head of + * the given cqr (or erp). + * This erp is initialized as an default erp (retry TIC) + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_add_erp (ccw_req_t * cqr) +{ + /* allocate additional request block */ + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); + if ( !erp ) { + printk( KERN_WARNING PRINTK_HEADER + "unable to allocate ERP request\n" ); + return NULL; + } + + /* initialize request with default TIC to current ERP/CQR */ + erp->cpaddr->cmd_code = CCW_CMD_TIC; + erp->cpaddr->cda = ((__u32) cqr->cpaddr); + erp->function = dasd_3990_erp_add_erp; + erp->refers = cqr; + erp->device = cqr->device; + erp->magic = cqr->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 255; + + atomic_set(&erp->status, + CQR_STATUS_FILLED); + + return erp; +} + +/* + * DASD_3990_ERP_ADDITIONAL_ERP + * + * DESCRIPTION + * An additional ERP is needed to handle the current error. + * Add ERP to the head of the ERP-chain containing the ERP processing + * determined based on the sense data. + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_additional_erp (ccw_req_t * cqr) +{ + + ccw_req_t *erp = NULL; + + /* add erp and initialize with default TIC */ + erp = dasd_3990_erp_add_erp (cqr); + + /* inspect sense, determine specific ERP if possible */ + erp = dasd_3990_erp_inspect (erp); + + return erp; + +} /* end dasd_3990_erp_additional_erp */ + +/* + * DASD_3990_ERP_ERROR_MATCH + * + * DESCRIPTION + * check if the the device status of the given cqr is the same. + * This means that the failed CCW and the relevant sense data + * must match. + * I don't distinguish between 24 and 32 byte sense becaus in case of + * 24 byte sense byte 25 and 27 is set as well. + * + * PARAMETER + * cqr1 first cqr, which will be compared with the + * cqr2 second cqr. + * + * RETURN VALUES + * match 'boolean' for match found + * returns 1 if match found, otherwise 0. + */ +int +dasd_3990_erp_error_match (ccw_req_t * cqr1, + ccw_req_t * cqr2) +{ + /* check failed CCW */ + if (cqr1->dstat->cpa != + cqr2->dstat->cpa) { + return 0; /* CCW doesn't match */ + + } + /* check sense data; byte 0-2,25,27 */ + if (!((strncmp (cqr1->dstat->ii.sense.data, + cqr2->dstat->ii.sense.data, + 3) == 0) && + (cqr1->dstat->ii.sense.data[27] == + cqr2->dstat->ii.sense.data[27] ) && + (cqr1->dstat->ii.sense.data[25] == + cqr2->dstat->ii.sense.data[25] ) )) { + + return 0; /* sense doesn't match */ + } + return 1; /* match */ + +} /* end dasd_3990_erp_error_match */ + +/* + * DASD_3990_ERP_IN_ERP + * + * DESCRIPTION + * check if the current error already happened before. + * quick exit if current cqr is not an ERP (cqr->refers=NULL) + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the already defined error recovery procedure OR + * NULL if a 'new' error occured. + */ +ccw_req_t * +dasd_3990_erp_in_erp (ccw_req_t * cqr) +{ + ccw_req_t *erp_head = cqr, /* save erp chain head */ + *erp_match = NULL; /* save erp chain head */ + int match = 0; /* 'boolean' for matching error found */ + + if (cqr->refers == NULL) { /* return if not in erp */ + return NULL; + } + /* check the erp/cqr chain for current error */ + do { + match = dasd_3990_erp_error_match (erp_head, + cqr->refers); + erp_match = cqr; /* save possible matching erp */ + cqr = cqr->refers; /* check next erp/cqr in queue */ + } while ((cqr->refers != NULL) && + (match == 0)); + + if (match) { + /* TBD */ + printk(KERN_WARNING PRINTK_HEADER + "dasd_3990_erp_in_erp: return matching erp\n"); + return erp_match; /* retrun address of matching erp */ + } else { + printk(KERN_WARNING PRINTK_HEADER + "dasd_3990_erp_in_erp: return no match\n"); + return NULL; /* return NULL to indicate that no match + was found */ + } + +} /* END dasd_3990_erp_in_erp */ + +/* + * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense) + * + * DESCRIPTION + * No retry is left for the current ERP. Check what has to be done + * with the ERP. + * - do further defined ERP action or + * - wait for interrupt or + * - exit with permanent error + * + * PARAMETER + * erp ERP which is in progress wiht no retry left + * + * RETURN VALUES + * erp modified/additional ERP + */ +ccw_req_t * +dasd_3990_erp_further_erp (ccw_req_t * erp) +{ + dasd_device_t *device = erp->device; + + /* check for 24 byte sense ERP */ + if ((erp->function == dasd_3990_erp_action_1) || + (erp->function == dasd_3990_erp_action_4) ){ + + erp = dasd_3990_erp_action_1 (erp); + + } else { + /* no retry left and no additional special handling necessary */ + DASD_MESSAGE (KERN_WARNING, device, + "no retries left for erp %p - " + "set status to FAILED", + erp); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + + return erp; + +} /* end dasd_3990_erp_further_erp */ + +/* + * DASD_3990_ERP_HANDLE_MATCH_ERP + * + * DESCRIPTION + * An error occured again and an ERP has been detected which is already + * used to handle this error (e.g. retries). + * All prior ERP's are set to status DONE and the retry counter is + * decremented. + * If retry counter is already 0, it has to checked if further action + * is needed (besides retry) or if the ERP has failed. + * + * PARAMETER + * erp_head first ERP in ERP-chain + * erp_match ERP that handles the actual error. + * + * RETURN VALUES + * none + */ +void +dasd_3990_erp_handle_match_erp (ccw_req_t * erp_head, + ccw_req_t * erp_match) +{ + + dasd_device_t *device = erp_head->device; + ccw_req_t *erp_done = erp_head; + + /* loop over successful ERPs and remove them from chanq */ + while ((erp_done != erp_match) && + (erp_done != NULL)) { + +#ifdef ERP_DEBUG + printk (KERN_WARNING PRINTK_HEADER + "successful ERP - dequeue and free request %p\n", + (void *) erp_done); +#endif + atomic_compare_and_swap_debug (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + /* remove the request from the device queue */ + dasd_chanq_deq (&device->queue, + erp_done); + + /* free the finished erp request */ + dasd_free_request (erp_done); + + erp_done = erp_done->refers; + } + + if (erp_done == NULL) /* erp_done should never be NULL! */ + panic (PRINTK_HEADER "Programming error in ERP! The original " + "request was lost\n"); + +#ifdef ERP_DEBUG + /* handle matching ERP */ + printk (KERN_WARNING PRINTK_HEADER + "handle matching erp %p\n", + (void *) erp_done); +#endif + + if (erp_done->retries > 0) { + + /* check for special retries */ + if (erp_done->function == dasd_3990_erp_action_4) { + char *sense = erp_done->dstat->ii.sense.data; + erp_done = dasd_3990_erp_action_4 (erp_done, + sense); + + } else { + /* simple retry */ + printk (KERN_WARNING PRINTK_HEADER + "%i retries left for erp %p\n", + erp_done->retries, + (void *) erp_done); + + /* handle the request again... */ + atomic_compare_and_swap_debug (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } else { + /* no retry left - check for further necessary action */ + /* if no further actions, handle rest as permanent error */ + erp_done = dasd_3990_erp_further_erp (erp_done); + } + + erp_head = erp_done; + +} /* end dasd_3990_erp_handle_match_erp */ + +/* + * DASD_3990_ERP_ACTION + * + * DESCRIPTION + * controll routine for 3990 erp actions. + * Has to be called with the queue lock (namely the s390_irq_lock) acquired. + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the head of the ERP action chain. + * This means: + * - either a ptr to an additional ERP cqr or + * - the original given cqr (which's status might be modified) + */ +ccw_req_t * +dasd_3990_erp_action (ccw_req_t *cqr) +{ + ccw_req_t *erp = NULL; + dasd_device_t *device = cqr->device; + +#ifdef ERP_DEBUG + + printk (KERN_WARNING PRINTK_HEADER + "entering 3990 ERP for " + "0x%04X on sch %d = /dev/%s \n", + device->devinfo.devno, + device->devinfo.irq, + device->name); + + /* print current erp_chain */ + printk(KERN_WARNING PRINTK_HEADER + "ERP chain at BEGINNING of ERP-ACTION\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif + + /* double-check if current erp/cqr was successfull */ + if ((cqr->dstat->cstat == 0x00) && + (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called for successful request %p" + " - NO ERP necessary", + cqr); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + return cqr; + } + /* check if sense data are available */ + if (!cqr->dstat->ii.sense.data) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called witout sense data avail ..." + "request %p - NO ERP possible", + cqr); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return cqr; + + } + + /* check if error happened before */ + erp = dasd_3990_erp_in_erp (cqr); + + if (erp == NULL) { + /* no matching erp found - set up erp */ + erp = dasd_3990_erp_additional_erp (cqr); + } else { + /* matching erp found - set all leading erp's to DONE */ + dasd_3990_erp_handle_match_erp (cqr, erp); + erp = cqr; + } + +#ifdef ERP_DEBUG + /* print current erp_chain */ + printk(KERN_WARNING PRINTK_HEADER + "ERP chain at END of ERP-ACTION\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif - } /* end distinguish between 24 and 32 byte sense data */ + return erp; -} /* END dasd_3990_erp_examine */ +} /* end dasd_3990_erp_action */ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_3990_erp.h linux/drivers/s390/block/dasd_3990_erp.h --- v2.2.18/drivers/s390/block/dasd_3990_erp.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/s390/block/dasd_3990_erp.h Sun Mar 25 11:37:35 2001 @@ -0,0 +1,21 @@ +/* + * File...........: linux/drivers/s390/block/dasd_3990_erp.h + * Author(s)......: Horst Hummel + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts Jul 2000) + */ + +#ifndef DASD_3990_ERP_H +#define DASD_3990_ERP_H + + +dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *); + +ccw_req_t *dasd_3990_erp_action (ccw_req_t *); +ccw_req_t *dasd_2105_erp_action (ccw_req_t *); + +void dasd_3990_erp_restart_queue (unsigned long); + +#endif /* DASD_3990_ERP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_9336_erp.c linux/drivers/s390/block/dasd_9336_erp.c --- v2.2.18/drivers/s390/block/dasd_9336_erp.c Sun Mar 25 11:13:11 2001 +++ linux/drivers/s390/block/dasd_9336_erp.c Sun Mar 25 11:37:35 2001 @@ -5,6 +5,7 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 */ +#include #include #include @@ -32,8 +33,6 @@ dasd_era_t dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat) { - char *sense = stat->ii.sense.data; - /* check for successful execution first */ if (stat->cstat == 0x00 && stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_9343_erp.c linux/drivers/s390/block/dasd_9343_erp.c --- v2.2.18/drivers/s390/block/dasd_9343_erp.c Sun Mar 25 11:13:11 2001 +++ linux/drivers/s390/block/dasd_9343_erp.c Sun Mar 25 11:37:35 2001 @@ -5,6 +5,7 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 */ +#include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_9343_erp.h linux/drivers/s390/block/dasd_9343_erp.h --- v2.2.18/drivers/s390/block/dasd_9343_erp.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/s390/block/dasd_9343_erp.h Sun Mar 25 11:37:35 2001 @@ -0,0 +1,18 @@ +/* + * File...........: linux/drivers/s390/block/dasd_9343_erp.h + * Author(s)......: Horst Hummel + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_9343_ERP_H +#define DASD_9343_ERP_H + + +dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *); + +ccw_req_t *dasd_9343_erp_action (ccw_req_t *); + +#endif /* DASD_9343_ERP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c --- v2.2.18/drivers/s390/block/dasd_diag.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/dasd_diag.c Sun Mar 25 11:37:35 2001 @@ -268,13 +268,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL); if ( device->private == NULL ) { - device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL); - if ( device->private == NULL ) { - printk ( KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk ( KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_diag_private_t *)device->private; rdc_data = (void *)&(private->rdc_data); @@ -318,7 +319,7 @@ if (rc > 4) { continue; } - cqr = ccw_alloc_request (dasd_diag_discipline.name, 2,0); + cqr = dasd_alloc_request (dasd_diag_discipline.name, 2,0); if ( cqr == NULL ) { printk ( KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -501,7 +502,7 @@ } } else { PRINT_WARN ("Cannot fulfill request smaller than block\n"); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } } @@ -532,6 +533,7 @@ dasd_discipline_t dasd_diag_discipline = { name : "DIAG", ebcname : "DIAG", + max_blocks: PAGE_SIZE/sizeof(diag_bio_t), check_characteristics: dasd_diag_check_characteristics, do_analysis: dasd_diag_do_analysis, fill_geometry: dasd_diag_fill_geometry, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c --- v2.2.18/drivers/s390/block/dasd_eckd.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/dasd_eckd.c Sun Mar 25 11:37:35 2001 @@ -12,6 +12,7 @@ * 08/07/00 added some bits to define_extent for ESS support * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF) * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages) + * 01/23/00 fixed kmalloc in dump_sense to be GFP_ATOMIC */ #include @@ -49,22 +50,6 @@ #define ECKD_F7(i) (i->factor7) #define ECKD_F8(i) (i->factor8) -#define DASD_ECKD_CCW_WRITE 0x05 -#define DASD_ECKD_CCW_READ 0x06 -#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 -#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a -#define DASD_ECKD_CCW_READ_COUNT 0x12 -#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 -#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 -#define DASD_ECKD_CCW_WRITE_CKD 0x1d -#define DASD_ECKD_CCW_READ_CKD 0x1e -#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 -#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 -#define DASD_ECKD_CCW_WRITE_MT 0x85 -#define DASD_ECKD_CCW_READ_MT 0x86 -#define DASD_ECKD_CCW_READ_CKD_MT 0x9e -#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d - dasd_discipline_t dasd_eckd_discipline; typedef struct @@ -74,6 +59,7 @@ eckd_count_t count_area; } dasd_eckd_private_t; +#ifdef CONFIG_DASD_DYNAMIC static devreg_t dasd_eckd_known_devices[] = { { @@ -92,6 +78,7 @@ oper_func: dasd_oper_handler } }; +#endif static inline unsigned int round_up_multiple (unsigned int no, unsigned int mult) @@ -372,9 +359,9 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device) { int rc = -ENODEV; - void *conf_data; + void *conf_data=NULL; void *rdc_data; - int conf_len; + int conf_len=0; dasd_eckd_private_t *private; if ( device == NULL ) { @@ -382,13 +369,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL); if ( device->private == NULL ) { - device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL); - if ( device->private == NULL ) { - printk ( KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk ( KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_eckd_private_t *)device->private; rdc_data = (void *)&(private->rdc_data); @@ -448,7 +436,7 @@ LO_eckd_data_t *LO_data; eckd_count_t *count_data = &(((dasd_eckd_private_t *)(device->private))->count_area); - cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); + cqr = dasd_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); if ( cqr == NULL ) { printk ( KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -622,9 +610,9 @@ datasize += sizeof(eckd_home_t); } } - fcp = ccw_alloc_request (dasd_eckd_discipline.name, - wrccws + 2, - datasize+rpt*sizeof(eckd_count_t)); + fcp = dasd_alloc_request (dasd_eckd_discipline.name, + wrccws + 2, + datasize+rpt*sizeof(eckd_count_t)); if ( fcp != NULL ) { fcp->device = device; fcp->retries = 2; /* set retry counter to enable ERP */ @@ -749,21 +737,26 @@ } } -static dasd_erp_action_fn_t -dasd_eckd_erp_action ( ccw_req_t * cqr ) +static dasd_erp_action_fn_t +dasd_eckd_erp_action (ccw_req_t * cqr) { - return default_erp_action; + dasd_device_t *device = (dasd_device_t *) cqr->device; + + switch (device->devinfo.sid_data.cu_type) { + case 0x3990: + case 0x2105: + return dasd_3990_erp_action; + case 0x9343: + /* return dasd_9343_erp_action; */ + default: + return default_erp_action; + } } static dasd_erp_postaction_fn_t dasd_eckd_erp_postaction (ccw_req_t * cqr) { - if ( cqr -> function == default_erp_action) - return default_erp_postaction; - printk ( KERN_WARNING PRINTK_HEADER - "unknown ERP action %p\n", - cqr -> function); - return NULL; + return default_erp_postaction; } static ccw_req_t * @@ -842,7 +835,7 @@ } if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } ccw->flags = CCW_FLAG_CC; @@ -860,7 +853,7 @@ static char * dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req) { - char *page = (char *)get_free_page(GFP_KERNEL); + char *page = (char *)get_free_page(GFP_ATOMIC); devstat_t *stat = &device->dev_status; char *sense = stat->ii.sense.data; int len,sl,sct; @@ -905,6 +898,7 @@ dasd_discipline_t dasd_eckd_discipline = { name : "ECKD", ebcname : "ECKD", + max_blocks: 255, id_check: dasd_eckd_id_check, check_characteristics: dasd_eckd_check_characteristics, init_analysis: dasd_eckd_init_analysis, @@ -923,7 +917,9 @@ int dasd_eckd_init( void ) { int rc = 0; +#ifdef CONFIG_DASD_DYNAMIC int i; +#endif printk ( KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_eckd_discipline.name); ASCEBC(dasd_eckd_discipline.ebcname,4); @@ -944,8 +940,9 @@ void dasd_eckd_cleanup( void ) { - int rc = 0; +#ifdef CONFIG_DASD_DYNAMIC int i; +#endif printk ( KERN_INFO PRINTK_HEADER "%s discipline cleaning up\n", dasd_eckd_discipline.name); #ifdef CONFIG_DASD_DYNAMIC @@ -960,7 +957,7 @@ } #endif /* CONFIG_DASD_DYNAMIC */ dasd_discipline_deq(&dasd_eckd_discipline); - return rc; + return; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_eckd.h linux/drivers/s390/block/dasd_eckd.h --- v2.2.18/drivers/s390/block/dasd_eckd.h Sun Mar 25 11:13:11 2001 +++ linux/drivers/s390/block/dasd_eckd.h Sun Mar 25 11:37:35 2001 @@ -1,6 +1,25 @@ #ifndef DASD_ECKD_H #define DASD_ECKD_H +#include "dasd_3990_erp.h" +#include "dasd_9343_erp.h" + +#define DASD_ECKD_CCW_WRITE 0x05 +#define DASD_ECKD_CCW_READ 0x06 +#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 +#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a +#define DASD_ECKD_CCW_READ_COUNT 0x12 +#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 +#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 +#define DASD_ECKD_CCW_WRITE_CKD 0x1d +#define DASD_ECKD_CCW_READ_CKD 0x1e +#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 +#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 +#define DASD_ECKD_CCW_WRITE_MT 0x85 +#define DASD_ECKD_CCW_READ_MT 0x86 +#define DASD_ECKD_CCW_READ_CKD_MT 0x9e +#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d + typedef struct eckd_count_t { __u16 cyl; @@ -282,5 +301,6 @@ } __attribute__ ((packed)) dasd_eckd_confdata_t; int dasd_eckd_init( void ); +void dasd_eckd_cleanup( void ); #endif /* DASD_ECKD_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c --- v2.2.18/drivers/s390/block/dasd_fba.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/dasd_fba.c Sun Mar 25 11:37:35 2001 @@ -117,13 +117,14 @@ "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL); if ( device->private == NULL ) { - device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL); - if ( device->private == NULL ) { - printk ( KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk ( KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_fba_private_t *)device->private; rdc_data = (void *)&(private->rdc_data); @@ -181,9 +182,7 @@ int rc = 0; unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift; unsigned long tracks = sectors >> 6; - unsigned long trk_rem = sectors & ((1<<6)-1); unsigned long cyls = tracks >> 4; - unsigned long cyls_rem = tracks & ((1<<4)-1); switch(device->sizes.bp_block) { case 512: @@ -308,7 +307,7 @@ ccw->flags = CCW_FLAG_DC; } else { PRINT_WARN ("Cannot chain chunks smaller than one block\n"); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } ccw->cmd_code = rw_cmd; @@ -320,7 +319,7 @@ ccw->flags = CCW_FLAG_CC; if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill request smaller than block\n"); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } } @@ -354,6 +353,7 @@ dasd_discipline_t dasd_fba_discipline = { name : "FBA ", ebcname : "FBA ", + max_blocks: PAGE_SIZE/sizeof(ccw1_t), id_check: dasd_fba_id_check, check_characteristics: dasd_fba_check_characteristics, do_analysis: dasd_fba_do_analysis, @@ -371,7 +371,9 @@ int dasd_fba_init( void ) { int rc = 0; +#ifdef CONFIG_DASD_DYNAMIC int i; +#endif printk ( KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_fba_discipline.name); ASCEBC(dasd_fba_discipline.ebcname,4); @@ -392,8 +394,9 @@ void dasd_fba_cleanup( void ) { - int rc = 0; +#ifdef CONFIG_DASD_DYNAMIC int i; +#endif printk ( KERN_INFO PRINTK_HEADER "%s discipline cleaning up\n", dasd_fba_discipline.name); #ifdef CONFIG_DASD_DYNAMIC @@ -408,7 +411,7 @@ } #endif /* CONFIG_DASD_DYNAMIC */ dasd_discipline_deq(&dasd_fba_discipline); - return rc; + return; } /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd_fba.h linux/drivers/s390/block/dasd_fba.h --- v2.2.18/drivers/s390/block/dasd_fba.h Sun Mar 25 11:13:11 2001 +++ linux/drivers/s390/block/dasd_fba.h Sun Mar 25 11:37:35 2001 @@ -66,5 +66,6 @@ } __attribute__ ((packed)) dasd_fba_characteristics_t; int dasd_fba_init( void ); +void dasd_fba_cleanup( void ); #endif /* DASD_FBA_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/mdisk.c linux/drivers/s390/block/mdisk.c --- v2.2.18/drivers/s390/block/mdisk.c Sun Mar 25 11:13:11 2001 +++ linux/drivers/s390/block/mdisk.c Sun Mar 25 11:37:35 2001 @@ -105,6 +105,122 @@ } mdisk_setup_data; /* + * The 'low level' IO function + */ + +static __inline__ int +dia250(void* iob,int cmd) +{ + int rc; + + iob = (void*) virt_to_phys(iob); + + asm volatile (" lr 2,%1\n" + " lr 3,%2\n" + " .long 0x83230250\n" + " lr %0,3" + : "=d" (rc) + : "d" (iob) , "d" (cmd) + : "2", "3" ); + return rc; +} + +/* + * The device characteristics function + */ + +static __inline__ int +dia210(void* devchar) +{ + int rc; + + devchar = (void*) virt_to_phys(devchar); + + asm volatile (" lr 2,%1\n" + " .long 0x83200210\n" + " ipm %0\n" + " srl %0,28" + : "=d" (rc) + : "d" (devchar) + : "2" ); + return rc; +} + + +/* + * release of minidisk device + */ + +static __inline__ int +mdisk_term_io(mdisk_Dev *dev) +{ + mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob; + + memset(iob,0,sizeof(mdisk_init_io_t)); + + iob->dev_nr = dev->vdev; + + return dia250(iob,TERM_BIO); +} + + +/* + * Init of minidisk device + */ + +static __inline__ int +mdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size) +{ + mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob; + int rc; + + memset(iob,0,sizeof(mdisk_init_io_t)); + + iob->dev_nr = dev->vdev; + iob->block_size = blocksize; + iob->offset = offset; + iob->start_block= 0; + iob->end_block = size; + + rc = dia250(iob,INIT_BIO); + + /* + * clear for following io once + */ + + memset(iob,0,sizeof(mdisk_rw_io_t)); + + return rc; +} + + +/* + * setup and start of minidisk io request + */ + +static __inline__ int +mdisk_rw_io_clustered (mdisk_Dev *dev, + mdisk_bio_t* bio_array, + int length, + int req, + int sync) +{ + int rc; + mdisk_rw_io_t *iob = dev->iob; + + iob->dev_nr = dev->vdev; + iob->key = 0; + iob->flags = sync; + + iob->block_count = length; + iob->interrupt_params = req; + iob->bio_list = virt_to_phys(bio_array); + + rc = dia250(iob,RW_BIO); + return rc; +} + +/* * Parameter parsing function, called from init/main.c * vdev : virtual device number * size : size in kbyte @@ -117,7 +233,7 @@ { char *cur = str; int vdev, size, offset=0,blksize; - static i = 0; +static int i = 0; if (!i) memset(&mdisk_setup_data,0,sizeof(mdisk_setup_data)); @@ -280,48 +396,7 @@ NULL, /* mdisk_lock */ }; -/* - * The 'low level' IO function - */ - - -static __inline__ int -dia250(void* iob,int cmd) -{ - int rc; - - iob = (void*) virt_to_phys(iob); - - asm volatile (" lr 2,%1\n" - " lr 3,%2\n" - " .long 0x83230250\n" - " lr %0,3" - : "=d" (rc) - : "d" (iob) , "d" (cmd) - : "2", "3" ); - return rc; -} - -/* - * The device characteristics function - */ - -static __inline__ int -dia210(void* devchar) -{ - int rc; - - devchar = (void*) virt_to_phys(devchar); - asm volatile (" lr 2,%1\n" - " .long 0x83200210\n" - " ipm %0\n" - " srl %0,28" - : "=d" (rc) - : "d" (devchar) - : "2" ); - return rc; -} /* * read the label of a minidisk and extract its characteristics */ @@ -396,80 +471,6 @@ } - -/* - * Init of minidisk device - */ - -static __inline__ int -mdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size) -{ - mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob; - int rc; - - memset(iob,0,sizeof(mdisk_init_io_t)); - - iob->dev_nr = dev->vdev; - iob->block_size = blocksize; - iob->offset = offset; - iob->start_block= 0; - iob->end_block = size; - - rc = dia250(iob,INIT_BIO); - - /* - * clear for following io once - */ - - memset(iob,0,sizeof(mdisk_rw_io_t)); - - return rc; -} - -/* - * release of minidisk device - */ - -static __inline__ int -mdisk_term_io(mdisk_Dev *dev) -{ - mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob; - - memset(iob,0,sizeof(mdisk_init_io_t)); - - iob->dev_nr = dev->vdev; - - return dia250(iob,TERM_BIO); -} - -/* - * setup and start of minidisk io request - */ - -static __inline__ int -mdisk_rw_io_clustered (mdisk_Dev *dev, - mdisk_bio_t* bio_array, - int length, - int req, - int sync) -{ - int rc; - mdisk_rw_io_t *iob = dev->iob; - - iob->dev_nr = dev->vdev; - iob->key = 0; - iob->flags = sync; - - iob->block_count = length; - iob->interrupt_params = req; - iob->bio_list = virt_to_phys(bio_array); - - rc = dia250(iob,RW_BIO); - return rc; -} - - - /* * this handles a clustered request in success case * all buffers are detach and marked uptodate to the kernel @@ -640,11 +641,8 @@ */ void do_mdisk_interrupt(struct pt_regs *regs, __u16 code) { - u16 code; mdisk_Dev *dev; - code = S390_lowcore.cpu_addr; - if ((code >> 8) != 0x03) { printk("mnd: wrong sub-interruption code %d",code>>8); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c --- v2.2.18/drivers/s390/block/xpram.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/block/xpram.c Sun Mar 25 11:37:35 2001 @@ -413,7 +413,7 @@ " .long 0xb22e0012 \n" /* pgin r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ - " srl %0,28(0) \n" /* cc into least significant bits */ + " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lhi %0,2 \n" /* return unused condition code 2 */ @@ -456,7 +456,7 @@ " .long 0xb22f0012 \n" /* pgout r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ - " srl %0,28(0) \n" /* cc into least significant bits */ + " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lhi %0,2 \n" /* return unused condition code 2 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/ccwcache.c linux/drivers/s390/ccwcache.c --- v2.2.18/drivers/s390/ccwcache.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/ccwcache.c Sun Mar 25 11:37:35 2001 @@ -8,6 +8,7 @@ * 07/10/00 moved ccwcache.h from linux/ to asm/ */ +#include #include #include #include @@ -15,19 +16,14 @@ #include #include -#ifdef PRINTK_HEADER -#undef PRINTK_HEADER -#endif +#undef PRINTK_HEADER #define PRINTK_HEADER "ccwcache" -#ifdef MODULE MODULE_AUTHOR ("Holger Smolinski "); MODULE_DESCRIPTION ("Linux on S/390 CCW cache," "Copyright 2000 IBM Corporation"); -EXPORT_NO_SYMBOLS; EXPORT_SYMBOL(ccw_alloc_request); EXPORT_SYMBOL(ccw_free_request); -#endif /* MODULE */ /* pointer to list of allocated requests */ @@ -314,8 +310,7 @@ } else { printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area ); } - debug_register_view(debug_area,&debug_hex_view); - debug_register_view(debug_area,&debug_ebcdic_view); + debug_register_view(debug_area,&debug_hex_ascii_view); debug_text_event ( debug_area, 0, "INIT"); /* First allocate the kmem caches */ @@ -389,3 +384,4 @@ ccwcache_cleanup(); } #endif /* MODULE */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/char/hwc.h linux/drivers/s390/char/hwc.h --- v2.2.18/drivers/s390/char/hwc.h Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/char/hwc.h Sun Mar 25 11:37:35 2001 @@ -39,6 +39,8 @@ #define HWC_BUSY 2 #define HWC_NOT_OPERATIONAL 3 +#define hwc_cmdw_t u32; + #define HWC_CMDW_READDATA 0x00770005 #define HWC_CMDW_WRITEDATA 0x00760005 @@ -207,9 +209,25 @@ 0x0000, 0x0000, sizeof (_hwcb_mask_t), - ET_OpCmd_Mask | ET_PMsgCmd_Mask, - ET_Msg_Mask + ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask, + ET_Msg_Mask | ET_PMsgCmd_Mask }; + +typedef struct { + _EBUF_HEADER + u8 validity_hwc_active_facility_mask:1; + u8 validity_hwc_receive_mask:1; + u8 validity_hwc_send_mask:1; + u8 validity_read_data_function_mask:1; + u16 _zeros:12; + u16 mask_length; + u64 hwc_active_facility_mask; + _hwcb_mask_t hwc_receive_mask; + _hwcb_mask_t hwc_send_mask; + u32 read_data_function_mask; +} __attribute__ ((packed)) + +statechangebuf_t; #define _GDS_VECTOR_HEADER u16 length; \ u16 gds_id; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c --- v2.2.18/drivers/s390/char/hwc_rw.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/char/hwc_rw.c Sun Mar 25 11:37:35 2001 @@ -29,9 +29,13 @@ #include #ifndef MIN -#define MIN(a,b) ((amsgbuf.type = ET_PMsgCmd; - return 0; } @@ -375,7 +379,7 @@ #ifdef DUMP_HWC_WRITE_LIST_ERROR __asm__ ("LHI 1,0xe30\n\t" - "LRA 2,0(0,%0) \n\t" + "LRA 2,0(%0) \n\t" "J .+0 \n\t" : : "a" (bad_addr) @@ -437,8 +441,8 @@ if (hwc_data.hwcb_count < 2) #ifdef DUMP_HWC_WRITE_LIST_ERROR __asm__ ("LHI 1,0xe31\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "LRA 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0 \n\t" : : "a" (BUF_HWCB), "a" (OUT_HWCB) @@ -658,32 +662,65 @@ return count; } +static int write_event_data_1 (void); + +static void +do_poll_hwc (unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave (&hwc_data.lock, flags); + + write_event_data_1 (); + + spin_unlock_irqrestore (&hwc_data.lock, flags); +} + +void +start_poll_hwc (void) +{ + init_timer (&hwc_data.poll_timer); + hwc_data.poll_timer.function = do_poll_hwc; + hwc_data.poll_timer.data = (unsigned long) NULL; + hwc_data.poll_timer.expires = jiffies + 2 * HZ; + add_timer (&hwc_data.poll_timer); + hwc_data.flags |= HWC_PTIMER_RUNS; +} + static int write_event_data_1 (void) { unsigned short int condition_code; int retval; + write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB; - if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio)) - return -EPERM; + if ((!hwc_data.write_prio) && + (!hwc_data.write_nonprio) && + hwc_data.read_statechange) + return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; retval = sane_write_hwcb (); if (retval < 0) - return retval; + return -EIO; if (!OUT_HWCB_MTO) return -ENODATA; + if (!hwc_data.write_nonprio && hwc_data.write_prio) + hwcb->msgbuf.type = ET_PMsgCmd; + else + hwcb->msgbuf.type = ET_Msg; + condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB); #ifdef DUMP_HWC_WRITE_ERROR if (condition_code != HWC_COMMAND_INITIATED) __asm__ ("LHI 1,0xe20\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "L 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0 \n\t" : : "a" (&condition_code), "a" (OUT_HWCB) @@ -702,6 +739,8 @@ case HWC_BUSY: retval = -EBUSY; break; + case HWC_NOT_OPERATIONAL: + start_poll_hwc (); default: retval = -EIO; } @@ -724,7 +763,7 @@ write_event_data_2 (void) { write_hwcb_t *hwcb; - int retval; + int retval = 0; #ifdef DUMP_HWC_WRITE_ERROR unsigned char *param; @@ -734,7 +773,7 @@ internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER - "write_event_mask_2 : " + "write_event_data_2 : " "HWCB address does not fit " "(expected: 0x%x, got: 0x%x).\n", hwc_data.current_hwcb, @@ -748,10 +787,10 @@ #ifdef DUMP_HWC_WRITE_LIST_ERROR if (((unsigned char *) hwcb) != hwc_data.current_hwcb) { __asm__ ("LHI 1,0xe22\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" + "LRA 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" + "LRA 4,0(%2)\n\t" + "LRA 5,0(%3)\n\t" "J .+0 \n\t" : : "a" (OUT_HWCB), @@ -765,11 +804,11 @@ #ifdef DUMP_HWC_WRITE_ERROR if (hwcb->response_code != 0x0020) { __asm__ ("LHI 1,0xe21\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LH 5,0(0,%3)\n\t" - "SRL 5,8(0)\n\t" + "LRA 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" + "LRA 4,0(%2)\n\t" + "LH 5,0(%3)\n\t" + "SRL 5,8\n\t" "J .+0 \n\t" : : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb), @@ -779,11 +818,22 @@ } #endif - if (hwcb->response_code == 0x0020) { + switch (hwcb->response_code) { + case 0x0020: retval = OUT_HWCB_CHAR; release_write_hwcb (); - } else { + break; + case 0x0040: + case 0x0340: + case 0x40F0: + if (!hwc_data.read_statechange) { + hwcb->response_code = 0; + start_poll_hwc (); + } + retval = -EIO; + break; + default: internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER @@ -796,6 +846,13 @@ retval = -EIO; } + if (retval == -EIO) { + + hwcb->control_mask[0] = 0; + hwcb->control_mask[1] = 0; + hwcb->control_mask[2] = 0; + hwcb->response_code = 0; + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -819,10 +876,10 @@ #ifdef DUMP_HWC_WRITE_LIST_ERROR if (add_mto (message, count) != count) __asm__ ("LHI 1,0xe32\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" + "LRA 2,0(%0)\n\t" + "L 3,0(%1)\n\t" + "LRA 4,0(%2)\n\t" + "LRA 5,0(%3)\n\t" "J .+0 \n\t" : : "a" (message), "a" (&hwc_data.kmem_pages), @@ -840,9 +897,9 @@ unsigned short count) { - if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) { + if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) { del_timer (&hwc_data.write_timer); - hwc_data.flags &= ~HWC_TIMER_RUNS; + hwc_data.flags &= ~HWC_WTIMER_RUNS; } hwc_data.obuf_start += count; @@ -888,13 +945,12 @@ int from_user, unsigned char *msg, unsigned int count, - unsigned char code, unsigned char write_time) { unsigned int i_msg = 0; unsigned short int spaces = 0; unsigned int processed_characters = 0; - unsigned char ch, orig_ch; + unsigned char ch; unsigned short int obuf_count; unsigned short int obuf_cursor; unsigned short int obuf_columns; @@ -911,15 +967,10 @@ } for (i_msg = 0; i_msg < count; i_msg++) { - if (from_user) - get_user (orig_ch, msg + i_msg); + get_user (ch, msg + i_msg); else - orig_ch = msg[i_msg]; - if (code == CODE_EBCDIC) - ch = (MACHINE_IS_VM ? _ebcasc[orig_ch] : _ebcasc_500[orig_ch]); - else - ch = orig_ch; + ch = msg[i_msg]; processed_characters++; @@ -957,7 +1008,7 @@ if (obuf_cursor < obuf_columns) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor] - = 0x20; + = HWC_ASCEBC (' '); obuf_cursor++; } else break; @@ -975,7 +1026,7 @@ while (spaces) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor - spaces] - = 0x20; + = HWC_ASCEBC (' '); spaces--; } @@ -1005,11 +1056,7 @@ if (isprint (ch)) hwc_data.obuf[hwc_data.obuf_start + obuf_cursor++] - = (code == CODE_ASCII) ? - (MACHINE_IS_VM ? - _ascebc[orig_ch] : - _ascebc_500[orig_ch]) : - orig_ch; + = HWC_ASCEBC (ch); } if (obuf_cursor > obuf_count) obuf_count = obuf_cursor; @@ -1028,11 +1075,10 @@ if (hwc_data.ioctls.final_nl > 0) { - if (hwc_data.flags & HWC_TIMER_RUNS) { + if (hwc_data.flags & HWC_WTIMER_RUNS) { - hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl * HZ / 10; + mod_timer (&hwc_data.write_timer, + jiffies + hwc_data.ioctls.final_nl * HZ / 10); } else { init_timer (&hwc_data.write_timer); @@ -1044,7 +1090,7 @@ jiffies + hwc_data.ioctls.final_nl * HZ / 10; add_timer (&hwc_data.write_timer); - hwc_data.flags |= HWC_TIMER_RUNS; + hwc_data.flags |= HWC_WTIMER_RUNS; } } else; @@ -1072,8 +1118,7 @@ spin_lock_irqsave (&hwc_data.lock, flags); retval = do_hwc_write (from_user, (unsigned char *) msg, - count, hwc_data.ioctls.code, - IMMEDIATE_WRITE); + count, IMMEDIATE_WRITE); spin_unlock_irqrestore (&hwc_data.lock, flags); @@ -1329,15 +1374,11 @@ if (hwc_data.ioctls.delim) count = seperate_cases (start, count); + HWC_EBCASC_STR (start, count); + if (hwc_data.ioctls.echo) - do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE); + do_hwc_write (0, start, count, IMMEDIATE_WRITE); - if (hwc_data.ioctls.code == CODE_ASCII) { - if (MACHINE_IS_VM) - EBCASC (start, count); - else - EBCASC_500 (start, count); - } if (hwc_data.calls != NULL) if (hwc_data.calls->move_input != NULL) (hwc_data.calls->move_input) (start, count); @@ -1440,7 +1481,7 @@ return retval; } -inline static int +static int eval_evbuf (gds_vector_t * start, void *end) { gds_vector_t *vec; @@ -1458,6 +1499,128 @@ return retval; } +static inline int +eval_hwc_receive_mask (_hwcb_mask_t mask) +{ + + hwc_data.write_nonprio + = ((mask & ET_Msg_Mask) == ET_Msg_Mask); + + hwc_data.write_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + + if (hwc_data.write_prio || hwc_data.write_nonprio) { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can write messages\n"); + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not write messages\n"); + return -1; + } +} + +static inline int +eval_hwc_send_mask (_hwcb_mask_t mask) +{ + + hwc_data.read_statechange + = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask); + if (hwc_data.read_statechange) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read state change notifications\n"); + else + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read state change notifications\n"); + + hwc_data.read_nonprio + = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask); + if (hwc_data.read_nonprio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read commands\n"); + + hwc_data.read_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + if (hwc_data.read_prio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read priority commands\n"); + + if (hwc_data.read_prio || hwc_data.read_nonprio) { + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read commands from operator\n"); + return -1; + } +} + +static int +eval_statechangebuf (statechangebuf_t * scbuf) +{ + int retval = 0; + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "HWC state change detected\n"); + + if (scbuf->validity_hwc_active_facility_mask) { + + } + if (scbuf->validity_hwc_receive_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe50\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_receive_mask + (scbuf->hwc_receive_mask); + } + } + if (scbuf->validity_hwc_send_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe51\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_send_mask + (scbuf->hwc_send_mask); + } + } + if (scbuf->validity_read_data_function_mask) { + + } + return retval; +} + static int process_evbufs (void *start, void *end) { @@ -1490,17 +1653,17 @@ retval += eval_evbuf (evbuf_data, evbuf_end); break; case ET_StateChange: - - retval = -ENOSYS; + retval += eval_statechangebuf + ((statechangebuf_t *) evbuf); break; default: - printk ( - KERN_WARNING - HWC_RW_PRINT_HEADER - "unconditional read: " - "unknown event buffer found, " - "type 0x%x", - evbuf->type); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " + "unknown event buffer found, " + "type 0x%x", + evbuf->type); retval = -ENOSYS; } evbuf = (evbuf_t *) evbuf_end; @@ -1515,11 +1678,14 @@ read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; int retval; +#if 0 + if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio)) return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; +#endif memset (hwcb, 0x00, PAGE_SIZE); memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t)); @@ -1529,8 +1695,8 @@ #ifdef DUMP_HWC_READ_ERROR if (condition_code == HWC_NOT_OPERATIONAL) __asm__ ("LHI 1,0xe40\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "L 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0 \n\t" : : "a" (&condition_code), "a" (hwc_data.page) @@ -1564,8 +1730,8 @@ (hwcb->response_code != 0x60F0) && (hwcb->response_code != 0x62F0)) __asm__ ("LHI 1,0xe41\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" + "LRA 2,0(%0)\n\t" + "L 3,0(%1)\n\t" "J .+0\n\t" : : "a" (hwc_data.page), "a" (&(hwcb->response_code)) @@ -1625,26 +1791,21 @@ internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: invalid function code - this " - "must not occur in a correct driver, please contact " - "author\n"); + "unconditional read: invalid function code\n"); return -EIO; case 0x70F0: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: invalid selection mask - this " - "must not occur in a correct driver, please contact " - "author\n"); + "unconditional read: invalid selection mask\n"); return -EIO; case 0x0040: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: HWC equipment check - don't " - "know how to handle this case\n"); + "unconditional read: HWC equipment check\n"); return -EIO; default: @@ -1671,8 +1832,8 @@ if (condition_code == HWC_NOT_OPERATIONAL) __asm__ ("LHI 1,0xe10\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "L 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0\n\t" : : "a" (&condition_code), "a" (hwc_data.page) @@ -1701,38 +1862,34 @@ init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page; int retval = 0; - if (hwcb->hwc_receive_mask & ET_Msg_Mask) - hwc_data.write_nonprio = 1; - - if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask) - hwc_data.write_prio = 1; - - if (hwcb->hwc_send_mask & ET_OpCmd_Mask) { - internal_print (DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "capable of receipt of commands\n"); - hwc_data.read_nonprio = 1; - } - if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) { - internal_print (DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "capable of receipt of priority commands\n"); - hwc_data.read_nonprio = 1; - } - if ((hwcb->response_code != 0x0020) || - (!hwc_data.write_nonprio) || - ((!hwc_data.read_nonprio) && (!hwc_data.read_prio))) + if (hwcb->response_code != 0x0020) { #ifdef DUMP_HWC_INIT_ERROR __asm__ ("LHI 1,0xe11\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" + "LRA 2,0(%0)\n\t" + "L 3,0(%1)\n\t" "J .+0\n\t" : : "a" (hwcb), "a" (&(hwcb->response_code)) : "1", "2", "3"); #else - retval = -EIO; + retval = -1; #endif + } else { + if (hwcb->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe52\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (hwcb) + : "1", "2"); +#endif + } else { + retval += eval_hwc_receive_mask + (hwcb->hwc_receive_mask); + retval += eval_hwc_send_mask (hwcb->hwc_send_mask); + } + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -1764,18 +1921,6 @@ } else tmp.columns = ioctls->columns; - switch (ioctls->code) { - case CODE_EBCDIC: - case CODE_ASCII: - tmp.code = ioctls->code; - break; - default: - if (correct) - tmp.code = CODE_ASCII; - else - retval = -EINVAL; - } - tmp.final_nl = ioctls->final_nl; if (ioctls->max_hwcb < 2) { @@ -1915,7 +2060,7 @@ HWC_RW_PRINT_HEADER "use %i bytes for buffering.\n", hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); - for (i = 0; i < 500; i++) { + for (i = 0; i < 2000; i++) { hwcb = (init_hwcb_t *) BUF_HWCB; internal_print ( DELAYED_WRITE, @@ -1975,6 +2120,10 @@ } else { spin_lock (&hwc_data.lock); + if (hwc_data.flags & HWC_PTIMER_RUNS) { + del_timer (&hwc_data.poll_timer); + hwc_data.flags &= ~HWC_PTIMER_RUNS; + } if (!hwc_data.current_servc) { unconditional_read_1 (); @@ -2064,12 +2213,6 @@ goto fault; break; - case TIOCHWCSCODE: - if (get_user (tmp.code, (ioctl_code_t *) arg)) - goto fault; - - break; - case TIOCHWCSNL: if (get_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; @@ -2126,12 +2269,6 @@ case TIOCHWCGCOLS: if (put_user (tmp.columns, (ioctl_cols_t *) arg)) goto fault; - break; - - case TIOCHWCGCODE: - if (put_user (tmp.code, (ioctl_code_t *) arg)) - goto fault; - break; case TIOCHWCGNL: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/char/hwc_rw.h linux/drivers/s390/char/hwc_rw.h --- v2.2.18/drivers/s390/char/hwc_rw.h Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/char/hwc_rw.h Sun Mar 25 11:37:35 2001 @@ -26,7 +26,6 @@ typedef unsigned short int ioctl_htab_t; typedef unsigned char ioctl_echo_t; typedef unsigned short int ioctl_cols_t; -typedef unsigned char ioctl_code_t; typedef signed char ioctl_nl_t; typedef unsigned short int ioctl_obuf_t; typedef unsigned char ioctl_case_t; @@ -37,7 +36,6 @@ ioctl_htab_t width_htab; ioctl_echo_t echo; ioctl_cols_t columns; - ioctl_code_t code; ioctl_nl_t final_nl; ioctl_obuf_t max_hwcb; ioctl_obuf_t kmem_hwcb; @@ -58,8 +56,6 @@ #define TIOCHWCSCOLS _IOW(HWC_IOCTL_LETTER, 2, _hwc_ioctls.columns) -#define TIOCHWCSCODE _IOW(HWC_IOCTL_LETTER, 3, _hwc_ioctls.code) - #define TIOCHWCSNL _IOW(HWC_IOCTL_LETTER, 4, _hwc_ioctls.final_nl) #define TIOCHWCSOBUF _IOW(HWC_IOCTL_LETTER, 5, _hwc_ioctls.max_hwcb) @@ -78,8 +74,6 @@ #define TIOCHWCGCOLS _IOR(HWC_IOCTL_LETTER, 12, _hwc_ioctls.columns) -#define TIOCHWCGCODE _IOR(HWC_IOCTL_LETTER, 13, _hwc_ioctls.code) - #define TIOCHWCGNL _IOR(HWC_IOCTL_LETTER, 14, _hwc_ioctls.final_nl) #define TIOCHWCGOBUF _IOR(HWC_IOCTL_LETTER, 15, _hwc_ioctls.max_hwcb) @@ -99,9 +93,6 @@ #define TIOCHWCGMEASC _IOR(HWC_IOCTL_LETTER, 22, _hwc_ioctls.measured_chars) #define TIOCHWCGMEASS _IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls) - -#define CODE_ASCII 0x0 -#define CODE_EBCDIC 0x1 #ifndef __HWC_RW_C__ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c --- v2.2.18/drivers/s390/char/hwc_tty.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/char/hwc_tty.c Sun Mar 25 11:37:35 2001 @@ -171,7 +171,9 @@ switch (cmd) { case TIOCHWCTTYSINTRC: - count = strlen_user ((const char *) arg); + count = strnlen_user((const char *)arg, HWC_TTY_MAX_CNTL_SIZE); + if (!count) + return -EFAULT; if (count > HWC_TTY_MAX_CNTL_SIZE) return -EINVAL; strncpy_from_user (hwc_tty_data.ioctl.intr_char, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/idals.c linux/drivers/s390/idals.c --- v2.2.18/drivers/s390/idals.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/idals.c Sun Mar 25 11:37:35 2001 @@ -9,71 +9,36 @@ */ #include + #include #include -#include - -#ifdef PRINTK_HEADER -#undef PRINTK_HEADER -#endif -#define PRINTK_HEADER "idals:" - -/* a name template for the cache-names */ -static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */ -/* the cache's names */ -static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1]; -/* the caches itself*/ -static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES]; -void -free_idal ( ccw1_t *cp ) +#ifdef CONFIG_ARCH_S390X +void +set_normalized_cda ( ccw1_t * cp, unsigned long address ) { + int nridaws; idaw_t *idal; - unsigned long upper2k,lower2k; - int nridaws,cacheind; - if ( cp -> flags & CCW_FLAG_IDA ) { - idal = cp -> cda; - lower2k = *idal & 0xfffffffffffff800; - upper2k = (*idal + cp -> count - 1) & 0xfffffffffffff800; - nridaws = ((upper2k - lower2k) >> 11) + 1; - for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ ); - kmem_cache_free ( idal_cache[cacheind], idal ); - } -} - -int -idal_support_init ( void ) -{ - int rc=0; - int cachind; - - for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { - int slabsize = 8 << cachind; - sprintf ( idal_cache_name[cachind], - "%s%d%c", idal_name_template, slabsize, 0); - idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind], - slabsize, 0, - SLAB_HWCACHE_ALIGN | SLAB_DMA, - NULL, NULL ); - if ( ! idal_cache [cachind] ) { - printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n"); - } - } - - return rc; -} + int count = cp->count; -void idal_support_cleanup ( void ) -{ - int cachind; - - /* Shrink the caches, if available */ - for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { - if ( idal_cache[cachind] ) { - if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) { - idal_cache[cachind] = NULL; - } - } + if (cp->flags & CCW_FLAG_IDA) + BUG(); + if (((address + count) >> 31) == 0) + cp -> cda = address; + return; + nridaws = ((address & 2047L) + count + 2047L) >> 11; + idal = idal_alloc(nridaws); + if ( idal == NULL ) { + /* probably we should have a fallback here */ + panic ("Cannot allocate memory for IDAL\n"); } - + cp->flags |= CCW_FLAG_IDA; + cp->cda = (__u32)(unsigned long)(idaw_t *)idal; + do { + *idal++ = address; + address = (address & -2048L) + 2048; + nridaws --; + } while ( nridaws > 0 ); + return; } +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/misc/Makefile linux/drivers/s390/misc/Makefile --- v2.2.18/drivers/s390/misc/Makefile Sun Mar 25 11:13:11 2001 +++ linux/drivers/s390/misc/Makefile Sun Mar 25 11:37:35 2001 @@ -2,7 +2,8 @@ CFLAFS += O_TARGET := s390-misc.o -O_OBJS := +O_OBJS := +OX_OBJS := M_OBJS := include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile --- v2.2.18/drivers/s390/net/Makefile Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/net/Makefile Sun Mar 25 11:37:35 2001 @@ -2,7 +2,8 @@ CFLAFS += O_TARGET := s390-net.o -O_OBJS := iucv.o +O_OBJS := +OX_OBJS := iucv.o M_OBJS := ifeq ($(CONFIG_CTC),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c --- v2.2.18/drivers/s390/net/ctc.c Sun Mar 25 11:28:27 2001 +++ linux/drivers/s390/net/ctc.c Sun Mar 25 11:37:35 2001 @@ -1,5 +1,5 @@ /* - * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $ + * $Id: ctc.c,v 1.29 2001/01/25 22:28:21 uweigand Exp $ * * drivers/s390/net/ctc.c * CTC / ESCON network driver @@ -22,12 +22,13 @@ * order or doesn't want to have automatic channel selection on, you can do * this with the "ctc= kernel keyword". * - * ctc=0,0xrrrr,0xwwww,ddddd + * ctc=prid,0xrrrr,0xwwww,ddddd * * Where: * - * "rrrr" is the read channel address - * "wwww" is the write channel address + * "prid" is the protocol id (must always be 0) + * "rrrr" is the read channel address (hexadecimal) + * "wwww" is the write channel address (hexadecimal) * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 * to escon7 for ESCON channels). * @@ -38,24 +39,39 @@ * ctc=noauto * * $Log: ctc.c,v $ - * Revision 1.25.2.5 2000/10/11 15:08:59 bird - * ctc_tx(): Quick fix of possible underflow when calculating free block space + * Revision 1.29 2001/01/25 22:28:21 uweigand + * Minor 2.2.18 fix. * - * Revision 1.25.2.4 2000/09/25 16:40:56 bird - * Some more debug information + * Revision 1.28 2001/01/18 13:04:47 tonn + * upgrade to 2.2.18 * - * Revision 1.25.2.3 2000/09/20 13:28:19 bird - * - ctc_open(): fixed bug - * - ctc_release(): added timer for terminating in case of halt_io()-hang - * - * Revision 1.25.2.2 2000/09/20 09:48:27 bird - * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in - * instead of direct waiting on a wait queue - * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check(): - * print more debug information + * Revision 1.27 2000/10/26 16:16:07 bird + * Merged in changes from Revision 1.25.2.1 to Revision 1.25.2.6: * - * Revision 1.25.2.1 2000/09/19 09:09:56 bird - * Merged in changes from 1.25 to 1.26 + * Revision 1.25.2.6 2000/10/25 16:11:55 bird + * Set size of empty block to BLOCK_HEADER_LENGTH (used to be 0) + * + * Revision 1.25.2.5 2000/10/11 15:08:59 bird + * ctc_tx(): Quick fix of possible underflow when calculating free block space + * + * Revision 1.25.2.4 2000/09/25 16:40:56 bird + * Some more debug information + * + * Revision 1.25.2.3 2000/09/20 13:28:19 bird + * - ctc_open(): fixed bug + * - ctc_release(): added timer for terminating in case of halt_io()-hang + * + * Revision 1.25.2.2 2000/09/20 09:48:27 bird + * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in + * instead of direct waiting on a wait queue + * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check(): + * print more debug information + * + * Revision 1.25.2.1 2000/09/19 09:09:56 bird + * Merged in changes from 1.25 to 1.26 + * + * Revision 1.26 2000/09/15 12:29:32 weigand + * Some 2.3 diffs merged and other fixes. * * Revision 1.25 2000/09/08 09:22:11 bird * Proper cleanup and bugfixes in ctc_probe() @@ -276,8 +292,6 @@ typedef struct net_device net_device; #else typedef struct device net_device; -typedef struct wait_queue* wait_queue_head_t; -#define init_waitqueue_head(nothing) #endif struct adapterlist{ @@ -319,9 +333,9 @@ #define CTC_BH_ACTIVE 0 __u8 last_dstat; __u8 flag; -#define CTC_WRITE 0x01 /* - Set if this is a write channel */ +#define CTC_WRITE 0x01 /* - Set if this is a write channel */ #define CTC_WAKEUP 0x02 /* - Set if this channel should wake up from waiting for an event */ -#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ +#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ }; @@ -352,6 +366,8 @@ __u16 length; struct packet data; }; +#define BLOCK_PAGES_POW 4 /* 2^4 = 16 pages per block (64k) */ +#define BLOCK_MAX_DATA 65535 /* maximal amount of data a block can hold */ #if LINUX_VERSION_CODE>=0x02032D #define ctc_protect_busy(dev) \ @@ -485,7 +501,7 @@ */ static void print_banner(void) { static int printed = 0; - char vbuf[] = "$Revision: 1.25.2.5 $"; + char vbuf[] = "$Revision: 1.29 $"; char *version = vbuf; if (printed) @@ -763,12 +779,12 @@ else { p->next = NULL; p->packets = 0; - p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4); + p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, BLOCK_PAGES_POW); if (p->block == NULL) { kfree(p); return -ENOMEM; } - p->block->length = 0; + p->block->length = BLOCK_HEADER_LENGTH; /* empty block */ } if (ctc->free_anchor == NULL) @@ -1109,7 +1125,7 @@ } - + static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) { int rc = 0; @@ -1196,7 +1212,6 @@ wake_up(&ctc->wait); /* wake up ctc_release */ return; - case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_HALT_IO"); @@ -1228,7 +1243,6 @@ return; ctc->state = CTC_START_SELECT; - case CTC_START_SELECT: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SELECT"); @@ -1241,7 +1255,7 @@ } if (!(ctc->flag & CTC_WRITE)) { ctc->state = CTC_START_READ_TEST; - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); @@ -1253,7 +1267,7 @@ } else { ctc->state = CTC_START_WRITE_TEST; /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; @@ -1263,7 +1277,6 @@ } return; - case CTC_START_READ_TEST: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ_TEST"); @@ -1300,8 +1313,7 @@ /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ - - case CTC_START_READ: + case CTC_START_READ: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ"); #endif @@ -1333,7 +1345,7 @@ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); if (ctc->free_anchor != NULL) { - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); @@ -1352,7 +1364,6 @@ } return; - case CTC_START_WRITE_TEST: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE_TEST"); @@ -1378,7 +1389,6 @@ wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ return; - case CTC_START_WRITE: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE"); @@ -1394,7 +1404,7 @@ privptr->stats.tx_packets += ctc->proc_anchor->packets; } - ctc->proc_anchor->block->length = 0; + ctc->proc_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev); ctc_clearbit_busy(TB_NOBUFFER, dev); if (ctc->proc_anchor != NULL) { @@ -1416,7 +1426,7 @@ "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr); return; } - if (ctc->free_anchor->block->length != 0) { + if (ctc->free_anchor->block->length != BLOCK_HEADER_LENGTH) { /* non-empty block */ if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { /* set transmission to busy */ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); @@ -1470,15 +1480,17 @@ while (ctc->proc_anchor != NULL) { block = ctc->proc_anchor->block; - if (block->length < BLOCK_HEADER_LENGTH) { - if(block->length == 0 && !ctc->initial_block_received) - ctc->initial_block_received = 1; - else + + if ((block->length < BLOCK_HEADER_LENGTH) + || (block->length == BLOCK_HEADER_LENGTH && ctc->initial_block_received)) { printk(KERN_INFO "%s: %s(): discarding block at 0x%p: " - "block length=%d<%d=block header length\n", + "block length=%d<=%d=block header length\n", dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH); } - else { + else if(block->length == BLOCK_HEADER_LENGTH && !ctc->initial_block_received) { + ctc->initial_block_received = 1; + } + else { /* there is valid data in the buffer */ lp = &block->data; while ((__u8 *) lp < (__u8 *) block + block->length) { if(lp->length < PACKET_HEADER_LENGTH) { @@ -1559,6 +1571,7 @@ dev->name, ctc->state); #endif s390irq_spin_lock_irqsave(ctc->irq, saveflags); + if (ctc->state != CTC_STOP) { if (!ctc->free_anchor) { s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); @@ -1568,7 +1581,7 @@ return; } - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags); @@ -1636,7 +1649,6 @@ struct ctc_priv *privptr; struct timer_list timer; - ctc_set_busy(dev); privptr = (struct ctc_priv *) (dev->priv); @@ -1698,13 +1710,13 @@ rc = halt_IO(privptr->channel[i].irq, parm, flags); s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); - - del_timer(&timer); - if(rc != 0) ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); + + del_timer(&timer); + if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */ for (ii=0; ii<=i; ii++) { @@ -1720,7 +1732,7 @@ return -ERESTARTSYS; } } - + if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) { @@ -1783,7 +1795,7 @@ ctc_setbit_busy(TB_STOP,dev); ctc_unprotect_busy_irqrestore(dev, saveflags); - for (i = 0; i < 2; i++) { + for (i = 0; i < 2; i++) { privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER); init_timer(&timer); timer.function = ctc_timer; @@ -1805,7 +1817,7 @@ if (rc != 0) { ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); } - + if(privptr->channel[i].flag & CTC_TIMER) { printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n", @@ -1874,7 +1886,7 @@ goto Done; } - if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) { + if (privptr->channel[WRITE].free_anchor->block->length + PACKET_HEADER_LENGTH + skb->len > BLOCK_MAX_DATA) { #ifdef DEBUG printk(KERN_DEBUG "%s: early swap\n", dev->name); #endif @@ -1887,15 +1899,14 @@ } } - if (privptr->channel[WRITE].free_anchor->block->length == 0) { - privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; + if (privptr->channel[WRITE].free_anchor->block->length == BLOCK_HEADER_LENGTH) { /* empty block */ privptr->channel[WRITE].free_anchor->packets = 0; } (__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length; - privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH; - lp->length = skb->len + PACKET_HEADER_LENGTH; + privptr->channel[WRITE].free_anchor->block->length += PACKET_HEADER_LENGTH + skb->len; + lp->length = PACKET_HEADER_LENGTH + skb->len; lp->type = 0x0800; lp->unused = 0; memcpy(&lp->data, skb->data, skb->len); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c --- v2.2.18/drivers/s390/net/iucv.c Sun Mar 25 11:28:28 2001 +++ linux/drivers/s390/net/iucv.c Sun Mar 25 11:37:35 2001 @@ -9,6 +9,8 @@ * Alan Altmark (Alan_Altmark@us.ibm.com) */ +#include +#include #include #include #include @@ -28,8 +30,6 @@ //#define DEBUG /* Turns Printk's on */ //#define DEBUG2 /* This prints the parameter list before and */ /* after the b2f0 call to cp */ -#define EXPORT_SYMTAB -#include #undef NULL #define NULL 0 #define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */ @@ -1533,7 +1533,7 @@ { iucv_packet *pkt; pkt = (iucv_packet *) kmalloc - (sizeof (iucv_packet), GFP_KERNEL | GFP_ATOMIC); + (sizeof (iucv_packet), GFP_ATOMIC); if (pkt == NULL) { printk (KERN_DEBUG "out of memory\n"); return; @@ -1869,15 +1869,16 @@ new_handler->size = ADDED_STOR; /* Allocate storage for pathid table */ new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL); - memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong)); if (new_handler->start == NULL) { #ifdef DEBUG printk (KERN_DEBUG "IUCV: returned NULL address for pathid table," " exiting\n"); #endif + kfree(new_handler); return NULL; } + memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong)); new_handler->end = (*new_handler).start + ADDED_STOR; new_handler->next = 0; new_handler->prev = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c --- v2.2.18/drivers/s390/net/netiucv.c Sun Mar 25 11:28:28 2001 +++ linux/drivers/s390/net/netiucv.c Sun Mar 25 11:37:35 2001 @@ -493,7 +493,7 @@ pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid, buffer_length); - buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA); + buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA); if (buffer == NULL) { p->stats.rx_dropped++; return; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sbus/audio/cs4215.h linux/drivers/sbus/audio/cs4215.h --- v2.2.18/drivers/sbus/audio/cs4215.h Sun Mar 25 11:13:08 2001 +++ linux/drivers/sbus/audio/cs4215.h Sun Mar 25 11:37:35 2001 @@ -105,7 +105,7 @@ /* Time Slot 6, Output Setting */ #define CS4215_RO(v) v /* Right Output Attenuation 0x3f: -94.5 dB */ -#define CS4215_SE (1<<6) /* Line Out Enable */ +#define CS4215_SE (1<<6) /* Speaker Enable */ #define CS4215_ADI (1<<7) /* A/D Data Invalid: Busy in calibration */ /* Time Slot 7, Input Setting */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c --- v2.2.18/drivers/sbus/audio/dbri.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/sbus/audio/dbri.c Sun Mar 25 11:37:35 2001 @@ -1382,8 +1382,13 @@ dbri->perchip_info.play.channels = 1; dbri->perchip_info.play.precision = 8; - dbri->perchip_info.play.gain = 128; + dbri->perchip_info.play.gain = (AUDIO_MAX_GAIN * 7 / 10); /* 70% */ dbri->perchip_info.play.balance = AUDIO_MID_BALANCE; + dbri->perchip_info.play.port = dbri->perchip_info.play.avail_ports = + AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT; + dbri->perchip_info.record.port = AUDIO_MICROPHONE; + dbri->perchip_info.record.avail_ports = + AUDIO_MICROPHONE | AUDIO_LINE_IN; } /* mmcodec_setgain(dbri, int muted) @@ -1406,6 +1411,7 @@ } else { int left_gain = (dbri->perchip_info.play.gain / 4) % 64; int right_gain = (dbri->perchip_info.play.gain / 4) % 64; + int outport = dbri->perchip_info.play.port; if (dbri->perchip_info.play.balance < AUDIO_MID_BALANCE) { right_gain *= dbri->perchip_info.play.balance; @@ -1416,8 +1422,12 @@ left_gain /= AUDIO_MID_BALANCE; } - dbri->mm.data[0] = CS4215_LE | CS4215_HE | (63 - left_gain); - dbri->mm.data[1] = CS4215_SE | (63 - right_gain); + dbri->mm.data[0] = (63 - left_gain); + if (outport & AUDIO_HEADPHONE) dbri->mm.data[0] |= CS4215_HE; + if (outport & AUDIO_LINE_OUT) dbri->mm.data[0] |= CS4215_LE; + dbri->mm.data[1] = (63 - right_gain); + if (outport & AUDIO_SPEAKER) dbri->mm.data[1] |= CS4215_SE; + } xmit_fixed(dbri, 20, *(int *)dbri->mm.data); @@ -1585,7 +1595,7 @@ dbri->mm.offset = chi_offsets[i]; if (mmcodec_setctrl(dbri) && dbri->mm.version != 0xff) { dbri->perchip_info.play.balance = AUDIO_MID_BALANCE; - dbri->perchip_info.play.gain = AUDIO_MAX_GAIN/2; + dbri->perchip_info.play.gain = AUDIO_MAX_GAIN*7/10; return 0; } } @@ -1936,32 +1946,52 @@ static int dbri_set_output_port(struct sparcaudio_driver *drv, int port) { - return 0; + struct dbri *dbri = (struct dbri *) drv->private; + + port &= dbri->perchip_info.play.avail_ports; + dbri->perchip_info.play.port = port; + mmcodec_setgain(dbri, 0); + + return 0; } static int dbri_get_output_port(struct sparcaudio_driver *drv) { - return 0; + struct dbri *dbri = (struct dbri *) drv->private; + + return dbri->perchip_info.play.port; } static int dbri_set_input_port(struct sparcaudio_driver *drv, int port) { - return 0; + struct dbri *dbri = (struct dbri *) drv->private; + + port &= dbri->perchip_info.record.avail_ports; + dbri->perchip_info.record.port = port; + mmcodec_setgain(dbri, 0); + + return 0; } static int dbri_get_input_port(struct sparcaudio_driver *drv) { - return 0; + struct dbri *dbri = (struct dbri *) drv->private; + + return dbri->perchip_info.record.port; } static int dbri_get_output_ports(struct sparcaudio_driver *drv) { - return 0; + struct dbri *dbri = (struct dbri *) drv->private; + + return dbri->perchip_info.play.avail_ports; } static int dbri_get_input_ports(struct sparcaudio_driver *drv) { - return 0; + struct dbri *dbri = (struct dbri *) drv->private; + + return dbri->perchip_info.record.avail_ports; } /******************* sparcaudio midlevel - driver ID ********************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile --- v2.2.18/drivers/sbus/char/Makefile Sun Mar 25 11:13:08 2001 +++ linux/drivers/sbus/char/Makefile Sun Mar 25 11:37:35 2001 @@ -45,6 +45,14 @@ endif endif +ifeq ($(CONFIG_WATCHDOG_CP1XXX),y) +O_OBJS += cpwatchdog.o +else + ifeq ($(CONFIG_WATCHDOG_CP1XXX),m) + M_OBJS += cpwatchdog.o + endif +endif + endif # eq($(CONFIG_PCI,y) ifeq ($(CONFIG_OBP_FLASH),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sbus/char/cpwatchdog.c linux/drivers/sbus/char/cpwatchdog.c --- v2.2.18/drivers/sbus/char/cpwatchdog.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/sbus/char/cpwatchdog.c Sun Mar 25 11:37:35 2001 @@ -0,0 +1,846 @@ +/* cpwatchdog.c - driver implementation for hardware watchdog + * timers found on Sun Microsystems CP1400 and CP1500 boards. + * + * This device supports both the generic Linux watchdog + * interface and Solaris-compatible ioctls as best it is + * able. + * + * NOTE: CP1400 systems appear to have a defective intr_mask + * register on the PLD, preventing the disabling of + * timer interrupts. We use a timer to periodically + * reset 'stopped' watchdogs on affected platforms. + * + * Copyright (c) 2000 Eric Brower (ebrower@usa.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WD_OBPNAME "watchdog" +#define WD_BADMODEL "SUNW,501-5336" +#define WD_BTIMEOUT (jiffies + (HZ * 1000)) +#define WD_BLIMIT 0xFFFF + +#define WD0_DEVNAME "watchdog0" +#define WD1_DEVNAME "watchdog1" +#define WD2_DEVNAME "watchdog2" + +#define WD0_MINOR 212 +#define WD1_MINOR 213 +#define WD2_MINOR 214 + +#define WD_DEBUG + +/* Internal driver definitions + */ +#define WD0_ID 0 /* Watchdog0 */ +#define WD1_ID 1 /* Watchdog1 */ +#define WD2_ID 2 /* Watchdog2 */ +#define WD_NUMDEVS 3 /* Device contains 3 timers */ + +#define WD_INTR_OFF 0 /* Interrupt disable value */ +#define WD_INTR_ON 1 /* Interrupt enable value */ + +#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ +#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ +#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ + +/* Register value definitions + */ +#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ +#define WD1_INTR_MASK 0x02 +#define WD2_INTR_MASK 0x04 + +#define WD_S_RUNNING 0x01 /* Watchdog device status running */ +#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ + +/* Sun uses Altera PLD EPF8820ATC144-4 + * providing three hardware watchdogs: + * + * 1) RIC - sends an interrupt when triggered + * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU + * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board + * + *** Timer register block definition (struct wd_timer_regblk) + * + * dcntr and limit registers (halfword access): + * ------------------- + * | 15 | ...| 1 | 0 | + * ------------------- + * |- counter val -| + * ------------------- + * dcntr - Current 16-bit downcounter value. + * When downcounter reaches '0' watchdog expires. + * Reading this register resets downcounter with 'limit' value. + * limit - 16-bit countdown value in 1/10th second increments. + * Writing this register begins countdown with input value. + * Reading from this register does not affect counter. + * NOTES: After watchdog reset, dcntr and limit contain '1' + * + * status register (byte access): + * --------------------------- + * | 7 | ... | 2 | 1 | 0 | + * --------------+------------ + * |- UNUSED -| EXP | RUN | + * --------------------------- + * status- Bit 0 - Watchdog is running + * Bit 1 - Watchdog has expired + * + *** PLD register block definition (struct wd_pld_regblk) + * + * intr_mask register (byte access): + * --------------------------------- + * | 7 | ... | 3 | 2 | 1 | 0 | + * +-------------+------------------ + * |- UNUSED -| WD3 | WD2 | WD1 | + * --------------------------------- + * WD3 - 1 == Interrupt disabled for watchdog 3 + * WD2 - 1 == Interrupt disabled for watchdog 2 + * WD1 - 1 == Interrupt disabled for watchdog 1 + * + * pld_status register (byte access): + * UNKNOWN, MAGICAL MYSTERY REGISTER + * + */ +struct wd_timer_regblk { + volatile __u16 dcntr; /* down counter - hw */ + volatile __u16 dcntr_pad; + volatile __u16 limit; /* limit register - hw */ + volatile __u16 limit_pad; + volatile __u8 status; /* status register - b */ + volatile __u8 status_pad; + volatile __u16 status_pad2; + volatile __u32 pad32; /* yet more padding */ +}; + +struct wd_pld_regblk { + volatile __u8 intr_mask; /* interrupt mask - b */ + volatile __u8 intr_mask_pad; + volatile __u16 intr_mask_pad2; + volatile __u8 status; /* device status - b */ + volatile __u8 status_pad; + volatile __u16 status_pad2; +}; + +struct wd_regblk { + volatile struct wd_timer_regblk wd0_regs; + volatile struct wd_timer_regblk wd1_regs; + volatile struct wd_timer_regblk wd2_regs; + volatile struct wd_pld_regblk pld_regs; +}; + +/* Individual timer structure + */ +struct wd_timer { + __u16 timeout; + __u8 intr_mask; + unsigned char runstatus; + volatile struct wd_timer_regblk* regs; +}; + +/* Device structure + */ +struct wd_device { + int irq; + spinlock_t lock; + unsigned char isbaddoggie; /* defective PLD */ + unsigned char opt_enable; + unsigned char opt_reboot; + unsigned short opt_timeout; + unsigned char initialized; + struct wd_timer watchdog[WD_NUMDEVS]; + volatile struct wd_regblk* regs; +}; + +static struct wd_device wd_dev = { + 0, SPIN_LOCK_UNLOCKED, 0, 0, 0, 0, +}; + +struct timer_list wd_timer; + +static int wd0_timeout = 0; +static int wd1_timeout = 0; +static int wd2_timeout = 0; + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +MODULE_PARM (wd0_timeout, "i"); +MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); +MODULE_PARM (wd1_timeout, "i"); +MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); +MODULE_PARM (wd2_timeout, "i"); +MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); + +MODULE_AUTHOR + ("Eric Brower "); +MODULE_DESCRIPTION + ("Hardware watchdog driver for Sun Microsystems CP1400/1500"); +MODULE_SUPPORTED_DEVICE + ("watchdog"); +#endif /* ifdef MODULE */ + +/* Forward declarations of internal methods + */ +void wd_dumpregs(void); +void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs); +void wd_toggleintr(struct wd_timer* pTimer, int enable); +void wd_pingtimer(struct wd_timer* pTimer); +void wd_starttimer(struct wd_timer* pTimer); +void wd_resetbrokentimer(struct wd_timer* pTimer); +void wd_stoptimer(struct wd_timer* pTimer); +void wd_brokentimer(unsigned long data); +int wd_getstatus(struct wd_timer* pTimer); + +#define wd_writew(val, addr) (addr = val) +#define wd_writeb(val, addr) (addr = val) +#define wd_readw(addr) (addr) +#define wd_readb(addr) (addr) + +/* CP1400s seem to have broken PLD implementations-- + * the interrupt_mask register cannot be written, so + * no timer interrupts can be masked within the PLD. + */ +static inline int wd_isbroken(void) +{ + /* we could test this by read/write/read/restore + * on the interrupt mask register only if OBP + * 'watchdog-enable?' == FALSE, but it seems + * ubiquitous on CP1400s + */ + char val[32]; + prom_getproperty(prom_root_node, "model", val, sizeof(val)); + return((!strcmp(val, WD_BADMODEL)) ? 1 : 0); +} + +/* Retrieve watchdog-enable? option from OBP + * Returns 0 if false, 1 if true + */ +static inline int wd_opt_enable(void) +{ + int opt_node; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1); +} + +/* Retrieve watchdog-reboot? option from OBP + * Returns 0 if false, 1 if true + */ +static inline int wd_opt_reboot(void) +{ + int opt_node; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1); +} + +/* Retrieve watchdog-timeout option from OBP + * Returns OBP value, or 0 if not located + */ +static inline int wd_opt_timeout(void) +{ + int opt_node; + char value[32]; + char *p = value; + + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + opt_node = prom_getproperty(opt_node, + "watchdog-timeout", + value, + sizeof(value)); + if(-1 != opt_node) { + /* atoi implementation */ + for(opt_node = 0; /* nop */; p++) { + if(*p >= '0' && *p <= '9') { + opt_node = (10*opt_node)+(*p-'0'); + } + else { + break; + } + } + } + return((-1 == opt_node) ? (0) : (opt_node)); +} + +static int wd_open(struct inode *inode, struct file *f) +{ + switch(MINOR(inode->i_rdev)) + { + case WD0_MINOR: + f->private_data = &wd_dev.watchdog[WD0_ID]; + break; + case WD1_MINOR: + f->private_data = &wd_dev.watchdog[WD1_ID]; + break; + case WD2_MINOR: + f->private_data = &wd_dev.watchdog[WD2_ID]; + break; + default: + return(-ENODEV); + } + + /* Register IRQ on first open of device */ + if(0 == wd_dev.initialized) + { + if (request_irq(wd_dev.irq, + &wd_interrupt, + SA_SHIRQ, + WD_OBPNAME, + (void *)wd_dev.regs)) { + printk("%s: Cannot register IRQ %s\n", + WD_OBPNAME, __irq_itoa(wd_dev.irq)); + return(-EBUSY); + } + wd_dev.initialized = 1; + } + + MOD_INC_USE_COUNT; + return(0); +} + +static int wd_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int wd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int setopt = 0; + struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + struct watchdog_info info = { + 0, + 0, + "Altera EPF8820ATC144-4" + }; + + if(NULL == pTimer) { + return(-EINVAL); + } + + switch(cmd) + { + /* Generic Linux IOCTLs */ + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, + (struct watchdog_info *)&info, + sizeof(struct watchdog_info *))) { + return(-EFAULT); + } + break; + case WDIOC_KEEPALIVE: + wd_pingtimer(pTimer); + break; + case WDIOC_SETOPTIONS: + if(copy_from_user(&setopt, (void*) arg, sizeof(unsigned int))) { + return -EFAULT; + } + if(setopt & WDIOS_DISABLECARD) { + if(wd_dev.opt_enable) { + printk( + "%s: cannot disable watchdog in ENABLED mode\n", + WD_OBPNAME); + return(-EINVAL); + } + wd_stoptimer(pTimer); + } + else if(setopt & WDIOS_ENABLECARD) { + wd_starttimer(pTimer); + } + else { + return(-EINVAL); + } + break; + /* Solaris-compatible IOCTLs */ + case WIOCGSTAT: + setopt = wd_getstatus(pTimer); + if(copy_to_user((void*)arg, &setopt, sizeof(unsigned int))) { + return(-EFAULT); + } + break; + case WIOCSTART: + wd_starttimer(pTimer); + break; + case WIOCSTOP: + if(wd_dev.opt_enable) { + printk("%s: cannot disable watchdog in ENABLED mode\n", + WD_OBPNAME); + return(-EINVAL); + } + wd_stoptimer(pTimer); + break; + default: + return(-EINVAL); + } + return(0); +} + +static ssize_t wd_write( struct file *file, + const char *buf, + size_t count, + loff_t *ppos) +{ + struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + + if(NULL == pTimer) { + return(-EINVAL); + } + + wd_pingtimer(pTimer); + return(count); +} + +static ssize_t wd_read(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ +#ifdef WD_DEBUG + wd_dumpregs(); + return(0); +#else + return(-EINVAL); +#endif /* ifdef WD_DEBUG */ +} + +void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* Only WD0 will interrupt-- others are NMI and we won't + * see them here.... + */ + spin_lock_irq(&wd_dev.lock); + if((unsigned long)wd_dev.regs == (unsigned long)dev_id) + { + wd_stoptimer(&wd_dev.watchdog[WD0_ID]); + wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD; + } + spin_unlock_irq(&wd_dev.lock); + return; +} + +static struct file_operations wd_fops = { + NULL, /* lseek */ + wd_read, + wd_write, + NULL, /* readdir */ + NULL, /* select */ + wd_ioctl, + NULL, /* mmap */ + wd_open, + NULL, /* flush */ + wd_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* chk media*/ + NULL, /* revalid */ + NULL, /* lock */ +}; + +static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops }; +static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; +static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; + +void wd_dumpregs(void) +{ + /* Reading from downcounters initiates watchdog countdown-- + * Example is included below for illustration purposes. + */ + int i; + printk("%s: dumping register values\n", WD_OBPNAME); + for(i = WD0_ID; i < WD_NUMDEVS; ++i) { + /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n", + WD_OBPNAME, + i, + (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), + wd_readw(wd_dev.watchdog[i].regs->dcntr)); + */ + printk("\t%s%i: limit at 0x%lx: 0x%x\n", + WD_OBPNAME, + i, + (unsigned long)(&wd_dev.watchdog[i].regs->limit), + wd_readw(wd_dev.watchdog[i].regs->limit)); + printk("\t%s%i: status at 0x%lx: 0x%x\n", + WD_OBPNAME, + i, + (unsigned long)(&wd_dev.watchdog[i].regs->status), + wd_readb(wd_dev.watchdog[i].regs->status)); + printk("\t%s%i: driver status: 0x%x\n", + WD_OBPNAME, + i, + wd_getstatus(&wd_dev.watchdog[i])); + } + printk("\tintr_mask at 0x%lx: 0x%x\n", + (unsigned long)(&wd_dev.regs->pld_regs.intr_mask), + wd_readb(wd_dev.regs->pld_regs.intr_mask)); + printk("\tpld_status at 0x%lx: 0x%x\n", + (unsigned long)(&wd_dev.regs->pld_regs.status), + wd_readb(wd_dev.regs->pld_regs.status)); +} + +/* Enable or disable watchdog interrupts + * Because of the CP1400 defect this should only be + * called during initialzation or by wd_[start|stop]timer() + * + * pTimer - pointer to timer device, or NULL to indicate all timers + * enable - non-zero to enable interrupts, zero to disable + */ +void wd_toggleintr(struct wd_timer* pTimer, int enable) +{ + unsigned char curregs = wd_readb(wd_dev.regs->pld_regs.intr_mask); + unsigned char setregs = + (NULL == pTimer) ? + (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : + (pTimer->intr_mask); + + (WD_INTR_ON == enable) ? + (curregs &= ~setregs): + (curregs |= setregs); + + wd_writeb(curregs, wd_dev.regs->pld_regs.intr_mask); + return; +} + +/* Reset countdown timer with 'limit' value and continue countdown. + * This will not start a stopped timer. + * + * pTimer - pointer to timer device + */ +void wd_pingtimer(struct wd_timer* pTimer) +{ + if(wd_readb(pTimer->regs->status) & WD_S_RUNNING) { + wd_readb(pTimer->regs->dcntr); + } +} + +/* Stop a running watchdog timer-- the timer actually keeps + * running, but the interrupt is masked so that no action is + * taken upon expiration. + * + * pTimer - pointer to timer device + */ +void wd_stoptimer(struct wd_timer* pTimer) +{ + if(wd_readb(pTimer->regs->status) & WD_S_RUNNING) { + wd_toggleintr(pTimer, WD_INTR_OFF); + + if(wd_dev.isbaddoggie) { + pTimer->runstatus |= WD_STAT_BSTOP; + wd_brokentimer((unsigned long)&wd_dev); + } + } +} + +/* Start a watchdog timer with the specified limit value + * If the watchdog is running, it will be restarted with + * the provided limit value. + * + * This function will enable interrupts on the specified + * watchdog. + * + * pTimer - pointer to timer device + * limit - limit (countdown) value in 1/10th seconds + */ +void wd_starttimer(struct wd_timer* pTimer) +{ + if(wd_dev.isbaddoggie) { + pTimer->runstatus &= ~WD_STAT_BSTOP; + } + pTimer->runstatus &= ~WD_STAT_SVCD; + wd_writew(pTimer->timeout, pTimer->regs->limit); + wd_toggleintr(pTimer, WD_INTR_ON); +} + +/* Restarts timer with maximum limit value and + * does not unset 'brokenstop' value. + */ +void wd_resetbrokentimer(struct wd_timer* pTimer) +{ + wd_toggleintr(pTimer, WD_INTR_ON); + wd_writew(WD_BLIMIT, pTimer->regs->limit); +} + +/* Timer device initialization helper. + * Returns 0 on success, other on failure + */ +int wd_inittimer(int whichdog) +{ + struct miscdevice *whichmisc; + volatile struct wd_timer_regblk *whichregs; + char whichident[8]; + int whichmask; + __u16 whichlimit; + + switch(whichdog) + { + case WD0_ID: + whichmisc = &wd0_miscdev; + strcpy(whichident, "RIC"); + whichregs = &wd_dev.regs->wd0_regs; + whichmask = WD0_INTR_MASK; + whichlimit= (0 == wd0_timeout) ? + (wd_dev.opt_timeout): + (wd0_timeout); + break; + case WD1_ID: + whichmisc = &wd1_miscdev; + strcpy(whichident, "XIR"); + whichregs = &wd_dev.regs->wd1_regs; + whichmask = WD1_INTR_MASK; + whichlimit= (0 == wd1_timeout) ? + (wd_dev.opt_timeout): + (wd1_timeout); + break; + case WD2_ID: + whichmisc = &wd2_miscdev; + strcpy(whichident, "POR"); + whichregs = &wd_dev.regs->wd2_regs; + whichmask = WD2_INTR_MASK; + whichlimit= (0 == wd2_timeout) ? + (wd_dev.opt_timeout): + (wd2_timeout); + break; + default: + printk("%s: %s: invalid watchdog id: %i\n", + WD_OBPNAME, __FUNCTION__, whichdog); + return(1); + } + if(0 != misc_register(whichmisc)) + { + return(1); + } + wd_dev.watchdog[whichdog].regs = whichregs; + wd_dev.watchdog[whichdog].timeout = whichlimit; + wd_dev.watchdog[whichdog].intr_mask = whichmask; + wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP; + wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT; + + printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", + WD_OBPNAME, + whichdog, + whichident, + wd_dev.watchdog[whichdog].timeout / 10, + wd_dev.watchdog[whichdog].timeout % 10, + (0 != wd_dev.opt_enable) ? "in ENABLED mode" : ""); + return(0); +} + +/* Timer method called to reset stopped watchdogs-- + * because of the PLD bug on CP1400, we cannot mask + * interrupts within the PLD so me must continually + * reset the timers ad infinitum. + */ +void wd_brokentimer(unsigned long data) +{ + struct wd_device* pDev = (struct wd_device*)data; + int id, tripped = 0; + + /* kill a running timer instance, in case we + * were called directly instead of by kernel timer + */ + if(timer_pending(&wd_timer)) { + del_timer(&wd_timer); + } + + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) { + ++tripped; + wd_resetbrokentimer(&pDev->watchdog[id]); + } + } + + if(tripped) { + /* there is at least one timer brokenstopped-- reschedule */ + wd_timer.expires = WD_BTIMEOUT; + add_timer(&wd_timer); + } +} + +int wd_getstatus(struct wd_timer* pTimer) +{ + unsigned char stat = wd_readb(pTimer->regs->status); + unsigned char intr = wd_readb(wd_dev.regs->pld_regs.intr_mask); + unsigned char ret = WD_STOPPED; + + /* determine STOPPED */ + if(0 == stat ) { + return(ret); + } + /* determine EXPIRED vs FREERUN vs RUNNING */ + else if(WD_S_EXPIRED & stat) { + ret = WD_EXPIRED; + } + else if(WD_S_RUNNING & stat) { + if(intr & pTimer->intr_mask) { + ret = WD_FREERUN; + } + else { + /* Fudge WD_EXPIRED status for defective CP1400-- + * IF timer is running + * AND brokenstop is set + * AND an interrupt has been serviced + * we are WD_EXPIRED. + * + * IF timer is running + * AND brokenstop is set + * AND no interrupt has been serviced + * we are WD_FREERUN. + */ + if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) { + if(pTimer->runstatus & WD_STAT_SVCD) { + ret = WD_EXPIRED; + } + else { + /* we could as well pretend we are expired */ + ret = WD_FREERUN; + } + } + else { + ret = WD_RUNNING; + } + } + } + + /* determine SERVICED */ + if(pTimer->runstatus & WD_STAT_SVCD) { + ret |= WD_SERVICED; + } + + return(ret); +} + +#ifdef MODULE +int init_module(void) +#else +__initfunc(int wd_init(void)) +#endif +{ + int id; + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, WD_OBPNAME)) + goto ebus_done; + } + } + +ebus_done: + if(!edev) { + printk("%s: unable to locate device\n", WD_OBPNAME); + return -ENODEV; + } + + if(check_region(edev->base_address[0], sizeof(*wd_dev.regs))) + { + printk("%s: Unable to get region %lx, %d\n", + __FUNCTION__, edev->base_address[0], (int)sizeof(*wd_dev.regs)); + } + + wd_dev.regs = + (struct wd_regblk *)edev->base_address[0]; + request_region( + (unsigned long)wd_dev.regs, sizeof(*wd_dev.regs), WD_OBPNAME); + + if(NULL == wd_dev.regs) { + printk("%s: unable to map registers\n", WD_OBPNAME); + return(-ENODEV); + } + + /* initialize device structure from OBP parameters */ + wd_dev.irq = edev->irqs[0]; + wd_dev.opt_enable = wd_opt_enable(); + wd_dev.opt_reboot = wd_opt_reboot(); + wd_dev.opt_timeout = wd_opt_timeout(); + wd_dev.isbaddoggie = wd_isbroken(); + + /* disable all interrupts unless watchdog-enabled? == true */ + if(! wd_dev.opt_enable) { + wd_toggleintr(NULL, WD_INTR_OFF); + } + + /* register miscellaneous devices */ + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(0 != wd_inittimer(id)) { + printk("%s%i: unable to initialize\n", WD_OBPNAME, id); + } + } + + /* warn about possible defective PLD */ + if(wd_dev.isbaddoggie) { + init_timer(&wd_timer); + wd_timer.function = wd_brokentimer; + wd_timer.data = (unsigned long)&wd_dev; + wd_timer.expires = WD_BTIMEOUT; + + printk("%s: PLD defect workaround enabled for model %s\n", + WD_OBPNAME, WD_BADMODEL); + } + return(0); +} + +#ifdef MODULE +void cleanup_module(void) +{ + int id; + + /* if 'watchdog-enable?' == TRUE, timers are not stopped + * when module is unloaded. All brokenstopped timers will + * also now eventually trip. + */ + for(id = WD0_ID; id < WD_NUMDEVS; ++id) { + if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs->status)) { + if(wd_dev.opt_enable) { + printk(KERN_WARNING "%s%i: timer not stopped at release\n", + WD_OBPNAME, id); + } + else { + wd_stoptimer(&wd_dev.watchdog[id]); + if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) { + wd_resetbrokentimer(&wd_dev.watchdog[id]); + printk(KERN_WARNING + "%s%i: defect workaround disabled at release, "\ + "timer expires in ~%01i sec\n", + WD_OBPNAME, id, + wd_readw(wd_dev.watchdog[id].regs->limit) / 10); + } + } + } + } + + if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) { + del_timer(&wd_timer); + } + if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd0_miscdev); + } + if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd1_miscdev); + } + if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) { + misc_deregister(&wd2_miscdev); + } + if(0 != wd_dev.initialized) { + free_irq(wd_dev.irq, (void *)wd_dev.regs); + } + release_region((unsigned long)wd_dev.regs, sizeof(*wd_dev.regs)); +} +#endif /* ifdef MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.2.18/drivers/sbus/char/zs.c Sun Mar 25 11:13:08 2001 +++ linux/drivers/sbus/char/zs.c Sun Mar 25 11:37:35 2001 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.41.2.6 2000/04/17 05:46:05 davem Exp $ +/* $Id: zs.c,v 1.41.2.7 2001/01/03 08:07:04 ecd Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -904,7 +904,6 @@ */ static void change_speed(struct sun_serial *info) { - unsigned short port; unsigned cflag; int quot = 0; int i; @@ -913,7 +912,7 @@ if (!info->tty || !info->tty->termios) return; cflag = info->tty->termios->c_cflag; - if (!(port = info->port)) + if (!info->port) return; i = cflag & CBAUD; if (cflag & CBAUDEX) { @@ -1857,7 +1856,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.41.2.6 $"; + char *revision = "$Revision: 1.41.2.7 $"; char *version, *p; version = strchr(revision, ' '); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c --- v2.2.18/drivers/scsi/3w-xxxx.c Sun Mar 25 11:13:04 2001 +++ linux/drivers/scsi/3w-xxxx.c Sun Mar 25 11:37:35 2001 @@ -3,8 +3,10 @@ Written By: Adam Radford Modifications By: Joel Jacobson + Arnaldo Carvalho de Melo - Copyright (C) 1999-2000 3ware Inc. + + Copyright (C) 1999-2001 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -64,6 +66,17 @@ Bug fix so hot spare drives don't show up. 1.02.00.002 - Fix bug with tw_setfeature() call that caused oops on some systems. + 12/09/2000 - release previously allocated resources on failure at + tw_allocate_memory (acme) + 1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when + controller status is non-zero. + Added handling of request_sense opcode. + Fix possible null pointer dereference in + tw_reset_device_extension() + 1.02.00.004 - Add support for device id of 3ware 7000 series controllers. + Make tw_setfeature() call with interrupts disabled. + Register interrupt handler before enabling interrupts. + Clear attention interrupt before draining aen queue. */ #include @@ -115,7 +128,7 @@ }; /* Globals */ -char *tw_driver_version="1.02.00.002"; +char *tw_driver_version="1.02.00.004"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -416,37 +429,29 @@ /* This function will allocate memory and check if it is 16 d-word aligned */ int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which) { - u32 *virt_addr; + u32 *virt_addr = kmalloc(size, GFP_ATOMIC); dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n"); + if (!virt_addr) { + printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n"); + return 1; + } + + if ((u32)virt_addr % TW_ALIGNMENT) { + kfree(virt_addr); + printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); + return 1; + } + if (which == 0) { - /* Allocate command packet memory */ - virt_addr = kmalloc(size, GFP_ATOMIC); - if (virt_addr == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n"); - return 1; - } - if ((u32)virt_addr % TW_ALIGNMENT) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); - return 1; - } tw_dev->command_packet_virtual_address[request_id] = virt_addr; tw_dev->command_packet_physical_address[request_id] = - virt_to_bus(virt_addr); + virt_to_bus(virt_addr); } else { - /* Allocate generic buffer */ - virt_addr = kmalloc(size, GFP_ATOMIC); - if (virt_addr == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n"); - return 1; - } - if ((u32)virt_addr % TW_ALIGNMENT) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); - return 1; - } tw_dev->alignment_virtual_address[request_id] = virt_addr; - tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr); + tw_dev->alignment_physical_address[request_id] = + virt_to_bus(virt_addr); } return 0; } /* End tw_allocate_memory() */ @@ -593,173 +598,178 @@ struct pci_dev *tw_pci_dev = pci_devices; u32 status_reg_value; unsigned char c = 1; + int i; + u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 }; dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n"); - while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, tw_pci_dev))) { - /* Prepare temporary device extension */ - tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC); - if (tw_dev == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards); - continue; - } - memset(tw_dev, 0, sizeof(TW_Device_Extension)); - - error = tw_initialize_device_extension(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Calculate the cards register addresses */ - tw_dev->registers.base_addr = tw_pci_dev->base_address[0]; - tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15); - tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4); - tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8); - tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC); - /* Save pci_dev struct to device extension */ - tw_dev->tw_pci_dev = tw_pci_dev; - - /* Poll status register for 60 secs for 'Controller Ready' flag */ - if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Disable interrupts on the card */ - tw_disable_interrupts(tw_dev); - - while (tries < TW_MAX_RESET_TRIES) { - /* Do soft reset */ - tw_soft_reset(tw_dev); - - error = tw_aen_drain_queue(tw_dev); + + for (i=0;iregisters.base_addr = tw_pci_dev->base_address[0]; + tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15); + tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4); + tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8); + tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC); + /* Save pci_dev struct to device extension */ + tw_dev->tw_pci_dev = tw_pci_dev; + + /* Poll status register for 60 secs for 'Controller Ready' flag */ + if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards); + tw_free_device_extension(tw_dev); + kfree(tw_dev); continue; } - - /* Empty the response queue */ - error = tw_empty_response_que(tw_dev); + + /* Disable interrupts on the card */ + tw_disable_interrupts(tw_dev); + + while (tries < TW_MAX_RESET_TRIES) { + /* Do soft reset */ + tw_soft_reset(tw_dev); + + error = tw_aen_drain_queue(tw_dev); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards); + tries++; + continue; + } + + /* Check for controller errors */ + if (tw_check_errors(tw_dev)) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards); + tries++; + continue; + } + + /* Empty the response queue */ + error = tw_empty_response_que(tw_dev); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards); + tries++; + continue; + } + + /* Now the controller is in a good state */ + break; + } + + if (tries >= TW_MAX_RESET_TRIES) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } + + /* Make sure that io region isn't already taken */ + if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", + (tw_dev->tw_pci_dev->base_address[0]), + (tw_dev->tw_pci_dev->base_address[0]) + + TW_IO_ADDRESS_RANGE, numcards); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } + + /* Reserve the io address space */ + request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); + error = tw_initialize_units(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards); - tries++; + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards); + release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); continue; } - - /* Now the controller is in a good state */ - break; - } - - if (tries >= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Make sure that io region isn't already taken */ - if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", - (tw_dev->tw_pci_dev->base_address[0]), - (tw_dev->tw_pci_dev->base_address[0]) + - TW_IO_ADDRESS_RANGE, numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Reserve the io address space */ - request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); - error = tw_initialize_units(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards); - release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards); - release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Calculate max cmds per lun */ - if (tw_dev->num_units > 0) - tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units; - - /* Register the card with the kernel SCSI layer */ - host = scsi_register(tw_host, sizeof(TW_Device_Extension)); - - /* FIXME - check for NULL */ - - status_reg_value = inl(tw_dev->registers.status_reg_addr); - - dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no, + + error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards); + release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } + + /* Calculate max cmds per lun */ + if (tw_dev->num_units > 0) + tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units; + + /* Register the card with the kernel SCSI layer */ + host = scsi_register(tw_host, sizeof(TW_Device_Extension)); + + /* FIXME - check for NULL */ + + status_reg_value = inl(tw_dev->registers.status_reg_addr); + + dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no, (u32)(tw_pci_dev->base_address[0]), tw_pci_dev->irq, (status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, (status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24); + + if (host->hostdata) { + tw_dev2 = (TW_Device_Extension *)host->hostdata; + memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension)); + tw_device_extension_list[tw_device_extension_count] = tw_dev2; + numcards++; + tw_device_extension_count = numcards; + tw_dev2->host = host; + } else { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1); + scsi_unregister(host); + release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } + + /* Tell the firmware we support shutdown notification*/ + tw_setfeature(tw_dev2, 2, 1, &c); + + /* Now setup the interrupt handler */ + error = tw_setup_irq(tw_dev2); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1); + scsi_unregister(host); + release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); + + tw_free_device_extension(tw_dev); + kfree(tw_dev); + numcards--; + continue; + } - if (host->hostdata) { - tw_dev2 = (TW_Device_Extension *)host->hostdata; - memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension)); - tw_device_extension_list[tw_device_extension_count] = tw_dev2; - numcards++; - tw_device_extension_count = numcards; - tw_dev2->host = host; - } else { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1); - scsi_unregister(host); - release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Re-enable interrupts on the card */ - tw_enable_interrupts(tw_dev2); - - /* Now setup the interrupt handler */ - error = tw_setup_irq(tw_dev2); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1); - scsi_unregister(host); - release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); - - tw_free_device_extension(tw_dev); - kfree(tw_dev); - numcards--; - continue; + /* Re-enable interrupts on the card */ + tw_enable_interrupts(tw_dev2); + + /* Free the temporary device extension */ + if (tw_dev) + kfree(tw_dev); } - - /* Free the temporary device extension */ - if (tw_dev) - kfree(tw_dev); - /* Tell the firmware we support shutdown notification*/ - tw_setfeature(tw_dev2, 2, 1, &c); } - if (numcards == 0) printk(KERN_WARNING "3w-xxxx: tw_findcards(): No cards found.\n"); else - register_reboot_notifier(&tw_notifier); - + register_reboot_notifier(&tw_notifier); + return numcards; } /* End tw_findcards() */ @@ -1090,15 +1100,14 @@ /* Handle attention interrupt */ if (do_attention_interrupt) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); + tw_clear_attention_interrupt(tw_dev); tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); if (error) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); - } else { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); - tw_clear_attention_interrupt(tw_dev); } } @@ -1134,13 +1143,15 @@ response_que.value = inl(response_que_addr); request_id = response_que.u.response_id; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + error = 0; if (command_packet->status != 0) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); + error = 1; } if (tw_dev->state[request_id] != TW_S_POSTED) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode); + error = 1; } - error = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id); /* Check for internal command */ if (tw_dev->srb[request_id] == 0) { @@ -1184,8 +1195,8 @@ } if (error) { /* Tell scsi layer there was an error */ - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); - tw_dev->srb[request_id]->result = (DID_ERROR << 16); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); + tw_dev->srb[request_id]->result = (DID_RESET << 16); } else { /* Tell scsi layer command was a success */ tw_dev->srb[request_id]->result = (DID_OK << 16); @@ -1467,8 +1478,10 @@ (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { srb = tw_dev->srb[i]; - srb->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); + if (srb != NULL) { + srb->result = (DID_RESET << 16); + tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); + } } } @@ -1813,6 +1826,10 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n"); error = tw_scsiop_read_capacity(tw_dev, request_id); break; + case REQUEST_SENSE: + dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n"); + error = tw_scsiop_request_sense(tw_dev, request_id); + break; case TW_IOCTL: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n"); error = tw_ioctl(tw_dev, request_id); @@ -2168,6 +2185,23 @@ return 0; } /* End tw_scsiop_read_write() */ + +/* This function will handle the request sense scsi command */ +int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id) +{ + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n"); + + /* For now we just zero the sense buffer */ + memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + + /* If we got a request_sense, we probably want a reset, return error */ + tw_dev->srb[request_id]->result = (DID_ERROR << 16); + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + + return 0; +} /* End tw_scsiop_request_sense() */ /* This function will handle test unit ready scsi command */ int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/3w-xxxx.h linux/drivers/scsi/3w-xxxx.h --- v2.2.18/drivers/scsi/3w-xxxx.h Sun Mar 25 11:13:04 2001 +++ linux/drivers/scsi/3w-xxxx.h Sun Mar 25 11:37:35 2001 @@ -3,8 +3,9 @@ Written By: Adam Radford Modifications By: Joel Jacobson + Arnaldo Carvalho de Melo - Copyright (C) 1999, 2000 3ware Inc. + Copyright (C) 1999-2001 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -97,6 +98,8 @@ #define TW_DEVICE_NAME "3ware Storage Controller" #define TW_VENDOR_ID (0x13C1) /* 3ware */ #define TW_DEVICE_ID (0x1000) /* Storage Controller */ +#define TW_DEVICE_ID2 (0x1001) /* 7000 series controller */ +#define TW_NUMDEVICES 2 /* Command packet opcodes */ #define TW_OP_NOP 0x0 @@ -330,6 +333,7 @@ int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id); +int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id); int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val); int tw_setup_irq(TW_Device_Extension *tw_dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.2.18/drivers/scsi/Config.in Sun Mar 25 11:28:28 2001 +++ linux/drivers/scsi/Config.in Sun Mar 25 11:37:35 2001 @@ -2,6 +2,7 @@ dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI +dep_tristate 'OnStream SC-x0 SCSI tape support' CONFIG_CHR_DEV_OSST $CONFIG_SCSI dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR @@ -29,9 +30,8 @@ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT - int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8 - bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N - int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 + int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 24 + bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS fi dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI @@ -71,7 +71,7 @@ dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI fi -if [ "$CONFIG_PARPORT" != "n" ]; then +if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "m" ]; then dep_tristate 'IOMEGA parallel port (ppa - older drives)' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT dep_tristate 'IOMEGA parallel port (imm - newer drives)' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT if [ "$CONFIG_SCSI_PPA" != "n" -o "$CONFIG_SCSI_IMM" != "n" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.2.18/drivers/scsi/Makefile Sun Mar 25 11:28:28 2001 +++ linux/drivers/scsi/Makefile Sun Mar 25 11:37:35 2001 @@ -61,6 +61,14 @@ endif endif +ifeq ($(CONFIG_CHR_DEV_OSST),y) +L_OBJS += osst.o +else + ifeq ($(CONFIG_CHR_DEV_OSST),m) + M_OBJS += osst.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_SD),y) L_OBJS += sd.o sd_ioctl.o else diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx --- v2.2.18/drivers/scsi/README.aic7xxx Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/README.aic7xxx Sun Mar 25 11:37:35 2001 @@ -14,50 +14,17 @@ Adaptec Cards ---------------------------- AHA-274x - AHA-274xT - AHA-2842 - AHA-2910B - AHA-2920C - AHA-2930 - AHA-2930U - AHA-2930CU - AHA-2930U2 - AHA-2940 - AHA-2940W - AHA-2940U - AHA-2940UW - AHA-2940UW-PRO - AHA-2940AU - AHA-2940U2W - AHA-2940U2 - AHA-2940U2B - AHA-2940U2BOEM - AHA-2944D - AHA-2944WD - AHA-2944UD - AHA-2944UWD - AHA-2950U2 - AHA-2950U2W - AHA-2950U2B - AHA-29160M - AHA-3940 - AHA-3940U - AHA-3940W - AHA-3940UW - AHA-3940AUW - AHA-3940U2W - AHA-3950U2B - AHA-3950U2D - AHA-3960D - AHA-39160M - AHA-3985 - AHA-3985U - AHA-3985W - AHA-3985UW + AHA-274xT + AHA-274xW + AHA-284x + AHA-284xW + All PCI based cards using any of the chipsets listed under motherboard + chipsets. In general, this means *all* of the Adaptec SCSI controllers + except the ones specifically excluded later on in this document. Motherboard Chipsets ---------------------------- - AIC-777x + AIC-777x AIC-785x AIC-786x AIC-787x @@ -71,15 +38,14 @@ SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s. U - Ultra SCSI, transfer rates up to 40MB/s. U2- Ultra 2 SCSI, transfer rates up to 80MB/s. + U3- Ultra 3 SCSI, transfer rates up to 160MB/s. D - Differential SCSI. T - Twin Channel SCSI. Up to 14 SCSI devices. AHA-274x - EISA SCSI controller AHA-284x - VLB SCSI controller AHA-29xx - PCI SCSI controller - AHA-394x - PCI controllers with two separate SCSI controllers on-board. - AHA-398x - PCI RAID controllers with three separate SCSI controllers - on-board. + AHA-39xx - PCI controllers with multiple separate SCSI channels on-board. Not Supported Devices ------------------------------ @@ -93,7 +59,7 @@ Motherboard Chipsets ---------------------------- - AIC-7810 + AIC-781x Bus Types ---------------------------- diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/README.osst linux/drivers/scsi/README.osst --- v2.2.18/drivers/scsi/README.osst Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/README.osst Sun Mar 25 11:37:35 2001 @@ -0,0 +1,218 @@ +README file for the osst driver +=============================== +(w) Kurt Garloff 11/2000 + +This file describes the osst driver as of version 0.8.x/0.9.x, the released +version of the osst driver. +It is intended to help advanced users to understand the role of osst and to +get them started using (and maybe debugging) it. +It won't address issues like "How do I compile a kernel?" or "How do I load +a module?", as these are too basic. +Once the OnStream got merged into the official kernel, the distro makers +will provide the OnStream support for those who are not familiar with +hacking their kernels. + + +Purpose +------- +The osst driver was developed, because the standard SCSI tape driver in +Linux, st, does not support the OnStream SC-x0 SCSI tape. The st is not to +blame for that, as the OnStream tape drives do not support the standard SCSI +command set for Serial Access Storage Devices (SASDs), which basically +corresponds to the QIC-157 spec. +Nevertheless, the OnStream tapes are nice pieces of hardware and therefore +the osst driver has been written to make these tape devs supported by Linux. +The driver is free software. It's released under the GNU GPL and planned to +be integrated into the mainstream kernel. + + +Implementation +-------------- +The osst is a new high-level SCSI driver, just like st, sr, sd and sg. It +can be compiled into the kernel or loaded as a module. +As it represents a new device, it got assigned a new device node: /dev/osstX +are character devices with major no 206 and minor numbers like the /dev/stX +devices. If those are not present, you may create them by calling +Makedevs.sh as root (see below). +The driver started being a copy of st and as such, the osst devices' +behavior looks very much the same as st to the userspace applications. + + +History +------- +In the first place, osst shared it's identity very much with st. That meant +that it used the same kernel structures and the same device node as st. +So you could only have either of them being present in the kernel. This has +been fixed by registering an own device, now. +st and osst can coexist, each only accessing the devices it can support by +their own device. + + +Installation +------------ +osst got integrated into the linux kernel. Select it during kernel +configuration as module or compile statically into the kernel. +Compile your kernel and install the modules. + +Now, your osst driver is inside the kernel or available as a module, +depending on your choice during kernel config. You may still need to create +the device nodes by calling the Makedevs.sh script (see below) manually, +unless you use a devfs kernel, where this won't be needed. + +To load your module, you may use the command +modprobe osst +as root. dmesg should show you, whether your OnStream tapes have been +recognized. + +If you want to have the module autoloaded on access to /dev/osst, you may +add something like +alias char-major-206 osst +to your /etc/modules.conf (old name: conf.modules). + +You may find it convenient to create a symbolic link +ln -s nosst0 /dev/tape +to make programs assuming a default name of /dev/tape more convenient to +use. + +The device nodes for osst have to be created. Use the Makedevs.sh script +attached to this file. + + +Using it +-------- +You may use the OnStream tape driver with your standard backup software, +which may be tar, cpio, amanda, arkeia, BRU, Lone Tar, ... +by specifying /dev/(n)osst0 as the tape device to use or using the above +symlink trick. The IOCTLs to control tape operation are also mostly +supported and you may try the mt (or mt_st) program to jump between +filemarks, eject the tape, ... + +There's one limitation: You need to use a block size of 32kB. + +(This limitation is worked on and will be fixed in version 0.8.7 of + this driver.) + +If you just want to get started with standard software, here is an example +for creating and restoring a full backup: +# Backup +tar cvf - / --exclude /proc | buffer -s 32k -m 24M -B -t -o /dev/nosst0 +# Restore +buffer -s 32k -m 8M -B -t -i /dev/osst0 | tar xvf - -C / + +The buffer command has been used to buffer the data before it goes to the +tape (or the file system) in order to smooth out the data stream and prevent +the tape from needing to stop and rewind. The OnStream does have an internal +buffer and a variable speed which help this, but especially on writing, the +buffering still proves useful in most cases. It also pads the data to +guarantees the block size of 32k. (Otherwise you may pass the -b64 option to +tar.) +Expect something like 1.8MB/s for the SC-x0 drives and 0.9MB/s for the DI-30. +The USB drive will give you about 0.7MB/s. +On a fast machine, you may profit from software data compression (z flag for +tar). + + +USB and IDE +----------- +Via the SCSI emulation layers usb-storage and ide-scsi, you can also use the +osst driver to drive the USB-30 and the DI-30 drives. (Unfortunately, there +is no such layer for the parallel port, otherwise the DP-30 would work as +well.) For the USB support, you need the latest 2.4.0-test kernels and the +latest usb-storage driver from +http://www.linux-usb.org/ +http://sourceforge.net/cvs/?group_id=3581 + +Note that the ide-tape driver as of 1.16f uses a slightly outdated on-tape +format and therefore is not completely interoperable with osst tapes. + +The ADR-x0 line is fully SCSI-2 compliant and is supported by st, not osst. +The on-tape format is supposed to be compatible with the one used by osst. + + +Feedback and updates +-------------------- +The driver development is coordinated through a mailing list + +a CVS repository and some web pages. +The tester's pages which contain recent news and updated drivers to download +can be found on +http://linux1.onstream.nl/test/ + +If you find any problems, please have a look at the tester's page in order +to see whether the problem is already known and solved. Otherwise, please +report it to the mailing list. Your feedback is welcome. (This holds also +for reports of successful usage, of course.) +In case of trouble, please do always provide the following info: +* driver and kernel version used (see syslog) +* driver messages (syslog) +* SCSI config and OnStream Firmware (/proc/scsi/scsi) +* description of error. Is it reproducible? +* software and commands used + +You may subscribe to the mailing list, BTW, it's a majordomo list. + + +Status +------ +0.8.0 was the first widespread BETA release. Since then a lot of reports +have been sent, but mostly reported success or only minor trouble. +All the issues have been addressed. +Check the web pages for more info about the current developments. + + +Acknowledgments +---------------- +The driver has been started by making a copy of Kai Makisara's st driver. +Most of the development has been done by Willem Riede. The presence of the +userspace program osg (onstreamsg) from Terry Hardie has been rather +helpful. The same holds for Gadi Oxman's ide-tape support for the DI-30. +I did add some patches to those drivers as well and coordinated things a +little bit. +Note that most of them did mostly spend their spare time for the creation of +this driver. +The people from OnStream, especially Jack Bombeeck did support this project +and always tried to answer HW or FW related questions. Furthermore, he +pushed the FW developers to do the right things. +SuSE did support this project by allowing me to work on it during my working +time for them and by integrating the driver into their distro. + +More people did help by sending useful comments. Sorry to those who have +been forgotten. Thanks to all the GNU/FSF and Linux developers who made this +platform such an interesting, nice and stable platform. +Thanks go to those who tested the drivers and did send useful reports. Your +help is needed! + + +Makedevs.sh +----------- +#!/bin/sh +# Script to create OnStream SC-x0 device nodes (major 206) +# Usage: Makedevs.sh [nos [path to dev]] +# $Id: README.osst.kernel,v 1.1.2.2 2000/12/20 14:08:38 garloff Exp $ +major=206 +nrs=4 +dir=/dev +test -z "$1" || nrs=$1 +test -z "$2" || dir=$2 +declare -i nr +nr=0 +test -d $dir || mkdir -p $dir +while test $nr -lt $nrs; do + mknod $dir/osst$nr c $major $nr + chown 0.disk $dir/osst$nr; chmod 660 $dir/osst$nr; + mknod $dir/nosst$nr c $major $[nr+128] + chown 0.disk $dir/nosst$nr; chmod 660 $dir/nosst$nr; + mknod $dir/osst${nr}l c $major $[nr+32] + chown 0.disk $dir/osst${nr}l; chmod 660 $dir/osst${nr}l; + mknod $dir/nosst${nr}l c $major $[nr+160] + chown 0.disk $dir/nosst${nr}l; chmod 660 $dir/nosst${nr}l; + mknod $dir/osst${nr}m c $major $[nr+64] + chown 0.disk $dir/osst${nr}m; chmod 660 $dir/osst${nr}m; + mknod $dir/nosst${nr}m c $major $[nr+192] + chown 0.disk $dir/nosst${nr}m; chmod 660 $dir/nosst${nr}m; + mknod $dir/osst${nr}a c $major $[nr+96] + chown 0.disk $dir/osst${nr}a; chmod 660 $dir/osst${nr}a; + mknod $dir/nosst${nr}a c $major $[nr+224] + chown 0.disk $dir/nosst${nr}a; chmod 660 $dir/nosst${nr}a; + let nr+=1 +done diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/README.tmscsim linux/drivers/scsi/README.tmscsim --- v2.2.18/drivers/scsi/README.tmscsim Sun Mar 25 11:13:03 2001 +++ linux/drivers/scsi/README.tmscsim Sun Mar 25 11:37:35 2001 @@ -9,6 +9,7 @@ 6. Potential improvements 7. Bug reports, debugging and updates 8. Acknowledgements +9. Copyright 1. Purpose and history @@ -25,7 +26,7 @@ Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F (NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter, -tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more, +tmscsiw, which supported DC390W/U/F adapters. It's not maintained any more, as the ncr53c8xx is perfectly supporting these adpaters since some time. The driver first appeared in April 1996, exclusively supported the DC390 @@ -56,10 +57,13 @@ driver. Of course you have to choose to compile SCSI support and DC390(T) support into your kernel or as module when configuring your kernel for compiling. +NEW: You may as well compile this module outside your kernel, using the +supplied Makefile. If you got an old kernel (pre 2.1.127, pre 2.0.37p1) with an old version of this driver: Get dc390-21125-20b.diff.gz or dc390-2036p21-20b1.diff.gz from - my website and apply the patch. + my web page and apply the patch. Apply further patches to upgrade to the + latest version of the driver. If you want to do it manually, you should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and README.tmscsim) from this directory to @@ -91,6 +95,8 @@ tune2fs -e remount-ro /dev/sd?? * have copies of your SCSI disk's partition tables on some safe location: dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1 + or just print it with: + fdisk -l | lpr * make sure you are able to boot Linux (e.g. from floppy disk using InitRD) if your SCSI disk gets corrupted. You can use ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz @@ -102,7 +108,7 @@ than the 33.33 MHz being in the PCI spec. If you want to share the IRQ with another device and the driver refuses to -do, you might succeed with changing the DC390_IRQ type in tmscsim.c to +do so, you might succeed with changing the DC390_IRQ type in tmscsim.c to SA_SHIRQ | SA_INTERRUPT. @@ -121,11 +127,12 @@ * Dynamically configurable by writing to /proc/scsi/tmscsim/? * Dynamic allocation of resources * SMP support: Locking on io_request lock (Linux 2.1/2.2) or adapter - specific locks (Linux 2.3) + specific locks (Linux 2.5?) * Uniform source code for Linux-2.x.y * Support for dyn. addition/removal of devices via add/remove-single-device - (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi - H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care! + (Try: echo "scsi add-single-device C B T U" >/proc/scsi/scsi + C = Controller, B = Bus, T = Target SCSI ID, U = Unit SCSI LUN.) + Use with care! * Try to use the partition table for the determination of the mapping @@ -139,20 +146,21 @@ the attached devices and their settings. Here's an example: -garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0 -Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20 -SCSI Host Nr 0, AM53C974 Adapter Nr 0 -IOPortBase 0x6200, IRQLevel 0x09 -MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms -TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns -Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0 - Nr of lost arbitrations 17 +garloff@kurt:/home/garloff > cat /proc/scsi/tmscsim/0 +Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 2.0e7 2000-11-28 +SCSI Host Nr 1, AM53C974 Adapter Nr 0 +IOPortBase 0xb000, IRQ 10 +MaxID 8, MaxLUN 8, AdapterID 6, SelTimeout 250 ms, DelayReset 1 s +TagMaxNum 16, Status 0x00, ACBFlag 0x00, GlitchEater 24 ns +Statistics: Cmnds 1470165, Cmnds not sent directly 0, Out of SRB conds 0 + Lost arbitrations 587, Sel. connected 0, Connected: No Nr of attached devices: 4, Nr of DCBs: 4 -Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs -00 00 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 -01 01 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 -02 03 00 Yes Yes Yes Yes No No 100 ns 10.0 M 15 -03 05 00 Yes No Yes Yes No No (200 ns) +Map of attached LUNs: 01 00 00 03 01 00 00 00 +Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd +00 00 00 Yes Yes Yes Yes Yes 100 ns 10.0 M 15 16 +01 03 00 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 +02 03 01 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 +03 04 00 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 Note that the settings MaxID and MaxLUN are not zero- but one-based, which means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This @@ -178,9 +186,8 @@ The last values are only shown, if Sync is enabled. (NegoPeriod is still displayed in brackets to show the values which will be used after enabling Sync.) -The STOP parameter is for testing/debugging purposes only and should bet set -to No. Please don't fiddle with it, unless you want to get rid of the -contents of your disk. +MaxCmd ist the number of commands (=tags) which can be processed at the same +time by the device. If you want to change a setting, you can do that by writing to /proc/scsi/tmscsim/?. Basically you have to imitate the output of driver. @@ -196,8 +203,8 @@ echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0 Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut, - TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you - want to see what happens, if the driver hangs. + TagMaxNum, ACBFlag, GlitchEater and DelayReset. Don't change ACBFlag + unless you want to see what happens, if the driver hangs. (2) Change device settings: You write a config line to the driver. The Nr must match the ID and LUN given. If you give "-" as parameter, it is @@ -207,8 +214,8 @@ an INQUIRY on the device if necessary to check if it is capable to operate with the given settings (Sync, TagQ). Examples: - echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0 - echo "3 5 0 y n y" >/proc/scsi/tmscsim/0 + echo "0 0 0 y y y - y - 10 " >/proc/scsi/tmscsim/0 + echo "3 5 0 y n y " >/proc/scsi/tmscsim/0 To give a short explanation of the first example: The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0), @@ -223,22 +230,26 @@ discussed above. The values used in this example will result in maximum performance. -(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and - the removal of a device's DCB. +(3) Special commands: You can force a SCSI bus reset, an INQUIRY command, the + removal or the addition of a device's DCB and a SCSI register dump. This is only used for debugging when you meet problems. The parameter of - the INQUIRY and remove command is the device index as shown by the + the INQUIRY and REMOVE commands is the device index as shown by the output of /proc/scsi/tmscsim/? in the device listing in the first column - (Idx). + (Idx). ADD takes the SCSI ID and LUN. Examples: echo "reset" >/proc/scsi/tmscsim/0 echo "inquiry 1" >/proc/scsi/tmscsim/0 echo "remove 2" >/proc/scsi/tmscsim/1 + echo "add 2 3" >/proc/scsi/tmscsim/? + echo "dump" >/proc/scsi/tmscsim/0 - Note that you will meet problems when you remove a device's DCB with the + Note that you will meet problems when you REMOVE a device's DCB with the remove command if it contains partitions which are mounted. Only use it after unmounting its partitions, telling the SCSI mid-level code to remove it (scsi remove-single-device) and you really need a few bytes of memory. + The ADD command allows you to configure a device before you tell the + mid-level code to try detection. I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing @@ -247,18 +258,20 @@ 5. Configuration via boot/module parameters ------------------------------------------- -With the DC390, the driver reads its EEPROM settings and IGNORES boot / -module parameters. If you want to override the EEPROM settings of a DC390, -you have to use the /proc/scsi/tmscsim/? interface described in the above -chapter. - -However, if you do have another AM53C974 based adapter you might want to -adjust some settings before you are able to write to the /proc/scsi/tmscsim/? -pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that -the log message "DC390: No EEPROM found!" is normal without a DC390.) +With the DC390, the driver reads its EEPROM settings and tries to use them. +But you may want to override the settings prior to being able to change the +driver configuration via /proc/scsi/tmscsim/?. +If you do have another AM53C974 based adapter, that's even the only +possibility to adjust settings before you are able to write to the +/proc/scsi/tmscsim/? pseudo-file, e.g. if you want to use another +adapter ID than 7. +(BTW, the log message "DC390: No EEPROM found!" is normal without a DC390.) For this purpose, you can pass options to the driver before it is initialised by using kernel or module parameters. See lilo(8) or modprobe(1) manual pages on how to pass params to the kernel or a module. +[NOTE: Formerly, it was not possible to override the EEPROM supplied + settings of the DC390 with cmd line parameters. This has changed since + 2.0e7] The syntax of the params is much shorter than the syntax of the /proc/... interface. This makes it a little bit more difficult to use. However, long @@ -269,7 +282,7 @@ DC390 EEPROM, the settings are given in a DC390 BIOS' way. Here's the syntax: -tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds +tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds,DelayReset Each of the parameters is a number, containing the described information: @@ -278,7 +291,7 @@ * SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values 0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is - 1 (8.0 MHz). + 0 (10.0 MHz). * DevMode is a bit mapped value describing the per-device features. It applies to all devices. (Sync, Disc and TagQ will only apply, if the @@ -289,7 +302,7 @@ *1 0x02 2 Synchronous Negotiation *2 0x04 4 Disconnection *3 0x08 8 Send Start command on startup. (Not used) - *4 0x10 16 Tagged Queueing + *4 0x10 16 Tagged Command Queueing As usual, the desired value is obtained by adding the wanted values. If you want to enable all values, e.g., you would use 31(0x1f). Default is 31. @@ -315,18 +328,23 @@ *3 16 4 32 +* DelayReset is the time in seconds (minus 0.5s), the adapter waits, after a + bus reset. Default is 1 (corresp. to 1.5s). + Example: modprobe tmscsim tmscsim=6,2,31 would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device -features and leave the adapter features and the number of Tagged Commands -to the defaults. - -As you can see, you don't need to specify all of the five params. +features and leave the adapter features, the number of Tagged Commands +and the Delay after a reset to the defaults. -The defaults (7,1,31,15,3) are aggressive to allow good performance. You can -use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is -perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut -for tmscsim=7,4,9,15,2. +As you can see, you don't need to specify all of the six params. +If you want values to be ignored (i.e. the EEprom settings or the defaults +will be used), you may pass -2 (not 0!) at the corresponding position. + +The defaults (7,0,31,15,3,1) are aggressive to allow good performance. You +can use tmscsim=7,0,31,63,4,0 for maximum performance, if your SCSI chain +allows it. If you meet problems, you can use tmscsim=-1 which is a shortcut +for tmscsim=7,4,9,15,2,10. 6. Potential improvements @@ -334,42 +352,47 @@ Most of the intended work on the driver has been done. Here are a few ideas to further improve its usability: +* Cleanly separate per-Target and per-LUN properties (DCB) * More intelligent abort() routine -* Implement new_eh code (Linux-2.1+) -* Have the mid-level code (and not the driver) handle more of the various - conditions. -* Rework command queueing in the driver +* Use new_eh code (Linux-2.1+) +* Have the mid-level (ML) code (and not the driver) handle more of the + various conditions. +* Command queueing in the driver: Eliminate Query list and use ML instead. * More user friendly boot/module param syntax Further investigation on these problems: * Driver hangs with sync readcdda (xcdroast) (most probably VIA PCI error) -Known problems: +Known problems: +Please see http://www.garloff.de/kurt/linux/dc390/problems.html -* There was a report that with a certain Scanner, the last SCSI command - won't be finished correctly. This might be a command queueing bug or a bug - in SCSI implementation of the scanner. Issueing another command to the - scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where - x is the index (not the SCSI ID!) of the scanner. See 4.(3).) +* Changing the parameters of multi-lun by the tmscsim/? interface will + cause problems, cause these settings are mostly per Target and not per LUN + and should be updated accordingly. To be fixed for 2.0d24. +* CDRs (eg Yam CRW4416) not recognized, because some buggy devices don't + recover from a SCSI reset in time. Use a higher delay or don't issue + a SCSI bus reset on driver initialization. See problems page. + For the CRW4416S, this seems to be solved with firmware 1.0g (reported by + Jean-Yves Barbier). +* TEAC CD-532S not being recognized. (Works with 1.11). +* Scanners (eg. Astra UMAX 1220S) don't work: Disable Sync Negotiation. + If this does not help, try echo "INQUIRY t" >/proc/scsi/tmscsim/? (t + replaced by the dev index of your scanner). You may try to reset your SCSI + bus afterwards (echo "RESET" >/proc/scsi/tmscsim/?). + The problem seems to be solved as of 2.0d18, thanks to Andreas Rick. * If there is a valid partition table, the driver will use it for determing - the mapping. Other operating systems may not like this mapping, though + the mapping. If there's none, a reasonable mapping (Symbios-like) will be + assumed. Other operating systems may not like this mapping, though it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the partition table and used a H/S = 64/32 or 255/63 translation. So if you want to be compatible to those, use this old mapping when creating - partition tables. -* In some situations, the driver will get stuck in an abort loop. Please - disable DsCn, if you meet this problem. Please contact me for further - debugging. -* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c - There used to be a patch included here, which partially solved the - problem. I suggest you contact Chiaki Ishikawa , - Richard Waltham or Doug Ledford - , if you want to help further debugging it. -* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because - the mid-level code doesn't handle BLIST_SINGLELUN correctly. There used - to be a patch included here to fix this, but I was told that it is fixed - in 2.0.36. + partition tables. Even worse, on bootup the DC390 might complain if other + mappings are found, so auto rebooting may fail. +* In some situations, the driver will get stuck in an abort loop. This is a + bad interaction between the Mid-Layer of Linux' SCSI code and the driver. + Try to disable DsCn, if you meet this problem. Please contact me for + further debugging. 7. Bug reports, debugging and updates @@ -394,25 +417,33 @@ The latest version of the driver can be found at: http://www.garloff.de/kurt/linux/dc390/ -and - ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/ -(The latter might shut down some day.) + ftp://ftp.suse.com/pub/people/garloff/linux/dc390/ 8. Acknowledgements ------------------- -Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF -people, the XFree86 team and all the others for the wonderful OS and -software. +Thanks to Linus Torvalds, Alan Cox, the FSF people, the XFree86 team and +all the others for the wonderful OS and software. Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver release and support. -Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding. +Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding. Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert Tonneau) for intensively testing the driver (and even risking data loss -doing this during early revisions). +doing this during early revisions). +Recently, SuSE GmbH, Nuernberg, FRG, has been paying me for the driver +development and maintenance. Special thanks! + +9. Copyright +------------ + This driver is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + If you want to use any later version of the GNU GPL, you will probably + be allowed to, but you have to ask me and Tekram + before. ------------------------------------------------------------------------- Written by Kurt Garloff 1998/06/11 -Last updated 1998/12/25, driver revision 2.0d -$Id: README.tmscsim,v 2.9 1998/12/25 18:04:20 garloff Exp $ +Last updated 2000/11/28, driver revision 2.0e7 +$Id: README.tmscsim,v 2.25.2.7 2000/12/20 01:07:12 garloff Exp $ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.2.18/drivers/scsi/aha1542.c Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/aha1542.c Sun Mar 25 11:37:35 2001 @@ -560,7 +560,9 @@ done(SCpnt); return 0;}); if(*cmd == REQUEST_SENSE){ -#ifndef DEBUG +#if 0 + /* scsi_request_sense() provides a buffer of size 256, + so there is no reason to expect equality */ if (bufflen != sizeof(SCpnt->sense_buffer)) { printk("Wrong buffer length supplied for request sense (%d)\n",bufflen); }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c --- v2.2.18/drivers/scsi/aha1740.c Sun Mar 25 11:13:00 2001 +++ linux/drivers/scsi/aha1740.c Sun Mar 25 11:37:35 2001 @@ -324,11 +324,13 @@ if(*cmd == REQUEST_SENSE) { +#if 0 if (bufflen != sizeof(SCpnt->sense_buffer)) { printk("Wrong buffer length supplied for request sense (%d)\n", bufflen); } +#endif SCpnt->result = 0; done(SCpnt); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx/aic7xxx.h linux/drivers/scsi/aic7xxx/aic7xxx.h --- v2.2.18/drivers/scsi/aic7xxx/aic7xxx.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx.h Sun Mar 25 11:37:35 2001 @@ -0,0 +1,114 @@ +/*+M************************************************************************* + * Adaptec AIC7xxx device driver for Linux. + * + * Copyright (c) 1994 John Aycock + * The University of Calgary Department of Computer Science. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $ + *-M*************************************************************************/ +#ifndef _aic7xxx_h +#define _aic7xxx_h + +#define AIC7XXX_H_VERSION "3.2.4" + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#if defined(__i386__) +# define AIC7XXX_BIOSPARAM aic7xxx_biosparam +#else +# define AIC7XXX_BIOSPARAM NULL +#endif + +/* + * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields + * to do with card config are filled in after the card is detected. + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65) +#define AIC7XXX { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: aic7xxx_proc_info, \ + name: NULL, \ + detect: aic7xxx_detect, \ + release: aic7xxx_release, \ + info: aic7xxx_info, \ + command: NULL, \ + queuecommand: aic7xxx_queue, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: aic7xxx_abort, \ + reset: aic7xxx_reset, \ + slave_attach: NULL, \ + bios_param: AIC7XXX_BIOSPARAM, \ + can_queue: 255, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: 0, /* max scatter-gather cmds */\ + cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} +#else +#define AIC7XXX { \ + next: NULL, \ + usage_count: NULL, \ + proc_dir: NULL, \ + proc_info: aic7xxx_proc_info, \ + name: NULL, \ + detect: aic7xxx_detect, \ + release: aic7xxx_release, \ + info: aic7xxx_info, \ + command: NULL, \ + queuecommand: aic7xxx_queue, \ + abort: aic7xxx_abort, \ + reset: aic7xxx_reset, \ + slave_attach: NULL, \ + bios_param: AIC7XXX_BIOSPARAM, \ + can_queue: 255, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: 0, /* max scatter-gather cmds */\ + cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING \ +} +#endif + +extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +extern int aic7xxx_biosparam(Disk *, kdev_t, int[]); +extern int aic7xxx_detect(Scsi_Host_Template *); +extern int aic7xxx_command(Scsi_Cmnd *); +extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int); +extern int aic7xxx_abort(Scsi_Cmnd *); +extern int aic7xxx_release(struct Scsi_Host *); + +extern const char *aic7xxx_info(struct Scsi_Host *); + +extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int); + +#endif /* _aic7xxx_h */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.2.18/drivers/scsi/aic7xxx/aic7xxx.reg Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Sun Mar 25 11:37:35 2001 @@ -703,7 +703,12 @@ * it that it can fill the * message buffer. */ - mask TRACEPOINT 0xb0|SEQINT + mask SEQ_SG_FIXUP 0xb0|SEQINT /* need help with fixing up + * the sg array pointer after + * a phasemis with no valid + * sg elements in the shadow + * pipeline. + */ mask TRACEPOINT2 0xc0|SEQINT mask MSGIN_PHASEMIS 0xd0|SEQINT /* * Target changed phase on us diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq --- v2.2.18/drivers/scsi/aic7xxx/aic7xxx.seq Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.seq Sun Mar 25 11:37:35 2001 @@ -332,12 +332,15 @@ /* clear target specific flags */ clr SEQ_FLAGS ret; + +data_phase_reinit: /* * If we re-enter the data phase after going through another phase, the * STCNT may have been cleared, so restore it from the residual field. + * On Ultra2, we have to put it into the HCNT field because we have to + * drop the data down into the shadow layer via the preload ability. */ -data_phase_reinit: - if ((p->features & AHC_ULTRA2) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { bmov HADDR, SHADDR, 4; bmov HCNT, SCB_RESID_DCNT, 3; } @@ -349,27 +352,24 @@ mvi SCB_RESID_DCNT call bcopy_3; } jmp data_phase_loop; - p_data: - if ((p->features & AHC_ULTRA2) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; } else { mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; } test LASTPHASE, IOI jnz . + 2; or DMAPARAMS, DIRECTION; - call assert; /* - * Ensure entering a data - * phase is okay - seen identify, etc. - */ + call assert; /* + * Ensure entering a data + * phase is okay - seen identify, etc. + */ if ((p->features & AHC_CMD_CHAN) != 0) { mvi CCSGADDR, CCSGADDR_MAX; } - test SEQ_FLAGS, DPHASE jnz data_phase_reinit; - - /* We have seen a data phase */ - or SEQ_FLAGS, DPHASE; + test SEQ_FLAGS, DPHASE jnz data_phase_reinit; + or SEQ_FLAGS, DPHASE; /* we've seen a data phase */ /* * Initialize the DMA address and counter from the SCB. * Also set SG_COUNT and SG_NEXT in memory since we cannot @@ -378,8 +378,10 @@ */ if ((p->features & AHC_CMD_CHAN) != 0) { bmov HADDR, SCB_DATAPTR, 7; - bmov STCNT, HCNT, 3; bmov SG_COUNT, SCB_SGCOUNT, 5; + if ((p->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } } else { mvi DINDEX, HADDR; mvi SCB_DATAPTR call bcopy_7; @@ -387,9 +389,8 @@ mvi DINDEX, SG_COUNT; mvi SCB_SGCOUNT call bcopy_5; } - data_phase_loop: -/* Guard against overruns */ + /* Guard against overruns */ test SG_COUNT, 0xff jnz data_phase_inbounds; /* * Turn on 'Bit Bucket' mode, set the transfer count to @@ -399,66 +400,62 @@ */ or SXFRCTL1,BITBUCKET; and DMAPARAMS, ~(HDMAEN|SDMAEN); - if ((p->features & AHC_CMD_CHAN) != 0) { - if ((p->features & AHC_ULTRA2) != 0) { - bmov HCNT, ALLONES, 3; - } + if ((p->features & AHC_ULTRA2) != 0) { + bmov HCNT, ALLONES, 3; + } + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { bmov STCNT, ALLONES, 3; - } else { + } + if ((p->features & AHC_CMD_CHAN) == 0) { mvi STCNT[0], 0xFF; mvi STCNT[1], 0xFF; mvi STCNT[2], 0xFF; } + data_phase_inbounds: /* If we are the last SG block, tell the hardware. */ - cmp SG_COUNT,0x01 jne data_phase_wideodd; - if ((p->features & AHC_ULTRA2) == 0) { - and DMAPARAMS, ~WIDEODD; + if ((p->features & AHC_ULTRA2) != 0) { + shl A, 2, SG_COUNT; + cmp SG_COUNT,0x01 jne data_phase_wideodd; + or A, LAST_SEG; } else { - mvi SG_CACHEPTR, LAST_SEG; + cmp SG_COUNT,0x01 jne data_phase_wideodd; + and DMAPARAMS, ~WIDEODD; } data_phase_wideodd: - if ((p->features & AHC_ULTRA2) != 0) { - mov SINDEX, ALLONES; - mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; -data_phase_dma_loop: - test SSTAT0, SDONE jnz data_phase_dma_done; - test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ -data_phase_dma_phasemis: - test SSTAT0,SDONE jnz data_phase_dma_done; - clr SINDEX; /* Remember the phasemiss */ + if ((p->features & AHC_ULTRA2) != 0) { + mov SG_CACHEPTR, A; + mov DFCNTRL, DMAPARAMS; /* start the operation */ + test SXFRCTL1, BITBUCKET jnz data_phase_overrun; +u2_preload_wait: + test SSTAT1, PHASEMIS jnz u2_phasemis; + test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait; } else { mov DMAPARAMS call dma; - } - data_phase_dma_done: /* Go tell the host about any overruns */ - test SXFRCTL1,BITBUCKET jnz data_phase_overrun; + test SXFRCTL1,BITBUCKET jnz data_phase_overrun; /* Exit if we had an underrun. dma clears SINDEX in this case. */ - test SINDEX,0xff jz data_phase_finish; - + test SINDEX,0xff jz data_phase_finish; + } /* - * Advance the scatter-gather pointers if needed + * Advance the scatter-gather pointers */ sg_advance: - dec SG_COUNT; /* one less segment to go */ + if ((p->features & AHC_ULTRA2) != 0) { + cmp SG_COUNT, 0x01 je u2_data_phase_finish; + } else { + dec SG_COUNT; + test SG_COUNT, 0xff jz data_phase_finish; + } - test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ -/* - * Load a struct scatter and set up the data address and length. - * If the working value of the SG count is nonzero, then - * we need to load a new set of values. - * - * This, like all DMA's, assumes little-endian host data storage. - */ -sg_load: if ((p->features & AHC_CMD_CHAN) != 0) { + /* * Do we have any prefetch left??? */ - cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; + cmp CCSGADDR, CCSGADDR_MAX jne prefetch_avail; /* * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. @@ -474,10 +471,12 @@ and CCSGCTL, ~CCSGEN; test CCSGCTL, CCSGEN jnz .; mvi CCSGCTL, CCSGRESET; -prefetched_segs_avail: +prefetch_avail: bmov HADDR, CCSGRAM, 8; if ((p->features & AHC_ULTRA2) == 0) { bmov STCNT, HCNT, 3; + } else { + dec SG_COUNT; } } else { mvi DINDEX, HADDR; @@ -491,30 +490,63 @@ call dma_finish; - /* - * Copy data from FIFO into SCB data pointer and data count. - * This assumes that the SG segments are of the form: - * struct ahc_dma_seg { - * u_int32_t addr; four bytes, little-endian order - * u_int32_t len; four bytes, little endian order - * }; - */ - mvi HADDR call dfdat_in_7; +/* + * Copy data from FIFO into SCB data pointer and data count. + * This assumes that the SG segments are of the form: + * struct ahc_dma_seg { + * u_int32_t addr; four bytes, little-endian order + * u_int32_t len; four bytes, little endian order + * }; + */ + mvi DINDEX, HADDR; + call dfdat_in_7; call set_stcnt_from_hcnt; } - /* Advance the SG pointer */ - clr A; /* add sizeof(struct scatter) */ + clr A; /* add sizeof(struct scatter) */ add SG_NEXT[0],SG_SIZEOF; adc SG_NEXT[1],A; - test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + if ((p->features & AHC_ULTRA2) != 0) { + jmp data_phase_loop; + } else { + test SSTAT1, REQINIT jz .; + test SSTAT1,PHASEMIS jz data_phase_loop; + } + -/* This drops the last SG segment down to the shadow layer for us */ +/* + * We've loaded all of our segments into the preload layer. Now, we simply + * have to wait for it to finish or for us to get a phasemis. And, since + * we'll get a phasemis if we do finish, all we really need to do is wait + * for a phasemis then check if we did actually complete all the segments. + */ if ((p->features & AHC_ULTRA2) != 0) { - mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; +u2_data_phase_finish: + test SSTAT1, PHASEMIS jnz u2_phasemis; + test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish; + clr SG_COUNT; + test SSTAT1, REQINIT jz .; + test SSTAT1, PHASEMIS jz data_phase_loop; +u2_phasemis: + call ultra2_dmafinish; + test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish; + test SSTAT2, SHVALID jnz u2_fixup_residual; + mvi INTSTAT, SEQ_SG_FIXUP; + jmp data_phase_finish; +u2_fixup_residual: + shr ARG_1, 2, SG_CACHEPTR; +u2_phasemis_loop: + and A, 0x3f, SG_COUNT; + cmp ARG_1, A je data_phase_finish; +/* + * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT + */ + clr A; + add SG_NEXT[0], -SG_SIZEOF; + adc SG_NEXT[1], 0xff; + inc SG_COUNT; + jmp u2_phasemis_loop; } data_phase_finish: @@ -523,64 +555,83 @@ * We use STCNT instead of HCNT, since it's a reflection of how many bytes * were transferred on the SCSI (as opposed to the host) bus. */ - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; - } - if ((p->features & AHC_ULTRA2) == 0) { - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - } else { - mov SCB_RESID_DCNT[0],STCNT[0]; - mov SCB_RESID_DCNT[1],STCNT[1]; - mov SCB_RESID_DCNT[2],STCNT[2]; - mov SCB_RESID_SGCNT, SG_COUNT; + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, STCNT, 3; + mov SCB_RESID_SGCNT, SG_COUNT; + if ((p->features & AHC_ULTRA2) != 0) { + or SXFRCTL0, CLRSTCNT|CLRCHN; } + } else { + mov SCB_RESID_DCNT[0],STCNT[0]; + mov SCB_RESID_DCNT[1],STCNT[1]; + mov SCB_RESID_DCNT[2],STCNT[2]; + mov SCB_RESID_SGCNT, SG_COUNT; } jmp ITloop; data_phase_overrun: - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; - } /* * Turn off BITBUCKET mode and notify the host */ + if ((p->features & AHC_ULTRA2) != 0) { +/* + * Wait for the target to quit transferring data on the SCSI bus + */ + test SSTAT1, PHASEMIS jz .; + call ultra2_dmafinish; + } and SXFRCTL1, ~BITBUCKET; mvi INTSTAT,DATA_OVERRUN; jmp ITloop; -ultra2_dmafinish: + + + +/* + * Actually turn off the DMA hardware, save our current position into the + * proper residual variables, wait for the next REQ signal, then jump to + * the ITloop. Jumping to the ITloop ensures that if we happen to get + * brought into the data phase again (or are still in it after our last + * segment) that we will properly signal an overrun to the kernel. + */ if ((p->features & AHC_ULTRA2) != 0) { +ultra2_dmafinish: test DFCNTRL, DIRECTION jnz ultra2_dmahalt; and DFCNTRL, ~SCSIEN; test DFCNTRL, SCSIEN jnz .; + if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { + or DFCNTRL, FIFOFLUSH; + } ultra2_dmafifoflush: - or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz . - 1; - /* - * hardware bug alert! This needless set of jumps is to - * protect against a FIFOEMP status bit glitch in the - * silicon. - */ - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { + /* + * hardware bug alert! This needless set of jumps + * works around a glitch in the silicon. When the + * PCI DMA fifo goes empty, but there is still SCSI + * data to be flushed into the PCI DMA fifo (and from + * there on into main memory), the FIFOEMP bit will + * come on between the time when the PCI DMA buffer + * went empty and the next bit of data is copied from + * the SCSI fifo into the PCI fifo. It should only + * come on when both FIFOs (meaning the entire FIFO + * chain) are emtpy. Since it can take up to 4 cycles + * for new data to be copied from the SCSI fifo into + * the PCI fifo, testing for FIFOEMP status for 4 + * extra times gives the needed time for any + * remaining SCSI fifo data to be put in the PCI fifo + * before we declare it *truly* empty. + */ + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + } test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, MREQPEND jnz .; ultra2_dmahalt: - test SCSIOFFSET, 0x7f jnz ultra2_shutdown; -ultra2_await_nreq: - test SCSISIGI, REQI jz ultra2_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq; -ultra2_shutdown: and DFCNTRL, ~(HDMAEN|SCSIEN); test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - or SXFRCTL0, CLRSTCNT|CLRCHN; ret; } @@ -1021,6 +1072,7 @@ inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ + mesgin_phasemis: /* * We expected to receive another byte, but the target changed phase @@ -1080,7 +1132,9 @@ * to drain the data fifo until there is space for the input * latch to drain and HDMAEN de-asserts. */ - mov NONE, DFDAT; + if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { + mov NONE, DFDAT; + } test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; } return: @@ -1306,20 +1360,30 @@ cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; jmp dma_scb_finish; dma_scb_tohost: - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + if ((p->features & AHC_ULTRA2) == 0) { mvi CCSCBCTL, CCSCBRESET; bmov CCSCBRAM, SCB_CONTROL, 32; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; - } else { - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } + if ((p->features & AHC_ULTRA2) != 0) { + if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) { + mvi CCSCBCTL, CCARREN|CCSCBRESET; + cmp CCSCBCTL, ARRDONE|CCARREN jne .; + mvi CCHCNT, 32; + mvi CCSCBCTL, CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; + } else { + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } } dma_scb_finish: clr CCSCBCTL; test CCSCBCTL, CCARREN|CCSCBEN jnz .; ret; - } else { + } + if ((p->features & AHC_CMD_CHAN) == 0) { mvi DINDEX, HADDR; mvi HSCB_ADDR call set_32byte_addr; mvi HCNT[0], 32; @@ -1342,17 +1406,81 @@ mov DFDAT,SINDIR; cmp SINDEX, A jne copy_scb_tofifo_loop; or DFCNTRL, HDMAEN|FIFOFLUSH; + jmp dma_finish; dma_scb_fromhost: - call dma_finish; - /* If we were putting the SCB, we are done */ - test DMAPARAMS, DIRECTION jz return; - mvi SCB_CONTROL call dfdat_in_7; - call dfdat_in_7_continued; - call dfdat_in_7_continued; - jmp dfdat_in_7_continued; + mvi DINDEX, SCB_CONTROL; + if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { + /* + * Set the A to -24. It it hits 0, then we let + * our code fall through to dfdat_in_8 to complete + * the last of the copy. + * + * Also, things happen 8 bytes at a time in this + * case, so we may need to drain the fifo at most + * 3 times to keep things flowing + */ + mvi A, -24; +dma_scb_hang_fifo: + /* Wait for the first bit of data to hit the fifo */ + test DFSTATUS, FIFOEMP jnz .; +dma_scb_hang_wait: + /* OK, now they've started to transfer into the fifo, + * so wait for them to stop trying to transfer any + * more data. + */ + test DFSTATUS, MREQPEND jnz .; + /* + * OK, they started, then they stopped, now see if they + * managed to complete the job before stopping. Try + * it multiple times to give the chip a few cycles to + * set the flag if it did complete. + */ + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + /* + * Too bad, the chip didn't complete the DMA, but there + * aren't any more memory requests pending, so that + * means it stopped part way through and hung. That's + * our bug, so now we drain what data there is in the + * fifo in order to get things going again. + */ +dma_scb_hang_empty_fifo: + call dfdat_in_8; + add A, 8; + add SINDEX, A, HCNT; + /* + * If there are another 8 bytes of data waiting in the + * fifo, then the carry bit will be set as a result + * of the above add command (unless A is non-negative, + * in which case the carry bit won't be set). + */ + jc dma_scb_hang_empty_fifo; + /* + * We've emptied the fifo now, but we wouldn't have got + * here if the memory transfer hadn't stopped part way + * through, so go back up to the beginning of the + * loop and start over. When it succeeds in getting + * all the data down, HDONE will be set and we'll + * jump to the code just below here. + */ + jmp dma_scb_hang_fifo; +dma_scb_hang_dma_done: + and DFCNTRL, ~HDMAEN; + test DFCNTRL, HDMAEN jnz .; + call dfdat_in_8; + add A, 8; + cmp A, 8 jne . - 2; + ret; + } else { + call dma_finish; + call dfdat_in_8; + call dfdat_in_8; + call dfdat_in_8; + } +dfdat_in_8: + mov DINDIR,DFDAT; dfdat_in_7: - mov DINDEX,SINDEX; -dfdat_in_7_continued: mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c --- v2.2.18/drivers/scsi/aic7xxx/aic7xxx_proc.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c Sun Mar 25 11:37:35 2001 @@ -0,0 +1,414 @@ +/*+M************************************************************************* + * Adaptec AIC7xxx device driver proc support for Linux. + * + * Copyright (c) 1995, 1996 Dean W. Gehnert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * ---------------------------------------------------------------- + * o Modified from the EATA-DMA /proc support. + * o Additional support for device block statistics provided by + * Matthew Jacob. + * o Correction of overflow by Heinz Mauelshagen + * o Adittional corrections by Doug Ledford + * + * Dean W. Gehnert, deang@teleport.com, 05/01/96 + * + * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ + *-M*************************************************************************/ + +#include + +#define BLS (&aic7xxx_buffer[size]) +#define HDRB \ +" < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+" + +#ifdef PROC_DEBUG +extern int vsprintf(char *, const char *, va_list); + +static void +proc_debug(const char *fmt, ...) +{ + va_list ap; + char buf[256]; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + printk(buf); + va_end(ap); +} +#else /* PROC_DEBUG */ +# define proc_debug(fmt, args...) +#endif /* PROC_DEBUG */ + +static int aic7xxx_buffer_size = 0; +static char *aic7xxx_buffer = NULL; + + +/*+F************************************************************************* + * Function: + * aic7xxx_set_info + * + * Description: + * Set parameters for the driver from the /proc filesystem. + *-F*************************************************************************/ +int +aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) +{ + proc_debug("aic7xxx_set_info(): %s\n", buffer); + return (-ENOSYS); /* Currently this is a no-op */ +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_proc_info + * + * Description: + * Return information to handle /proc support for the driver. + *-F*************************************************************************/ +int +aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, + int hostno, int inout) +{ + struct Scsi_Host *HBAptr; + struct aic7xxx_host *p; + int size = 0; + unsigned char i; + struct aic7xxx_xferstats *sp; + unsigned char target; + + HBAptr = NULL; + + for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next) + ; + + if (!p) + { + size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if (size > length) + { + return (size); + } + else + { + return (length); + } + } + + HBAptr = p->host; + + if (inout == TRUE) /* Has data been written to the file? */ + { + return (aic7xxx_set_info(buffer, length, HBAptr)); + } + + p = (struct aic7xxx_host *) HBAptr->hostdata; + + /* + * It takes roughly 1K of space to hold all relevant card info, not + * counting any proc stats, so we start out with a 1.5k buffer size and + * if proc_stats is defined, then we sweep the stats structure to see + * how many drives we will be printing out for and add 384 bytes per + * device with active stats. + * + * Hmmmm...that 1.5k seems to keep growing as items get added so they + * can be easily viewed for debugging purposes. So, we bumped that + * 1.5k to 4k so we can quit having to bump it all the time. + */ + + size = 4096; + for (target = 0; target < MAX_TARGETS; target++) + { + if (p->dev_flags[target] & DEVICE_PRESENT) +#ifdef AIC7XXX_PROC_STATS + size += 512; +#else + size += 256; +#endif + } + if (aic7xxx_buffer_size != size) + { + if (aic7xxx_buffer != NULL) + { + kfree(aic7xxx_buffer); + aic7xxx_buffer_size = 0; + } + aic7xxx_buffer = kmalloc(size, GFP_KERNEL); + } + if (aic7xxx_buffer == NULL) + { + size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n", + __LINE__); + return size; + } + aic7xxx_buffer_size = size; + + size = 0; + size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); + size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION); + size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Compile Options:\n"); +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); +#else + size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); +#endif +#ifdef AIC7XXX_PROC_STATS + size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n"); +#else + size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); +#endif + size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY); + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Adapter Configuration:\n"); + size += sprintf(BLS, " SCSI Adapter: %s\n", + board_names[p->board_name_index]); + if (p->flags & AHC_TWIN) + size += sprintf(BLS, " Twin Channel Controller "); + else + { + char *channel = ""; + char *ultra = ""; + char *wide = "Narrow "; + if (p->flags & AHC_MULTI_CHANNEL) + { + channel = " Channel A"; + if (p->flags & (AHC_CHNLB|AHC_CHNLC)) + channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C"; + } + if (p->features & AHC_WIDE) + wide = "Wide "; + if (p->features & AHC_ULTRA3) + { + switch(p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7892: + case AHC_AIC7899: + ultra = "Ultra-160/m LVD/SE "; + break; + default: + ultra = "Ultra-3 LVD/SE "; + break; + } + } + else if (p->features & AHC_ULTRA2) + ultra = "Ultra-2 LVD/SE "; + else if (p->features & AHC_ULTRA) + ultra = "Ultra "; + size += sprintf(BLS, " %s%sController%s ", + ultra, wide, channel); + } + switch(p->chip & ~AHC_CHIPID_MASK) + { + case AHC_VL: + size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn); + break; + case AHC_EISA: + size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn); + break; + default: + size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus, + PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn)); + break; + } + if( !(p->maddr) ) + { + size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base); + } + else + { + size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase); + } + if( (p->chip & (AHC_VL | AHC_EISA)) ) + { + size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address); + } + size += sprintf(BLS, " Adapter SEEPROM Config: %s\n", + (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." : + ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." : + "SEEPROM not found, using leftover BIOS values.") ); + size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n", + (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled"); + size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); + size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n", + p->activescbs, p->max_activescbs); + size += sprintf(BLS, " Allocated %d, HW %d, " + "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, + p->scb_data->maxscbs); + if (p->flags & AHC_EXTERNAL_SRAM) + size += sprintf(BLS, " Using External SCB SRAM\n"); + size += sprintf(BLS, " Interrupts: %ld", p->isr_count); + if (p->chip & AHC_EISA) + { + size += sprintf(BLS, " %s\n", + (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)"); + } + else + { + size += sprintf(BLS, "\n"); + } + size += sprintf(BLS, " BIOS Control Word: 0x%04x\n", + p->bios_control); + size += sprintf(BLS, " Adapter Control Word: 0x%04x\n", + p->adapter_control); + size += sprintf(BLS, " Extended Translation: %sabled\n", + (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis"); + size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable); + if (p->features & (AHC_ULTRA | AHC_ULTRA2)) + { + size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb); + } + size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable); + size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag); + size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE); + size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " + "instance %d:\n", p->instance); + size += sprintf(BLS, " {"); + for(i=0; i < (MAX_TARGETS - 1); i++) + size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]); + size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]); + size += sprintf(BLS, " Actual queue depth per device for aic7xxx host " + "instance %d:\n", p->instance); + size += sprintf(BLS, " {"); + for(i=0; i < (MAX_TARGETS - 1); i++) + size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]); + size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]); + + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Statistics:\n\n"); + for (target = 0; target < MAX_TARGETS; target++) + { + sp = &p->stats[target]; + if ((p->dev_flags[target] & DEVICE_PRESENT) == 0) + { + continue; + } + if (p->features & AHC_TWIN) + { + size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", + p->host_no, (target >> 3), (target & 0x7), 0); + } + else + { + size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", + p->host_no, 0, target, 0); + } + size += sprintf(BLS, " Device using %s/%s", + (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ? + "Wide" : "Narrow", + (p->transinfo[target].cur_offset != 0) ? + "Sync transfers at " : "Async transfers.\n" ); + if (p->transinfo[target].cur_offset != 0) + { + struct aic7xxx_syncrate *sync_rate; + unsigned char options = p->transinfo[target].cur_options; + int period = p->transinfo[target].cur_period; + int rate = (p->transinfo[target].cur_width == + MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0; + + sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options); + if (sync_rate != NULL) + { + size += sprintf(BLS, "%s MByte/sec, offset %d\n", + sync_rate->rate[rate], + p->transinfo[target].cur_offset ); + } + else + { + size += sprintf(BLS, "3.3 MByte/sec, offset %d\n", + p->transinfo[target].cur_offset ); + } + } + size += sprintf(BLS, " Transinfo settings: "); + size += sprintf(BLS, "current(%d/%d/%d/%d), ", + p->transinfo[target].cur_period, + p->transinfo[target].cur_offset, + p->transinfo[target].cur_width, + p->transinfo[target].cur_options); + size += sprintf(BLS, "goal(%d/%d/%d/%d), ", + p->transinfo[target].goal_period, + p->transinfo[target].goal_offset, + p->transinfo[target].goal_width, + p->transinfo[target].goal_options); + size += sprintf(BLS, "user(%d/%d/%d/%d)\n", + p->transinfo[target].user_period, + p->transinfo[target].user_offset, + p->transinfo[target].user_width, + p->transinfo[target].user_options); +#ifdef AIC7XXX_PROC_STATS + size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", + sp->r_total + sp->w_total, sp->r_total, sp->w_total); + size += sprintf(BLS, "%s\n", HDRB); + size += sprintf(BLS, " Reads:"); + for (i = 0; i < NUMBER(sp->r_bins); i++) + { + size += sprintf(BLS, " %7ld", sp->r_bins[i]); + } + size += sprintf(BLS, "\n"); + size += sprintf(BLS, " Writes:"); + for (i = 0; i < NUMBER(sp->w_bins); i++) + { + size += sprintf(BLS, " %7ld", sp->w_bins[i]); + } + size += sprintf(BLS, "\n"); +#else + size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", + sp->r_total + sp->w_total, sp->r_total, sp->w_total); +#endif /* AIC7XXX_PROC_STATS */ + size += sprintf(BLS, "\n\n"); + } + + if (size >= aic7xxx_buffer_size) + { + printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); + } + + if (offset > size - 1) + { + kfree(aic7xxx_buffer); + aic7xxx_buffer = NULL; + aic7xxx_buffer_size = length = 0; + *start = NULL; + } + else + { + *start = buffer; + length = MIN(length, size - offset); + memcpy(buffer, &aic7xxx_buffer[offset], length); + } + + return (length); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx/aic7xxx_reg.h linux/drivers/scsi/aic7xxx/aic7xxx_reg.h --- v2.2.18/drivers/scsi/aic7xxx/aic7xxx_reg.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_reg.h Sun Mar 25 11:37:35 2001 @@ -0,0 +1,629 @@ +/* + * DO NOT EDIT - This file is automatically generated. + */ + +#define SCSISEQ 0x00 +#define TEMODE 0x80 +#define ENSELO 0x40 +#define ENSELI 0x20 +#define ENRSELI 0x10 +#define ENAUTOATNO 0x08 +#define ENAUTOATNI 0x04 +#define ENAUTOATNP 0x02 +#define SCSIRSTO 0x01 + +#define SXFRCTL0 0x01 +#define DFON 0x80 +#define DFPEXP 0x40 +#define FAST20 0x20 +#define CLRSTCNT 0x10 +#define SPIOEN 0x08 +#define SCAMEN 0x04 +#define CLRCHN 0x02 + +#define SXFRCTL1 0x02 +#define BITBUCKET 0x80 +#define SWRAPEN 0x40 +#define ENSPCHK 0x20 +#define STIMESEL 0x18 +#define ENSTIMER 0x04 +#define ACTNEGEN 0x02 +#define STPWEN 0x01 + +#define SCSISIGO 0x03 +#define CDO 0x80 +#define IOO 0x40 +#define MSGO 0x20 +#define ATNO 0x10 +#define SELO 0x08 +#define BSYO 0x04 +#define REQO 0x02 +#define ACKO 0x01 + +#define SCSISIGI 0x03 +#define ATNI 0x10 +#define SELI 0x08 +#define BSYI 0x04 +#define REQI 0x02 +#define ACKI 0x01 + +#define SCSIRATE 0x04 +#define WIDEXFER 0x80 +#define SXFR_ULTRA2 0x7f +#define SXFR 0x70 +#define SOFS 0x0f + +#define SCSIID 0x05 +#define SCSIOFFSET 0x05 +#define SOFS_ULTRA2 0x7f + +#define SCSIDATL 0x06 + +#define SCSIDATH 0x07 + +#define STCNT 0x08 + +#define OPTIONMODE 0x08 +#define AUTORATEEN 0x80 +#define AUTOACKEN 0x40 +#define ATNMGMNTEN 0x20 +#define BUSFREEREV 0x10 +#define EXPPHASEDIS 0x08 +#define SCSIDATL_IMGEN 0x04 +#define AUTO_MSGOUT_DE 0x02 +#define DIS_MSGIN_DUALEDGE 0x01 + +#define CLRSINT0 0x0b +#define CLRSELDO 0x40 +#define CLRSELDI 0x20 +#define CLRSELINGO 0x10 +#define CLRSWRAP 0x08 +#define CLRSPIORDY 0x02 + +#define SSTAT0 0x0b +#define TARGET 0x80 +#define SELDO 0x40 +#define SELDI 0x20 +#define SELINGO 0x10 +#define IOERR 0x08 +#define SWRAP 0x08 +#define SDONE 0x04 +#define SPIORDY 0x02 +#define DMADONE 0x01 + +#define CLRSINT1 0x0c +#define CLRSELTIMEO 0x80 +#define CLRATNO 0x40 +#define CLRSCSIRSTI 0x20 +#define CLRBUSFREE 0x08 +#define CLRSCSIPERR 0x04 +#define CLRPHASECHG 0x02 +#define CLRREQINIT 0x01 + +#define SSTAT1 0x0c +#define SELTO 0x80 +#define ATNTARG 0x40 +#define SCSIRSTI 0x20 +#define PHASEMIS 0x10 +#define BUSFREE 0x08 +#define SCSIPERR 0x04 +#define PHASECHG 0x02 +#define REQINIT 0x01 + +#define SSTAT2 0x0d +#define OVERRUN 0x80 +#define SHVALID 0x40 +#define WIDE_RES 0x20 +#define SFCNT 0x1f +#define EXP_ACTIVE 0x10 +#define CRCVALERR 0x08 +#define CRCENDERR 0x04 +#define CRCREQERR 0x02 +#define DUAL_EDGE_ERROR 0x01 + +#define SSTAT3 0x0e +#define SCSICNT 0xf0 +#define OFFCNT 0x0f + +#define SCSIID_ULTRA2 0x0f +#define OID 0x0f + +#define SIMODE0 0x10 +#define ENSELDO 0x40 +#define ENSELDI 0x20 +#define ENSELINGO 0x10 +#define ENIOERR 0x08 +#define ENSWRAP 0x08 +#define ENSDONE 0x04 +#define ENSPIORDY 0x02 +#define ENDMADONE 0x01 + +#define SIMODE1 0x11 +#define ENSELTIMO 0x80 +#define ENATNTARG 0x40 +#define ENSCSIRST 0x20 +#define ENPHASEMIS 0x10 +#define ENBUSFREE 0x08 +#define ENSCSIPERR 0x04 +#define ENPHASECHG 0x02 +#define ENREQINIT 0x01 + +#define SCSIBUSL 0x12 + +#define SCSIBUSH 0x13 + +#define SHADDR 0x14 + +#define SELTIMER 0x18 +#define STAGE6 0x20 +#define STAGE5 0x10 +#define STAGE4 0x08 +#define STAGE3 0x04 +#define STAGE2 0x02 +#define STAGE1 0x01 + +#define SELID 0x19 +#define SELID_MASK 0xf0 +#define ONEBIT 0x08 + +#define SPIOCAP 0x1b +#define SOFT1 0x80 +#define SOFT0 0x40 +#define SOFTCMDEN 0x20 +#define HAS_BRDCTL 0x10 +#define SEEPROM 0x08 +#define EEPROM 0x04 +#define ROM 0x02 +#define SSPIOCPS 0x01 + +#define BRDCTL 0x1d +#define BRDDAT7 0x80 +#define BRDDAT6 0x40 +#define BRDDAT5 0x20 +#define BRDDAT4 0x10 +#define BRDSTB 0x10 +#define BRDCS 0x08 +#define BRDDAT3 0x08 +#define BRDDAT2 0x04 +#define BRDRW 0x04 +#define BRDRW_ULTRA2 0x02 +#define BRDCTL1 0x02 +#define BRDSTB_ULTRA2 0x01 +#define BRDCTL0 0x01 + +#define SEECTL 0x1e +#define EXTARBACK 0x80 +#define EXTARBREQ 0x40 +#define SEEMS 0x20 +#define SEERDY 0x10 +#define SEECS 0x08 +#define SEECK 0x04 +#define SEEDO 0x02 +#define SEEDI 0x01 + +#define SBLKCTL 0x1f +#define DIAGLEDEN 0x80 +#define DIAGLEDON 0x40 +#define AUTOFLUSHDIS 0x20 +#define ENAB40 0x08 +#define ENAB20 0x04 +#define SELWIDE 0x02 +#define XCVR 0x01 + +#define SRAM_BASE 0x20 + +#define TARG_SCSIRATE 0x20 + +#define ULTRA_ENB 0x30 + +#define DISC_DSB 0x32 + +#define MSG_OUT 0x34 + +#define DMAPARAMS 0x35 +#define PRELOADEN 0x80 +#define WIDEODD 0x40 +#define SCSIEN 0x20 +#define SDMAENACK 0x10 +#define SDMAEN 0x10 +#define HDMAEN 0x08 +#define HDMAENACK 0x08 +#define DIRECTION 0x04 +#define FIFOFLUSH 0x02 +#define FIFORESET 0x01 + +#define SEQ_FLAGS 0x36 +#define IDENTIFY_SEEN 0x80 +#define SCBPTR_VALID 0x20 +#define DPHASE 0x10 +#define AMTARGET 0x08 +#define WIDE_BUS 0x02 +#define TWIN_BUS 0x01 + +#define SAVED_TCL 0x37 + +#define SG_COUNT 0x38 + +#define SG_NEXT 0x39 + +#define LASTPHASE 0x3d +#define P_MESGIN 0xe0 +#define PHASE_MASK 0xe0 +#define P_STATUS 0xc0 +#define P_MESGOUT 0xa0 +#define P_COMMAND 0x80 +#define CDI 0x80 +#define IOI 0x40 +#define P_DATAIN 0x40 +#define MSGI 0x20 +#define P_BUSFREE 0x01 +#define P_DATAOUT 0x00 + +#define WAITING_SCBH 0x3e + +#define DISCONNECTED_SCBH 0x3f + +#define FREE_SCBH 0x40 + +#define HSCB_ADDR 0x41 + +#define SCBID_ADDR 0x45 + +#define TMODE_CMDADDR 0x49 + +#define KERNEL_QINPOS 0x4d + +#define QINPOS 0x4e + +#define QOUTPOS 0x4f + +#define TMODE_CMDADDR_NEXT 0x50 + +#define ARG_1 0x51 +#define RETURN_1 0x51 +#define SEND_MSG 0x80 +#define SEND_SENSE 0x40 +#define SEND_REJ 0x20 +#define MSGOUT_PHASEMIS 0x10 + +#define ARG_2 0x52 +#define RETURN_2 0x52 + +#define LAST_MSG 0x53 + +#define PREFETCH_CNT 0x54 + +#define SCSICONF 0x5a +#define TERM_ENB 0x80 +#define RESET_SCSI 0x40 +#define HWSCSIID 0x0f +#define HSCSIID 0x07 + +#define HOSTCONF 0x5d + +#define HA_274_BIOSCTRL 0x5f +#define BIOSMODE 0x30 +#define BIOSDISABLED 0x30 +#define CHANNEL_B_PRIMARY 0x08 + +#define SEQCTL 0x60 +#define PERRORDIS 0x80 +#define PAUSEDIS 0x40 +#define FAILDIS 0x20 +#define FASTMODE 0x10 +#define BRKADRINTEN 0x08 +#define STEP 0x04 +#define SEQRESET 0x02 +#define LOADRAM 0x01 + +#define SEQRAM 0x61 + +#define SEQADDR0 0x62 + +#define SEQADDR1 0x63 +#define SEQADDR1_MASK 0x01 + +#define ACCUM 0x64 + +#define SINDEX 0x65 + +#define DINDEX 0x66 + +#define ALLONES 0x69 + +#define ALLZEROS 0x6a + +#define NONE 0x6a + +#define FLAGS 0x6b +#define ZERO 0x02 +#define CARRY 0x01 + +#define SINDIR 0x6c + +#define DINDIR 0x6d + +#define FUNCTION1 0x6e + +#define STACK 0x6f + +#define TARG_OFFSET 0x70 + +#define BCTL 0x84 +#define ACE 0x08 +#define ENABLE 0x01 + +#define DSCOMMAND0 0x84 +#define INTSCBRAMSEL 0x08 +#define RAMPS 0x04 +#define USCBSIZE32 0x02 +#define CIOPARCKEN 0x01 + +#define DSCOMMAND 0x84 +#define CACHETHEN 0x80 +#define DPARCKEN 0x40 +#define MPARCKEN 0x20 +#define EXTREQLCK 0x10 + +#define BUSTIME 0x85 +#define BOFF 0xf0 +#define BON 0x0f + +#define BUSSPD 0x86 +#define DFTHRSH 0xc0 +#define STBOFF 0x38 +#define STBON 0x07 + +#define DSPCISTATUS 0x86 +#define DFTHRSH_100 0xc0 + +#define HCNTRL 0x87 +#define POWRDN 0x40 +#define SWINT 0x10 +#define IRQMS 0x08 +#define PAUSE 0x04 +#define INTEN 0x02 +#define CHIPRST 0x01 +#define CHIPRSTACK 0x01 + +#define HADDR 0x88 + +#define HCNT 0x8c + +#define SCBPTR 0x90 + +#define INTSTAT 0x91 +#define SEQINT_MASK 0xf1 +#define DATA_OVERRUN 0xe1 +#define MSGIN_PHASEMIS 0xd1 +#define TRACEPOINT2 0xc1 +#define SEQ_SG_FIXUP 0xb1 +#define AWAITING_MSG 0xa1 +#define RESIDUAL 0x81 +#define BAD_STATUS 0x71 +#define REJECT_MSG 0x61 +#define WIDE_RESIDUE 0x51 +#define EXTENDED_MSG 0x41 +#define NO_MATCH 0x31 +#define NO_IDENT 0x21 +#define SEND_REJECT 0x11 +#define INT_PEND 0x0f +#define BRKADRINT 0x08 +#define SCSIINT 0x04 +#define CMDCMPLT 0x02 +#define BAD_PHASE 0x01 +#define SEQINT 0x01 + +#define CLRINT 0x92 +#define CLRPARERR 0x10 +#define CLRBRKADRINT 0x08 +#define CLRSCSIINT 0x04 +#define CLRCMDINT 0x02 +#define CLRSEQINT 0x01 + +#define ERROR 0x92 +#define CIOPARERR 0x80 +#define PCIERRSTAT 0x40 +#define MPARERR 0x20 +#define DPARERR 0x10 +#define SQPARERR 0x08 +#define ILLOPCODE 0x04 +#define DSCTMOUT 0x02 +#define ILLSADDR 0x02 +#define ILLHADDR 0x01 + +#define DFCNTRL 0x93 + +#define DFSTATUS 0x94 +#define PRELOAD_AVAIL 0x80 +#define DWORDEMP 0x20 +#define MREQPEND 0x10 +#define HDONE 0x08 +#define DFTHRESH 0x04 +#define FIFOFULL 0x02 +#define FIFOEMP 0x01 + +#define DFDAT 0x99 + +#define SCBCNT 0x9a +#define SCBAUTO 0x80 +#define SCBCNT_MASK 0x1f + +#define QINFIFO 0x9b + +#define QINCNT 0x9c + +#define SCSIDATL_IMG 0x9c + +#define QOUTFIFO 0x9d + +#define CRCCONTROL1 0x9d +#define CRCONSEEN 0x80 +#define CRCVALCHKEN 0x40 +#define CRCENDCHKEN 0x20 +#define CRCREQCHKEN 0x10 +#define TARGCRCENDEN 0x08 +#define TARGCRCCNTEN 0x04 + +#define SCSIPHASE 0x9e +#define SP_STATUS 0x20 +#define SP_COMMAND 0x10 +#define SP_MSG_IN 0x08 +#define SP_MSG_OUT 0x04 +#define SP_DATA_IN 0x02 +#define SP_DATA_OUT 0x01 + +#define QOUTCNT 0x9e + +#define SFUNCT 0x9f +#define ALT_MODE 0x80 + +#define SCB_CONTROL 0xa0 +#define MK_MESSAGE 0x80 +#define DISCENB 0x40 +#define TAG_ENB 0x20 +#define DISCONNECTED 0x04 +#define SCB_TAG_TYPE 0x03 + +#define SCB_BASE 0xa0 + +#define SCB_TCL 0xa1 +#define TID 0xf0 +#define SELBUSB 0x08 +#define LID 0x07 + +#define SCB_TARGET_STATUS 0xa2 + +#define SCB_SGCOUNT 0xa3 + +#define SCB_SGPTR 0xa4 + +#define SCB_RESID_SGCNT 0xa8 + +#define SCB_RESID_DCNT 0xa9 + +#define SCB_DATAPTR 0xac + +#define SCB_DATACNT 0xb0 + +#define SCB_CMDPTR 0xb4 + +#define SCB_CMDLEN 0xb8 + +#define SCB_TAG 0xb9 + +#define SCB_NEXT 0xba + +#define SCB_PREV 0xbb + +#define SCB_BUSYTARGETS 0xbc + +#define SEECTL_2840 0xc0 +#define CS_2840 0x04 +#define CK_2840 0x02 +#define DO_2840 0x01 + +#define STATUS_2840 0xc1 +#define EEPROM_TF 0x80 +#define BIOS_SEL 0x60 +#define ADSEL 0x1e +#define DI_2840 0x01 + +#define CCHADDR 0xe0 + +#define CCHCNT 0xe8 + +#define CCSGRAM 0xe9 + +#define CCSGADDR 0xea + +#define CCSGCTL 0xeb +#define CCSGDONE 0x80 +#define CCSGEN 0x08 +#define FLAG 0x02 +#define CCSGRESET 0x01 + +#define CCSCBRAM 0xec + +#define CCSCBADDR 0xed + +#define CCSCBCTL 0xee +#define CCSCBDONE 0x80 +#define ARRDONE 0x40 +#define CCARREN 0x10 +#define CCSCBEN 0x08 +#define CCSCBDIR 0x04 +#define CCSCBRESET 0x01 + +#define CCSCBCNT 0xef + +#define CCSCBPTR 0xf1 + +#define HNSCB_QOFF 0xf4 + +#define HESCB_QOFF 0xf5 + +#define SNSCB_QOFF 0xf6 + +#define SESCB_QOFF 0xf7 + +#define SDSCB_QOFF 0xf8 + +#define QOFF_CTLSTA 0xfa +#define ESTABLISH_SCB_AVAIL 0x80 +#define SCB_AVAIL 0x40 +#define SNSCB_ROLLOVER 0x20 +#define SDSCB_ROLLOVER 0x10 +#define SESCB_ROLLOVER 0x08 +#define SCB_QSIZE 0x07 +#define SCB_QSIZE_256 0x06 + +#define DFF_THRSH 0xfb +#define WR_DFTHRSH 0x70 +#define WR_DFTHRSH_MAX 0x70 +#define WR_DFTHRSH_90 0x60 +#define WR_DFTHRSH_85 0x50 +#define WR_DFTHRSH_75 0x40 +#define WR_DFTHRSH_63 0x30 +#define WR_DFTHRSH_50 0x20 +#define WR_DFTHRSH_25 0x10 +#define RD_DFTHRSH_MAX 0x07 +#define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_90 0x06 +#define RD_DFTHRSH_85 0x05 +#define RD_DFTHRSH_75 0x04 +#define RD_DFTHRSH_63 0x03 +#define RD_DFTHRSH_50 0x02 +#define RD_DFTHRSH_25 0x01 +#define WR_DFTHRSH_MIN 0x00 +#define RD_DFTHRSH_MIN 0x00 + +#define SG_CACHEPTR 0xfc +#define SG_USER_DATA 0xfc +#define LAST_SEG 0x02 +#define LAST_SEG_DONE 0x01 + + +#define CMD_GROUP2_BYTE_DELTA 0xfa +#define MAX_OFFSET_8BIT 0x0f +#define BUS_16_BIT 0x01 +#define QINFIFO_OFFSET 0x02 +#define CMD_GROUP5_BYTE_DELTA 0x0b +#define CMD_GROUP_CODE_SHIFT 0x05 +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 +#define BUS_8_BIT 0x00 +#define QOUTFIFO_OFFSET 0x01 +#define UNTAGGEDSCB_OFFSET 0x00 +#define CCSGRAM_MAXSEGS 0x10 +#define SCB_LIST_NULL 0xff +#define SG_SIZEOF 0x08 +#define CMD_GROUP4_BYTE_DELTA 0x04 +#define CMD_GROUP0_BYTE_DELTA 0xfc +#define HOST_MSG 0xff +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 + + +/* Downloaded Constant Definitions */ +#define TMODE_NUMCMDS 0x00 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx/aic7xxx_seq.c linux/drivers/scsi/aic7xxx/aic7xxx_seq.c --- v2.2.18/drivers/scsi/aic7xxx/aic7xxx_seq.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.c Sun Mar 25 11:37:35 2001 @@ -0,0 +1,817 @@ +/* + * DO NOT EDIT - This file is automatically generated. + */ +static unsigned char seqprog[] = { + 0xff, 0x6a, 0x06, 0x08, + 0x7f, 0x02, 0x04, 0x08, + 0x12, 0x6a, 0x00, 0x00, + 0xff, 0x6a, 0xd6, 0x09, + 0xff, 0x6a, 0xdc, 0x09, + 0x00, 0x65, 0xca, 0x58, + 0xf7, 0x01, 0x02, 0x08, + 0xff, 0x4e, 0xc8, 0x08, + 0xbf, 0x60, 0xc0, 0x08, + 0x60, 0x0b, 0x86, 0x68, + 0x40, 0x00, 0x0c, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0x60, 0x0b, 0x86, 0x68, + 0x40, 0x00, 0x0c, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0xff, 0x3e, 0x48, 0x60, + 0x40, 0xfa, 0x10, 0x78, + 0xff, 0xf6, 0xd4, 0x08, + 0x01, 0x4e, 0x9c, 0x18, + 0x40, 0x60, 0xc0, 0x00, + 0x00, 0x4d, 0x10, 0x70, + 0x01, 0x4e, 0x9c, 0x18, + 0xbf, 0x60, 0xc0, 0x08, + 0x00, 0x6a, 0x86, 0x5c, + 0xff, 0x4e, 0xc8, 0x18, + 0x02, 0x6a, 0x70, 0x5b, + 0xff, 0x52, 0x20, 0x09, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0x52, 0xe6, 0x5b, + 0x03, 0xb0, 0x52, 0x31, + 0xff, 0xb0, 0x52, 0x09, + 0xff, 0xb1, 0x54, 0x09, + 0xff, 0xb2, 0x56, 0x09, + 0xff, 0xa3, 0x50, 0x09, + 0xff, 0x3e, 0x74, 0x09, + 0xff, 0x90, 0x7c, 0x08, + 0xff, 0x3e, 0x20, 0x09, + 0x00, 0x65, 0x4e, 0x58, + 0x00, 0x65, 0x0c, 0x40, + 0xf7, 0x1f, 0xca, 0x08, + 0x08, 0xa1, 0xc8, 0x08, + 0x00, 0x65, 0xca, 0x00, + 0xff, 0x65, 0x3e, 0x08, + 0xf0, 0xa1, 0xc8, 0x08, + 0x0f, 0x0f, 0x1e, 0x08, + 0x00, 0x0f, 0x1e, 0x00, + 0xf0, 0xa1, 0xc8, 0x08, + 0x0f, 0x05, 0x0a, 0x08, + 0x00, 0x05, 0x0a, 0x00, + 0xff, 0x6a, 0x0c, 0x08, + 0x5a, 0x6a, 0x00, 0x04, + 0x12, 0x65, 0x02, 0x00, + 0x31, 0x6a, 0xca, 0x00, + 0x80, 0x37, 0x6e, 0x68, + 0xff, 0x65, 0xca, 0x18, + 0xff, 0x37, 0xdc, 0x08, + 0xff, 0x6e, 0xc8, 0x08, + 0x00, 0x6c, 0x76, 0x78, + 0x20, 0x01, 0x02, 0x00, + 0x4c, 0x37, 0xc8, 0x28, + 0x08, 0x1f, 0x7e, 0x78, + 0x08, 0x37, 0x6e, 0x00, + 0x08, 0x64, 0xc8, 0x00, + 0x70, 0x64, 0xca, 0x18, + 0xff, 0x6c, 0x0a, 0x08, + 0x20, 0x64, 0xca, 0x18, + 0xff, 0x6c, 0x08, 0x0c, + 0x40, 0x0b, 0x96, 0x68, + 0x20, 0x6a, 0x16, 0x00, + 0xf0, 0x19, 0x6e, 0x08, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x08, 0x6a, 0x66, 0x58, + 0x08, 0x6a, 0x68, 0x00, + 0x00, 0x65, 0xaa, 0x40, + 0x12, 0x6a, 0x00, 0x00, + 0x40, 0x6a, 0x16, 0x00, + 0xff, 0x3e, 0x20, 0x09, + 0xff, 0xba, 0x7c, 0x08, + 0xff, 0xa1, 0x6e, 0x08, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x08, 0x6a, 0x66, 0x58, + 0x80, 0x6a, 0x68, 0x00, + 0x80, 0x36, 0x6c, 0x00, + 0x00, 0x65, 0xba, 0x5b, + 0xff, 0x3d, 0xc8, 0x08, + 0xbf, 0x64, 0xe2, 0x78, + 0x80, 0x64, 0xc8, 0x71, + 0xa0, 0x64, 0xf8, 0x71, + 0xc0, 0x64, 0xf0, 0x71, + 0xe0, 0x64, 0x38, 0x72, + 0x01, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0xf7, 0x11, 0x22, 0x08, + 0x00, 0x65, 0xca, 0x58, + 0xff, 0x06, 0xd4, 0x08, + 0xf7, 0x01, 0x02, 0x08, + 0x09, 0x0c, 0xc4, 0x78, + 0x08, 0x0c, 0x0c, 0x68, + 0x01, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0x26, 0x09, + 0x02, 0x6a, 0x08, 0x30, + 0xff, 0x6a, 0x08, 0x08, + 0xdf, 0x01, 0x02, 0x08, + 0x01, 0x6a, 0x7a, 0x00, + 0xff, 0x6a, 0x6c, 0x0c, + 0x04, 0x14, 0x10, 0x31, + 0x03, 0xa9, 0x18, 0x31, + 0x03, 0xa9, 0x10, 0x30, + 0x08, 0x6a, 0xcc, 0x00, + 0xa9, 0x6a, 0xd0, 0x5b, + 0x00, 0x65, 0x02, 0x41, + 0xa8, 0x6a, 0x6a, 0x00, + 0x79, 0x6a, 0x6a, 0x00, + 0x40, 0x3d, 0xea, 0x68, + 0x04, 0x35, 0x6a, 0x00, + 0x00, 0x65, 0x2a, 0x5b, + 0x80, 0x6a, 0xd4, 0x01, + 0x10, 0x36, 0xd6, 0x68, + 0x10, 0x36, 0x6c, 0x00, + 0x07, 0xac, 0x10, 0x31, + 0x05, 0xa3, 0x70, 0x30, + 0x03, 0x8c, 0x10, 0x30, + 0x88, 0x6a, 0xcc, 0x00, + 0xac, 0x6a, 0xc8, 0x5b, + 0x00, 0x65, 0xc2, 0x5b, + 0x38, 0x6a, 0xcc, 0x00, + 0xa3, 0x6a, 0xcc, 0x5b, + 0xff, 0x38, 0x12, 0x69, + 0x80, 0x02, 0x04, 0x00, + 0xe7, 0x35, 0x6a, 0x08, + 0x03, 0x69, 0x18, 0x31, + 0x03, 0x69, 0x10, 0x30, + 0xff, 0x6a, 0x10, 0x00, + 0xff, 0x6a, 0x12, 0x00, + 0xff, 0x6a, 0x14, 0x00, + 0x22, 0x38, 0xc8, 0x28, + 0x01, 0x38, 0x1c, 0x61, + 0x02, 0x64, 0xc8, 0x00, + 0x01, 0x38, 0x1c, 0x61, + 0xbf, 0x35, 0x6a, 0x08, + 0xff, 0x64, 0xf8, 0x09, + 0xff, 0x35, 0x26, 0x09, + 0x80, 0x02, 0xa4, 0x69, + 0x10, 0x0c, 0x7a, 0x69, + 0x80, 0x94, 0x22, 0x79, + 0x00, 0x35, 0x0a, 0x5b, + 0x80, 0x02, 0xa4, 0x69, + 0xff, 0x65, 0x94, 0x79, + 0x01, 0x38, 0x70, 0x71, + 0xff, 0x38, 0x70, 0x18, + 0xff, 0x38, 0x94, 0x79, + 0x80, 0xea, 0x4a, 0x61, + 0xef, 0x38, 0xc8, 0x18, + 0x80, 0x6a, 0xc8, 0x00, + 0x00, 0x65, 0x3c, 0x49, + 0x33, 0x38, 0xc8, 0x28, + 0xff, 0x64, 0xd0, 0x09, + 0x04, 0x39, 0xc0, 0x31, + 0x09, 0x6a, 0xd6, 0x01, + 0x80, 0xeb, 0x42, 0x79, + 0xf7, 0xeb, 0xd6, 0x09, + 0x08, 0xeb, 0x46, 0x69, + 0x01, 0x6a, 0xd6, 0x01, + 0x08, 0xe9, 0x10, 0x31, + 0x03, 0x8c, 0x10, 0x30, + 0xff, 0x38, 0x70, 0x18, + 0x88, 0x6a, 0xcc, 0x00, + 0x39, 0x6a, 0xce, 0x5b, + 0x08, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x0d, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x78, 0x5c, + 0x88, 0x6a, 0xcc, 0x00, + 0x00, 0x65, 0x6a, 0x5c, + 0x00, 0x65, 0xc2, 0x5b, + 0xff, 0x6a, 0xc8, 0x08, + 0x08, 0x39, 0x72, 0x18, + 0x00, 0x3a, 0x74, 0x20, + 0x00, 0x65, 0x02, 0x41, + 0x01, 0x0c, 0x6c, 0x79, + 0x10, 0x0c, 0x02, 0x79, + 0x10, 0x0c, 0x7a, 0x69, + 0x01, 0xfc, 0x70, 0x79, + 0xff, 0x6a, 0x70, 0x08, + 0x01, 0x0c, 0x76, 0x79, + 0x10, 0x0c, 0x02, 0x79, + 0x00, 0x65, 0xae, 0x59, + 0x01, 0xfc, 0x94, 0x69, + 0x40, 0x0d, 0x84, 0x69, + 0xb1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x94, 0x41, + 0x2e, 0xfc, 0xa2, 0x28, + 0x3f, 0x38, 0xc8, 0x08, + 0x00, 0x51, 0x94, 0x71, + 0xff, 0x6a, 0xc8, 0x08, + 0xf8, 0x39, 0x72, 0x18, + 0xff, 0x3a, 0x74, 0x20, + 0x01, 0x38, 0x70, 0x18, + 0x00, 0x65, 0x86, 0x41, + 0x03, 0x08, 0x52, 0x31, + 0xff, 0x38, 0x50, 0x09, + 0x12, 0x01, 0x02, 0x00, + 0xff, 0x08, 0x52, 0x09, + 0xff, 0x09, 0x54, 0x09, + 0xff, 0x0a, 0x56, 0x09, + 0xff, 0x38, 0x50, 0x09, + 0x00, 0x65, 0xaa, 0x40, + 0x10, 0x0c, 0xa4, 0x79, + 0x00, 0x65, 0xae, 0x59, + 0x7f, 0x02, 0x04, 0x08, + 0xe1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0x04, 0x93, 0xc2, 0x69, + 0xdf, 0x93, 0x26, 0x09, + 0x20, 0x93, 0xb2, 0x69, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x10, 0x94, 0xc0, 0x69, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xc4, 0x69, + 0xff, 0x6a, 0xd4, 0x0c, + 0x00, 0x65, 0x2a, 0x5b, + 0x05, 0xb4, 0x10, 0x31, + 0x02, 0x6a, 0x1a, 0x31, + 0x03, 0x8c, 0x10, 0x30, + 0x88, 0x6a, 0xcc, 0x00, + 0xb4, 0x6a, 0xcc, 0x5b, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x00, 0x65, 0xc2, 0x5b, + 0x3d, 0x6a, 0x0a, 0x5b, + 0xac, 0x6a, 0x26, 0x01, + 0x04, 0x0b, 0xde, 0x69, + 0x04, 0x0b, 0xe4, 0x69, + 0x10, 0x0c, 0xe0, 0x79, + 0x02, 0x03, 0xe8, 0x79, + 0x11, 0x0c, 0xe4, 0x79, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xea, 0x69, + 0x12, 0x01, 0x02, 0x00, + 0x00, 0x65, 0xaa, 0x40, + 0x00, 0x65, 0x2a, 0x5b, + 0xff, 0x06, 0x44, 0x09, + 0x00, 0x65, 0xaa, 0x40, + 0x10, 0x3d, 0x06, 0x00, + 0xff, 0x34, 0xca, 0x08, + 0x80, 0x65, 0x1c, 0x62, + 0x0f, 0xa1, 0xca, 0x08, + 0x07, 0xa1, 0xca, 0x08, + 0x40, 0xa0, 0xc8, 0x08, + 0x00, 0x65, 0xca, 0x00, + 0x80, 0x65, 0xca, 0x00, + 0x80, 0xa0, 0x0c, 0x7a, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0x1e, 0x42, + 0x20, 0xa0, 0x24, 0x7a, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0x2c, 0x62, + 0x23, 0xa0, 0x0c, 0x08, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0x2c, 0x62, + 0x00, 0xb9, 0x24, 0x42, + 0xff, 0x65, 0x24, 0x62, + 0xa1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x10, 0x51, 0x2c, 0x72, + 0x40, 0x6a, 0x18, 0x00, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0xf6, 0x71, + 0x40, 0x6a, 0x18, 0x00, + 0xff, 0x34, 0xa6, 0x08, + 0x80, 0x34, 0x34, 0x62, + 0x7f, 0xa0, 0x40, 0x09, + 0x08, 0x6a, 0x68, 0x00, + 0x00, 0x65, 0xaa, 0x40, + 0x64, 0x6a, 0x00, 0x5b, + 0x80, 0x64, 0xaa, 0x6a, + 0x04, 0x64, 0x8c, 0x72, + 0x02, 0x64, 0x92, 0x72, + 0x00, 0x6a, 0x54, 0x72, + 0x03, 0x64, 0xa6, 0x72, + 0x01, 0x64, 0x88, 0x72, + 0x07, 0x64, 0xe8, 0x72, + 0x08, 0x64, 0x50, 0x72, + 0x23, 0x64, 0xec, 0x72, + 0x11, 0x6a, 0x22, 0x01, + 0x07, 0x6a, 0xf2, 0x5a, + 0xff, 0x06, 0xd4, 0x08, + 0x00, 0x65, 0xaa, 0x40, + 0xff, 0xa8, 0x58, 0x6a, + 0xff, 0xa2, 0x70, 0x7a, + 0x01, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0xe6, 0x5b, + 0xff, 0xa2, 0x70, 0x7a, + 0x71, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x40, 0x51, 0x70, 0x62, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0xe6, 0x5b, + 0xff, 0x3e, 0x74, 0x09, + 0xff, 0x90, 0x7c, 0x08, + 0x00, 0x65, 0x4e, 0x58, + 0x00, 0x65, 0xbc, 0x40, + 0x20, 0xa0, 0x78, 0x6a, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0x6a, 0x90, 0x5b, + 0xff, 0x6a, 0xa6, 0x5b, + 0xff, 0xf8, 0xc8, 0x08, + 0xff, 0x4f, 0xc8, 0x08, + 0x01, 0x6a, 0x90, 0x5b, + 0x00, 0xb9, 0xa6, 0x5b, + 0x01, 0x4f, 0x9e, 0x18, + 0x02, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x80, 0x5c, + 0x00, 0x65, 0xbc, 0x40, + 0x41, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0x04, 0xa0, 0x40, 0x01, + 0x00, 0x65, 0x98, 0x5c, + 0x00, 0x65, 0xbc, 0x40, + 0x10, 0x36, 0x50, 0x7a, + 0x05, 0x38, 0x46, 0x31, + 0x04, 0x14, 0x58, 0x31, + 0x03, 0xa9, 0x60, 0x31, + 0xa3, 0x6a, 0xcc, 0x00, + 0x38, 0x6a, 0xcc, 0x5b, + 0xac, 0x6a, 0xcc, 0x00, + 0x14, 0x6a, 0xce, 0x5b, + 0xa9, 0x6a, 0xd0, 0x5b, + 0x00, 0x65, 0x50, 0x42, + 0xef, 0x36, 0x6c, 0x08, + 0x00, 0x65, 0x50, 0x42, + 0x0f, 0x64, 0xc8, 0x08, + 0x07, 0x64, 0xc8, 0x08, + 0x00, 0x37, 0x6e, 0x00, + 0xff, 0x6a, 0xa4, 0x00, + 0x00, 0x65, 0x60, 0x5b, + 0xff, 0x51, 0xbc, 0x72, + 0x20, 0x36, 0xc6, 0x7a, + 0x00, 0x90, 0x4e, 0x5b, + 0x00, 0x65, 0xc8, 0x42, + 0xff, 0x06, 0xd4, 0x08, + 0x00, 0x65, 0xba, 0x5b, + 0xe0, 0x3d, 0xe2, 0x62, + 0x20, 0x12, 0xe2, 0x62, + 0x51, 0x6a, 0xf6, 0x5a, + 0x00, 0x65, 0x48, 0x5b, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0xa1, 0xda, 0x62, + 0x04, 0xa0, 0xda, 0x7a, + 0xfb, 0xa0, 0x40, 0x09, + 0x80, 0x36, 0x6c, 0x00, + 0x80, 0xa0, 0x50, 0x7a, + 0x7f, 0xa0, 0x40, 0x09, + 0xff, 0x6a, 0xf2, 0x5a, + 0x00, 0x65, 0x50, 0x42, + 0x04, 0xa0, 0xe0, 0x7a, + 0x00, 0x65, 0x98, 0x5c, + 0x00, 0x65, 0xe2, 0x42, + 0x00, 0x65, 0x80, 0x5c, + 0x31, 0x6a, 0x22, 0x01, + 0x0c, 0x6a, 0xf2, 0x5a, + 0x00, 0x65, 0x50, 0x42, + 0x61, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x50, 0x42, + 0x51, 0x6a, 0xf6, 0x5a, + 0x51, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x50, 0x42, + 0x10, 0x3d, 0x06, 0x00, + 0xff, 0x65, 0x68, 0x0c, + 0xff, 0x06, 0xd4, 0x08, + 0x01, 0x0c, 0xf8, 0x7a, + 0x04, 0x0c, 0xfa, 0x6a, + 0xe0, 0x03, 0x7a, 0x08, + 0xe0, 0x3d, 0x06, 0x63, + 0xff, 0x65, 0xcc, 0x08, + 0xff, 0x12, 0xda, 0x0c, + 0xff, 0x06, 0xd4, 0x0c, + 0xd1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0xff, 0x65, 0x26, 0x09, + 0x01, 0x0b, 0x1a, 0x6b, + 0x10, 0x0c, 0x0c, 0x7b, + 0x04, 0x0b, 0x14, 0x6b, + 0xff, 0x6a, 0xca, 0x08, + 0x04, 0x93, 0x18, 0x6b, + 0x01, 0x94, 0x16, 0x7b, + 0x10, 0x94, 0x18, 0x6b, + 0x80, 0x3d, 0x1e, 0x73, + 0x0f, 0x04, 0x22, 0x6b, + 0x02, 0x03, 0x22, 0x7b, + 0x11, 0x0c, 0x1e, 0x7b, + 0xc7, 0x93, 0x26, 0x09, + 0xff, 0x99, 0xd4, 0x08, + 0x38, 0x93, 0x24, 0x6b, + 0xff, 0x6a, 0xd4, 0x0c, + 0x80, 0x36, 0x28, 0x6b, + 0x21, 0x6a, 0x22, 0x05, + 0xff, 0x65, 0x20, 0x09, + 0xff, 0x51, 0x36, 0x63, + 0xff, 0x37, 0xc8, 0x08, + 0xa1, 0x6a, 0x42, 0x43, + 0xff, 0x51, 0xc8, 0x08, + 0xb9, 0x6a, 0x42, 0x43, + 0xff, 0x90, 0xa4, 0x08, + 0xff, 0xba, 0x46, 0x73, + 0xff, 0xba, 0x20, 0x09, + 0xff, 0x65, 0xca, 0x18, + 0x00, 0x6c, 0x3a, 0x63, + 0xff, 0x90, 0xca, 0x0c, + 0xff, 0x6a, 0xca, 0x04, + 0x20, 0x36, 0x5a, 0x7b, + 0x00, 0x90, 0x2e, 0x5b, + 0xff, 0x65, 0x5a, 0x73, + 0xff, 0x52, 0x58, 0x73, + 0xff, 0xba, 0xcc, 0x08, + 0xff, 0x52, 0x20, 0x09, + 0xff, 0x66, 0x74, 0x09, + 0xff, 0x65, 0x20, 0x0d, + 0xff, 0xba, 0x7e, 0x0c, + 0x00, 0x6a, 0x86, 0x5c, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0x51, 0xe6, 0x43, + 0xff, 0x3f, 0xb4, 0x73, + 0xff, 0x6a, 0xa2, 0x00, + 0x00, 0x3f, 0x2e, 0x5b, + 0xff, 0x65, 0xb4, 0x73, + 0x20, 0x36, 0x6c, 0x00, + 0x20, 0xa0, 0x6e, 0x6b, + 0xff, 0xb9, 0xa2, 0x0c, + 0xff, 0x6a, 0xa2, 0x04, + 0xff, 0x65, 0xa4, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xda, 0x5b, + 0x01, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xd6, 0x01, + 0x80, 0xeb, 0x7a, 0x7b, + 0x01, 0x6a, 0xd6, 0x01, + 0x01, 0xe9, 0xa4, 0x34, + 0x88, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xda, 0x5b, + 0x01, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x0d, 0x6a, 0x26, 0x01, + 0x00, 0x65, 0x78, 0x5c, + 0xff, 0x99, 0xa4, 0x0c, + 0xff, 0x65, 0xa4, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xda, 0x5b, + 0x01, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x05, + 0x88, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xda, 0x5b, + 0x01, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x01, 0x6a, 0x26, 0x05, + 0x01, 0x65, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xaa, 0x7b, + 0xff, 0x6a, 0xdc, 0x0d, + 0xff, 0x65, 0x32, 0x09, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x78, 0x44, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0x6a, 0x70, 0x5b, + 0xff, 0x52, 0xa2, 0x0c, + 0x01, 0x0c, 0xba, 0x7b, + 0x04, 0x0c, 0xba, 0x6b, + 0xe0, 0x03, 0x06, 0x08, + 0xe0, 0x03, 0x7a, 0x0c, + 0xff, 0x8c, 0x10, 0x08, + 0xff, 0x8d, 0x12, 0x08, + 0xff, 0x8e, 0x14, 0x0c, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x0c, + 0x3d, 0x64, 0xa4, 0x28, + 0x55, 0x64, 0xc8, 0x28, + 0x00, 0x6c, 0xda, 0x18, + 0xff, 0x52, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0xff, 0x6a, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0x00, 0x6c, 0xda, 0x24, + 0xff, 0x65, 0xc8, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x41, 0x6a, 0xd6, 0x5b, + 0xff, 0x90, 0xe2, 0x09, + 0x20, 0x6a, 0xd0, 0x01, + 0x04, 0x35, 0xf8, 0x7b, + 0x1d, 0x6a, 0xdc, 0x01, + 0xdc, 0xee, 0xf4, 0x63, + 0x00, 0x65, 0x0e, 0x44, + 0x01, 0x6a, 0xdc, 0x01, + 0x20, 0xa0, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xfe, 0x7b, + 0x11, 0x6a, 0xdc, 0x01, + 0x50, 0xee, 0x02, 0x64, + 0x20, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xdc, 0x01, + 0x88, 0xee, 0x08, 0x64, + 0x19, 0x6a, 0xdc, 0x01, + 0xd8, 0xee, 0x0c, 0x64, + 0xff, 0x6a, 0xdc, 0x09, + 0x18, 0xee, 0x10, 0x6c, + 0xff, 0x6a, 0xd4, 0x0c, + 0x88, 0x6a, 0xcc, 0x00, + 0x41, 0x6a, 0xd6, 0x5b, + 0x20, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0xff, 0x35, 0x26, 0x09, + 0x04, 0x35, 0x3c, 0x6c, + 0xa0, 0x6a, 0xca, 0x00, + 0x20, 0x65, 0xc8, 0x18, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0x00, 0x65, 0x26, 0x64, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x78, 0x44, + 0xa0, 0x6a, 0xcc, 0x00, + 0xe8, 0x6a, 0xc8, 0x00, + 0x01, 0x94, 0x40, 0x6c, + 0x10, 0x94, 0x42, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x00, 0x65, 0x68, 0x5c, + 0x08, 0x64, 0xc8, 0x18, + 0x00, 0x8c, 0xca, 0x18, + 0x00, 0x65, 0x4a, 0x4c, + 0x00, 0x65, 0x40, 0x44, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x56, 0x6c, + 0x00, 0x65, 0x68, 0x5c, + 0x08, 0x64, 0xc8, 0x18, + 0x08, 0x64, 0x58, 0x64, + 0xff, 0x6a, 0xd4, 0x0c, + 0x00, 0x65, 0x78, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x0c, + 0x08, 0x94, 0x78, 0x7c, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x7c, 0x6c, + 0xff, 0x6a, 0xd4, 0x0c, + 0xff, 0x40, 0x74, 0x09, + 0xff, 0x90, 0x80, 0x08, + 0xff, 0x6a, 0x72, 0x05, + 0xff, 0x40, 0x94, 0x64, + 0xff, 0x3f, 0x8c, 0x64, + 0xff, 0x6a, 0xca, 0x04, + 0xff, 0x3f, 0x20, 0x09, + 0x01, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0xe6, 0x5b, + 0xff, 0xba, 0x7e, 0x0c, + 0xff, 0x40, 0x20, 0x09, + 0xff, 0xba, 0x80, 0x0c, + 0xff, 0x3f, 0x74, 0x09, + 0xff, 0x90, 0x7e, 0x0c, +}; + +static int aic7xxx_patch15_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch15_func(struct aic7xxx_host *p) +{ + return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0); +} + +static int aic7xxx_patch14_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch14_func(struct aic7xxx_host *p) +{ + return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0); +} + +static int aic7xxx_patch13_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch13_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_WIDE) != 0); +} + +static int aic7xxx_patch12_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch12_func(struct aic7xxx_host *p) +{ + return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0); +} + +static int aic7xxx_patch11_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch11_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_ULTRA2) == 0); +} + +static int aic7xxx_patch10_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch10_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_CMD_CHAN) == 0); +} + +static int aic7xxx_patch9_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch9_func(struct aic7xxx_host *p) +{ + return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); +} + +static int aic7xxx_patch8_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch8_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_ULTRA) != 0); +} + +static int aic7xxx_patch7_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch7_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_ULTRA2) != 0); +} + +static int aic7xxx_patch6_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch6_func(struct aic7xxx_host *p) +{ + return ((p->flags & AHC_PAGESCBS) == 0); +} + +static int aic7xxx_patch5_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch5_func(struct aic7xxx_host *p) +{ + return ((p->flags & AHC_PAGESCBS) != 0); +} + +static int aic7xxx_patch4_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch4_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_QUEUE_REGS) != 0); +} + +static int aic7xxx_patch3_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch3_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_TWIN) != 0); +} + +static int aic7xxx_patch2_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch2_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_QUEUE_REGS) == 0); +} + +static int aic7xxx_patch1_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch1_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_CMD_CHAN) != 0); +} + +static int aic7xxx_patch0_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch0_func(struct aic7xxx_host *p) +{ + return (0); +} + +struct sequencer_patch { + int (*patch_func)(struct aic7xxx_host *); + unsigned int begin :10, + skip_instr :10, + skip_patch :12; +} sequencer_patches[] = { + { aic7xxx_patch1_func, 3, 2, 1 }, + { aic7xxx_patch2_func, 7, 1, 1 }, + { aic7xxx_patch2_func, 8, 1, 1 }, + { aic7xxx_patch3_func, 11, 4, 1 }, + { aic7xxx_patch4_func, 16, 3, 2 }, + { aic7xxx_patch0_func, 19, 4, 1 }, + { aic7xxx_patch5_func, 23, 1, 1 }, + { aic7xxx_patch6_func, 26, 1, 1 }, + { aic7xxx_patch1_func, 29, 1, 2 }, + { aic7xxx_patch0_func, 30, 3, 1 }, + { aic7xxx_patch3_func, 39, 4, 1 }, + { aic7xxx_patch7_func, 43, 3, 2 }, + { aic7xxx_patch0_func, 46, 3, 1 }, + { aic7xxx_patch8_func, 52, 7, 1 }, + { aic7xxx_patch3_func, 60, 3, 1 }, + { aic7xxx_patch7_func, 63, 2, 1 }, + { aic7xxx_patch7_func, 102, 1, 2 }, + { aic7xxx_patch0_func, 103, 2, 1 }, + { aic7xxx_patch7_func, 107, 2, 1 }, + { aic7xxx_patch9_func, 109, 1, 1 }, + { aic7xxx_patch10_func, 110, 2, 1 }, + { aic7xxx_patch7_func, 113, 1, 2 }, + { aic7xxx_patch0_func, 114, 1, 1 }, + { aic7xxx_patch1_func, 118, 1, 1 }, + { aic7xxx_patch1_func, 121, 3, 3 }, + { aic7xxx_patch11_func, 123, 1, 1 }, + { aic7xxx_patch0_func, 124, 5, 1 }, + { aic7xxx_patch7_func, 132, 1, 1 }, + { aic7xxx_patch9_func, 133, 1, 1 }, + { aic7xxx_patch10_func, 134, 3, 1 }, + { aic7xxx_patch7_func, 137, 3, 2 }, + { aic7xxx_patch0_func, 140, 2, 1 }, + { aic7xxx_patch7_func, 142, 5, 2 }, + { aic7xxx_patch0_func, 147, 3, 1 }, + { aic7xxx_patch7_func, 150, 1, 2 }, + { aic7xxx_patch0_func, 151, 2, 1 }, + { aic7xxx_patch1_func, 153, 15, 4 }, + { aic7xxx_patch11_func, 166, 1, 2 }, + { aic7xxx_patch0_func, 167, 1, 1 }, + { aic7xxx_patch0_func, 168, 10, 1 }, + { aic7xxx_patch7_func, 181, 1, 2 }, + { aic7xxx_patch0_func, 182, 2, 1 }, + { aic7xxx_patch7_func, 184, 18, 1 }, + { aic7xxx_patch1_func, 202, 3, 3 }, + { aic7xxx_patch7_func, 204, 1, 1 }, + { aic7xxx_patch0_func, 205, 4, 1 }, + { aic7xxx_patch7_func, 210, 2, 1 }, + { aic7xxx_patch7_func, 215, 13, 3 }, + { aic7xxx_patch12_func, 218, 1, 1 }, + { aic7xxx_patch12_func, 219, 4, 1 }, + { aic7xxx_patch1_func, 229, 3, 3 }, + { aic7xxx_patch11_func, 231, 1, 1 }, + { aic7xxx_patch0_func, 232, 5, 1 }, + { aic7xxx_patch11_func, 237, 1, 2 }, + { aic7xxx_patch0_func, 238, 9, 1 }, + { aic7xxx_patch13_func, 254, 1, 2 }, + { aic7xxx_patch0_func, 255, 1, 1 }, + { aic7xxx_patch4_func, 316, 1, 2 }, + { aic7xxx_patch0_func, 317, 1, 1 }, + { aic7xxx_patch2_func, 320, 1, 1 }, + { aic7xxx_patch1_func, 330, 3, 2 }, + { aic7xxx_patch0_func, 333, 5, 1 }, + { aic7xxx_patch13_func, 341, 1, 2 }, + { aic7xxx_patch0_func, 342, 1, 1 }, + { aic7xxx_patch5_func, 347, 1, 1 }, + { aic7xxx_patch11_func, 389, 15, 2 }, + { aic7xxx_patch14_func, 402, 1, 1 }, + { aic7xxx_patch1_func, 441, 7, 2 }, + { aic7xxx_patch0_func, 448, 8, 1 }, + { aic7xxx_patch1_func, 457, 4, 2 }, + { aic7xxx_patch0_func, 461, 6, 1 }, + { aic7xxx_patch1_func, 467, 4, 2 }, + { aic7xxx_patch0_func, 471, 3, 1 }, + { aic7xxx_patch10_func, 481, 10, 1 }, + { aic7xxx_patch1_func, 500, 22, 5 }, + { aic7xxx_patch11_func, 508, 4, 1 }, + { aic7xxx_patch7_func, 512, 7, 3 }, + { aic7xxx_patch15_func, 512, 5, 2 }, + { aic7xxx_patch0_func, 517, 2, 1 }, + { aic7xxx_patch10_func, 522, 50, 3 }, + { aic7xxx_patch14_func, 543, 17, 2 }, + { aic7xxx_patch0_func, 560, 4, 1 }, + { aic7xxx_patch10_func, 572, 4, 1 }, + { aic7xxx_patch5_func, 576, 2, 1 }, + { aic7xxx_patch5_func, 579, 9, 1 }, + +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.2.18/drivers/scsi/aic7xxx.c Sun Mar 25 11:13:00 2001 +++ linux/drivers/scsi/aic7xxx.c Sun Mar 25 11:37:35 2001 @@ -246,11 +246,11 @@ #include "sd.h" #include "scsi.h" #include "hosts.h" -#include "aic7xxx.h" +#include "aic7xxx/aic7xxx.h" #include "aic7xxx/sequencer.h" #include "aic7xxx/scsi_message.h" -#include "aic7xxx_reg.h" +#include "aic7xxx/aic7xxx_reg.h" #include #include @@ -270,7 +270,7 @@ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.31" +#define AIC7XXX_C_VERSION "5.1.33" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -790,6 +790,7 @@ typedef enum { SCB_FREE = 0x0000, + SCB_DTR_SCB = 0x0001, SCB_WAITINGQ = 0x0002, SCB_ACTIVE = 0x0004, SCB_SENSE = 0x0008, @@ -896,6 +897,17 @@ AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3, } ahc_feature; +typedef enum { + AHC_BUG_NONE = 0x0000, + AHC_BUG_TMODE_WIDEODD = 0x0001, + AHC_BUG_AUTOFLUSH = 0x0002, + AHC_BUG_CACHETHEN = 0x0004, + AHC_BUG_CACHETHEN_DIS = 0x0008, + AHC_BUG_PCI_2_1_RETRY = 0x0010, + AHC_BUG_PCI_MWI = 0x0020, + AHC_BUG_SCBCHAN_UPLOAD = 0x0040, +} ahc_bugs; + struct aic7xxx_scb { struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ @@ -1004,7 +1016,6 @@ unsigned long isr_count; /* Interrupt count */ unsigned long spurious_int; scb_data_type *scb_data; - volatile unsigned short needdv; volatile unsigned short needppr; volatile unsigned short needsdtr; volatile unsigned short needwdtr; @@ -1032,10 +1043,9 @@ #define BUS_DEVICE_RESET_PENDING 0x02 #define DEVICE_RESET_DELAY 0x04 #define DEVICE_PRINT_DTR 0x08 -#define DEVICE_PARITY_ERROR 0x10 -#define DEVICE_WAS_BUSY 0x20 -#define DEVICE_SCSI_3 0x40 -#define DEVICE_SCANNED 0x80 +#define DEVICE_WAS_BUSY 0x10 +#define DEVICE_SCSI_3 0x20 +#define DEVICE_DTR_SCANNED 0x40 volatile unsigned char dev_flags[MAX_TARGETS]; volatile unsigned char dev_active_cmds[MAX_TARGETS]; volatile unsigned char dev_temp_queue_depth[MAX_TARGETS]; @@ -1051,10 +1061,6 @@ #endif - Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS]; - - unsigned int dev_checksum[MAX_TARGETS]; - unsigned char dev_last_queue_full[MAX_TARGETS]; unsigned char dev_last_queue_full_count[MAX_TARGETS]; unsigned char dev_max_queue_depth[MAX_TARGETS]; @@ -1111,6 +1117,7 @@ int host_no; /* SCSI host number */ unsigned long mbase; /* I/O memory address */ ahc_chip chip; /* chip type */ + ahc_bugs bugs; /* hardware bugs this chip has */ /* * Statistics Kept: @@ -1712,7 +1719,7 @@ * prototype, our code has to be ordered that way, it's a left-over from * the original driver days.....I should fix it some time DL). */ -#include "aic7xxx_seq.c" +#include "aic7xxx/aic7xxx_seq.c" /*+F************************************************************************* * Function: @@ -2876,138 +2883,98 @@ { p->flags &= ~AHC_ABORT_PENDING; } - if (scb->flags & SCB_RESET) + if (scb->flags & (SCB_RESET|SCB_ABORT)) { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); + cmd->result |= (DID_RESET << 16); } - else if (scb->flags & SCB_ABORT) - { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); - } - else if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) + + if (!(p->dev_flags[tindex] & DEVICE_PRESENT)) { if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) ) { - char *buffer; - + p->dev_flags[tindex] |= DEVICE_PRESENT; - if(cmd->use_sg) - { - struct scatterlist *sg; - - sg = (struct scatterlist *)cmd->request_buffer; - buffer = (char *)sg[0].address; - } - else - { - buffer = (char *)cmd->request_buffer; - } #define WIDE_INQUIRY_BITS 0x60 #define SYNC_INQUIRY_BITS 0x10 #define SCSI_VERSION_BITS 0x07 #define SCSI_DT_BIT 0x04 - if ( (buffer[7] & WIDE_INQUIRY_BITS) && - (p->features & AHC_WIDE) ) - { - p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width = p->transinfo[tindex].user_width; - } - else - { - p->needwdtr &= ~(1<needwdtr_copy &= ~(1<target, cmd->channel, cmd->lun, - MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | - AHC_TRANS_GOAL | - AHC_TRANS_CUR) ); - unpause_sequencer(p, FALSE); - } - if ( (buffer[7] & SYNC_INQUIRY_BITS) && - p->transinfo[tindex].user_offset ) - { - p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; - if (p->features & AHC_ULTRA2) - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) { + char *buffer; + + if(cmd->use_sg) + { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + buffer = (char *)sg[0].address; + } + else + { + buffer = (char *)cmd->request_buffer; + } + + + if ( (buffer[7] & WIDE_INQUIRY_BITS) && + (p->features & AHC_WIDE) ) + { + p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width = p->transinfo[tindex].user_width; + } else - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) || - (buffer[56] & SCSI_DT_BIT) || - (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && - (p->transinfo[tindex].user_period <= 9) && - (p->transinfo[tindex].user_options) ) { - p->needppr |= (1<needppr_copy |= (1<needsdtr &= ~(1<needsdtr_copy &= ~(1<needwdtr &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] |= DEVICE_SCSI_3; + pause_sequencer(p); + aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun, + MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | + AHC_TRANS_GOAL | + AHC_TRANS_CUR) ); + unpause_sequencer(p, FALSE); } - else + if ( (buffer[7] & SYNC_INQUIRY_BITS) && + p->transinfo[tindex].user_offset ) { - p->needsdtr |= (1<needsdtr_copy |= (1<transinfo[tindex].goal_period = - MAX(10, p->transinfo[tindex].goal_period); - p->transinfo[tindex].goal_options = 0; + p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; + if (p->features & AHC_ULTRA2) + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + else + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) || + (buffer[56] & SCSI_DT_BIT) || + (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && + (p->transinfo[tindex].user_period <= 9) && + (p->transinfo[tindex].user_options) ) + { + p->needppr |= (1<needppr_copy |= (1<needsdtr &= ~(1<needsdtr_copy &= ~(1<needwdtr &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] |= DEVICE_SCSI_3; + } + else + { + p->needsdtr |= (1<needsdtr_copy |= (1<transinfo[tindex].goal_period = + MAX(10, p->transinfo[tindex].goal_period); + p->transinfo[tindex].goal_options = 0; + } } - } - else - { - p->needsdtr &= ~(1<needsdtr_copy &= ~(1<transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_options = 0; - } - /* - * This is needed to work around a sequencer bug for now. Regardless - * of the controller in use, if we have a Quantum drive, we need to - * limit the speed to 80MByte/sec. As soon as I get a fixed version - * of the sequencer, this code will get yanked. - */ - if(!strncmp(buffer + 8, "QUANTUM", 7) && - p->transinfo[tindex].goal_options ) - { - p->transinfo[tindex].goal_period = - MAX(p->transinfo[tindex].goal_period, 10); - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<needppr_copy &= ~(1<needsdtr |= (1<needsdtr_copy |= (1<needwdtr |= (1<needwdtr_copy |= (1<dev_dtr_cmnd[tindex] == cmd) { - unsigned int checksum = 0; - int *ibuffer; - int i=0; - - ibuffer = (int *)buffer; - for( i = 0; i < (cmd->request_bufflen >> 2); i++) + else { - checksum += ibuffer[i]; + p->needsdtr &= ~(1<needsdtr_copy &= ~(1<transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_options = 0; } - p->dev_checksum[tindex] = checksum; - p->dev_flags[tindex] |= DEVICE_SCANNED; + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED; p->dev_flags[tindex] |= DEVICE_PRINT_DTR; } #undef WIDE_INQUIRY_BITS @@ -3016,7 +2983,8 @@ #undef SCSI_DT_BIT } } - else if ((scb->flags & SCB_MSGOUT_BITS) != 0) + + if ((scb->flags & SCB_MSGOUT_BITS) != 0) { unsigned short mask; int message_error = FALSE; @@ -3036,7 +3004,6 @@ if (scb->flags & SCB_MSGOUT_WDTR) { - p->dtr_pending &= ~mask; if (message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3055,7 +3022,6 @@ } if (scb->flags & SCB_MSGOUT_SDTR) { - p->dtr_pending &= ~mask; if (message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3075,7 +3041,6 @@ } if (scb->flags & SCB_MSGOUT_PPR) { - p->dtr_pending &= ~mask; if(message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3100,6 +3065,7 @@ } } } + queue_depth = p->dev_temp_queue_depth[tindex]; if (queue_depth >= p->dev_active_cmds[tindex]) { @@ -3133,9 +3099,18 @@ } } } - if ( !(scb->tag_action) && (p->tagenable & (1<tag_action)) + { + aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, + /* unbusy */ TRUE); + if (p->tagenable & (1<dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; + } + } + if(scb->flags & SCB_DTR_SCB) { - p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; + p->dtr_pending &= ~(1 << tindex); } p->dev_active_cmds[tindex]--; p->activescbs--; @@ -3244,6 +3219,14 @@ printk(INFO_LEAD "Aborting scb %d\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag); found++; + /* + * Clear any residual information since the normal aic7xxx_done() path + * doesn't touch the residuals. + */ + scb->hscb->residual_SG_segment_count = 0; + scb->hscb->residual_data_count[0] = 0; + scb->hscb->residual_data_count[1] = 0; + scb->hscb->residual_data_count[2] = 0; aic7xxx_done(p, scb); } } @@ -3456,8 +3439,22 @@ active_scb = aic_inb(p, SCBPTR); if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) + { printk(INFO_LEAD "Reset device, active_scb %d\n", p->host_no, channel, target, lun, active_scb); + printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE " + "0x%x\n", + p->host_no, channel, target, lun, aic_inb(p, SCB_TAG), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, LASTPHASE)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", + p->host_no, channel, target, lun, + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI)); + printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", + p->host_no, channel, target, lun, aic_inb(p, SSTAT0), + aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); + } /* * Deal with the busy target and linked next issues. */ @@ -3501,11 +3498,11 @@ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) printk(INFO_LEAD "Cleaning up status information " "and delayed_scbs.\n", p->host_no, channel, i, lun); - p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR); + p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING; if ( tag == SCB_LIST_NULL ) { p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY; - p->dev_expires[i] = jiffies + (4 * HZ); + p->dev_expires[i] = jiffies + (1 * HZ); p->dev_timer_active |= (0x01 << i); p->dev_last_queue_full_count[i] = 0; p->dev_last_queue_full[i] = 0; @@ -3550,7 +3547,7 @@ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; } } - if ( j > (p->scb_data->maxscbs + 1) ) + if ( j > (p->scb_data->numscbs + 1) ) { if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) printk(WARN_LEAD "Yikes!! There's a loop in the " @@ -3611,7 +3608,7 @@ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; } } - if ( j > (p->scb_data->maxscbs + 1) ) + if ( j > (p->scb_data->numscbs + 1) ) { if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) printk(WARN_LEAD "Yikes!! There's a loop in the " @@ -4375,11 +4372,25 @@ if (actual < cmd->underflow) { if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) + { printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG " "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow, (cmd->request.cmd == WRITE) ? "wrote" : "read", actual, hscb->residual_SG_segment_count); + printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb), + hscb->target_status); + } + /* + * In 2.4, only send back the residual information, don't flag this + * as an error. Before 2.4 we had to flag this as an error because + * the mid layer didn't check residual data counts to see if the + * command needs retried. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + cmd->resid = scb->sg_length - actual; +#else aic7xxx_error(cmd) = DID_RETRY_COMMAND; +#endif aic7xxx_status(cmd) = hscb->target_status; } } @@ -4698,7 +4709,6 @@ */ p->needwdtr &= ~target_mask; p->needwdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; scb->flags &= ~SCB_MSGOUT_BITS; aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR)); @@ -4718,8 +4728,7 @@ */ p->needsdtr &= ~target_mask; p->needsdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; - scb->flags &= ~SCB_MSGOUT_SDTR; + scb->flags &= ~SCB_MSGOUT_BITS; aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL)); if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) @@ -4852,6 +4861,8 @@ aic7xxx_error(cmd) = DID_OK; break; } /* first time sense, no errors */ + printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning " + "an error.\n", p->host_no, CTL_OF_SCB(scb)); aic7xxx_error(cmd) = DID_ERROR; scb->flags &= ~SCB_SENSE; break; @@ -5214,12 +5225,21 @@ printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n", (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't", scb->sg_length, scb->sg_count); - for (i = 0; i < scb->sg_count; i++) + printk(KERN_WARNING " Raw SCSI Command: 0x"); + for (i = 0; i < scb->hscb->SCSI_cmd_length; i++) + { + printk("%02x ", scb->cmd->cmnd[i]); + } + printk("\n"); + if(aic7xxx_verbose > 0xffff) { - printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", + for (i = 0; i < scb->sg_count; i++) + { + printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", i, le32_to_cpu(scb->sg_list[i].address), le32_to_cpu(scb->sg_list[i].length) ); + } } aic7xxx_error(scb->cmd) = DID_ERROR; } @@ -5234,7 +5254,7 @@ unsigned char resid_sgcnt, index; unsigned char scb_index = aic_inb(p, SCB_TAG); unsigned int cur_addr, resid_dcnt; - unsigned int native_addr, native_length; + unsigned int native_addr, native_length, sg_addr; int i; if(scb_index > p->scb_data->numscbs) @@ -5254,6 +5274,9 @@ scb->flags, (unsigned int)scb->cmd); break; } + if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data " + "pointer.\n", p->host_no, CTL_OF_SCB(scb)); /* * We have a valid scb to use on this WIDE_RESIDUE message, so @@ -5266,132 +5289,87 @@ */ cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) | (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24); + sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) | + (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24); resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | (aic_inb(p, SCB_RESID_DCNT + 2) << 16); - index = scb->sg_count - (resid_sgcnt + 1); + index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1); native_addr = le32_to_cpu(scb->sg_list[index].address); native_length = le32_to_cpu(scb->sg_list[index].length); /* - * Make sure this is a valid sg_seg for the given pointer + * If resid_dcnt == native_length, then we just loaded this SG + * segment and we need to back it up one... */ - if(cur_addr < native_addr || - cur_addr > (native_addr + native_length + 1)) - { - printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n", - p->host_no, CTL_OF_SCB(scb), cur_addr); - if(index > 0) - printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index - 1].address), - le32_to_cpu(scb->sg_list[index - 1].length)); - printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n", - p->host_no, CTL_OF_SCB(scb), - native_addr, native_length); - if(resid_sgcnt > 1) - printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index + 1].address), - le32_to_cpu(scb->sg_list[index + 1].length)); - printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n", - p->host_no, CTL_OF_SCB(scb), - cur_addr, resid_dcnt); - break; - } - - if( (resid_sgcnt == 0) && - ((resid_dcnt == 0) || (resid_dcnt == 0xffffff))) + if(resid_dcnt == native_length) { - /* - * We are at the end of the transfer and this is about a byte - * we ignored already (because the sequencer knew this was - * the last segment and set the adapter to ignore any wide - * residue bytes that might come through, which is only done - * on the last scatter gather segment of transfers). - */ - break; - } - else if(cur_addr == native_addr) - { - /* - * If our current address matches the sg_seg->address then we - * have to back up the sg array to the previous segment and set - * it up to have only one byte of transfer left to go. - */ if(index == 0) { - printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been " - "transferred.\n", p->host_no, CTL_OF_SCB(scb)); + /* + * Oops, this isn't right, we can't back up to before the + * beginning. This must be a bogus message, ignore it. + */ break; } - resid_sgcnt++; - index--; - cur_addr = le32_to_cpu(scb->sg_list[index].address) + - le32_to_cpu(scb->sg_list[index].length) - 1; - native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8) - | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24); - native_addr -= SG_SIZEOF; - aic_outb(p, resid_sgcnt, SG_COUNT); - aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); - aic_outb(p, native_addr & 0xff, SG_NEXT); - aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1); - aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2); - aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3); - aic_outb(p, 1, SCB_RESID_DCNT); - aic_outb(p, 0, SCB_RESID_DCNT + 1); - aic_outb(p, 0, SCB_RESID_DCNT + 2); - aic_outb(p, 1, HCNT); - aic_outb(p, 0, HCNT + 1); - aic_outb(p, 0, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + resid_dcnt = 1; + resid_sgcnt += 1; + native_addr = le32_to_cpu(scb->sg_list[index - 1].address); + native_length = le32_to_cpu(scb->sg_list[index - 1].length); + cur_addr = native_addr + (native_length - 1); + sg_addr -= sizeof(struct hw_scatterlist); } else { /* - * Back the data pointer up by one and add one to the remaining - * byte count. Then store that in the HCNT and HADDR registers. + * resid_dcnt != native_length, so we are in the middle of a SG + * element. Back it up one byte and leave the rest alone. */ - cur_addr--; - resid_dcnt++; - aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); - aic_outb(p, resid_dcnt & 0xff, HCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + resid_dcnt += 1; + cur_addr -= 1; } + + /* + * Output the new addresses and counts to the right places on the + * card. + */ + aic_outb(p, resid_sgcnt, SG_COUNT); + aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); + aic_outb(p, sg_addr & 0xff, SG_COUNT + 1); + aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2); + aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3); + aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4); + aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); + /* - * The sequencer actually wants to find the new address and byte - * count in the SHCNT and SHADDR register sets. These registers - * are a shadow of the regular HCNT and HADDR registers. On the - * Ultra2 controllers, these registers are read only and the way - * we have to set their values is to put the values we want into - * the HCNT and HADDR registers and then output PRELOADEN into - * the DFCNTRL register which causes the card to latch the current - * values in the HADDR and HCNT registers and drop it through to - * the shadow registers. On older cards we copy them directly - * across by hand. + * The sequencer actually wants to find the new address + * in the SHADDR register set. On the Ultra2 and later controllers + * this register set is readonly. In order to get the right number + * into the register, you actually have to enter it in HADDR and then + * use the PRELOADEN bit of DFCNTRL to drop it through from the + * HADDR register to the SHADDR register. On non-Ultra2 controllers, + * we simply write it direct. */ if(p->features & AHC_ULTRA2) { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - i=0; + /* + * We might as well be accurate and drop both the resid_dcnt and + * cur_addr into HCNT and HADDR and have both of them drop + * through to the shadow layer together. + */ + aic_outb(p, resid_dcnt & 0xff, HCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); + aic_outb(p, cur_addr & 0xff, HADDR); + aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL); udelay(1); - while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) - { - udelay(1); - } aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); i=0; - udelay(1); while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) { udelay(1); @@ -5399,9 +5377,6 @@ } else { - aic_outb(p, resid_dcnt & 0xff, STCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); aic_outb(p, cur_addr & 0xff, SHADDR); aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); @@ -5410,15 +5385,82 @@ } break; - -#if AIC7XXX_NOT_YET - case TRACEPOINT: + case SEQ_SG_FIXUP: + { + unsigned char scb_index, tmp; + int sg_addr, sg_length; + + scb_index = aic_inb(p, SCB_TAG); + + if(scb_index > p->scb_data->numscbs) { - printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, - channel, target, lun); + printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n", + p->host_no, -1, -1, -1); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, -1, -1, -1, + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR), + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); + /* + * XXX: Add error handling here + */ + break; } - break; + scb = p->scb_data->scb_array[scb_index]; + if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) + { + printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x " + "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb), + scb->flags, (unsigned int)scb->cmd); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR), + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); + break; + } + if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no, + CTL_OF_SCB(scb)); + /* + * Advance the SG pointer to the next element in the list + */ + tmp = aic_inb(p, SG_NEXT); + tmp += SG_SIZEOF; + aic_outb(p, tmp, SG_NEXT); + if( tmp < SG_SIZEOF ) + aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1); + tmp = aic_inb(p, SG_COUNT) - 1; + aic_outb(p, tmp, SG_COUNT); + sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address); + sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length); + /* + * Now stuff the element we just advanced past down onto the + * card so it can be stored in the residual area. + */ + aic_outb(p, sg_addr & 0xff, HADDR); + aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3); + aic_outb(p, sg_length & 0xff, HCNT); + aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1); + aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2); + aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR); + aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); + while(aic_inb(p, SSTAT0) & SDONE) udelay(1); + while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL); + } + break; +#if AIC7XXX_NOT_YET case TRACEPOINT2: { printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, @@ -5463,6 +5505,10 @@ unsigned char target_scsirate, tindex; unsigned short target_mask; unsigned char target, channel, lun; + unsigned char bus_width, new_bus_width; + unsigned char trans_options, new_trans_options; + unsigned int period, new_period, offset, new_offset, maxsync; + struct aic7xxx_syncrate *syncrate; target = scb->cmd->target; channel = scb->cmd->channel; @@ -5486,6 +5532,35 @@ } /* + * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when + * using the SDTR messages. We need the PPR messages to enable the + * higher speeds that include things like Dual Edge clocking. + */ + if (p->features & AHC_ULTRA2) + { + if ( (aic_inb(p, SBLKCTL) & ENAB40) && + !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) + { + if (p->features & AHC_ULTRA3) + maxsync = AHC_SYNCRATE_ULTRA3; + else + maxsync = AHC_SYNCRATE_ULTRA2; + } + else + { + maxsync = AHC_SYNCRATE_ULTRA; + } + } + else if (p->features & AHC_ULTRA) + { + maxsync = AHC_SYNCRATE_ULTRA; + } + else + { + maxsync = AHC_SYNCRATE_FAST; + } + + /* * Just accept the length byte outright and perform * more checking once we know the message type. */ @@ -5496,9 +5571,6 @@ { case MSG_EXT_SDTR: { - unsigned int period, offset; - unsigned char maxsync, saved_offset, options; - struct aic7xxx_syncrate *syncrate; if (p->msg_buf[1] != MSG_EXT_SDTR_LEN) { @@ -5511,35 +5583,18 @@ break; } - period = p->msg_buf[3]; - saved_offset = offset = p->msg_buf[4]; - options = 0; + period = new_period = p->msg_buf[3]; + offset = new_offset = p->msg_buf[4]; + trans_options = new_trans_options = 0; + bus_width = new_bus_width = target_scsirate & WIDEXFER; /* - * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when - * using the SDTR messages. We need the PPR messages to enable the - * higher speeds that include things like Dual Edge clocking. + * If our current max syncrate is in the Ultra3 range, bump it back + * down to Ultra2 since we can't negotiate DT transfers using SDTR */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - maxsync = AHC_SYNCRATE_ULTRA; - } - else - { - maxsync = AHC_SYNCRATE_FAST; - } + if(maxsync == AHC_SYNCRATE_ULTRA3) + maxsync = AHC_SYNCRATE_ULTRA2; + /* * We might have a device that is starting negotiation with us * before we can start up negotiation with it....be prepared to @@ -5549,88 +5604,116 @@ if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) { - if (!(p->dev_flags[tindex] & DEVICE_SCANNED) && - !(p->needsdtr_copy & target_mask) && - (p->transinfo[tindex].user_offset) ) + if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) { /* - * Not only is the device starting this up, but it also hasn't - * been scanned yet, so this would likely be our TUR or our - * INQUIRY command at scan time, so we need to use the - * settings from the SEEPROM if they existed. Of course, even - * if we didn't find a SEEPROM, we stuffed default values into - * the user settings anyway, so use those in all cases. + * We shouldn't get here unless this is a narrow drive, wide + * devices should trigger this same section of code in the WDTR + * handler first instead. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - if(p->features & AHC_ULTRA2) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - } - else if (p->transinfo[tindex].cur_width) + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT; + p->transinfo[tindex].goal_options = 0; + if(p->transinfo[tindex].user_offset) { - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + p->needsdtr_copy |= target_mask; + p->transinfo[tindex].goal_period = + MAX(10,p->transinfo[tindex].user_period); + if(p->features & AHC_ULTRA2) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + } + else + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + } } else { - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + p->needsdtr_copy &= ~target_mask; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; } - p->needsdtr_copy |= target_mask; + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; + } + else if ((p->needsdtr_copy & target_mask) == 0) + { + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a WDTR with this target (for whatever reason), + * so reject this incoming WDTR + */ + reject = TRUE; + break; } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Received pre-emptive SDTR message from " "target.\n", p->host_no, CTL_OF_SCB(scb)); } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; + /* + * Validate the values the device passed to us against our SEEPROM + * settings. We don't have to do this if we aren't replying since + * the device isn't allowed to send values greater than the ones + * we first sent to it. + */ + new_period = MAX(period, p->transinfo[tindex].goal_period); + new_offset = MIN(offset, p->transinfo[tindex].goal_offset); } - - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options); - aic7xxx_validate_offset(p, syncrate, &offset, - target_scsirate & WIDEXFER); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + + /* + * Use our new_period, new_offset, bus_width, and card options + * to determine the actual syncrate settings + */ + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width); /* - * Did we drop to async? Or are we sending a reply? If we are, - * then we have to make sure that the reply value reflects the proper - * settings so we need to set the goal values according to what - * we need to send. + * Did we drop to async? If so, send a reply regardless of whether + * or not we initiated this negotiation. */ - if ( (offset != saved_offset) || - ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) ) + if ((new_offset == 0) && (new_offset != offset)) { - aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset, - options, AHC_TRANS_GOAL|AHC_TRANS_QUITE); + p->needsdtr_copy &= ~target_mask; + reply = TRUE; } /* - * Did we start this, if not, or if we went to low and had to + * Did we start this, if not, or if we went too low and had to * go async, then send an SDTR back to the target */ - p->needsdtr &= ~target_mask; - p->dtr_pending &= ~target_mask; - if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) || - (offset != saved_offset) ) + if(reply) { - reply = TRUE; - p->dtr_pending |= target_mask; + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, trans_options, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_SDTR; aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); } + else + { + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, trans_options, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + p->needsdtr &= ~target_mask; + } done = TRUE; break; } case MSG_EXT_WDTR: { - unsigned char bus_width; if (p->msg_buf[1] != MSG_EXT_WDTR_LEN) { @@ -5643,7 +5726,8 @@ break; } - bus_width = p->msg_buf[3]; + bus_width = new_bus_width = p->msg_buf[3]; + if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) == (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) ) { @@ -5662,7 +5746,7 @@ } /* We fall through on purpose */ case MSG_EXT_WDTR_BUS_8_BIT: { - bus_width = MSG_EXT_WDTR_BUS_8_BIT; + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT; p->needwdtr_copy &= ~target_mask; break; } @@ -5671,29 +5755,40 @@ break; } } - p->dtr_pending &= ~target_mask; p->needwdtr &= ~target_mask; + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); } else { - if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) ) + if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) ) { /* * Well, we now know the WDTR and SYNC caps of this device since * it contacted us first, mark it as such and copy the user stuff * over to the goal stuff. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; + if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width ) + { + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT; + p->needwdtr_copy |= target_mask; + } + + /* + * Devices that support DT transfers don't start WDTR requests + */ + p->transinfo[tindex].goal_options = 0; + if(p->transinfo[tindex].user_offset) { + p->needsdtr_copy |= target_mask; + p->transinfo[tindex].goal_period = + MAX(10,p->transinfo[tindex].user_period); if(p->features & AHC_ULTRA2) { p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; } - else if( p->transinfo[tindex].user_width && - (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE ) + else if( p->transinfo[tindex].goal_width ) { p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; } @@ -5701,48 +5796,76 @@ { p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; } + } else { + p->needsdtr_copy &= ~target_mask; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->needwdtr_copy |= target_mask; - p->needsdtr_copy |= target_mask; + + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; } - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + else if ((p->needwdtr_copy & target_mask) == 0) { - printk(INFO_LEAD "Received pre-emptive WDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a WDTR with this target (for whatever reason), + * so reject this incoming WDTR + */ + reject = TRUE; + break; + } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Received pre-emptive WDTR message from " + "target.\n", p->host_no, CTL_OF_SCB(scb)); + } switch(bus_width) { - default: + case MSG_EXT_WDTR_BUS_16_BIT: { if ( (p->features & AHC_WIDE) && (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) ) { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; + new_bus_width = MSG_EXT_WDTR_BUS_16_BIT; break; } } /* Fall through if we aren't a wide card */ + default: case MSG_EXT_WDTR_BUS_8_BIT: { p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); + new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; } } - reply = TRUE; scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_WDTR; p->needwdtr &= ~target_mask; - p->dtr_pending |= target_mask; + if((p->dtr_pending & target_mask) == 0) + { + /* there is no other command with SCB_DTR_SCB already set that will + * trigger the release of the dtr_pending bit. Both set the bit + * and set scb->flags |= SCB_DTR_SCB + */ + p->dtr_pending |= target_mask; + scb->flags |= SCB_DTR_SCB; + } aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); } - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); /* * By virtue of the SCSI spec, a WDTR message negates any existing @@ -5759,10 +5882,6 @@ } case MSG_EXT_PPR: { - unsigned char bus_width, trans_options, new_trans_options; - unsigned int period, offset; - unsigned char maxsync, saved_offset; - struct aic7xxx_syncrate *syncrate; if (p->msg_buf[1] != MSG_EXT_PPR_LEN) { @@ -5775,9 +5894,9 @@ break; } - period = p->msg_buf[3]; - offset = saved_offset = p->msg_buf[5]; - bus_width = p->msg_buf[6]; + period = new_period = p->msg_buf[3]; + offset = new_offset = p->msg_buf[5]; + bus_width = new_bus_width = p->msg_buf[6]; trans_options = new_trans_options = p->msg_buf[7] & 0xf; if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) @@ -5787,22 +5906,6 @@ trans_options); } - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - if(p->features & AHC_ULTRA3) - { - maxsync = AHC_SYNCRATE_ULTRA3; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } /* * We might have a device that is starting negotiation with us * before we can start up negotiation with it....be prepared to @@ -5811,13 +5914,22 @@ */ if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) ) - { - reply = TRUE; - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_PPR; - p->dev_flags[tindex] |= DEVICE_SCSI_3; - if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) - { + { + /* Have we scanned the device yet? */ + if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) + { + /* The device is electing to use PPR messages, so we will too until + * we know better */ + p->needppr |= target_mask; + p->needppr_copy |= target_mask; + p->needsdtr &= ~target_mask; + p->needsdtr_copy &= ~target_mask; + p->needwdtr &= ~target_mask; + p->needwdtr_copy &= ~target_mask; + + /* We know the device is SCSI-3 compliant due to PPR */ + p->dev_flags[tindex] |= DEVICE_SCSI_3; + /* * Not only is the device starting this up, but it also hasn't * been scanned yet, so this would likely be our TUR or our @@ -5826,15 +5938,19 @@ * if we didn't find a SEEPROM, we stuffed default values into * the user settings anyway, so use those in all cases. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_width = + p->transinfo[tindex].user_width; if(p->transinfo[tindex].user_offset) { + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; if(p->features & AHC_ULTRA2) { p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; } - else if( p->transinfo[tindex].user_width && + else if( p->transinfo[tindex].goal_width && (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE ) { @@ -5845,117 +5961,142 @@ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; } } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; + else + { + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_options = 0; + } + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; + } + else if ((p->needppr_copy & target_mask) == 0) + { + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a PPR with this target (for whatever reason), + * so reject this incoming PPR + */ + reject = TRUE; + break; } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Received pre-emptive PPR message from " "target.\n", p->host_no, CTL_OF_SCB(scb)); } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; - if ( p->transinfo[tindex].goal_options == 0 ) - new_trans_options = 0; - switch(bus_width) + + } + + switch(bus_width) + { + case MSG_EXT_WDTR_BUS_16_BIT: { - default: - { - if ( (p->features & AHC_WIDE) && - (p->transinfo[tindex].goal_width == - MSG_EXT_WDTR_BUS_16_BIT) ) - { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - } /* Fall through if we aren't a wide card */ - case MSG_EXT_WDTR_BUS_8_BIT: + if ( (p->transinfo[tindex].goal_width == + MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE) { - p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); break; } } - if ( (p->transinfo[tindex].goal_period > 9) || - (p->transinfo[tindex].goal_options == 0) ) + default: { - scb->flags &= ~SCB_MSGOUT_BITS; - reject = TRUE; - reply = FALSE; - p->needppr &= ~(1 << tindex); - p->needppr_copy &= ~(1 << tindex); - if ( p->transinfo[tindex].goal_offset ) - { - p->needsdtr |= (1 << tindex); - p->needsdtr_copy |= (1 << tindex); - } - if ( p->transinfo[tindex].goal_width ) - { - p->needwdtr |= (1 << tindex); - p->needwdtr_copy |= (1 << tindex); + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || + (aic7xxx_verbose > 0xffff)) ) + { + reply = TRUE; + printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", + p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); } + } /* We fall through on purpose */ + case MSG_EXT_WDTR_BUS_8_BIT: + { + /* + * According to the spec, if we aren't wide, we also can't be + * Dual Edge so clear the options byte + */ + new_trans_options = 0; + new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; } } + + if(reply) + { + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, new_trans_options, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + } else { - switch(bus_width) + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, new_trans_options, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + } + + /* + * As it turns out, if we don't *have* to have PPR messages, then + * configure ourselves not to use them since that makes some + * external drive chassis work (those chassis can't parse PPR + * messages and they mangle the SCSI bus until you send a WDTR + * and SDTR that they can understand). + */ + if(new_trans_options == 0) + { + p->needppr &= ~target_mask; + p->needppr_copy &= ~target_mask; + if(new_offset) { - default: - { - reject = TRUE; - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - /* - * According to the spec, if we aren't wide, we also can't be - * Dual Edge so clear the options byte - */ - new_trans_options = 0; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - case MSG_EXT_WDTR_BUS_16_BIT: - { - break; - } + p->needsdtr |= target_mask; + p->needsdtr_copy |= target_mask; + } + if (new_bus_width) + { + p->needwdtr |= target_mask; + p->needwdtr_copy |= target_mask; } } - if ( !reject ) + if((new_offset == 0) && (offset != 0)) { - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &offset, bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, new_trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + /* + * Oops, the syncrate went to low for this card and we fell off + * to async (should never happen with a device that uses PPR + * messages, but have to be complete) + */ + reply = TRUE; } - p->dtr_pending &= ~target_mask; - p->needppr &= ~target_mask; if(reply) { - p->dtr_pending |= target_mask; scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_PPR; aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); } + else + { + p->needppr &= ~target_mask; + } done = TRUE; break; } @@ -6193,16 +6334,14 @@ printerror = 0; } } - if ( (scb != NULL) && - (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) ) + if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) { /* - * This might be a SCSI-3 device that is dropping the bus due to - * errors and signalling that we should reduce the transfer speed. - * All we have to do is complete this command (since it's a negotiation - * command already) and the checksum routine should flag an error and - * reduce the speed setting and renegotiate. We call the reset routing - * just to clean out the hardware from this scb. + * Hmmm...error during a negotiation command. Either we have a + * borken bus, or the device doesn't like our negotiation message. + * Since we check the INQUIRY data of a device before sending it + * negotiation messages, assume the bus is borken for whatever + * reason. Complete the command. */ printerror = 0; aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag); @@ -6334,19 +6473,6 @@ cmd->result = 0; scb = NULL; } - else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) - { - /* - * Turn off the needsdtr, needwdtr, and needppr bits since this device - * doesn't seem to exist. - */ - p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - } } /* * Keep the sequencer from trying to restart any selections @@ -6469,7 +6595,6 @@ } } else if( (lastphase == P_MESGOUT) && - (cmd == p->dev_dtr_cmnd[tindex]) && (scb->flags & SCB_MSGOUT_PPR) ) { /* @@ -6488,7 +6613,6 @@ aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0, 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); p->transinfo[tindex].goal_options = 0; - p->dtr_pending &= ~(1 << tindex); scb->flags &= ~SCB_MSGOUT_BITS; if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) { @@ -6511,87 +6635,6 @@ } scb = NULL; } - else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR) - { - struct aic7xxx_syncrate *syncrate; - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - /* - * oops, we had a failure, lower the transfer rate and try again. It's - * worth noting here that it might be wise to also check for typical - * wide setting on narrow cable type problems and try disabling wide - * instead of slowing down if those exist. That's hard to do with simple - * checksums though. - */ - printk(WARN_LEAD "Parity error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] &= ~DEVICE_PARITY_ERROR; - } - else - { - p->dev_flags[tindex] |= DEVICE_PARITY_ERROR; - } /* * We've set the hardware to assert ATN if we get a parity @@ -6860,34 +6903,11 @@ else if (scb->flags & SCB_SENSE) { char *buffer = &scb->cmd->sense_buffer[0]; - if (scb->cmd == p->dev_dtr_cmnd[tindex]) - { - struct aic7xxx_scb *old_scb; - /* - * We have valid sense data, send it back immediately. - */ - old_scb = p->scb_data->scb_array[scb->cmd->next->tag]; - *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer; - old_scb->hscb->target_status = scb->hscb->target_status; - old_scb->cmd->result = scb->hscb->target_status; - old_scb->cmd->result |= (DID_ERROR << 16); - aic7xxx_status(old_scb->cmd) = scb->hscb->target_status; - scbq_remove(&p->waiting_scbs, old_scb); - scbq_remove(&p->delayed_scbs[tindex], old_scb); - scb->cmd->next = NULL; - aic7xxx_done(p, scb); - aic7xxx_done(p, old_scb); - continue; - } - else if (buffer[12] == 0x47 || buffer[12] == 0x54) + + if (buffer[12] == 0x47 || buffer[12] == 0x54) { /* - * SCSI errors, run domain validation and re-run negotiation - */ - p->needdv |= (1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<hscb->target_status = 0; scb->cmd->result = 0; + scb->hscb->residual_SG_segment_count = 0; + scb->hscb->residual_data_count[0] = 0; + scb->hscb->residual_data_count[1] = 0; + scb->hscb->residual_data_count[2] = 0; aic7xxx_error(scb->cmd) = DID_OK; + aic7xxx_status(scb->cmd) = 0; + /* + * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting + * this command on a timer and allowing us to retry it. Here, we + * just 0 out a few values so that they don't carry through to when + * the command finally does complete. + */ break; default: cmd = scb->cmd; @@ -7065,33 +7096,27 @@ if(!p) return; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) - if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags)) - { - return; - } spin_lock_irqsave(&io_request_lock, cpu_flags); + p->flags |= AHC_IN_ISR; do { aic7xxx_isr(irq, dev_id, regs); } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); aic7xxx_done_cmds_complete(p); aic7xxx_run_waiting_queues(p); - clear_bit(AHC_IN_ISR_BIT, &p->flags); + p->flags &= ~AHC_IN_ISR; spin_unlock_irqrestore(&io_request_lock, cpu_flags); #else - if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags)) - { - return; - } DRIVER_LOCK + p->flags |= AHC_IN_ISR; do { aic7xxx_isr(irq, dev_id, regs); } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); + p->flags &= ~AHC_IN_ISR; DRIVER_UNLOCK aic7xxx_done_cmds_complete(p); aic7xxx_run_waiting_queues(p); - clear_bit(AHC_IN_ISR_BIT, (int *)&p->flags); #endif } @@ -9012,22 +9037,6 @@ kfree(p->scb_data); } - /* - * Free any alloced Scsi_Cmnd structures that might be around for - * negotiation purposes.... - */ - for (i = 0; i < MAX_TARGETS; i++) - { - if(p->dev_dtr_cmnd[i]) - { - if(p->dev_dtr_cmnd[i]->request_buffer) - { - kfree(p->dev_dtr_cmnd[i]->request_buffer); - } - kfree(p->dev_dtr_cmnd[i]); - } - } - } /*+F************************************************************************* @@ -9413,7 +9422,7 @@ } aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB); aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1); - p->needppr = p->needppr_copy = p->needdv = 0; + p->needppr = p->needppr_copy = 0; p->needwdtr = p->needwdtr_copy; p->needsdtr = p->needsdtr_copy; p->dtr_pending = 0; @@ -9471,53 +9480,165 @@ /*+F************************************************************************* * Function: - * aic7xxx_detect + * aic7xxx_configure_bugs * * Description: - * Try to detect and register an Adaptec 7770 or 7870 SCSI controller. - * - * XXX - This should really be called aic7xxx_probe(). A sequence of - * probe(), attach()/detach(), and init() makes more sense than - * one do-it-all function. This may be useful when (and if) the - * mid-level SCSI code is overhauled. + * Take the card passed in and set the appropriate bug flags based upon + * the card model. Also make any changes needed to device registers or + * PCI registers while we are here. *-F*************************************************************************/ -int -aic7xxx_detect(Scsi_Host_Template *template) +static void +aic7xxx_configure_bugs(struct aic7xxx_host *p) { - struct aic7xxx_host *temp_p = NULL; - struct aic7xxx_host *current_p = NULL; - struct aic7xxx_host *list_p = NULL; - int found = 0; -#if defined(__i386__) || defined(__alpha__) - ahc_flag_type flags = 0; - int type; -#endif - unsigned char sxfrctl1; -#if defined(__i386__) || defined(__alpha__) - unsigned char hcntrl, hostconf; - unsigned int slot, base; -#endif - -#ifdef MODULE - /* - * If we are called as a module, the aic7xxx pointer may not be null - * and it would point to our bootup string, just like on the lilo - * command line. IF not NULL, then process this config string with - * aic7xxx_setup - */ - if(aic7xxx) - aic7xxx_setup(aic7xxx, NULL); - if(dummy_buffer[0] != 'P') - printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers" - "/scsi/README.aic7xxx\n" - "aic7xxx: to see the proper way to specify options to the aic7xxx " - "module\n" - "aic7xxx: Specifically, don't use any commas when passing arguments to\n" - "aic7xxx: insmod or else it might trash certain memory areas.\n"); + unsigned char pci_rev; + unsigned short tmp_word; + + if((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92) + pcibios_read_config_byte(p->pci_bus, p->pci_device_fn, + PCI_REVISION_ID, &pci_rev); +#else + pci_read_config_byte(p->pdev, PCI_REVISION_ID, &pci_rev); #endif + } - template->proc_dir = &proc_scsi_aic7xxx; - template->sg_tablesize = AIC7XXX_MAX_SG; + switch(p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7860: + if(pci_rev >= 1) + { + p->bugs |= AHC_BUG_PCI_2_1_RETRY; + } + /* fall through */ + case AHC_AIC7850: + case AHC_AIC7870: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + break; + case AHC_AIC7880: + p->bugs |= AHC_BUG_TMODE_WIDEODD; + if(pci_rev >= 1) + { + p->bugs |= AHC_BUG_PCI_2_1_RETRY; + } + else + { + p->bugs |= AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + } + break; + case AHC_AIC7890: + if(pci_rev == 0) + { + p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN; + } + break; + case AHC_AIC7892: + p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; + break; + case AHC_AIC7895: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | + AHC_BUG_CACHETHEN; + if(pci_rev <= 3) + { + p->bugs |= AHC_BUG_PCI_MWI; + } + break; + case AHC_AIC7896: + p->bugs |= AHC_BUG_CACHETHEN_DIS; + break; + case AHC_AIC7899: + p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; + break; + default: + /* Nothing to do */ + break; + } + + /* + * Now handle the bugs that require PCI register or card register tweaks + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92) + pcibios_read_config_word(p->pci_bus, p->pci_device_fn, + PCI_COMMAND, &tmp_word); +#else + pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word); +#endif + if(p->bugs & AHC_BUG_PCI_MWI) + { + tmp_word &= ~PCI_COMMAND_INVALIDATE; + } + else + { + tmp_word |= PCI_COMMAND_INVALIDATE; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92) + pcibios_write_config_word(p->pci_bus, p->pci_device_fn, + PCI_COMMAND, tmp_word); +#else + pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word); +#endif + + if(p->bugs & AHC_BUG_CACHETHEN) + { + aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0); + } + else if (p->bugs & AHC_BUG_CACHETHEN_DIS) + { + aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0); + } + + return; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_detect + * + * Description: + * Try to detect and register an Adaptec 7770 or 7870 SCSI controller. + * + * XXX - This should really be called aic7xxx_probe(). A sequence of + * probe(), attach()/detach(), and init() makes more sense than + * one do-it-all function. This may be useful when (and if) the + * mid-level SCSI code is overhauled. + *-F*************************************************************************/ +int +aic7xxx_detect(Scsi_Host_Template *template) +{ + struct aic7xxx_host *temp_p = NULL; + struct aic7xxx_host *current_p = NULL; + struct aic7xxx_host *list_p = NULL; + int found = 0; +#if defined(__i386__) || defined(__alpha__) + ahc_flag_type flags = 0; + int type; +#endif + unsigned char sxfrctl1; +#if defined(__i386__) || defined(__alpha__) + unsigned char hcntrl, hostconf; + unsigned int slot, base; +#endif + +#ifdef MODULE + /* + * If we are called as a module, the aic7xxx pointer may not be null + * and it would point to our bootup string, just like on the lilo + * command line. IF not NULL, then process this config string with + * aic7xxx_setup + */ + if(aic7xxx) + aic7xxx_setup(aic7xxx, NULL); + if(dummy_buffer[0] != 'P') + printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers" + "/scsi/README.aic7xxx\n" + "aic7xxx: to see the proper way to specify options to the aic7xxx " + "module\n" + "aic7xxx: Specifically, don't use any commas when passing arguments to\n" + "aic7xxx: insmod or else it might trash certain memory areas.\n"); +#endif + + template->proc_dir = &proc_scsi_aic7xxx; + template->sg_tablesize = AIC7XXX_MAX_SG; #ifdef CONFIG_PCI @@ -10290,6 +10411,14 @@ aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS); } + /* + * Call our function to fixup any bugs that exist on this chipset. + * This may muck with PCI settings and other device settings, so + * make sure it's after all the other PCI and device register + * tweaks so it can back out bad settings on specific broken cards. + */ + aic7xxx_configure_bugs(temp_p); + if ( list_p == NULL ) { list_p = current_p = temp_p; @@ -10533,6 +10662,11 @@ } /* + * All the 7770 based chipsets have this bug + */ + temp_p->bugs |= AHC_BUG_TMODE_WIDEODD; + + /* * Set the FIFO threshold and the bus off time. */ hostconf = aic_inb(temp_p, HOSTCONF); @@ -10751,297 +10885,6 @@ return (found); } -static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex); - -/*+F************************************************************************* - * Function: - * aic7xxx_allocate_negotiation_command - * - * Description: - * allocate the actual command struct and fill in the gaps... - *-F*************************************************************************/ -static Scsi_Cmnd * -aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex) -{ - Scsi_Cmnd *cmd; - char *buffer; - - if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) ) - { - return(NULL); - } - if (!(buffer = kmalloc(256, GFP_ATOMIC))) - { - kfree(p->dev_dtr_cmnd[tindex]); - p->dev_dtr_cmnd[tindex] = NULL; - return(NULL); - } - cmd = p->dev_dtr_cmnd[tindex]; - memset(cmd, 0, sizeof(Scsi_Cmnd)); - memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd)); - memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd)); - memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd)); - cmd->lun = 0; - cmd->request_bufflen = 255; - cmd->request_buffer = buffer; - cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0; - cmd->bufflen = 0; - cmd->buffer = NULL; - cmd->underflow = 0; - cmd->cmd_len = 6; - cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY; - cmd->cmnd[1] = cmd->data_cmnd[1] = 0; - cmd->cmnd[2] = cmd->data_cmnd[2] = 0; - cmd->cmnd[3] = cmd->data_cmnd[3] = 0; - cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */ - cmd->cmnd[5] = cmd->data_cmnd[5] = 0; - return(cmd); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_negotiation_complete - * - * Description: - * Handle completion events for our Negotiation commands. Clear out the - * struct and get it ready for its next use. - *-F*************************************************************************/ -static void -aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) -{ - unsigned int checksum; - int i; - int *ibuffer; - struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_syncrate *syncrate; - - /* - * perform our minimalistic domain validation - */ - if(p->dev_flags[tindex] & DEVICE_SCANNED) - { - ibuffer = (int *)cmd->request_buffer; - checksum = 0; - for(i = 0; i < (cmd->request_bufflen >> 2); i++) - { - checksum += ibuffer[i]; - } - if( (checksum != p->dev_checksum[tindex]) && - (p->transinfo[tindex].cur_offset != 0) ) - { - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - - if (p->needdv & (1<host_no, CTL_OF_CMD(cmd)); - } - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<needdv &= ~(1<host_no, CTL_OF_CMD(cmd)); - } - /* - * Update the checksum in case the INQUIRY data has changed, maybe - * in relation to a change in the mode pages, or whatever. - */ - p->dev_checksum[tindex] = checksum; - /* - * Signal that we are trying out the domain validation - */ - p->needdv |= (1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<needdv & (1<host_no, CTL_OF_CMD(cmd)); - } - /* - * We successfully did our checksum, so don't leave the needdv flag set - * in case we might have set it last time through. - */ - p->needdv &= ~(1<dtr_pending &= ~(0x01 << tindex); - /* - * This looks recursive in the extreme, but if this was a WDTR negotiation - * and we didn't follow up with SDTR yet, then this will get it started. - * For all other cases, this should work out to be a no-op, unless we are - * doing domain validation and happen to need a new negotiation command. - * - * In case we don't want this to go any further, the cmdcmplt interrupt - * handler will NULL out the cmd->next entry so that the real SCSI command - * can be sent back to the mid layer code with SENSE data intact. We'll - * finish things up when the cmd gets sent back down to us, so no worries. - */ - if(cmd->next) - { - aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex); - } - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_build_negotiation_command - * - * Description: - * Build a Scsi_Cmnd structure to perform negotiation with or else send - * a pre-built command specifically for this purpose. - *-F*************************************************************************/ -static void -aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd, - int tindex) -{ - - if ( !(p->dtr_pending & (1<needppr & (1<needwdtr & (1<needsdtr & (1<dev_dtr_cmnd[tindex] == NULL) && - (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) ) - { - return; - } - /* - * Before sending this thing out, we also make the cmd->next pointer - * point to the real command so we can stuff any possible SENSE data - * into the real command instead of this fake command. This has to be - * done each time the command is built, not just the first time, hence - * it's outside of the above if()... - */ - p->dev_dtr_cmnd[tindex]->next = old_cmd; - /* - * Clear the buffer so checksums come out right.... - */ - memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0, - p->dev_dtr_cmnd[tindex]->request_bufflen); - /* - * Remove any commands for this particular device that might be on the - * waiting_scbs queue or qinfifo so that this command goes out first. - * This is vital for our implementation of domain validation. - */ - pause_sequencer(p); - aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS, - SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]); - unpause_sequencer(p, FALSE); - { - struct aic7xxx_scb *scb, *next; - - scb = p->waiting_scbs.head; - while(scb != NULL) - { - if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel, - ALL_LUNS, SCB_LIST_NULL) ) - { - next = scb->q_next; - scbq_remove(&p->waiting_scbs, scb); - scbq_insert_tail(&p->delayed_scbs[tindex], scb); - scb = next; - } - else - { - scb = scb->q_next; - } - } - } - aic7xxx_queue(p->dev_dtr_cmnd[tindex], - aic7xxx_negotiation_complete); - } -} - #ifdef AIC7XXX_VERBOSE_DEBUGGING /*+F************************************************************************* * Function: @@ -11090,7 +10933,7 @@ */ hscb->control = 0; scb->tag_action = 0; - cmd->tag = hscb->tag; + if (p->discenable & mask) { hscb->control |= DISCENB; @@ -11119,34 +10962,29 @@ } } } - if ( cmd == p->dev_dtr_cmnd[tindex] ) + if ( !(p->dtr_pending & mask) && + ( (p->needppr & mask) || + (p->needwdtr & mask) || + (p->needsdtr & mask) ) && + (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) ) { p->dtr_pending |= mask; scb->tag_action = 0; - if (p->dev_flags[tindex] & DEVICE_SCANNED) + hscb->control &= DISCENB; + hscb->control |= MK_MESSAGE; + if(p->needppr & mask) { - hscb->control &= DISCENB; - hscb->control |= MK_MESSAGE; - if(p->needppr & mask) - { - scb->flags |= SCB_MSGOUT_PPR; - } - else if(p->needwdtr & mask) - { - scb->flags |= SCB_MSGOUT_WDTR; - } - else if(p->needsdtr & mask) - { - scb->flags |= SCB_MSGOUT_SDTR; - } + scb->flags |= SCB_MSGOUT_PPR; } - } - if ( !(p->dtr_pending & mask) && - ( (p->needppr & mask) || - (p->needwdtr & mask) || - (p->needsdtr & mask) ) ) - { - aic7xxx_build_negotiation_cmnd(p, cmd, tindex); + else if(p->needwdtr & mask) + { + scb->flags |= SCB_MSGOUT_WDTR; + } + else if(p->needsdtr & mask) + { + scb->flags |= SCB_MSGOUT_SDTR; + } + scb->flags |= SCB_DTR_SCB; } hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) | ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07); @@ -11285,50 +11123,58 @@ aic7xxx_allocate_scb(p); DRIVER_UNLOCK scb = scbq_remove_head(&p->scb_data->free_scbs); - } - if (scb == NULL) - { - printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, - CTL_OF_CMD(cmd)); - cmd->result = (DID_BUS_BUSY << 16); + if(scb == NULL) + printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, + CTL_OF_CMD(cmd)); + } + while (scb == NULL) + { + /* + * Well, all SCBs are currently active on the bus. So, we spin here + * running the interrupt handler until one completes and becomes free. + * We can do this safely because we either A) hold the driver lock (in + * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later + * kernels) and so either way, we won't take any other interrupts and + * the queue path will block until we release it. Also, we would worry + * about running the completion queues, but obviously there are plenty + * of commands outstanding to trigger a later interrupt that will do + * that for us, so skip it here. + */ DRIVER_LOCK - aic7xxx_queue_cmd_complete(p, cmd); + aic7xxx_isr(p->irq, p, NULL); DRIVER_UNLOCK - return 0; + scb = scbq_remove_head(&p->scb_data->free_scbs); } - else - { - scb->cmd = cmd; - aic7xxx_position(cmd) = scb->hscb->tag; + scb->cmd = cmd; + aic7xxx_position(cmd) = scb->hscb->tag; - /* - * Construct the SCB beforehand, so the sequencer is - * paused a minimal amount of time. - */ - aic7xxx_buildscb(p, cmd, scb); + /* + * Make sure the Scsi_Cmnd pointer is saved, the struct it points to + * is set up properly, and the parity error flag is reset, then send + * the SCB to the sequencer and watch the fun begin. + */ + cmd->scsi_done = fn; + cmd->result = DID_OK; + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + aic7xxx_error(cmd) = DID_OK; + aic7xxx_status(cmd) = 0; + cmd->host_scribble = NULL; - /* - * Make sure the Scsi_Cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ - cmd->scsi_done = fn; - cmd->result = DID_OK; - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - aic7xxx_error(cmd) = DID_OK; - aic7xxx_status(cmd) = 0; - cmd->host_scribble = NULL; + /* + * Construct the SCB beforehand, so the sequencer is + * paused a minimal amount of time. + */ + aic7xxx_buildscb(p, cmd, scb); - scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; + scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; - DRIVER_LOCK - scbq_insert_tail(&p->waiting_scbs, scb); - if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) - { - aic7xxx_run_waiting_queues(p); - } - DRIVER_UNLOCK + DRIVER_LOCK + scbq_insert_tail(&p->waiting_scbs, scb); + if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) + { + aic7xxx_run_waiting_queues(p); } + DRIVER_UNLOCK return (0); } @@ -11394,6 +11240,12 @@ aic_inb(p, SCSISIGI), aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no, + CTL_OF_SCB(scb), + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SSTAT2), + aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 | + aic_inb(p, STCNT)); } channel = cmd->channel; @@ -11687,7 +11539,6 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned long cpu_flags = 0; #endif - Scsi_Cmnd *cmd_next, *cmd_prev; p = (struct aic7xxx_host *) cmd->host->hostdata; scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); @@ -11718,13 +11569,11 @@ { aic7xxx_isr(p->irq, p, (void *)NULL); pause_sequencer(p); - aic7xxx_done_cmds_complete(p); } + aic7xxx_done_cmds_complete(p); - if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout)) - /* Totally bogus cmd since it points beyond our */ - { /* valid SCB range or doesn't even match it's own*/ - /* timeout serial number. */ + if (scb == NULL) + { if (aic7xxx_verbose & VERBOSE_ABORT_MID) printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd " "pointer.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -11743,28 +11592,6 @@ /* finish successfully, or to indicate that we */ /* don't have this cmd any more and the mid level */ /* code needs to find it. */ - cmd_next = p->completeq.head; - cmd_prev = NULL; - while (cmd_next != NULL) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Abort called for command " - "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( cmd_prev == NULL ) - p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble; - else - cmd_prev->host_scribble = cmd_next->host_scribble; - cmd_next->scsi_done(cmd_next); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful - * completion */ - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } if (aic7xxx_verbose & VERBOSE_ABORT_MID) printk(INFO_LEAD "Abort called for already completed" " command.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -11822,8 +11649,20 @@ found = 0; p->flags |= AHC_IN_ABORT; if (aic7xxx_verbose & VERBOSE_ABORT) - printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); + { + printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE " + "0x%x\n", + p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags, + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, LASTPHASE)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", + p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ? + aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT), + aic_inb(p, SCSISIGI)); + printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", + p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0), + aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); + } /* * First, let's check to see if the currently running command is our target @@ -11851,6 +11690,16 @@ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) printk(INFO_LEAD "SCB is currently active. " "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, CTL_OF_SCB(scb), + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); unpause_sequencer(p, FALSE); p->flags &= ~AHC_IN_ABORT; scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */ @@ -11866,35 +11715,7 @@ if ((found == 0) && (scb->flags & SCB_WAITINGQ)) { int tindex = TARGET_INDEX(cmd); - unsigned short mask; - - mask = (1 << tindex); - if (p->dtr_pending & mask) - { - if (p->dev_dtr_cmnd[tindex]->next != cmd) - found = 1; - else - found = 0; - } - else - { - found = 1; - } - if (found == 0) - { - /* - * OK..this means the command we are currently getting an abort - * for has an outstanding negotiation command in front of it. - * We don't really have a way to tie back into the negotiation - * commands, so we just send this back as pending, then it - * will get reset in 2 seconds. - */ - unpause_sequencer(p, TRUE); - scb->flags |= SCB_ABORT; - DRIVER_UNLOCK - return(SCSI_ABORT_PENDING); - } if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) printk(INFO_LEAD "SCB found on waiting list and " "aborted.\n", p->host_no, CTL_OF_SCB(scb)); @@ -12051,10 +11872,8 @@ #define DEVICE_RESET 0x01 #define BUS_RESET 0x02 #define HOST_RESET 0x04 -#define FAIL 0x08 -#define RESET_DELAY 0x10 +#define RESET_DELAY 0x08 int action; - Scsi_Cmnd *cmd_prev, *cmd_next; if ( cmd == NULL ) @@ -12082,86 +11901,32 @@ DRIVER_LOCK pause_sequencer(p); - while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) - { - aic7xxx_isr(p->irq, p, (void *)NULL ); - pause_sequencer(p); - aic7xxx_done_cmds_complete(p); - } - if (scb == NULL) + if(flags & SCSI_RESET_SYNCHRONOUS) { if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" - "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) - { - action = HOST_RESET; - } - else - { - action = BUS_RESET; - } + printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, " + "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags, + cmd->result); + scb = NULL; + action = HOST_RESET; } - else if (scb->cmd != cmd) + else if ((scb == NULL) || (scb->cmd != cmd)) { if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with recycled SCB " - "for cmd.\n", p->host_no, CTL_OF_CMD(cmd)); - cmd_prev = NULL; - cmd_next = p->completeq.head; - while ( cmd_next != NULL ) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, found cmd on completeq" - ", completing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } - if ( !(flags & SCSI_RESET_SYNCHRONOUS) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, cmd not found," - " failing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - else - { - if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called, no scb, " - "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags); - scb = NULL; - action = HOST_RESET; - } + printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" + "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd)); + aic7xxx_done_cmds_complete(p); + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_NOT_RUNNING); } else { if (aic7xxx_verbose & VERBOSE_RESET_MID) printk(INFO_LEAD "Reset called, scb %d, flags " "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); - if ( aic7xxx_scb_on_qoutfifo(p, scb) ) - { - if(aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no, - CTL_OF_SCB(scb)); - if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0) - printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no, - CTL_OF_SCB(scb)); - aic7xxx_handle_command_completion_intr(p); - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_SUCCESS); - } if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) { action = HOST_RESET; @@ -12175,6 +11940,26 @@ action = DEVICE_RESET; } } + + while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) + { + aic7xxx_isr(p->irq, p, (void *)NULL ); + pause_sequencer(p); + } + aic7xxx_done_cmds_complete(p); + + if(scb && (scb->cmd == NULL)) + { + /* + * We just completed the command when we ran the isr stuff, so we no + * longer have it. + */ + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_SUCCESS); + } + if ( (action & DEVICE_RESET) && (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) ) { @@ -12234,14 +12019,13 @@ switch (action) { case RESET_DELAY: + aic7xxx_run_waiting_queues(p); unpause_sequencer(p, FALSE); DRIVER_UNLOCK - return(SCSI_RESET_PENDING); - break; - case FAIL: - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_ERROR); + if(scb == NULL) + return(SCSI_RESET_PUNT); + else + return(SCSI_RESET_PENDING); break; case DEVICE_RESET: p->flags |= AHC_IN_RESET; @@ -12259,7 +12043,7 @@ case HOST_RESET: default: p->flags |= AHC_IN_RESET | AHC_RESET_DELAY; - p->dev_expires[p->scsi_id] = jiffies + (3 * HZ); + p->dev_expires[p->scsi_id] = jiffies + (1 * HZ); p->dev_timer_active |= (0x01 << p->scsi_id); if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) || time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) ) @@ -12288,21 +12072,14 @@ p->msg_index = 0; p->msg_len = 0; } - aic7xxx_run_done_queue(p, TRUE); - /* - * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is - * in need of being re-started, so send it on through to aic7xxx_queue - * and let it set until the delay is over. This keeps it from dying - * entirely and avoids getting a bogus dead command back through the - * mid-level code due to too many retries. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132) - if ( flags & SCSI_RESET_SYNCHRONOUS ) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + if(flags & SCSI_RESET_SYNCHRONOUS) { - cmd->result = DID_BUS_BUSY << 16; + cmd->result = DID_RESET << 16; cmd->done(cmd); } #endif + aic7xxx_run_done_queue(p, TRUE); p->flags &= ~AHC_IN_RESET; /* * We can't rely on run_waiting_queues to unpause the sequencer for @@ -12313,7 +12090,10 @@ aic7xxx_run_waiting_queues(p); unpause_sequencer(p, FALSE); DRIVER_UNLOCK - return(result); + if(scb == NULL) + return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET); + else + return(result); break; } } @@ -12623,7 +12403,7 @@ } -#include "aic7xxx_proc.c" +#include "aic7xxx/aic7xxx_proc.c" #ifdef MODULE /* Eventually this will go into an include file, but this will be later */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h --- v2.2.18/drivers/scsi/aic7xxx.h Sun Mar 25 11:13:01 2001 +++ linux/drivers/scsi/aic7xxx.h Wed Dec 31 19:00:00 1969 @@ -1,114 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $ - *-M*************************************************************************/ -#ifndef _aic7xxx_h -#define _aic7xxx_h - -#define AIC7XXX_H_VERSION "3.2.4" - -#ifndef LINUX_VERSION_CODE -#include -#endif - -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) -#endif - -#if defined(__i386__) -# define AIC7XXX_BIOSPARAM aic7xxx_biosparam -#else -# define AIC7XXX_BIOSPARAM NULL -#endif - -/* - * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields - * to do with card config are filled in after the card is detected. - */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65) -#define AIC7XXX { \ - next: NULL, \ - module: NULL, \ - proc_dir: NULL, \ - proc_info: aic7xxx_proc_info, \ - name: NULL, \ - detect: aic7xxx_detect, \ - release: aic7xxx_release, \ - info: aic7xxx_info, \ - command: NULL, \ - queuecommand: aic7xxx_queue, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: aic7xxx_abort, \ - reset: aic7xxx_reset, \ - slave_attach: NULL, \ - bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 255, /* max simultaneous cmds */\ - this_id: -1, /* scsi id of host adapter */\ - sg_tablesize: 0, /* max scatter-gather cmds */\ - cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ - present: 0, /* number of 7xxx's present */\ - unchecked_isa_dma: 0, /* no memory DMA restrictions */\ - use_clustering: ENABLE_CLUSTERING, \ - use_new_eh_code: 0 \ -} -#else -#define AIC7XXX { \ - next: NULL, \ - usage_count: NULL, \ - proc_dir: NULL, \ - proc_info: aic7xxx_proc_info, \ - name: NULL, \ - detect: aic7xxx_detect, \ - release: aic7xxx_release, \ - info: aic7xxx_info, \ - command: NULL, \ - queuecommand: aic7xxx_queue, \ - abort: aic7xxx_abort, \ - reset: aic7xxx_reset, \ - slave_attach: NULL, \ - bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 255, /* max simultaneous cmds */\ - this_id: -1, /* scsi id of host adapter */\ - sg_tablesize: 0, /* max scatter-gather cmds */\ - cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ - present: 0, /* number of 7xxx's present */\ - unchecked_isa_dma: 0, /* no memory DMA restrictions */\ - use_clustering: ENABLE_CLUSTERING \ -} -#endif - -extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -extern int aic7xxx_biosparam(Disk *, kdev_t, int[]); -extern int aic7xxx_detect(Scsi_Host_Template *); -extern int aic7xxx_command(Scsi_Cmnd *); -extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int); -extern int aic7xxx_abort(Scsi_Cmnd *); -extern int aic7xxx_release(struct Scsi_Host *); - -extern const char *aic7xxx_info(struct Scsi_Host *); - -extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int); - -#endif /* _aic7xxx_h */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c --- v2.2.18/drivers/scsi/aic7xxx_proc.c Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/aic7xxx_proc.c Wed Dec 31 19:00:00 1969 @@ -1,414 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver proc support for Linux. - * - * Copyright (c) 1995, 1996 Dean W. Gehnert - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ---------------------------------------------------------------- - * o Modified from the EATA-DMA /proc support. - * o Additional support for device block statistics provided by - * Matthew Jacob. - * o Correction of overflow by Heinz Mauelshagen - * o Adittional corrections by Doug Ledford - * - * Dean W. Gehnert, deang@teleport.com, 05/01/96 - * - * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ - *-M*************************************************************************/ - -#include - -#define BLS (&aic7xxx_buffer[size]) -#define HDRB \ -" < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+" - -#ifdef PROC_DEBUG -extern int vsprintf(char *, const char *, va_list); - -static void -proc_debug(const char *fmt, ...) -{ - va_list ap; - char buf[256]; - - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - printk(buf); - va_end(ap); -} -#else /* PROC_DEBUG */ -# define proc_debug(fmt, args...) -#endif /* PROC_DEBUG */ - -static int aic7xxx_buffer_size = 0; -static char *aic7xxx_buffer = NULL; - - -/*+F************************************************************************* - * Function: - * aic7xxx_set_info - * - * Description: - * Set parameters for the driver from the /proc filesystem. - *-F*************************************************************************/ -int -aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) -{ - proc_debug("aic7xxx_set_info(): %s\n", buffer); - return (-ENOSYS); /* Currently this is a no-op */ -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_proc_info - * - * Description: - * Return information to handle /proc support for the driver. - *-F*************************************************************************/ -int -aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, - int hostno, int inout) -{ - struct Scsi_Host *HBAptr; - struct aic7xxx_host *p; - int size = 0; - unsigned char i; - struct aic7xxx_xferstats *sp; - unsigned char target; - - HBAptr = NULL; - - for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next) - ; - - if (!p) - { - size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); - if (size > length) - { - return (size); - } - else - { - return (length); - } - } - - HBAptr = p->host; - - if (inout == TRUE) /* Has data been written to the file? */ - { - return (aic7xxx_set_info(buffer, length, HBAptr)); - } - - p = (struct aic7xxx_host *) HBAptr->hostdata; - - /* - * It takes roughly 1K of space to hold all relevant card info, not - * counting any proc stats, so we start out with a 1.5k buffer size and - * if proc_stats is defined, then we sweep the stats structure to see - * how many drives we will be printing out for and add 384 bytes per - * device with active stats. - * - * Hmmmm...that 1.5k seems to keep growing as items get added so they - * can be easily viewed for debugging purposes. So, we bumped that - * 1.5k to 4k so we can quit having to bump it all the time. - */ - - size = 4096; - for (target = 0; target < MAX_TARGETS; target++) - { - if (p->dev_flags[target] & DEVICE_PRESENT) -#ifdef AIC7XXX_PROC_STATS - size += 512; -#else - size += 256; -#endif - } - if (aic7xxx_buffer_size != size) - { - if (aic7xxx_buffer != NULL) - { - kfree(aic7xxx_buffer); - aic7xxx_buffer_size = 0; - } - aic7xxx_buffer = kmalloc(size, GFP_KERNEL); - } - if (aic7xxx_buffer == NULL) - { - size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n", - __LINE__); - return size; - } - aic7xxx_buffer_size = size; - - size = 0; - size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); - size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION); - size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Compile Options:\n"); -#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT - size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); -#else - size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); -#endif -#ifdef AIC7XXX_PROC_STATS - size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n"); -#else - size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); -#endif - size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY); - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Adapter Configuration:\n"); - size += sprintf(BLS, " SCSI Adapter: %s\n", - board_names[p->board_name_index]); - if (p->flags & AHC_TWIN) - size += sprintf(BLS, " Twin Channel Controller "); - else - { - char *channel = ""; - char *ultra = ""; - char *wide = "Narrow "; - if (p->flags & AHC_MULTI_CHANNEL) - { - channel = " Channel A"; - if (p->flags & (AHC_CHNLB|AHC_CHNLC)) - channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C"; - } - if (p->features & AHC_WIDE) - wide = "Wide "; - if (p->features & AHC_ULTRA3) - { - switch(p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7892: - case AHC_AIC7899: - ultra = "Ultra-160/m LVD/SE "; - break; - default: - ultra = "Ultra-3 LVD/SE "; - break; - } - } - else if (p->features & AHC_ULTRA2) - ultra = "Ultra-2 LVD/SE "; - else if (p->features & AHC_ULTRA) - ultra = "Ultra "; - size += sprintf(BLS, " %s%sController%s ", - ultra, wide, channel); - } - switch(p->chip & ~AHC_CHIPID_MASK) - { - case AHC_VL: - size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn); - break; - case AHC_EISA: - size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn); - break; - default: - size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus, - PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn)); - break; - } - if( !(p->maddr) ) - { - size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base); - } - else - { - size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase); - } - if( (p->chip & (AHC_VL | AHC_EISA)) ) - { - size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address); - } - size += sprintf(BLS, " Adapter SEEPROM Config: %s\n", - (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." : - ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." : - "SEEPROM not found, using leftover BIOS values.") ); - size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n", - (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled"); - size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n", - p->activescbs, p->max_activescbs); - size += sprintf(BLS, " Allocated %d, HW %d, " - "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, - p->scb_data->maxscbs); - if (p->flags & AHC_EXTERNAL_SRAM) - size += sprintf(BLS, " Using External SCB SRAM\n"); - size += sprintf(BLS, " Interrupts: %ld", p->isr_count); - if (p->chip & AHC_EISA) - { - size += sprintf(BLS, " %s\n", - (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)"); - } - else - { - size += sprintf(BLS, "\n"); - } - size += sprintf(BLS, " BIOS Control Word: 0x%04x\n", - p->bios_control); - size += sprintf(BLS, " Adapter Control Word: 0x%04x\n", - p->adapter_control); - size += sprintf(BLS, " Extended Translation: %sabled\n", - (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis"); - size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable); - if (p->features & (AHC_ULTRA | AHC_ULTRA2)) - { - size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb); - } - size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable); - size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag); - size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE); - size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " - "instance %d:\n", p->instance); - size += sprintf(BLS, " {"); - for(i=0; i < (MAX_TARGETS - 1); i++) - size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]); - size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]); - size += sprintf(BLS, " Actual queue depth per device for aic7xxx host " - "instance %d:\n", p->instance); - size += sprintf(BLS, " {"); - for(i=0; i < (MAX_TARGETS - 1); i++) - size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]); - size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]); - - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Statistics:\n\n"); - for (target = 0; target < MAX_TARGETS; target++) - { - sp = &p->stats[target]; - if ((p->dev_flags[target] & DEVICE_PRESENT) == 0) - { - continue; - } - if (p->features & AHC_TWIN) - { - size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", - p->host_no, (target >> 3), (target & 0x7), 0); - } - else - { - size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", - p->host_no, 0, target, 0); - } - size += sprintf(BLS, " Device using %s/%s", - (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ? - "Wide" : "Narrow", - (p->transinfo[target].cur_offset != 0) ? - "Sync transfers at " : "Async transfers.\n" ); - if (p->transinfo[target].cur_offset != 0) - { - struct aic7xxx_syncrate *sync_rate; - unsigned char options = p->transinfo[target].cur_options; - int period = p->transinfo[target].cur_period; - int rate = (p->transinfo[target].cur_width == - MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0; - - sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options); - if (sync_rate != NULL) - { - size += sprintf(BLS, "%s MByte/sec, offset %d\n", - sync_rate->rate[rate], - p->transinfo[target].cur_offset ); - } - else - { - size += sprintf(BLS, "3.3 MByte/sec, offset %d\n", - p->transinfo[target].cur_offset ); - } - } - size += sprintf(BLS, " Transinfo settings: "); - size += sprintf(BLS, "current(%d/%d/%d/%d), ", - p->transinfo[target].cur_period, - p->transinfo[target].cur_offset, - p->transinfo[target].cur_width, - p->transinfo[target].cur_options); - size += sprintf(BLS, "goal(%d/%d/%d/%d), ", - p->transinfo[target].goal_period, - p->transinfo[target].goal_offset, - p->transinfo[target].goal_width, - p->transinfo[target].goal_options); - size += sprintf(BLS, "user(%d/%d/%d/%d)\n", - p->transinfo[target].user_period, - p->transinfo[target].user_offset, - p->transinfo[target].user_width, - p->transinfo[target].user_options); -#ifdef AIC7XXX_PROC_STATS - size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", - sp->r_total + sp->w_total, sp->r_total, sp->w_total); - size += sprintf(BLS, "%s\n", HDRB); - size += sprintf(BLS, " Reads:"); - for (i = 0; i < NUMBER(sp->r_bins); i++) - { - size += sprintf(BLS, " %7ld", sp->r_bins[i]); - } - size += sprintf(BLS, "\n"); - size += sprintf(BLS, " Writes:"); - for (i = 0; i < NUMBER(sp->w_bins); i++) - { - size += sprintf(BLS, " %7ld", sp->w_bins[i]); - } - size += sprintf(BLS, "\n"); -#else - size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", - sp->r_total + sp->w_total, sp->r_total, sp->w_total); -#endif /* AIC7XXX_PROC_STATS */ - size += sprintf(BLS, "\n\n"); - } - - if (size >= aic7xxx_buffer_size) - { - printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); - } - - if (offset > size - 1) - { - kfree(aic7xxx_buffer); - aic7xxx_buffer = NULL; - aic7xxx_buffer_size = length = 0; - *start = NULL; - } - else - { - *start = buffer; - length = MIN(length, size - offset); - memcpy(buffer, &aic7xxx_buffer[offset], length); - } - - return (length); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h --- v2.2.18/drivers/scsi/aic7xxx_reg.h Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/aic7xxx_reg.h Wed Dec 31 19:00:00 1969 @@ -1,629 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ - -#define SCSISEQ 0x00 -#define TEMODE 0x80 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRSELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 -#define SCSIRSTO 0x01 - -#define SXFRCTL0 0x01 -#define DFON 0x80 -#define DFPEXP 0x40 -#define FAST20 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define SCAMEN 0x04 -#define CLRCHN 0x02 - -#define SXFRCTL1 0x02 -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 -#define ENSTIMER 0x04 -#define ACTNEGEN 0x02 -#define STPWEN 0x01 - -#define SCSISIGO 0x03 -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 - -#define SCSISIGI 0x03 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - -#define SCSIRATE 0x04 -#define WIDEXFER 0x80 -#define SXFR_ULTRA2 0x7f -#define SXFR 0x70 -#define SOFS 0x0f - -#define SCSIID 0x05 -#define SCSIOFFSET 0x05 -#define SOFS_ULTRA2 0x7f - -#define SCSIDATL 0x06 - -#define SCSIDATH 0x07 - -#define STCNT 0x08 - -#define OPTIONMODE 0x08 -#define AUTORATEEN 0x80 -#define AUTOACKEN 0x40 -#define ATNMGMNTEN 0x20 -#define BUSFREEREV 0x10 -#define EXPPHASEDIS 0x08 -#define SCSIDATL_IMGEN 0x04 -#define AUTO_MSGOUT_DE 0x02 -#define DIS_MSGIN_DUALEDGE 0x01 - -#define CLRSINT0 0x0b -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRSWRAP 0x08 -#define CLRSPIORDY 0x02 - -#define SSTAT0 0x0b -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define IOERR 0x08 -#define SWRAP 0x08 -#define SDONE 0x04 -#define SPIORDY 0x02 -#define DMADONE 0x01 - -#define CLRSINT1 0x0c -#define CLRSELTIMEO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 - -#define SSTAT1 0x0c -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -#define SSTAT2 0x0d -#define OVERRUN 0x80 -#define SHVALID 0x40 -#define WIDE_RES 0x20 -#define SFCNT 0x1f -#define EXP_ACTIVE 0x10 -#define CRCVALERR 0x08 -#define CRCENDERR 0x04 -#define CRCREQERR 0x02 -#define DUAL_EDGE_ERROR 0x01 - -#define SSTAT3 0x0e -#define SCSICNT 0xf0 -#define OFFCNT 0x0f - -#define SCSIID_ULTRA2 0x0f -#define OID 0x0f - -#define SIMODE0 0x10 -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENIOERR 0x08 -#define ENSWRAP 0x08 -#define ENSDONE 0x04 -#define ENSPIORDY 0x02 -#define ENDMADONE 0x01 - -#define SIMODE1 0x11 -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 - -#define SCSIBUSL 0x12 - -#define SCSIBUSH 0x13 - -#define SHADDR 0x14 - -#define SELTIMER 0x18 -#define STAGE6 0x20 -#define STAGE5 0x10 -#define STAGE4 0x08 -#define STAGE3 0x04 -#define STAGE2 0x02 -#define STAGE1 0x01 - -#define SELID 0x19 -#define SELID_MASK 0xf0 -#define ONEBIT 0x08 - -#define SPIOCAP 0x1b -#define SOFT1 0x80 -#define SOFT0 0x40 -#define SOFTCMDEN 0x20 -#define HAS_BRDCTL 0x10 -#define SEEPROM 0x08 -#define EEPROM 0x04 -#define ROM 0x02 -#define SSPIOCPS 0x01 - -#define BRDCTL 0x1d -#define BRDDAT7 0x80 -#define BRDDAT6 0x40 -#define BRDDAT5 0x20 -#define BRDDAT4 0x10 -#define BRDSTB 0x10 -#define BRDCS 0x08 -#define BRDDAT3 0x08 -#define BRDDAT2 0x04 -#define BRDRW 0x04 -#define BRDRW_ULTRA2 0x02 -#define BRDCTL1 0x02 -#define BRDCTL0 0x01 -#define BRDSTB_ULTRA2 0x01 - -#define SEECTL 0x1e -#define EXTARBACK 0x80 -#define EXTARBREQ 0x40 -#define SEEMS 0x20 -#define SEERDY 0x10 -#define SEECS 0x08 -#define SEECK 0x04 -#define SEEDO 0x02 -#define SEEDI 0x01 - -#define SBLKCTL 0x1f -#define DIAGLEDEN 0x80 -#define DIAGLEDON 0x40 -#define AUTOFLUSHDIS 0x20 -#define ENAB40 0x08 -#define ENAB20 0x04 -#define SELWIDE 0x02 -#define XCVR 0x01 - -#define SRAM_BASE 0x20 - -#define TARG_SCSIRATE 0x20 - -#define ULTRA_ENB 0x30 - -#define DISC_DSB 0x32 - -#define MSG_OUT 0x34 - -#define DMAPARAMS 0x35 -#define PRELOADEN 0x80 -#define WIDEODD 0x40 -#define SCSIEN 0x20 -#define SDMAENACK 0x10 -#define SDMAEN 0x10 -#define HDMAEN 0x08 -#define HDMAENACK 0x08 -#define DIRECTION 0x04 -#define FIFOFLUSH 0x02 -#define FIFORESET 0x01 - -#define SEQ_FLAGS 0x36 -#define IDENTIFY_SEEN 0x80 -#define SCBPTR_VALID 0x20 -#define DPHASE 0x10 -#define AMTARGET 0x08 -#define WIDE_BUS 0x02 -#define TWIN_BUS 0x01 - -#define SAVED_TCL 0x37 - -#define SG_COUNT 0x38 - -#define SG_NEXT 0x39 - -#define LASTPHASE 0x3d -#define P_MESGIN 0xe0 -#define PHASE_MASK 0xe0 -#define P_STATUS 0xc0 -#define P_MESGOUT 0xa0 -#define P_COMMAND 0x80 -#define CDI 0x80 -#define IOI 0x40 -#define P_DATAIN 0x40 -#define MSGI 0x20 -#define P_BUSFREE 0x01 -#define P_DATAOUT 0x00 - -#define WAITING_SCBH 0x3e - -#define DISCONNECTED_SCBH 0x3f - -#define FREE_SCBH 0x40 - -#define HSCB_ADDR 0x41 - -#define SCBID_ADDR 0x45 - -#define TMODE_CMDADDR 0x49 - -#define KERNEL_QINPOS 0x4d - -#define QINPOS 0x4e - -#define QOUTPOS 0x4f - -#define TMODE_CMDADDR_NEXT 0x50 - -#define ARG_1 0x51 -#define RETURN_1 0x51 -#define SEND_MSG 0x80 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 -#define MSGOUT_PHASEMIS 0x10 - -#define ARG_2 0x52 -#define RETURN_2 0x52 - -#define LAST_MSG 0x53 - -#define PREFETCH_CNT 0x54 - -#define SCSICONF 0x5a -#define TERM_ENB 0x80 -#define RESET_SCSI 0x40 -#define HWSCSIID 0x0f -#define HSCSIID 0x07 - -#define HOSTCONF 0x5d - -#define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 -#define BIOSDISABLED 0x30 -#define CHANNEL_B_PRIMARY 0x08 - -#define SEQCTL 0x60 -#define PERRORDIS 0x80 -#define PAUSEDIS 0x40 -#define FAILDIS 0x20 -#define FASTMODE 0x10 -#define BRKADRINTEN 0x08 -#define STEP 0x04 -#define SEQRESET 0x02 -#define LOADRAM 0x01 - -#define SEQRAM 0x61 - -#define SEQADDR0 0x62 - -#define SEQADDR1 0x63 -#define SEQADDR1_MASK 0x01 - -#define ACCUM 0x64 - -#define SINDEX 0x65 - -#define DINDEX 0x66 - -#define ALLONES 0x69 - -#define ALLZEROS 0x6a - -#define NONE 0x6a - -#define FLAGS 0x6b -#define ZERO 0x02 -#define CARRY 0x01 - -#define SINDIR 0x6c - -#define DINDIR 0x6d - -#define FUNCTION1 0x6e - -#define STACK 0x6f - -#define TARG_OFFSET 0x70 - -#define BCTL 0x84 -#define ACE 0x08 -#define ENABLE 0x01 - -#define DSCOMMAND0 0x84 -#define INTSCBRAMSEL 0x08 -#define RAMPS 0x04 -#define USCBSIZE32 0x02 -#define CIOPARCKEN 0x01 - -#define DSCOMMAND 0x84 -#define CACHETHEN 0x80 -#define DPARCKEN 0x40 -#define MPARCKEN 0x20 -#define EXTREQLCK 0x10 - -#define BUSTIME 0x85 -#define BOFF 0xf0 -#define BON 0x0f - -#define BUSSPD 0x86 -#define DFTHRSH 0xc0 -#define STBOFF 0x38 -#define STBON 0x07 - -#define DSPCISTATUS 0x86 -#define DFTHRSH_100 0xc0 - -#define HCNTRL 0x87 -#define POWRDN 0x40 -#define SWINT 0x10 -#define IRQMS 0x08 -#define PAUSE 0x04 -#define INTEN 0x02 -#define CHIPRST 0x01 -#define CHIPRSTACK 0x01 - -#define HADDR 0x88 - -#define HCNT 0x8c - -#define SCBPTR 0x90 - -#define INTSTAT 0x91 -#define SEQINT_MASK 0xf1 -#define DATA_OVERRUN 0xe1 -#define MSGIN_PHASEMIS 0xd1 -#define TRACEPOINT2 0xc1 -#define TRACEPOINT 0xb1 -#define AWAITING_MSG 0xa1 -#define RESIDUAL 0x81 -#define BAD_STATUS 0x71 -#define REJECT_MSG 0x61 -#define WIDE_RESIDUE 0x51 -#define EXTENDED_MSG 0x41 -#define NO_MATCH 0x31 -#define NO_IDENT 0x21 -#define SEND_REJECT 0x11 -#define INT_PEND 0x0f -#define BRKADRINT 0x08 -#define SCSIINT 0x04 -#define CMDCMPLT 0x02 -#define BAD_PHASE 0x01 -#define SEQINT 0x01 - -#define CLRINT 0x92 -#define CLRPARERR 0x10 -#define CLRBRKADRINT 0x08 -#define CLRSCSIINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSEQINT 0x01 - -#define ERROR 0x92 -#define CIOPARERR 0x80 -#define PCIERRSTAT 0x40 -#define MPARERR 0x20 -#define DPARERR 0x10 -#define SQPARERR 0x08 -#define ILLOPCODE 0x04 -#define DSCTMOUT 0x02 -#define ILLSADDR 0x02 -#define ILLHADDR 0x01 - -#define DFCNTRL 0x93 - -#define DFSTATUS 0x94 -#define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 -#define MREQPEND 0x10 -#define HDONE 0x08 -#define DFTHRESH 0x04 -#define FIFOFULL 0x02 -#define FIFOEMP 0x01 - -#define DFDAT 0x99 - -#define SCBCNT 0x9a -#define SCBAUTO 0x80 -#define SCBCNT_MASK 0x1f - -#define QINFIFO 0x9b - -#define QINCNT 0x9c - -#define SCSIDATL_IMG 0x9c - -#define QOUTFIFO 0x9d - -#define CRCCONTROL1 0x9d -#define CRCONSEEN 0x80 -#define CRCVALCHKEN 0x40 -#define CRCENDCHKEN 0x20 -#define CRCREQCHKEN 0x10 -#define TARGCRCENDEN 0x08 -#define TARGCRCCNTEN 0x04 - -#define QOUTCNT 0x9e - -#define SCSIPHASE 0x9e -#define SP_STATUS 0x20 -#define SP_COMMAND 0x10 -#define SP_MSG_IN 0x08 -#define SP_MSG_OUT 0x04 -#define SP_DATA_IN 0x02 -#define SP_DATA_OUT 0x01 - -#define SFUNCT 0x9f -#define ALT_MODE 0x80 - -#define SCB_CONTROL 0xa0 -#define MK_MESSAGE 0x80 -#define DISCENB 0x40 -#define TAG_ENB 0x20 -#define DISCONNECTED 0x04 -#define SCB_TAG_TYPE 0x03 - -#define SCB_BASE 0xa0 - -#define SCB_TCL 0xa1 -#define TID 0xf0 -#define SELBUSB 0x08 -#define LID 0x07 - -#define SCB_TARGET_STATUS 0xa2 - -#define SCB_SGCOUNT 0xa3 - -#define SCB_SGPTR 0xa4 - -#define SCB_RESID_SGCNT 0xa8 - -#define SCB_RESID_DCNT 0xa9 - -#define SCB_DATAPTR 0xac - -#define SCB_DATACNT 0xb0 - -#define SCB_CMDPTR 0xb4 - -#define SCB_CMDLEN 0xb8 - -#define SCB_TAG 0xb9 - -#define SCB_NEXT 0xba - -#define SCB_PREV 0xbb - -#define SCB_BUSYTARGETS 0xbc - -#define SEECTL_2840 0xc0 -#define CS_2840 0x04 -#define CK_2840 0x02 -#define DO_2840 0x01 - -#define STATUS_2840 0xc1 -#define EEPROM_TF 0x80 -#define BIOS_SEL 0x60 -#define ADSEL 0x1e -#define DI_2840 0x01 - -#define CCHADDR 0xe0 - -#define CCHCNT 0xe8 - -#define CCSGRAM 0xe9 - -#define CCSGADDR 0xea - -#define CCSGCTL 0xeb -#define CCSGDONE 0x80 -#define CCSGEN 0x08 -#define FLAG 0x02 -#define CCSGRESET 0x01 - -#define CCSCBRAM 0xec - -#define CCSCBADDR 0xed - -#define CCSCBCTL 0xee -#define CCSCBDONE 0x80 -#define ARRDONE 0x40 -#define CCARREN 0x10 -#define CCSCBEN 0x08 -#define CCSCBDIR 0x04 -#define CCSCBRESET 0x01 - -#define CCSCBCNT 0xef - -#define CCSCBPTR 0xf1 - -#define HNSCB_QOFF 0xf4 - -#define HESCB_QOFF 0xf5 - -#define SNSCB_QOFF 0xf6 - -#define SESCB_QOFF 0xf7 - -#define SDSCB_QOFF 0xf8 - -#define QOFF_CTLSTA 0xfa -#define ESTABLISH_SCB_AVAIL 0x80 -#define SCB_AVAIL 0x40 -#define SNSCB_ROLLOVER 0x20 -#define SDSCB_ROLLOVER 0x10 -#define SESCB_ROLLOVER 0x08 -#define SCB_QSIZE 0x07 -#define SCB_QSIZE_256 0x06 - -#define DFF_THRSH 0xfb -#define WR_DFTHRSH 0x70 -#define WR_DFTHRSH_MAX 0x70 -#define WR_DFTHRSH_90 0x60 -#define WR_DFTHRSH_85 0x50 -#define WR_DFTHRSH_75 0x40 -#define WR_DFTHRSH_63 0x30 -#define WR_DFTHRSH_50 0x20 -#define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 -#define RD_DFTHRSH 0x07 -#define RD_DFTHRSH_90 0x06 -#define RD_DFTHRSH_85 0x05 -#define RD_DFTHRSH_75 0x04 -#define RD_DFTHRSH_63 0x03 -#define RD_DFTHRSH_50 0x02 -#define RD_DFTHRSH_25 0x01 -#define RD_DFTHRSH_MIN 0x00 -#define WR_DFTHRSH_MIN 0x00 - -#define SG_CACHEPTR 0xfc -#define SG_USER_DATA 0xfc -#define LAST_SEG 0x02 -#define LAST_SEG_DONE 0x01 - - -#define CMD_GROUP_CODE_SHIFT 0x05 -#define BUS_8_BIT 0x00 -#define QOUTFIFO_OFFSET 0x01 -#define CCSGRAM_MAXSEGS 0x10 -#define CMD_GROUP2_BYTE_DELTA 0xfa -#define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 -#define QINFIFO_OFFSET 0x02 -#define CMD_GROUP5_BYTE_DELTA 0x0b -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define UNTAGGEDSCB_OFFSET 0x00 -#define SCB_LIST_NULL 0xff -#define SG_SIZEOF 0x08 -#define CMD_GROUP4_BYTE_DELTA 0x04 -#define CMD_GROUP0_BYTE_DELTA 0xfc -#define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 - - -/* Downloaded Constant Definitions */ -#define TMODE_NUMCMDS 0x00 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_seq.c --- v2.2.18/drivers/scsi/aic7xxx_seq.c Sun Mar 25 11:13:03 2001 +++ linux/drivers/scsi/aic7xxx_seq.c Wed Dec 31 19:00:00 1969 @@ -1,745 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ -static unsigned char seqprog[] = { - 0xff, 0x6a, 0x06, 0x08, - 0x7f, 0x02, 0x04, 0x08, - 0x12, 0x6a, 0x00, 0x00, - 0xff, 0x6a, 0xd6, 0x09, - 0xff, 0x6a, 0xdc, 0x09, - 0x00, 0x65, 0xca, 0x58, - 0xf7, 0x01, 0x02, 0x08, - 0xff, 0x4e, 0xc8, 0x08, - 0xbf, 0x60, 0xc0, 0x08, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0xff, 0x3e, 0x48, 0x60, - 0x40, 0xfa, 0x10, 0x78, - 0xff, 0xf6, 0xd4, 0x08, - 0x01, 0x4e, 0x9c, 0x18, - 0x40, 0x60, 0xc0, 0x00, - 0x00, 0x4d, 0x10, 0x70, - 0x01, 0x4e, 0x9c, 0x18, - 0xbf, 0x60, 0xc0, 0x08, - 0x00, 0x6a, 0x3e, 0x5c, - 0xff, 0x4e, 0xc8, 0x18, - 0x02, 0x6a, 0x54, 0x5b, - 0xff, 0x52, 0x20, 0x09, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x52, 0xca, 0x5b, - 0x03, 0xb0, 0x52, 0x31, - 0xff, 0xb0, 0x52, 0x09, - 0xff, 0xb1, 0x54, 0x09, - 0xff, 0xb2, 0x56, 0x09, - 0xff, 0xa3, 0x50, 0x09, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0xff, 0x3e, 0x20, 0x09, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0x0c, 0x40, - 0xf7, 0x1f, 0xca, 0x08, - 0x08, 0xa1, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0xff, 0x65, 0x3e, 0x08, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x0f, 0x1e, 0x08, - 0x00, 0x0f, 0x1e, 0x00, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x05, 0x0a, 0x08, - 0x00, 0x05, 0x0a, 0x00, - 0xff, 0x6a, 0x0c, 0x08, - 0x5a, 0x6a, 0x00, 0x04, - 0x12, 0x65, 0x02, 0x00, - 0x31, 0x6a, 0xca, 0x00, - 0x80, 0x37, 0x6e, 0x68, - 0xff, 0x65, 0xca, 0x18, - 0xff, 0x37, 0xdc, 0x08, - 0xff, 0x6e, 0xc8, 0x08, - 0x00, 0x6c, 0x76, 0x78, - 0x20, 0x01, 0x02, 0x00, - 0x4c, 0x37, 0xc8, 0x28, - 0x08, 0x1f, 0x7e, 0x78, - 0x08, 0x37, 0x6e, 0x00, - 0x08, 0x64, 0xc8, 0x00, - 0x70, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x0a, 0x08, - 0x20, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x08, 0x0c, - 0x40, 0x0b, 0x96, 0x68, - 0x20, 0x6a, 0x16, 0x00, - 0xf0, 0x19, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x12, 0x6a, 0x00, 0x00, - 0x40, 0x6a, 0x16, 0x00, - 0xff, 0x3e, 0x20, 0x09, - 0xff, 0xba, 0x7c, 0x08, - 0xff, 0xa1, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x80, 0x6a, 0x68, 0x00, - 0x80, 0x36, 0x6c, 0x00, - 0x00, 0x65, 0x9e, 0x5b, - 0xff, 0x3d, 0xc8, 0x08, - 0xbf, 0x64, 0xe2, 0x78, - 0x80, 0x64, 0xac, 0x71, - 0xa0, 0x64, 0xdc, 0x71, - 0xc0, 0x64, 0xd4, 0x71, - 0xe0, 0x64, 0x1c, 0x72, - 0x01, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xca, 0x58, - 0xff, 0x06, 0xd4, 0x08, - 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xc4, 0x78, - 0x08, 0x0c, 0x0c, 0x68, - 0x01, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0x26, 0x09, - 0x02, 0x6a, 0x08, 0x30, - 0xff, 0x6a, 0x08, 0x08, - 0xdf, 0x01, 0x02, 0x08, - 0x01, 0x6a, 0x7a, 0x00, - 0xff, 0x6a, 0x6c, 0x0c, - 0x04, 0x14, 0x10, 0x31, - 0x03, 0xa9, 0x18, 0x31, - 0x03, 0xa9, 0x10, 0x30, - 0x08, 0x6a, 0xcc, 0x00, - 0xa9, 0x6a, 0xb4, 0x5b, - 0x00, 0x65, 0x02, 0x41, - 0xa8, 0x6a, 0x6a, 0x00, - 0x79, 0x6a, 0x6a, 0x00, - 0x40, 0x3d, 0xea, 0x68, - 0x04, 0x35, 0x6a, 0x00, - 0x00, 0x65, 0x0e, 0x5b, - 0x80, 0x6a, 0xd4, 0x01, - 0x10, 0x36, 0xd6, 0x68, - 0x10, 0x36, 0x6c, 0x00, - 0x07, 0xac, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x05, 0xa3, 0x70, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xac, 0x5b, - 0x00, 0x65, 0xa6, 0x5b, - 0x38, 0x6a, 0xcc, 0x00, - 0xa3, 0x6a, 0xb0, 0x5b, - 0xff, 0x38, 0x12, 0x69, - 0x80, 0x02, 0x04, 0x00, - 0xe7, 0x35, 0x6a, 0x08, - 0x03, 0x69, 0x18, 0x31, - 0x03, 0x69, 0x10, 0x30, - 0xff, 0x6a, 0x10, 0x00, - 0xff, 0x6a, 0x12, 0x00, - 0xff, 0x6a, 0x14, 0x00, - 0x01, 0x38, 0x18, 0x61, - 0xbf, 0x35, 0x6a, 0x08, - 0x02, 0x6a, 0xf8, 0x01, - 0xff, 0x69, 0xca, 0x08, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x1c, 0x69, - 0x04, 0x0b, 0x28, 0x69, - 0x10, 0x0c, 0x1e, 0x79, - 0x04, 0x0b, 0x28, 0x69, - 0xff, 0x6a, 0xca, 0x08, - 0x00, 0x35, 0xee, 0x5a, - 0x80, 0x02, 0x7c, 0x69, - 0xff, 0x65, 0x6c, 0x79, - 0xff, 0x38, 0x70, 0x18, - 0xff, 0x38, 0x6c, 0x79, - 0x80, 0xea, 0x48, 0x61, - 0xef, 0x38, 0xc8, 0x18, - 0x80, 0x6a, 0xc8, 0x00, - 0x00, 0x65, 0x3a, 0x49, - 0x33, 0x38, 0xc8, 0x28, - 0xff, 0x64, 0xd0, 0x09, - 0x04, 0x39, 0xc0, 0x31, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x40, 0x79, - 0xf7, 0xeb, 0xd6, 0x09, - 0x08, 0xeb, 0x44, 0x69, - 0x01, 0x6a, 0xd6, 0x01, - 0x08, 0xe9, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0x39, 0x6a, 0xb2, 0x5b, - 0x08, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x88, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0xa6, 0x5b, - 0xff, 0x6a, 0xc8, 0x08, - 0x08, 0x39, 0x72, 0x18, - 0x00, 0x3a, 0x74, 0x20, - 0x01, 0x0c, 0x64, 0x79, - 0x10, 0x0c, 0x02, 0x79, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x6a, 0x69, - 0x00, 0x65, 0x84, 0x59, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0xff, 0x08, 0x52, 0x09, - 0xff, 0x09, 0x54, 0x09, - 0xff, 0x0a, 0x56, 0x09, - 0xff, 0x38, 0x50, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x84, 0x59, - 0x7f, 0x02, 0x04, 0x08, - 0xe1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0x93, 0x9a, 0x69, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0x88, 0x69, - 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x10, 0x94, 0x98, 0x69, - 0x7f, 0x05, 0xa0, 0x69, - 0x02, 0x03, 0xa0, 0x79, - 0x11, 0x0c, 0x9c, 0x79, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xa2, 0x69, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0x12, 0x01, 0x02, 0x00, - 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x0e, 0x5b, - 0x05, 0xb4, 0x10, 0x31, - 0x02, 0x6a, 0x1a, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xb4, 0x6a, 0xb0, 0x5b, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x00, 0x65, 0xa6, 0x5b, - 0x3d, 0x6a, 0xee, 0x5a, - 0xac, 0x6a, 0x26, 0x01, - 0x04, 0x0b, 0xc2, 0x69, - 0x04, 0x0b, 0xc8, 0x69, - 0x10, 0x0c, 0xc4, 0x79, - 0x02, 0x03, 0xcc, 0x79, - 0x11, 0x0c, 0xc8, 0x79, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xce, 0x69, - 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x0e, 0x5b, - 0xff, 0x06, 0x44, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x34, 0xca, 0x08, - 0x80, 0x65, 0x00, 0x62, - 0x0f, 0xa1, 0xca, 0x08, - 0x07, 0xa1, 0xca, 0x08, - 0x40, 0xa0, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0x80, 0x65, 0xca, 0x00, - 0x80, 0xa0, 0xf0, 0x79, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x02, 0x42, - 0x20, 0xa0, 0x08, 0x7a, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, - 0x23, 0xa0, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, - 0x00, 0xb9, 0x08, 0x42, - 0xff, 0x65, 0x08, 0x62, - 0xa1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x10, 0x51, 0x10, 0x72, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0xda, 0x71, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x34, 0xa6, 0x08, - 0x80, 0x34, 0x18, 0x62, - 0x7f, 0xa0, 0x40, 0x09, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x64, 0x6a, 0xe4, 0x5a, - 0x80, 0x64, 0x8e, 0x6a, - 0x04, 0x64, 0x70, 0x72, - 0x02, 0x64, 0x76, 0x72, - 0x00, 0x6a, 0x38, 0x72, - 0x03, 0x64, 0x8a, 0x72, - 0x01, 0x64, 0x6c, 0x72, - 0x07, 0x64, 0xcc, 0x72, - 0x08, 0x64, 0x34, 0x72, - 0x23, 0x64, 0xd0, 0x72, - 0x11, 0x6a, 0x22, 0x01, - 0x07, 0x6a, 0xd6, 0x5a, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0xa8, 0x3c, 0x6a, - 0xff, 0xa2, 0x54, 0x7a, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0xa2, 0x54, 0x7a, - 0x71, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x40, 0x51, 0x54, 0x62, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0xbc, 0x40, - 0x20, 0xa0, 0x5c, 0x6a, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x74, 0x5b, - 0xff, 0x6a, 0x8a, 0x5b, - 0xff, 0xf8, 0xc8, 0x08, - 0xff, 0x4f, 0xc8, 0x08, - 0x01, 0x6a, 0x74, 0x5b, - 0x00, 0xb9, 0x8a, 0x5b, - 0x01, 0x4f, 0x9e, 0x18, - 0x02, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x38, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x41, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0xa0, 0x40, 0x01, - 0x00, 0x65, 0x50, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x10, 0x36, 0x34, 0x7a, - 0x05, 0x38, 0x46, 0x31, - 0x04, 0x14, 0x58, 0x31, - 0x03, 0xa9, 0x60, 0x31, - 0xa3, 0x6a, 0xcc, 0x00, - 0x38, 0x6a, 0xb0, 0x5b, - 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xb2, 0x5b, - 0xa9, 0x6a, 0xb4, 0x5b, - 0x00, 0x65, 0x34, 0x42, - 0xef, 0x36, 0x6c, 0x08, - 0x00, 0x65, 0x34, 0x42, - 0x0f, 0x64, 0xc8, 0x08, - 0x07, 0x64, 0xc8, 0x08, - 0x00, 0x37, 0x6e, 0x00, - 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x44, 0x5b, - 0xff, 0x51, 0xa0, 0x72, - 0x20, 0x36, 0xaa, 0x7a, - 0x00, 0x90, 0x32, 0x5b, - 0x00, 0x65, 0xac, 0x42, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xe0, 0x3d, 0xc6, 0x62, - 0x20, 0x12, 0xc6, 0x62, - 0x51, 0x6a, 0xda, 0x5a, - 0x00, 0x65, 0x2c, 0x5b, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0xa1, 0xbe, 0x62, - 0x04, 0xa0, 0xbe, 0x7a, - 0xfb, 0xa0, 0x40, 0x09, - 0x80, 0x36, 0x6c, 0x00, - 0x80, 0xa0, 0x34, 0x7a, - 0x7f, 0xa0, 0x40, 0x09, - 0xff, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, - 0x04, 0xa0, 0xc4, 0x7a, - 0x00, 0x65, 0x50, 0x5c, - 0x00, 0x65, 0xc6, 0x42, - 0x00, 0x65, 0x38, 0x5c, - 0x31, 0x6a, 0x22, 0x01, - 0x0c, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, - 0x61, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, - 0x51, 0x6a, 0xda, 0x5a, - 0x51, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x65, 0x68, 0x0c, - 0xff, 0x06, 0xd4, 0x08, - 0x01, 0x0c, 0xdc, 0x7a, - 0x04, 0x0c, 0xde, 0x6a, - 0xe0, 0x03, 0x7a, 0x08, - 0xe0, 0x3d, 0xea, 0x62, - 0xff, 0x65, 0xcc, 0x08, - 0xff, 0x12, 0xda, 0x0c, - 0xff, 0x06, 0xd4, 0x0c, - 0xd1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0x65, 0x26, 0x09, - 0x01, 0x0b, 0xfe, 0x6a, - 0x10, 0x0c, 0xf0, 0x7a, - 0x04, 0x0b, 0xf8, 0x6a, - 0xff, 0x6a, 0xca, 0x08, - 0x04, 0x93, 0xfc, 0x6a, - 0x01, 0x94, 0xfa, 0x7a, - 0x10, 0x94, 0xfc, 0x6a, - 0x80, 0x3d, 0x02, 0x73, - 0x0f, 0x04, 0x06, 0x6b, - 0x02, 0x03, 0x06, 0x7b, - 0x11, 0x0c, 0x02, 0x7b, - 0xc7, 0x93, 0x26, 0x09, - 0xff, 0x99, 0xd4, 0x08, - 0x38, 0x93, 0x08, 0x6b, - 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0x36, 0x0c, 0x6b, - 0x21, 0x6a, 0x22, 0x05, - 0xff, 0x65, 0x20, 0x09, - 0xff, 0x51, 0x1a, 0x63, - 0xff, 0x37, 0xc8, 0x08, - 0xa1, 0x6a, 0x26, 0x43, - 0xff, 0x51, 0xc8, 0x08, - 0xb9, 0x6a, 0x26, 0x43, - 0xff, 0x90, 0xa4, 0x08, - 0xff, 0xba, 0x2a, 0x73, - 0xff, 0xba, 0x20, 0x09, - 0xff, 0x65, 0xca, 0x18, - 0x00, 0x6c, 0x1e, 0x63, - 0xff, 0x90, 0xca, 0x0c, - 0xff, 0x6a, 0xca, 0x04, - 0x20, 0x36, 0x3e, 0x7b, - 0x00, 0x90, 0x12, 0x5b, - 0xff, 0x65, 0x3e, 0x73, - 0xff, 0x52, 0x3c, 0x73, - 0xff, 0xba, 0xcc, 0x08, - 0xff, 0x52, 0x20, 0x09, - 0xff, 0x66, 0x74, 0x09, - 0xff, 0x65, 0x20, 0x0d, - 0xff, 0xba, 0x7e, 0x0c, - 0x00, 0x6a, 0x3e, 0x5c, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x51, 0xca, 0x43, - 0xff, 0x3f, 0x98, 0x73, - 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3f, 0x12, 0x5b, - 0xff, 0x65, 0x98, 0x73, - 0x20, 0x36, 0x6c, 0x00, - 0x20, 0xa0, 0x52, 0x6b, - 0xff, 0xb9, 0xa2, 0x0c, - 0xff, 0x6a, 0xa2, 0x04, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x5e, 0x7b, - 0x01, 0x6a, 0xd6, 0x01, - 0x01, 0xe9, 0xa4, 0x34, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0xff, 0x99, 0xa4, 0x0c, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x01, 0x6a, 0xdc, 0x05, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x01, 0x6a, 0x26, 0x05, - 0x01, 0x65, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x8e, 0x7b, - 0xff, 0x6a, 0xdc, 0x0d, - 0xff, 0x65, 0x32, 0x09, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x44, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x54, 0x5b, - 0xff, 0x52, 0xa2, 0x0c, - 0x01, 0x0c, 0x9e, 0x7b, - 0x04, 0x0c, 0x9e, 0x6b, - 0xe0, 0x03, 0x06, 0x08, - 0xe0, 0x03, 0x7a, 0x0c, - 0xff, 0x8c, 0x10, 0x08, - 0xff, 0x8d, 0x12, 0x08, - 0xff, 0x8e, 0x14, 0x0c, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x0c, - 0x3d, 0x64, 0xa4, 0x28, - 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x6c, 0xda, 0x18, - 0xff, 0x52, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0xff, 0x6a, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0x00, 0x6c, 0xda, 0x24, - 0xff, 0x65, 0xc8, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, - 0xff, 0x90, 0xe2, 0x09, - 0x20, 0x6a, 0xd0, 0x01, - 0x04, 0x35, 0xdc, 0x7b, - 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xd8, 0x63, - 0x00, 0x65, 0xe8, 0x43, - 0x01, 0x6a, 0xdc, 0x01, - 0x20, 0xa0, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xe2, 0x7b, - 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0xe6, 0x63, - 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0xea, 0x6b, - 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, - 0x20, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x35, 0x14, 0x6c, - 0xa0, 0x6a, 0xca, 0x00, - 0x20, 0x65, 0xc8, 0x18, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0x00, 0x65, 0x00, 0x64, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x04, 0x35, 0x0c, 0x7b, - 0xa0, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x44, - 0xff, 0x65, 0xcc, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x0c, - 0x08, 0x94, 0x30, 0x7c, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x34, 0x6c, - 0xff, 0x6a, 0xd4, 0x0c, - 0xff, 0x40, 0x74, 0x09, - 0xff, 0x90, 0x80, 0x08, - 0xff, 0x6a, 0x72, 0x05, - 0xff, 0x40, 0x4c, 0x64, - 0xff, 0x3f, 0x44, 0x64, - 0xff, 0x6a, 0xca, 0x04, - 0xff, 0x3f, 0x20, 0x09, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0xba, 0x7e, 0x0c, - 0xff, 0x40, 0x20, 0x09, - 0xff, 0xba, 0x80, 0x0c, - 0xff, 0x3f, 0x74, 0x09, - 0xff, 0x90, 0x7e, 0x0c, -}; - -static int aic7xxx_patch12_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch12_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_WIDE) != 0); -} - -static int aic7xxx_patch11_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch11_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) == 0); -} - -static int aic7xxx_patch10_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch10_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) == 0); -} - -static int aic7xxx_patch9_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch9_func(struct aic7xxx_host *p) -{ - return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); -} - -static int aic7xxx_patch8_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch8_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA) != 0); -} - -static int aic7xxx_patch7_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch7_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) != 0); -} - -static int aic7xxx_patch6_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch6_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) == 0); -} - -static int aic7xxx_patch5_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch5_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) != 0); -} - -static int aic7xxx_patch4_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch4_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) != 0); -} - -static int aic7xxx_patch3_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch3_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_TWIN) != 0); -} - -static int aic7xxx_patch2_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch2_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) == 0); -} - -static int aic7xxx_patch1_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch1_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) != 0); -} - -static int aic7xxx_patch0_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch0_func(struct aic7xxx_host *p) -{ - return (0); -} - -struct sequencer_patch { - int (*patch_func)(struct aic7xxx_host *); - unsigned int begin :10, - skip_instr :10, - skip_patch :12; -} sequencer_patches[] = { - { aic7xxx_patch1_func, 3, 2, 1 }, - { aic7xxx_patch2_func, 7, 1, 1 }, - { aic7xxx_patch2_func, 8, 1, 1 }, - { aic7xxx_patch3_func, 11, 4, 1 }, - { aic7xxx_patch4_func, 16, 3, 2 }, - { aic7xxx_patch0_func, 19, 4, 1 }, - { aic7xxx_patch5_func, 23, 1, 1 }, - { aic7xxx_patch6_func, 26, 1, 1 }, - { aic7xxx_patch1_func, 29, 1, 2 }, - { aic7xxx_patch0_func, 30, 3, 1 }, - { aic7xxx_patch3_func, 39, 4, 1 }, - { aic7xxx_patch7_func, 43, 3, 2 }, - { aic7xxx_patch0_func, 46, 3, 1 }, - { aic7xxx_patch8_func, 52, 7, 1 }, - { aic7xxx_patch3_func, 60, 3, 1 }, - { aic7xxx_patch7_func, 63, 2, 1 }, - { aic7xxx_patch7_func, 102, 1, 2 }, - { aic7xxx_patch0_func, 103, 2, 1 }, - { aic7xxx_patch7_func, 107, 2, 1 }, - { aic7xxx_patch9_func, 109, 1, 1 }, - { aic7xxx_patch10_func, 110, 2, 1 }, - { aic7xxx_patch7_func, 113, 1, 2 }, - { aic7xxx_patch0_func, 114, 1, 1 }, - { aic7xxx_patch1_func, 118, 1, 1 }, - { aic7xxx_patch1_func, 121, 3, 2 }, - { aic7xxx_patch0_func, 124, 5, 1 }, - { aic7xxx_patch1_func, 132, 2, 3 }, - { aic7xxx_patch7_func, 132, 1, 1 }, - { aic7xxx_patch0_func, 134, 3, 1 }, - { aic7xxx_patch11_func, 138, 1, 2 }, - { aic7xxx_patch0_func, 139, 1, 1 }, - { aic7xxx_patch7_func, 140, 7, 2 }, - { aic7xxx_patch0_func, 147, 1, 1 }, - { aic7xxx_patch1_func, 152, 14, 3 }, - { aic7xxx_patch11_func, 165, 1, 1 }, - { aic7xxx_patch0_func, 166, 9, 1 }, - { aic7xxx_patch7_func, 180, 2, 1 }, - { aic7xxx_patch7_func, 182, 1, 1 }, - { aic7xxx_patch11_func, 183, 6, 3 }, - { aic7xxx_patch1_func, 183, 2, 2 }, - { aic7xxx_patch0_func, 185, 4, 1 }, - { aic7xxx_patch7_func, 190, 1, 1 }, - { aic7xxx_patch7_func, 194, 20, 1 }, - { aic7xxx_patch1_func, 215, 3, 3 }, - { aic7xxx_patch11_func, 217, 1, 1 }, - { aic7xxx_patch0_func, 218, 5, 1 }, - { aic7xxx_patch11_func, 223, 1, 2 }, - { aic7xxx_patch0_func, 224, 9, 1 }, - { aic7xxx_patch12_func, 240, 1, 2 }, - { aic7xxx_patch0_func, 241, 1, 1 }, - { aic7xxx_patch4_func, 302, 1, 2 }, - { aic7xxx_patch0_func, 303, 1, 1 }, - { aic7xxx_patch2_func, 306, 1, 1 }, - { aic7xxx_patch1_func, 316, 3, 2 }, - { aic7xxx_patch0_func, 319, 5, 1 }, - { aic7xxx_patch12_func, 327, 1, 2 }, - { aic7xxx_patch0_func, 328, 1, 1 }, - { aic7xxx_patch5_func, 333, 1, 1 }, - { aic7xxx_patch11_func, 375, 15, 1 }, - { aic7xxx_patch1_func, 427, 7, 2 }, - { aic7xxx_patch0_func, 434, 8, 1 }, - { aic7xxx_patch1_func, 443, 4, 2 }, - { aic7xxx_patch0_func, 447, 6, 1 }, - { aic7xxx_patch1_func, 453, 4, 2 }, - { aic7xxx_patch0_func, 457, 3, 1 }, - { aic7xxx_patch10_func, 467, 10, 1 }, - { aic7xxx_patch1_func, 486, 17, 4 }, - { aic7xxx_patch9_func, 494, 4, 2 }, - { aic7xxx_patch0_func, 498, 2, 1 }, - { aic7xxx_patch0_func, 503, 33, 1 }, - { aic7xxx_patch10_func, 536, 4, 1 }, - { aic7xxx_patch5_func, 540, 2, 1 }, - { aic7xxx_patch5_func, 543, 9, 1 }, - -}; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c --- v2.2.18/drivers/scsi/atp870u.c Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/atp870u.c Sun Mar 25 11:37:36 2001 @@ -10,6 +10,7 @@ * support atp876 chip * enable 32 bit fifo transfer * support cdrom & remove device run ultra speed + * fix disconnect bug 2000/12/21 */ #include @@ -76,6 +77,7 @@ unsigned char dirctu; unsigned char devspu; unsigned char devtypeu; + unsigned char devlcmdu; unsigned long prdaddru; unsigned long tran_lenu; unsigned long last_lenu; @@ -143,14 +145,6 @@ tmport -= 0x08; i = inb(tmport); - if ((j & 0x40) == 0) - { - if ((dev->last_cmd & 0x40) == 0) - { - dev->last_cmd = 0xff; - } - } - else dev->last_cmd |= 0x40; tmport -= 0x02; target_id = inb(tmport); @@ -166,8 +160,21 @@ target_id &= 0x07; } + if ((j & 0x40) != 0) + { + if (dev->last_cmd == 0xff) + { + dev->last_cmd = target_id; + } + dev->last_cmd |= 0x40; + } + if (i == 0x85) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } /* * Flip wide */ @@ -196,6 +203,10 @@ } if (i == 0x21) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } tmport -= 0x05; adrcntu = 0; ((unsigned char *) &adrcntu)[2] = inb(tmport++); @@ -221,6 +232,10 @@ tmport += 0x0d; lun = inb(tmport) & 0x07; } else { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } if (j == 0x41) { tmport += 0x02; @@ -251,6 +266,10 @@ return; } } + if (dev->last_cmd != 0xff) + { + dev->last_cmd |= 0x40; + } tmport = workportu + 0x10; outb(0x45, tmport); tmport += 0x06; @@ -371,12 +390,20 @@ workrequ = dev->id[target_id].curr_req; if (i == 0x42) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } errstus = 0x02; workrequ->result = errstus; goto go_42; } if (i == 0x16) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } errstus = 0; tmport -= 0x08; errstus = inb(tmport); @@ -387,13 +414,13 @@ */ spin_lock_irqsave(&io_request_lock, flags); (*workrequ->scsi_done) (workrequ); - spin_unlock_irqrestore(&io_request_lock, flags); /* * Clear it off the queue */ dev->id[target_id].curr_req = 0; dev->working--; + spin_unlock_irqrestore(&io_request_lock, flags); /* * Take it back wide */ @@ -411,11 +438,15 @@ if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && (dev->in_snd == 0)) { - send_s870(h); + send_s870(h); } dev->in_int = 0; return; } + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } if (i == 0x4f) { i = 0x89; } @@ -480,7 +511,7 @@ int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *)) { - unsigned char i, h; + unsigned char h; unsigned long flags; unsigned short int m; unsigned int tmport; @@ -522,6 +553,8 @@ /* * Count new command */ + save_flags(flags); + cli(); dev->quendu++; if (dev->quendu >= qcnt) { dev->quendu = 0; @@ -529,18 +562,17 @@ /* * Check queue state */ -wait_que_empty: if (dev->quhdu == dev->quendu) { - goto wait_que_empty; + if (dev->quendu == 0) { + dev->quendu = qcnt; + } + dev->quendu--; + req_p->result = 0x00020000; + done(req_p); + restore_flags(flags); + return 0; } - save_flags(flags); - cli(); dev->querequ[dev->quendu] = req_p; - if (dev->quendu == 0) { - i = qcnt - 1; - } else { - i = dev->quendu - 1; - } tmport = dev->ioport + 0x1c; restore_flags(flags); if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) { @@ -593,6 +625,12 @@ return ; } } + if ((dev->last_cmd != 0xff) && (dev->working != 0)) + { + dev->in_snd = 0; + restore_flags(flags); + return ; + } dev->working++; j = dev->quhdu; dev->quhdu++; @@ -626,6 +664,7 @@ restore_flags(flags); return; oktosend: + dev->id[workrequ->target].devlcmdu=0; memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len); if (dev->ata_cdbu[0] == READ_CAPACITY) { if (workrequ->request_bufflen > 8) { @@ -635,15 +674,6 @@ if (dev->ata_cdbu[0] == 0x00) { workrequ->request_bufflen = 0; } - /* - * Why limit this ???? - */ - if (dev->ata_cdbu[0] == INQUIRY) { - if (workrequ->request_bufflen > 0x24) { - workrequ->request_bufflen = 0x24; - dev->ata_cdbu[4] = 0x24; - } - } tmport = workportu + 0x1b; j = 0; @@ -735,6 +765,7 @@ } else { dev->last_cmd |= 0x40; } + dev->id[target_id].devlcmdu=dev->last_cmd; dev->in_snd = 0; restore_flags(flags); return; @@ -809,6 +840,7 @@ } else { dev->last_cmd |= 0x40; } + dev->id[target_id].devlcmdu=dev->last_cmd; dev->in_snd = 0; restore_flags(flags); return; @@ -821,6 +853,7 @@ } else { dev->last_cmd |= 0x40; } + dev->id[target_id].devlcmdu=dev->last_cmd; dev->in_snd = 0; restore_flags(flags); return; @@ -1751,7 +1784,7 @@ if (chip_ver[h] > 0x07) /* check if atp876 chip */ { /* then enable terminator */ tmport = base_io + 0x3e; - outb(0x30, tmport); + outb(0x00, tmport); } tmport = base_io + 0x3a; @@ -1812,7 +1845,8 @@ int atp870u_abort(Scsi_Cmnd * SCpnt) { - unsigned char h, j; + unsigned char h, j, k; + Scsi_Cmnd *workrequ; unsigned int tmport; struct atp_unit *dev; for (h = 0; h <= admaxu; h++) { @@ -1839,12 +1873,27 @@ printk(" r22=%2x", inb(tmport)); tmport += 0x18; printk(" r3a=%2x \n",inb(tmport)); + for(j=0;j<16;j++) + { + if (dev->id[j].curr_req != NULL) + { + workrequ = dev->id[j].curr_req; + printk("\n que cdb= "); + for (k=0; k < workrequ->cmd_len; k++) + { + printk(" %2x ",workrequ->cmnd[k]); + } + printk(" last_lenu= %x ",dev->id[j].last_lenu); + printk(" dev_lcmd= %x ",dev->id[j].devlcmdu); + } + } return (SCSI_ABORT_SNOOZE); } int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) { unsigned char h; + struct atp_unit *dev; /* * See if a bus reset was suggested. */ @@ -1855,6 +1904,7 @@ } panic("Reset bus host not found !"); find_host: + dev=&atp_unit[h]; /* SCpnt->result = 0x00080000; SCpnt->scsi_done(SCpnt); dev->working=0; @@ -1868,7 +1918,7 @@ { static char buffer[128]; - strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.1+ac "); + strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.3+ac "); return buffer; } @@ -1913,7 +1963,7 @@ if (offset == 0) { memset(buff, 0, sizeof(buff)); } - size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.1+ac\n"); + size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.3+ac\n"); len += size; pos = begin + len; size = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/cpqfc.Readme linux/drivers/scsi/cpqfc.Readme --- v2.2.18/drivers/scsi/cpqfc.Readme Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/cpqfc.Readme Sun Mar 25 11:37:36 2001 @@ -6,6 +6,11 @@ 33 and 66MHz. Only supports FC-AL. SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() max of 128k bytes contiguous. + +Ver 1.3.6 Feb 27, 2001 + Added Target_Device_Reset function for SCSI error handling + Fixed problem with not reseting addressing mode after implicit logout + Ver 1.3.4 Sep 7, 2000 Added Modinfo information Fixed problem with statically linking the driver @@ -212,5 +217,5 @@ Send questions/comments to: -donald.zimmerman@compaq.com -dszimmerman@yahoo.com +Amy Vanzant-Hodge (fibrechannel@compaq.com) + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/cpqfcTS.h linux/drivers/scsi/cpqfcTS.h --- v2.2.18/drivers/scsi/cpqfcTS.h Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/cpqfcTS.h Sun Mar 25 11:37:36 2001 @@ -5,11 +5,13 @@ // These functions are required by the Linux SCSI layers extern int cpqfcTS_detect(Scsi_Host_Template *); extern int cpqfcTS_release(struct Scsi_Host *); -const char * cpqfcTS_info(struct Scsi_Host *); +extern const char * cpqfcTS_info(struct Scsi_Host *); extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int); extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); extern int cpqfcTS_abort(Scsi_Cmnd *); extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int); +extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd); +extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *); extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]); extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg); @@ -24,8 +26,10 @@ proc_info: cpqfcTS_proc_info, \ ioctl: cpqfcTS_ioctl, \ queuecommand: cpqfcTS_queuecommand, \ - eh_abort_handler: cpqfcTS_abort, \ + eh_device_reset_handler: cpqfcTS_eh_device_reset, \ + eh_abort_handler: cpqfcTS_eh_abort, \ reset: cpqfcTS_reset, \ + abort: cpqfcTS_abort, \ bios_param: cpqfcTS_biosparam, \ can_queue: CPQFCTS_REQ_QUEUE_LEN, \ this_id: -1, \ @@ -33,7 +37,8 @@ cmd_per_lun: CPQFCTS_CMD_PER_LUN, \ present: 0, \ unchecked_isa_dma: 0, \ - use_clustering: ENABLE_CLUSTERING \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 1 \ } #endif /* CPQFCTS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c --- v2.2.18/drivers/scsi/cpqfcTSinit.c Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/cpqfcTSinit.c Sun Mar 25 11:37:36 2001 @@ -61,10 +61,13 @@ #include "cpqfcTS.h" +#include #include /* Embedded module documentation macros - see module.h */ MODULE_AUTHOR("Compaq Computer Corporation"); MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA"); + +int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags); // This struct was originally defined in // /usr/src/linux/include/linux/proc_fs.h @@ -312,7 +315,6 @@ HostAdapter->max_id = 0; // incremented as devices log in HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses? - HostAdapter->hostt->use_new_eh_code = 1; // new error handling // get the pointer to our HBA specific data... (one for // each HBA on the PCI bus(ses)). @@ -410,9 +412,12 @@ // slowest(worst) case, measured on 1Gb Finisar GT analyzer int wait_time; + unsigned long flags=0; + + spin_unlock_irqrestore(&io_request_lock, flags); for( wait_time = jiffies + 4*HZ; wait_time > jiffies; ) schedule(); // (our worker task needs to run) - + spin_lock_irqsave(&io_request_lock, flags); } NumberOfAdapters++; @@ -454,7 +459,7 @@ Scsi_Cmnd *ScsiPassThruCmnd; unsigned long flags; - ENTER("cpqfcTS_ioctl"); + printk(" Enter cpqfcTS_ioctl "); // can we find an FC device mapping to this SCSI target? DumCmnd.channel = ScsiDev->channel; // For searching @@ -472,6 +477,7 @@ else // we know what FC device to operate on... { + printk("ioctl CMND %d", Cmnd); switch (Cmnd) { // Passthrough provides a mechanism to bypass the RAID @@ -653,6 +659,17 @@ put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]); break; + + + case SCSI_IOCTL_FC_TDR: + + result = cpqfcTS_TargetDeviceReset( ScsiDev, 0); + + break; + + + + default: result = -EINVAL; break; @@ -1347,13 +1364,20 @@ int cpqfcTS_abort(Scsi_Cmnd *Cmnd) { + printk(" cpqfcTS_abort called?? \n"); + return 0; +} + +int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd) +{ + struct Scsi_Host *HostAdapter = Cmnd->host; // get the pointer to our Scsi layer HBA buffer CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; PTACHYON fcChip = &cpqfcHBAdata->fcChip; FC_EXCHANGES *Exchanges = fcChip->Exchanges; int i; - ENTER("cpqfcTS_abort"); + ENTER("cpqfcTS_eh_abort"); Cmnd->result = DID_ABORT <<16; // assume we'll find it @@ -1439,28 +1463,116 @@ Done: // panic("_abort"); - LEAVE("cpqfcTS_abort"); + LEAVE("cpqfcTS_eh_abort"); return 0; // (see scsi.h) } +// FCP-SCSI Target Device Reset +// See dpANS Fibre Channel Protocol for SCSI +// X3.269-199X revision 12, pg 25 + +int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, + unsigned int reset_flags) +{ + int timeout = 10*HZ; + int retries = 1; + char scsi_cdb[12]; + unsigned long flags; + int result; + Scsi_Cmnd * SCpnt; + Scsi_Device * SDpnt; -// To be done... -int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) -{ - int return_status = SUCCESS; + // printk(" ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags); - ENTER("cpqfcTS_reset"); + if (ScsiDev->host->eh_active) return FAILED; + memset( scsi_cdb, 0, sizeof( scsi_cdb)); - + scsi_cdb[0] = RELEASE; - LEAVE("cpqfcTS_reset"); - return return_status; -} + spin_lock_irqsave(&io_request_lock, flags); + SCpnt = scsi_allocate_device(NULL, ScsiDev, 1); + { + struct semaphore sem = MUTEX_LOCKED; + + SCpnt->SCp.buffers_residual = FCP_TARGET_RESET; + SCpnt->request.sem = &sem; + scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries); + spin_unlock_irqrestore(&io_request_lock, flags); + down(&sem); + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->request.sem = NULL; + } + +/* + if(driver_byte(SCpnt->result) != 0) + switch(SCpnt->sense_buffer[2] & 0xf) { + case ILLEGAL_REQUEST: + if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; + else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); + break; + case NOT_READY: // This happens if there is no disc in drive + if(dev->removable && (cmd[0] != TEST_UNIT_READY)){ + printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); + break; + } + case UNIT_ATTENTION: + if (dev->removable){ + dev->changed = 1; + SCpnt->result = 0; // This is no longer considered an error + // gag this error, VFS will log it anyway /axboe + // printk(KERN_INFO "Disc change detected.\n"); + break; + }; + default: // Fall through for non-removable media + printk("SCSI error: host %d id %d lun %d return code = %x\n", + dev->host->host_no, + dev->id, + dev->lun, + SCpnt->result); + printk("\tSense class %x, sense error %x, extended sense %x\n", + sense_class(SCpnt->sense_buffer[0]), + sense_error(SCpnt->sense_buffer[0]), + SCpnt->sense_buffer[2] & 0xf); + + }; +*/ + result = SCpnt->result; + + SDpnt = SCpnt->device; + scsi_release_command(SCpnt); + SCpnt = NULL; + + if (!SDpnt->was_reset && SDpnt->scsi_request_fn) + (*SDpnt->scsi_request_fn)(); + + wake_up(&SDpnt->device_wait); + spin_unlock_irqrestore(&io_request_lock, flags); + // printk(" LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n"); + return SUCCESS; +} + + +int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd) +{ + Scsi_Device *SDpnt = Cmnd->device; + // printk(" ENTERING cpqfcTS_eh_device_reset() \n"); + return cpqfcTS_TargetDeviceReset( SDpnt, 0); +} + + +int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) +{ + + ENTER("cpqfcTS_reset"); + + LEAVE("cpqfcTS_reset"); + return SCSI_RESET_ERROR; /* Bus Reset Not supported */ +} /* This function determines the bios parameters for a given harddisk. These tend to be numbers that are made up by the @@ -1805,7 +1917,7 @@ #ifdef MODULE -Scsi_Host_Template driver_template = CPQFCTS; +static Scsi_Host_Template driver_template = CPQFCTS; #include "scsi_module.c" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/cpqfcTSstructs.h linux/drivers/scsi/cpqfcTSstructs.h --- v2.2.18/drivers/scsi/cpqfcTSstructs.h Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/cpqfcTSstructs.h Sun Mar 25 11:37:36 2001 @@ -31,7 +31,7 @@ #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) #define VER_MAJOR 1 #define VER_MINOR 3 -#define VER_SUBMINOR 4 +#define VER_SUBMINOR 6 // Macros for kernel (esp. SMP) tracing using a PCI analyzer // (e.g. x86). @@ -244,6 +244,7 @@ #define ELS_RJT 0x1000000 #define SCSI_REPORT_LUNS 0x0A0 #define REPORT_LUNS 0xA0 // SCSI-3 command op-code +#define FCP_TARGET_RESET 0x200 #define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c --- v2.2.18/drivers/scsi/cpqfcTSworker.c Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/cpqfcTSworker.c Sun Mar 25 11:37:36 2001 @@ -149,7 +149,6 @@ CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs); - // (see scsi_error.c comments on kernel task creation) void cpqfcTSWorkerThread( void *host) @@ -1069,6 +1068,7 @@ pFcPort->flogi = FALSE; pFcPort->LOGO_timer = 0; pFcPort->device_blocked = TRUE; // block Scsi Requests + pFcPort->ScsiNexus.VolumeSetAddressing=0; } @@ -2934,7 +2934,6 @@ ULONG ulStatus; UCHAR *ucBuff; - if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn { printk("Discard Q'd ReportLun command\n"); @@ -2976,7 +2975,7 @@ Cmnd->channel = pLoggedInPort->ScsiNexus.channel; Cmnd->target = pLoggedInPort->ScsiNexus.target; - + ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, @@ -3404,7 +3403,7 @@ if( port_id_valid ) // look for alpa first { if( pLoggedInPort->port_id == port_id ) - break; // found it! + break; // found it! } if( wwn_valid ) // look for wwn second { @@ -4326,7 +4325,6 @@ break; - case BLS_ABTS: // FC defined basic link service command ABTS // Abort Sequence @@ -4498,6 +4496,7 @@ // Fibre Channel SCSI 'originator' sequences... // (originator means 'initiator' in FCP-SCSI) + case SCSI_IWE: // TachLite Initiator Write Entry { PFC_LOGGEDIN_PORT pLoggedInPort = @@ -6171,7 +6170,18 @@ // 4 bytes Control Field FCP_CNTL *payload++ = 0; // byte 0: (MSB) reserved *payload++ = 0; // byte 1: task codes - *payload++ = 0; // byte 2: task management flags + + // byte 2: task management flags + // another "use" of the spare field to accomplish TDR + // note combination needed + if( (Cmnd->cmnd[0] == RELEASE) && + (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) ) + { + Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR + *payload++ = 0x20; // target device reset bit + } + else + *payload++ = 0; // no TDR // byte 3: (LSB) execution management codes // bit 0 write, bit 1 read (don't set together) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h --- v2.2.18/drivers/scsi/dc390.h Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/dc390.h Sun Mar 25 11:37:36 2001 @@ -4,9 +4,7 @@ * Description: Device Driver for Tekram DC-390(T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ -/* $Id: dc390.h,v 2.12 1998/12/25 17:33:27 garloff Exp $ */ - -#include +/* $Id: dc390.h,v 2.43.2.22 2000/12/20 00:39:36 garloff Exp $ */ /* * DC390/AMD 53C974 driver, header file @@ -15,12 +13,27 @@ #ifndef DC390_H #define DC390_H +#include +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + #define DC390_BANNER "Tekram DC390/AM53C974" -#define DC390_VERSION "2.0d 1998/12/25" +#define DC390_VERSION "2.0f 2000-12-20" -#if defined(HOSTS_C) || defined(MODULE) +/* We don't have eh_abort_handler, eh_device_reset_handler, + * eh_bus_reset_handler, eh_host_reset_handler yet! + * So long: Use old exception handling :-( */ +#define OLD_EH -#include +#if LINUX_VERSION_CODE < KERNEL_VERSION (2,1,70) || defined (OLD_EH) +# define NEW_EH +#else +# define NEW_EH use_new_eh_code: 1, +# define USE_NEW_EH +#endif + +#if defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99) extern int DC390_detect(Scsi_Host_Template *psht); extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); @@ -34,9 +47,29 @@ # define DC390_release NULL #endif -extern struct proc_dir_entry DC390_proc_scsi_tmscsim; extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) +#define DC390_T { \ + proc_name: "tmscsim", \ + proc_info: DC390_proc_info, \ + name: DC390_BANNER " V" DC390_VERSION, \ + detect: DC390_detect, \ + release: DC390_release, \ + queuecommand: DC390_queue_command, \ + abort: DC390_abort, \ + reset: DC390_reset, \ + bios_param: DC390_bios_param, \ + can_queue: 42, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 16, \ + NEW_EH \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING \ + } +#else +extern struct proc_dir_entry DC390_proc_scsi_tmscsim; #define DC390_T { \ proc_dir: &DC390_proc_scsi_tmscsim, \ proc_info: DC390_proc_info, \ @@ -47,13 +80,15 @@ abort: DC390_abort, \ reset: DC390_reset, \ bios_param: DC390_bios_param, \ - can_queue: 17, \ + can_queue: 42, \ this_id: 7, \ sg_tablesize: SG_ALL, \ - cmd_per_lun: 8, \ + cmd_per_lun: 16, \ + NEW_EH \ + unchecked_isa_dma: 0, \ use_clustering: DISABLE_CLUSTERING \ } - +#endif #endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* DC390_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.2.18/drivers/scsi/gdth.c Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/gdth.c Sun Mar 25 11:37:36 2001 @@ -20,9 +20,19 @@ * along with this kernel; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * - * Tested with Linux 1.2.13, ..., 2.2.16, ..., 2.4.0-test4 * + * Tested with Linux 1.2.13, ..., 2.2.16, ..., 2.4.0-test10 * * * * $Log: gdth.c,v $ + * Revision 1.45 2000/11/16 12:02:24 achim + * Changes for kernel 2.4 + * + * Revision 1.44 2000/10/11 08:44:10 achim + * Clustering changes: New flag media_changed added + * + * Revision 1.43 2000/09/20 12:59:01 achim + * DPMEM remap functions for all PCI controller types implemented + * Small changes for ia64 platform + * * Revision 1.42 2000/07/20 09:04:50 achim * Small changes for kernel 2.4 * @@ -180,7 +190,7 @@ * Initial revision * ************************************************************************/ -#ident "$Id: gdth.c,v 1.42 2000/07/20 09:04:50 achim Exp $" +#ident "$Id: gdth.c,v 1.45 2000/11/16 12:02:24 achim Exp $" /* All GDT Disk Array Controllers are fully supported by this driver. * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the @@ -1111,8 +1121,51 @@ printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); return 0; } + /* check and reset interface area */ dp6_ptr = (gdt6_dpram_str *)ha->brd; - /* reset interface area */ + gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); + if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) { + printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", + pcistr->dpmem); + found = FALSE; + for (i = 0xC8000; i < 0xE8000; i += 0x4000) { + gdth_munmap(ha->brd); + ha->brd = gdth_mmap(i, sizeof(ushort)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + if (gdth_readw(ha->brd) != 0xffff) { + TRACE2(("init_pci_old() address 0x%x busy\n", i)); + continue; + } + gdth_munmap(ha->brd); +#if LINUX_VERSION_CODE >= 0x2015C + pci_write_config_dword(pcistr->pdev, + PCI_BASE_ADDRESS_0, i); +#else + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_BASE_ADDRESS_0, i); +#endif + ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + dp6_ptr = (gdt6_dpram_str *)ha->brd; + gdth_writel(DPMEM_MAGIC, &dp6_ptr->u); + if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) { + printk("GDT-PCI: Use free address at 0x%x\n", i); + found = TRUE; + break; + } + } + if (!found) { + printk("GDT-PCI: No free address found!\n"); + gdth_munmap(ha->brd); + return 0; + } + } memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u)); if (gdth_readl(&dp6_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); @@ -1181,8 +1234,51 @@ gdth_munmap(ha->brd); return 0; } + /* check and reset interface area */ dp6c_ptr = (gdt6c_dpram_str *)ha->brd; - /* reset interface area */ + gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); + if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) { + printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", + pcistr->dpmem); + found = FALSE; + for (i = 0xC8000; i < 0xE8000; i += 0x4000) { + gdth_munmap(ha->brd); + ha->brd = gdth_mmap(i, sizeof(ushort)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + if (gdth_readw(ha->brd) != 0xffff) { + TRACE2(("init_pci_plx() address 0x%x busy\n", i)); + continue; + } + gdth_munmap(ha->brd); +#if LINUX_VERSION_CODE >= 0x2015C + pci_write_config_dword(pcistr->pdev, + PCI_BASE_ADDRESS_2, i); +#else + pcibios_write_config_dword(pcistr->bus, pcistr->device_fn, + PCI_BASE_ADDRESS_2, i); +#endif + ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str)); + if (ha->brd == NULL) { + printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); + return 0; + } + dp6c_ptr = (gdt6c_dpram_str *)ha->brd; + gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u); + if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) { + printk("GDT-PCI: Use free address at 0x%x\n", i); + found = TRUE; + break; + } + } + if (!found) { + printk("GDT-PCI: No free address found!\n"); + gdth_munmap(ha->brd); + return 0; + } + } memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u)); if (gdth_readl(&dp6c_ptr->u) != 0) { printk("GDT-PCI: Initialization error (DPMEM write error)\n"); @@ -1741,6 +1837,7 @@ register gdth_ha_str *ha; ushort cdev_cnt, i; ulong32 bus_no, drv_cnt, drv_no, j; + unsigned long flags; gdth_getch_str *chn; gdth_drlist_str *drl; gdth_iochan_str *ioc; @@ -1765,6 +1862,7 @@ #ifdef GDTH_RTC /* read realtime clock info, send to controller */ /* 1. wait for the falling edge of update flag */ + spin_lock_irqsave(&rtc_lock, flags) for (j = 0; j < 1000000; ++j) if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) break; @@ -1776,6 +1874,7 @@ for (j = 0; j < 12; ++j) rtc[j] = CMOS_READ(j); } while (rtc[0] != CMOS_READ(0)); + spin_unlock_irqrestore(&rtc_lock, flags); TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0], *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8])); /* 3. send to controller firmware */ @@ -1966,7 +2065,6 @@ TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n")); /* set/get features raw service (scatter/gather) */ - ha->raw_feat = 0; if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER, 0,0)) { TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n")); @@ -2061,18 +2159,14 @@ TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", hdrive,ha->info)); ha->hdr[hdrive].cluster_type = (unchar)ha->info; - } else { - ha->hdr[hdrive].cluster_type = 0; - } + } /* R/W attributes */ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) { TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", hdrive,ha->info)); ha->hdr[hdrive].rw_attribs = (unchar)ha->info; - } else { - ha->hdr[hdrive].rw_attribs = 0; - } + } return 1; } @@ -2264,10 +2358,14 @@ TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n", nscp->cmnd[0], b, t, nscp->lun)); nscp->result = DID_BAD_TARGET << 16; - GDTH_UNLOCK_HA(ha,flags); - /* io_request_lock already active ! */ - nscp->scsi_done(nscp); - GDTH_LOCK_HA(ha,flags); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } } else { switch (nscp->cmnd[0]) { case TEST_UNIT_READY: @@ -2280,7 +2378,24 @@ TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0], nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], nscp->cmnd[4],nscp->cmnd[5])); - if (gdth_internal_cache_cmd(hanum,nscp)) { + if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) { + /* return UNIT_ATTENTION */ + TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", + nscp->cmnd[0], t)); + ha->hdr[t].media_changed = FALSE; + memset((char*)nscp->sense_buffer,0,16); + nscp->sense_buffer[0] = 0x70; + nscp->sense_buffer[2] = UNIT_ATTENTION; + nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } + } else if (gdth_internal_cache_cmd(hanum,nscp)) { GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ nscp->scsi_done(nscp); @@ -2325,7 +2440,24 @@ case WRITE_6: case READ_10: case WRITE_10: - if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) + if (ha->hdr[t].media_changed) { + /* return UNIT_ATTENTION */ + TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", + nscp->cmnd[0], t)); + ha->hdr[t].media_changed = FALSE; + memset((char*)nscp->sense_buffer,0,16); + nscp->sense_buffer[0] = 0x70; + nscp->sense_buffer[2] = UNIT_ATTENTION; + nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + if (!nscp->SCp.have_data_in) + nscp->SCp.have_data_in++; + else { + GDTH_UNLOCK_HA(ha,flags); + /* io_request_lock already active ! */ + nscp->scsi_done(nscp); + GDTH_LOCK_HA(ha,flags); + } + } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t))) this_cmd = FALSE; break; @@ -2471,6 +2603,7 @@ TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0])); break; } + scp->result = DID_OK << 16; scp->sense_buffer[0] = 0; @@ -2487,7 +2620,8 @@ register gdth_ha_str *ha; register gdth_cmd_str *cmdp; struct scatterlist *sl; - ushort i; + ushort i, cnt; + ulong32 no; int cmd_index, read_write; ha = HADATA(gdth_ctr_tab[hanum]); @@ -2543,11 +2677,13 @@ if (read_write) { if (scp->cmd_len != 6) { - cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]); - cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]); + memcpy(&no, &scp->cmnd[2], sizeof(ulong32)); + cmdp->u.cache.BlockNo = ntohl(no); + memcpy(&cnt, &scp->cmnd[7], sizeof(ushort)); + cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt); } else { - cmdp->u.cache.BlockNo = - ntohl(*(ulong32*)&scp->cmnd[0]) & 0x001fffffUL; + memcpy(&no, &scp->cmnd[0], sizeof(ulong32)); + cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL; cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; } @@ -2660,7 +2796,7 @@ cmdp->u.raw.lun = l; cmdp->u.raw.bus = b; cmdp->u.raw.priority = 0; - cmdp->u.raw.link_p = NULL; + cmdp->u.raw.link_p = 0; cmdp->u.raw.sdlen = scp->request_bufflen; cmdp->u.raw.sense_len = 16; cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer); @@ -2825,6 +2961,7 @@ e->first_stamp = e->last_stamp = tv.tv_sec; e->same_count = 1; e->event_data = *evt; + e->application = 0; } return e; } @@ -3195,36 +3332,28 @@ if (!(ha->hdr[scp->target].cluster_type & CLUSTER_MOUNTED)) { /* NOT MOUNTED -> MOUNT */ - if (!(ha->hdr[scp->target].cluster_type & - CLUSTER_RESERVED)) { - /* cluster drive NOT RESERVED */ - scp->SCp.Status = GDT_MOUNT; - } else { + scp->SCp.Status = GDT_MOUNT; + if (ha->hdr[scp->target].cluster_type & + CLUSTER_RESERVED) { /* cluster drive RESERVED (on the other node) */ - scp->SCp.Status = GDT_MOUNT; scp->SCp.phase = -2; /* reservation conflict */ } } else { scp->SCp.Status = -1; } - /* retry */ - scp->SCp.this_residual = HIGH_PRI; - return 2; - } else if (scp->SCp.Status == GDT_MOUNT) { - ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED; - scp->SCp.Status = -1; - /* return UNIT_ATTENTION */ - memset((char*)scp->sense_buffer,0,16); - scp->sense_buffer[0] = 0x70; - scp->sense_buffer[2] = UNIT_ATTENTION; - scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - scp->SCp.Message = (int)(ha->info<<16|S_BSY); - } else { + } else { + if (scp->SCp.Status == GDT_MOUNT) { + ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED; + ha->hdr[scp->target].media_changed = TRUE; + } else if (scp->SCp.Status == GDT_UNMOUNT) { + ha->hdr[scp->target].cluster_type &= ~CLUSTER_MOUNTED; + ha->hdr[scp->target].media_changed = TRUE; + } scp->SCp.Status = -1; - /* retry */ - scp->SCp.this_residual = HIGH_PRI; - return 2; } + /* retry */ + scp->SCp.this_residual = HIGH_PRI; + return 2; } else { /* RESERVE/RELEASE ? */ if (scp->cmnd[0] == RESERVE) { @@ -3259,12 +3388,6 @@ scp->sense_buffer[0] = 0x70; scp->sense_buffer[2] = NOT_READY; scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - } else if (scp->cmnd[0] == RESERVE || - scp->cmnd[0] == RELEASE) { - memset((char*)scp->sense_buffer,0,16); - scp->sense_buffer[0] = 0x70; - scp->sense_buffer[2] = NOT_READY; - scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); } else if (service == CACHESERVICE) { if (ha->status == S_CACHE_UNKNOWN && (ha->hdr[scp->target].cluster_type & @@ -3293,7 +3416,7 @@ } } else { /* sense buffer filled from controller firmware (DMA) */ - if (ha->status!=S_RAW_SCSI || ha->info>=0x100) { + if (ha->status != S_RAW_SCSI || ha->info >= 0x100) { scp->result = DID_BAD_TARGET << 16; } else { scp->result = (DID_OK << 16) | ha->info; @@ -4467,8 +4590,12 @@ } } - +#if LINUX_VERSION_CODE < 0x020400 #ifdef MODULE +Scsi_Host_Template driver_template = GDTH; +#include "scsi_module.c" +#endif +#else Scsi_Host_Template driver_template = GDTH; #include "scsi_module.c" #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/gdth.h linux/drivers/scsi/gdth.h --- v2.2.18/drivers/scsi/gdth.h Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/gdth.h Sun Mar 25 11:37:36 2001 @@ -10,7 +10,7 @@ * * * - * $Id: gdth.h,v 1.33 2000/07/24 09:29:25 achim Exp $ + * $Id: gdth.h,v 1.35 2000/10/11 08:42:38 achim Exp $ */ #include @@ -29,9 +29,9 @@ /* defines, macros */ /* driver version */ -#define GDTH_VERSION_STR "1.23" +#define GDTH_VERSION_STR "1.25" #define GDTH_VERSION 1 -#define GDTH_SUBVERSION 23 +#define GDTH_SUBVERSION 25 /* protocol version */ #define PROTOCOL_VERSION 1 @@ -625,7 +625,7 @@ unchar priority; /* only 0 used */ ulong32 sense_len; /* sense data length */ ulong32 sense_data; /* sense data addr. */ - struct raw *link_p; /* linked cmds (not supp.) */ + ulong32 link_p; /* linked cmds (not supp.) */ ulong32 sg_ranz; /* s/g element count */ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ } PACKED raw; /* raw service cmd. struct. */ @@ -877,7 +877,7 @@ Scsi_Cmnd *req_first; /* top of request queue */ struct { unchar present; /* Flag: host drive present? */ - unchar is_logdrv; /* Flag: logical drive (master)? */ + unchar is_logdrv; /* Flag: log. drive (master)? */ unchar is_arraydrv; /* Flag: array drive? */ unchar is_master; /* Flag: array drive master? */ unchar is_parity; /* Flag: parity drive? */ @@ -891,7 +891,7 @@ unchar ldr_no; /* log. drive no. */ unchar rw_attribs; /* r/w attributes */ unchar cluster_type; /* cluster properties */ - unchar reserved; + unchar media_changed; /* Flag:MOUNT/UNMOUNT occured */ ulong32 start_sec; /* start sector */ } hdr[MAX_LDRIVES]; /* host drives */ struct { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/gdth_ioctl.h linux/drivers/scsi/gdth_ioctl.h --- v2.2.18/drivers/scsi/gdth_ioctl.h Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/gdth_ioctl.h Sun Mar 25 11:37:36 2001 @@ -2,7 +2,7 @@ #define _GDTH_IOCTL_H /* gdth_ioctl.h - * $Id: gdth_ioctl.h,v 1.6 2000/07/24 09:29:43 achim Exp $ + * $Id: gdth_ioctl.h,v 1.7 2000/10/11 08:43:35 achim Exp $ */ /* IOCTLs */ @@ -19,6 +19,7 @@ #define GDTIOCTL_SCSI (GDTIOCTL_MASK | 9) /* SCSI command */ #define GDTIOCTL_RESET_BUS (GDTIOCTL_MASK |10) /* reset SCSI bus */ #define GDTIOCTL_RESCAN (GDTIOCTL_MASK |11) /* rescan host drives */ +#define GDTIOCTL_RESET_DRV (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */ #define GDTIOCTL_MAGIC 0xaffe0003UL #define EVENT_SIZE 294 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/gdth_proc.c linux/drivers/scsi/gdth_proc.c --- v2.2.18/drivers/scsi/gdth_proc.c Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/gdth_proc.c Sun Mar 25 11:37:36 2001 @@ -1,5 +1,5 @@ /* gdth_proc.c - * $Id: gdth_proc.c,v 1.22 2000/07/24 09:30:28 achim Exp $ + * $Id: gdth_proc.c,v 1.23 2000/10/11 08:43:11 achim Exp $ */ #include "gdth_ioctl.h" @@ -524,6 +524,30 @@ gdth_analyse_hdrive(hanum, k); gdth_polling = FALSE; GDTH_UNLOCK_HA(ha, flags); + break; + + case GDTIOCTL_RESET_DRV: + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) )) + return(-EBUSY); + piord = (gdth_iord_str *)ha->pscratch; + piord->size = sizeof(gdth_iord_str); + piord->status = S_OK; + i = piowr->iu.scsi.target; + if (ha->hdr[i].present) { + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_CLUST_RESET; + gdtcmd.u.cache.DeviceNo = i; + gdtcmd.u.cache.BlockNo = 0; + gdtcmd.u.cache.sg_canz = 0; +#if LINUX_VERSION_CODE >= 0x020322 + gdth_do_cmd(scp, &gdtcmd, cmnd, 30); + piord->status = (ulong32)scp->SCp.Message; +#else + gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); + piord->status = (ulong32)scp.SCp.Message; +#endif + } break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.2.18/drivers/scsi/hosts.c Sun Mar 25 11:28:29 2001 +++ linux/drivers/scsi/hosts.c Sun Mar 25 11:37:36 2001 @@ -136,7 +136,7 @@ #endif #ifdef CONFIG_SCSI_AIC7XXX -#include "aic7xxx.h" +#include "aic7xxx/aic7xxx.h" #endif #ifdef CONFIG_SCSI_IPS @@ -897,6 +897,9 @@ #endif #ifdef CONFIG_CHR_DEV_ST scsi_register_device(&st_template); +#endif +#ifdef CONFIG_CHR_DEV_OSST + scsi_register_device(&osst_template); #endif #ifdef CONFIG_CHR_DEV_SG scsi_register_device(&sg_template); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.2.18/drivers/scsi/hosts.h Sun Mar 25 11:13:00 2001 +++ linux/drivers/scsi/hosts.h Sun Mar 25 11:37:36 2001 @@ -458,6 +458,7 @@ extern struct Scsi_Device_Template sd_template; extern struct Scsi_Device_Template st_template; +extern struct Scsi_Device_Template osst_template; extern struct Scsi_Device_Template sr_template; extern struct Scsi_Device_Template sg_template; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c --- v2.2.18/drivers/scsi/i60uscsi.c Sun Mar 25 11:13:03 2001 +++ linux/drivers/scsi/i60uscsi.c Sun Mar 25 11:37:36 2001 @@ -765,10 +765,10 @@ if (inia100_adpt[i].ADPT_BIOS < wBIOS) continue; if (inia100_adpt[i].ADPT_BIOS == wBIOS) { - if (inia100_adpt[i].ADPT_BASE == wBASE) + if (inia100_adpt[i].ADPT_BASE == wBASE) { if (inia100_adpt[i].ADPT_Bus != 0xFF) return (FAILURE); - else if (inia100_adpt[i].ADPT_BASE < wBASE) + } else if (inia100_adpt[i].ADPT_BASE < wBASE) continue; } for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h --- v2.2.18/drivers/scsi/i60uscsi.h Sun Mar 25 11:13:03 2001 +++ linux/drivers/scsi/i60uscsi.h Sun Mar 25 11:37:36 2001 @@ -78,6 +78,14 @@ #define U32 unsigned long #endif +#ifndef VIRT_TO_BUS +#define VIRT_TO_BUS(x) (unsigned long)virt_to_bus((void *) x) +#endif + +#ifndef VIRT_TO_BUS +#define VIRT_TO_BUS(x) (unsigned int)virt_to_bus((void *) x) +#endif + #ifndef NULL #define NULL 0 /* zero */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/osst.c linux/drivers/scsi/osst.c --- v2.2.18/drivers/scsi/osst.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/osst.c Sun Mar 25 11:37:36 2001 @@ -0,0 +1,5184 @@ +/* + SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying + file README.st for more information. + + History: + + OnStream SCSI Tape support (osst) cloned from st.c by + Willem Riede (osst@riede.org) Feb 2000 + Fixes ... Kurt Garloff Mar 2000 + + Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. + Contribution and ideas from several people including (in alphabetical + order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, + Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. + + Copyright 1992 - 2000 Kai Makisara + email Kai.Makisara@metla.fi + + $Header: /home/cvsroot/Driver/osst.c,v 1.28.2.12.2.1 2000/12/15 20:36:12 garloff Exp $ + + Last modified: Wed Feb 2 22:04:05 2000 by makisara@kai.makisara.local + Some small formal changes - aeb, 950809 +*/ + +static const char * cvsid = "$Id: osst.c,v 1.28.2.12.2.1 2000/12/15 20:36:12 garloff Exp $"; +const char * osst_version = "0.8.6.1"; + +/* The "failure to reconnect" firmware bug */ +#define OSST_FW_NEED_POLL_MIN 10602 /*(107A)*/ +#define OSST_FW_NEED_POLL_MAX 10708 /*(108D)*/ +#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The driver prints some debugging information on the console if DEBUG + is defined and non-zero. */ +#define DEBUG 0 + +/* The message level for the debug messages is currently set to KERN_NOTICE + so that people can easily see the messages. Later when the debugging messages + in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ +#define OSST_DEB_MSG KERN_NOTICE + +#define MAJOR_NR OSST_MAJOR +#include + +#include "scsi.h" +#include "hosts.h" +#include + +#define ST_KILOBYTE 1024 + +#include "st.h" +#include "osst.h" +#include "osst_options.h" +#include "osst_detect.h" + +#include "constants.h" + +#ifdef MODULE +MODULE_PARM(buffer_kbs, "i"); +MODULE_PARM(write_threshold_kbs, "i"); +MODULE_PARM(max_buffers, "i"); +MODULE_PARM(max_sg_segs, "i"); +static int buffer_kbs = 0; +static int write_threshold_kbs = 0; +static int max_buffers = 0; +static int max_sg_segs = 0; +#endif + +/* Some default definitions have been moved to osst_options.h */ +#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE) +#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE) + +/* The buffer size should fit into the 24 bits for length in the + 6-byte SCSI read and write commands. */ +#if OSST_BUFFER_SIZE >= (2 << 24 - 1) +#error "Buffer size should not exceed (2 << 24 - 1) bytes!" +#endif + +#if DEBUG +static int debugging = 1; +#endif + +#define MAX_RETRIES 0 +#define MAX_WRITE_RETRIES 0 +#define MAX_READY_RETRIES 5 +#define NO_TAPE NOT_READY + +#define OSST_TIMEOUT (200 * HZ) +#define OSST_LONG_TIMEOUT (1800 * HZ) + +#define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK)) +#define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) + +/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower + 24 bits) */ +#define SET_DENS_AND_BLK 0x10001 + +static int osst_nbr_buffers; +static OSST_buffer **osst_buffers; +static int osst_buffer_size = OSST_BUFFER_SIZE; +static int osst_write_threshold = OSST_WRITE_THRESHOLD; +static int osst_max_buffers = OSST_MAX_BUFFERS; +static int osst_max_sg_segs = OSST_MAX_SG; + +static OS_Scsi_Tape ** os_scsi_tapes = NULL; + +static int modes_defined = FALSE; + +static OSST_buffer *new_tape_buffer(int, int); +static int enlarge_buffer(OSST_buffer *, int, int); +static void normalize_buffer(OSST_buffer *); +static int append_to_buffer(const char *, OSST_buffer *, int); +static int from_buffer(OSST_buffer *, char *, int); +static int osst_zero_buffer_tail(OSST_buffer *); +static int osst_copy_to_buffer(OSST_buffer *, unsigned char *); +static int osst_copy_from_buffer(OSST_buffer *, unsigned char *); + +static int osst_init(void); +static int osst_attach(Scsi_Device *); +static int osst_detect(Scsi_Device *); +static void osst_detach(Scsi_Device *); + +struct Scsi_Device_Template osst_template = {NULL, "OnStream tape", "osst", NULL, TYPE_TAPE, + OSST_MAJOR, 0, 0, 0, 0, + osst_detect, osst_init, + NULL, osst_attach, osst_detach}; + +static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, unsigned int cmd_in,unsigned long arg); + +static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int frame, int skip); + +static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt); + +static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int file_blk); + +static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int pending); + + +/* Routines that handle the interaction with mid-layer SCSI routines */ + +/* Convert the result to success code */ +static int osst_chk_result(Scsi_Cmnd * SCpnt) +{ + int dev = TAPE_NR(SCpnt->request.rq_dev); + int result = SCpnt->result; + unsigned char * sense = SCpnt->sense_buffer, scode; +#if DEBUG + const char *stp; +#endif + + if (!result /* && SCpnt->sense_buffer[0] == 0 */ ) + return 0; + + if (driver_byte(result) & DRIVER_SENSE) + scode = sense[2] & 0x0f; + else { + sense[0] = 0; /* We don't have sense data if this byte is zero */ + scode = 0; + if ((sense[2] & 0x0f) == 1) + return 0; /* FIXME -- is this safe? */ + } + +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", + dev, result, + SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2], + SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5], + SCpnt->request_bufflen); + if (driver_byte(result) & DRIVER_SENSE) + print_sense("osst", SCpnt); + } + else +#endif + if (!(driver_byte(result) & DRIVER_SENSE) || + ((sense[0] & 0x70) == 0x70 && + scode != NO_SENSE && + scode != RECOVERED_ERROR && +/* scode != UNIT_ATTENTION && */ + scode != BLANK_CHECK && + scode != VOLUME_OVERFLOW && + SCpnt->data_cmnd[0] != MODE_SENSE && + SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ + if (driver_byte(result) & DRIVER_SENSE) { + printk(KERN_WARNING "osst%d: Error with sense data: ", dev); + print_sense("osst", SCpnt); + } + else + printk(KERN_WARNING + "osst%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", + dev, result, suggestion(result), driver_byte(result), + host_byte(result)); + } + + if ((sense[0] & 0x70) == 0x70 && + scode == RECOVERED_ERROR + ) { + os_scsi_tapes[dev]->recover_count++; + os_scsi_tapes[dev]->recover_erreg++; +#if DEBUG + if (debugging) { + if (SCpnt->data_cmnd[0] == READ_6) + stp = "read"; + else if (SCpnt->data_cmnd[0] == WRITE_6) + stp = "write"; + else + stp = "ioctl"; + printk(OSST_DEB_MSG "osst%d: Recovered %s error (%d).\n", dev, stp, + os_scsi_tapes[dev]->recover_count); + } +#endif + if ((sense[2] & 0xe0) == 0) + return 0; + } + return (-EIO); +} + + +/* Wakeup from interrupt */ +static void osst_sleep_done (Scsi_Cmnd * SCpnt) +{ + unsigned int st_nbr; + int remainder; + OS_Scsi_Tape * STp; + + if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) { + STp = os_scsi_tapes[st_nbr]; + if ((STp->buffer)->writing && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40)) { + /* EOM at write-behind, has all been written? */ + if ((SCpnt->sense_buffer[0] & 0x80) != 0) + remainder = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else + remainder = 0; + if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW || + remainder > 0) + (STp->buffer)->last_result = SCpnt->result; /* Error */ + else + (STp->buffer)->last_result = INT_MAX; /* OK */ + } + else + (STp->buffer)->last_result = SCpnt->result; + SCpnt->request.rq_status = RQ_SCSI_DONE; + (STp->buffer)->last_SCpnt = SCpnt; + +#if DEBUG + STp->write_pending = 0; +#endif + up(SCpnt->request.sem); + } +#if DEBUG + else if (debugging) + printk(KERN_ERR "osst?: Illegal interrupt device %x\n", st_nbr); +#endif +} + + +/* Do the scsi command. Waits until command performed if do_wait is true. + Otherwise osst_write_behind_check() is used to check that the command + has finished. */ +static Scsi_Cmnd * osst_do_scsi(Scsi_Cmnd *SCpnt, OS_Scsi_Tape *STp, + unsigned char *cmd, int bytes, int timeout, int retries, int do_wait) +{ + unsigned long flags; + unsigned char *bp; +//static int inject = 0; /* FIXME - take out inject occasional read errors */ +//static int repeat = 0; + spin_lock_irqsave(&io_request_lock, flags); + if (SCpnt == NULL) + if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) { + printk(KERN_ERR "osst%d: Can't get SCSI request.\n", TAPE_NR(STp->devt)); + spin_unlock_irqrestore(&io_request_lock, flags); + return NULL; + } + + cmd[1] |= (SCpnt->lun << 5) & 0xe0; + STp->sem = MUTEX_LOCKED; + SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ? + (STp->buffer)->use_sg : 0; + if (SCpnt->use_sg) { + bp = (char *)&((STp->buffer)->sg[0]); + if ((STp->buffer)->sg_segs < SCpnt->use_sg) + SCpnt->use_sg = (STp->buffer)->sg_segs; + } + else + bp = (STp->buffer)->b_data; + SCpnt->cmd_len = 0; + SCpnt->request.sem = &(STp->sem); + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.rq_dev = STp->devt; + + scsi_do_cmd(SCpnt, (void *)cmd, bp, bytes, + osst_sleep_done, timeout, retries); + spin_unlock_irqrestore(&io_request_lock, flags); + + if (do_wait) { + down(SCpnt->request.sem); + + (STp->buffer)->last_result_fatal = osst_chk_result(SCpnt); +//if ((STp->buffer)->last_result_fatal == 0 && +// cmd[0] == READ_6 && cmd[4] && ( /* (++ inject % 83) == 29 || */ +// (STp->first_frame_position == 240 /* or STp->read_error_frame to fail again on the block calculated above */ && ++repeat < 3))) { +// printk(OSST_DEB_MSG "osst%d: injecting read error\n", TAPE_NR(STp->devt)); +// STp->buffer->last_result_fatal = 1; /* FIXME - take out inject occasional read errors */ +//} + } + + return SCpnt; +} + + +/* Handle the write-behind checking (downs the semaphore) */ +static void osst_write_behind_check(OS_Scsi_Tape *STp) +{ + OSST_buffer * STbuffer; + ST_partstat * STps; + + STbuffer = STp->buffer; + +#if DEBUG + if (STp->write_pending) + STp->nbr_waits++; + else + STp->nbr_finished++; +#endif + + down(&(STp->sem)); + + (STp->buffer)->last_result_fatal = osst_chk_result((STp->buffer)->last_SCpnt); + + if ((STp->buffer)->last_result_fatal) + (STp->buffer)->last_result_fatal = + osst_write_error_recovery(STp, &((STp->buffer)->last_SCpnt), 1); + else + STp->first_frame_position++; + + scsi_release_command((STp->buffer)->last_SCpnt); + + if (STbuffer->writing < STbuffer->buffer_bytes) +#if 0 + memcpy(STbuffer->b_data, + STbuffer->b_data + STbuffer->writing, + STbuffer->buffer_bytes - STbuffer->writing); +#else + printk(KERN_WARNING "osst: write_behind_check: something left in buffer!\n"); +#endif + STbuffer->buffer_bytes -= STbuffer->writing; + STps = &(STp->ps[STp->partition]); + if (STps->drv_block >= 0) { + if (STp->block_size == 0) + STps->drv_block++; + else + STps->drv_block += STbuffer->writing / STp->block_size; + } + STbuffer->writing = 0; + + return; +} + + + +/* Onstream specific Routines */ +/* + * Initialize the OnStream AUX + */ +static void osst_init_aux(OS_Scsi_Tape * STp, int frame_type, int logical_blk_num) +{ + os_aux_t *aux = STp->buffer->aux; + os_partition_t *par = &aux->partition; + os_dat_t *dat = &aux->dat; + + if (STp->raw) return; + + memset(aux, 0, sizeof(*aux)); + aux->format_id = htonl(0); + memcpy(aux->application_sig, "LIN4", 4); + aux->hdwr = htonl(0); + aux->frame_type = frame_type; + + switch (frame_type) { + case OS_FRAME_TYPE_HEADER: + aux->update_frame_cntr = htonl(STp->update_frame_cntr); + par->partition_num = OS_CONFIG_PARTITION; + par->par_desc_ver = OS_PARTITION_VERSION; + par->wrt_pass_cntr = htons(0xffff); + /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */ + par->first_frame_ppos = htonl(0); + par->last_frame_ppos = htonl(0xbb7); + aux->frame_seq_num = htonl(0); + aux->logical_blk_num_high = htonl(0); + aux->logical_blk_num = htonl(0); + aux->next_mark_ppos = htonl(STp->first_mark_ppos); + break; + case OS_FRAME_TYPE_DATA: + case OS_FRAME_TYPE_MARKER: + dat->dat_sz = 8; + dat->reserved1 = 0; + dat->entry_cnt = 1; + dat->reserved3 = 0; + dat->dat_list[0].blk_sz = htonl(frame_type==OS_FRAME_TYPE_DATA?STp->block_size:0); + dat->dat_list[0].blk_cnt = htons(1); + dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA; + dat->dat_list[0].reserved = 0; + case OS_FRAME_TYPE_EOD: + aux->update_frame_cntr = htonl(0); + par->partition_num = OS_DATA_PARTITION; + par->par_desc_ver = OS_PARTITION_VERSION; + par->wrt_pass_cntr = htons(STp->wrt_pass_cntr); + par->first_frame_ppos = htonl(STp->first_data_ppos); + par->last_frame_ppos = htonl(STp->capacity); + aux->frame_seq_num = htonl(logical_blk_num); + aux->logical_blk_num_high = htonl(0); + aux->logical_blk_num = htonl(logical_blk_num); + break; + default: ; /* probably FILL */ + } + aux->filemark_cnt = ntohl(STp->filemark_cnt); /* FIXME -- violates ADR spec */ + aux->phys_fm = ntohl(0xffffffff); + aux->last_mark_ppos = ntohl(STp->last_mark_ppos); +} + +/* + * Verify that we have the correct tape frame + */ +static int osst_verify_frame(OS_Scsi_Tape * STp, int logical_blk_num, int quiet) +{ + os_aux_t * aux = STp->buffer->aux; + os_partition_t * par = &(aux->partition); + ST_partstat * STps = &(STp->ps[STp->partition]); + int i; + int dev = TAPE_NR(STp->devt); + + if (STp->raw) { + if (STp->buffer->last_result_fatal) { + for (i=0; i < STp->buffer->sg_segs; i++) + memset(STp->buffer->sg[i].address, 0, STp->buffer->sg[i].length); + strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); + } + return 1; + } + if (STp->buffer->last_result_fatal) { + printk(KERN_INFO "osst%d: Skipping frame, read error\n", dev); + return 0; + } + if (ntohl(aux->format_id) != 0) { + printk(KERN_INFO "osst%d: Skipping frame, format_id %u\n", dev, ntohl(aux->format_id)); + return 0; + } + if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 && + (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) { + printk(KERN_INFO "osst%d: Skipping frame, incorrect application signature\n", dev); + return 0; + } + if (par->partition_num != OS_DATA_PARTITION) { + if (!STp->linux_media || STp->linux_media_version != 2) { + printk(KERN_INFO "osst%d: Skipping frame, partition num %d\n", dev, par->partition_num); return 0; + } + } + if (par->par_desc_ver != OS_PARTITION_VERSION) { + printk(KERN_INFO "osst%d: Skipping frame, partition version %d\n", dev, par->par_desc_ver); + return 0; + } + if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) { + printk(KERN_INFO "osst%d: Skipping frame, wrt_pass_cntr %d (expected %d)\n", + dev, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr); + return 0; + } + if (aux->frame_seq_num != aux->logical_blk_num) { + printk(KERN_INFO "osst%d: Skipping frame, seq != logical\n", dev); + return 0; + } + if (aux->frame_type != OS_FRAME_TYPE_DATA && + aux->frame_type != OS_FRAME_TYPE_EOD && + aux->frame_type != OS_FRAME_TYPE_MARKER) { + if (!quiet) + printk(KERN_INFO "osst%d: Skipping frame, frame type %x\n", dev, aux->frame_type); + return 0; + } + if (aux->frame_type == OS_FRAME_TYPE_EOD && + STp->first_frame_position < STp->eod_frame_ppos) { + printk(KERN_INFO "osst%d: skipping premature EOD frame %d\n", dev, STp->first_frame_position); + return 0; + } + STp->logical_blk_in_buffer = 1; + + if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) { + if (!quiet) + printk(KERN_INFO "osst%d: Skipping frame, logical_blk_num %u (expected %d)\n", + dev, ntohl(aux->logical_blk_num), logical_blk_num); + return 0; + } + if (aux->frame_type == OS_FRAME_TYPE_MARKER) { + STps->eof = ST_FM_HIT; + + i = ntohl(aux->filemark_cnt); + if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt || + STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) { +#if 1 //DEBUG + printk(OSST_DEB_MSG "osst%i: %s filemark %d at frame %d\n", dev, + STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected", + i, STp->first_frame_position - 1); +#endif + STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1); + if (i >= STp->filemark_cnt) + STp->filemark_cnt = i+1; + } + } + if (aux->frame_type == OS_FRAME_TYPE_EOD) { + STps->eof = ST_EOD_1; + } + if (aux->frame_type == OS_FRAME_TYPE_DATA) { + STps->eof = ST_NOEOF; + } + return 1; +} + +/* + * Wait for the unit to become Ready + */ +static int osst_wait_ready(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, unsigned timeout) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt; + long startwait = jiffies; +#if DEBUG + int dbg = debugging; + int dev = TAPE_NR(STp->devt); + + printk(OSST_DEB_MSG "osst%d: reached onstream wait ready\n", dev); +#endif + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE); + *aSCpnt = SCpnt; + if (!SCpnt) return (-EBUSY); + + while ( SCpnt->sense_buffer[2] == 2 && SCpnt->sense_buffer[12] == 4 && + ( SCpnt->sense_buffer[13] == 1 || SCpnt->sense_buffer[13] == 8 ) && + time_before(jiffies, startwait + timeout*HZ) ) { +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d: Sleeping in onstream wait ready\n", dev); + printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev); + debugging = 0; + } +#endif + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ / 10); + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE); + } + *aSCpnt = SCpnt; +#if DEBUG + debugging = dbg; +#endif + if ( SCpnt->sense_buffer[2] && + osst_write_error_recovery(STp, aSCpnt, 0) ) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Abnormal exit from onstream wait ready\n", dev); +#endif + return (-EIO); + } +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Normal exit from onstream wait ready\n", dev); +#endif + return 0; +} + +static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int frame) +{ + int retval; + + osst_wait_ready(STp, aSCpnt, 15 * 60); /* TODO - can this catch a write error? */ + retval = osst_set_frame_position(STp, aSCpnt, frame, 0); + if (retval) return (retval); + osst_wait_ready(STp, aSCpnt, 15 * 60); + return (osst_get_frame_position(STp, aSCpnt)); +} + +/* + * Wait for write(s) to complete + */ +static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt; + + int result = 0; +#if DEBUG + int dev = TAPE_NR(STp->devt); + + printk(OSST_DEB_MSG "osst%d: Reached onstream flush drive buffer (write filemark)\n", dev); +#endif + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = WRITE_FILEMARKS; + cmd[1] = 1; + + SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES, TRUE); + *aSCpnt = SCpnt; + if (!SCpnt) return (-EBUSY); + + if ((STp->buffer)->last_result_fatal) + result = osst_write_error_recovery(STp, aSCpnt, 0); + + result |= osst_wait_ready(STp, aSCpnt, 5 * 60); + STp->ps[STp->partition].rw = ST_IDLE; + return (result); +} +/* +static int osst_buffer_stats[64]; + +static void osst_build_stats(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + unsigned int i; + + osst_get_frame_position (STp, aSCpnt); + i = STp->cur_frames > 63 ? 63 : STp->cur_frames; + osst_buffer_stats[i]++; +} + +static void osst_report_stats() +{ + unsigned int i; + + for (i=0; i<64; i+=8) { + printk(OSST_DEB_MSG "osst buffer stats %2d: %5d %5d %5d %5d %5d %5d %5d %5d\n", i, + osst_buffer_stats[i ], osst_buffer_stats[i+1], + osst_buffer_stats[i+2], osst_buffer_stats[i+3], + osst_buffer_stats[i+4], osst_buffer_stats[i+5], + osst_buffer_stats[i+6], osst_buffer_stats[i+7]); + } + +} +*/ +#define OSST_POLL_PER_SEC 10 +static int osst_wait_frame(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int curr, int minlast, int to) +{ + long startwait = jiffies; + int dev = TAPE_NR(STp->devt); +#if DEBUG + char notyetprinted = 1; +#endif + if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING) + printk(KERN_ERR "osst%i: waiting for frame without having initialized read!\n", dev); + + while (time_before (jiffies, startwait + to*HZ)) + { + int result; + result = osst_get_frame_position (STp, aSCpnt); + if (result == -EIO) + if ((result = osst_write_error_recovery(STp, aSCpnt, 0)) == 0) + return 0; /* successfull recovery leaves drive ready for frame */ + if (result < 0) break; + if (STp->first_frame_position == curr && + ((minlast < 0 && + (signed)STp->last_frame_position > (signed)curr + minlast) || + (minlast >= 0 && STp->cur_frames > minlast) + ) && result >= 0) + { +#if DEBUG + if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC) + printk ("osst%i: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", + dev, curr, curr+minlast, STp->first_frame_position, + STp->last_frame_position, STp->cur_frames, + result, (jiffies-startwait)/HZ, + (((jiffies-startwait)%HZ)*10)/HZ); +#endif + return 0; + } +#if DEBUG + if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted) + { + printk ("osst%i: Wait for frame %i (>%i): %i-%i %i (%i)\n", + dev, curr, curr+minlast, STp->first_frame_position, + STp->last_frame_position, STp->cur_frames, result); + notyetprinted--; + } +#endif + current->state = TASK_INTERRUPTIBLE; + schedule_timeout (HZ / OSST_POLL_PER_SEC); + } +#if DEBUG + printk ("osst%i: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n", + dev, curr, curr+minlast, STp->first_frame_position, + STp->last_frame_position, STp->cur_frames, + (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ); +#endif + return -EBUSY; +} + +/* + * Read the next OnStream tape block at the current location + */ +static int osst_read_block(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int timeout) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt; + int retval = 0; +#if DEBUG + os_aux_t * aux = STp->buffer->aux; + int dev = TAPE_NR(STp->devt); +#endif + + /* TODO: Error handling */ + if (STp->poll) + retval = osst_wait_frame (STp, aSCpnt, STp->first_frame_position, 0, timeout); +#if 0// DEBUG + printk ("osst_read: wait for frame returned %i\n", retval); +#endif + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = READ_6; + cmd[1] = 1; + cmd[4] = 1; + +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%i: Reading block from OnStream tape\n", dev); +#endif + SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout, MAX_RETRIES, TRUE); + *aSCpnt = SCpnt; + if (!SCpnt) + return (-EBUSY); + + if ((STp->buffer)->last_result_fatal) { + retval = 1; + if (STp->read_error_frame == 0) { + STp->read_error_frame = STp->first_frame_position; + printk(OSST_DEB_MSG "osst: recording read error at %d\n", STp->read_error_frame);/*FIXME*/ + } +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", + dev, + SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], + SCpnt->sense_buffer[2], SCpnt->sense_buffer[3], + SCpnt->sense_buffer[4], SCpnt->sense_buffer[5], + SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]); +#endif + } + else + STp->first_frame_position++; +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%i: AUX: %c%c%c%c UpdFrCt#%d %s FrSeq#%d LogBlk#%d\n", dev, + aux->application_sig[0], aux->application_sig[1], + aux->application_sig[2], aux->application_sig[3], ntohl(aux->update_frame_cntr), + aux->frame_type==1?"EOD":aux->frame_type==2?"MARK": + aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", + ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num) ); + if (aux->frame_type==2) + printk(OSST_DEB_MSG "osst%i: mark_cnt=%d, last_mark=%d, next_mark=%d\n", dev, + ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->next_mark_ppos)); + printk(OSST_DEB_MSG "osst%i: Exit read block from OnStream tape with code %d\n", dev, retval); + } +#endif + return (retval); +} + +static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + ST_partstat * STps = &(STp->ps[STp->partition]); + Scsi_Cmnd * SCpnt ; + unsigned char cmd[MAX_COMMAND_SIZE]; + int retval = 0; +#if DEBUG + int dev = TAPE_NR(STp->devt); +#endif + + if (STps->rw != ST_READING) { /* Initialize read operation */ + if (STps->rw == ST_WRITING) { + osst_flush_write_buffer(STp, aSCpnt, 1); + osst_flush_drive_buffer(STp, aSCpnt); + } + STps->rw = ST_READING; + STp->logical_blk_in_buffer = 0; + + /* + * Issue a read 0 command to get the OnStream drive + * read blocks into its buffer. + */ + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = READ_6; + cmd[1] = 1; + +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Start Read Ahead on OnStream tape\n", dev); +#endif + SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE); + *aSCpnt = SCpnt; + retval = STp->buffer->last_result_fatal; + } + + return retval; +} + +static int osst_get_logical_blk(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int logical_blk_num, int quiet) +{ + ST_partstat * STps = &(STp->ps[STp->partition]); + int dev = TAPE_NR(STp->devt); + int cnt = 0, + bad = 0, + past = 0, + x, + position; + + /* + * Search and wait for the next logical tape block + */ + while (1) { + if (cnt++ > 400) { + printk(KERN_WARNING "osst%d: Couldn't find logical block %d, aborting\n", + dev, logical_blk_num); + if (STp->read_error_frame) { + osst_set_frame_position(STp, aSCpnt, STp->read_error_frame, 0); +#if 1 //DEBUG + printk(OSST_DEB_MSG "osst%d: Repositioning tape to bad block %d\n", + dev, STp->read_error_frame); +#endif + STp->read_error_frame = 0; + } + return (-EIO); + } +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Looking for block %d, attempt %d\n", + dev, logical_blk_num, cnt); +#endif + if ( osst_initiate_read(STp, aSCpnt) + || ( (!STp->logical_blk_in_buffer) && osst_read_block(STp, aSCpnt, 30) ) ) { + position = osst_get_frame_position(STp, aSCpnt); + if (position >= 0xbae && position < 0xbb8) + position = 0xbb8; + else if (position > STp->eod_frame_ppos || ++bad == 10) { +printk(OSST_DEB_MSG "osst%d: start again from pos %d, eod %d, bad %d\n", dev, position, STp->eod_frame_ppos, bad); /*FIXME*/ + position = STp->read_error_frame - 1; + } + else { + position += 39; + cnt += 20; + } +#if 1 //DEBUG + printk(OSST_DEB_MSG "osst%d: Bad block detected, positioning tape to block %d\n", + dev, position); +#endif + osst_set_frame_position(STp, aSCpnt, position, 0); + continue; + } + if (osst_verify_frame(STp, logical_blk_num, quiet)) + break; + if (osst_verify_frame(STp, -1, quiet)) { + x = ntohl(STp->buffer->aux->logical_blk_num); + if (STp->fast_open) { +#if 1 //DEBUG + printk(OSST_DEB_MSG "osst%d: Found logical block %d instead of %d after fast open\n", + dev, x, logical_blk_num); +#endif + STp->header_ok = 0; + STp->read_error_frame = 0; + return (-EIO); + } + if (x > logical_blk_num) { + if (++past > 3) { + /* positioning backwards did not bring us to the desired block */ + position = STp->read_error_frame - 1; + } + else + position = osst_get_frame_position(STp, aSCpnt) + + logical_blk_num - x - 1; +#if 1 //DEBUG + printk(OSST_DEB_MSG + "osst%d: Found logical block %d while looking for %d: back up %d\n", + dev, x, logical_blk_num, + STp->first_frame_position - position); +#endif + osst_set_frame_position(STp, aSCpnt, position, 0); + cnt += 10; + } + else + past = 0; + } + if (osst_get_frame_position(STp, aSCpnt) == 0xbaf) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Skipping config partition\n", dev); +#endif + osst_set_frame_position(STp, aSCpnt, 0xbb8, 0); + cnt--; + } + STp->logical_blk_in_buffer = 0; + } + if (cnt > 1) { + STp->recover_count++; + STp->recover_erreg++; + } + STp->logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num); + +#if DEBUG + if (debugging || STps->eof) + printk(OSST_DEB_MSG "osst%i: Exit get logical block (%d=>%d) from OnStream tape with code %d\n", dev, logical_blk_num, STp->logical_blk_num, STps->eof); +#endif + STp->fast_open = FALSE; + STp->read_error_frame = 0; + return (STps->eof); +} + +static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int logical_blk_num) +{ + int estimate; + int retries = 0; + int dev = TAPE_NR(STp->devt); + + if (logical_blk_num < 0) logical_blk_num = 0; + /* FIXME -- this may not be valid for foreign formats */ + if (logical_blk_num < 2980) estimate = logical_blk_num + 10; + else estimate = logical_blk_num + 20; + +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Seeking logical block %d (now at %d)\n", + dev, logical_blk_num, STp->logical_blk_num); +#endif + while (++retries < 10) { + osst_set_frame_position(STp, aSCpnt, estimate, 0); + if (osst_get_logical_blk(STp, aSCpnt, logical_blk_num, 1) >= 0) + return 0; + if (osst_get_logical_blk(STp, aSCpnt, -1, 1) < 0) + goto error; + if (STp->logical_blk_num != logical_blk_num) + estimate += logical_blk_num - STp->logical_blk_num; + else + break; + } +error: + printk(KERN_WARNING "osst%d: Couldn't seek to logical block %d (at %d), %d retries\n", + dev, logical_blk_num, STp->logical_blk_num, retries); + return (-EIO); +} + +static int osst_seek_frame(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int frame) +{ + ST_partstat * STps = &(STp->ps[STp->partition]); + int r; + + if (frame < 0 || frame >= STp->capacity) return (-ENXIO); + + if (frame <= STp->first_data_ppos) { + STp->logical_blk_num = STps->drv_file = STps->drv_block = 0; + return (osst_set_frame_position(STp, aSCpnt, frame, 0)); + } + r = osst_set_frame_position(STp, aSCpnt, frame-1, 0); + if (r < 0) return r; + + r = osst_get_logical_blk(STp, aSCpnt, -1, 1); + if (r < 0) return r; + + if (osst_get_frame_position(STp, aSCpnt) != frame) return (-EIO); + + STp->logical_blk_num++; + STp->logical_blk_in_buffer = 0; + STps->drv_file = htonl(STp->buffer->aux->filemark_cnt); + STps->drv_block = -1; + STps->eof = ST_NOEOF; /* FIXME test for eod */ + return 0; +} + +/* + * Read back the drive's internal buffer contents, as a part + * of the write error recovery mechanism for old OnStream + * firmware revisions. + */ +static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, + unsigned int block, unsigned int skip, int pending) +{ + Scsi_Cmnd * SCpnt = * aSCpnt; + unsigned char * buffer, * p; + unsigned char cmd[MAX_COMMAND_SIZE]; + int frames, flag, new_block, i, logical_blk_num; + int dev = TAPE_NR(STp->devt); + long startwait = jiffies; +#if DEBUG + int dbg = debugging; +#endif + + frames = STp->cur_frames; + if ((buffer = (unsigned char *)vmalloc((frames + pending) * OS_DATA_SIZE)) == NULL) + return (-EIO); + + logical_blk_num = STp->logical_blk_num - frames - pending; + printk(KERN_INFO "osst%d: Reading back %d frames from drive buffer%s\n", + dev, frames, pending?" and one that was pending":""); + + if (pending) { + osst_copy_from_buffer(STp->buffer, (p = &buffer[frames * OS_DATA_SIZE])); +// memcpy((p = &buffer[frames * OS_DATA_SIZE]), STp->buffer->b_data, OS_DATA_SIZE); +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Pending logical block %d, data %x %x %x %x\n", + dev, logical_blk_num + frames, p[0], p[1], p[2], p[3]); +#endif + } + for (i = 0, p = buffer; i < frames; i++, p += OS_DATA_SIZE) { + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = 0x3C; /* Buffer Read */ + cmd[1] = 6; /* Retrieve Faulty Block */ + cmd[7] = 32768 >> 8; + cmd[8] = 32768 & 0xff; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout, MAX_RETRIES, TRUE); + + if ((STp->buffer)->last_result_fatal) { + printk(KERN_ERR "osst%d: Failed to read block back from OnStream buffer\n", dev); + vfree((void *)buffer); + *aSCpnt = SCpnt; + return (-EIO); + } + osst_copy_from_buffer(STp->buffer, p); +// memcpy(p, STp->buffer->b_data, OS_DATA_SIZE); +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Read back logical block %d, data %x %x %x %x\n", + dev, logical_blk_num + i, p[0], p[1], p[2], p[3]); +#endif + } + *aSCpnt = SCpnt; + osst_get_frame_position(STp, aSCpnt); + +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Frames left in buffer: %d\n", dev, STp->cur_frames); +#endif + /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */ + /* In the header we don't actually re-write the blocks that fail, just the ones after them */ + + for (flag=1, new_block=block, p=buffer, i=0; i < frames + pending; ) { + + if (flag) { + if (STp->write_type == OS_WRITE_HEADER) { + i += skip; + p += skip * OS_DATA_SIZE; + } + else if (new_block < 2990 && new_block+skip+frames+pending >= 2990) + new_block = 3000-i; + else + new_block += skip; +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Position to frame %d, write lblk %d\n", + dev, new_block+i, logical_blk_num+i); /* FIXME var blk sz */ +#endif + osst_set_frame_position(STp, aSCpnt, new_block + i, 0); + osst_wait_ready(STp, aSCpnt, 60); + osst_get_frame_position(STp, aSCpnt); + SCpnt = * aSCpnt; + + if (new_block > block + 1000) { + printk(KERN_ERR "osst%d: Failed to find valid tape media\n", dev); + vfree((void *)buffer); + return (-EIO); + } + flag = 0; + if ( i >= frames + pending ) break; + } + osst_copy_to_buffer(STp->buffer, p); +// memcpy(STp->buffer->b_data, p, OS_DATA_SIZE); + /* + * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type! + */ + osst_init_aux(STp, STp->buffer->aux->frame_type, logical_blk_num+i ); + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = WRITE_6; + cmd[1] = 1; + cmd[4] = 1; + +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: About to attempt to write to frame %d\n", dev, new_block+i); +#endif + SCpnt = osst_do_scsi(SCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout, MAX_WRITE_RETRIES, TRUE); + + if (STp->buffer->last_result_fatal) + flag = 1; + else { + p += OS_DATA_SIZE; i++; + + /* if we just sent the last frame, wait till all successfully written */ + if ( i == frames + pending ) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Check re-write successful\n", dev); +#endif + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = WRITE_FILEMARKS; + cmd[1] = 1; + SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES, TRUE); + +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d: Sleeping in re-write wait ready\n", dev); + printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev); + debugging = 0; + } +#endif + flag = STp->buffer->last_result_fatal; + while ( !flag && time_before(jiffies, startwait + 60*HZ) ) { + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, + MAX_READY_RETRIES, TRUE); + + if (SCpnt->sense_buffer[2] == 2 && SCpnt->sense_buffer[12] == 4 && + (SCpnt->sense_buffer[13] == 1 || SCpnt->sense_buffer[13] == 8)) { + /* in the process of becoming ready */ + schedule_timeout(HZ / 10); + continue; + } + if (STp->buffer->last_result_fatal) + flag = 1; + break; + } +#if DEBUG + debugging = dbg; + printk(OSST_DEB_MSG "osst%d: Wait re-write finished\n", dev); +#endif + } + } + if (flag) { + if ((SCpnt->sense_buffer[ 2] & 0x0f) == 13 && + SCpnt->sense_buffer[12] == 0 && + SCpnt->sense_buffer[13] == 2) { + printk(KERN_ERR "osst%d: Volume overflow in write error recovery\n", dev); + vfree((void *)buffer); + return (-EIO); /* hit end of tape = fail */ + } + i = ((SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6] ) - new_block; + p = &buffer[i * OS_DATA_SIZE]; +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Additional write error at %d\n", dev, new_block+i); +#endif + osst_get_frame_position(STp, aSCpnt); +#if DEBUG + printk(OSST_DEB_MSG "osst%d: reported frame positions: host = %d, tape = %d\n", + dev, STp->first_frame_position, STp->last_frame_position); +#endif + } + *aSCpnt = SCpnt; + } + vfree((void *)buffer); + return 0; +} + +static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, + unsigned int block, unsigned int skip, int pending) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt = * aSCpnt; + int dev = TAPE_NR(STp->devt); + int attempts = 1000 / skip; + int flag = 1; + long startwait = jiffies; +#if DEBUG + int dbg = debugging; +#endif + + while (attempts && time_before(jiffies, startwait + 60*HZ)) { + if (flag) { +#if DEBUG + debugging = dbg; +#endif + if (block < 2990 && block+skip+STp->cur_frames+pending >= 2990) + block = 3000-skip; +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Position to frame %d, re-write from lblk %d\n", + dev, block+skip, STp->logical_blk_num-STp->cur_frames-pending); +#endif + osst_set_frame_position(STp, aSCpnt, block + skip, 1); + flag = 0; + attempts--; + } + if (osst_get_frame_position(STp, aSCpnt) < 0) { /* additional write error */ +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Addl error, host %d, tape %d, buffer %d\n", + dev, STp->first_frame_position, + STp->last_frame_position, STp->cur_frames); +#endif + block = STp->last_frame_position; + flag = 1; + continue; + } + if (pending && STp->cur_frames < 50) { + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = WRITE_6; + cmd[1] = 1; + cmd[4] = 1; +#if DEBUG + printk(OSST_DEB_MSG "osst%d: About to write pending lblk %d at frame %d\n", + dev, STp->logical_blk_num-1, STp->first_frame_position); +#endif + SCpnt = osst_do_scsi(SCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout, + MAX_WRITE_RETRIES, TRUE); + *aSCpnt = SCpnt; + + if (STp->buffer->last_result_fatal) { /* additional write error */ + if ((SCpnt->sense_buffer[ 2] & 0x0f) == 13 && + SCpnt->sense_buffer[12] == 0 && + SCpnt->sense_buffer[13] == 2) { + printk(OSST_DEB_MSG + "osst%d: Volume overflow in write error recovery\n", + dev); + break; /* hit end of tape = fail */ + } + flag = 1; + } + else + pending = 0; + + continue; + } + if (STp->cur_frames == 0) { +#if DEBUG + debugging = dbg; + printk(OSST_DEB_MSG "osst%d: Wait re-write finished\n", dev); +#endif + return 0; + } +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d: Sleeping in re-write wait ready\n", dev); + printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev); + debugging = 0; + } +#endif + schedule_timeout(HZ / 10); + } + printk(KERN_ERR "osst%d: Failed to find valid tape media\n", dev); +#if DEBUG + debugging = dbg; +#endif + return (-EIO); +} + +/* + * Error recovery algorithm for the OnStream tape. + */ + +static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int pending) +{ + Scsi_Cmnd * SCpnt = * aSCpnt; + ST_partstat * STps = & STp->ps[STp->partition]; + int dev = TAPE_NR(STp->devt); + int retval = 0; + int rw_state; + unsigned int block, skip; + + rw_state = STps->rw; + + if ((SCpnt->sense_buffer[ 2] & 0x0f) != 3 + || SCpnt->sense_buffer[12] != 12 + || SCpnt->sense_buffer[13] != 0) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Write error recovery cannot handle %02x:%02x:%02x\n", + dev, SCpnt->sense_buffer[ 2], SCpnt->sense_buffer[12], SCpnt->sense_buffer[13]); +#endif + return (-EIO); + } + block = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; + skip = SCpnt->sense_buffer[9]; + +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Detected physical bad block at %u, advised to skip %d\n", dev, block, skip); +#endif + osst_get_frame_position(STp, aSCpnt); +#if DEBUG + printk(OSST_DEB_MSG "osst%d: reported frame positions: host = %d, tape = %d\n", + dev, STp->first_frame_position, STp->last_frame_position); +#endif + switch (STp->write_type) { + case OS_WRITE_DATA: + case OS_WRITE_EOD: + case OS_WRITE_NEW_MARK: + printk(KERN_WARNING "osst%d: Relocating %d buffered logical blocks to physical block %u\n", + dev, STp->cur_frames, block + skip); + if (STp->os_fw_rev >= 10600) + retval = osst_reposition_and_retry(STp, aSCpnt, block, skip, pending); + else + retval = osst_read_back_buffer_and_rewrite(STp, aSCpnt, block, skip, pending); + break; + case OS_WRITE_LAST_MARK: + printk(KERN_ERR "osst%d: Bad block in update last marker, fatal\n", dev); + osst_set_frame_position(STp, aSCpnt, block + STp->cur_frames + pending, 0); + retval = -EIO; + break; + case OS_WRITE_HEADER: + printk(KERN_WARNING "osst%d: Bad block in header partition, skipped\n", dev); + retval = osst_read_back_buffer_and_rewrite(STp, aSCpnt, block, 1, pending); + break; + default: + printk(KERN_WARNING "osst%d: Bad block in filler, ignored\n", dev); + osst_set_frame_position(STp, aSCpnt, block + STp->cur_frames + pending, 0); + } + osst_get_frame_position(STp, aSCpnt); +#if DEBUG + printk(KERN_ERR "osst%d: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", + dev, STp->cur_frames, STp->first_frame_position, STp->last_frame_position); + printk(OSST_DEB_MSG "osst%d: next logical block to write: %d\n", dev, STp->logical_blk_num); +#endif + if (retval == 0) { + STp->recover_count++; + STp->recover_erreg++; + } + STps->rw = rw_state; + return retval; +} + +static int osst_space_over_filemarks_backward(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int mt_op, int mt_count) +{ + int dev = TAPE_NR(STp->devt); + int cnt; + int last_mark_ppos = -1; + +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_backwards %d %d\n", dev, mt_op, mt_count); +#endif + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_bwd\n", dev); + return -EIO; + } + if (STp->linux_media_version >= 4) { + /* + * direct lookup in header filemark list + */ + cnt = ntohl(STp->buffer->aux->filemark_cnt); + if (STp->header_ok && + STp->header_cache != NULL && + (cnt - mt_count) >= 0 && + (cnt - mt_count) < OS_FM_TAB_MAX && + (cnt - mt_count) < STp->filemark_cnt && + STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos) + + last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]); +#if 1 //DEBUG + if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX) + printk(OSST_DEB_MSG "osst%i: Filemark lookup fail due to %s\n", dev, + STp->header_cache == NULL?"lack of header cache":"count out of range"); + else + printk(OSST_DEB_MSG "osst%i: Filemark lookup: prev mark %d (%s), skip %d to %d\n", dev, cnt, + ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || + (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == + STp->buffer->aux->last_mark_ppos))?"match":"error", + mt_count, last_mark_ppos); +#endif + if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { + osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0); + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev); + return (-EIO); + } + if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n", + dev, last_mark_ppos); + return (-EIO); + } + if (mt_op == MTBSFM) { + STp->logical_blk_num++; + STp->logical_blk_in_buffer = 0; + } + return 0; + } + printk(KERN_INFO "osst%i: Reverting to scan filemark backwards\n", dev); + } + cnt = 0; + while (cnt != mt_count) { + last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos); + if (last_mark_ppos == -1) + return (-EIO); +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Positioning to last mark at %d\n", dev, last_mark_ppos); +#endif + osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0); + cnt++; + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev); + return (-EIO); + } + if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "osst%i: expected to find marker at block %d, not found\n", dev, last_mark_ppos); + return (-EIO); + } + } + if (mt_op == MTBSFM) { + STp->logical_blk_num++; + STp->logical_blk_in_buffer = 0; + } + return 0; +} + +/* + * ADRL 1.1 compatible "slow" space filemarks fwd version + * + * Just scans for the filemark sequentially. + */ +static int osst_space_over_filemarks_forward_slow(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int mt_op, int mt_count) +{ + int dev = TAPE_NR(STp->devt); + int cnt = 0; + +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_forward_slow %d %d\n", dev, mt_op, mt_count); +#endif + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_fwd\n", dev); + return (-EIO); + } + while (1) { + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev); + return (-EIO); + } + if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) + cnt++; + if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: space_fwd: EOD reached\n", dev); +#endif + if (STp->first_frame_position > STp->eod_frame_ppos+1) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: EOD position corrected (%d=>%d)\n", + dev, STp->eod_frame_ppos, STp->first_frame_position-1); +#endif + STp->eod_frame_ppos = STp->first_frame_position-1; + } + return (-EIO); + } + if (cnt == mt_count) + break; + STp->logical_blk_in_buffer = 0; + } + if (mt_op == MTFSF) { + STp->logical_blk_num++; + STp->logical_blk_in_buffer = 0; + } + return 0; +} + +/* + * Fast linux specific version of OnStream FSF + */ +static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int mt_op, int mt_count) +{ + int dev = TAPE_NR(STp->devt); + int cnt = 0, + next_mark_ppos = -1; + +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_forward_fast %d %d\n", dev, mt_op, mt_count); +#endif + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_fwd\n", dev); + return (-EIO); + } + + if (STp->linux_media_version >= 4) { + /* + * direct lookup in header filemark list + */ + cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1; + if (STp->header_ok && + STp->header_cache != NULL && + (cnt + mt_count) < OS_FM_TAB_MAX && + (cnt + mt_count) < STp->filemark_cnt && + ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || + (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos))) + + next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]); +#if 1 //DEBUG + if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX) + printk(OSST_DEB_MSG "osst%i: Filemark lookup fail due to %s\n", dev, + STp->header_cache == NULL?"lack of header cache":"count out of range"); + else + printk(OSST_DEB_MSG "osst%i: Filemark lookup: prev mark %d (%s), skip %d to %d\n", dev, cnt, + ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || + (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == + STp->buffer->aux->last_mark_ppos))?"match":"error", + mt_count, next_mark_ppos); +#endif + if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) { + printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev); + return osst_space_over_filemarks_forward_slow(STp, aSCpnt, mt_op, mt_count); + } else { + osst_set_frame_position(STp, aSCpnt, next_mark_ppos, 0); + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev); + return (-EIO); + } + if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n", + dev, next_mark_ppos); + return (-EIO); + } + if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) { + printk(KERN_INFO "osst%i: Expected to find marker %d at block %d, not %d\n", + dev, cnt+mt_count, next_mark_ppos, + ntohl(STp->buffer->aux->filemark_cnt)); + return (-EIO); + } + } + } else { + /* + * Find nearest (usually previous) marker, then jump from marker to marker + */ + while (1) { + if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) + break; + if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: space_fwd: EOD reached\n", dev); +#endif + return (-EIO); + } + if (ntohl(STp->buffer->aux->filemark_cnt) == 0) { + if (STp->first_mark_ppos == -1) { + printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev); + return osst_space_over_filemarks_forward_slow(STp, aSCpnt, mt_op, mt_count); + } + osst_set_frame_position(STp, aSCpnt, STp->first_mark_ppos, 0); + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO + "osst%i: Couldn't get logical blk num in space_filemarks_fwd_fast\n", + dev); + return (-EIO); + } + if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "osst%i: Expected to find filemark at %d\n", + dev, STp->first_mark_ppos); + return (-EIO); + } + } else { + if (osst_space_over_filemarks_backward(STp, aSCpnt, MTBSF, 1) < 0) + return (-EIO); + mt_count++; + } + } + cnt++; + while (cnt != mt_count) { + next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos); + if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) { + printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev); + return osst_space_over_filemarks_forward_slow(STp, aSCpnt, mt_op, mt_count - cnt); + } +#if DEBUG + else printk(OSST_DEB_MSG "osst%i: Positioning to next mark at %d\n", dev, next_mark_ppos); +#endif + osst_set_frame_position(STp, aSCpnt, next_mark_ppos, 0); + cnt++; + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { + printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev); + return (-EIO); + } + if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n", + dev, next_mark_ppos); + return (-EIO); + } + } + } + if (mt_op == MTFSF) + STp->logical_blk_num++; + STp->logical_blk_in_buffer = 0; + return 0; +} + +/* + * In debug mode, we want to see as many errors as possible + * to test the error recovery mechanism. + */ +#if DEBUG +static void osst_set_retries(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int retries) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt = * aSCpnt; + int dev = TAPE_NR(STp->devt); + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SELECT; + cmd[1] = 0x10; + cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH; + + (STp->buffer)->b_data[0] = cmd[4] - 1; + (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ + (STp->buffer)->b_data[2] = 0; /* Reserved */ + (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7); + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries; + + if (debugging) + printk(OSST_DEB_MSG "osst%i: Setting number of retries on OnStream tape to %d\n", dev, retries); + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + *aSCpnt = SCpnt; + + if ((STp->buffer)->last_result_fatal) + printk (KERN_ERR "osst%d: Couldn't set retries to %d\n", dev, retries); +} +#endif + +#if 0 +static void osst_update_markers(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int last_mark_ppos, int this_mark_ppos) +{ + int dev = TAPE_NR(STp->devt); + int frame, + reslt; + + if (STp->raw) return; + + STp->last_mark_ppos = this_mark_ppos; + if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) + STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos); + if (STp->filemark_cnt++ == 0) + STp->first_mark_ppos = this_mark_ppos; + + if (STp->linux_media_version >= 4) return; + if (last_mark_ppos == -1) return; + + STp->write_type = OS_WRITE_LAST_MARK; + frame = osst_get_frame_position(STp, aSCpnt); +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Update last_marker at frame %d\n", dev, last_mark_ppos); + printk(OSST_DEB_MSG "osst%i: current position %d, lblk %d, tape blk %d\n", + dev, frame, STp->logical_blk_num, STp->last_frame_position); +#endif + osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0); + osst_initiate_read (STp, aSCpnt); + reslt = osst_read_block(STp, aSCpnt, 180); + + if (reslt) { + printk(KERN_WARNING "osst%i: couldn't read last marker\n", dev); + osst_set_frame_position(STp, aSCpnt, frame, 0); + return; + } + if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { + printk(KERN_WARNING "osst%i: expected marker at addr %d\n", dev, last_mark_ppos); + osst_set_frame_position(STp, aSCpnt, frame, 0); + return; + } +#if DEBUG + printk(OSST_DEB_MSG "osst%i: writing back marker\n", dev); +#endif + STp->buffer->aux->next_mark_ppos = htonl(this_mark_ppos); + osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0); + STp->dirty = 1; + if (osst_flush_write_buffer(STp, aSCpnt, 0) || + osst_flush_drive_buffer(STp, aSCpnt) ) { + printk(KERN_WARNING "osst%i: couldn't write marker back at addr %d\n", dev, last_mark_ppos); + } + osst_set_frame_position(STp, aSCpnt, frame, 0); + + return; /* FIXME -- errors should go back to user space */ +} +#endif + +static int osst_write_filemark(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + int result; + int this_mark_ppos; +#if DEBUG + int dev = TAPE_NR(STp->devt); +#endif + + if (STp->raw) return 0; + + STp->write_type = OS_WRITE_NEW_MARK; + this_mark_ppos = osst_get_frame_position(STp, aSCpnt); +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Writing Filemark %i at frame %d (lblk %d)\n", + dev, STp->filemark_cnt, this_mark_ppos, STp->logical_blk_num); +#endif + osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->logical_blk_num++); + STp->dirty = 1; + result = osst_flush_write_buffer(STp, aSCpnt, 0); + result |= osst_flush_drive_buffer(STp, aSCpnt); +//printk(OSST_DEB_MSG "osst%d: Finished writing file\n",TAPE_NR(STp->devt)); + STp->last_mark_ppos = this_mark_ppos; + if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) + STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos); + if (STp->filemark_cnt++ == 0) + STp->first_mark_ppos = this_mark_ppos; +// osst_update_markers(STp, aSCpnt, STp->last_mark_ppos, this_mark_ppos); + return result; +} + +static int osst_write_eod(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + int result; +#if DEBUG + int dev = TAPE_NR(STp->devt); +#endif + + if (STp->raw) return 0; + + STp->write_type = OS_WRITE_EOD; + STp->eod_frame_ppos = osst_get_frame_position(STp, aSCpnt); +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Writing EOD at %d=>%d\n", dev, STp->logical_blk_num, STp->eod_frame_ppos); +#endif + osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->logical_blk_num++); + STp->dirty = 1; + + result = osst_flush_write_buffer(STp, aSCpnt, 0); + result |= osst_flush_drive_buffer(STp, aSCpnt); + STp->eod_frame_lfa = --(STp->logical_blk_num); + return result; +} + +static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int block, int count) +{ + int dev = TAPE_NR(STp->devt); + +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Reached onstream write filler group %d\n", dev, block); +#endif + osst_wait_ready(STp, aSCpnt, 60 * 5); + osst_set_frame_position(STp, aSCpnt, block, 0); + STp->write_type = OS_WRITE_FILLER; + osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0); + while (count--) { + memcpy(STp->buffer->b_data, "Filler", 6); + STp->buffer->buffer_bytes = 6; + STp->dirty = 1; + if (osst_flush_write_buffer(STp, aSCpnt, 0)) { + printk(KERN_INFO "osst%i: Couldn't write filler frame\n", dev); + return (-EIO); + } + } +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Exiting onstream write filler group\n", dev); +#endif + return osst_flush_drive_buffer(STp, aSCpnt); +} + +static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int block, int count) +{ + int dev = TAPE_NR(STp->devt); + int result; + +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Reached onstream write header group %d\n", dev, block); +#endif + osst_wait_ready(STp, aSCpnt, 60 * 5); + osst_set_frame_position(STp, aSCpnt, block, 0); + STp->write_type = OS_WRITE_HEADER; + osst_init_aux(STp, OS_FRAME_TYPE_HEADER, STp->logical_blk_num); + while (count--) { + osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache); +// memcpy(STp->buffer->b_data, STp->header_cache, sizeof(os_header_t)); + STp->buffer->buffer_bytes = sizeof(os_header_t); + STp->dirty = 1; + if (osst_flush_write_buffer(STp, aSCpnt, 0)) { + printk(KERN_INFO "osst%i: Couldn't write header frame\n", dev); + return (-EIO); + } + } + result = osst_flush_drive_buffer(STp, aSCpnt); +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Write onstream header group %s\n", dev, result?"failed":"done"); +#endif + return result; +} + +static int osst_write_header(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int locate_eod) +{ + os_header_t * header; + int reslt ; + int dev = TAPE_NR(STp->devt); + +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Writing tape header\n", dev); +#endif + if (STp->raw) return 0; + + if (STp->header_cache == NULL) { + if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) { + printk(KERN_ERR "osst%i: Failed to allocate header cache\n", dev); + return (-ENOMEM); + } + memset(STp->header_cache, 0, sizeof(os_header_t)); +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Allocated and cleared memory for header cache\n", dev); +#endif + } + if (STp->header_ok) STp->update_frame_cntr++; + else STp->update_frame_cntr = 0; + + header = STp->header_cache; + strcpy(header->ident_str, "ADR_SEQ"); + header->major_rev = 1; + header->minor_rev = 4; + header->ext_trk_tb_off = htons(17192); + header->pt_par_num = 1; + header->partition[0].partition_num = OS_DATA_PARTITION; + header->partition[0].par_desc_ver = OS_PARTITION_VERSION; + header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr); + header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos); + header->partition[0].last_frame_ppos = htonl(STp->capacity); + header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos); + header->cfg_col_width = htonl(20); + header->dat_col_width = htonl(1500); + header->qfa_col_width = htonl(0); + header->ext_track_tb.nr_stream_part = 1; + header->ext_track_tb.et_ent_sz = 32; + header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0; + header->ext_track_tb.dat_ext_trk_ey.fmt = 1; + header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736); + header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0; + header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa); + header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos); + header->dat_fm_tab.fm_part_num = 0; + header->dat_fm_tab.fm_tab_ent_sz = 4; + header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cntfilemark_cnt:OS_FM_TAB_MAX); + + reslt = __osst_write_header(STp, aSCpnt, 0xbae, 5); + if (STp->update_frame_cntr == 0) + osst_write_filler(STp, aSCpnt, 0xbb3, 5); + reslt &= __osst_write_header(STp, aSCpnt, 5, 5); + + if (locate_eod) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: locating back to eod frame addr %d\n", dev, STp->eod_frame_ppos); +#endif + osst_set_frame_position(STp, aSCpnt, STp->eod_frame_ppos, 0); + } + if (reslt) + printk(KERN_WARNING "osst%i: write header failed\n", dev); + else { + memcpy(STp->application_sig, "LIN4", 4); + STp->linux_media = 1; + STp->linux_media_version = 4; + STp->header_ok = 1; + } + return reslt; +} + +static int osst_reset_header(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + if (STp->header_cache != NULL) + memset(STp->header_cache, 0, sizeof(os_header_t)); + + STp->logical_blk_num = 0; + STp->logical_blk_in_buffer = 0; + STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A; + STp->filemark_cnt = 0; + STp->first_mark_ppos = STp->last_mark_ppos = -1; + return osst_write_header(STp, aSCpnt, 1); +} + +static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int block) +{ + int dev = TAPE_NR(STp->devt); + os_header_t * header; + os_aux_t * aux; + char id_string[8]; + int linux_media_version, + update_frame_cntr; + + if (STp->raw) + return 1; + + if (block == 5 || block == 0xbae || STp->buffer->last_result_fatal) { + if (osst_set_frame_position(STp, aSCpnt, block, 0)) + printk(KERN_WARNING "osst%i: Couldn't position tape\n", dev); + if (osst_initiate_read (STp, aSCpnt)) { + printk(KERN_WARNING "osst%i: Couldn't initiate read\n", dev); + return 0; + } + } + if (osst_read_block(STp, aSCpnt, 180)) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Couldn't read header frame\n", dev); +#endif + return 0; + } + header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */ + aux = STp->buffer->aux; + if (aux->frame_type != OS_FRAME_TYPE_HEADER) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Skipping non-header frame (%d)\n", dev, block); +#endif + return 0; + } + if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 && + strncmp(header->ident_str, "ADR-SEQ", 7) != 0) { + strncpy(id_string, header->ident_str, 7); + id_string[7] = 0; + printk(KERN_INFO "osst%i: Invalid header identification string %s\n", dev, id_string); + return 0; + } + update_frame_cntr = ntohl(aux->update_frame_cntr); + if (update_frame_cntr < STp->update_frame_cntr) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Skipping frame %d with update_frame_counter %d<%d\n", + dev, block, update_frame_cntr, STp->update_frame_cntr); +#endif + return 0; + } + if (header->major_rev != 1 || header->minor_rev != 4 ) { + printk(KERN_INFO "osst%i: %s revision %d.%d detected (1.4 supported)\n", + dev, (header->major_rev != 1 || header->minor_rev < 2 || + header->minor_rev > 4 )? "Invalid" : "Warning:", + header->major_rev, header->minor_rev); + if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4) + return 0; + } + if (header->pt_par_num != 1) + printk(KERN_INFO "osst%i: Warning: %d partitions defined, only one supported\n", + dev, header->pt_par_num); + memcpy(id_string, aux->application_sig, 4); + id_string[4] = 0; + if (memcmp(id_string, "LIN", 3) == 0) { + STp->linux_media = 1; + linux_media_version = id_string[3] - '0'; + if (linux_media_version != 4) + printk(KERN_INFO "osst%i: Linux media version %d detected (current 4)\n", + dev, linux_media_version); + } else { + printk(KERN_WARNING "osst%i: non Linux media detected (%s)\n", dev, id_string); + return 0; + } + if (linux_media_version < STp->linux_media_version) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Skipping frame %d with linux_media_version %d\n", + dev, block, linux_media_version); +#endif + return 0; + } + if (linux_media_version > STp->linux_media_version) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Frame %d sets linux_media_version to %d\n", + dev, block, linux_media_version); +#endif + memcpy(STp->application_sig, id_string, 5); + STp->linux_media_version = linux_media_version; + STp->update_frame_cntr = -1; + } + if (update_frame_cntr > STp->update_frame_cntr) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Frame %d sets update_frame_counter to %d\n", + dev, block, update_frame_cntr); +#endif + if (STp->header_cache == NULL) { + if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) { + printk(KERN_ERR "osst%i: Failed to allocate header cache\n", dev); + return 0; + } +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Allocated memory for header cache\n", dev); +#endif + } + osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache); + header = STp->header_cache; /* further accesses from cached (full) copy */ + + STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr); + STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos); + STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos); + STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb); + STp->filemark_cnt = ntohl(aux->filemark_cnt); + STp->first_mark_ppos = ntohl(aux->next_mark_ppos); + STp->last_mark_ppos = ntohl(aux->last_mark_ppos); + STp->update_frame_cntr = update_frame_cntr; +#if DEBUG + printk(OSST_DEB_MSG "osst%i: detected write pass %d, update frame counter %d, filemark counter %d\n", + dev, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt); + printk(OSST_DEB_MSG "osst%i: first data frame on tape = %d, last = %d, eod frame = %d\n", dev, + STp->first_data_ppos, + ntohl(header->partition[0].last_frame_ppos), + ntohl(header->partition[0].eod_frame_ppos)); + printk(OSST_DEB_MSG "osst%i: first mark on tape = %d, last = %d, eod frame = %d\n", + dev, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos); +#endif + if (header->minor_rev < 4 && STp->linux_media_version == 4) { + printk(OSST_DEB_MSG "osst%i: Moving filemark list to ADR 1.4 location\n", dev); + memcpy((void *)header->dat_fm_tab.fm_tab_ent, + (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent)); + memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list)); + } + if (header->minor_rev == 4 && + (header->ext_trk_tb_off != htons(17192) || + header->partition[0].partition_num != OS_DATA_PARTITION || + header->partition[0].par_desc_ver != OS_PARTITION_VERSION || + header->partition[0].last_frame_ppos != htonl(STp->capacity) || + header->cfg_col_width != htonl(20) || + header->dat_col_width != htonl(1500) || + header->qfa_col_width != htonl(0) || + header->ext_track_tb.nr_stream_part != 1 || + header->ext_track_tb.et_ent_sz != 32 || + header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION || + header->ext_track_tb.dat_ext_trk_ey.fmt != 1 || + header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) || + header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 || + header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) || + header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION || + header->dat_fm_tab.fm_tab_ent_sz != 4 || + header->dat_fm_tab.fm_tab_ent_cnt != + htons(STp->filemark_cntfilemark_cnt:OS_FM_TAB_MAX))) + printk(KERN_WARNING "osst%i: Failed consistency check ADR 1.4 format\n", dev); + +// memcpy(STp->header_cache, header, sizeof(os_header_t)); + } + + return 1; +} + +static int osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + int position, block; + int first, last; + int valid = 0; + int dev = TAPE_NR(STp->devt); + + position = osst_get_frame_position(STp, aSCpnt); + + if (STp->raw) { + STp->header_ok = STp->linux_media = 1; + STp->linux_media_version = 0; + return 1; + } + STp->header_ok = STp->linux_media = STp->linux_media_version = 0; + STp->wrt_pass_cntr = STp->update_frame_cntr = -1; + STp->eod_frame_ppos = STp->first_data_ppos = -1; + STp->first_mark_ppos = STp->last_mark_ppos = -1; +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Reading header\n", dev); +#endif + + /* optimization for speed - if we are positioned at block 10, read second group first */ + /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */ + + first = position==10?0xbae: 5; + last = position==10?0xbb3:10; + + for (block = first; block < last; block++) + if (__osst_analyze_headers(STp, aSCpnt, block)) + valid = 1; + + first = position==10? 5:0xbae; + last = position==10?10:0xbb3; + + for (block = first; block < last; block++) + if (__osst_analyze_headers(STp, aSCpnt, block)) + valid = 1; + + if (!valid) { + printk(KERN_ERR "osst%i: Failed to find valid ADRL header, new media?\n", dev); + STp->eod_frame_ppos = STp->first_data_ppos = 0; + osst_set_frame_position(STp, aSCpnt, 10, 0); + return 0; + } + if (position <= STp->first_data_ppos) { + position = STp->first_data_ppos; + STp->ps[0].drv_file = STp->ps[0].drv_block = STp->logical_blk_num = 0; + } + osst_set_frame_position(STp, aSCpnt, position, 0); + STp->header_ok = 1; + + return 1; +} + +static int osst_verify_position(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt) +{ + int frame_position = STp->first_frame_position; + int logical_blk_num = STp->logical_blk_num; + int prev_mark_ppos = -1; + int actual_mark_ppos, i, n; +#if 1 //DEBUG + int dev = TAPE_NR(STp->devt); + + printk(OSST_DEB_MSG "osst%i: Verify that the tape is really the one we think before writing\n", dev); +#endif + osst_set_frame_position(STp, aSCpnt, frame_position - 1, 0); + if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Couldn't get logical blk num in verify_position\n", dev); +#endif + return (-EIO); + } + if (STp->linux_media_version >= 4) { + for (i=0; ifilemark_cnt; i++) + if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position) + prev_mark_ppos = n; + } else + prev_mark_ppos = frame_position - 1; /* usually - we don't really know */ + actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ? + frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos); + if (frame_position != STp->first_frame_position || + logical_blk_num != STp->logical_blk_num + 1 || + prev_mark_ppos != actual_mark_ppos ) { +#if 1 //DEBUG + printk(OSST_DEB_MSG "osst%i: Block mismatch: frame %d-%d, lblk %d-%d, mark %d-%d\n", dev, + STp->first_frame_position, frame_position, STp->logical_blk_num + 1, + logical_blk_num, actual_mark_ppos, prev_mark_ppos); +#endif + return (-EIO); + } + STp->logical_blk_in_buffer = 0; + STp->logical_blk_num = logical_blk_num; + return 0; +} + +/* Acc. to OnStream, the vers. numbering is the following: + * X.XX for released versions (X=digit), + * XXXY for unreleased versions (Y=letter) + * Ordering 1.05 < 106A < 106a < 106B < ... < 1.06 + * This fn makes monoton numbers out of this scheme ... + */ +static unsigned int osst_parse_firmware_rev (const char * str) +{ + unsigned int rev; + if (str[1] == '.') { + rev = (str[0]-0x30)*10000 + +(str[2]-0x30)*1000 + +(str[3]-0x30)*100; + } else { + rev = (str[0]-0x30)*10000 + +(str[1]-0x30)*1000 + +(str[2]-0x30)*100 - 100; + rev += 2*(str[3] & 0x1f) + +(str[3] >= 0x60? 1: 0); + } + return rev; +} + +/* + * Configure the OnStream SCII tape drive for default operation + */ +static int osst_configure_onstream(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt) +{ + int dev = TAPE_NR(STp->devt); + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt = * aSCpnt; + osst_mode_parameter_header_t * header; + osst_block_size_page_t * bs; + osst_capabilities_page_t * cp; + osst_tape_paramtr_page_t * prm; + int drive_buffer_size; + + if (STp->ready != ST_READY) { +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Not Ready\n", dev); +#endif + return (-EIO); + } + + if (STp->os_fw_rev < 10600) { + printk("osst%i: Old OnStream firmware revision detected (%s)\n", + dev, STp->device->rev); + printk("osst%i: An upgrade to version 1.06 or above is recommended\n", + dev); + } + + /* + * Configure 32.5KB (data+aux) frame size. + * Get the current block size from the block size mode page + */ + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SENSE; + cmd[1] = 8; + cmd[2] = BLOCK_SIZE_PAGE; + cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + if (SCpnt == NULL) { +#if DEBUG + printk(OSST_DEB_MSG "osst: Busy\n"); +#endif + return (-EBUSY); + } + *aSCpnt = SCpnt; + if ((STp->buffer)->last_result_fatal != 0) { + printk (KERN_ERR "osst%i: Can't get tape block size mode page\n", dev); + return (-EIO); + } + + header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; + bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl); + +#if DEBUG + printk(KERN_INFO "osst%i: 32KB play back: %s\n", dev, bs->play32 ? "Yes" : "No"); + printk(KERN_INFO "osst%i: 32.5KB play back: %s\n", dev, bs->play32_5 ? "Yes" : "No"); + printk(KERN_INFO "osst%i: 32KB record: %s\n", dev, bs->record32 ? "Yes" : "No"); + printk(KERN_INFO "osst%i: 32.5KB record: %s\n", dev, bs->record32_5 ? "Yes" : "No"); +#endif + + /* + * Configure default auto columns mode, 32.5KB transfer mode + */ + bs->one = 1; + bs->play32 = 0; + bs->play32_5 = 1; + bs->record32 = 0; + bs->record32_5 = 1; + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SELECT; + cmd[1] = 0x10; + cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + *aSCpnt = SCpnt; + if ((STp->buffer)->last_result_fatal != 0) { + printk (KERN_ERR "osst%i: Couldn't set tape block size mode page\n", dev); + return (-EIO); + } + + STp->block_size = (STp->raw) ? OS_FRAME_SIZE : OS_DATA_SIZE; + STp->min_block = OS_FRAME_SIZE; /* FIXME */ + STp->max_block = STp->block_size; + +#if DEBUG + printk(KERN_INFO "osst%i: Block Size changed to 32.5K\n", dev); + /* + * In debug mode, we want to see as many errors as possible + * to test the error recovery mechanism. + */ + osst_set_retries(STp, aSCpnt, 0); + SCpnt = * aSCpnt; +#endif + + /* + * Set vendor name to 'LIN4' for "Linux support version 4". + */ + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SELECT; + cmd[1] = 0x10; + cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; + + header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1; + header->medium_type = 0; /* Medium Type - ignoring */ + header->dsp = 0; /* Reserved */ + header->bdl = 0; /* Block Descriptor Length */ + + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7); + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L'; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I'; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N'; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4'; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + *aSCpnt = SCpnt; + + if ((STp->buffer)->last_result_fatal != 0) { + printk (KERN_ERR "osst%i: Couldn't set vendor name to %s\n", dev, + (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2)); + return (-EIO); + } + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SENSE; + cmd[1] = 8; + cmd[2] = CAPABILITIES_PAGE; + cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + *aSCpnt = SCpnt; + + if ((STp->buffer)->last_result_fatal != 0) { + printk (KERN_ERR "osst%i: can't get capabilities page\n", dev); + return (-EIO); + } + + header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; + cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data + + sizeof(osst_mode_parameter_header_t) + header->bdl); + + drive_buffer_size = ntohs(cp->buffer_size) / 2; + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SENSE; + cmd[1] = 8; + cmd[2] = TAPE_PARAMTR_PAGE; + cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + *aSCpnt = SCpnt; + + if ((STp->buffer)->last_result_fatal != 0) { + printk (KERN_ERR "osst%i: can't get tape parameter page\n", dev); + return (-EIO); + } + + header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; + prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data + + sizeof(osst_mode_parameter_header_t) + header->bdl); + + STp->density = prm->density; + STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks); +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Density %d, tape length: %dMB, drive buffer size: %dKB\n", + dev, STp->density, STp->capacity / 32, drive_buffer_size); +#endif + + return 0; + +} + + +/* Step over EOF if it has been inadvertently crossed (ioctl not used because + it messes up the block number). */ +static int cross_eof(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int forward) +{ + int result; + int dev = TAPE_NR(STp->devt); + +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Stepping over filemark %s.\n", + dev, forward ? "forward" : "backward"); +#endif + + if (forward) { + /* assumes that the filemark is already read by the drive, so this is low cost */ + result = osst_space_over_filemarks_forward_slow(STp, aSCpnt, MTFSF, 1); + } + else + /* assumes this is only called if we just read the filemark! */ + result = osst_seek_logical_blk(STp, aSCpnt, STp->logical_blk_num - 1); + + if (result < 0) + printk(KERN_ERR "osst%d: Stepping over filemark %s failed.\n", + dev, forward ? "forward" : "backward"); + + return result; +} + + +/* Get the tape position. */ + +static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt) +{ + int result = 0; + unsigned char scmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt; + + /* KG: We want to be able to use it for checking Write Buffer availability + * and thus don't want to risk to overwrite anything. Exchange buffers ... */ + char mybuf[24]; + char * olddata = STp->buffer->b_data; + int oldsize = STp->buffer->buffer_size; + int dev = TAPE_NR(STp->devt); + + if (STp->ready != ST_READY) + return (-EIO); + + memset (scmd, 0, MAX_COMMAND_SIZE); + scmd[0] = READ_POSITION; + + STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; + SCpnt = osst_do_scsi(*aSCpnt, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE); + if (!SCpnt) { + STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; + return (-EBUSY); + } + *aSCpnt = SCpnt; + + if (STp->buffer->last_result_fatal) + result = ((SCpnt->sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL; + + if (result == -EINVAL) + printk(KERN_ERR "osst%d: Can't read tape position.\n", dev); + else { + + if (result == -EIO) { /* re-read position */ + unsigned char mysense[16]; + memcpy (mysense, SCpnt->sense_buffer, 16); + memset (scmd, 0, MAX_COMMAND_SIZE); + scmd[0] = READ_POSITION; + STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; + SCpnt = osst_do_scsi(SCpnt, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE); + if (!STp->buffer->last_result_fatal) + memcpy (SCpnt->sense_buffer, mysense, 16); + } + STp->first_frame_position = ((STp->buffer)->b_data[4] << 24) + + ((STp->buffer)->b_data[5] << 16) + + ((STp->buffer)->b_data[6] << 8) + + (STp->buffer)->b_data[7]; + STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24) + + ((STp->buffer)->b_data[ 9] << 16) + + ((STp->buffer)->b_data[10] << 8) + + (STp->buffer)->b_data[11]; + STp->cur_frames = (STp->buffer)->b_data[15]; +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d: Drive Positions: host %d, tape %d%s, buffer %d\n", dev, + STp->first_frame_position, STp->last_frame_position, + ((STp->buffer)->b_data[0]&0x80)?" (BOP)": + ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"", + STp->cur_frames); + } +#endif + if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) { +#if DEBUG + printk(KERN_WARNING "osst%d: Correcting read position %d, %d, %d\n", dev, + STp->first_frame_position, STp->last_frame_position, STp->cur_frames); +#endif + STp->first_frame_position = STp->last_frame_position; + } + } + STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; + + return (result == 0 ? STp->first_frame_position : result); +} + + +/* Set the tape block */ +static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int block, int skip) +{ + ST_partstat *STps; + int result = 0; + int timeout; + unsigned char scmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt; + int dev = TAPE_NR(STp->devt); + + if (STp->ready != ST_READY) + return (-EIO); + timeout = STp->long_timeout; + STps = &(STp->ps[STp->partition]); + + if (block < 0 || block > STp->capacity) { + printk(KERN_ERR "osst%d: Reposition request %d out of range\n", dev, block); + block = block < 0 ? 0 : (STp->capacity - 1); + result = (-EINVAL); + } +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Setting block to %d.\n", dev, block); +#endif + memset (scmd, 0, MAX_COMMAND_SIZE); + scmd[0] = SEEK_10; + scmd[1] = 1; + scmd[3] = (block >> 24); + scmd[4] = (block >> 16); + scmd[5] = (block >> 8); + scmd[6] = block; + if (skip) + scmd[9] = 0x80; + + SCpnt = osst_do_scsi(*aSCpnt, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE); + if (!SCpnt) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Busy\n", dev); +#endif + return (-EBUSY); + } + *aSCpnt = SCpnt; + + STp->first_frame_position = STp->last_frame_position = block; + STps->eof = ST_NOEOF; + if ((STp->buffer)->last_result_fatal != 0) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: SEEK command failed.\n", dev); +#endif + result = (-EIO); + } + STps->at_sm = 0; + STps->rw = ST_IDLE; + STp->logical_blk_in_buffer = 0; + return result; +} + + + +/* osst versions of st functions - augmented and stripped to suit OnStream only */ + +/* Flush the write buffer (never need to write if variable blocksize). */ +static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int file_blk) +{ + int offset, transfer, blks = 0; + int result = 0; + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt = *aSCpnt; + ST_partstat * STps; + int dev = TAPE_NR(STp->devt); + + if ((STp->buffer)->writing) { + if (SCpnt == (STp->buffer)->last_SCpnt) +#if DEBUG + { printk(OSST_DEB_MSG + "osst%d: aSCpnt points to Scsi_Cmnd that write_behind_check will release -- cleared\n", dev); +#endif + *aSCpnt = SCpnt = NULL; +#if DEBUG + } else if (SCpnt) + printk(OSST_DEB_MSG + "osst%d: aSCpnt does not point to Scsi_Cmnd that write_behind_check will release -- strange\n", dev); +#endif + osst_write_behind_check(STp); + if ((STp->buffer)->last_result_fatal) { +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Async write error (flush) %x.\n", + dev, (STp->buffer)->last_result); +#endif + if ((STp->buffer)->last_result == INT_MAX) + return (-ENOSPC); + return (-EIO); + } + } + + result = 0; + if (STp->dirty == 1) { + + offset = STp->buffer->buffer_bytes; + transfer = OS_FRAME_SIZE; + blks = 1; + +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Flushing %d bytes, Tranfering %d bytes in %d blocks.\n", + dev, offset, transfer, blks); +#endif + if (offset < OS_DATA_SIZE) + osst_zero_buffer_tail(STp->buffer); + + /* TODO: Error handling! */ + if (STp->poll) + result = osst_wait_frame (STp, aSCpnt, STp->first_frame_position, -50, 120); +//osst_build_stats(STp, aSCpnt); + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = WRITE_6; + cmd[1] = 1; + cmd[4] = blks; + + SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, TRUE); + *aSCpnt = SCpnt; + if (!SCpnt) + return (-EBUSY); + + STps = &(STp->ps[STp->partition]); + if ((STp->buffer)->last_result_fatal != 0) { + printk(OSST_DEB_MSG "osst%d: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", TAPE_NR(STp->devt), + SCpnt->sense_buffer[0], SCpnt->sense_buffer[2], SCpnt->sense_buffer[12], SCpnt->sense_buffer[13]); + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */ + (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) { + STp->dirty = 0; + (STp->buffer)->buffer_bytes = 0; + result = (-ENOSPC); + } + else { + if (osst_write_error_recovery(STp, aSCpnt, 1)) { + printk(KERN_ERR "osst%d: Error on flush.\n", dev); + result = (-EIO); + } + } + STps->drv_block = (-1); + } + else { + STp->first_frame_position++; + if (file_blk && STps->drv_block >= 0) + STps->drv_block += blks; + STp->first_frame_position += blks; + STp->dirty = 0; + (STp->buffer)->buffer_bytes = 0; + } + } +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Exit flush write buffer with code %d\n", dev, result); +#endif + return result; +} + + +/* Flush the tape buffer. The tape will be positioned correctly unless + seek_next is true. */ +static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int seek_next) +{ + int backspace, result; + OSST_buffer * STbuffer; + ST_partstat * STps; +#if DEBUG + int dev = TAPE_NR(STp->devt); +#endif + + STbuffer = STp->buffer; + + /* + * If there was a bus reset, block further access + * to this device. + */ + if( STp->device->was_reset ) + return (-EIO); + + if (STp->ready != ST_READY) + return 0; + + STps = &(STp->ps[STp->partition]); + if (STps->rw == ST_WRITING) /* Writing */ + return osst_flush_write_buffer(STp, aSCpnt, 1); + + if (STp->block_size == 0) + return 0; + +#if DEBUG + printk(OSST_DEB_MSG "osst%i: Reached flush (read) buffer\n", dev); +#endif + backspace = ((STp->buffer)->buffer_bytes + + (STp->buffer)->read_pointer) / STp->block_size - + ((STp->buffer)->read_pointer + STp->block_size - 1) / + STp->block_size; + (STp->buffer)->buffer_bytes = 0; + (STp->buffer)->read_pointer = 0; + result = 0; + if (!seek_next) { + if (STps->eof == ST_FM_HIT) { + result = cross_eof(STp, aSCpnt, FALSE); /* Back over the EOF hit */ + if (!result) + STps->eof = ST_NOEOF; + else { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + } + } + if (!result && backspace > 0) /* TODO -- design and run a test case for this */ + result = osst_seek_logical_blk(STp, aSCpnt, STp->logical_blk_num - backspace); + } + else if (STps->eof == ST_FM_HIT) { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + STps->eof = ST_NOEOF; + } + + return result; + +} + + +/* Entry points to osst */ + +/* Write command */ +static ssize_t osst_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + ssize_t total; + ssize_t i, do_count, blks, retval, transfer; + int write_threshold; + int doing_write = 0; + unsigned char cmd[MAX_COMMAND_SIZE]; + const char *b_point; + Scsi_Cmnd * SCpnt = NULL; + OS_Scsi_Tape * STp; + ST_mode * STm; + ST_partstat * STps; + int dev = TAPE_NR(inode->i_rdev); + + STp = os_scsi_tapes[dev]; + + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + if( !scsi_block_when_processing_errors(STp->device) ) { + return -ENXIO; + } + + if (ppos != &filp->f_pos) { + /* "A request was outside the capabilities of the device." */ + return -ENXIO; + } + + if (STp->ready != ST_READY) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + STm = &(STp->modes[STp->current_mode]); + if (!STm->defined) + return (-ENXIO); + if (count == 0) + return 0; + + /* + * If there was a bus reset, block further access + * to this device. + */ + if( STp->device->was_reset ) + return (-EIO); + +#if DEBUG + if (!STp->in_use) { + printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + + if (STp->write_prot) + return (-EACCES); + + /* Write must be integral number of blocks */ + if (STp->block_size != 0 && (count % STp->block_size) != 0) { + printk(KERN_WARNING "osst%d: Write (%d bytes) not multiple of tape block size (32k).\n", + dev, count); + return (-EIO); + } + + if (STp->first_frame_position >= STp->capacity - 164) { + printk(KERN_WARNING "osst%d: Write truncated at EOM early warning (frame %d).\n", + dev, STp->first_frame_position); + return (-ENOSPC); + } + + STps = &(STp->ps[STp->partition]); + + if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && + !osst_int_ioctl(STp, &SCpnt, MTLOCK, 0)) + STp->door_locked = ST_LOCKED_AUTO; + + if (STps->rw == ST_READING) { + retval = osst_flush_buffer(STp, &SCpnt, 0); + if (retval) { + if (SCpnt) scsi_release_command(SCpnt); + return retval; + } + STps->rw = ST_IDLE; + } + else if (STps->rw != ST_WRITING) { + /* Are we totally rewriting this tape? */ + if (!STp->header_ok || STp->first_frame_position == STp->first_data_ppos || + (STps->drv_file == 0 && STps->drv_block == 0)) { + STp->wrt_pass_cntr++; +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Allocating next write pass counter: %d\n", + dev, STp->wrt_pass_cntr); +#endif + osst_reset_header(STp, &SCpnt); + STps->drv_file = STps->drv_block = STp->logical_blk_num = 0; + } + /* Do we know where we'll be writing on the tape? */ + else { + if ((STp->fast_open && osst_verify_position(STp, &SCpnt)) || + STps->drv_file < 0 || STps->drv_block < 0) { + if (STp->first_frame_position == STp->eod_frame_ppos) { + STps->drv_file = STp->filemark_cnt; + STps->drv_block = 0; + } + else { + /* We have no idea where the tape is positioned - give up */ +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Cannot write at indeterminate position.\n", dev); +#endif + if (SCpnt) scsi_release_command(SCpnt); + return (-EIO); + } + } + if (STps->drv_file > 0 && STps->drv_file < STp->filemark_cnt) { + STp->filemark_cnt = STps->drv_file; + STp->last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]); + printk(KERN_WARNING "osst%d: Overwriting file %d with old write pass counter %d\n", + dev, STps->drv_file, STp->wrt_pass_cntr); + printk(KERN_WARNING "osst%d: may lead to stale data being accepted on reading back!\n", + dev); +#if DEBUG + printk(OSST_DEB_MSG "osst%d: resetting filemark count to %d and last mark ppos to %d\n", + dev, STp->filemark_cnt, STp->last_mark_ppos); +#endif + } + } + STp->fast_open = FALSE; +//printk(OSST_DEB_MSG "osst%d: Starting write next file\n",dev); + } + if (!STp->header_ok) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Write cannot proceed without valid headers\n", dev); +#endif + if (SCpnt) scsi_release_command(SCpnt); + return (-EIO); + } + if ((STp->buffer)->writing) { +if (SCpnt) printk(KERN_ERR "osst%d: Not supposed to have SCpnt at line %d\n", dev, __LINE__); + osst_write_behind_check(STp); + if ((STp->buffer)->last_result_fatal) { +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Async write error (write) %x.\n", dev, + (STp->buffer)->last_result); +#endif + if ((STp->buffer)->last_result == INT_MAX) + STps->eof = ST_EOM_OK; + else + STps->eof = ST_EOM_ERROR; + } + } + if (SCpnt) scsi_release_command(SCpnt); + SCpnt = NULL; + if (STps->eof == ST_EOM_OK) + return (-ENOSPC); + else if (STps->eof == ST_EOM_ERROR) + return (-EIO); + + /* Check the buffer readability in cases where copy_user might catch + the problems after some tape movement. */ + if ((copy_from_user(&i, buf, 1) != 0 || + copy_from_user(&i, buf + count - 1, 1) != 0)) + return (-EFAULT); + + if (!STm->do_buffer_writes) { +#if 0 + if (STp->block_size != 0 && (count % STp->block_size) != 0) + return (-EIO); /* Write must be integral number of blocks */ +#endif + write_threshold = 1; + } + else + write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; + if (!STm->do_async_writes) + write_threshold--; + + total = count; + + if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Skipping over config partition.\n", dev); +#endif + if (osst_flush_drive_buffer(STp, &SCpnt) < 0) { + if (SCpnt) scsi_release_command(SCpnt); + return (-EIO); + } + /* error recovery may have bumped us past the header partition */ + if (osst_get_frame_position(STp, &SCpnt) < 0xbb8) + osst_position_tape_and_confirm(STp, &SCpnt, 0xbb8); + } + + if (STp->poll) + retval = osst_wait_frame (STp, &SCpnt, STp->first_frame_position, -50, 60); + /* TODO: Check for an error ! */ +//osst_build_stats(STp, &SCpnt); + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = WRITE_6; + cmd[1] = 1; + + STps->rw = ST_WRITING; + STp->write_type = OS_WRITE_DATA; + +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Writing %d bytes to file %d block %d lblk %d frame %d\n", + dev, count, STps->drv_file, STps->drv_block, + STp->logical_blk_num, STp->first_frame_position); +#endif + + b_point = buf; + while ((STp->buffer)->buffer_bytes + count > write_threshold) + { + doing_write = 1; + do_count = (STp->buffer)->buffer_blocks * STp->block_size - + (STp->buffer)->buffer_bytes; + if (do_count > count) + do_count = count; + + i = append_to_buffer(b_point, STp->buffer, do_count); + if (i) { + if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + return i; + } + + transfer = OS_FRAME_SIZE; + blks = 1; + + osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->logical_blk_num++ ); + + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, TRUE); + if (!SCpnt) + return (-EBUSY); + + if ((STp->buffer)->last_result_fatal != 0) { +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Error on write:\n", dev); +#endif + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40)) { + if ((SCpnt->sense_buffer[0] & 0x80) != 0) + transfer = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else + transfer = 0; + transfer *= STp->block_size; + if (transfer <= do_count) { + filp->f_pos += do_count - transfer; + count -= do_count - transfer; + if (STps->drv_block >= 0) { + STps->drv_block += (do_count - transfer) / STp->block_size; + } + STps->eof = ST_EOM_OK; + retval = (-ENOSPC); /* EOM within current request */ +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: EOM with %d bytes unwritten.\n", + dev, transfer); +#endif + } + else { + STps->eof = ST_EOM_ERROR; + STps->drv_block = (-1); /* Too cautious? */ + retval = (-EIO); /* EOM for old data */ +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: EOM with lost data.\n", dev); +#endif + } + } + else { + if (osst_write_error_recovery(STp, &SCpnt, 1) == 0) goto ok; + STps->drv_block = (-1); /* Too cautious? */ + retval = (-EIO); + } + + scsi_release_command(SCpnt); + SCpnt = NULL; + (STp->buffer)->buffer_bytes = 0; + STp->dirty = 0; + if (count < total) + return total - count; + else + return retval; + } + STp->first_frame_position++; +ok: + filp->f_pos += do_count; + b_point += do_count; + count -= do_count; + if (STps->drv_block >= 0) { + STps->drv_block += blks; + } + STp->first_frame_position += blks; + (STp->buffer)->buffer_bytes = 0; + STp->dirty = 0; + } + if (count != 0) { + STp->dirty = 1; + i = append_to_buffer(b_point, STp->buffer, count); + if (i) { + if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + return i; + } + filp->f_pos += count; + count = 0; + } + + if (doing_write && (STp->buffer)->last_result_fatal != 0) { + scsi_release_command(SCpnt); + SCpnt = NULL; + return (STp->buffer)->last_result_fatal; + } + + if (STm->do_async_writes && + ((STp->buffer)->buffer_bytes >= STp->write_threshold && + (STp->buffer)->buffer_bytes >= OS_DATA_SIZE) ) { + /* Schedule an asynchronous write */ + (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / + STp->block_size) * STp->block_size; + STp->dirty = !((STp->buffer)->writing == + (STp->buffer)->buffer_bytes); + + transfer = OS_FRAME_SIZE; + blks = 1; + + osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->logical_blk_num++ ); + + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; +#if DEBUG + STp->write_pending = 1; +#endif + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, FALSE); + if (SCpnt == NULL) + return (-EIO); + } + else if (SCpnt != NULL) { + scsi_release_command(SCpnt); + SCpnt = NULL; + } + STps->at_sm &= (total == 0); + if (total > 0) + STps->eof = ST_NOEOF; + + return( total); +} + + +/* Read command */ +static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *ppos) +{ + struct inode * inode = filp->f_dentry->d_inode; + ssize_t total; + ssize_t i, transfer; + int special; + OS_Scsi_Tape * STp; + ST_mode * STm; + ST_partstat * STps; + Scsi_Cmnd *SCpnt = NULL; + int dev = TAPE_NR(inode->i_rdev); + + STp = os_scsi_tapes[dev]; + + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + if( !scsi_block_when_processing_errors(STp->device) ) { + return -ENXIO; + } + + if (ppos != &filp->f_pos) { + /* "A request was outside the capabilities of the device." */ + return -ENXIO; + } + + if (STp->ready != ST_READY) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + STm = &(STp->modes[STp->current_mode]); + if (!STm->defined) + return (-ENXIO); +#if DEBUG + if (!STp->in_use) { + printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + /* Must have initialized medium */ + if (!STp->header_ok) return (-EIO); + + if ((count % STp->block_size) != 0) { + printk(KERN_WARNING "osst%d: Use multiple of %d bytes as block size (%d requested)\n", + dev, STp->block_size, count); + return (-EIO); /* Read must be integral number of blocks */ + } + + if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && + !osst_int_ioctl(STp, &SCpnt, MTLOCK, 0)) + STp->door_locked = ST_LOCKED_AUTO; + + STps = &(STp->ps[STp->partition]); + if (STps->rw == ST_WRITING) { + transfer = osst_flush_buffer(STp, &SCpnt, 0); + if (SCpnt) scsi_release_command(SCpnt); + SCpnt = NULL; + if (transfer) + return transfer; + STps->rw = ST_IDLE; + } + +#if DEBUG + if (debugging && STps->eof != ST_NOEOF) + printk(OSST_DEB_MSG "osst%d: EOF/EOM flag up (%d). Bytes %d\n", dev, + STps->eof, (STp->buffer)->buffer_bytes); +#endif + if ((STp->buffer)->buffer_bytes == 0 && + STps->eof >= ST_EOD_1) { + if (SCpnt) scsi_release_command(SCpnt); + if (STps->eof < ST_EOD) { + STps->eof += 1; + return 0; + } + return (-EIO); /* EOM or Blank Check */ + } + + /* Check the buffer writability before any tape movement. Don't alter + buffer data. */ + if (copy_from_user(&i, buf, 1) != 0 || + copy_to_user(buf, &i, 1) != 0 || + copy_from_user(&i, buf + count - 1, 1) != 0 || + copy_to_user(buf + count - 1, &i, 1) != 0) { + if (SCpnt) scsi_release_command(SCpnt); + return (-EFAULT); + } + + /* Loop until enough data in buffer or a special condition found */ + for (total = 0, special = 0; total < count && !special; ) { + + /* Get new data if the buffer is empty */ + if ((STp->buffer)->buffer_bytes == 0) { + special = osst_get_logical_blk(STp, &SCpnt, STp->logical_blk_num, 0); + STp->buffer->buffer_bytes = special ? 0 : OS_DATA_SIZE; + STp->buffer->read_pointer = 0; + STp->logical_blk_num++; /* block to look for next time */ + STp->logical_blk_in_buffer = 0; + if (special < 0) { /* No need to continue read */ + if (SCpnt) scsi_release_command(SCpnt); + return special; + } + STps->drv_block++; + } + + /* Move the data from driver buffer to user buffer */ + if ((STp->buffer)->buffer_bytes > 0) { +#if DEBUG + if (debugging && STps->eof != ST_NOEOF) + printk(OSST_DEB_MSG "osst%d: EOF up (%d). Left %d, needed %d.\n", dev, + STps->eof, (STp->buffer)->buffer_bytes, count - total); +#endif + transfer = (STp->buffer)->buffer_bytes < count - total ? + (STp->buffer)->buffer_bytes : count - total; + i = from_buffer(STp->buffer, buf, transfer); + if (i) { + if (SCpnt) scsi_release_command(SCpnt); + return i; + } + filp->f_pos += transfer; + buf += transfer; + total += transfer; + } + + } /* for (total = 0, special = 0; total < count && !special; ) */ + if (SCpnt) scsi_release_command(SCpnt); + + /* Change the eof state if no data from tape or buffer */ + if (total == 0) { + if (STps->eof == ST_FM_HIT) { + STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; + STps->drv_block = 0; + if (STps->drv_file >= 0) + STps->drv_file++; + } + else if (STps->eof == ST_EOD_1) { + STps->eof = ST_EOD_2; + if (STps->drv_block > 0 && STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + } + else if (STps->eof == ST_EOD_2) + STps->eof = ST_EOD; + } + else if (STps->eof == ST_FM) + STps->eof = ST_NOEOF; + + return total; +} + + +/* Set the driver options */ +static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, int dev) +{ + printk(KERN_INFO +"osst%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", + dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, + STm->do_read_ahead); + printk(KERN_INFO +"osst%d: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", + dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); + printk(KERN_INFO +"osst%d: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", + dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, + STp->scsi2_logical); + printk(KERN_INFO +"osst%d: sysv: %d\n", dev, STm->sysv); +#if DEBUG + printk(KERN_INFO + "osst%d: debugging: %d\n", + dev, debugging); +#endif +} + + +static int osst_set_options(OS_Scsi_Tape *STp, long options) +{ + int value; + long code; + ST_mode *STm; + int dev = TAPE_NR(STp->devt); + + STm = &(STp->modes[STp->current_mode]); + if (!STm->defined) { + memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); + modes_defined = TRUE; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Initialized mode %d definition from mode 0\n", + dev, STp->current_mode); +#endif + } + + code = options & MT_ST_OPTIONS; + if (code == MT_ST_BOOLEANS) { + STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; + STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; + STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; + STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; + STp->two_fm = (options & MT_ST_TWO_FM) != 0; + STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; + STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; + STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; + STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; + if ((STp->device)->scsi_level >= SCSI_2) + STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; + STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; + STm->sysv = (options & MT_ST_SYSV) != 0; +#if DEBUG + debugging = (options & MT_ST_DEBUGGING) != 0; +#endif + osst_log_options(STp, STm, dev); + } + else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { + value = (code == MT_ST_SETBOOLEANS); + if ((options & MT_ST_BUFFER_WRITES) != 0) + STm->do_buffer_writes = value; + if ((options & MT_ST_ASYNC_WRITES) != 0) + STm->do_async_writes = value; + if ((options & MT_ST_DEF_WRITES) != 0) + STm->defaults_for_writes = value; + if ((options & MT_ST_READ_AHEAD) != 0) + STm->do_read_ahead = value; + if ((options & MT_ST_TWO_FM) != 0) + STp->two_fm = value; + if ((options & MT_ST_FAST_MTEOM) != 0) + STp->fast_mteom = value; + if ((options & MT_ST_AUTO_LOCK) != 0) + STp->do_auto_lock = value; + if ((options & MT_ST_CAN_BSR) != 0) + STp->can_bsr = value; + if ((options & MT_ST_NO_BLKLIMS) != 0) + STp->omit_blklims = value; + if ((STp->device)->scsi_level >= SCSI_2 && + (options & MT_ST_CAN_PARTITIONS) != 0) + STp->can_partitions = value; + if ((options & MT_ST_SCSI2LOGICAL) != 0) + STp->scsi2_logical = value; + if ((options & MT_ST_SYSV) != 0) + STm->sysv = value; +#if DEBUG + if ((options & MT_ST_DEBUGGING) != 0) + debugging = value; +#endif + osst_log_options(STp, STm, dev); + } + else if (code == MT_ST_WRITE_THRESHOLD) { + value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; + if (value < 1 || value > osst_buffer_size) { + printk(KERN_WARNING "osst%d: Write threshold %d too small or too large.\n", + dev, value); + return (-EIO); + } + STp->write_threshold = value; + printk(KERN_INFO "osst%d: Write threshold set to %d bytes.\n", + dev, value); + } + else if (code == MT_ST_DEF_BLKSIZE) { + value = (options & ~MT_ST_OPTIONS); + if (value == ~MT_ST_OPTIONS) { + STm->default_blksize = (-1); + printk(KERN_INFO "osst%d: Default block size disabled.\n", dev); + } + else { + STm->default_blksize = value; + printk(KERN_INFO "osst%d: Default block size set to %d bytes.\n", + dev, STm->default_blksize); + } + } + else if (code == MT_ST_TIMEOUTS) { + value = (options & ~MT_ST_OPTIONS); + if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { + STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; + printk(KERN_INFO "osst%d: Long timeout set to %d seconds.\n", dev, + (value & ~MT_ST_SET_LONG_TIMEOUT)); + } + else { + STp->timeout = value * HZ; + printk(KERN_INFO "osst%d: Normal timeout set to %d seconds.\n", dev, + value); + } + } + else if (code == MT_ST_DEF_OPTIONS) { + code = (options & ~MT_ST_CLEAR_DEFAULT); + value = (options & MT_ST_CLEAR_DEFAULT); + if (code == MT_ST_DEF_DENSITY) { + if (value == MT_ST_CLEAR_DEFAULT) { + STm->default_density = (-1); + printk(KERN_INFO "osst%d: Density default disabled.\n", dev); + } + else { + STm->default_density = value & 0xff; + printk(KERN_INFO "osst%d: Density default set to %x\n", + dev, STm->default_density); + } + } + else if (code == MT_ST_DEF_DRVBUFFER) { + if (value == MT_ST_CLEAR_DEFAULT) { + STp->default_drvbuffer = 0xff; + printk(KERN_INFO "osst%d: Drive buffer default disabled.\n", dev); + } + else { + STp->default_drvbuffer = value & 7; + printk(KERN_INFO "osst%d: Drive buffer default set to %x\n", + dev, STp->default_drvbuffer); + } + } + else if (code == MT_ST_DEF_COMPRESSION) { + if (value == MT_ST_CLEAR_DEFAULT) { + STm->default_compression = ST_DONT_TOUCH; + printk(KERN_INFO "osst%d: Compression default disabled.\n", dev); + } + else { + STm->default_compression = (value & 1 ? ST_YES : ST_NO); + printk(KERN_INFO "osst%d: Compression default set to %x\n", + dev, (value & 1)); + } + } + } + else + return (-EIO); + + return 0; +} + + +/* Internal ioctl function */ +static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, unsigned int cmd_in, unsigned long arg) +{ + int timeout; + long ltmp; + int i, ioctl_result; + int chg_eof = TRUE; + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt = *aSCpnt; + ST_partstat * STps; + int fileno, blkno, at_sm, datalen; + int logical_blk_num; + int dev = TAPE_NR(STp->devt); + + if (STp->ready != ST_READY && cmd_in != MTLOAD) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + timeout = STp->long_timeout; + STps = &(STp->ps[STp->partition]); + fileno = STps->drv_file; + blkno = STps->drv_block; + at_sm = STps->at_sm; + logical_blk_num = STp->logical_blk_num; + + memset(cmd, 0, MAX_COMMAND_SIZE); + datalen = 0; + switch (cmd_in) { + case MTFSFM: + chg_eof = FALSE; /* Changed from the FSF after this */ + case MTFSF: + if (STp->raw) + return (-EIO); + if (STp->linux_media) + ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SCpnt, cmd_in, arg); + else + ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SCpnt, cmd_in, arg); + logical_blk_num = STp->logical_blk_num; + if (fileno >= 0) + fileno += arg; + blkno = 0; + at_sm &= (arg == 0); + goto os_bypass; + + case MTBSF: + chg_eof = FALSE; /* Changed from the FSF after this */ + case MTBSFM: + if (STp->raw) + return (-EIO); + ioctl_result = osst_space_over_filemarks_backward(STp, &SCpnt, cmd_in, arg); + logical_blk_num = STp->logical_blk_num; + if (fileno >= 0) + fileno -= arg; + blkno = (-1); /* We can't know the block number */ + at_sm &= (arg == 0); + goto os_bypass; + + case MTFSR: + case MTBSR: +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%i: Skipping %lu blocks %s from logical block %d\n", + dev, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num); +#endif + if (cmd_in == MTFSR) { + logical_blk_num += arg; + if (blkno >= 0) blkno += arg; + } + else { + logical_blk_num -= arg; + if (blkno >= 0) blkno -= arg; + } + ioctl_result = osst_seek_logical_blk(STp, &SCpnt, logical_blk_num-1); + STp->logical_blk_in_buffer = 0; + at_sm &= (arg == 0); + goto os_bypass; + + case MTFSS: + cmd[0] = SPACE; + cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Spacing tape forward %d setmarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); +#endif + if (arg != 0) { + blkno = fileno = (-1); + at_sm = 1; + } + break; + case MTBSS: + cmd[0] = SPACE; + cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ + ltmp = (-arg); + cmd[2] = (ltmp >> 16); + cmd[3] = (ltmp >> 8); + cmd[4] = ltmp; +#if DEBUG + if (debugging) { + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk(OSST_DEB_MSG "osst%d: Spacing tape backward %ld setmarks.\n", + dev, (-ltmp)); + } +#endif + if (arg != 0) { + blkno = fileno = (-1); + at_sm = 1; + } + break; + case MTWEOF: + if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) + ioctl_result = osst_flush_write_buffer(STp, &SCpnt, 1); + else + ioctl_result = 0; + for (i=0; ilogical_blk_num; + if (fileno >= 0) fileno += arg; + if (blkno >= 0) blkno = 0; + goto os_bypass; + + case MTWSM: + if (STp->write_prot) + return (-EACCES); + if (!STp->raw) + return 0; + cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */ + if (cmd_in == MTWSM) + cmd[1] = 2; + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; + timeout = STp->timeout; +#if DEBUG + if (debugging) { + if (cmd_in == MTWEOF) + printk(OSST_DEB_MSG "osst%d: Writing %d filemarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); + else + printk(OSST_DEB_MSG "osst%d: Writing %d setmarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); + } +#endif + if (fileno >= 0) + fileno += arg; + blkno = 0; + at_sm = (cmd_in == MTWSM); + break; + case MTOFFL: + case MTLOAD: + case MTUNLOAD: + case MTRETEN: + cmd[0] = START_STOP; + cmd[1] = 1; /* Don't wait for completion */ + if (cmd_in == MTLOAD) + cmd[4] = 1; /* load */ + if (cmd_in == MTRETEN) + cmd[4] = 3; /* retension then mount */ + if (cmd_in == MTOFFL) + cmd[4] = 4; /* rewind then eject */ + timeout = STp->timeout; +#if DEBUG + if (debugging) { + switch (cmd_in) { + case MTUNLOAD: + printk(OSST_DEB_MSG "osst%d: Unloading tape.\n", dev); + break; + case MTLOAD: + printk(OSST_DEB_MSG "osst%d: Loading tape.\n", dev); + break; + case MTRETEN: + printk(OSST_DEB_MSG "osst%d: Retensioning tape.\n", dev); + break; + case MTOFFL: + printk(OSST_DEB_MSG "osst%d: Ejecting tape.\n", dev); + break; + } + } +#endif + fileno = blkno = at_sm = logical_blk_num = 0 ; + break; + case MTNOP: +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: No op on tape.\n", dev); +#endif + return 0; /* Should do something ? */ + break; + case MTEOM: +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Spacing to end of recorded medium.\n", dev); +#endif + osst_set_frame_position(STp, &SCpnt, STp->eod_frame_ppos, 0); + if (osst_get_logical_blk(STp, &SCpnt, -1, 0) < 0) { + ioctl_result = -EIO; + goto os_bypass; + } + if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: No EOD frame found where expected.\n", dev); +#endif + ioctl_result = -EIO; + goto os_bypass; + } + ioctl_result = osst_set_frame_position(STp, &SCpnt, STp->eod_frame_ppos, 0); + logical_blk_num = STp->logical_blk_num; + fileno = STp->filemark_cnt; + blkno = at_sm = 0; + goto os_bypass; + + case MTERASE: + if (STp->write_prot) + return (-EACCES); + ioctl_result = osst_reset_header(STp, &SCpnt); + i = osst_write_eod(STp, &SCpnt); + if (i < ioctl_result) ioctl_result = i; + i = osst_position_tape_and_confirm(STp, &SCpnt, STp->eod_frame_ppos); + if (i < ioctl_result) ioctl_result = i; + fileno = blkno = at_sm = logical_blk_num = 0 ; + goto os_bypass; + + case MTREW: + cmd[0] = REZERO_UNIT; /* rewind */ + cmd[1] = 1; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Rewinding tape, Immed=%d.\n", dev, cmd[1]); +#endif + fileno = blkno = at_sm = logical_blk_num = 0 ; + break; + + case MTLOCK: + chg_eof = FALSE; + cmd[0] = ALLOW_MEDIUM_REMOVAL; + cmd[4] = SCSI_REMOVAL_PREVENT; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Locking drive door.\n", dev); +#endif; + break; + + case MTUNLOCK: + chg_eof = FALSE; + cmd[0] = ALLOW_MEDIUM_REMOVAL; + cmd[4] = SCSI_REMOVAL_ALLOW; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Unlocking drive door.\n", dev); +#endif; + break; + + case MTSETBLK: /* Set block length */ + case MTSETDENSITY: /* Set tape density */ + case MTSETDRVBUFFER: /* Set drive buffering */ + case SET_DENS_AND_BLK: /* Set density and block size */ + chg_eof = FALSE; + if (STp->dirty || (STp->buffer)->buffer_bytes != 0) + return (-EIO); /* Not allowed if data in buffer */ + if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && + (arg & MT_ST_BLKSIZE_MASK) != 0 && + ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || + (arg & MT_ST_BLKSIZE_MASK) > STp->max_block || + (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) { + printk(KERN_WARNING "osst%d: Illegal block size.\n", dev); + return (-EINVAL); + } + return 0; /* silently ignore if block size didn't change */ + + default: + return (-ENOSYS); + } + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE); + if (!SCpnt) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Couldn't exec scsi cmd for IOCTL\n", dev); +#endif + return (-EBUSY); + } + + ioctl_result = (STp->buffer)->last_result_fatal; + +os_bypass: +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result); +#endif + + if (!ioctl_result) { /* SCSI command successful */ + + if (cmd_in == MTFSFM) { + fileno--; + blkno--; + } + if (cmd_in == MTBSFM) { + fileno++; + blkno++; + } + STps->drv_block = blkno; + STps->drv_file = fileno; + STps->at_sm = at_sm; + STp->logical_blk_num = logical_blk_num; + + if (cmd_in == MTLOCK) + STp->door_locked = ST_LOCKED_EXPLICIT; + else if (cmd_in == MTUNLOCK) + STp->door_locked = ST_UNLOCKED; + + if (cmd_in == MTEOM) + STps->eof = ST_EOD; + else if (cmd_in == MTFSF) + STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; + else if (chg_eof) + STps->eof = ST_NOEOF; + + if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) + STp->rew_at_close = 0; + else if (cmd_in == MTLOAD) { +/* STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; FIXME */ + for (i=0; i < ST_NBR_PARTITIONS; i++) { + STp->ps[i].rw = ST_IDLE; + STp->ps[i].last_block_valid = FALSE; + } + STp->partition = 0; + } + + if (cmd_in == MTREW) { + ioctl_result = osst_position_tape_and_confirm(STp, &SCpnt, STp->first_data_ppos); + if (ioctl_result > 0) + ioctl_result = 0; + } + + } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) { + if (osst_position_tape_and_confirm(STp, &SCpnt, STp->first_data_ppos) < 0) + STps->drv_file = STps->drv_block = -1; + else + STps->drv_file = STps->drv_block = 0; + STps->eof = ST_NOEOF; + } else if (cmd_in == MTFSF || cmd_in == MTFSFM) { + if (osst_position_tape_and_confirm(STp, &SCpnt, STp->eod_frame_ppos) < 0) + STps->drv_file = STps->drv_block = -1; + else { + STps->drv_file = STp->filemark_cnt; + STps->drv_block = 0; + } + STps->eof = ST_EOD; + } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) { + STps->drv_file = STps->drv_block = (-1); + STps->eof = ST_NOEOF; + STp->header_ok = 0; + } else if (cmd_in == MTERASE) { + STp->header_ok = 0; + } else if (SCpnt) { /* SCSI command was not completely successful. */ + if (SCpnt->sense_buffer[2] & 0x40) { + STps->eof = ST_EOM_OK; + STps->drv_block = 0; + } + if (chg_eof) + STps->eof = ST_NOEOF; + + if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) + STps->eof = ST_EOD; + + if (cmd_in == MTLOCK) + STp->door_locked = ST_LOCK_FAILS; + + } + *aSCpnt = SCpnt; + + return ioctl_result; +} + + +/* Open the device */ +static int os_scsi_tape_open(struct inode * inode, struct file * filp) +{ + unsigned short flags; + int i, b_size, need_dma_buffer, new_session = FALSE; + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Cmnd * SCpnt; + OS_Scsi_Tape * STp; + ST_mode * STm; + ST_partstat * STps; + int dev = TAPE_NR(inode->i_rdev); + int mode = TAPE_MODE(inode->i_rdev); + + if (dev >= osst_template.dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device) + return (-ENXIO); + + if( !scsi_block_when_processing_errors(STp->device) ) { + return -ENXIO; + } + + if (STp->in_use) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Device already in use.\n", dev); +#endif + return (-EBUSY); + } + STp->in_use = 1; + STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; + + if (STp->device->host->hostt->module) + __MOD_INC_USE_COUNT(STp->device->host->hostt->module); + if (osst_template.module) + __MOD_INC_USE_COUNT(osst_template.module); + + if (mode != STp->current_mode) { +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Mode change from %d to %d.\n", + dev, STp->current_mode, mode); +#endif + new_session = TRUE; + STp->current_mode = mode; + } + STm = &(STp->modes[STp->current_mode]); + + flags = filp->f_flags; + STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); + + STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0; + + /* Allocate a buffer for this user */ + need_dma_buffer = STp->restr_dma; + for (i=0; i < osst_nbr_buffers; i++) + if (!osst_buffers[i]->in_use && + (!need_dma_buffer || osst_buffers[i]->dma)) + break; + if (i >= osst_nbr_buffers) { + STp->buffer = new_tape_buffer(FALSE, need_dma_buffer); + if (STp->buffer == NULL) { + printk(KERN_WARNING "osst%d: Can't allocate tape buffer.\n", dev); + STp->in_use = 0; + if (STp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); + if(osst_template.module) + __MOD_DEC_USE_COUNT(osst_template.module); + return (-EBUSY); + } + } + else + STp->buffer = osst_buffers[i]; + (STp->buffer)->in_use = 1; + (STp->buffer)->writing = 0; + (STp->buffer)->last_result_fatal = 0; + (STp->buffer)->use_sg = STp->device->host->sg_tablesize; + + /* Compute the usable buffer size for this SCSI adapter */ + if (!(STp->buffer)->use_sg) + (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; + else { + for (i=0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && + i < (STp->buffer)->sg_segs; i++) + (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; + } + + STp->dirty = 0; + for (i=0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + } + STp->ready = ST_READY; + STp->recover_count = 0; +#if DEBUG + STp->nbr_waits = STp->nbr_finished = 0; +#endif + memset (cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SCpnt = osst_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE); + if (!SCpnt) { + STp->buffer->in_use = 0; + STp->buffer = NULL; + STp->in_use = 0; + + if (STp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); + if (osst_template.module) + __MOD_DEC_USE_COUNT(osst_template.module); + return (-EBUSY); + } + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY && + SCpnt->sense_buffer[12] == 4 ) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Unit not ready, cause %x\n", dev, SCpnt->sense_buffer[13]); +#endif + if (SCpnt->sense_buffer[13] == 2) { /* initialize command required (LOAD) */ + memset (cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = START_STOP; + cmd[1] = 1; + cmd[4] = 1; + SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE); + } + osst_wait_ready(STp, &SCpnt, (SCpnt->sense_buffer[13]==1?15:3) * 60); + } + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ +#if DEBUG + printk(OSST_DEB_MSG "osst%d: Unit wants attention\n", dev); +#endif + STp->header_ok = 0; + + for (i=0; i < 10; i++) { + + memset (cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE); + if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || + (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION) + break; + } + + STp->device->was_reset = 0; + STp->partition = STp->new_partition = 0; + if (STp->can_partitions) + STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ + for (i=0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + STps->eof = ST_NOEOF; + STps->at_sm = 0; + STps->last_block_valid = FALSE; + STps->drv_block = 0; + STps->drv_file = 0 ; + } + new_session = TRUE; + } + /* + * if we have valid headers from before, and the drive/tape seem untouched, + * open without reconfiguring and re-reading the headers + */ + if (!STp->buffer->last_result_fatal && STp->header_ok && + !SCpnt->result && SCpnt->sense_buffer[0] == 0 ) { + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SENSE; + cmd[1] = 8; + cmd[2] = VENDOR_IDENT_PAGE; + cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + + if (STp->buffer->last_result_fatal || + STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' || + STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' || + STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' || + STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d: signature was changed to %c%c%c%c\n", dev, + STp->buffer->b_data[MODE_HEADER_LENGTH + 2], + STp->buffer->b_data[MODE_HEADER_LENGTH + 3], + STp->buffer->b_data[MODE_HEADER_LENGTH + 4], + STp->buffer->b_data[MODE_HEADER_LENGTH + 5]); +#endif + STp->header_ok = 0; + } + i = STp->first_frame_position; + if (STp->header_ok && i == osst_get_frame_position(STp, &SCpnt)) { + if (STp->door_locked == ST_UNLOCKED) { + if (osst_int_ioctl(STp, &SCpnt, MTLOCK, 0)) + printk(KERN_WARNING "osst%d: Can't lock drive door\n", dev); + else + STp->door_locked = ST_LOCKED_AUTO; + } + STp->fast_open = TRUE; + scsi_release_command(SCpnt); + return 0; + } +#if DEBUG + if (i != STp->first_frame_position) + printk(OSST_DEB_MSG "osst%d: tape position changed from %d to %d\n", dev, i, STp->first_frame_position); +#endif + STp->header_ok = 0; + } + STp->fast_open = FALSE; + + if ((STp->buffer)->last_result_fatal != 0 && /* in all error conditions except no medium */ + (SCpnt->sense_buffer[2] != 2 || SCpnt->sense_buffer[12] != 0x3A) ) { + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = MODE_SELECT; + cmd[1] = 0x10; + cmd[4] = 4 + MODE_HEADER_LENGTH; + + (STp->buffer)->b_data[0] = cmd[4] - 1; + (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ + (STp->buffer)->b_data[2] = 0; /* Reserved */ + (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2; + (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3; + +#if 1 //DEBUG + printk(OSST_DEB_MSG "osst%i: Applying soft reset\n", dev); +#endif + SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + + STp->header_ok = 0; + + for (i=0; i < 10; i++) { + + memset (cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE); + if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || + (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY) + break; + + if ((SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { + STp->device->was_reset = 0; + STp->partition = STp->new_partition = 0; + if (STp->can_partitions) + STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ + for (i=0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + STps->eof = ST_NOEOF; + STps->at_sm = 0; + STps->last_block_valid = FALSE; + STps->drv_block = 0; + STps->drv_file = 0 ; + } + new_session = TRUE; + } + } + } + + if (osst_wait_ready(STp, &SCpnt, 3 * 60)) /* FIXME - not allowed with NOBLOCK */ + printk(KERN_WARNING "osst%i: Device did not become Ready in open\n",dev); + + if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->device)->scsi_level >= SCSI_2 && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY && + SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */ + STp->ready = ST_NO_TAPE; + } else + STp->ready = ST_NOT_READY; + scsi_release_command(SCpnt); + SCpnt = NULL; + STp->density = 0; /* Clear the erroneous "residue" */ + STp->write_prot = 0; + STp->block_size = 0; + STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); + STp->partition = STp->new_partition = 0; + STp->door_locked = ST_UNLOCKED; + return 0; + } + + STp->min_block = STp->max_block = (-1); + + osst_configure_onstream(STp, &SCpnt); + +/* STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */ + + if (OS_FRAME_SIZE > (STp->buffer)->buffer_size && + !enlarge_buffer(STp->buffer, OS_FRAME_SIZE, STp->restr_dma)) { + printk(KERN_NOTICE "osst%d: Framesize %d too large for buffer.\n", dev, + OS_FRAME_SIZE); + scsi_release_command(SCpnt); + SCpnt = NULL; + STp->buffer->in_use = 0; + STp->buffer = NULL; + if (STp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); + if (osst_template.module) + __MOD_DEC_USE_COUNT(osst_template.module); + return (-EIO); + } + + if ((STp->buffer)->buffer_size >= OS_FRAME_SIZE) + { + for (i = 0, b_size = 0; + i < STp->buffer->sg_segs && (b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE; + b_size += STp->buffer->sg[i++].length); + STp->buffer->aux = (os_aux_t *) (STp->buffer->sg[i].address + OS_DATA_SIZE - b_size); +#if DEBUG + printk(OSST_DEB_MSG "osst%d: b_data points to %p in segment 0 at %p\n", dev, + STp->buffer->b_data, STp->buffer->sg[0].address); + printk(OSST_DEB_MSG "osst%d: AUX points to %p in segment %d at %p\n", dev, + STp->buffer->aux, i, STp->buffer->sg[i].address); +#endif + } else + STp->buffer->aux = NULL; /* this had better never happen! */ + + (STp->buffer)->buffer_blocks = 1; + (STp->buffer)->buffer_bytes = + (STp->buffer)->read_pointer = + STp->logical_blk_in_buffer = 0; + +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n", + dev, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size, + (STp->buffer)->buffer_blocks); +#endif + + if (STp->drv_write_prot) { + STp->write_prot = 1; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Write protected\n", dev); +#endif + if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { + (STp->buffer)->in_use = 0; + STp->buffer = NULL; + STp->in_use = 0; + STp->in_use = 0; + if (STp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); + if(osst_template.module) + __MOD_DEC_USE_COUNT(osst_template.module); + scsi_release_command(SCpnt); + SCpnt = NULL; + return (-EROFS); + } + } + + if (new_session) { /* Change the drive parameters for the new mode */ +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: New Session\n", dev); +#endif + STp->density_changed = STp->blksize_changed = FALSE; + STp->compression_changed = FALSE; + } + + /* + * properly position the tape and check the ADR headers + */ + if (STp->door_locked == ST_UNLOCKED) { + if (osst_int_ioctl(STp, &SCpnt, MTLOCK, 0)) + printk(KERN_WARNING "osst%d: Can't lock drive door\n", dev); + else + STp->door_locked = ST_LOCKED_AUTO; + } + + osst_analyze_headers(STp, &SCpnt); + + scsi_release_command(SCpnt); + SCpnt = NULL; + + return 0; +} + + +/* Flush the tape buffer before close */ +static int os_scsi_tape_flush(struct file * filp) +{ + int result = 0, result2; + OS_Scsi_Tape * STp; + ST_mode * STm; + ST_partstat * STps; + Scsi_Cmnd *SCpnt = NULL; + + struct inode *inode = filp->f_dentry->d_inode; + kdev_t devt = inode->i_rdev; + int dev; + + if (filp->f_count > 1) + return 0; + + dev = TAPE_NR(devt); + STp = os_scsi_tapes[dev]; + STm = &(STp->modes[STp->current_mode]); + STps = &(STp->ps[STp->partition]); + + if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { + result = osst_flush_write_buffer(STp, &SCpnt, 1); + if (result != 0 && result != (-ENOSPC)) + goto out; + } + + if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { + +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d: File length %ld bytes.\n", + dev, (long)(filp->f_pos)); + printk(OSST_DEB_MSG "osst%d: Async write waits %d, finished %d.\n", + dev, STp->nbr_waits, STp->nbr_finished); + } +#endif + + result = osst_flush_drive_buffer(STp, &SCpnt); + if (result < 0) goto out; + result = osst_write_filemark(STp, &SCpnt); + if (result < 0) goto out; + + if (STps->drv_file >= 0) + STps->drv_file++ ; + STps->drv_block = 0; +//osst_report_stats(); + result = osst_write_eod(STp, &SCpnt); + osst_write_header(STp, &SCpnt, !(STp->rew_at_close)); + + STps->eof = ST_FM; + +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d: Buffer flushed, %d EOF(s) written\n", + dev, 1+STp->two_fm); +#endif + } + else if (!STp->rew_at_close) { + STps = &(STp->ps[STp->partition]); + if (!STm->sysv || STps->rw != ST_READING) { + if (STp->can_bsr) + result = osst_flush_buffer(STp, &SCpnt, 0); + else if (STps->eof == ST_FM_HIT) { + result = cross_eof(STp, &SCpnt, FALSE); + if (result) { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + STps->eof = ST_FM; + } + else + STps->eof = ST_NOEOF; + } + } + else if ((STps->eof == ST_NOEOF && + !(result = cross_eof(STp, &SCpnt, TRUE))) || + STps->eof == ST_FM_HIT) { + if (STps->drv_file >= 0) + STps->drv_file++; + STps->drv_block = 0; + STps->eof = ST_FM; + } + } + +out: + if (STp->rew_at_close) { + result2 = osst_position_tape_and_confirm(STp, &SCpnt, STp->first_data_ppos); + STps->drv_file = STps->drv_block = STp->logical_blk_num = 0; + if (result == 0) + result = result2; + } + if (SCpnt) scsi_release_command(SCpnt); + + return result; +} + + +/* Close the device and release it */ +static int os_scsi_tape_close(struct inode * inode, struct file * filp) +{ + int result = 0; + OS_Scsi_Tape * STp; + Scsi_Cmnd *SCpnt = NULL; + + kdev_t devt = inode->i_rdev; + int dev; + + dev = TAPE_NR(devt); + STp = os_scsi_tapes[dev]; + + if (STp->door_locked == ST_LOCKED_AUTO) + osst_int_ioctl(STp, &SCpnt, MTUNLOCK, 0); + if (SCpnt) scsi_release_command(SCpnt); + + if (STp->buffer != 0) + STp->buffer->in_use = 0; + + STp->in_use = 0; + if (STp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); + if(osst_template.module) + __MOD_DEC_USE_COUNT(osst_template.module); + + return result; +} + + +/* The ioctl command */ +static int osst_ioctl(struct inode * inode,struct file * file, + unsigned int cmd_in, unsigned long arg) +{ + int i, cmd_nr, cmd_type; + unsigned int blk; + struct mtop mtc; + struct mtpos mt_pos; + OS_Scsi_Tape *STp; + ST_mode *STm; + ST_partstat *STps; + Scsi_Cmnd *SCpnt = NULL; + int dev = TAPE_NR(inode->i_rdev); + + STp = os_scsi_tapes[dev]; +#if DEBUG + if (debugging && !STp->in_use) { + printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + STm = &(STp->modes[STp->current_mode]); + STps = &(STp->ps[STp->partition]); + + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + if( !scsi_block_when_processing_errors(STp->device) ) { + return -ENXIO; + } + + cmd_type = _IOC_TYPE(cmd_in); + cmd_nr = _IOC_NR(cmd_in); + + if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { + if (_IOC_SIZE(cmd_in) != sizeof(mtc)) + return (-EINVAL); + + i = copy_from_user((char *) &mtc, (char *)arg, sizeof(struct mtop)); + if (i) + return (-EFAULT); + + if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { + printk(KERN_WARNING "osst%d: MTSETDRVBUFFER only allowed for root.\n", dev); + return (-EPERM); + } + if (!STm->defined && + (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) + return (-ENXIO); + + if (!(STp->device)->was_reset) { + + if (STps->eof == ST_FM_HIT) { + if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { + mtc.mt_count -= 1; + if (STps->drv_file >= 0) + STps->drv_file += 1; + } + else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { + mtc.mt_count += 1; + if (STps->drv_file >= 0) + STps->drv_file += 1; + } + } + + if (mtc.mt_op == MTSEEK) { + /* Old position must be restored if partition will be changed */ + i = !STp->can_partitions || + (STp->new_partition != STp->partition); + } + else { + i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || + mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || + mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || + mtc.mt_op == MTCOMPRESSION; + } + i = osst_flush_buffer(STp, &SCpnt, i); + if (SCpnt) scsi_release_command(SCpnt); + if (i < 0) + return i; + } + else { + /* + * If there was a bus reset, block further access + * to this device. If the user wants to rewind the tape, + * then reset the flag and allow access again. + */ + if(mtc.mt_op != MTREW && + mtc.mt_op != MTOFFL && + mtc.mt_op != MTRETEN && + mtc.mt_op != MTERASE && + mtc.mt_op != MTSEEK && + mtc.mt_op != MTEOM) + return (-EIO); + STp->device->was_reset = 0; + if (STp->door_locked != ST_UNLOCKED && + STp->door_locked != ST_LOCK_FAILS) { + if (osst_int_ioctl(STp, &SCpnt, MTLOCK, 0)) { + printk(KERN_NOTICE "osst%d: Could not relock door after bus reset.\n", + dev); + STp->door_locked = ST_UNLOCKED; + } + } + } + + if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && + mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && + mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) + STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ + + if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) + osst_int_ioctl(STp, &SCpnt, MTUNLOCK, 0); /* Ignore result! */ + if (SCpnt) scsi_release_command(SCpnt); + + if (mtc.mt_op == MTSETDRVBUFFER && + (mtc.mt_count & MT_ST_OPTIONS) != 0) + return osst_set_options(STp, mtc.mt_count); + if (mtc.mt_op == MTSETPART) { +/* if (!STp->can_partitions || + mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) + return (-EINVAL); + if (mtc.mt_count >= STp->nbr_partitions && + (STp->nbr_partitions = nbr_partitions(inode)) < 0) + return (-EIO);*/ + if (mtc.mt_count >= STp->nbr_partitions) + return (-EINVAL); + STp->new_partition = mtc.mt_count; + return 0; + } + if (mtc.mt_op == MTMKPART) { + if (!STp->can_partitions) + return (-EINVAL); + if ((i = osst_int_ioctl(STp, &SCpnt, MTREW, 0)) < 0 /*|| + (i = partition_tape(inode, mtc.mt_count)) < 0*/) { + if (SCpnt) scsi_release_command(SCpnt); + return i; + } + for (i=0; i < ST_NBR_PARTITIONS; i++) { + STp->ps[i].rw = ST_IDLE; + STp->ps[i].at_sm = 0; + STp->ps[i].last_block_valid = FALSE; + } + STp->partition = STp->new_partition = 0; + STp->nbr_partitions = 1; /* Bad guess ?-) */ + STps->drv_block = STps->drv_file = 0; + return 0; + } + if (mtc.mt_op == MTSEEK) { + i = osst_seek_frame(STp, &SCpnt, mtc.mt_count); + if (SCpnt) scsi_release_command(SCpnt); + if (!STp->can_partitions) + STp->ps[0].rw = ST_IDLE; + return i; + } +/* if (STp->can_partitions && STp->ready == ST_READY && + (i = update_partition(inode)) < 0) + return i;*/ + if (mtc.mt_op == MTCOMPRESSION) + return (-EINVAL)/*osst_compression(STp, (mtc.mt_count & 1))*/; + else { + i = osst_int_ioctl(STp, &SCpnt, mtc.mt_op, mtc.mt_count); + if (SCpnt) scsi_release_command(SCpnt); + return i; + } + } + + if (!STm->defined) + return (-ENXIO); + + i = osst_flush_buffer(STp, &SCpnt, FALSE); + if (SCpnt) scsi_release_command(SCpnt); + if (i < 0) + return i; +/* if (STp->can_partitions && + (i = update_partition(inode)) < 0) + return i;*/ + + if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { + struct mtget mt_status; + + if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) + return (-EINVAL); + + mt_status.mt_type = MT_ISONSTREAM_SC; + mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT; + mt_status.mt_dsreg = + ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | + ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); + mt_status.mt_blkno = STps->drv_block; + mt_status.mt_fileno = STps->drv_file; + if (STp->block_size != 0) { + if (STps->rw == ST_WRITING) + mt_status.mt_blkno += + (STp->buffer)->buffer_bytes / STp->block_size; + else if (STps->rw == ST_READING) + mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes + + STp->block_size - 1) / STp->block_size; + } + + mt_status.mt_gstat = 0; + if (STp->drv_write_prot) + mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff); + if (mt_status.mt_blkno == 0) { + if (mt_status.mt_fileno == 0) + mt_status.mt_gstat |= GMT_BOT(0xffffffff); + else + mt_status.mt_gstat |= GMT_EOF(0xffffffff); + } + mt_status.mt_resid = STp->partition; + if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) + mt_status.mt_gstat |= GMT_EOT(0xffffffff); + else if (STps->eof >= ST_EOM_OK) + mt_status.mt_gstat |= GMT_EOD(0xffffffff); + if (STp->density == 1) + mt_status.mt_gstat |= GMT_D_800(0xffffffff); + else if (STp->density == 2) + mt_status.mt_gstat |= GMT_D_1600(0xffffffff); + else if (STp->density == 3) + mt_status.mt_gstat |= GMT_D_6250(0xffffffff); + if (STp->ready == ST_READY) + mt_status.mt_gstat |= GMT_ONLINE(0xffffffff); + if (STp->ready == ST_NO_TAPE) + mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff); + if (STps->at_sm) + mt_status.mt_gstat |= GMT_SM(0xffffffff); + if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || + STp->drv_buffer != 0) + mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); + + i = copy_to_user((char *)arg, (char *)&mt_status, + sizeof(struct mtget)); + if (i) + return (-EFAULT); + + STp->recover_erreg = 0; /* Clear after read */ + return 0; + } /* End of MTIOCGET */ + + if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { + if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) + return (-EINVAL); + blk = osst_get_frame_position(STp, &SCpnt); + if (SCpnt) scsi_release_command(SCpnt); + if (blk < 0) + return blk; + mt_pos.mt_blkno = blk; + i = copy_to_user((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos)); + if (i) + return (-EFAULT); + return 0; + } + + return scsi_ioctl(STp->device, cmd_in, (void *) arg); +} + + +/* Memory handling routines */ + +/* Try to allocate a new tape buffer */ +static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma ) +{ + int i, priority, b_size, order, got = 0, segs = 0; + OSST_buffer *tb; + + if (osst_nbr_buffers >= osst_template.dev_max) + return NULL; /* Should never happen */ + + if (from_initialization) + priority = GFP_ATOMIC; + else + priority = GFP_KERNEL; + + i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); + tb = (OSST_buffer *)kmalloc(i, priority); + if (tb) { +// tb->this_size = i; + if (need_dma) + priority |= GFP_DMA; + + /* Try to allocate the first segment up to OSST_FIRST_ORDER and the + others big enough to reach the goal */ + for (b_size = PAGE_SIZE, order = 0; + b_size < osst_buffer_size && order < OSST_FIRST_ORDER; + b_size *= 2, order++ ); + + for ( ; b_size >= PAGE_SIZE; order--, b_size /= 2) { + tb->sg[0].address = + (unsigned char *)__get_free_pages(priority, order); + if (tb->sg[0].address != NULL) { + tb->sg[0].alt_address = NULL; + tb->sg[0].length = b_size; + break; + } + } + if (tb->sg[segs].address == NULL) { + kfree(tb); + tb = NULL; + } + else { /* Got something, continue */ + + for (b_size = PAGE_SIZE, order = 0; + osst_buffer_size > tb->sg[0].length + (OSST_FIRST_SG - 1) * b_size; + b_size *= 2, order++ ); + + for (segs=1, got=tb->sg[0].length; + got < osst_buffer_size && segs < OSST_FIRST_SG; ) { + tb->sg[segs].address = + (unsigned char *)__get_free_pages(priority, order); + if (tb->sg[segs].address == NULL) { + if (osst_buffer_size - got <= + (OSST_FIRST_SG - segs) * b_size / 2) { + b_size /= 2; /* Large enough for the rest of the buffers */ + order--; + continue; + } + tb->sg_segs = segs; + tb->orig_sg_segs = 0; +#if DEBUG + tb->buffer_size = got; +#endif + normalize_buffer(tb); + kfree(tb); + tb = NULL; + break; + } + tb->sg[segs].alt_address = NULL; + tb->sg[segs].length = b_size; + got += b_size; + segs++; + } + } + } + if (!tb) { + printk(KERN_NOTICE "osst: Can't allocate new tape buffer (nbr %d).\n", + osst_nbr_buffers); + return NULL; + } + tb->sg_segs = tb->orig_sg_segs = segs; + tb->b_data = tb->sg[0].address; + +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG + "osst: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n", + osst_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data); + printk(OSST_DEB_MSG + "osst: segment sizes: first %d, last %d bytes.\n", + tb->sg[0].length, tb->sg[segs-1].length); + } +#endif + tb->in_use = 0; + tb->dma = need_dma; + tb->buffer_size = got; + tb->writing = 0; + osst_buffers[osst_nbr_buffers++] = tb; + + return tb; +} + + +/* Try to allocate a temporary enlarged tape buffer */ +static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma) +{ + int segs, nbr, max_segs, b_size, priority, order, got; + + normalize_buffer(STbuffer); + + max_segs = STbuffer->use_sg; + if (max_segs > osst_max_sg_segs) + max_segs = osst_max_sg_segs; + nbr = max_segs - STbuffer->sg_segs; + if (nbr <= 0) + return FALSE; + + priority = GFP_KERNEL; + if (need_dma) + priority |= GFP_DMA; + for (b_size = PAGE_SIZE, order = 0; + b_size * nbr < new_size - STbuffer->buffer_size; + b_size *= 2, order++); + + for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size; + segs < max_segs && got < new_size; ) { + STbuffer->sg[segs].address = + (unsigned char *)__get_free_pages(priority, order); + if (STbuffer->sg[segs].address == NULL) { + if (new_size - got <= (max_segs - segs) * b_size / 2) { + b_size /= 2; /* Large enough for the rest of the buffers */ + order--; + continue; + } + printk(KERN_NOTICE "osst: Failed to enlarge buffer to %d bytes.\n", + new_size); +#if DEBUG + STbuffer->buffer_size = got; +#endif + normalize_buffer(STbuffer); + return FALSE; + } + STbuffer->sg[segs].alt_address = NULL; + STbuffer->sg[segs].length = b_size; + STbuffer->sg_segs += 1; + got += b_size; + STbuffer->buffer_size = got; + segs++; + } +#if DEBUG + if (debugging) { + for (nbr=0; osst_buffers[nbr] != STbuffer && nbr < osst_nbr_buffers; nbr++); + printk(OSST_DEB_MSG + "osst: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).\n", + nbr, got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data); + printk(OSST_DEB_MSG + "osst: segment sizes: first %d, last %d bytes.\n", + STbuffer->sg[0].length, STbuffer->sg[segs-1].length); + } +#endif + + return TRUE; +} + + +/* Release the extra buffer */ +static void normalize_buffer(OSST_buffer *STbuffer) +{ + int i, order, b_size; + + for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) { + + for (b_size = PAGE_SIZE, order = 0; + b_size < STbuffer->sg[i].length; + b_size *= 2, order++); + + free_pages((unsigned long)STbuffer->sg[i].address, order); + STbuffer->buffer_size -= STbuffer->sg[i].length; + } +#if DEBUG + if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) + printk(OSST_DEB_MSG "osst: Buffer at %p normalized to %d bytes (segs %d).\n", + STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); +#endif + STbuffer->sg_segs = STbuffer->orig_sg_segs; +} + + +/* Move data from the user buffer to the tape buffer. Returns zero (success) or + negative error code. */ +static int append_to_buffer(const char *ubp, OSST_buffer *st_bp, int do_count) +{ + int i, cnt, res, offset; + + for (i=0, offset=st_bp->buffer_bytes; + i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) + offset -= st_bp->sg[i].length; + if (i == st_bp->sg_segs) { /* Should never happen */ + printk(KERN_WARNING "osst: Append_to_buffer offset overflow.\n"); + return (-EIO); + } + for ( ; i < st_bp->sg_segs && do_count > 0; i++) { + cnt = st_bp->sg[i].length - offset < do_count ? + st_bp->sg[i].length - offset : do_count; + res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt); + if (res) + return (-EFAULT); + do_count -= cnt; + st_bp->buffer_bytes += cnt; + ubp += cnt; + offset = 0; + } + if (do_count) { /* Should never happen */ + printk(KERN_WARNING "osst: Append_to_buffer overflow (left %d).\n", + do_count); + return (-EIO); + } + return 0; +} + + +/* Move data from the tape buffer to the user buffer. Returns zero (success) or + negative error code. */ +static int from_buffer(OSST_buffer *st_bp, char *ubp, int do_count) +{ + int i, cnt, res, offset; + + for (i=0, offset=st_bp->read_pointer; + i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) + offset -= st_bp->sg[i].length; + if (i == st_bp->sg_segs) { /* Should never happen */ + printk(KERN_WARNING "osst: From_buffer offset overflow.\n"); + return (-EIO); + } + for ( ; i < st_bp->sg_segs && do_count > 0; i++) { + cnt = st_bp->sg[i].length - offset < do_count ? + st_bp->sg[i].length - offset : do_count; + res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt); + if (res) + return (-EFAULT); + do_count -= cnt; + st_bp->buffer_bytes -= cnt; + st_bp->read_pointer += cnt; + ubp += cnt; + offset = 0; + } + if (do_count) { /* Should never happen */ + printk(KERN_WARNING "osst: From_buffer overflow (left %d).\n", + do_count); + return (-EIO); + } + return 0; +} + +/* Sets the tail of the buffer after fill point to zero. + Returns zero (success) or negative error code. */ +static int osst_zero_buffer_tail(OSST_buffer *st_bp) +{ + int i, offset, do_count, cnt; + + for (i = 0, offset = st_bp->buffer_bytes; + i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) + offset -= st_bp->sg[i].length; + if (i == st_bp->sg_segs) { /* Should never happen */ + printk(KERN_WARNING "osst: Zero_buffer offset overflow.\n"); + return (-EIO); + } + for (do_count = OS_DATA_SIZE - st_bp->read_pointer; + i < st_bp->sg_segs && do_count > 0; i++) { + cnt = st_bp->sg[i].length - offset < do_count ? + st_bp->sg[i].length - offset : do_count ; + memset(st_bp->sg[i].address + offset, 0, cnt); + do_count -= cnt; + offset = 0; + } + if (do_count) { /* Should never happen */ + printk(KERN_WARNING "osst: Zero_buffer overflow (left %d).\n", do_count); + return (-EIO); + } + return 0; +} + +/* Copy a osst 32K block of memory into the buffer. + Returns zero (success) or negative error code. */ +static int osst_copy_to_buffer(OSST_buffer *st_bp, unsigned char *ptr) +{ + int i, cnt, do_count = OS_DATA_SIZE; + + for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { + cnt = st_bp->sg[i].length < do_count ? + st_bp->sg[i].length : do_count ; + memcpy(st_bp->sg[i].address, ptr, cnt); + do_count -= cnt; + ptr += cnt; + } + if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ + printk(KERN_WARNING "osst: Copy_to_buffer overflow (left %d at sg %d).\n", + do_count, i); + return (-EIO); + } + return 0; +} + +/* Copy a osst 32K block of memory from the buffer. + Returns zero (success) or negative error code. */ +static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr) +{ + int i, cnt, do_count = OS_DATA_SIZE; + + for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { + cnt = st_bp->sg[i].length < do_count ? + st_bp->sg[i].length : do_count ; + memcpy(ptr, st_bp->sg[i].address, cnt); + do_count -= cnt; + ptr += cnt; + } + if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ + printk(KERN_WARNING "osst: Copy_from_buffer overflow (left %d at sg %d).\n", + do_count, i); + return (-EIO); + } + return 0; +} + + +/* Module housekeeping */ + +#ifndef MODULE +/* Set the boot options. Syntax: st=xxx,yyy + where xxx is buffer size in 1024 byte blocks and yyy is write threshold + in 1024 byte blocks. */ +__initfunc( void osst_setup(char *str, int *ints)) +{ + if (ints[0] > 0 && ints[1] > 0) + osst_buffer_size = ints[1] * ST_KILOBYTE; + if (ints[0] > 1 && ints[2] > 0) { + osst_write_threshold = ints[2] * ST_KILOBYTE; + if (osst_write_threshold > osst_buffer_size) + osst_write_threshold = osst_buffer_size; + } + if (ints[0] > 2 && ints[3] > 0) + osst_max_buffers = ints[3]; +} +#endif + + +static struct file_operations osst_fops = { + NULL, /* lseek - default */ + osst_read, /* read - general block-dev read */ + osst_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + osst_ioctl, /* ioctl */ + NULL, /* mmap */ + os_scsi_tape_open, /* open */ + os_scsi_tape_flush, /* flush */ + os_scsi_tape_close, /* release */ + NULL /* fsync */ +}; + + +static int osst_attach(Scsi_Device * SDp){ + OS_Scsi_Tape * tpnt; + ST_mode * STm; + ST_partstat * STps; + int i; +#ifdef CONFIG_DEVFS_FS + int mode; +#endif + + if (SDp->type != TYPE_TAPE || !OSST_SUPPORTS(SDp)) + return 1; + + if (osst_template.nr_dev >= osst_template.dev_max) { + SDp->attached--; + return 1; + } + + /* find a free minor number */ + for (i=0; os_scsi_tapes[i] && i= osst_template.dev_max) panic ("Scsi_devices corrupt (osst)"); + + /* allocate a OS_Scsi_Tape for this device */ + tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC); + if (tpnt == NULL) { + SDp->attached--; + printk(KERN_ERR "osst: Can't allocate device descriptor.\n"); + return 1; + } + memset(tpnt, 0, sizeof(OS_Scsi_Tape)); + os_scsi_tapes[i] = tpnt; + tpnt->capacity = 0xfffff; + + /* allocate a buffer for this device */ + if (!new_tape_buffer(TRUE, TRUE)) + printk(KERN_ERR "osst: Unable to allocate a tape buffer.\n"); + +#ifdef CONFIG_DEVFS_FS + for (mode = 0; mode < ST_NBR_MODES; ++mode) { + char name[8]; + static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"}; + + /* Rewind entry */ + sprintf (name, "mt%s", formats[mode]); + tpnt->de_r[mode] = + devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT, + MAJOR_NR, i + (mode << 5), + S_IFCHR | S_IRUGO | S_IWUGO, + 0, 0, &osst_fops, NULL); + /* No-rewind entry */ + sprintf (name, "mt%sn", formats[mode]); + tpnt->de_n[mode] = + devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT, + MAJOR_NR, i + (mode << 5) + 128, + S_IFCHR | S_IRUGO | S_IWUGO, + 0, 0, &osst_fops, NULL); + } + devfs_register_tape (tpnt->de_r[0]); +#endif + + tpnt->device = SDp; + tpnt->devt = MKDEV(MAJOR_NR, i); + tpnt->dirty = 0; + tpnt->in_use = 0; + tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ + tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; + tpnt->density = 0; + tpnt->do_auto_lock = OSST_AUTO_LOCK; + tpnt->can_bsr = OSST_IN_FILE_POS; + tpnt->can_partitions = 0; + tpnt->two_fm = OSST_TWO_FM; + tpnt->fast_mteom = OSST_FAST_MTEOM; + tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */ + tpnt->write_threshold = osst_write_threshold; + tpnt->default_drvbuffer = 0xff; /* No forced buffering */ + tpnt->partition = 0; + tpnt->new_partition = 0; + tpnt->nbr_partitions = 0; + tpnt->timeout = OSST_TIMEOUT; + tpnt->long_timeout = OSST_LONG_TIMEOUT; + + /* Recognize OnStream tapes */ + printk ("osst%i: Tape driver with OnStream support osst %s\nosst%i: %s\n", + i, osst_version, i, cvsid); + /* We don't need to test for OnStream, as this has been done in detect () */ + tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev); +#if DEBUG + printk ("osst%i: OnStream tape drive recognized, Model %s\n", i, SDp->model); +#endif + tpnt->omit_blklims = 1; + + tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp); + tpnt->logical_blk_in_buffer = 0; + tpnt->header_ok = 0; + tpnt->linux_media = 0; + tpnt->header_cache = NULL; + + for (i=0; i < ST_NBR_MODES; i++) { + STm = &(tpnt->modes[i]); + STm->defined = FALSE; + STm->sysv = OSST_SYSV; + STm->defaults_for_writes = 0; + STm->do_async_writes = OSST_ASYNC_WRITES; + STm->do_buffer_writes = OSST_BUFFER_WRITES; + STm->do_read_ahead = OSST_READ_AHEAD; + STm->default_compression = ST_DONT_TOUCH; + STm->default_blksize = 32 * ST_KILOBYTE; /* No forced size */ + STm->default_density = (-1); /* No forced density */ + } + + for (i=0; i < ST_NBR_PARTITIONS; i++) { + STps = &(tpnt->ps[i]); + STps->rw = ST_IDLE; + STps->eof = ST_NOEOF; + STps->at_sm = 0; + STps->last_block_valid = FALSE; + STps->drv_block = (-1); + STps->drv_file = (-1); + } + + tpnt->current_mode = 0; + tpnt->modes[0].defined = TRUE; + + tpnt->density_changed = tpnt->compression_changed = + tpnt->blksize_changed = FALSE; + + osst_template.nr_dev++; + return 0; +}; + +static int osst_detect(Scsi_Device * SDp) +{ + if (SDp->type != TYPE_TAPE) return 0; + /* We are willing to drive OnStream SC-x0 as well as the + * IDE, ParPort, USB variants, if accessible by emulation + * layer (ide-scsi, usb-storage, ...) */ + if (!OSST_SUPPORTS(SDp)) return 0; + + printk(KERN_WARNING + "Detected OnStream scsi tape osst%d at scsi%d, channel %d, id %d, lun %d\n", + osst_template.dev_noticed++, + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + + return 1; +} + +static int osst_registered = 0; + +/* Driver initialization (not __initfunc because may be called later) */ +static int osst_init() +{ + int i; + + if (osst_template.dev_noticed == 0) return 0; + + if(!osst_registered) { +#ifdef CONFIG_DEVFS_FS + if (devfs_register_chrdev(MAJOR_NR,"osst",&osst_fops)) { +#else + if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) { +#endif + printk(KERN_ERR "osst: Unable to get major %d for OnStream tapes\n",MAJOR_NR); + return 1; + } + osst_registered++; + } + + if (os_scsi_tapes) return 0; + osst_template.dev_max = OSST_MAX_TAPES; + if (osst_template.dev_max > 128 / ST_NBR_MODES) + printk(KERN_INFO "osst: Only %d tapes accessible.\n", 128 / ST_NBR_MODES); + os_scsi_tapes = + (OS_Scsi_Tape **)kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *), + GFP_ATOMIC); + if (os_scsi_tapes == NULL) { + printk(KERN_ERR "osst: Unable to allocate array for OnStream SCSI tapes.\n"); +#ifdef CONFIG_DEVFS_FS + devfs_unregister_chrdev(MAJOR_NR, "osst"); +#else + unregister_chrdev(MAJOR_NR, "osst"); +#endif + return 1; + } + + for (i=0; i < osst_template.dev_max; ++i) os_scsi_tapes[i] = NULL; + + /* Allocate the buffer pointers */ + osst_buffers = + (OSST_buffer **)kmalloc(osst_template.dev_max * sizeof(OSST_buffer *), + GFP_ATOMIC); + if (osst_buffers == NULL) { + printk(KERN_ERR "osst: Unable to allocate tape buffer pointers.\n"); +#ifdef CONFIG_DEVFS_FS + devfs_unregister_chrdev(MAJOR_NR, "osst"); +#else + unregister_chrdev(MAJOR_NR, "osst"); +#endif + kfree(os_scsi_tapes); + return 1; + } + osst_nbr_buffers = 0; + +#if DEBUG + printk(OSST_DEB_MSG "osst: Buffer size %d bytes, write threshold %d bytes.\n", + osst_buffer_size, osst_write_threshold); +#endif + return 0; +} + + +static void osst_detach(Scsi_Device * SDp) +{ + OS_Scsi_Tape * tpnt; + int i; +#ifdef CONFIG_DEVFS_FS + int mode; +#endif + + for(i=0; idevice == SDp) { + tpnt->device = NULL; +#ifdef CONFIG_DEVFS_FS + for (mode = 0; mode < ST_NBR_MODES; ++mode) { + devfs_unregister (tpnt->de_r[mode]); + tpnt->de_r[mode] = NULL; + devfs_unregister (tpnt->de_n[mode]); + tpnt->de_n[mode] = NULL; + } +#endif + kfree(tpnt); + os_scsi_tapes[i] = NULL; + SDp->attached--; + osst_template.nr_dev--; + osst_template.dev_noticed--; + return; + } + } + return; +} + + +#ifdef MODULE + +int init_module(void) { + int result; + + if (buffer_kbs > 0) + osst_buffer_size = buffer_kbs * ST_KILOBYTE; + if (write_threshold_kbs > 0) + osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; + if (osst_write_threshold > osst_buffer_size) + osst_write_threshold = osst_buffer_size; + if (max_buffers > 0) + osst_max_buffers = max_buffers; + if (max_sg_segs >= OSST_FIRST_SG) + osst_max_sg_segs = max_sg_segs; + printk(KERN_INFO "osst: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n", + osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs); +//printk(OSST_DEB_MSG "osst: sizeof(header) = %d (%s)\n",sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error"); + osst_template.module = &__this_module; + result = scsi_register_module(MODULE_SCSI_DEV, &osst_template); + if (result) + return result; + + return 0; +} + +void cleanup_module( void) +{ + int i; + OS_Scsi_Tape * STp; + + scsi_unregister_module(MODULE_SCSI_DEV, &osst_template); +#ifdef CONFIG_DEVFS_FS + devfs_unregister_chrdev(MAJOR_NR, "osst"); +#else + unregister_chrdev(MAJOR_NR, "osst"); +#endif + osst_registered--; + if(os_scsi_tapes != NULL) { + for (i=0; i < osst_template.dev_max; ++i) { + if ((STp = os_scsi_tapes[i])) { + if (STp->header_cache != NULL) vfree(STp->header_cache); + kfree(STp); + } + } + kfree(os_scsi_tapes); + + if (osst_buffers != NULL) { + for (i=0; i < osst_nbr_buffers; i++) + if (osst_buffers[i] != NULL) { + osst_buffers[i]->orig_sg_segs = 0; + normalize_buffer(osst_buffers[i]); + kfree(osst_buffers[i]); + } + + kfree(osst_buffers); + } + } + osst_template.dev_max = 0; + printk(KERN_INFO "osst: Unloaded.\n"); +} +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/osst.h linux/drivers/scsi/osst.h --- v2.2.18/drivers/scsi/osst.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/osst.h Sun Mar 25 11:37:36 2001 @@ -0,0 +1,514 @@ +/* + * $Header: /home/cvsroot/Driver/osst.h,v 1.5.2.2 2000/10/08 03:07:33 riede Exp $ + */ + +#include +#ifdef CONFIG_DEVFS_FS +#include +#endif + +/* FIXME - rename and use the following two types or delete them! + * and the types really should go to st.h anyway... + * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) + */ +typedef struct { + unsigned device_type :5; /* Peripheral Device Type */ + unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ + unsigned reserved1_6t0 :7; /* Reserved */ + unsigned rmb :1; /* Removable Medium Bit */ + unsigned ansi_version :3; /* ANSI Version */ + unsigned ecma_version :3; /* ECMA Version */ + unsigned iso_version :2; /* ISO Version */ + unsigned response_format :4; /* Response Data Format */ + unsigned reserved3_45 :2; /* Reserved */ + unsigned reserved3_6 :1; /* TrmIOP - Reserved */ + unsigned reserved3_7 :1; /* AENC - Reserved */ + u8 additional_length; /* Additional Length (total_length-4) */ + u8 rsv5, rsv6, rsv7; /* Reserved */ + u8 vendor_id[8]; /* Vendor Identification */ + u8 product_id[16]; /* Product Identification */ + u8 revision_level[4]; /* Revision Level */ + u8 vendor_specific[20]; /* Vendor Specific - Optional */ + u8 reserved56t95[40]; /* Reserved - Optional */ + /* Additional information may be returned */ +} idetape_inquiry_result_t; + +/* + * READ POSITION packet command - Data Format (From Table 6-57) + */ +typedef struct { + unsigned reserved0_10 :2; /* Reserved */ + unsigned bpu :1; /* Block Position Unknown */ + unsigned reserved0_543 :3; /* Reserved */ + unsigned eop :1; /* End Of Partition */ + unsigned bop :1; /* Beginning Of Partition */ + u8 partition; /* Partition Number */ + u8 reserved2, reserved3; /* Reserved */ + u32 first_block; /* First Block Location */ + u32 last_block; /* Last Block Location (Optional) */ + u8 reserved12; /* Reserved */ + u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */ + u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */ +} idetape_read_position_result_t; + +/* + * Follows structures which are related to the SELECT SENSE / MODE SENSE + * packet commands. + */ +#define COMPRESSION_PAGE 0x0f +#define COMPRESSION_PAGE_LENGTH 16 + +#define CAPABILITIES_PAGE 0x2a +#define CAPABILITIES_PAGE_LENGTH 20 + +#define TAPE_PARAMTR_PAGE 0x2b +#define TAPE_PARAMTR_PAGE_LENGTH 16 + +#define NUMBER_RETRIES_PAGE 0x2f +#define NUMBER_RETRIES_PAGE_LENGTH 4 + +#define BLOCK_SIZE_PAGE 0x30 +#define BLOCK_SIZE_PAGE_LENGTH 4 + +#define BUFFER_FILLING_PAGE 0x33 +#define BUFFER_FILLING_PAGE_LENGTH + +#define VENDOR_IDENT_PAGE 0x36 +#define VENDOR_IDENT_PAGE_LENGTH 8 + +#define LOCATE_STATUS_PAGE 0x37 +#define LOCATE_STATUS_PAGE_LENGTH 0 + +#define MODE_HEADER_LENGTH 4 + + +/* + * REQUEST SENSE packet command result - Data Format. + */ +typedef struct { + unsigned error_code :7; /* Current of deferred errors */ + unsigned valid :1; /* The information field conforms to QIC-157C */ + u8 reserved1 :8; /* Segment Number - Reserved */ + unsigned sense_key :4; /* Sense Key */ + unsigned reserved2_4 :1; /* Reserved */ + unsigned ili :1; /* Incorrect Length Indicator */ + unsigned eom :1; /* End Of Medium */ + unsigned filemark :1; /* Filemark */ + u32 information __attribute__ ((packed)); + u8 asl; /* Additional sense length (n-7) */ + u32 command_specific; /* Additional command specific information */ + u8 asc; /* Additional Sense Code */ + u8 ascq; /* Additional Sense Code Qualifier */ + u8 replaceable_unit_code; /* Field Replaceable Unit Code */ + unsigned sk_specific1 :7; /* Sense Key Specific */ + unsigned sksv :1; /* Sense Key Specific information is valid */ + u8 sk_specific2; /* Sense Key Specific */ + u8 sk_specific3; /* Sense Key Specific */ + u8 pad[2]; /* Padding to 20 bytes */ +} idetape_request_sense_result_t; + +/* + * Mode Parameter Header for the MODE SENSE packet command + */ +typedef struct { + u8 mode_data_length; /* Length of the following data transfer */ + u8 medium_type; /* Medium Type */ + u8 dsp; /* Device Specific Parameter */ + u8 bdl; /* Block Descriptor Length */ +} osst_mode_parameter_header_t; + +/* + * Mode Parameter Block Descriptor the MODE SENSE packet command + * + * Support for block descriptors is optional. + */ +typedef struct { + u8 density_code; /* Medium density code */ + u8 blocks[3]; /* Number of blocks */ + u8 reserved4; /* Reserved */ + u8 length[3]; /* Block Length */ +} osst_parameter_block_descriptor_t; + +/* + * The Data Compression Page, as returned by the MODE SENSE packet command. + */ +typedef struct { + unsigned page_code :6; /* Page Code - Should be 0xf */ + unsigned reserved0 :1; /* Reserved */ + unsigned ps :1; + u8 page_length; /* Page Length - Should be 14 */ + unsigned reserved2 :6; /* Reserved */ + unsigned dcc :1; /* Data Compression Capable */ + unsigned dce :1; /* Data Compression Enable */ + unsigned reserved3 :5; /* Reserved */ + unsigned red :2; /* Report Exception on Decompression */ + unsigned dde :1; /* Data Decompression Enable */ + u32 ca; /* Compression Algorithm */ + u32 da; /* Decompression Algorithm */ + u8 reserved[4]; /* Reserved */ +} osst_data_compression_page_t; + +/* + * The Medium Partition Page, as returned by the MODE SENSE packet command. + */ +typedef struct { + unsigned page_code :6; /* Page Code - Should be 0x11 */ + unsigned reserved1_6 :1; /* Reserved */ + unsigned ps :1; + u8 page_length; /* Page Length - Should be 6 */ + u8 map; /* Maximum Additional Partitions - Should be 0 */ + u8 apd; /* Additional Partitions Defined - Should be 0 */ + unsigned reserved4_012 :3; /* Reserved */ + unsigned psum :2; /* Should be 0 */ + unsigned idp :1; /* Should be 0 */ + unsigned sdp :1; /* Should be 0 */ + unsigned fdp :1; /* Fixed Data Partitions */ + u8 mfr; /* Medium Format Recognition */ + u8 reserved[2]; /* Reserved */ +} osst_medium_partition_page_t; + +/* + * Capabilities and Mechanical Status Page + */ +typedef struct { + unsigned page_code :6; /* Page code - Should be 0x2a */ + unsigned reserved1_67 :2; + u8 page_length; /* Page Length - Should be 0x12 */ + u8 reserved2, reserved3; + unsigned ro :1; /* Read Only Mode */ + unsigned reserved4_1234 :4; + unsigned sprev :1; /* Supports SPACE in the reverse direction */ + unsigned reserved4_67 :2; + unsigned reserved5_012 :3; + unsigned efmt :1; /* Supports ERASE command initiated formatting */ + unsigned reserved5_4 :1; + unsigned qfa :1; /* Supports the QFA two partition formats */ + unsigned reserved5_67 :2; + unsigned lock :1; /* Supports locking the volume */ + unsigned locked :1; /* The volume is locked */ + unsigned prevent :1; /* The device defaults in the prevent state after power up */ + unsigned eject :1; /* The device can eject the volume */ + unsigned reserved6_45 :2; /* Reserved */ + unsigned ecc :1; /* Supports error correction */ + unsigned cmprs :1; /* Supports data compression */ + unsigned reserved7_0 :1; + unsigned blk512 :1; /* Supports 512 bytes block size */ + unsigned blk1024 :1; /* Supports 1024 bytes block size */ + unsigned reserved7_3_6 :4; + unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ + /* transfers for slow buffer memory ??? */ + /* Also 32768 block size in some cases */ + u16 max_speed; /* Maximum speed supported in KBps */ + u8 reserved10, reserved11; + u16 ctl; /* Continuous Transfer Limit in blocks */ + u16 speed; /* Current Speed, in KBps */ + u16 buffer_size; /* Buffer Size, in 512 bytes */ + u8 reserved18, reserved19; +} osst_capabilities_page_t; + +/* + * Block Size Page + */ +typedef struct { + unsigned page_code :6; /* Page code - Should be 0x30 */ + unsigned reserved1_6 :1; + unsigned ps :1; + u8 page_length; /* Page Length - Should be 2 */ + u8 reserved2; + unsigned play32 :1; + unsigned play32_5 :1; + unsigned reserved2_23 :2; + unsigned record32 :1; + unsigned record32_5 :1; + unsigned reserved2_6 :1; + unsigned one :1; +} osst_block_size_page_t; + +/* + * Tape Parameters Page + */ +typedef struct { + unsigned page_code :6; /* Page code - Should be 0x2b */ + unsigned reserved1_6 :1; + unsigned ps :1; + u8 reserved2; + u8 density; + u8 reserved3,reserved4; + u16 segtrk; + u16 trks; + u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; +} osst_tape_paramtr_page_t; + +/* OnStream definitions */ + +#define OS_CONFIG_PARTITION (0xff) +#define OS_DATA_PARTITION (0) +#define OS_PARTITION_VERSION (1) + +/* + * partition + */ +typedef struct os_partition_s { + __u8 partition_num; + __u8 par_desc_ver; + __u16 wrt_pass_cntr; + __u32 first_frame_ppos; + __u32 last_frame_ppos; + __u32 eod_frame_ppos; +} os_partition_t; + +/* + * DAT entry + */ +typedef struct os_dat_entry_s { + __u32 blk_sz; + __u16 blk_cnt; + __u8 flags; + __u8 reserved; +} os_dat_entry_t; + +/* + * DAT + */ +#define OS_DAT_FLAGS_DATA (0xc) +#define OS_DAT_FLAGS_MARK (0x1) + +typedef struct os_dat_s { + __u8 dat_sz; + __u8 reserved1; + __u8 entry_cnt; + __u8 reserved3; + os_dat_entry_t dat_list[16]; +} os_dat_t; + +/* + * Frame types + */ +#define OS_FRAME_TYPE_FILL (0) +#define OS_FRAME_TYPE_EOD (1 << 0) +#define OS_FRAME_TYPE_MARKER (1 << 1) +#define OS_FRAME_TYPE_HEADER (1 << 3) +#define OS_FRAME_TYPE_DATA (1 << 7) + +/* + * AUX + */ +typedef struct os_aux_s { + __u32 format_id; /* hardware compability AUX is based on */ + char application_sig[4]; /* driver used to write this media */ + __u32 hdwr; /* reserved */ + __u32 update_frame_cntr; /* for configuration frame */ + __u8 frame_type; + __u8 frame_type_reserved; + __u8 reserved_18_19[2]; + os_partition_t partition; + __u8 reserved_36_43[8]; + __u32 frame_seq_num; + __u32 logical_blk_num_high; + __u32 logical_blk_num; + os_dat_t dat; + __u8 reserved188_191[4]; + __u32 filemark_cnt; + __u32 phys_fm; + __u32 last_mark_ppos; + __u8 reserved204_223[20]; + + /* + * __u8 app_specific[32]; + * + * Linux specific fields: + */ + __u32 next_mark_ppos; /* when known, points to next marker */ + __u8 linux_specific[28]; + + __u8 reserved_256_511[256]; +} os_aux_t; + +#define OS_FM_TAB_MAX 1024 + +typedef struct os_fm_tab_s { + __u8 fm_part_num; + __u8 reserved_1; + __u8 fm_tab_ent_sz; + __u8 reserved_3; + __u16 fm_tab_ent_cnt; + __u8 reserved6_15[10]; + __u32 fm_tab_ent[OS_FM_TAB_MAX]; +} os_fm_tab_t; + +typedef struct os_ext_trk_ey_s { + __u8 et_part_num; + __u8 fmt; + __u16 fm_tab_off; + __u8 reserved4_7[4]; + __u32 last_hlb_hi; + __u32 last_hlb; + __u32 last_pp; + __u8 reserved20_31[12]; +} os_ext_trk_ey_t; + +typedef struct os_ext_trk_tb_s { + __u8 nr_stream_part; + __u8 reserved_1; + __u8 et_ent_sz; + __u8 reserved3_15[13]; + os_ext_trk_ey_t dat_ext_trk_ey; + os_ext_trk_ey_t qfa_ext_trk_ey; +} os_ext_trk_tb_t; + +typedef struct os_header_s { + char ident_str[8]; + __u8 major_rev; + __u8 minor_rev; + __u16 ext_trk_tb_off; + __u8 reserved12_15[4]; + __u8 pt_par_num; + __u8 pt_reserved1_3[3]; + os_partition_t partition[16]; + __u32 cfg_col_width; + __u32 dat_col_width; + __u32 qfa_col_width; + __u8 cartridge[16]; + __u8 reserved304_511[208]; + __u32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ + os_ext_trk_tb_t ext_track_tb; + __u8 reserved17272_17735[464]; + os_fm_tab_t dat_fm_tab; + os_fm_tab_t qfa_fm_tab; + __u8 reserved25960_32767[6808]; +} os_header_t; + + +/* + * OnStream ADRL frame + */ +#define OS_FRAME_SIZE (32 * 1024 + 512) +#define OS_DATA_SIZE (32 * 1024) +#define OS_AUX_SIZE (512) +//#define OSST_MAX_SG 2 + +/* The tape buffer descriptor. */ +typedef struct { + unsigned char in_use; + unsigned char dma; /* DMA-able buffer */ + int this_size; /* allocated size of the structure */ + int buffer_size; + int buffer_blocks; + int buffer_bytes; + int read_pointer; + int writing; + int last_result; + int last_result_fatal; + Scsi_Cmnd *last_SCpnt; + unsigned char *b_data; + os_aux_t *aux; /* onstream AUX structure at end of each block */ + unsigned short use_sg; /* zero or number of segments for this adapter */ + unsigned short sg_segs; /* total number of allocated segments */ + unsigned short orig_sg_segs; /* number of segments allocated at first try */ + struct scatterlist sg[1]; /* MUST BE last item */ +} OSST_buffer; + +/* The tape drive descriptor */ +typedef struct { + kdev_t devt; + unsigned capacity; + Scsi_Device* device; + struct semaphore sem; + OSST_buffer * buffer; + + /* Drive characteristics */ + unsigned char omit_blklims; + unsigned char do_auto_lock; + unsigned char can_bsr; + unsigned char can_partitions; + unsigned char two_fm; + unsigned char fast_mteom; + unsigned char restr_dma; + unsigned char scsi2_logical; + unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ + int write_threshold; + int timeout; /* timeout for normal commands */ + int long_timeout; /* timeout for commands known to take long time*/ + + /* Mode characteristics */ + ST_mode modes[ST_NBR_MODES]; + int current_mode; +#ifdef CONFIG_DEVFS_FS + devfs_handle_t de_r[ST_NBR_MODES]; /* Rewind entries */ + devfs_handle_t de_n[ST_NBR_MODES]; /* No-rewind entries */ +#endif + + /* Status variables */ + int partition; + int new_partition; + int nbr_partitions; /* zero until partition support enabled */ + ST_partstat ps[ST_NBR_PARTITIONS]; + unsigned char dirty; + unsigned char ready; + unsigned char write_prot; + unsigned char drv_write_prot; + unsigned char in_use; + unsigned char blksize_changed; + unsigned char density_changed; + unsigned char compression_changed; + unsigned char drv_buffer; + unsigned char density; + unsigned char door_locked; + unsigned char rew_at_close; + int block_size; + int min_block; + int max_block; + int recover_count; /* from tape opening */ + int recover_erreg; /* from last status call */ + /* + * OnStream specific data + */ + int os_fw_rev; /* the firmware revision * 10000 */ + unsigned char raw; /* flag OnStream raw access (32.5KB block size) */ + unsigned char poll; /* flag that this drive needs polling (IDE|firmware) */ + unsigned char logical_blk_in_buffer; /* flag that the block as per logical_blk_num + * has been read into STp->buffer and is valid */ + int logical_blk_num; /* logical block number */ + unsigned first_frame_position; /* physical frame to be transfered to/from host */ + unsigned last_frame_position; /* physical frame to be transferd to/from tape */ + int cur_frames; /* current number of frames in internal buffer */ + int max_frames; /* max number of frames in internal buffer */ + char application_sig[5]; /* application signature */ + unsigned char fast_open; /* flag that reminds us we didn't check headers at open */ + unsigned short wrt_pass_cntr; /* write pass counter */ + int update_frame_cntr; /* update frame counter */ + int onstream_write_error; /* write error recovery active */ + int header_ok; /* header frame verified ok */ + int linux_media; /* reading linux-specifc media */ + int linux_media_version; + os_header_t * header_cache; /* cache is kept for filemark positions */ + int filemark_cnt; + int first_mark_ppos; + int last_mark_ppos; + int first_data_ppos; + int eod_frame_ppos; + int eod_frame_lfa; + int write_type; /* used in write error recovery */ + int read_error_frame; /* used in read error recovery */ + unsigned long cmd_start_time; + unsigned long max_cmd_time; + +#if DEBUG + unsigned char write_pending; + int nbr_finished; + int nbr_waits; + unsigned char last_cmnd[6]; + unsigned char last_sense[16]; +#endif +} OS_Scsi_Tape; + +extern Scsi_Tape * scsi_tapes; + +/* Values of write_type */ +#define OS_WRITE_DATA 0 +#define OS_WRITE_EOD 1 +#define OS_WRITE_NEW_MARK 2 +#define OS_WRITE_LAST_MARK 3 +#define OS_WRITE_HEADER 4 +#define OS_WRITE_FILLER 5 + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/osst_detect.h linux/drivers/scsi/osst_detect.h --- v2.2.18/drivers/scsi/osst_detect.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/osst_detect.h Sun Mar 25 11:37:36 2001 @@ -0,0 +1,5 @@ +#define OSST_SUPPORTS(SDp) (! ( memcmp (SDp->vendor, "OnStream", 8) || \ + ( memcmp (SDp->model, "SC-", 3) && \ + memcmp (SDp->model, "DI-", 3) && \ + memcmp (SDp->model, "DP-", 3) && \ + memcmp (SDp->model, "USB", 3) ) ) ) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/osst_options.h linux/drivers/scsi/osst_options.h --- v2.2.18/drivers/scsi/osst_options.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/scsi/osst_options.h Sun Mar 25 11:37:36 2001 @@ -0,0 +1,100 @@ +/* + The compile-time configurable defaults for the Linux SCSI tape driver. + + Copyright 1995 Kai Makisara. + + Last modified: Wed Sep 2 21:24:07 1998 by root@home + + Changed (and renamed) for OnStream SCSI drives garloff@suse.de + 2000-06-21 + + $Header: /home/cvsroot/Driver/osst_options.h,v 1.4 2000/06/26 01:44:01 riede Exp $ +*/ + +#ifndef _OSST_OPTIONS_H +#define _OSST_OPTIONS_H + +/* The minimum limit for the number of SCSI tape devices is determined by + OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by + OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */ +#define OSST_MAX_TAPES 4 + +/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the + record been read by the user program even if the tape has moved further + because of buffered reads. Should be set to zero to support also drives + that can't space backwards over records. NOTE: The tape will be + spaced backwards over an "accidentally" crossed filemark in any case. */ +#define OSST_IN_FILE_POS 0 + +/* The tape driver buffer size in kilobytes. */ +/* Don't change, as this is the HW blocksize */ +#define OSST_BUFFER_BLOCKS 32 + +/* The number of kilobytes of data in the buffer that triggers an + asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES + below. */ +#define OSST_WRITE_THRESHOLD_BLOCKS 30 + +/* The maximum number of tape buffers the driver allocates. The number + is also constrained by the number of drives detected. Determines the + maximum number of concurrently active tape drives. */ +#define OSST_MAX_BUFFERS OSST_MAX_TAPES + +/* Maximum number of scatter/gather segments */ +/* Fit one buffer in pages and add one for the AUX header */ +#define OSST_MAX_SG (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1) + +/* The number of scatter/gather segments to allocate at first try (must be + smaller or equal to the maximum). */ +#define OSST_FIRST_SG ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + +/* The size of the first scatter/gather segments (determines the maximum block + size for SCSI adapters not supporting scatter/gather). The default is set + to try to allocate the buffer as one chunk. */ +#define OSST_FIRST_ORDER 5 + + +/* The following lines define defaults for properties that can be set + separately for each drive using the MTSTOPTIONS ioctl. */ + +/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a + file being written. Some drives can't handle two filemarks at the + end of data. */ +#define OSST_TWO_FM 0 + +/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are + buffered until the driver buffer is full or asynchronous write is + triggered. May make detection of End-Of-Medium early enough fail. */ +#define OSST_BUFFER_WRITES 1 + +/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started + without waiting for it to finish. May cause problems in multiple + tape backups. */ +#define OSST_ASYNC_WRITES 1 + +/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block + mode. */ +#define OSST_READ_AHEAD 1 + +/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first + read or write command after the device is opened. The door is opened + when the device is closed. */ +#define OSST_AUTO_LOCK 0 + +/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the + direct SCSI command. The file number status is lost but this method + is fast with some drives. Otherwise MTEOM is done by spacing over + files and the file number status is retained. */ +#define OSST_FAST_MTEOM 0 + +/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for + MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL + is zero. */ +#define OSST_SCSI2LOGICAL 0 + +/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics. + The default is BSD semantics. */ +#define OSST_SYSV 0 + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.2.18/drivers/scsi/ppa.c Sun Mar 25 11:28:30 2001 +++ linux/drivers/scsi/ppa.c Sun Mar 25 11:37:36 2001 @@ -31,6 +31,7 @@ Scsi_Cmnd *cur_cmd; /* Current queued command */ struct tq_struct ppa_tq; /* Polling interupt stuff */ unsigned long jstart; /* Jiffies at start */ + unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */ unsigned int failed:1; /* Failure flag */ unsigned int p_busy:1; /* Parport sharing busy flag */ } ppa_struct; @@ -43,6 +44,7 @@ cur_cmd: NULL, \ ppa_tq: {0, 0, ppa_interrupt, NULL}, \ jstart: 0, \ + recon_tmo: PPA_RECON_TMO, \ failed: 0, \ p_busy: 0 \ } @@ -236,6 +238,12 @@ ppa_hosts[hostno].mode = x; return length; } + if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) { + x = simple_strtoul(buffer + 10, NULL, 0); + ppa_hosts[hostno].recon_tmo = x; + printk("ppa: recon_tmo set to %ld\n", x); + return length; + } printk("ppa /proc: invalid variable\n"); return (-EINVAL); } @@ -256,6 +264,9 @@ len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION); len += sprintf(buffer + len, "Parport : %s\n", ppa_hosts[i].dev->port->name); len += sprintf(buffer + len, "Mode : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]); +#if PPA_DEBUG > 0 + len += sprintf(buffer + len, "recon_tmo : %lu\n", ppa_hosts[i].recon_tmo); +#endif /* Request for beyond end of buffer */ if (offset > length) @@ -299,12 +310,11 @@ unsigned char r; k = PPA_SPIN_TMO; - do { - r = r_str(ppb); - k--; - udelay(1); + /* Wait for bit 6 and 7 - PJC */ + for (r = r_str (ppb); ((r & 0xc0)!=0xc0) && (k); k--) { + udelay (1); + r = r_str (ppb); } - while (!(r & 0x80) && (k)); /* * return some status information. @@ -545,6 +555,7 @@ k = PPA_SELECT_TMO; do { k--; + udelay(1); } while ((r_str(ppb) & 0x40) && (k)); if (!k) return 0; @@ -558,6 +569,7 @@ k = PPA_SELECT_TMO; do { k--; + udelay(1); } while (!(r_str(ppb) & 0x40) && (k)); if (!k) @@ -667,12 +679,36 @@ if (time_after(jiffies, start_jiffies + 1)) return 0; - if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) { + if ((cmd->SCp.this_residual <= 0)) { ppa_fail(host_no, DID_ERROR); return -1; /* ERROR_RETURN */ } - /* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE)) - ? PPA_BURST_SIZE : 1; + + /* On some hardware we have SCSI disconnected (6th bit low) + * for about 100usecs. It is too expensive to wait a + * tick on every loop so we busy wait for no more than + * 500usecs to give the drive a chance first. We do not + * change things for "normal" hardware since generally + * the 6th bit is always high. + * This makes the CPU load higher on some hardware + * but otherwise we can not get more then 50K/secs + * on this problem hardware. + */ + if ((r & 0xc0) != 0xc0) { + /* Wait for reconnection should be no more than + * jiffy/2 = 5ms = 5000 loops + */ + unsigned long k = ppa_hosts[host_no].recon_tmo; + for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0; k--) + udelay(1); + + if(!k) + return 0; + } + + /* determine if we should use burst I/O */ + fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE)) + ? PPA_BURST_SIZE : 1; if (r == (unsigned char) 0xc0) status = ppa_out(host_no, cmd->SCp.ptr, fast); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h --- v2.2.18/drivers/scsi/ppa.h Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/ppa.h Sun Mar 25 11:37:36 2001 @@ -10,7 +10,7 @@ #ifndef _PPA_H #define _PPA_H -#define PPA_VERSION "2.03 (for Linux 2.2.x)" +#define PPA_VERSION "2.07 (for Linux 2.2.x)" /* * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu) @@ -51,6 +51,17 @@ * CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16 * added CONFIG_SCSI_IZIP_SLOW_CTR option * [2.03] + * + * Use ppa_wait() to check for ready AND connected status bits + * Busy wait for connected status bit in ppa_completion() + * in order to cope with some hardware that has this bit low + * for short periods of time. + * Add udelay() to ppa_select() + * by Dr. Peter Cherriman and + * Oleg Makarenko + * [2.04a] + * + * Fix kernel panic on scsi timeout, 2000-08-18 [2.07] */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ @@ -106,6 +117,7 @@ #define PPA_BURST_SIZE 512 /* data burst size */ #define PPA_SELECT_TMO 5000 /* how long to wait for target ? */ #define PPA_SPIN_TMO 50000 /* ppa_wait loop limiter */ +#define PPA_RECON_TMO 500 /* scsi reconnection loop limiter */ #define PPA_DEBUG 0 /* debuging option */ #define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32) @@ -166,6 +178,7 @@ eh_device_reset_handler: NULL, \ eh_bus_reset_handler: ppa_reset, \ eh_host_reset_handler: ppa_reset, \ + use_new_eh_code: 1, \ bios_param: ppa_biosparam, \ this_id: -1, \ sg_tablesize: SG_ALL, \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.2.18/drivers/scsi/scsi.h Sun Mar 25 11:13:00 2001 +++ linux/drivers/scsi/scsi.h Sun Mar 25 11:37:36 2001 @@ -634,7 +634,7 @@ extern int scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device); -#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR) +#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR) #include "hosts.h" static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c --- v2.2.18/drivers/scsi/scsiiom.c Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/scsiiom.c Sun Mar 25 11:37:36 2001 @@ -4,16 +4,40 @@ * Description: Device Driver for Tekram DC-390 (T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ -/* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */ +/* $Id: scsiiom.c,v 2.55.2.17 2000/12/20 00:39:37 garloff Exp $ */ + +static void __inline__ +dc390_freetag (PDCB pDCB, PSRB pSRB) +{ + if (pSRB->TagNumber < 255) { + pDCB->TagMask &= ~(1 << pSRB->TagNumber); /* free tag mask */ + pSRB->TagNumber = 255; + } +}; + UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) { - USHORT wlval; - UCHAR bval, bval1; + UCHAR cmd; UCHAR disc_allowed, try_sync_nego; + + pSRB->ScsiPhase = SCSI_NOP0; - pSRB->TagNumber = 31; - DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + if (pACB->Connected) + { + // Should not happen normally + printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n", + pSRB->SRBState, pSRB->SRBFlag); + pSRB->SRBState = SRB_READY; + pACB->SelConn++; + return 1; + } + if (time_before (jiffies, pACB->pScsiHost->last_reset)) + { + DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n");) + return 1; + } + DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); DC390_write8 (Sync_Period, pDCB->SyncPeriod); DC390_write8 (Sync_Offset, pDCB->SyncOffset); DC390_write8 (CtrlReg1, pDCB->CtrlR1); @@ -21,151 +45,105 @@ DC390_write8 (CtrlReg4, pDCB->CtrlR4); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\ - pSRB->CmdBlock[0], pDCB->SyncMode);) - pSRB->ScsiPhase = SCSI_NOP0; - //pSRB->MsgOutBuf[0] = MSG_NOP; - //pSRB->MsgCnt = 0; - bval = pDCB->IdentifyMsg; - if( !(pDCB->SyncMode & EN_ATN_STOP) ) /* Don't always try send Extended messages on arbitration */ - { - if( (pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - bval &= 0xBF; /* No DisConn */ - DC390_write8 (ScsiFifo, bval); - bval1 = SEL_W_ATN; - pSRB->SRBState = SRB_START_; - DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) - if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY) ) - { - bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */ - pSRB->SRBState = SRB_MSGOUT; - } - } - } - else /* TagQ ? */ - { - DC390_write8 (ScsiFifo, bval); - if(pDCB->SyncMode & EN_TAG_QUEUEING) - { - DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG); - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);) - bval = 0; wlval = 1; - while (wlval & pDCB->TagMask) - { bval++; wlval <<= 1; }; - pDCB->TagMask |= wlval; - DC390_write8 (ScsiFifo, bval); - pSRB->TagNumber = bval; - DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) - bval1 = SEL_W_ATN3; - pSRB->SRBState = SRB_START_; - } - else /* No TagQ */ - { - bval1 = SEL_W_ATN; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) - pSRB->SRBState = SRB_START_; - } - } + pSRB->pcmd->cmnd[0], pDCB->SyncMode);) + disc_allowed = pDCB->DevMode & EN_DISCONNECT_; try_sync_nego = 0; + /* Don't disconnect on AUTO_REQSENSE, cause it might be an + * Contingent Allegiance Condition (6.6), where no tags should be used. + * All other have to be allowed to disconnect to prevent Incorrect + * Initiator Connection (6.8.2/6.5.2) */ + /* Changed KG, 99/06/06 */ + if( /*(((pSRB->pcmd->cmnd[0] == INQUIRY) || (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || + * (pSRB->pcmd->cmnd[0] == TEST_UNIT_READY)) && pACB->scan_devices) + ||*/ (pSRB->SRBFlag & AUTO_REQSENSE) ) + disc_allowed = 0; + if ( (pDCB->SyncMode & SYNC_ENABLE) && (pDCB->TargetLUN == 0) && (pDCB->Inquiry7 & 0x10) && + ( ( ( (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) + && !(pDCB->SyncMode & SYNC_NEGO_DONE) ) || (pSRB->pcmd->cmnd[0] == INQUIRY) ) ) + try_sync_nego = 1; + + pSRB->MsgCnt = 0; cmd = SEL_W_ATN; + DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN)); + /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */ + if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed) + { + UCHAR tag_no = 0; + while ((1 << tag_no) & pDCB->TagMask) tag_no++; + if (tag_no >= sizeof (pDCB->TagMask)*8 || tag_no >= pDCB->MaxCommand) { + printk (KERN_WARNING "DC390: Out of tags for Dev. %02x %02x\n", pDCB->TargetID, pDCB->TargetLUN); + return 1; + //goto no_tag; + }; + DC390_write8 (ScsiFifo, SIMPLE_QUEUE_TAG); + pDCB->TagMask |= (1 << tag_no); pSRB->TagNumber = tag_no; + DC390_write8 (ScsiFifo, tag_no); + DEBUG1(printk (KERN_DEBUG "DC390: Select w/DisCn for Cmd %li (SRB %p), Using Tag %02x\n", pSRB->pcmd->pid, pSRB, tag_no);) + cmd = SEL_W_ATN3; + } + else /* No TagQ */ + { +// no_tag: + DEBUG1(printk (KERN_DEBUG "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", (disc_allowed?"":"o"), pSRB->pcmd->pid, pSRB);) + }; - } - else /* ATN_STOP: Always try to establish Sync nego */ - { - if( (pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - bval &= 0xBF; /* No DisConn */ - DC390_write8 (ScsiFifo, bval); - bval1 = SEL_W_ATN; - DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) - pSRB->SRBState = SRB_START_; - /* ??? */ - if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY) ) - { - bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */ - pSRB->SRBState = SRB_MSGOUT; - } - } - } - else /* TagQ ? */ - { - DC390_write8 (ScsiFifo, bval); - if(pDCB->SyncMode & EN_TAG_QUEUEING) - { - pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);) - bval = 0; wlval = 1; - while (wlval & pDCB->TagMask) - { bval++; wlval <<= 1; }; - pDCB->TagMask |= wlval; - pSRB->TagNumber = bval; - DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) - pSRB->MsgOutBuf[1] = bval; - pSRB->MsgCnt = 2; - bval1 = SEL_W_ATN_STOP; - pSRB->SRBState = SRB_START_; /* ?? */ - } - else /* No TagQ */ - { - pSRB->MsgOutBuf[0] = MSG_NOP; - pSRB->MsgCnt = 1; - pSRB->SRBState = SRB_START_; - bval1 = SEL_W_ATN_STOP; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) - }; - } - } - if (bval1 != SEL_W_ATN_STOP) - { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ + pSRB->SRBState = SRB_START_; + + if (try_sync_nego) + { + UCHAR Sync_Off = pDCB->SyncOffset; + DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);) + pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE; + pSRB->MsgOutBuf[1] = 3; + pSRB->MsgOutBuf[2] = EXTENDED_SDTR; + pSRB->MsgOutBuf[3] = pDCB->NegoPeriod; + if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET; + pSRB->MsgOutBuf[4] = Sync_Off; + pSRB->MsgCnt = 5; + //pSRB->SRBState = SRB_MSGOUT_; + pSRB->SRBState |= DO_SYNC_NEGO; + cmd = SEL_W_ATN_STOP; + }; + + /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ + if (cmd != SEL_W_ATN_STOP) + { if( pSRB->SRBFlag & AUTO_REQSENSE ) { - bval = 0; DC390_write8 (ScsiFifo, REQUEST_SENSE); - DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); - DC390_write8 (ScsiFifo, bval); - DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); + DC390_write8 (ScsiFifo, 0); + DC390_write8 (ScsiFifo, 0); DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); - DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, 0); DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");) } else /* write cmnd to bus */ { PUCHAR ptr; UCHAR i; - ptr = (PUCHAR) pSRB->CmdBlock; - for (i=0; iScsiCmdLen; i++) + ptr = (PUCHAR) pSRB->pcmd->cmnd; + for (i=0; ipcmd->cmd_len; i++) DC390_write8 (ScsiFifo, *(ptr++)); }; } - - /* Check if we can't win arbitration */ + DEBUG0(if (pACB->pActiveDCB) \ + printk (KERN_WARNING "DC390: ActiveDCB != 0\n");) + DEBUG0(if (pDCB->pActiveSRB) \ + printk (KERN_WARNING "DC390: ActiveSRB != 0\n");) + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); if (DC390_read8 (Scsi_Status) & INTERRUPT) { + dc390_freetag (pDCB, pSRB); + DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n", + pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);) pSRB->SRBState = SRB_READY; - pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); - DEBUG0(printk (KERN_WARNING "DC390: Interrupt during StartSCSI!\n");) + //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pACB->SelLost++; return 1; - } - else - { - pSRB->ScsiPhase = SCSI_NOP1; - DEBUG0(if (pACB->pActiveDCB) \ - printk (KERN_WARNING "DC390: ActiveDCB != 0\n");) - DEBUG0(if (pDCB->pActiveSRB) \ - printk (KERN_WARNING "DC390: ActiveSRB != 0\n");) - pACB->pActiveDCB = pDCB; - pDCB->pActiveSRB = pSRB; - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, bval1); - return 0; - } + }; + DC390_write8 (ScsiCmd, cmd); + pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; + pACB->Connected = 1; + pSRB->ScsiPhase = SCSI_NOP1; + return 0; } //#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ @@ -198,7 +176,7 @@ }; if (dstate & DMA_XFER_DONE) { - ULONG residual, xferCnt; int ctr = 5000000; + UINT residual, xferCnt; int ctr = 6000000; if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) { do @@ -236,47 +214,34 @@ void __inline__ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { - PACB pACB; + PACB pACB, pACB2; PDCB pDCB; PSRB pSRB; UCHAR sstatus=0; - UCHAR phase, i; + UCHAR phase; void (*stateV)( PACB, PSRB, PUCHAR ); UCHAR istate, istatus; #if DMA_INT UCHAR dstatus; #endif - DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS - - pACB = dc390_pACB_start; + DC390_AFLAGS DC390_IFLAGS //DC390_DFLAGS - if (pACB == 0) + pACB = (PACB)dev_id; + for (pACB2 = dc390_pACB_start; (pACB2 && pACB2 != pACB); pACB2 = pACB2->pNextACB); + if (!pACB2) { - printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n"); + printk ("DC390: IRQ called with foreign dev_id %p!\n", pACB); return; } - DC390_LOCK_DRV; + + //DC390_LOCK_DRV; - for( i=0; i < dc390_adapterCnt; i++ ) - { - if( pACB->IRQLevel == (UCHAR) irq ) - { - sstatus = DC390_read8 (Scsi_Status); - if( sstatus & INTERRUPT ) - break; - else - pACB = pACB->pNextACB; - } - else - { - pACB = pACB->pNextACB; - } - } + sstatus = DC390_read8 (Scsi_Status); + if( !(sstatus & INTERRUPT) ) + { /*DC390_UNLOCK_DRV;*/ return; }; DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);) - if( !pACB ) { DC390_UNLOCK_DRV; return; }; - #if DMA_INT DC390_LOCK_IO; DC390_LOCK_ACB; @@ -288,7 +253,7 @@ if (! (dstatus & SCSI_INTERRUPT)) { DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");) - DC390_UNLOCK_DRV; + //DC390_UNLOCK_DRV; return; }; #else @@ -299,7 +264,7 @@ DC390_LOCK_IO; DC390_LOCK_ACB; - DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ + //DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ istate = DC390_read8 (Intern_State); istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ @@ -310,23 +275,42 @@ if (sstatus & ILLEGAL_OP_ERR) { - printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus); + printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus); dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); - }; + } - if(istatus & DISCONNECTED) + else if (istatus & INVALID_CMD) + { + printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus); + dc390_InvalidCmd( pACB ); + goto unlock; + } + + if (istatus & SCSI_RESET) + { + dc390_ScsiRstDetect( pACB ); + goto unlock; + } + + if (istatus & DISCONNECTED) { dc390_Disconnect( pACB ); goto unlock; } - if(istatus & RESELECTED) + if (istatus & RESELECTED) { dc390_Reselect( pACB ); goto unlock; } - if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) + else if (istatus & (SELECTED | SEL_ATTENTION)) + { + printk (KERN_ERR "DC390: Target mode not supported!\n"); + goto unlock; + } + + if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) { pDCB = pACB->pActiveDCB; if (!pDCB) @@ -351,23 +335,11 @@ goto unlock; } - if(istatus & INVALID_CMD) - { - dc390_InvalidCmd( pACB ); - goto unlock; - } - - if(istatus & SCSI_RESET) - { - dc390_ScsiRstDetect( pACB ); - goto unlock; - } - unlock: - DC390_LOCK_DRV_NI; + //DC390_LOCK_DRV_NI; DC390_UNLOCK_ACB; DC390_UNLOCK_IO; - DC390_UNLOCK_DRV; /* Restore initial flags */ + //DC390_UNLOCK_DRV; /* Restore initial flags */ } void @@ -384,7 +356,7 @@ { UCHAR sstatus; PSGL psgl; - ULONG ResidCnt, xferCnt; + UINT ResidCnt, xferCnt; UCHAR dstate = 0; sstatus = *psstatus; @@ -396,7 +368,7 @@ if( sstatus & COUNT_2_ZERO ) { - int ctr = 5000000; /* only try for about a tenth of a second */ + int ctr = 6000000; /* only try for about a second */ while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; @@ -415,10 +387,10 @@ } else { - ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; - ResidCnt += (ULONG) DC390_read8 (CtcReg_Low); + ResidCnt = (UINT) DC390_read8 (Current_Fifo) & 0x1f; + ResidCnt |= (UINT) DC390_read8 (CtcReg_High) << 16; + ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid) << 8; + ResidCnt += (UINT) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; pSRB->SGBusAddr += xferCnt; @@ -426,7 +398,11 @@ pSRB->SGToBeXferLen = ResidCnt; } } - DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + if ((*psstatus & 7) != SCSI_DATA_OUT) + { + DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + } } void @@ -434,7 +410,8 @@ { UCHAR sstatus, residual, bval; PSGL psgl; - ULONG ResidCnt, xferCnt, i; + UINT ResidCnt, i; + ULONG xferCnt; PUCHAR ptr; sstatus = *psstatus; @@ -446,7 +423,7 @@ if( sstatus & COUNT_2_ZERO ) { - int ctr = 5000000; /* only try for about a tenth of a second */ + int ctr = 6000000; /* only try for about a second */ int dstate = 0; while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); @@ -455,7 +432,7 @@ DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \ + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \ + ((ULONG) DC390_read8 (CtcReg_Low));) - DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) + DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ @@ -509,12 +486,12 @@ //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; - DEBUG1(printk (KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000-i, bval);) - ResidCnt = (ULONG) DC390_read8 (CtcReg_High); + DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval);) + ResidCnt = (UINT) DC390_read8 (CtcReg_High); ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid); + ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid); ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low); + ResidCnt |= (UINT) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; pSRB->SGBusAddr += xferCnt; @@ -535,6 +512,11 @@ } } + if ((*psstatus & 7) != SCSI_DATA_IN) + { + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + } } static void @@ -593,7 +575,7 @@ static void __inline__ dc390_MsgIn_reject (PACB pACB, PSRB pSRB) { - pSRB->MsgOutBuf[0] = MSG_REJECT_; + pSRB->MsgOutBuf[0] = MESSAGE_REJECT; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");) } @@ -602,7 +584,7 @@ static void __inline__ dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB ) { - pSRB->MsgOutBuf[0] = MSG_ABORT; + pSRB->MsgOutBuf[0] = ABORT; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; } @@ -640,7 +622,7 @@ pSRB = pACB->pTmpSRB; pSRB->SRBState = SRB_UNEXPECT_RESEL; pDCB->pActiveSRB = pSRB; - pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; + pSRB->MsgOutBuf[0] = ABORT_TAG; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; } return pSRB; @@ -653,7 +635,7 @@ { PDCB pDCB = pSRB->pSRBDCB; if (!(pSRB->SRBState & DO_SYNC_NEGO)) - printk ("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID); + printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID); pSRB->SRBState &= ~DO_SYNC_NEGO; pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); pDCB->SyncPeriod = 0; @@ -677,8 +659,8 @@ if (!(pSRB->SRBState & DO_SYNC_NEGO)) { - printk ("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", - pDCB->UnitSCSIID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); + printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", + pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); /* reject */ //dc390_MsgIn_reject (pACB, pSRB); @@ -687,12 +669,12 @@ /* Reply with corrected SDTR Message */ if (pSRB->MsgInBuf[4] > 15) { - printk ("DC390: Lower Sync Offset to 15\n"); + printk (KERN_INFO "DC390: Lower Sync Offset to 15\n"); pSRB->MsgInBuf[4] = 15; } if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) { - printk ("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); + printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); pSRB->MsgInBuf[3] = pDCB->NegoPeriod; }; memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); @@ -728,10 +710,10 @@ pDCB->CtrlR3 = bval; pDCB->SyncPeriod = (UCHAR)wval1; - if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0) + if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0) { if (! (bval & FAST_SCSI)) wval1++; - printk ("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, + printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, 40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f); } @@ -739,6 +721,56 @@ }; +/* handle RESTORE_PTR */ +static void +dc390_restore_ptr (PACB pACB, PSRB pSRB) +{ + PSGL psgl; + pSRB->TotalXferredLen = 0; + pSRB->SGIndex = 0; + if( pSRB->pcmd->use_sg ) + { + pSRB->SGcount = (UCHAR) pSRB->pcmd->use_sg; + pSRB->pSegmentList = (PSGL) pSRB->pcmd->request_buffer; + psgl = pSRB->pSegmentList; + while (pSRB->TotalXferredLen + (ULONG) psgl->length < pSRB->Saved_Ptr) + { + pSRB->TotalXferredLen += (ULONG) psgl->length; + pSRB->SGIndex++; + if( pSRB->SGIndex < pSRB->SGcount ) + { + pSRB->pSegmentList++; + psgl = pSRB->pSegmentList; + + pSRB->SGBusAddr = virt_to_bus( psgl->address ); + pSRB->SGToBeXferLen = (ULONG) psgl->length; + } + else + pSRB->SGToBeXferLen = 0; + } + pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen); + pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen); + printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); + } + else if( pSRB->pcmd->request_buffer ) + { + pSRB->SGcount = 1; + pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pSRB->pcmd->request_buffer + pSRB->Saved_Ptr; + pSRB->Segmentx.length = pSRB->pcmd->request_bufflen - pSRB->Saved_Ptr; + printk (KERN_INFO "DC390: Pointer restored. Total %li, Bus %p\n", + pSRB->Saved_Ptr, pSRB->Segmentx.address); + } + else + { + pSRB->SGcount = 0; + printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n"); + }; + + pSRB->TotalXferredLen = pSRB->Saved_Ptr; +}; + + /* According to the docs, the AM53C974 reads the message and * generates a Succesful Operation IRQ before asserting ACK for * the last byte (how does it know whether it's the last ?) */ @@ -749,15 +781,15 @@ /* Check if the message is complete */ static UCHAR __inline__ -dc390_MsgIn_complete (UCHAR *msgbuf, ULONG len) +dc390_MsgIn_complete (UCHAR *msgbuf, UINT len) { - if (*msgbuf == MSG_EXTENDED) - { - if (len < 2) return 0; - if (len < msgbuf[1] + 2) return 0; - } + if (*msgbuf == EXTENDED_MESSAGE) + { + if (len < 2) return 0; + if (len < msgbuf[1] + 2) return 0; + } else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages - if (len < 2) return 0; + if (len < 2) return 0; return 1; } @@ -781,23 +813,23 @@ /* Now eval the msg */ switch (pSRB->MsgInBuf[0]) { - case MSG_DISCONNECT: + case DISCONNECT: pSRB->SRBState = SRB_DISCONNECT; break; - case MSG_SIMPLE_QTAG: - case MSG_HEAD_QTAG: - case MSG_ORDER_QTAG: + case SIMPLE_QUEUE_TAG: + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]); break; - case MSG_REJECT_: + case MESSAGE_REJECT: DC390_write8 (ScsiCmd, RESET_ATN_CMD); pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ if( pSRB->SRBState & DO_SYNC_NEGO) dc390_MsgIn_set_async (pACB, pSRB); break; - case MSG_EXTENDED: + case EXTENDED_MESSAGE: /* reject every extended msg but SDTR */ if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) dc390_MsgIn_reject (pACB, pSRB); @@ -810,15 +842,18 @@ }; // nothing has to be done - case MSG_COMPLETE: break; + case COMMAND_COMPLETE: break; - // SAVE POINTER my be ignored as we have the PSRB associated with the + // SAVE POINTER may be ignored as we have the PSRB associated with the // scsi command. Thanks, Gerard, for pointing it out. - case MSG_SAVE_PTR: break; + case SAVE_POINTERS: + pSRB->Saved_Ptr = pSRB->TotalXferredLen; + break; // The device might want to restart transfer with a RESTORE - case MSG_RESTORE_PTR: - printk ("DC390: RESTORE POINTER message received ... reject\n"); - // fall through + case RESTORE_POINTERS: + DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n");) + dc390_restore_ptr (pACB, pSRB); + break; // reject unknown messages default: dc390_MsgIn_reject (pACB, pSRB); @@ -840,6 +875,17 @@ { PSGL psgl; ULONG lval; + PDCB pDCB = pACB->pActiveDCB; + + if (pSRB == pACB->pTmpSRB) + { + if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", + pDCB->TargetID, pDCB->TargetLUN); + else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); + dc390_EnableMsgOut_Abort (pACB, pSRB); + if (pDCB) pDCB->DCBFlag |= ABORT_DEV; + return; + } if( pSRB->SGIndex < pSRB->SGcount ) { @@ -852,7 +898,7 @@ DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");) } lval = pSRB->SGToBeXferLen; - DEBUG1(printk (KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) + DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) DC390_write8 (CtcReg_Low, (UCHAR) lval); lval >>= 8; DC390_write8 (CtcReg_Mid, (UCHAR) lval); @@ -918,8 +964,8 @@ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) { - cnt = (UCHAR) pSRB->ScsiCmdLen; - ptr = (PUCHAR) pSRB->CmdBlock; + cnt = (UCHAR) pSRB->pcmd->cmd_len; + ptr = (PUCHAR) pSRB->pcmd->cmnd; for(i=0; i < cnt; i++) DC390_write8 (ScsiFifo, *(ptr++)); } @@ -928,11 +974,12 @@ UCHAR bval = 0; DC390_write8 (ScsiFifo, REQUEST_SENSE); pDCB = pACB->pActiveDCB; - DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); + DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); DC390_write8 (ScsiFifo, bval); DC390_write8 (ScsiFifo, bval); DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); DC390_write8 (ScsiFifo, bval); + DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n");) } pSRB->SRBState = SRB_COMMAND; DC390_write8 (ScsiCmd, INFO_XFER_CMD); @@ -966,14 +1013,14 @@ DC390_write8 (ScsiFifo, *(ptr++)); pSRB->MsgCnt = 0; if( (pDCB->DCBFlag & ABORT_DEV_) && - (pSRB->MsgOutBuf[0] == MSG_ABORT) ) + (pSRB->MsgOutBuf[0] == ABORT) ) pSRB->SRBState = SRB_ABORT_SENT; } else { - bval = MSG_ABORT; /* ??? MSG_NOP */ - if( (pSRB->CmdBlock[0] == INQUIRY ) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || + bval = ABORT; /* ??? MSG_NOP */ + if( (pSRB->pcmd->cmnd[0] == INQUIRY ) || + (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) { if( pDCB->SyncMode & SYNC_ENABLE ) @@ -986,8 +1033,8 @@ else { mop1: - //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); - DC390_write8 (ScsiFifo, MSG_EXTENDED); + printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN); + DC390_write8 (ScsiFifo, EXTENDED_MESSAGE); DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */ DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ DC390_write8 (ScsiFifo, pDCB->NegoPeriod); @@ -1030,20 +1077,16 @@ UCHAR bval, i, cnt; PDCB ptr; - if( !(pDCB->IdentifyMsg & 0x07) ) + if( !(pDCB->TargetLUN) ) { - if( pACB->scan_devices ) - { - dc390_CurrSyncOffset = pDCB->SyncOffset; - } - else + if( !pACB->scan_devices ) { ptr = pACB->pLinkDCB; cnt = pACB->DCBCnt; - bval = pDCB->UnitSCSIID; + bval = pDCB->TargetID; for(i=0; iUnitSCSIID == bval ) + if( ptr->TargetID == bval ) { ptr->SyncPeriod = pDCB->SyncPeriod; ptr->SyncOffset = pDCB->SyncOffset; @@ -1068,25 +1111,27 @@ DEBUG0(printk(KERN_INFO "DISC,");) + if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n"); + pACB->Connected = 0; pDCB = pACB->pActiveDCB; if (!pDCB) { int j = 400; - DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\ - (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);) + DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\ + pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel);) while (--j) udelay (1000); DC390_read8 (INT_Status); /* Reset Pending INT */ DC390_write8 (ScsiCmd, EN_SEL_RESEL); return; } + DC390_write8 (ScsiCmd, EN_SEL_RESEL); pSRB = pDCB->pActiveSRB; pACB->pActiveDCB = 0; pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8 (ScsiCmd, EN_SEL_RESEL); if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) { pSRB->SRBState = 0; - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process ( pACB ); } else if( pSRB->SRBState & SRB_ABORT_SENT ) { @@ -1098,22 +1143,24 @@ for( i=0; i < cnt; i++) { psrb = pSRB->pNextSRB; - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; + dc390_Free_insert (pACB, pSRB); pSRB = psrb; } pDCB->pGoingSRB = 0; - dc390_DoWaitingSRB( pACB ); + dc390_Query_to_Waiting (pACB); + dc390_Waiting_process (pACB); } else { if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) ) { /* Selection time out */ - if( !(pACB->scan_devices) ) + if( !(1/*pACB->scan_devices*/) ) { pSRB->SRBState = SRB_READY; - dc390_RewaitSRB( pDCB, pSRB); + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting (pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); } else { @@ -1123,15 +1170,12 @@ } else if( pSRB->SRBState & SRB_DISCONNECT ) { - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process ( pACB ); } else if( pSRB->SRBState & SRB_COMPLETED ) { disc1: - if(pDCB->MaxCommand > 1) - { - pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ - } + dc390_freetag (pDCB, pSRB); pDCB->pActiveSRB = 0; pSRB->SRBState = SRB_FREE; dc390_SRBdone( pACB, pDCB, pSRB); @@ -1146,43 +1190,48 @@ { PDCB pDCB; PSRB pSRB; - USHORT wval; - UCHAR bval; + UCHAR id, lun; DEBUG0(printk(KERN_INFO "RSEL,");) + pACB->Connected = 1; pDCB = pACB->pActiveDCB; if( pDCB ) { /* Arbitration lost but Reselection won */ - DEBUG0(printk ("(ActiveDCB != 0)");) + DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n");) pSRB = pDCB->pActiveSRB; if( !( pACB->scan_devices ) ) { pSRB->SRBState = SRB_READY; - dc390_RewaitSRB( pDCB, pSRB); + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting ( pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); } } - bval = DC390_read8 (ScsiFifo); /* get ID */ - DEBUG0(printk ("Dev %02x,", bval);) - bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ - wval = 0; - while (bval >>= 1) wval++; - wval |= ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8; /* get LUN */ - DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);) - pDCB = pACB->pLinkDCB; - while( wval != *((PUSHORT) &pDCB->UnitSCSIID) ) + /* Get ID */ + lun = DC390_read8 (ScsiFifo); + DEBUG0(printk ("Dev %02x,", lun);) + if (!(lun & (1 << pACB->pScsiHost->this_id))) + printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun); + else + lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ + id = 0; while (lun >>= 1) id++; + /* Get LUN */ + lun = DC390_read8 (ScsiFifo); + if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n"); + lun &= 7; + DEBUG0(printk ("(%02i-%i),", id, lun);) + pDCB = dc390_findDCB (pACB, id, lun); + if (!pDCB) { - pDCB = pDCB->pNextDCB; - if( pDCB == pACB->pLinkDCB ) - { - printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - return; - } + printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n", + id, lun); + return; } pACB->pActiveDCB = pDCB; + /* TagQ: We expect a message soon, so never mind the exact SRB */ if( pDCB->SyncMode & EN_TAG_QUEUEING ) { - pSRB = pACB->pTmpSRB; /* ?? */ + pSRB = pACB->pTmpSRB; pDCB->pActiveSRB = pSRB; } else @@ -1192,8 +1241,8 @@ { pSRB= pACB->pTmpSRB; pSRB->SRBState = SRB_UNEXPECT_RESEL; - printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); + printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n", + id, lun); pDCB->pActiveSRB = pSRB; dc390_EnableMsgOut_Abort ( pACB, pSRB ); } @@ -1202,8 +1251,8 @@ if( pDCB->DCBFlag & ABORT_DEV_ ) { pSRB->SRBState = SRB_ABORT_SENT; - printk (KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); + printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n", + id, lun); dc390_EnableMsgOut_Abort( pACB, pSRB ); } else @@ -1213,7 +1262,7 @@ DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);) pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); DC390_write8 (Sync_Period, pDCB->SyncPeriod); DC390_write8 (Sync_Offset, pDCB->SyncOffset); DC390_write8 (CtrlReg1, pDCB->CtrlR1); @@ -1228,30 +1277,36 @@ { PDCB pPrevDCB = pACB->pLinkDCB; - pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN); if (pDCB->GoingSRBCnt > 1) { DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);) + pDCB->TargetID, pDCB->TargetLUN, (int)pDCB, pDCB->GoingSRBCnt);) return; }; + pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN); + // The first one if (pDCB == pACB->pLinkDCB) - { - if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0; + { + // The last one + if (pACB->pLastDCB == pDCB) { + pDCB->pNextDCB = 0; pACB->pLastDCB = 0; + } pACB->pLinkDCB = pDCB->pNextDCB; - pACB->pLastDCB->pNextDCB = pDCB->pNextDCB; - } + } else - { + { while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB; pPrevDCB->pNextDCB = pDCB->pNextDCB; if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB; - } + } - DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) - kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0; + DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): %p\n",\ + pDCB->TargetID, pDCB->TargetLUN, pDCB);) + if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0; + if (pDCB == pACB->pLinkDCB) pACB->pLinkDCB = pDCB->pNextDCB; + if (pDCB == pACB->pDCBRunRobin) pACB->pDCBRunRobin = pDCB->pNextDCB; + kfree (pDCB); pACB->DCBCnt--; /* pACB->DeviceCnt--; */ }; @@ -1280,21 +1335,12 @@ || (pDCB->DevType == TYPE_MOD)) &&*/ !dc390_tagq_blacklist (((char*)ptr)+8) ) { - pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; + if (pDCB->MaxCommand ==1) pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */; - pDCB->TagMask = 0; + //pDCB->TagMask = 0; } else - { - /* Do we really need to check for DevType here ? */ - if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/ - /* && ((pDCB->DevType == TYPE_DISK) - || (pDCB->DevType == TYPE_MOD))*/ ) - pDCB->SyncMode |= EN_ATN_STOP; - else - //pDCB->SyncMode &= ~EN_ATN_STOP; - pDCB->SyncMode &= ~0; - } + pDCB->MaxCommand = 1; } }; @@ -1312,60 +1358,62 @@ void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) { - PSRB psrb; - UCHAR bval, status, i; + UCHAR bval, status, i, DCB_removed; PSCSICMD pcmd; PSCSI_INQDATA ptr; PSGL ptr2; ULONG swlval; - pcmd = pSRB->pcmd; + pcmd = pSRB->pcmd; DCB_removed = 0; status = pSRB->TargetStatus; + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if( pcmd->use_sg ) + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ pSRB, pcmd->pid);) if(pSRB->SRBFlag & AUTO_REQSENSE) { /* Last command was a Request Sense */ pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; - pSRB->TargetStatus = SCSI_STAT_CHECKCOND; + pSRB->TargetStatus = CHECK_CONDITION << 1; #ifdef DC390_REMOVABLEDEBUG switch (pcmd->sense_buffer[2] & 0x0f) { case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; } #endif - //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status; - if(status == SCSI_STAT_CHECKCOND) + //pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status); + if (status == (CHECK_CONDITION << 1)) { - pcmd->result = DID_BAD_TARGET << 16; + pcmd->result = MK_RES_LNX(0,DID_BAD_TARGET,0,/*CHECK_CONDITION*/0); goto ckc_e; } if(pSRB->RetryCnt == 0) { - (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0]; - pSRB->TotalXferredLen = pSRB->Segment1[1]; + //(UINT)(pSRB->pcmd->cmnd[0]) = pSRB->Segment0[0]; + pSRB->TotalXferredLen = pSRB->SavedTotXLen; if( (pSRB->TotalXferredLen) && (pSRB->TotalXferredLen >= pcmd->underflow) ) - pcmd->result |= (DID_OK << 16); + SET_RES_DID(pcmd->result,DID_OK) else - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | - SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\ - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->pcmd->cmnd[0],\ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) goto ckc_e; } else /* Retry */ @@ -1373,20 +1421,20 @@ pSRB->RetryCnt--; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; - *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; - *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; + //*((PUINT) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + //*((PUINT) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; /* Don't retry on TEST_UNIT_READY */ - if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */) + if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */) { - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) - | SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\ + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\ (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) goto ckc_e; } - pcmd->result |= (DRIVER_SENSE << 24); - pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; - pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + SET_RES_DRV(pcmd->result,DRIVER_SENSE); + pSRB->SGcount = (UCHAR) pSRB->SavedSGCount; + //pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->target, pcmd->lun);) pSRB->SGIndex = 0; pSRB->TotalXferredLen = 0; pSRB->SGToBeXferLen = 0; @@ -1398,17 +1446,19 @@ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } return; } } if( status ) { - if( status == SCSI_STAT_CHECKCOND) + if( status_byte(status) == CHECK_CONDITION ) { - REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\ - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + REMOVABLEDEBUG(printk (KERN_INFO "DC390: Check_Condition (Cmd %02x, Id %02x, LUN %02x)\n",\ + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) ) { bval = pSRB->SGcount; @@ -1425,12 +1475,14 @@ dc390_RequestSense( pACB, pDCB, pSRB ); return; } - else if( status == SCSI_STAT_QUEUEFULL ) + else if( status_byte(status) == QUEUE_FULL ) { bval = (UCHAR) pDCB->GoingSRBCnt; bval--; pDCB->MaxCommand = bval; - dc390_RewaitSRB( pDCB, pSRB ); + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; return; @@ -1439,23 +1491,23 @@ { pSRB->AdaptStatus = H_SEL_TIMEOUT; pSRB->TargetStatus = 0; - pcmd->result = DID_BAD_TARGET << 16; + pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0); /* Devices are removed below ... */ } - else if (status == SCSI_STAT_BUSY && - (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) && + else if (status_byte(status) == BUSY && + (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) && pACB->scan_devices) { pSRB->AdaptStatus = 0; pSRB->TargetStatus = status; - pcmd->result = (ULONG) (pSRB->EndMessage << 8) - /* | (ULONG) status */; + pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0); } else { /* Another error */ pSRB->AdaptStatus = 0; if( pSRB->RetryCnt ) { /* Retry */ + //printk ("DC390: retry\n"); pSRB->RetryCnt--; pSRB->TargetStatus = 0; pSRB->SGIndex = 0; @@ -1469,14 +1521,18 @@ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); - return; + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } + return; } else { /* Report error */ - pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) | - (ULONG) status; + //pcmd->result = MK_RES(0, DID_ERROR, pSRB->EndMessage, status); + SET_RES_DID(pcmd->result,DID_ERROR); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); + SET_RES_TARGET(pcmd->result,status); } } } @@ -1486,38 +1542,52 @@ if(status & H_OVER_UNDER_RUN) { pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8); + SET_RES_DID(pcmd->result,DID_OK); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); } else if( pSRB->SRBStatus & PARITY_ERROR) { - pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8); + //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0); + SET_RES_DID(pcmd->result,DID_PARITY); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); } else /* No error */ { pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16); + SET_RES_DID(pcmd->result,DID_OK); } } + if ((pcmd->result & RES_DID) == 0 && + pcmd->cmnd[0] == INQUIRY && + pcmd->cmnd[2] == 0 && + pcmd->request_bufflen >= 8 && + ptr && + (ptr->Vers & 0x07) >= 2) + pDCB->Inquiry7 = ptr->Flags; ckc_e: if( pACB->scan_devices ) { - if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + if( pcmd->cmnd[0] == TEST_UNIT_READY || + pcmd->cmnd[0] == INQUIRY) { #ifdef DC390_DEBUG0 - printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result); - if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n", + printk (KERN_INFO "DC390: %s: result: %08x", + (pcmd->cmnd[0] == INQUIRY? "INQUIRY": "TEST_UNIT_READY"), + pcmd->result); + if (pcmd->result & (DRIVER_SENSE << 24)) printk (" (sense: %02x %02x %02x %02x)\n", pcmd->sense_buffer[0], pcmd->sense_buffer[1], pcmd->sense_buffer[2], pcmd->sense_buffer[3]); else printk ("\n"); #endif - if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) || - ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && - (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16) + if( (host_byte(pcmd->result) != DID_OK && !(status_byte(pcmd->result) & CHECK_CONDITION) && !(status_byte(pcmd->result) & BUSY)) || + ((driver_byte(pcmd->result) & DRIVER_SENSE) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && + (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || host_byte(pcmd->result) & DID_ERROR ) { /* device not present: remove */ - dc390_remove_dev (pACB, pDCB); + //dc390_Going_remove (pDCB, pSRB); + dc390_remove_dev (pACB, pDCB); DCB_removed = 1; if( (pcmd->target == pACB->pScsiHost->max_id - 1) && ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) ) @@ -1534,16 +1604,17 @@ } } - if( pSRB->CmdBlock[0] == INQUIRY && - (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) ) + //if( pSRB->pcmd->cmnd[0] == INQUIRY && + // (host_byte(pcmd->result) == DID_OK || status_byte(pcmd->result) & CHECK_CONDITION) ) + if( pcmd->cmnd[0] == INQUIRY && + (pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) ) { - ptr = (PSCSI_INQDATA) (pcmd->request_buffer); - if( pcmd->use_sg ) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); - if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) + if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV && !DCB_removed) { + //printk ("DC390: Type = nodev! (%02i-%i)\n", pcmd->target, pcmd->lun); /* device not present: remove */ - dc390_remove_dev (pACB, pDCB); + //dc390_Going_remove (pDCB, pSRB); + dc390_remove_dev (pACB, pDCB); DCB_removed = 1; } else { @@ -1555,40 +1626,29 @@ (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) pACB->scan_devices = 0; }; -/* dc390_ReleaseSRB( pDCB, pSRB ); */ - if(pSRB == pDCB->pGoingSRB ) - { - pDCB->pGoingSRB = pSRB->pNextSRB; - } - else - { - psrb = pDCB->pGoingSRB; - while( psrb->pNextSRB != pSRB ) - psrb = psrb->pNextSRB; - psrb->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pGoingLast ) - pDCB->pGoingLast = psrb; - } - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pDCB->GoingSRBCnt--; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30) + pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen; +#endif - dc390_DoWaitingSRB( pACB ); + if (!DCB_removed) dc390_Going_remove (pDCB, pSRB); + /* Add to free list */ + dc390_Free_insert (pACB, pSRB); + DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid);) DC390_UNLOCK_ACB_NI; - pcmd->scsi_done( pcmd ); + pcmd->scsi_done (pcmd); DC390_LOCK_ACB_NI; - if( pDCB->QIORBCnt ) - dc390_DoNextCmd( pACB, pDCB ); + dc390_Query_to_Waiting (pACB); + dc390_Waiting_process (pACB); return; } -/* Remove all SRBs and tell midlevel code DID_RESET */ +/* Remove all SRBs from Going list and inform midlevel */ void -dc390_DoingSRB_Done( PACB pACB ) +dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; @@ -1605,16 +1665,21 @@ { psrb2 = psrb->pNextSRB; pcmd = psrb->pcmd; - pcmd->result = DID_RESET << 16; + dc390_Free_insert (pACB, psrb); +#ifndef USE_NEW_EH + /* New EH will crash on being given timed out cmnds */ + if (pcmd == cmd) + pcmd->result = MK_RES(0,DID_ABORT,0,0); + else + pcmd->result = MK_RES(0,DID_RESET,0,0); /* ReleaseSRB( pDCB, pSRB ); */ - psrb->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = psrb; - + DEBUG0(printk (KERN_DEBUG "DC390: DoingSRB_Done: done pid %li\n", pcmd->pid);) DC390_UNLOCK_ACB_NI; pcmd->scsi_done( pcmd ); DC390_LOCK_ACB_NI; +#endif psrb = psrb2; } pdcb->GoingSRBCnt = 0;; @@ -1622,21 +1687,21 @@ pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; } while( pdcb != pDCB ); + dc390_Query_to_Waiting (pACB); } static void dc390_ResetSCSIBus( PACB pACB ) { - pACB->ACBFlag |= RESET_DEV; - - DC390_write8 (ScsiCmd, RST_DEVICE_CMD); - udelay (250); - DC390_write8 (ScsiCmd, NOP_CMD); + //DC390_write8 (ScsiCmd, RST_DEVICE_CMD); + //udelay (250); + //DC390_write8 (ScsiCmd, NOP_CMD); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD); + pACB->Connected = 0; return; } @@ -1644,27 +1709,31 @@ static void dc390_ScsiRstDetect( PACB pACB ) { - printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus); + printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus); //DEBUG0(printk(KERN_INFO "RST_DETECT,");) + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); /* Unlock before ? */ - /* delay a second */ - { unsigned int msec = 1*1000; while (--msec) udelay(1000); } + /* delay half a second */ + udelay (1000); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pACB->pScsiHost->last_reset = jiffies + 5*HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + pACB->Connected = 0; if( pACB->ACBFlag & RESET_DEV ) pACB->ACBFlag |= RESET_DONE; else - { + { /* Reset was issued by sb else */ pACB->ACBFlag |= RESET_DETECT; dc390_ResetDevParam( pACB ); -/* dc390_DoingSRB_Done( pACB ); ???? */ - dc390_RecoverSRB( pACB ); + dc390_DoingSRB_Done( pACB, 0 ); + //dc390_RecoverSRB( pACB ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process( pACB ); } return; } @@ -1676,15 +1745,17 @@ PSCSICMD pcmd; REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ - pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + pSRB->pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0]; - pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4]; - pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount); - pSRB->Segment1[1] = pSRB->TotalXferredLen; + //pSRB->Segment0[0] = (UINT) pSRB->CmdBlock[0]; + //pSRB->Segment0[1] = (UINT) pSRB->CmdBlock[4]; + //pSRB->Segment1[0] = ((UINT)(pSRB->pcmd->cmd_len) << 8) + pSRB->SGcount; + //pSRB->Segment1[1] = pSRB->TotalXferredLen; + pSRB->SavedSGCount = pSRB->SGcount; + pSRB->SavedTotXLen = pSRB->TotalXferredLen; pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */ + pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ pcmd = pSRB->pcmd; @@ -1694,16 +1765,18 @@ pSRB->SGcount = 1; pSRB->SGIndex = 0; - pSRB->CmdBlock[0] = REQUEST_SENSE; - pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; - (USHORT) pSRB->CmdBlock[2] = 0; - (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); - pSRB->ScsiCmdLen = 6; + //pSRB->CmdBlock[0] = REQUEST_SENSE; + //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5; + //(USHORT) pSRB->CmdBlock[2] = 0; + //(USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); + //pSRB->ScsiCmdLen = 6; pSRB->TotalXferredLen = 0; pSRB->SGToBeXferLen = 0; - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.2.18/drivers/scsi/sr.c Sun Mar 25 11:28:30 2001 +++ linux/drivers/scsi/sr.c Sun Mar 25 11:37:36 2001 @@ -26,6 +26,8 @@ * Modified by Jens Axboe - support DVD-RAM * transparently and loose the GHOST hack * + * Modified by Arnaldo Carvalho de Melo + * check resource allocation in sr_init and some cleanups - 2000/12/09 */ #include @@ -70,10 +72,10 @@ sr_finish, sr_attach, sr_detach }; -Scsi_CD *scsi_CDs = NULL; -static int *sr_sizes = NULL; +Scsi_CD *scsi_CDs; +static int *sr_sizes; -static int *sr_blocksizes = NULL; +static int *sr_blocksizes; static int sr_open(struct cdrom_device_info *, int); void get_sectorsize(int); @@ -1113,16 +1115,21 @@ } if (scsi_CDs) return 0; - sr_template.dev_max = - sr_template.dev_noticed + SR_EXTRA_DEVS; - scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); - memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); - - sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); - memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); - - sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * - sizeof(int), GFP_ATOMIC); + sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS; + scsi_CDs = scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), + GFP_ATOMIC); + if (!scsi_CDs) + goto cleanup_register; + + sr_sizes = scsi_init_malloc(sr_template.dev_max * sizeof(int), + GFP_ATOMIC); + if (!sr_sizes) + goto cleanup_cds; + + sr_blocksizes = scsi_init_malloc(sr_template.dev_max * sizeof(int), + GFP_ATOMIC); + if (!sr_blocksizes) + goto cleanup_sizes; /* * These are good guesses for the time being. @@ -1131,6 +1138,18 @@ sr_blocksizes[i] = 2048; blksize_size[MAJOR_NR] = sr_blocksizes; return 0; +cleanup_sizes: + scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); + sr_sizes = NULL; +cleanup_cds: + scsi_init_free((char *) scsi_CDs, + (sr_template.dev_noticed + SR_EXTRA_DEVS) * + sizeof(Scsi_CD)); + scsi_CDs = NULL; +cleanup_register: + unregister_blkdev(MAJOR_NR, "sr"); + sr_registered--; + return 1; } void sr_finish() @@ -1241,7 +1260,7 @@ scsi_init_free((char *) scsi_CDs, (sr_template.dev_noticed + SR_EXTRA_DEVS) * sizeof(Scsi_CD)); - + scsi_CDs = NULL; scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); sr_sizes = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.2.18/drivers/scsi/st.c Sun Mar 25 11:28:30 2001 +++ linux/drivers/scsi/st.c Sun Mar 25 11:37:36 2001 @@ -55,6 +55,8 @@ #include "constants.h" +#include "osst_detect.h" + #ifdef MODULE MODULE_PARM(buffer_kbs, "i"); MODULE_PARM(write_threshold_kbs, "i"); @@ -3407,6 +3409,18 @@ #endif +/* Returns zero for drives not supported by this driver */ +static int st_supported(Scsi_Device * SDp) +{ + /* These OnStream SC drives require a special driver. The OnStream ADR* drives + are supported by this driver */ + if ( OSST_SUPPORTS(SDp) ) + return 0; + + return 1; +} + + static struct file_operations st_fops = { NULL, /* lseek - default */ st_read, /* read - general block-dev read */ @@ -3429,6 +3443,8 @@ if (SDp->type != TYPE_TAPE) return 1; + if (!st_supported(SDp)) + return 1; if (st_template.nr_dev >= st_template.dev_max) { SDp->attached--; @@ -3502,6 +3518,8 @@ static int st_detect(Scsi_Device * SDp) { if(SDp->type != TYPE_TAPE) return 0; + if (!st_supported(SDp)) + return 0; printk(KERN_WARNING "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.2.18/drivers/scsi/tmscsim.c Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/tmscsim.c Sun Mar 25 11:37:36 2001 @@ -5,11 +5,11 @@ * Bus Master Host Adapter * * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * ***********************************************************************/ -/* (C) Copyright: put under GNU GPL in 10/96 * +/* (C) Copyright: put under GNU GPL in 10/96 (see README.tmscsim) * *************************************************************************/ -/* $Id: tmscsim.c,v 2.16 1998/12/25 17:54:44 garloff Exp $ */ +/* $Id: tmscsim.c,v 2.60.2.30 2000/12/20 01:07:12 garloff Exp $ */ /* Enhancements and bugfixes by * - * Kurt Garloff * + * Kurt Garloff * ***********************************************************************/ /* HISTORY: * * * @@ -95,8 +95,75 @@ * 2.0c 98/11/19 KG Cleaned up detect/init for SMP boxes, * * Write Erase DMA (1.20t) caused problems * * 2.0d 98/12/25 KG Christmas release ;-) Message handling * - * competely reworked. Handle target ini- * + * completely reworked. Handle target ini- * * tiated SDTR correctly. * + * 2.0d1 99/01/25 KG Try to handle RESTORE_PTR * + * 2.0d2 99/02/08 KG Check for failure of kmalloc, correct * + * inclusion of scsicam.h, DelayReset * + * 2.0d3 99/05/31 KG DRIVER_OK -> DID_OK, DID_NO_CONNECT, * + * detect Target mode and warn. * + * pcmd->result handling cleaned up. * + * 2.0d4 99/06/01 KG Cleaned selection process. Found bug * + * which prevented more than 16 tags. Now: * + * 24. SDTR cleanup. Cleaner multi-LUN * + * handling. Don't modify ControlRegs/FIFO * + * when connected. * + * 2.0d5 99/06/01 KG Clear DevID, Fix INQUIRY after cfg chg. * + * 2.0d6 99/06/02 KG Added ADD special command to allow cfg. * + * before detection. Reset SYNC_NEGO_DONE * + * after a bus reset. * + * 2.0d7 99/06/03 KG Fixed bugs wrt add,remove commands * + * 2.0d8 99/06/04 KG Removed copying of cmnd into CmdBlock. * + * Fixed Oops in _release(). * + * 2.0d9 99/06/06 KG Also tag queue INQUIRY, T_U_R, ... * + * Allow arb. no. of Tagged Cmnds. Max 32 * + * 2.0d1099/06/20 KG TagMaxNo changes now honoured! Queueing * + * clearified (renamed ..) TagMask handling* + * cleaned. * + * 2.0d1199/06/28 KG cmd->result now identical to 2.0d2 * + * 2.0d1299/07/04 KG Changed order of processing in IRQ * + * 2.0d1399/07/05 KG Don't update DCB fields if removed * + * 2.0d1499/07/05 KG remove_dev: Move kfree() to the end * + * 2.0d1599/07/12 KG use_new_eh_code: 0, ULONG -> UINT where * + * appropriate * + * 2.0d1699/07/13 KG Reenable StartSCSI interrupt, Retry msg * + * 2.0d1799/07/15 KG Remove debug msg. Disable recfg. when * + * there are queued cmnds * + * 2.0d1899/07/18 KG Selection timeout: Don't requeue * + * 2.0d1999/07/18 KG Abort: Only call scsi_done if dequeued * + * 2.0d2099/07/19 KG Rst_Detect: DoingSRB_Done * + * 2.0d2199/08/15 KG dev_id for request/free_irq, cmnd[0] for* + * RETRY, SRBdone does DID_ABORT for the * + * cmd passed by DC390_reset() * + * 2.0d2299/08/25 KG dev_id fixed. can_queue: 42 * + * 2.0d2399/08/25 KG Removed some debugging code. dev_id * + * now is set to pACB. Use u8,u16,u32. * + * 2.0d2499/11/14 KG Unreg. I/O if failed IRQ alloc. Call * + * done () w/ DID_BAD_TARGET in case of * + * missing DCB. We are old EH!! * + * 2.0d2500/01/15 KG 2.3.3x compat from Andreas Schultz * + * set unique_id. Disable RETRY message. * + * 2.0d2600/01/29 KG Go to new EH. * + * 2.0d2700/01/31 KG ... but maintain 2.0 compat. * + * and fix DCB freeing * + * 2.0d2800/02/14 KG Queue statistics fixed, dump special cmd* + * Waiting_Timer for failed StartSCSI * + * New EH: Don't return cmnds to ML on RST * + * Use old EH (don't have new EH fns yet) * + * Reset: Unlock, but refuse to queue * + * 2.3 __setup function * + * 2.0e 00/05/22 KG Return residual for 2.3 * + * 2.0e1 00/05/25 KG Compile fixes for 2.3.99 * + * 2.0e2 00/05/27 KG Jeff Garzik's pci_enable_device() * + * 2.0e3 00/09/29 KG Some 2.4 changes. Don't try Sync Nego * + * before INQUIRY has reported ability. * + * Recognise INQUIRY as scanning command. * + * 2.0e4 00/10/13 KG Allow compilation into 2.4 kernel * + * 2.0e5 00/11/17 KG Store Inq.flags in DCB * + * 2.0e6 00/11/22 KG 2.4 init function (Thx to O.Schumann) * + * 2.4 PCI device table (Thx to A.Richter) * + * 2.0e7 00/11/28 KG Allow overriding of BIOS settings * + * 2.0f 00/12/20 KG Handle failed INQUIRYs during scan * ***********************************************************************/ /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */ @@ -108,6 +175,7 @@ //#define DC390_DCBDEBUG //#define DC390_PARSEDEBUG //#define DC390_REMOVABLEDEBUG +//#define DC390_LOCKDEBUG /* Debug definitions */ #ifdef DC390_DEBUG0 @@ -159,6 +227,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -175,8 +244,7 @@ /* Note: Starting from 2.1.9x, the mid-level scsi code issues a * spinlock_irqsave (&io_request_lock) before calling the driver's - * routines, so we don't need to lock. - * TODO: Verify, if we are locked in every case! + * routines, so we don't need to lock, except in the IRQ handler. * The policy 3, let the midlevel scsi code do the io_request_locks * and us locking on a driver specific lock, shouldn't hurt anybody; it * just causes a minor performance degradation for setting the locks. @@ -189,31 +257,46 @@ * undef : traditional save_flags; cli; restore_flags; */ -//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/asm/spinlock.h */ +//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/linux/spinlock.h */ -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) - -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) # include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) +# include +#else # include #endif +#endif -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) # define USE_SPINLOCKS 1 # define NEW_PCI 1 #else # undef NEW_PCI -# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) # define USE_SPINLOCKS 2 # endif #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99) +static struct pci_device_id tmscsim_pci_tbl[] __initdata = { + { + vendor: PCI_VENDOR_ID_AMD, + device: PCI_DEVICE_ID_AMD53C974, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl); +#endif + #ifdef USE_SPINLOCKS # if USE_SPINLOCKS == 3 /* both */ -# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0 # define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; # else # define DC390_LOCKA_INIT @@ -320,7 +403,11 @@ # define PCI_PRESENT pci_present () # define PCI_SET_MASTER pci_set_master (pdev) # define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,10) +# define PCI_GET_IO_AND_IRQ io_port = pci_resource_start (pdev, 0); irq = pdev->irq +#else # define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq +#endif #else # include # define PDEV pbus, pdevfn @@ -369,7 +456,7 @@ void dc390_Disconnect( PACB pACB ); void dc390_Reselect( PACB pACB ); void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); -void dc390_DoingSRB_Done( PACB pACB ); +void dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd ); static void dc390_ScsiRstDetect( PACB pACB ); static void dc390_ResetSCSIBus( PACB pACB ); static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); @@ -379,7 +466,7 @@ void do_DC390_Interrupt( int, void *, struct pt_regs *); int dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index ); -void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ); +void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun); void dc390_updateDCB (PACB pACB, PDCB pDCB); #ifdef MODULE @@ -393,31 +480,19 @@ //static PSH dc390_pSH_current = NULL; static PACB dc390_pACB_start= NULL; static PACB dc390_pACB_current = NULL; -static UCHAR dc390_adapterCnt = 0; -static UCHAR dc390_CurrSyncOffset = 0; static ULONG dc390_lastabortedpid = 0; -static ULONG dc390_laststatus = 0; +static UINT dc390_laststatus = 0; +static UCHAR dc390_adapterCnt = 0; -#ifndef CONFIG_SCSI_DC390T_NOGENSUPP /* Startup values, to be overriden on the commandline */ -int tmscsim[] = {7, 1 /* 8MHz */, - PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ - | SYNC_NEGO_ | TAG_QUEUEING_, - MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION - /* | NO_SEEK */ -# ifdef CONFIG_SCSI_MULTI_LUN - | LUN_CHECK -# endif - , 3 /* 16 Tags per LUN */}; +int tmscsim[] = {-2, -2, -2, -2, -2, -2}; -# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) -MODULE_PARM(tmscsim, "1-5i"); -MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)"); +# if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) +MODULE_PARM(tmscsim, "1-6i"); +MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)"); # endif -#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ - -#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +#if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) MODULE_AUTHOR("C.L. Huang / Kurt Garloff"); MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters"); MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); @@ -482,12 +557,14 @@ static char* dc390_adapname = "DC390"; UCHAR dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN]; UCHAR dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20}; +UCHAR dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20}; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,30) struct proc_dir_entry DC390_proc_scsi_tmscsim ={ PROC_SCSI_DC390T, 7 ,"tmscsim", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - +#endif /*********************************************************************** * Functions for access to DC390 EEPROM @@ -511,59 +588,107 @@ udelay(160); } -#ifndef CONFIG_SCSI_DC390T_NOGENSUPP -static void __init dc390_EEpromDefaults (UCHAR index) + +/* Override EEprom values with explicitly set values */ +static void __init dc390_EEprom_Override (UCHAR index) { PUCHAR ptr; UCHAR id; ptr = (PUCHAR) dc390_eepromBuf[index]; /* Adapter Settings */ - ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */ - ptr[EE_MODE2] = (UCHAR)tmscsim[3]; - ptr[EE_DELAY] = 0; /* ?? */ - ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */ + if (tmscsim[0] != -2) + ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */ + if (tmscsim[3] != -2) + ptr[EE_MODE2] = (UCHAR)tmscsim[3]; + if (tmscsim[5] != -2) + ptr[EE_DELAY] = tmscsim[5]; /* Reset delay */ + if (tmscsim[4] != -2) + ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Cmds */ /* Device Settings */ for (id = 0; id < MAX_SCSI_ID; id++) { - ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */ - ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */ + if (tmscsim[2] != -2) + ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */ + if (tmscsim[1] != -2) + ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */ }; - dc390_adapname = "AM53C974"; } -static void __init dc390_checkparams (void) +/* Handle "-1" case */ +static void __init dc390_check_for_safe_settings (void) { - PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\ - tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);) - if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */ + if (tmscsim[0] == -1 || tmscsim[0] > 15) /* modules-2.0.0 passes -1 as string */ { - tmscsim[0] = 7; tmscsim[1] = 4; - tmscsim[2] = 9; tmscsim[3] = 15; - tmscsim[4] = 2; + tmscsim[0] = 7; tmscsim[1] = 4; + tmscsim[2] = 0x09; tmscsim[3] = 0x0f; + tmscsim[4] = 2; tmscsim[5] = 10; printk (KERN_INFO "DC390: Using safe settings.\n"); } - else +} + + +#ifndef CONFIG_SCSI_DC390T_NOGENSUPP +int __initdata tmscsim_def[] = {7, 0 /* 10MHz */, + PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ + | SYNC_NEGO_ | TAG_QUEUEING_, + MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION + /* | NO_SEEK */ +# ifdef CONFIG_SCSI_MULTI_LUN + | LUN_CHECK +# endif + , 3 /* 16 Tags per LUN */, 1 /* s delay after Reset */ }; + +/* Copy defaults over set values where missing */ +static void __init dc390_fill_with_defaults (void) +{ + int i; + PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x %08x\n", tmscsim[0],\ + tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4], tmscsim[5]);) + for (i = 0; i < 6; i++) { - /* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */ - if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4; - if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4; - }; + if (tmscsim[i] < 0 || tmscsim[i] > 255) + tmscsim[i] = tmscsim_def[i]; + } + /* Sanity checks */ + if (tmscsim[0] > 7) tmscsim[0] = 7; + if (tmscsim[1] > 7) tmscsim[1] = 4; + if (tmscsim[4] > 5) tmscsim[4] = 4; + if (tmscsim[5] > 180) tmscsim[5] = 180; }; +#endif + /* Override defaults on cmdline: * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped) */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) +void __init dc390_setup (char *str) +{ + int ints[8]; + int i, im; + (void)get_options (str, ARRAY_SIZE(ints), ints); +#else void __init dc390_setup (char *str, int *ints) { - int i; - for (i = 0; i < ints[0]; i++) - tmscsim[i] = ints[i+1]; - if (ints[0] > 5) + int i, im; +#endif + im = ints[0]; + if (im > 6) + { printk (KERN_NOTICE "DC390: ignore extra params!\n"); + im = 6; + }; + for (i = 0; i < im; i++) + tmscsim[i] = ints[i+1]; /* dc390_checkparams (); */ }; -#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) +#ifndef MODULE +__setup("tmscsim=", dc390_setup); +#endif +#endif static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry ) @@ -652,6 +777,12 @@ } +static void __init dc390_interpret_delay (UCHAR index) +{ + char interpd [] = {1,3,5,10,16,30,60,120}; + dc390_eepromBuf[index][EE_DELAY] = interpd [dc390_eepromBuf[index][EE_DELAY]]; +}; + static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index ) { UCHAR i; @@ -662,6 +793,8 @@ memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID); memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID); + dc390_interpret_delay (index); + wval = 0; for(i=0; i<0x40; i++, ptr++) wval += *ptr; @@ -674,65 +807,94 @@ * (DCBs, SRBs, Queueing) * **********************************************************************/ -static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd) +static PDCB __inline__ dc390_findDCB ( PACB pACB, UCHAR id, UCHAR lun) { PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0; - while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun) + while (pDCB->TargetID != id || pDCB->TargetLUN != lun) { pDCB = pDCB->pNextDCB; if (pDCB == pACB->pLinkDCB) { - printk (KERN_WARNING "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n", - (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]); + DCBDEBUG(printk (KERN_WARNING "DC390: DCB not found (DCB=%p, DCBmap[%2x]=%2x)\n", + pDCB, id, pACB->DCBmap[id]);) return 0; } }; - DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n", \ - (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n", \ + pDCB, pDCB->TargetID, pDCB->TargetLUN);) return pDCB; }; -static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB ) -{ - PSCSICMD pcmd; +/* Queueing philosphy: + * There are a couple of lists: + * - Query: Contains the Scsi Commands not yet turned into SRBs (per ACB) + * (Note: For new EH, it is unecessary!) + * - Waiting: Contains a list of SRBs not yet sent (per DCB) + * - Free: List of free SRB slots + * + * If there are no waiting commands for the DCB, the new one is sent to the bus + * otherwise the oldest one is taken from the Waiting list and the new one is + * queued to the Waiting List + * + * Lists are managed using two pointers and eventually a counter + */ + - if( !pDCB->QIORBCnt ) +#if 0 +/* Look for a SCSI cmd in a SRB queue */ +static PSRB dc390_find_cmd_in_SRBq (PSCSICMD cmd, PSRB queue) +{ + PSRB q = queue; + while (q) { - pDCB->pQIORBhead = cmd; - pDCB->pQIORBtail = cmd; - pDCB->QIORBCnt++; - cmd->next = NULL; + if (q->pcmd == cmd) return q; + q = q->pNextSRB; + if (q == queue) return 0; } + return q; +}; +#endif + + +/* Append to Query List */ +static void dc390_Query_append( PSCSICMD cmd, PACB pACB ) +{ + DEBUG0(printk ("DC390: Append cmd %li to Query\n", cmd->pid);) + if( !pACB->QueryCnt ) + pACB->pQueryHead = cmd; else - { - pcmd = pDCB->pQIORBtail; - pcmd->next = cmd; - pDCB->pQIORBtail = cmd; - pDCB->QIORBCnt++; - cmd->next = NULL; - } + pACB->pQueryTail->next = cmd; + pACB->pQueryTail = cmd; + pACB->QueryCnt++; + pACB->CmdOutOfSRB++; + cmd->next = NULL; } -static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB ) +/* Return next cmd from Query list */ +static PSCSICMD dc390_Query_get ( PACB pACB ) { PSCSICMD pcmd; - pcmd = pDCB->pQIORBhead; - pDCB->pQIORBhead = pcmd->next; + pcmd = pACB->pQueryHead; + if (!pcmd) return pcmd; + DEBUG0(printk ("DC390: Get cmd %li from Query\n", pcmd->pid);) + pACB->pQueryHead = pcmd->next; pcmd->next = NULL; - pDCB->QIORBCnt--; - + if (!pACB->pQueryHead) pACB->pQueryTail = NULL; + pACB->QueryCnt--; return( pcmd ); } -static __inline__ PSRB dc390_GetSRB( PACB pACB ) +/* Return next free SRB */ +static __inline__ PSRB dc390_Free_get ( PACB pACB ) { PSRB pSRB; pSRB = pACB->pFreeSRB; + DEBUG0(printk ("DC390: Get Free SRB %p\n", pSRB);) if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; @@ -742,130 +904,174 @@ return( pSRB ); } - -static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB ) +/* Insert SRB oin top of free list */ +static __inline__ void dc390_Free_insert (PACB pACB, PSRB pSRB) { - PSRB psrb1; + DEBUG0(printk ("DC390: Free SRB %p\n", pSRB);) + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; +} - if( (psrb1 = pDCB->pWaitingSRB) ) - { - pSRB->pNextSRB = psrb1; - } - else - { - pSRB->pNextSRB = NULL; + +/* Inserts a SRB to the top of the Waiting list */ +static __inline__ void dc390_Waiting_insert ( PDCB pDCB, PSRB pSRB ) +{ + DEBUG0(printk ("DC390: Insert pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);) + pSRB->pNextSRB = pDCB->pWaitingSRB; + if (!pDCB->pWaitingSRB) pDCB->pWaitLast = pSRB; - } pDCB->pWaitingSRB = pSRB; + pDCB->WaitSRBCnt++; } -static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB ) +/* Queue SRB to waiting list */ +static __inline__ void dc390_Waiting_append ( PDCB pDCB, PSRB pSRB) { - PSRB psrb1; - UCHAR bval; - - pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++; - DEBUG0(printk(KERN_INFO "DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);) - psrb1 = pDCB->pGoingSRB; - if( pSRB == psrb1 ) - { - pDCB->pGoingSRB = psrb1->pNextSRB; - } + DEBUG0(printk ("DC390: Append pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);) + if( pDCB->pWaitingSRB ) + pDCB->pWaitLast->pNextSRB = pSRB; else - { - while( pSRB != psrb1->pNextSRB ) - psrb1 = psrb1->pNextSRB; - psrb1->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pGoingLast ) - pDCB->pGoingLast = psrb1; - } - if( (psrb1 = pDCB->pWaitingSRB) ) - { - pSRB->pNextSRB = psrb1; pDCB->pWaitingSRB = pSRB; - } + + pDCB->pWaitLast = pSRB; + pSRB->pNextSRB = NULL; + pDCB->WaitSRBCnt++; + pDCB->pDCBACB->CmdInQ++; +} + +static __inline__ void dc390_Going_append (PDCB pDCB, PSRB pSRB) +{ + pDCB->GoingSRBCnt++; + DEBUG0(printk("DC390: Append SRB %p to Going\n", pSRB);) + /* Append to the list of Going commands */ + if( pDCB->pGoingSRB ) + pDCB->pGoingLast->pNextSRB = pSRB; else - { - pSRB->pNextSRB = NULL; - pDCB->pWaitingSRB = pSRB; - pDCB->pWaitLast = pSRB; - } + pDCB->pGoingSRB = pSRB; + + pDCB->pGoingLast = pSRB; + /* No next one in sent list */ + pSRB->pNextSRB = NULL; +}; + +static __inline__ void dc390_Going_remove (PDCB pDCB, PSRB pSRB) +{ + DEBUG0(printk("DC390: Remove SRB %p from Going\n", pSRB);) + if (pSRB == pDCB->pGoingSRB) + pDCB->pGoingSRB = pSRB->pNextSRB; + else + { + PSRB psrb = pDCB->pGoingSRB; + while (psrb && psrb->pNextSRB != pSRB) + psrb = psrb->pNextSRB; + if (!psrb) + { printk (KERN_ERR "DC390: Remove non-ex. SRB %p from Going!\n", pSRB); return; } + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pGoingLast) + pDCB->pGoingLast = psrb; + } + pDCB->GoingSRBCnt--; +}; + +/* Moves SRB from Going list to the top of Waiting list */ +static void dc390_Going_to_Waiting ( PDCB pDCB, PSRB pSRB ) +{ + DEBUG0(printk(KERN_INFO "DC390: Going_to_Waiting (SRB %p) pid = %li\n", pSRB, pSRB->pcmd->pid);) + /* Remove SRB from Going */ + dc390_Going_remove (pDCB, pSRB); + /* Insert on top of Waiting */ + dc390_Waiting_insert (pDCB, pSRB); + /* Tag Mask must be freed elsewhere ! (KG, 99/06/18) */ +} + +/* Moves first SRB from Waiting list to Going list */ +static __inline__ void dc390_Waiting_to_Going ( PDCB pDCB, PSRB pSRB ) +{ + /* Remove from waiting list */ + DEBUG0(printk("DC390: Remove SRB %p from head of Waiting\n", pSRB);) + pDCB->pWaitingSRB = pSRB->pNextSRB; + if( !pDCB->pWaitingSRB ) pDCB->pWaitLast = NULL; + pDCB->WaitSRBCnt--; + dc390_Going_append (pDCB, pSRB); +} + +/* 2.0 timer compatibility */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,30) + static inline int timer_pending(struct timer_list * timer) + { + return timer->prev != NULL; + } + #define time_after(a,b) ((long)(b) - (long)(a) < 0) + #define time_before(a,b) time_after(b,a) +#endif - bval = pSRB->TagNumber; - pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ +void DC390_waiting_timed_out (unsigned long ptr); +/* Sets the timer to wake us up */ +static void dc390_waiting_timer (PACB pACB, unsigned long to) +{ + if (timer_pending (&pACB->Waiting_Timer)) return; + init_timer (&pACB->Waiting_Timer); + pACB->Waiting_Timer.function = DC390_waiting_timed_out; + pACB->Waiting_Timer.data = (unsigned long)pACB; + if (time_before (jiffies + to, pACB->pScsiHost->last_reset)) + pACB->Waiting_Timer.expires = pACB->pScsiHost->last_reset + 1; + else + pACB->Waiting_Timer.expires = jiffies + to + 1; + add_timer (&pACB->Waiting_Timer); } -static void dc390_DoWaitingSRB( PACB pACB ) +/* Send the next command from the waiting list to the bus */ +static void dc390_Waiting_process ( PACB pACB ) { PDCB ptr, ptr1; PSRB pSRB; - if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) - { - ptr = pACB->pDCBRunRobin; - if( !ptr ) - { - ptr = pACB->pLinkDCB; - pACB->pDCBRunRobin = ptr; - } - ptr1 = ptr; - for( ;ptr1; ) - { - pACB->pDCBRunRobin = ptr1->pNextDCB; - if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) || - !( pSRB = ptr1->pWaitingSRB ) ) - { - if(pACB->pDCBRunRobin == ptr) - break; - ptr1 = ptr1->pNextDCB; - } + if( (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) + return; + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); + ptr = pACB->pDCBRunRobin; + if( !ptr ) + { + ptr = pACB->pLinkDCB; + pACB->pDCBRunRobin = ptr; + } + ptr1 = ptr; + if (!ptr1) return; + do + { + pACB->pDCBRunRobin = ptr1->pNextDCB; + if( !( pSRB = ptr1->pWaitingSRB ) || + ( ptr1->MaxCommand <= ptr1->GoingSRBCnt )) + ptr1 = ptr1->pNextDCB; + else + { + /* Try to send to the bus */ + if( !dc390_StartSCSI(pACB, ptr1, pSRB) ) + dc390_Waiting_to_Going (ptr1, pSRB); else - { - if( !dc390_StartSCSI(pACB, ptr1, pSRB) ) - { - ptr1->GoingSRBCnt++; - if( ptr1->pWaitLast == pSRB ) - { - ptr1->pWaitingSRB = NULL; - ptr1->pWaitLast = NULL; - } - else - { - ptr1->pWaitingSRB = pSRB->pNextSRB; - } - pSRB->pNextSRB = NULL; - - if( ptr1->pGoingSRB ) - ptr1->pGoingLast->pNextSRB = pSRB; - else - ptr1->pGoingSRB = pSRB; - ptr1->pGoingLast = pSRB; - } - break; - } - } - } + dc390_waiting_timer (pACB, HZ/5); + break; + } + } while (ptr1 != ptr); return; } - -static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB) +/* Wake up waiting queue */ +void DC390_waiting_timed_out (unsigned long ptr) { - if( pDCB->pWaitingSRB ) - { - pDCB->pWaitLast->pNextSRB = pSRB; - pSRB->pNextSRB = NULL; - } - else - { - pDCB->pWaitingSRB = pSRB; - } - pDCB->pWaitLast = pSRB; + PACB pACB = (PACB)ptr; + DC390_IFLAGS + DC390_AFLAGS + DEBUG0(printk ("DC390: Debug: Waiting queue woken up by timer!\n");) + DC390_LOCK_IO; + DC390_LOCK_ACB; + dc390_Waiting_process (pACB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; } - /*********************************************************************** * Function: static void dc390_SendSRB (PACB pACB, PSRB pSRB) * @@ -878,41 +1084,33 @@ PDCB pDCB; pDCB = pSRB->pSRBDCB; - if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || + if( (pDCB->MaxCommand <= pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { - dc390_SRBwaiting(pDCB, pSRB); - goto SND_EXIT; + dc390_Waiting_append (pDCB, pSRB); + dc390_Waiting_process (pACB); + return; } +#if 0 if( pDCB->pWaitingSRB ) { - dc390_SRBwaiting(pDCB, pSRB); + dc390_Waiting_append (pDCB, pSRB); /* pSRB = GetWaitingSRB(pDCB); */ /* non-existent */ pSRB = pDCB->pWaitingSRB; + /* Remove from waiting list */ pDCB->pWaitingSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; + if (!pDCB->pWaitingSRB) pDCB->pWaitLast = NULL; } - - if( !dc390_StartSCSI(pACB, pDCB, pSRB) ) - { - pDCB->GoingSRBCnt++; - if( pDCB->pGoingSRB ) - { - pDCB->pGoingLast->pNextSRB = pSRB; - pDCB->pGoingLast = pSRB; - } - else - { - pDCB->pGoingSRB = pSRB; - pDCB->pGoingLast = pSRB; - } - } - else - dc390_RewaitSRB0( pDCB, pSRB ); - -SND_EXIT: - return; +#endif + + if (!dc390_StartSCSI(pACB, pDCB, pSRB)) + dc390_Going_append (pDCB, pSRB); + else { + dc390_Waiting_insert (pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); + }; } /*********************************************************************** @@ -927,8 +1125,8 @@ { pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); + //pSRB->ScsiCmdLen = pcmd->cmd_len; + //memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); if( pcmd->use_sg ) { @@ -961,8 +1159,39 @@ pSRB->SGToBeXferLen = 0; pSRB->ScsiPhase = 0; pSRB->EndMessage = 0; + pSRB->TagNumber = 255; }; +/* Put cmnd from Query to Waiting list and send next Waiting cmnd */ +static void dc390_Query_to_Waiting (PACB pACB) +{ + Scsi_Cmnd *pcmd; + PSRB pSRB; + PDCB pDCB; + + if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) + return; + + while (pACB->QueryCnt) + { + pSRB = dc390_Free_get ( pACB ); + if (!pSRB) return; + pcmd = dc390_Query_get ( pACB ); + if (!pcmd) { dc390_Free_insert (pACB, pSRB); return; }; /* should not happen */ + pDCB = dc390_findDCB (pACB, pcmd->target, pcmd->lun); + if (!pDCB) + { + dc390_Free_insert (pACB, pSRB); + printk (KERN_ERR "DC390: Command in queue to non-existing device!\n"); + pcmd->result = MK_RES(DRIVER_ERROR,DID_ERROR,0,0); + DC390_UNLOCK_ACB_NI; + pcmd->done (pcmd); + DC390_LOCK_ACB_NI; + }; + dc390_BuildSRB (pcmd, pDCB, pSRB); + dc390_Waiting_append ( pDCB, pSRB ); + } +} /*********************************************************************** * Function : static int DC390_queue_command (Scsi_Cmnd *cmd, @@ -985,7 +1214,6 @@ int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { - Scsi_Cmnd *pcmd; PDCB pDCB; PSRB pSRB; DC390_AFLAGS @@ -993,7 +1221,7 @@ DEBUG0(/* if(pACB->scan_devices) */ \ - printk(KERN_INFO "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\ + printk(KERN_INFO "DC390: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n",\ cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);) DC390_LOCK_ACB; @@ -1014,25 +1242,32 @@ if ( ( cmd->target >= pACB->pScsiHost->max_id ) || (cmd->lun >= pACB->pScsiHost->max_lun) ) { -/* printk("DC390: Ignore target %d lun %d\n", +/* printk ("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ DC390_UNLOCK_ACB; - done(cmd); - return( 0 ); + //return (1); + done (cmd); + return (0); } - if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) + if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY || cmd->cmnd[0] == INQUIRY) && + !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { - pACB->DCBmap[cmd->target] |= (1 << cmd->lun); pACB->scan_devices = 1; - dc390_initDCB( pACB, &pDCB, cmd ); + dc390_initDCB( pACB, &pDCB, cmd->target, cmd->lun ); if (!pDCB) { - printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target); + printk (KERN_ERR "DC390: kmalloc for DCB failed, target %02x lun %02x\n", + cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + printk ("DC390: No DCB in queue_command!\n"); +#ifdef USE_NEW_EH + return (1); +#else + done (cmd); + return (0); +#endif }; } @@ -1041,71 +1276,73 @@ printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n", cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + //return (1); + done (cmd); + return (0); } else { - pDCB = dc390_findDCB (pACB, cmd); + pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); if (!pDCB) { /* should never happen */ + printk (KERN_ERR "DC390: no DCB failed, target %02x lun %02x\n", + cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + printk ("DC390: No DCB in queuecommand (2)!\n"); +#ifdef USE_NEW_EH + return (1); +#else + done (cmd); + return (0); +#endif }; } pACB->Cmds++; cmd->scsi_done = done; cmd->result = 0; + + dc390_Query_to_Waiting (pACB); - if( pDCB->QIORBCnt ) /* Unsent commands ? */ + if( pACB->QueryCnt ) /* Unsent commands ? */ { - dc390_QLinkcmd( cmd, pDCB ); - pcmd = dc390_Getcmd( pDCB ); /* Get first command */ - pACB->CmdInQ++; + DEBUG0(printk ("DC390: QueryCnt != 0\n");) + dc390_Query_append ( cmd, pACB ); + dc390_Waiting_process (pACB); } - else - pcmd = cmd; - - pSRB = dc390_GetSRB( pACB ); - - if( !pSRB ) + else if (pDCB->pWaitingSRB) { - dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */ - pACB->CmdOutOfSRB++; - DC390_UNLOCK_ACB; - return(0); + pSRB = dc390_Free_get ( pACB ); + DEBUG0(if (!pSRB) printk ("DC390: No free SRB but Waiting\n"); else printk ("DC390: Free SRB w/ Waiting\n");) + if (!pSRB) dc390_Query_append (cmd, pACB); + else + { + dc390_BuildSRB (cmd, pDCB, pSRB); + dc390_Waiting_append (pDCB, pSRB); + } + dc390_Waiting_process (pACB); } - - dc390_BuildSRB (pcmd, pDCB, pSRB); - dc390_SendSRB( pACB, pSRB ); + else + { + pSRB = dc390_Free_get ( pACB ); + DEBUG0(if (!pSRB) printk ("DC390: No free SRB w/o Waiting\n"); else printk ("DC390: Free SRB w/o Waiting\n");) + if (!pSRB) + { + dc390_Query_append (cmd, pACB); + dc390_Waiting_process (pACB); + } + else + { + dc390_BuildSRB (cmd, pDCB, pSRB); + dc390_SendSRB (pACB, pSRB); + }; + }; DC390_UNLOCK_ACB; - DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);) + DEBUG1(printk (KERN_DEBUG " ... command (pid %li) queued successfully.\n", cmd->pid);) return(0); } - -static void dc390_DoNextCmd( PACB pACB, PDCB pDCB ) -{ - Scsi_Cmnd *pcmd; - PSRB pSRB; - - if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) - return; - - pcmd = dc390_Getcmd( pDCB ); - pSRB = dc390_GetSRB( pACB ); - if( !pSRB ) - dc390_QLinkcmd( pcmd, pDCB ); - else - { - dc390_BuildSRB (pcmd, pDCB, pSRB); - dc390_SendSRB( pACB, pSRB ); - }; -} - /* We ignore mapping problems, as we expect everybody to respect * valid partition tables. Waiting for complaints ;-) */ @@ -1242,15 +1479,17 @@ void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB) { USHORT pstat; PDEVDECL1; + if (!pDCB) pDCB = pACB->pActiveDCB; + if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB; if (pSRB) { - printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n", + printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08x, Phase %02x\n", pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState, pSRB->ScsiPhase); printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus); }; - printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus); + printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08x\n", dc390_laststatus); printk ("DC390: Register dump: SCSI block:\n"); printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n"); printk ("DC390: %06x %02x %02x %02x", @@ -1260,6 +1499,12 @@ DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1), DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4)); DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); + if (DC390_read8(Current_Fifo) & 0x1f) + { + printk ("DC390: FIFO:"); + while (DC390_read8(Current_Fifo) & 0x1f) printk (" %02x", DC390_read8(ScsiFifo)); + printk ("\n"); + }; printk ("DC390: Register dump: DMA engine:\n"); printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n"); printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n", @@ -1289,44 +1534,40 @@ { PDCB pDCB; PSRB pSRB, psrb; - ULONG count, i; - PSCSICMD pcmd, pcmd1; + UINT count, i; + PSCSICMD pcmd; int status; - ULONG sbac; + //ULONG sbac; DC390_AFLAGS PACB pACB = (PACB) cmd->host->hostdata; DC390_LOCK_ACB; - pDCB = dc390_findDCB (pACB, cmd); - /* abort() is too buggy at the moment. If it's called we are in trouble anyway. - * so let's dump some info into the syslog at least. (KG, 98/08/20) */ - if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0; - printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n", - cmd->pid, pDCB, pSRB); - dc390_dumpinfo (pACB, pDCB, pSRB); - - if( !pDCB ) goto NOT_RUN; + printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n", + cmd->pid, cmd->target, cmd->lun); - if( pDCB->QIORBCnt ) + /* First scan Query list */ + if( pACB->QueryCnt ) { - pcmd = pDCB->pQIORBhead; + pcmd = pACB->pQueryHead; if( pcmd == cmd ) { - pDCB->pQIORBhead = pcmd->next; + /* Found: Dequeue */ + pACB->pQueryHead = pcmd->next; pcmd->next = NULL; - pDCB->QIORBCnt--; + if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL; + pACB->QueryCnt--; status = SCSI_ABORT_SUCCESS; goto ABO_X; } - for( count = pDCB->QIORBCnt, i=0; iQueryCnt, i=0; inext == cmd ) { - pcmd1 = pcmd->next; - pcmd->next = pcmd1->next; - pcmd1->next = NULL; - pDCB->QIORBCnt--; + pcmd->next = cmd->next; + cmd->next = NULL; + if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL; + pACB->QueryCnt--; status = SCSI_ABORT_SUCCESS; goto ABO_X; } @@ -1337,14 +1578,21 @@ } } + pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); + if( !pDCB ) goto NOT_RUN; + /* Added 98/07/02 KG */ + /* pSRB = pDCB->pActiveSRB; if (pSRB && pSRB->pcmd == cmd ) goto ON_GOING; - + */ + pSRB = pDCB->pWaitingSRB; if( !pSRB ) goto ON_GOING; + + /* Now scan Waiting queue */ if( pSRB->pcmd == cmd ) { pDCB->pWaitingSRB = pSRB->pNextSRB; @@ -1364,16 +1612,21 @@ pSRB = psrb->pNextSRB; psrb->pNextSRB = pSRB->pNextSRB; if( pSRB == pDCB->pWaitLast ) - pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */ + pDCB->pWaitLast = psrb; IN_WAIT: - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; + dc390_Free_insert (pACB, pSRB); + pDCB->WaitSRBCnt--; cmd->next = NULL; status = SCSI_ABORT_SUCCESS; goto ABO_X; } + /* SRB has already been sent ! */ ON_GOING: + /* abort() is too stupid for already sent commands at the moment. + * If it's called we are in trouble anyway, so let's dump some info + * into the syslog at least. (KG, 98/08/20,99/06/20) */ + dc390_dumpinfo (pACB, pDCB, pSRB); pSRB = pDCB->pGoingSRB; pDCB->DCBFlag |= ABORT_DEV_; /* Now for the hard part: The command is currently processed */ @@ -1404,12 +1657,13 @@ ABO_X: cmd->result = DID_ABORT << 16; printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status); +#if 0 if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */ { /* Let's do something to help the bus getting clean again */ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, DMA_COMMAND); - //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); //DC390_write8 (ScsiCmd, RESET_ATN_CMD); DC390_write8 (ScsiCmd, NOP_CMD); //udelay (10000); @@ -1434,10 +1688,13 @@ sbac = DC390_read32 (DMA_ScsiBusCtrl); printk ("%08lx\n", sbac); }; +#endif dc390_lastabortedpid = cmd->pid; DC390_UNLOCK_ACB; //do_DC390_Interrupt (pACB->IRQLevel, 0, 0); - cmd->scsi_done(cmd); +#ifndef USE_NEW_EH + if (status == SCSI_ABORT_SUCCESS) cmd->scsi_done(cmd); +#endif return( status ); } @@ -1454,20 +1711,24 @@ pDCB->SyncMode &= ~SYNC_NEGO_DONE; pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; + pDCB->TagMask = 0; pDCB->CtrlR3 = FAST_CLK; pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK; pDCB->CtrlR4 |= pACB->glitch_cfg; pDCB = pDCB->pNextDCB; } while( pdcb != pDCB ); -} + pACB->ACBFlag &= ~(RESET_DEV | RESET_DONE | RESET_DETECT); +} +#if 0 +/* Moves all SRBs from Going to Waiting for all DCBs */ static void dc390_RecoverSRB( PACB pACB ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; - ULONG cnt, i; + UINT cnt, i; pDCB = pACB->pLinkDCB; if( !pDCB ) return; @@ -1499,7 +1760,7 @@ pdcb = pdcb->pNextDCB; } while( pdcb != pDCB ); } - +#endif /*********************************************************************** * Function : int DC390_reset (Scsi_Cmnd *cmd, ...) @@ -1507,34 +1768,37 @@ * Purpose : perform a hard reset on the SCSI bus * * Inputs : cmd - command which caused the SCSI RESET + * resetFlags - how hard to try * * Returns : 0 on success. ***********************************************************************/ -int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) +int DC390_reset (Scsi_Cmnd *cmd, unsigned int resetFlags) { UCHAR bval; - ULONG i; DC390_AFLAGS PACB pACB = (PACB) cmd->host->hostdata; printk(KERN_INFO "DC390: RESET ... "); DC390_LOCK_ACB; + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* disable interrupt */ + DC390_write8 (CtrlReg1, bval); /* disable IRQ on bus reset */ + pACB->ACBFlag |= RESET_DEV; dc390_ResetSCSIBus( pACB ); - /* Unlock ? */ - for( i=0; i<600; i++ ) - udelay(1000); + dc390_ResetDevParam( pACB ); + udelay (1000); + pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_read8 (INT_Status); /* Reset Pending INT */ - dc390_ResetDevParam( pACB ); - dc390_DoingSRB_Done( pACB ); + dc390_DoingSRB_Done( pACB, cmd ); /* dc390_RecoverSRB (pACB); */ pACB->pActiveDCB = NULL; @@ -1543,10 +1807,10 @@ bval &= ~DIS_INT_ON_SCSI_RST; DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */ - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process( pACB ); - DC390_UNLOCK_ACB; printk("done\n"); + DC390_UNLOCK_ACB; return( SCSI_RESET_SUCCESS ); } @@ -1556,22 +1820,22 @@ /*********************************************************************** * Function : static void dc390_initDCB() * - * Purpose : initialize the internal structures for a given DCB + * Purpose : initialize the internal structures for a DCB (to be malloced) * - * Inputs : cmd - pointer to this scsi cmd request block structure + * Inputs : SCSI id and lun ***********************************************************************/ -void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ) +void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun ) { PEEprom prom; UCHAR index; - PDCB pDCB; + PDCB pDCB, pDCB2; pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC); - DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n", \ - cmd->target, cmd->lun, (int)pDCB);) + DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): %p\n" \ + id, lun, pDCB);) - *ppDCB = pDCB; + *ppDCB = pDCB; pDCB2 = 0; if (!pDCB) return; if( pACB->DCBCnt == 0 ) { @@ -1585,37 +1849,58 @@ pACB->DCBCnt++; - pACB->pLastDCB = pDCB; pDCB->pNextDCB = pACB->pLinkDCB; + pACB->pLastDCB = pDCB; pDCB->pDCBACB = pACB; - pDCB->QIORBCnt = 0; - pDCB->UnitSCSIID = cmd->target; - pDCB->UnitSCSILUN = cmd->lun; + pDCB->TargetID = id; + pDCB->TargetLUN = lun; pDCB->pWaitingSRB = NULL; pDCB->pGoingSRB = NULL; pDCB->GoingSRBCnt = 0; + pDCB->WaitSRBCnt = 0; pDCB->pActiveSRB = NULL; pDCB->TagMask = 0; pDCB->MaxCommand = 1; index = pACB->AdapterIndex; pDCB->DCBFlag = 0; - prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2]; - pDCB->DevMode = prom->EE_MODE1; + /* Is there a corresp. LUN==0 device ? */ + if (lun != 0) + pDCB2 = dc390_findDCB (pACB, id, 0); + prom = (PEEprom) &dc390_eepromBuf[index][id << 2]; + /* Some values are for all LUNs: Copy them */ + /* In a clean way: We would have an own structure for a SCSI-ID */ + if (pDCB2) + { + pDCB->DevMode = pDCB2->DevMode; + pDCB->SyncMode = pDCB2->SyncMode; + pDCB->SyncPeriod = pDCB2->SyncPeriod; + pDCB->SyncOffset = pDCB2->SyncOffset; + pDCB->NegoPeriod = pDCB2->NegoPeriod; + + pDCB->CtrlR3 = pDCB2->CtrlR3; + pDCB->CtrlR4 = pDCB2->CtrlR4; + pDCB->Inquiry7 = pDCB2->Inquiry7; + } + else + { + pDCB->DevMode = prom->EE_MODE1; + pDCB->SyncMode = 0; + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; + + pDCB->CtrlR3 = FAST_CLK; + + pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; + if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) + pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; + pDCB->Inquiry7 = 0; + } - pDCB->SyncMode = 0; + pACB->DCBmap[id] |= (1 << lun); dc390_updateDCB(pACB, pDCB); - - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; - - pDCB->CtrlR3 = FAST_CLK; - - pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; - if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) - pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; } /*********************************************************************** @@ -1626,24 +1911,26 @@ void dc390_updateDCB (PACB pACB, PDCB pDCB) { - pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN); - - if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP; - else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP; - - if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) ) - pDCB->SyncMode |= SYNC_ENABLE; - else - { + pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE /*| EN_ATN_STOP*/; + if (pDCB->DevMode & TAG_QUEUEING_) { + //if (pDCB->SyncMode & EN_TAG_QUEUEING) pDCB->MaxCommand = pACB->TagMaxNum; + } else { + pDCB->SyncMode &= ~EN_TAG_QUEUEING; + pDCB->MaxCommand = 1; + }; + + if( pDCB->DevMode & SYNC_NEGO_ ) + pDCB->SyncMode |= SYNC_ENABLE; + else { pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE); pDCB->SyncOffset &= ~0x0f; - }; - - if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; - + }; + + //if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; + pDCB->CtrlR1 = pACB->pScsiHost->this_id; if( pDCB->DevMode & PARITY_CHK_ ) - pDCB->CtrlR1 |= PARITY_ERR_REPO; + pDCB->CtrlR1 |= PARITY_ERR_REPO; }; @@ -1657,7 +1944,7 @@ { int i; PDCB pDCB = pACB->pLinkDCB; - for (i = 0; i < pACB->DeviceCnt; i++) + for (i = 0; i < pACB->DCBCnt; i++) { dc390_updateDCB (pACB, pDCB); pDCB = pDCB->pNextDCB; @@ -1681,12 +1968,12 @@ void dc390_linkSRB( PACB pACB ) { - ULONG count, i; + UINT count, i; count = pACB->SRBCount; - for( i=0; i< count; i++) + for( i=0; iSRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; else pACB->SRB_array[i].pNextSRB = NULL; @@ -1716,7 +2003,15 @@ psh->io_port = io_port; psh->n_io_port = 0x80; psh->irq = Irq; - +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,50) + psh->base = io_port; +#else + psh->base = (char*)io_port; +#endif + psh->unique_id = io_port; + psh->dma_channel = -1; + psh->last_reset = jiffies; + pACB = (PACB) psh->hostdata; DC390_LOCKA_INIT; DC390_LOCK_ACB; @@ -1741,6 +2036,8 @@ pACB->pActiveDCB = NULL; pACB->pFreeSRB = pACB->SRB_array; pACB->SRBCount = MAX_SRB_CNT; + pACB->QueryCnt = 0; + pACB->pQueryHead = NULL; pACB->AdapterIndex = index; pACB->status = 0; psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID]; @@ -1759,7 +2056,9 @@ pACB->DCBmap[i] = 0; pACB->sel_timeout = SEL_TIMEOUT; pACB->glitch_cfg = EATER_25NS; - pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0; + pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = 0; + pACB->SelLost = pACB->SelConn = 0; + init_timer (&pACB->Waiting_Timer); } @@ -1777,22 +2076,11 @@ int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) { PACB pACB, pACB2; - UCHAR used_irq = 0, dstate; + UCHAR dstate; int i; pACB = (PACB) psh->hostdata; - for ( pACB2 = dc390_pACB_start; pACB2 ; ) - { - if( pACB2->IRQLevel == Irq ) - { - used_irq = 1; - break; - } - else - pACB2 = pACB2->pNextACB; - } - if (check_region (io_port, psh->n_io_port)) { printk(KERN_ERR "DC390: register IO ports error!\n"); @@ -1803,14 +2091,12 @@ DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */ - if( !used_irq ) - { - if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) )) - { - printk(KERN_ERR "DC390: register IRQ error!\n"); - return( -1 ); - } - } + if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", pACB) )) + { + printk(KERN_ERR "DC390: register IRQ error!\n"); + release_region (io_port, psh->n_io_port); + return( -1 ); + } if( !dc390_pACB_start ) { @@ -1832,9 +2118,13 @@ if (pACB->Gmode2 & RST_SCSI_BUS) { dc390_ResetSCSIBus( pACB ); - /* Unlock before ? */ - for( i=0; i<600; i++ ) + udelay (1000); + pACB->pScsiHost->last_reset = jiffies + HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + /* + for( i=0; i<(500 + 1000*dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); i++ ) udelay(1000); + */ }; pACB->ACBFlag = 0; DC390_read8 (INT_Status); /* Reset Pending INT */ @@ -1846,6 +2136,7 @@ DC390_write8 (CtrlReg3, FAST_CLK); /* fast clock */ DC390_write8 (CtrlReg4, pACB->glitch_cfg | /* glitch eater */ (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0); /* Negation */ + DC390_write8 (CtcReg_High, 0); /* Clear Transfer Count High: ID */ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); @@ -1885,18 +2176,24 @@ printk (KERN_ERR "DC390_init: No EEPROM found!\n"); return( -1 ); #else - int period; - printk (KERN_INFO "DC390_init: No EEPROM found!\n"); - printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n"); - dc390_checkparams (); - period = dc390_clock_period1[tmscsim[1]]; + int speed; + dc390_adapname = "AM53C974"; + printk (KERN_INFO "DC390_init: No EEPROM found! Trying default settings ...\n"); + dc390_check_for_safe_settings (); + dc390_fill_with_defaults (); + dc390_EEprom_Override (index); + speed = dc390_clock_speed[tmscsim[1]]; printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz)," - " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1], - 40 / period, ((40%period)*10 + period/2) / period, - (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4])); - dc390_EEpromDefaults (index); + " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i), DelayReset=%is\n", + tmscsim[0], tmscsim[1], speed/10, speed%10, + (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]), tmscsim[5]); #endif - }; + } + else + { + dc390_check_for_safe_settings (); + dc390_EEprom_Override (index); + } psh = scsi_register( psht, sizeof(DC390_ACB) ); if( !psh ) return( -1 ); @@ -2000,7 +2297,8 @@ PDEVDECL0; UCHAR irq; UINT io_port; - DC390_IFLAGS DC390_DFLAGS + //DC390_IFLAGS + DC390_DFLAGS DC390_LOCK_DRV; //dc390_pSHT_start = psht; @@ -2009,7 +2307,11 @@ if ( PCI_PRESENT ) while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974)) { - DC390_LOCK_IO; /* Remove this when going to new eh */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30) + if (pci_enable_device (pdev)) + continue; +#endif + //DC390_LOCK_IO; /* Remove this when going to new eh */ PCI_GET_IO_AND_IRQ; DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);) @@ -2019,14 +2321,17 @@ dc390_set_pci_cfg (PDEV); dc390_adapterCnt++; }; - DC390_UNLOCK_IO; /* Remove when going to new eh */ + //DC390_UNLOCK_IO; /* Remove when going to new eh */ } else printk (KERN_ERR "DC390: No PCI BIOS found!\n"); if (dc390_adapterCnt) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) + psht->proc_name = "tmscsim"; +#else psht->proc_dir = &DC390_proc_scsi_tmscsim; - +#endif printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt); DC390_UNLOCK_DRV; return( dc390_adapterCnt ); @@ -2048,7 +2353,7 @@ if (cmd->result) { PACB pACB = (PACB)cmd->host->hostdata; - PDCB pDCB = dc390_findDCB (pACB, cmd); + PDCB pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); printk ("DC390: Unsetting DsCn, Sync and TagQ!\n"); if (pDCB) { @@ -2056,7 +2361,6 @@ dc390_updateDCB (pACB, pDCB); }; }; - kfree (cmd->buffer); kfree (cmd); }; @@ -2064,20 +2368,21 @@ { char* buffer; Scsi_Cmnd* cmd; - buffer = kmalloc (256, GFP_ATOMIC); - cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC); + cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC); + if (!cmd) { printk ("DC390: kmalloc failed in inquiry!\n"); return; }; + buffer = (char*)cmd + sizeof(Scsi_Cmnd); - memset (buffer, 0, 256); - memset (cmd, 0, sizeof(Scsi_Cmnd)); + memset (cmd, 0, sizeof(Scsi_Cmnd) + 256); cmd->cmnd[0] = INQUIRY; - cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0; + cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0; cmd->cmnd[4] = 0xff; cmd->cmd_len = 6; cmd->old_cmd_len = 6; cmd->host = pACB->pScsiHost; - cmd->target = pDCB->UnitSCSIID; - cmd->lun = pDCB->UnitSCSILUN; + cmd->target = pDCB->TargetID; + cmd->lun = pDCB->TargetLUN; cmd->serial_number = 1; + cmd->pid = 390; cmd->bufflen = 128; cmd->buffer = buffer; cmd->request_bufflen = 128; @@ -2088,11 +2393,62 @@ cmd->request.rq_status = RQ_SCSI_BUSY; + pDCB->SyncMode &= ~SYNC_NEGO_DONE; printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n", - pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + pDCB->TargetID, pDCB->TargetLUN); DC390_queue_command (cmd, dc390_inquiry_done); }; +/*********************************************************************** + * Functions: dc390_sendstart(), dc390_sendstart_done() + * + * Purpose: When changing speed etc., we have to issue an INQUIRY + * command to make sure, we agree upon the nego parameters + * with the device + ***********************************************************************/ + +static void dc390_sendstart_done (Scsi_Cmnd* cmd) +{ + printk (KERN_INFO "DC390: SENDSTART (ID %02x LUN %02x) returned %08x\n", + cmd->target, cmd->lun, cmd->result); + kfree (cmd); +}; + +void dc390_sendstart (PACB pACB, PDCB pDCB) +{ + char* buffer; + Scsi_Cmnd* cmd; + cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC); + if (!cmd) { printk ("DC390: kmalloc failed in sendstart!\n"); return; }; + buffer = (char*)cmd + sizeof(Scsi_Cmnd); + + memset (cmd, 0, sizeof(Scsi_Cmnd) + 256); + cmd->cmnd[0] = 0x1b; /* START_STOP_UNIT */ + cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0; + cmd->cmnd[4] = 0x01; /* START */ + + cmd->cmd_len = 6; cmd->old_cmd_len = 6; + cmd->host = pACB->pScsiHost; + cmd->target = pDCB->TargetID; + cmd->lun = pDCB->TargetLUN; + cmd->serial_number = 1; + cmd->pid = 310; + cmd->bufflen = 128; + cmd->buffer = buffer; + cmd->request_bufflen = 128; + cmd->request_buffer = &buffer[128]; + cmd->done = dc390_sendstart_done; + cmd->scsi_done = dc390_sendstart_done; + cmd->timeout_per_command = 5*HZ; + + cmd->request.rq_status = RQ_SCSI_BUSY; + + pDCB->SyncMode &= ~SYNC_NEGO_DONE; + printk (KERN_INFO "DC390: Queue SEND_START command to dev ID %02x LUN %02x\n", + pDCB->TargetID, pDCB->TargetLUN); + DC390_queue_command (cmd, dc390_sendstart_done); +}; + /******************************************************************** * Function: dc390_set_info() * @@ -2210,6 +2566,9 @@ if (!memcmp (pos, "RESET", 5)) goto reset; else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry; else if (!memcmp (pos, "REMOVE", 6)) goto remove; + else if (!memcmp (pos, "ADD", 3)) goto add; + else if (!memcmp (pos, "START", 5)) goto start; + else if (!memcmp (pos, "DUMP", 4)) goto dump; if (isdigit (*pos)) { @@ -2226,13 +2585,20 @@ pDCB = pACB->pLinkDCB; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; /* Sanity Check */ - if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) + if (pDCB->TargetID != id || pDCB->TargetLUN != lun) { printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n", dev, id, lun); goto einv2; }; + if (pDCB->pWaitingSRB || pDCB->pGoingSRB) + { + printk ("DC390: Cannot change dev (%i-%i) cfg: Pending requests\n", + pDCB->TargetID, pDCB->TargetLUN); + goto einv; + }; + olddevmode = pDCB->DevMode; YESNO (pos, pDCB->DevMode, PARITY_CHK_); needs_inquiry++; @@ -2245,8 +2611,7 @@ needs_inquiry++; YESNO (pos, pDCB->DevMode, TAG_QUEUEING_); if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--; - YESNO (pos, pDCB->SyncMode, EN_ATN_STOP); - + dc390_updateDCB (pACB, pDCB); if (!pos) goto ok; @@ -2266,7 +2631,7 @@ else pos = strtok (0, " \t\n:=,;."); if (!pos) goto ok; - /* Speed: NegoPeriod */ + /* Sync Speed in MHz */ if (*pos != '-') { SCANF (pos, p0, dum, 1, 13); @@ -2281,11 +2646,11 @@ for (; p0-pos > 1; p0--) dum /= 10; pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2; if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19; - if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; pos = strtok (0, " \t\n:=,;"); if (!pos) goto ok; }; if (*pos == 'M') pos = strtok (0, " \t\n:=,;"); + if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; } else pos = strtok (0, " \t\n:=,;"); /* dc390_updateDCB (pACB, pDCB); */ @@ -2300,28 +2665,49 @@ if (pDCB->SyncOffset > olddevmode) needs_inquiry++; } else pos = strtok (0, " \t\n:=,;"); + if (!pos) goto ok; dc390_updateDCB (pACB, pDCB); + + //olddevmode = pDCB->MaxCommand; + /* MaxCommand (Tags) */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/); + if (pDCB->SyncMode & EN_TAG_QUEUEING) + pDCB->MaxCommand = dum; + else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n"); + } + else pos = strtok (0, " \t\n:=,;"); + } else { - char* p1 = pos; UCHAR dum; + char* p1 = pos; UCHAR dum, newadaptid; PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));) dum = GLITCH_TO_NS (pACB->glitch_cfg); /* Adapter setting */ SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); - SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7); + SEARCH (pos, p0, newadaptid, "ADAPTERID", 7); SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32); SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255); SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS"); SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS"); + SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S"); ok2: pACB->glitch_cfg = NS_TO_GLITCH (dum); if (pACB->sel_timeout < 60) pACB->sel_timeout = 60; - dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++; - pACB->TagMaxNum &= (1 << --dum); - if (pos == p1) goto einv; + DC390_write8 (Scsi_TimeOut, pACB->sel_timeout); + if (newadaptid != pACB->pScsiHost->this_id) + { + pACB->pScsiHost->this_id = newadaptid; + dc390_ResetDevParam (pACB); + } + //dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++; + //pACB->TagMaxNum &= (1 << --dum); dc390_updateDCBs (pACB); + // All devs should be INQUIRED now + if (pos == p1) goto einv; } if (pos) goto next; @@ -2351,7 +2737,15 @@ DC390_UNLOCK_IO; }; return (length); - + + dump: + { + dc390_dumpinfo (pACB, 0, 0); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + } + return (length); + inquiry: { pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; @@ -2359,7 +2753,7 @@ if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n", - dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dev, pDCB->TargetID, pDCB->TargetLUN); DC390_UNLOCK_ACB; dc390_inquiry (pACB, pDCB); DC390_UNLOCK_IO; @@ -2373,13 +2767,45 @@ if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n", - dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dev, pDCB->TargetID, pDCB->TargetLUN); + /* TO DO: We should make sure no pending commands are left */ dc390_remove_dev (pACB, pDCB); DC390_UNLOCK_ACB; DC390_UNLOCK_IO; }; return (length); + add: + { + int id, lun; + pos = strtok (0, " \t\n.:;="); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pDCB = dc390_findDCB (pACB, id, lun); + if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; }; + dc390_initDCB (pACB, &pDCB, id, lun); + DC390_UNLOCK_ACB; + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + + start: + { + int id, lun; + pos = strtok (0, " \t\n.:;="); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pDCB = dc390_findDCB (pACB, id, lun); + if (pDCB) printk ("DC390: SendStart: Device already existing ...\n"); + else dc390_initDCB (pACB, &pDCB, id, lun); + DC390_UNLOCK_ACB; + dc390_sendstart (pACB, pDCB); + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + einv_dev: printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", dev, pACB->DCBCnt - 1); @@ -2429,6 +2855,7 @@ PSH shpnt; PACB pACB; PDCB pDCB; + PSCSICMD pcmd; DC390_AFLAGS pACB = dc390_pACB_start; @@ -2454,46 +2881,87 @@ SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex); SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase); - SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel); + SPRINTF("IRQ %02i\n", pACB->IRQLevel); SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun); - SPRINTF("AdapterID %i, SelTimeout %i ms\n", - shpnt->this_id, (pACB->sel_timeout*164)/100); + SPRINTF("AdapterID %i, SelTimeout %i ms, DelayReset %i s\n", + shpnt->this_id, (pACB->sel_timeout*164)/100, + dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); - SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n", + SPRINTF("TagMaxNum %i, Status 0x%02x, ACBFlag 0x%02x, GlitchEater %i ns\n", pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12); - SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n", + SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %i, Out of SRB conds %i\n", pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB); - SPRINTF(" Lost arbitrations %li\n", pACB->SelLost); + SPRINTF(" Lost arbitrations %i, Sel. connected %i, Connected: %s\n", + pACB->SelLost, pACB->SelConn, pACB->Connected? "Yes": "No"); SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt); + SPRINTF("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n", + pACB->DCBmap[0], pACB->DCBmap[1], pACB->DCBmap[2], pACB->DCBmap[3], + pACB->DCBmap[4], pACB->DCBmap[5], pACB->DCBmap[6], pACB->DCBmap[7]); - SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n"); + SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd\n"); pDCB = pACB->pLinkDCB; for (dev = 0; dev < pACB->DCBCnt; dev++) { - SPRINTF("%02i %02i %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + SPRINTF("%02i %02i %02i ", dev, pDCB->TargetID, pDCB->TargetLUN); YESNO(pDCB->DevMode & PARITY_CHK_); YESNO(pDCB->SyncMode & SYNC_NEGO_DONE); YESNO(pDCB->DevMode & EN_DISCONNECT_); - //YESNO(pDCB->SyncMode & EN_ATN_STOP); YESNO(pDCB->DevMode & SEND_START_); YESNO(pDCB->SyncMode & EN_TAG_QUEUEING); - YESNO(pDCB->SyncMode & EN_ATN_STOP); if (pDCB->SyncOffset & 0x0f) { int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++; SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2); spd = 40/(sp); spd1 = 40%(sp); spd1 = (spd1 * 10 + sp/2) / (sp); - SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f)); + SPRINTF(" %2i.%1i M %02i", spd, spd1, (pDCB->SyncOffset & 0x0f)); } - else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2); + else SPRINTF(" (%03i ns) ", (pDCB->NegoPeriod) << 2); /* Add more info ...*/ + SPRINTF (" %02i\n", pDCB->MaxCommand); pDCB = pDCB->pNextDCB; } + SPRINTF ("Commands in Queues: Query: %li:", pACB->QueryCnt); + for (pcmd = pACB->pQueryHead; pcmd; pcmd = pcmd->next) + SPRINTF (" %li", pcmd->pid); + if (timer_pending(&pACB->Waiting_Timer)) SPRINTF ("Waiting queue timer running\n"); + else SPRINTF ("\n"); + pDCB = pACB->pLinkDCB; + + for (dev = 0; dev < pACB->DCBCnt; dev++) + { + PSRB pSRB; + if (pDCB->WaitSRBCnt) + SPRINTF ("DCB (%02i-%i): Waiting: %i:", pDCB->TargetID, pDCB->TargetLUN, + pDCB->WaitSRBCnt); + for (pSRB = pDCB->pWaitingSRB; pSRB; pSRB = pSRB->pNextSRB) + SPRINTF(" %li", pSRB->pcmd->pid); + if (pDCB->GoingSRBCnt) + SPRINTF ("\nDCB (%02i-%i): Going : %i:", pDCB->TargetID, pDCB->TargetLUN, + pDCB->GoingSRBCnt); + for (pSRB = pDCB->pGoingSRB; pSRB; pSRB = pSRB->pNextSRB) +#if 0 //def DC390_DEBUGTRACE + SPRINTF(" %s\n ", pSRB->debugtrace); +#else + SPRINTF(" %li", pSRB->pcmd->pid); +#endif + if (pDCB->WaitSRBCnt || pDCB->GoingSRBCnt) SPRINTF ("\n"); + pDCB = pDCB->pNextDCB; + } + +#ifdef DC390_DEBUGDCB + SPRINTF ("DCB list for ACB %p:\n", pACB); + pDCB = pACB->pLinkDCB; + SPRINTF ("%p", pDCB); + for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB=pDCB->pNextDCB) + SPRINTF ("->%p", pDCB->pNextDCB); + SPRINTF("\n"); +#endif + DC390_UNLOCK_ACB; *start = buffer + offset; @@ -2528,13 +2996,14 @@ printk(KERN_INFO "DC390: shutdown\n"); - pACB->ACBFlag = RESET_DONE; + pACB->ACBFlag = RESET_DEV; bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; DC390_write8 (CtrlReg1, bval); /* disable interrupt */ if (pACB->Gmode2 & RST_SCSI_BUS) dc390_ResetSCSIBus (pACB); + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); return( 0 ); } @@ -2548,41 +3017,30 @@ do { nDCB = pDCB->pNextDCB; - DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) - kfree (pDCB); + DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): %p\n",\ + pDCB->TargetID, pDCB->TargetLUN, pDCB);) + //kfree (pDCB); + dc390_remove_dev (pACB, pDCB); pDCB = nDCB; - } while (pDCB && pDCB != pACB->pLinkDCB); + } while (pDCB && pACB->pLinkDCB); }; -int DC390_release(struct Scsi_Host *host) +int DC390_release (struct Scsi_Host *host) { - int irq_count; - PACB pACB; DC390_AFLAGS DC390_IFLAGS -#if USE_SPINLOCKS > 1 PACB pACB = (PACB)(host->hostdata); -#endif DC390_LOCK_IO; DC390_LOCK_ACB; + /* TO DO: We should check for outstanding commands first. */ dc390_shutdown (host); if (host->irq != IRQ_NONE) { - for (irq_count = 0, pACB = dc390_pACB_start; - pACB; pACB = pACB->pNextACB) - { - if ( pACB->IRQLevel == host->irq ) - ++irq_count; - } - if (irq_count == 1) - { - DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);) - free_irq(host->irq,NULL); - } + DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);) + free_irq (host->irq, pACB); } release_region(host->io_port,host->n_io_port); @@ -2591,7 +3049,12 @@ DC390_UNLOCK_IO; return( 1 ); } +#endif /* def MODULE */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99) +static Scsi_Host_Template driver_template = DC390_T; +#include "scsi_module.c" +#elif defined(MODULE) Scsi_Host_Template driver_template = DC390_T; #include "scsi_module.c" -#endif /* def MODULE */ +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h --- v2.2.18/drivers/scsi/tmscsim.h Sun Mar 25 11:13:02 2001 +++ linux/drivers/scsi/tmscsim.h Sun Mar 25 11:37:36 2001 @@ -3,33 +3,47 @@ ;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter * ;* Device Driver * ;***********************************************************************/ -/* $Id: tmscsim.h,v 2.4 1998/12/25 17:33:27 garloff Exp $ */ +/* $Id: tmscsim.h,v 2.15.2.3 2000/11/17 20:52:27 garloff Exp $ */ #ifndef _TMSCSIM_H #define _TMSCSIM_H +#include +#include +/* 2.0 compat */ +#if defined(__SMP__) && !defined(CONFIG_SMP) +# if LINUX_VERSION_CODE < KERNEL_VERSION (2,2,0) +# define CONFIG_SMP +# else +# error __SMP__ defined but not CONFIG_SMP +# endif +#endif + + #define IRQ_NONE 255 #define MAX_ADAPTER_NUM 4 -#define MAX_SG_LIST_BUF 16 -#define MAX_CMD_PER_LUN 8 -#define MAX_CMD_QUEUE 2*MAX_CMD_PER_LUN+1 +#define MAX_SG_LIST_BUF 16 /* Not used */ +#define MAX_CMD_PER_LUN 32 +#define MAX_CMD_QUEUE MAX_CMD_PER_LUN+MAX_CMD_PER_LUN/2+1 #define MAX_SCSI_ID 8 #define MAX_SRB_CNT MAX_CMD_QUEUE+1 /* Max number of started commands */ -#define END_SCAN 2 #define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ -typedef unsigned char UCHAR; -typedef unsigned short USHORT; -typedef unsigned long ULONG; -typedef unsigned int UINT; +#define END_SCAN 2 + +typedef u8 UCHAR; /* 8 bits */ +typedef u16 USHORT; /* 16 bits */ +typedef u32 UINT; /* 32 bits */ +typedef unsigned long ULONG; /* 32/64 bits */ typedef UCHAR *PUCHAR; typedef USHORT *PUSHORT; +typedef UINT *PUINT; typedef ULONG *PULONG; -typedef Scsi_Host_Template *PSHT; -typedef struct Scsi_Host *PSH; +typedef Scsi_Host_Template *PSHT; +typedef struct Scsi_Host *PSH; typedef Scsi_Device *PSCSIDEV; typedef Scsi_Cmnd *PSCSICMD; typedef void *PVOID; @@ -72,48 +86,49 @@ */ struct _SRB { -UCHAR CmdBlock[12]; +//UCHAR CmdBlock[12]; struct _SRB *pNextSRB; struct _DCB *pSRBDCB; PSCSICMD pcmd; PSGL pSegmentList; -ULONG Segment0[2]; -ULONG Segment1[2]; +/* 0x10: */ +SGL Segmentx; /* make a one entry of S/G list table */ -/* 0x2c:*/ -ULONG TotalXferredLen; +/* 0x1c: */ ULONG SGBusAddr; /*;a segment starting address as seen by AM53C974A*/ ULONG SGToBeXferLen; /*; to be xfer length */ -ULONG SRBState; - -/* 0x3c: */ -UCHAR MsgInBuf[6]; -UCHAR MsgOutBuf[6]; - -/* 0x48: */ -SGL Segmentx; /* make a one entry of S/G list table */ - -UCHAR ScsiCmdLen; -UCHAR ScsiPhase; +ULONG TotalXferredLen; +ULONG SavedTotXLen; +UINT SRBState; +/* 0x30: */ +UCHAR SRBStatus; +UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ + /*; b4-settimeout,b5-Residual valid */ UCHAR AdaptStatus; UCHAR TargetStatus; -/* 0x58: */ +UCHAR ScsiPhase; +UCHAR TagNumber; +UCHAR SGIndex; +UCHAR SGcount; + +/* 0x38: */ UCHAR MsgCnt; UCHAR EndMessage; UCHAR RetryCnt; -UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ - /*; b4-settimeout,b5-Residual valid */ -UCHAR TagNumber; -UCHAR SGcount; -UCHAR SGIndex; -UCHAR SRBStatus; - //UCHAR IORBFlag; /*;81h-Reset, 2-retry */ +UCHAR SavedSGCount; + +ULONG Saved_Ptr; + +/* 0x40: */ +UCHAR MsgInBuf[6]; +UCHAR MsgOutBuf[6]; -/* 0x60: */ +//UCHAR IORBFlag; /*;81h-Reset, 2-retry */ +/* 0x4c: */ }; @@ -129,48 +144,47 @@ struct _DCB *pNextDCB; struct _ACB *pDCBACB; -PSCSICMD pQIORBhead; -PSCSICMD pQIORBtail; -PSCSICMD AboIORBhead; -PSCSICMD AboIORBtail; -ULONG QIORBCnt; -ULONG AboIORBcnt; +/* Aborted Commands */ +//PSCSICMD AboIORBhead; +//PSCSICMD AboIORBtail; +//ULONG AboIORBcnt; -/* 0x20: */ +/* 0x08: */ +/* Queued SRBs */ PSRB pWaitingSRB; PSRB pWaitLast; PSRB pGoingSRB; PSRB pGoingLast; PSRB pActiveSRB; +UCHAR WaitSRBCnt; /* Not used */ UCHAR GoingSRBCnt; -UCHAR WaitSRBCnt; /* ??? */ + UCHAR DevType; UCHAR MaxCommand; -/* 0x38: */ -ULONG TagMask; +/* 0x20: */ +UINT TagMask; -UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */ -UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */ +UCHAR TargetID; /*; SCSI Target ID (SCSI Only) */ +UCHAR TargetLUN; /*; SCSI Log. Unit (SCSI Only) */ UCHAR DevMode; -UCHAR IdentifyMsg; +UCHAR DCBFlag; UCHAR CtrlR1; UCHAR CtrlR3; UCHAR CtrlR4; +UCHAR Inquiry7; -UCHAR DCBFlag; - -/* 0x44: */ +/* 0x2c: */ UCHAR SyncMode; /*; 0:async mode */ UCHAR NegoPeriod; /*;for nego. */ UCHAR SyncPeriod; /*;for reg. */ UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */ -/* 0x48:*/ +/* 0x30:*/ //UCHAR InqDataBuf[8]; //UCHAR CapacityBuf[8]; -/* 0x58: */ +///* 0x40: */ }; typedef struct _DCB DC390_DCB, *PDCB; @@ -201,16 +215,24 @@ PDCB pLinkDCB; PDCB pLastDCB; PDCB pDCBRunRobin; + PDCB pActiveDCB; PSRB pFreeSRB; PSRB pTmpSRB; /* 0x2c: */ +ULONG QueryCnt; +PSCSICMD pQueryHead; +PSCSICMD pQueryTail; +/* 0x38: */ UCHAR msgin123[4]; UCHAR DCBmap[MAX_SCSI_ID]; +UCHAR Connected; +UCHAR pad; -#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0) +/* 0x3c: */ +#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0) spinlock_t lock; #endif UCHAR sel_timeout; @@ -220,18 +242,20 @@ UCHAR Ignore_IRQ; /* Not used */ PDEVDECL1; /* Pointer to PCI cfg. space */ -/* 0x40/0x3c: */ +/* 0x4c/0x48: */ ULONG Cmds; -ULONG CmdInQ; -ULONG CmdOutOfSRB; -ULONG SelLost; - +UINT SelLost; +UINT SelConn; +UINT CmdInQ; +UINT CmdOutOfSRB; -/* 0x50/0x4c: */ +/* 0x60/0x5c: */ +struct timer_list Waiting_Timer; +/* 0x74/0x70: */ DC390_SRB TmpSRB; -/* 0xb4/0xb0: */ -DC390_SRB SRB_array[MAX_SRB_CNT]; /* 18 SRBs */ -/* 0x7bc/0x7b8: */ +/* 0xd8/0xd4: */ +DC390_SRB SRB_array[MAX_SRB_CNT]; /* 50 SRBs */ +/* 0xfb0/0xfac: */ }; typedef struct _ACB DC390_ACB, *PACB; @@ -339,21 +363,29 @@ #define H_BAD_CCB_OR_SG 0x1A #define H_ABORT 0x0FF -/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */ -#define SCSI_STAT_GOOD 0x0 /*; Good status */ -#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */ -#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */ -#define SCSI_STAT_BUSY 0x08 /*; Target busy status */ -#define SCSI_STAT_INTER 0x10 /*; Intermediate status */ -#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */ -#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */ -#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */ -#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */ +/*; SCSI Status byte codes*/ +/* The values defined in include/scsi/scsi.h, to be shifted << 1 */ #define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */ #define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */ #define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */ +/* cmd->result */ +#define RES_TARGET 0x000000FF /* Target State */ +#define RES_TARGET_LNX STATUS_MASK /* Only official ... */ +#define RES_ENDMSG 0x0000FF00 /* End Message */ +#define RES_DID 0x00FF0000 /* DID_ codes */ +#define RES_DRV 0xFF000000 /* DRIVER_ codes */ + +#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)) +#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1) + +#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); } +#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } +#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; } +#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; } +#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; } + /*;---Sync_Mode */ #define SYNC_DISABLE 0 #define SYNC_ENABLE BIT0 @@ -375,31 +407,8 @@ #define SCSI_MSG_OUT 6 #define SCSI_MSG_IN 7 -/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ -#define MSG_COMPLETE 0x00 -#define MSG_EXTENDED 0x01 -#define MSG_SAVE_PTR 0x02 -#define MSG_RESTORE_PTR 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_INITIATOR_ERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT_ 0x07 -#define MSG_NOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define MSG_LINK_CMD_COMPL 0x0A -#define MSG_LINK_CMD_COMPL_FLG 0x0B -#define MSG_BUS_RESET 0x0C -#define MSG_ABORT_TAG 0x0D -#define MSG_SIMPLE_QTAG 0x20 -#define MSG_HEAD_QTAG 0x21 -#define MSG_ORDER_QTAG 0x22 -#define MSG_IDENTIFY 0x80 -#define MSG_HOST_ID 0x0C0 - -/* cmd->result */ -#define STATUS_MASK_ 0xFF -#define MSG_MASK 0xFF00 -#define RETURN_MASK 0xFF0000 +/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ /* One is missing ! */ +#define ABORT_TAG 0x0d /* ** Inquiry Data format @@ -439,8 +448,12 @@ /* Peripheral Device Type definitions */ /* see include/scsi/scsi.h for the rest */ -#define TYPE_PRINTER 0x02 /* Printer device */ -#define TYPE_COMM 0x09 /* Communications device */ +#ifndef TYPE_PRINTER +# define TYPE_PRINTER 0x02 /* Printer device */ +#endif +#ifndef TYPE_COMM +# define TYPE_COMM 0x09 /* Communications device */ +#endif /* ** Inquiry flag definitions (Inq data byte 7) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c --- v2.2.18/drivers/scsi/ultrastor.c Sun Mar 25 11:13:00 2001 +++ linux/drivers/scsi/ultrastor.c Sun Mar 25 11:37:36 2001 @@ -882,9 +882,8 @@ (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1)) { int flags; - save_flags(flags); printk("Ux4F: abort while completed command pending\n"); - restore_flags(flags); + save_flags(flags); cli(); ultrastor_interrupt(0, NULL, NULL); restore_flags(flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.2.18/drivers/sound/Config.in Sun Mar 25 11:28:30 2001 +++ linux/drivers/sound/Config.in Sun Mar 25 11:37:37 2001 @@ -35,6 +35,7 @@ fi dep_tristate 'ESS Maestro' CONFIG_SOUND_MAESTRO $CONFIG_SOUND +dep_tristate 'ESS Maestro3' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND dep_tristate 'ESS Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND dep_tristate 'Intel ICH (810, 820, 440MX...)' CONFIG_SOUND_ICH $CONFIG_SOUND @@ -311,9 +312,9 @@ fi dep_tristate 'NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS - dep_tristate 'Yamaha PCI legacy mode support' CONFIG_SOUND_YMPCI $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_YMPCI" = "n" ]; then - dep_tristate 'Yamaha PCI native mode support (EXPERIMENTAL)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS + dep_tristate 'Yamaha PCI native mode support' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_YMFPCI" != "n" ]; then + bool ' Yamaha PCI legacy ports support' CONFIG_SOUND_YMFPCI_LEGACY fi # Additional low level drivers. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.2.18/drivers/sound/Makefile Sun Mar 25 11:28:30 2001 +++ linux/drivers/sound/Makefile Sun Mar 25 11:37:37 2001 @@ -93,11 +93,15 @@ obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o -obj-$(CONFIG_SOUND_MAESTRO) += maestro.o +obj-$(CONFIG_SOUND_MAESTRO) += maestro.o ac97_codec.o +obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o +ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y) + obj-$(CONFIG_SOUND_YMFPCI) += opl3.o uart401.o +endif ifeq ($(CONFIG_SOUND_EMU10K1),y) obj-y += emu10k1/emu10k1.o @@ -126,7 +130,6 @@ wavefront-objs := wavfront.o wf_midi.o yss225.o nm256-objs := nm256_audio.o ac97.o via82cxxx-objs := via82cxxx_audio.o ac97.o -ymfsb-objs := ymf_sb.o ac97.o # Extract lists of the multi-part drivers. @@ -217,9 +220,6 @@ via82cxxx.o: $(via82cxxx-objs) $(LD) -r -o $@ $(via82cxxx-objs) - -ymfsb.o: $(ymfsb-objs) - $(LD) -r -o $@ $(ymfsb-objs) # Firmware files that need translation # diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c --- v2.2.18/drivers/sound/cs46xx.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/cs46xx.c Sun Mar 25 11:37:37 2001 @@ -2499,7 +2499,7 @@ {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack}, {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack}, {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL}, - {0, 0, "Card without SSID set", NULL, NULL }, + {0, 0, "Card without SSID set", amp_none, NULL }, {0, 0, NULL, NULL, NULL} }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c --- v2.2.18/drivers/sound/emu10k1/main.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/emu10k1/main.c Sun Mar 25 11:37:37 2001 @@ -784,10 +784,3 @@ module_init(emu10k1_init_module); module_exit(emu10k1_cleanup_module); - -#ifndef MODULE -int __init init_emu10k1(void) -{ - return emu10k1_init_module(); -} -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.2.18/drivers/sound/es1370.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/es1370.c Sun Mar 25 11:37:37 2001 @@ -114,6 +114,11 @@ * 03.09.1999 0.30 change read semantics for MIDI to match * OSS more closely; remove possible wakeup race * 28.10.1999 0.31 More waitqueue races fixed + * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this + * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.35 More dma buffer initializations, patch from + * Tjeerd Mulder * * some important things missing in Ensoniq documentation: * @@ -858,7 +863,8 @@ VALIDATE_STATE(s); if (cmd == SOUND_MIXER_PRIVATE1) { /* enable/disable/query mixer preamp */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { s->mix.micpreamp = !!val; wrcodec(s, 0x19, s->mix.micpreamp); @@ -867,7 +873,8 @@ } if (cmd == SOUND_MIXER_PRIVATE2) { /* enable/disable/query use of linein as second lineout */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { spin_lock_irqsave(&s->lock, flags); if (val) @@ -881,7 +888,8 @@ } if (cmd == SOUND_MIXER_PRIVATE3) { /* enable/disable/query microphone impedance setting */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != -1) { spin_lock_irqsave(&s->lock, flags); if (val) @@ -957,12 +965,14 @@ switch (_IOC_NR(cmd)) { case SOUND_MIXER_IMIX: - get_user_ret(s->mix.imix, (int *)arg, -EFAULT); + if (get_user(s->mix.imix, (int *)arg)) + return -EFAULT; set_recsrc(s, s->mix.recsrc); return 0; case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; set_recsrc(s, val); return 0; @@ -970,7 +980,8 @@ i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; l = val & 0xff; if (l > 100) l = 100; @@ -1354,6 +1365,7 @@ unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, mapped, ret; VALIDATE_STATE(s); @@ -1388,7 +1400,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE)) return -EINVAL; @@ -1407,7 +1420,8 @@ return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; @@ -1433,7 +1447,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1464,7 +1479,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1504,7 +1520,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) @@ -1526,12 +1543,15 @@ case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0) + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; - abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac2.dmasize - count; abinfo.fragstotal = s->dma_dac2.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1540,12 +1560,15 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0) + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; + count = s->dma_adc.count; + if (count < 0) + count = 0; + abinfo.bytes = count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1558,19 +1581,28 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); - val = s->dma_dac2.count; + count = s->dma_dac2.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + count = s->dma_adc.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1580,10 +1612,15 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -1601,7 +1638,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1628,7 +1666,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -1878,6 +1917,7 @@ unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; unsigned ctrl; int val, ret; @@ -1902,7 +1942,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -1917,7 +1958,8 @@ return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; stop_dac1(s); s->dma_dac1.ready = 0; spin_lock_irqsave(&s->lock, flags); @@ -1930,7 +1972,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (s->dma_dac1.mapped) return -EINVAL; @@ -1950,7 +1993,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -1971,7 +2015,8 @@ return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; @@ -1981,12 +2026,15 @@ return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); abinfo.fragsize = s->dma_dac1.fragsize; - abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac1.dmasize - count; abinfo.fragstotal = s->dma_dac1.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1997,19 +2045,26 @@ return 0; case SNDCTL_DSP_GETODELAY: + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); - val = s->dma_dac1.count; + count = s->dma_dac1.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -2022,7 +2077,8 @@ return put_user(s->dma_dac1.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; s->dma_dac1.ossfragshift = val & 0xffff; s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_dac1.ossfragshift < 4) @@ -2036,7 +2092,8 @@ case SNDCTL_DSP_SUBDIVIDE: if (s->dma_dac1.subdivision) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; s->dma_dac1.subdivision = val; @@ -2463,7 +2520,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.31 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.35 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->base_address[0] == 0 || diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.2.18/drivers/sound/es1371.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/es1371.c Sun Mar 25 11:37:37 2001 @@ -96,6 +96,12 @@ * detect ES137x chip and derivatives. * 05.01.2000 0.22 Should now work with rev7 boards; patch by * Eric Lemar, elemar@cs.washington.edu + * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this + * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot + * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.28 More dma buffer initializations, patch from + * Tjeerd Mulder */ /*****************************************************************************/ @@ -1937,6 +1943,7 @@ unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, mapped, ret; VALIDATE_STATE(s); @@ -1971,7 +1978,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1987,7 +1995,8 @@ return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; @@ -2013,7 +2022,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -2044,7 +2054,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -2084,7 +2095,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) @@ -2106,12 +2118,15 @@ case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0) + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_dac2.fragsize; - abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac2.dmasize - count; abinfo.fragstotal = s->dma_dac2.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -2120,12 +2135,15 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0) + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; + count = s->dma_adc.count; + if (count < 0) + count = 0; + abinfo.bytes = count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -2138,19 +2156,28 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); - val = s->dma_dac2.count; + count = s->dma_dac2.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + count = s->dma_adc.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -2160,10 +2187,15 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; + count = s->dma_dac2.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -2181,7 +2213,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -2208,7 +2241,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -2458,6 +2492,7 @@ unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, ret; VALIDATE_STATE(s); @@ -2481,7 +2516,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -2490,7 +2526,8 @@ return put_user(s->dac1rate, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; stop_dac1(s); s->dma_dac1.ready = 0; spin_lock_irqsave(&s->lock, flags); @@ -2503,7 +2540,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -2521,7 +2559,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { stop_dac1(s); s->dma_dac1.ready = 0; @@ -2542,7 +2581,8 @@ return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) return ret; @@ -2552,12 +2592,15 @@ return 0; case SNDCTL_DSP_GETOSPACE: - if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0) + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); abinfo.fragsize = s->dma_dac1.fragsize; - abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac1.dmasize - count; abinfo.fragstotal = s->dma_dac1.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -2568,19 +2611,26 @@ return 0; case SNDCTL_DSP_GETODELAY: + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); - val = s->dma_dac1.count; + count = s->dma_dac1.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; + count = s->dma_dac1.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -2593,7 +2643,8 @@ return put_user(s->dma_dac1.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; s->dma_dac1.ossfragshift = val & 0xffff; s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_dac1.ossfragshift < 4) @@ -2607,7 +2658,8 @@ case SNDCTL_DSP_SUBDIVIDE: if (s->dma_dac1.subdivision) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; s->dma_dac1.subdivision = val; @@ -3261,7 +3313,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.22 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.28 time " __TIME__ " " __DATE__ "\n"); for (pcidev = pci_devices; pcidev && index < NR_DEVICE; pcidev = pcidev->next) { if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) { if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 && diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.2.18/drivers/sound/esssolo1.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/esssolo1.c Sun Mar 25 11:37:37 2001 @@ -63,7 +63,12 @@ * 28.10.1999 0.10 More waitqueue races fixed * 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M) * Disabling recording on Alpha - * + * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this + * Integrated (aka redid 8-)) APM support patch by Zach Brown + * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.17 More dma buffer initializations, patch from + * Tjeerd Mulder */ /*****************************************************************************/ @@ -1276,7 +1281,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { stop_adc(s); stop_dac(s); @@ -1303,7 +1309,8 @@ return put_user(s->rate, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; stop_adc(s); stop_dac(s); s->dma_adc.ready = s->dma_dac.ready = 0; @@ -1313,7 +1320,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { stop_adc(s); stop_dac(s); @@ -1328,7 +1336,8 @@ return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { stop_adc(s); stop_dac(s); @@ -1354,7 +1363,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) @@ -1378,7 +1388,7 @@ case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0) + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); @@ -1395,7 +1405,7 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0) + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); @@ -1413,6 +1423,8 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); count = s->dma_dac.count; @@ -1424,13 +1436,12 @@ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; + if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_dac.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1440,10 +1451,15 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); solo1_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + count = s->dma_dac.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; @@ -1467,7 +1483,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1494,7 +1511,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -2170,7 +2188,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.11 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.17 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) { if (pcidev->base_address[0] == 0 || diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c --- v2.2.18/drivers/sound/maestro3.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/sound/maestro3.c Sun Mar 25 11:37:37 2001 @@ -0,0 +1,3033 @@ +/***************************************************************************** + * + * ESS Maestro3/Allegro driver for Linux 2.2.x + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * (c) Copyright 2000 Zach Brown + * + * I need to thank many people for helping make this driver happen. + * As always, Eric Brombaugh was a hacking machine and killed many bugs + * that I was too dumb to notice. Howard Kim at ESS provided reference boards + * and as much docs as he could. Todd and Mick at Dell tested snapshots on + * an army of laptops. msw and deviant at Red Hat also humoured me by hanging + * their laptops every few hours in the name of science. + * + * Shouts go out to Mike "DJ XPCom" Ang. + * + * History + * v0.51 - Dec 31 2000 - Zach Brown + * fix up incredibly broken open/release resource management + * duh. fix record format setting. + * add SMP locking and cleanup formatting here and there + * v0.50 - Dec 16 2000 - Zach Brown + * use native ac97_codec + * pull out most SILLY_ stuff + * align instance allocation so record works + * fix up PCI IDs.. + * v0.02 - Nov 04 2000 - Zach Brown + * changed clocking setup for m3, slowdown fixed. + * codec reset is hopefully reliable now + * rudimentary apm/power management makes suspend/resume work + * v0.01 - Oct 31 2000 - Zach Brown + * first release + * v0.00 - Sep 09 2000 - Zach Brown + * first pass derivation from maestro.c + * + * TODO + * no beep on init (mute) + * resetup msrc data memory if freq changes? + * clean up driver in general, 2.2/2.3 junk, etc. + * + * --- + * + * Allow me to ramble a bit about the m3 architecture. The core of the + * chip is the 'assp', the custom ESS dsp that runs the show. It has + * a small amount of code and data ram. ESS drops binary dsp code images + * on our heads, but we don't get to see specs on the dsp. + * + * The constant piece of code on the dsp is the 'kernel'. It also has a + * chunk of the dsp memory that is statically set aside for its control + * info. This is the KDATA defines in maestro3.h. Part of its core + * data is a list of code addresses that point to the pieces of DSP code + * that it should walk through in its loop. These other pieces of code + * do the real work. The kernel presumably jumps into each of them in turn. + * These code images tend to have their own data area, and one can have + * multiple data areas representing different states for each of the 'client + * instance' code portions. There is generaly a list in the kernel data + * that points to the data instances for a given piece of code. + * + * We've only been given the binary image for the 'minisrc', mini sample + * rate converter. This is rather annoying because it limits the work + * we can do on the dsp, but it also greatly simplifies the job of managing + * dsp data memory for the code and data for our playing streams :). We + * statically allocate the minisrc code into a region we 'know' to be free + * based on the map of the binary kernel image we're loading. We also + * statically allocate the data areas for the maximum number of pcm streams + * we can be dealing with. This max is set by the length of the static list + * in the kernel data that records the number of minisrc data regions we + * can have. Thats right, all software dsp mixing with static code list + * limits. Rock. + * + * How sound goes in and out is still a relative mystery. It appears + * that the dsp has the ability to get input and output through various + * 'connections'. To do IO from or to a connection, you put the address + * of the minisrc client area in the static kernel data lists for that + * input or output. so for pcm -> dsp -> mixer, we put the minisrc data + * instance in the DMA list and also in the list for the mixer. I guess + * it Just Knows which is in/out, and we give some dma control info that + * helps. There are all sorts of cool inputs/outputs that it seems we can't + * use without dsp code images that know how to use them. + * + * So at init time we preload all the memory allocation stuff and set some + * system wide parameters. When we really get a sound to play we build + * up its minisrc header (stream parameters, buffer addresses, input/output + * settings). Then we throw its header on the various lists. We also + * tickle some KDATA settings that ask the assp to raise clock interrupts + * and do some amount of software mixing before handing data to the ac97. + * + * Sorry for the vague details. Feel free to ask Eric or myself if you + * happen to be trying to use this driver elsewhere. Please accept my + * apologies for the quality of the OSS support code, its passed through + * too many hands now and desperately wants to be rethought. + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + /* + * apologies for old intra-2.2 and + * 2.2->2.4 compat cruft.. it will + * die someday. + */ +#ifndef wait_queue_head_t + #define wait_queue_head_t struct wait_queue * +#endif +#ifndef DECLARE_WAITQUEUE + #define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL} +#endif +#ifndef init_waitqueue_head + #define init_waitqueue_head init_waitqueue +#endif + +#define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK) +#define SILLY_INIT_SEM(SEM) SEM=MUTEX; +#define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC) +#define SILLY_OFFSET(VMA) ((VMA)->vm_offset) + +#include + +#include "maestro3.h" + +#define M_DEBUG 1 + +#define DRIVER_VERSION "0.51" +#define PFX "maestro3: " + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#endif + +#define M3_STATE_MAGIC 0x734d724d +#define M3_CARD_MAGIC 0x646e6f50 + +#define ESS_FMT_STEREO 0x01 +#define ESS_FMT_16BIT 0x02 +#define ESS_FMT_MASK 0x03 +#define ESS_DAC_SHIFT 0 +#define ESS_ADC_SHIFT 4 + +#define DAC_RUNNING 1 +#define ADC_RUNNING 2 + +#define SND_DEV_DSP16 5 + + +#ifdef M_DEBUG +static int debug=0; +static int global_dsp_speed = 49; +#define DPMOD 1 /* per module load */ +#define DPSTR 2 /* per 'stream' */ +#define DPSYS 3 /* per syscall */ +#define DPCRAP 4 /* stuff the user shouldn't see unless they're really debuggin */ +#define DPINT 5 /* per interrupt, LOTS */ +#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);} +#else +#define DPRINTK(x) +#endif + +#ifdef CONFIG_APM +#include +static int m3_apm_callback(apm_event_t ae); +static int in_suspend=0; +wait_queue_head_t suspend_queue; +static void check_suspend(void); +#else +#define check_suspend(args...) +#define in_suspend 0 +#endif + +struct m3_list { + int curlen; + int mem_addr; + int max; +}; + +int external_amp = 1; +static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf); + +struct notifier_block maestro_nb = {maestro_notifier, NULL, 0}; + +struct ess_state { + unsigned int magic; + struct ess_card *card; + unsigned char fmt, enable; + + spinlock_t lock; + + int index; + + struct semaphore open_sem; + wait_queue_head_t open_wait; + mode_t open_mode; + + int dev_audio; + + struct assp_instance { + u16 code, data; + } dac_inst, adc_inst; + + /* should be in dmabuf */ + unsigned int rateadc, ratedac; + + struct dmabuf { + void *rawbuf; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + unsigned hwptr, swptr; + unsigned total_bytes; + int count; + unsigned error; /* over/underrun */ + wait_queue_head_t wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + /* new in m3 */ + int mixer_index, dma_index, msrc_index, adc1_index; + int in_lists; + + } dma_dac, dma_adc; +}; + +struct ess_card { + unsigned int magic; + + struct ess_card *next; + + struct ac97_codec *ac97; + spinlock_t ac97_lock; + + int card_type; + +#define NR_DSPS 1 +#define MAX_DSPS NR_DSPS + struct ess_state channels[MAX_DSPS]; + + spinlock_t lock; + + /* hardware resources */ + struct pci_dev *pcidev; + u32 iobase; + u32 irq; + + int dacs_active; + + int timer_users; + + struct m3_list msrc_list, + mixer_list, + adc1_list, + dma_list; + + /* for storing reset state..*/ + u8 reset_state; + +#ifdef CONFIG_APM + u16 *suspend_dsp_mem; +#endif +}; + +/* + * an arbitrary volume we set the internal + * volume settings to so that the ac97 volume + * range is a little less insane. 0x7fff is + * max. + */ +#define ARB_VOLUME ( 0x6800 ) + +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +enum { + ESS_ALLEGRO, + ESS_MAESTRO3, + /* hardware strapping */ + ESS_MAESTRO3HW +}; + +static struct card_type { + int pci_id; + int type; + char *name; +} m3_card_types[] = { + {0x1988, ESS_ALLEGRO, "Allegro"}, + {0x1998, ESS_MAESTRO3, "Maestro3(i)"}, + {0x199a, ESS_MAESTRO3, "Maestro3(i)hw"}, +}; +#define NUM_CARD_TYPES ( sizeof(m3_card_types) / sizeof(m3_card_types[0]) ) + +static unsigned +ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + +static struct ess_card *devs = NULL; + +static void m3_outw(struct ess_card *card, + u16 value, unsigned long reg) +{ + check_suspend(); + outw(value, card->iobase + reg); +} + +static u16 m3_inw(struct ess_card *card, unsigned long reg) +{ + check_suspend(); + return inw(card->iobase + reg); +} +static void m3_outb(struct ess_card *card, + u8 value, unsigned long reg) +{ + check_suspend(); + outb(value, card->iobase + reg); +} +static u8 m3_inb(struct ess_card *card, unsigned long reg) +{ + check_suspend(); + return inb(card->iobase + reg); +} + +/* + * access 16bit words to the code or data regions of the dsp's memory. + * index addresses 16bit words. + */ +static u16 __m3_assp_read(struct ess_card *card, u16 region, u16 index) +{ + m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); + m3_outw(card, index, DSP_PORT_MEMORY_INDEX); + return m3_inw(card, DSP_PORT_MEMORY_DATA); +} +static u16 m3_assp_read(struct ess_card *card, u16 region, u16 index) +{ + unsigned long flags; + u16 ret; + + spin_lock_irqsave(&(card->lock), flags); + ret = __m3_assp_read(card, region, index); + spin_unlock_irqrestore(&(card->lock), flags); + + return ret; +} +static void __m3_assp_write(struct ess_card *card, + u16 region, u16 index, u16 data) +{ + m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); + m3_outw(card, index, DSP_PORT_MEMORY_INDEX); + m3_outw(card, data, DSP_PORT_MEMORY_DATA); +} + +static void m3_assp_write(struct ess_card *card, + u16 region, u16 index, u16 data) +{ + unsigned long flags; + spin_lock_irqsave(&(card->lock), flags); + __m3_assp_write(card, region, index, data); + spin_unlock_irqrestore(&(card->lock), flags); +} + +static void m3_assp_halt(struct ess_card *card) +{ + card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK; + mdelay(10); + m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B); +} + +static void m3_assp_continue(struct ess_card *card) +{ + m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B); +} + +/* + * This makes me sad. the maestro3 has lists + * internally that must be packed.. 0 terminates, + * apparently, or maybe all unused entries have + * to be 0, the lists have static lengths set + * by the binary code images. + */ + +static int m3_add_list(struct ess_card *card, + struct m3_list *list, u16 val) +{ + DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n", + val, list, list->curlen); + + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + list->mem_addr + list->curlen, + val); + + return list->curlen++; + +} + +static void m3_remove_list(struct ess_card *card, + struct m3_list *list, int index) +{ + u16 val; + int lastindex = list->curlen - 1; + + DPRINTK(DPSTR, "removing ind %d from list 0x%p\n", + index, list); + + if(index != lastindex) { + val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, + list->mem_addr + lastindex); + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + list->mem_addr + index, + val); + } + + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + list->mem_addr + lastindex, + 0); + + list->curlen--; +} + +static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data) +{ + int tmp; + + s->fmt = (s->fmt & mask) | data; + + tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK; + + /* write to 'mono' word */ + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1, + (tmp & ESS_FMT_STEREO) ? 0 : 1); + /* write to '8bit' word */ + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2, + (tmp & ESS_FMT_16BIT) ? 0 : 1); + + tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK; + + /* write to 'mono' word */ + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1, + (tmp & ESS_FMT_STEREO) ? 0 : 1); + /* write to '8bit' word */ + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2, + (tmp & ESS_FMT_16BIT) ? 0 : 1); +} + +static void set_dac_rate(struct ess_state *s, unsigned int rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + + s->ratedac = rate; + + freq = ((rate << 15) + 24000 ) / 48000; + if(freq) + freq--; + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_FREQUENCY, + freq); +} + +static void set_adc_rate(struct ess_state *s, unsigned int rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + + s->rateadc = rate; + + freq = ((rate << 15) + 24000 ) / 48000; + if(freq) + freq--; + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_FREQUENCY, + freq); +} + +static void inc_timer_users(struct ess_card *card) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + card->timer_users++; + DPRINTK(DPSYS, "inc timer users now %d\n", + card->timer_users); + if(card->timer_users != 1) + goto out; + + __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_TIMER_COUNT_RELOAD, + 240 ) ; + + __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_TIMER_COUNT_CURRENT, + 240 ) ; + + m3_outw(card, + m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE, + HOST_INT_CTRL); + +out: + spin_unlock_irqrestore(&card->lock, flags); +} + +static void dec_timer_users(struct ess_card *card) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + card->timer_users--; + DPRINTK(DPSYS, "dec timer users now %d\n", + card->timer_users); + if(card->timer_users > 0 ) + goto out; + + __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_TIMER_COUNT_RELOAD, + 0 ) ; + + __m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_TIMER_COUNT_CURRENT, + 0 ) ; + + m3_outw(card, m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE, + HOST_INT_CTRL); +out: + spin_unlock_irqrestore(&card->lock, flags); +} + +/* + * {start,stop}_{adc,dac} should be called + * while holding the 'state' lock and they + * will try to grab the 'card' lock.. + */ +static void stop_adc(struct ess_state *s) +{ + if (! (s->enable & ADC_RUNNING)) + return; + + s->enable &= ~ADC_RUNNING; + dec_timer_users(s->card); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_INSTANCE_READY, 0); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + KDATA_ADC1_REQUEST, 0); +} + +static void stop_dac(struct ess_state *s) +{ + if (! (s->enable & DAC_RUNNING)) + return; + + DPRINTK(DPSYS, "stop_dac()\n"); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_INSTANCE_READY, 0); + + s->enable &= ~DAC_RUNNING; + s->card->dacs_active--; + dec_timer_users(s->card); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + KDATA_MIXER_TASK_NUMBER, + s->card->dacs_active ) ; +} + +static void start_dac(struct ess_state *s) +{ + if( (!s->dma_dac.mapped && s->dma_dac.count < 1) || + !s->dma_dac.ready || + (s->enable & DAC_RUNNING)) + return; + + DPRINTK(DPSYS, "start_dac()\n"); + + s->enable |= DAC_RUNNING; + s->card->dacs_active++; + inc_timer_users(s->card); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_INSTANCE_READY, 1); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + KDATA_MIXER_TASK_NUMBER, + s->card->dacs_active ) ; +} + +static void start_adc(struct ess_state *s) +{ + if ((! s->dma_adc.mapped && + s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) + || !s->dma_adc.ready + || (s->enable & ADC_RUNNING) ) + return; + + DPRINTK(DPSYS, "start_adc()\n"); + + s->enable |= ADC_RUNNING; + inc_timer_users(s->card); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + KDATA_ADC1_REQUEST, 1); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_INSTANCE_READY, 1); +} + +static struct play_vals { + u16 addr, val; +} pv[] = { + {CDATA_LEFT_VOLUME, ARB_VOLUME}, + {CDATA_RIGHT_VOLUME, ARB_VOLUME}, + {SRC3_DIRECTION_OFFSET, 0} , + /* +1, +2 are stereo/16 bit */ + {SRC3_DIRECTION_OFFSET + 3, 0X0000}, /* fraction? */ + {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */ + {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */ + {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */ + {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */ + {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */ + {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */ + {SRC3_DIRECTION_OFFSET + 10, 0X8000}, /* round */ + {SRC3_DIRECTION_OFFSET + 11, 0XFF00}, /* higher bute mark */ + {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */ + {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */ + {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */ + {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */ + {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */ + {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */ + {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */ + {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */ +}; + +static void +ess_play_setup(struct ess_state *s, int mode, u32 rate, void *buffer, int size) +{ + int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2); + int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2); + int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2); + int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1; + struct dmabuf *db = &s->dma_dac; + int i; + + DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n", + mode, rate, buffer, size); + +#define LO(x) ((x) & 0xffff) +#define HI(x) LO((x) >> 16) + + /* host dma buffer pointers */ + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_HOST_SRC_ADDRL, + LO(virt_to_bus(buffer))); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_HOST_SRC_ADDRH, + HI(virt_to_bus(buffer))); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L, + LO(virt_to_bus(buffer) + size)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H, + HI(virt_to_bus(buffer) + size)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_HOST_SRC_CURRENTL, + LO(virt_to_bus(buffer))); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_HOST_SRC_CURRENTH, + HI(virt_to_bus(buffer))); +#undef LO +#undef HI + + /* dsp buffers */ + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_IN_BUF_BEGIN, + dsp_in_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1, + dsp_in_buffer + (dsp_in_size / 2)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_IN_BUF_HEAD, + dsp_in_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_IN_BUF_TAIL, + dsp_in_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_OUT_BUF_BEGIN, + dsp_out_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1, + dsp_out_buffer + (dsp_out_size / 2)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_OUT_BUF_HEAD, + dsp_out_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_OUT_BUF_TAIL, + dsp_out_buffer); + + /* + * some per client initializers + */ + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12, + s->dac_inst.data + 40 + 8); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19, + s->dac_inst.code + MINISRC_COEF_LOC); + + /* enable or disable low pass filter? */ + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22, + s->ratedac > 45000 ? 0xff : 0 ); + + /* tell it which way dma is going? */ + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + CDATA_DMA_CONTROL, + DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); + + /* + * set an armload of static initializers + */ + for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++) + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->dac_inst.data + pv[i].addr, pv[i].val); + + /* + * put us in the lists if we're not already there + */ + + if(db->in_lists == 0) { + + db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, + s->dac_inst.data >> DP_SHIFT_COUNT); + + db->dma_index = m3_add_list(s->card, &s->card->dma_list, + s->dac_inst.data >> DP_SHIFT_COUNT); + + db->mixer_index = m3_add_list(s->card, &s->card->mixer_list, + s->dac_inst.data >> DP_SHIFT_COUNT); + + db->in_lists = 1; + } + + set_dac_rate(s,rate); + start_dac(s); +} + +/* + * Native record driver + */ +static struct rec_vals { + u16 addr, val; +} rv[] = { + {CDATA_LEFT_VOLUME, ARB_VOLUME}, + {CDATA_RIGHT_VOLUME, ARB_VOLUME}, + {SRC3_DIRECTION_OFFSET, 1} , + /* +1, +2 are stereo/16 bit */ + {SRC3_DIRECTION_OFFSET + 3, 0X0000}, /* fraction? */ + {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */ + {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */ + {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */ + {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */ + {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */ + {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */ + {SRC3_DIRECTION_OFFSET + 10, 0X8000}, /* round */ + {SRC3_DIRECTION_OFFSET + 11, 0XFF00}, /* higher bute mark */ + {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */ + {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */ + {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */ + {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */ + {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */ + {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */ + {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */ + {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */ + {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */ + {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */ +}; + +/* + * the buffer passed here must be 32bit aligned + */ +static void +ess_rec_setup(struct ess_state *s, int mode, u32 rate, void *buffer, int size) +{ + int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2); + int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2); + int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2); + int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1; + struct dmabuf *db = &s->dma_adc; + int i; + + DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n", + mode, rate, buffer, size); + +#define LO(x) ((x) & 0xffff) +#define HI(x) LO((x) >> 16) + + /* host dma buffer pointers */ + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_HOST_SRC_ADDRL, + LO(virt_to_bus(buffer))); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_HOST_SRC_ADDRH, + HI(virt_to_bus(buffer))); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L, + LO(virt_to_bus(buffer) + size)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H, + HI(virt_to_bus(buffer) + size)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_HOST_SRC_CURRENTL, + LO(virt_to_bus(buffer))); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_HOST_SRC_CURRENTH, + HI(virt_to_bus(buffer))); +#undef LO +#undef HI + + /* dsp buffers */ + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_IN_BUF_BEGIN, + dsp_in_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1, + dsp_in_buffer + (dsp_in_size / 2)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_IN_BUF_HEAD, + dsp_in_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_IN_BUF_TAIL, + dsp_in_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_OUT_BUF_BEGIN, + dsp_out_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1, + dsp_out_buffer + (dsp_out_size / 2)); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_OUT_BUF_HEAD, + dsp_out_buffer); + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_OUT_BUF_TAIL, + dsp_out_buffer); + + /* + * some per client initializers + */ + + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12, + s->adc_inst.data + 40 + 8); + + /* tell it which way dma is going? */ + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + CDATA_DMA_CONTROL, + DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); + + /* + * set an armload of static initializers + */ + for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) + m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA, + s->adc_inst.data + rv[i].addr, rv[i].val); + + /* + * put us in the lists if we're not already there + */ + + if(db->in_lists == 0) { + + db->adc1_index = m3_add_list(s->card, &s->card->adc1_list, + s->adc_inst.data >> DP_SHIFT_COUNT); + + db->dma_index = m3_add_list(s->card, &s->card->dma_list, + s->adc_inst.data >> DP_SHIFT_COUNT); + + db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, + s->adc_inst.data >> DP_SHIFT_COUNT); + + db->in_lists = 1; + } + + set_fmt(s, ~0, 0); + set_adc_rate(s,rate); + start_adc(s); +} +/* --------------------------------------------------------------------- */ + +static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count) +{ + DPRINTK(DPINT,"set_dmaa??\n"); +} + +static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count) +{ + DPRINTK(DPINT,"set_dmac??\n"); +} + +u32 get_dma_pos(struct ess_card *card, + int instance_addr) +{ + u16 hi = 0, lo = 0; + int retry = 10; + + /* + * try and get a valid answer + */ + while(retry--) { + hi = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, + instance_addr + CDATA_HOST_SRC_CURRENTH); + + lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA, + instance_addr + CDATA_HOST_SRC_CURRENTL); + + if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA, + instance_addr + CDATA_HOST_SRC_CURRENTH)) + break; + } + return lo | (hi<<16); +} + +u32 get_dmaa(struct ess_state *s) +{ + u32 offset; + + offset = get_dma_pos(s->card, s->dac_inst.data) - + virt_to_bus(s->dma_dac.rawbuf); + + DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset); + + return offset; +} + +u32 get_dmac(struct ess_state *s) +{ + u32 offset; + + offset = get_dma_pos(s->card, s->adc_inst.data) - + virt_to_bus(s->dma_adc.rawbuf); + + DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset); + + return offset; + +} + +static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static int +prog_dmabuf(struct ess_state *s, unsigned rec) +{ + struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; + unsigned rate = rec ? s->rateadc : s->ratedac; + unsigned bytepersec; + unsigned bufs; + unsigned char fmt; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + + fmt = s->fmt; + if (rec) { + stop_adc(s); + fmt >>= ESS_ADC_SHIFT; + } else { + stop_dac(s); + fmt >>= ESS_DAC_SHIFT; + } + fmt &= ESS_FMT_MASK; + + db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; + + bytepersec = rate << sample_shift[fmt]; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + if ((1000 << db->ossfragshift) < bytepersec) + db->fragshift = ld2(bytepersec/1000); + else + db->fragshift = db->ossfragshift; + } else { + db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); + if (db->fragshift < 3) + db->fragshift = 3; + } + db->numfrag = bufs >> db->fragshift; + while (db->numfrag < 4 && db->fragshift > 3) { + db->fragshift--; + db->numfrag = bufs >> db->fragshift; + } + db->fragsize = 1 << db->fragshift; + if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) + db->numfrag = db->ossmaxfrags; + db->fragsamples = db->fragsize >> sample_shift[fmt]; + db->dmasize = db->numfrag << db->fragshift; + + DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize); + + memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize); + + if (rec) + ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize); + else + ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize); + + db->ready = 1; + + spin_unlock_irqrestore(&s->lock, flags); + + return 0; +} + +static void clear_advance(struct ess_state *s) +{ + unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80; + + unsigned char *buf = s->dma_dac.rawbuf; + unsigned bsize = s->dma_dac.dmasize; + unsigned bptr = s->dma_dac.swptr; + unsigned len = s->dma_dac.fragsize; + + if (bptr + len > bsize) { + unsigned x = bsize - bptr; + memset(buf + bptr, c, x); + /* account for wrapping? */ + bptr = 0; + len -= x; + } + memset(buf + bptr, c, len); +} + +static void ess_update_ptr(struct ess_state *s) +{ + unsigned hwptr; + int diff; + + /* update ADC pointer */ + if (s->dma_adc.ready) { + hwptr = get_dmac(s) % s->dma_adc.dmasize; + diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; + s->dma_adc.hwptr = hwptr; + s->dma_adc.total_bytes += diff; + s->dma_adc.count += diff; + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + wake_up(&s->dma_adc.wait); + if (!s->dma_adc.mapped) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { + stop_adc(s); + /* brute force everyone back in sync, sigh */ + s->dma_adc.count = 0; + s->dma_adc.swptr = 0; + s->dma_adc.hwptr = 0; + s->dma_adc.error++; + } + } + } + /* update DAC pointer */ + if (s->dma_dac.ready) { + hwptr = get_dmaa(s) % s->dma_dac.dmasize; + diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; + + DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n", + hwptr,diff,s->dma_dac.count); + + s->dma_dac.hwptr = hwptr; + s->dma_dac.total_bytes += diff; + + if (s->dma_dac.mapped) { + + s->dma_dac.count += diff; + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) { + wake_up(&s->dma_dac.wait); + } + } else { + + s->dma_dac.count -= diff; + + if (s->dma_dac.count <= 0) { + DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n", + diff, diff, + s->dma_dac.count, + s->dma_dac.count, + hwptr, hwptr, + s->dma_dac.swptr, + s->dma_dac.swptr); + stop_dac(s); + /* brute force everyone back in sync, sigh */ + s->dma_dac.count = 0; + s->dma_dac.swptr = hwptr; + s->dma_dac.error++; + } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { + clear_advance(s); + s->dma_dac.endcleared = 1; + } + if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) { + wake_up(&s->dma_dac.wait); + DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n", + s->dma_dac.count, s->dma_dac.swptr, hwptr); + } + } + } +} + +static void +ess_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ess_card *c = (struct ess_card *)dev_id; + struct ess_state *s = &c->channels[0]; + u8 status; + + status = inb(c->iobase + 0x1A); + + if(status == 0xff) + return; + + /* presumably acking the ints? */ + outw(status, c->iobase + 0x1A); + + if(in_suspend) + return; + + /* + * ack an assp int if its running + * and has an int pending + */ + if( status & ASSP_INT_PENDING) { + u8 ctl = inb(c->iobase + ASSP_CONTROL_B); + if( !(ctl & STOP_ASSP_CLOCK)) { + ctl = inb(c->iobase + ASSP_HOST_INT_STATUS ); + if(ctl & DSP2HOST_REQ_TIMER) { + outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS); + + /* update adc/dac info if it was a timer int */ + spin_lock(&s->lock); + ess_update_ptr(s); + spin_unlock(&s->lock); + } + } + } + + /* XXX is this needed? */ + if(status & 0x40) + outb(0x40, c->iobase+0x1A); +} + + +/* --------------------------------------------------------------------- */ + +static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n"; + +#define VALIDATE_MAGIC(FOO,MAG) \ +({ \ + if (!(FOO) || (FOO)->magic != MAG) { \ + printk(invalid_magic,__FUNCTION__); \ + return -ENXIO; \ + } \ +}) + +#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC) +#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC) + +/* --------------------------------------------------------------------- */ + +static loff_t m3_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + +static int drain_dac(struct ess_state *s, int nonblock) +{ + DECLARE_WAITQUEUE(wait,current); + unsigned long flags; + int count; + signed long tmo; + + if (s->dma_dac.mapped || !s->dma_dac.ready) + return 0; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac.wait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) { + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + tmo = (count * HZ) / s->ratedac; + tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]; + /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken. + or something. who cares. - zach */ + if (!schedule_timeout(tmo ? tmo : 1) && tmo) + DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies); + } + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +static ssize_t +ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_adc.mapped) + return -ENXIO; + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + + spin_lock_irqsave(&s->lock, flags); + + while (count > 0) { + int timed_out; + + swptr = s->dma_adc.swptr; + cnt = s->dma_adc.dmasize-swptr; + if (s->dma_adc.count < cnt) + cnt = s->dma_adc.count; + + if (cnt > count) + cnt = count; + + if (cnt <= 0) { + start_adc(s); + if (file->f_flags & O_NONBLOCK) { + ret = ret ? ret : -EAGAIN; + goto out; + } + + spin_unlock_irqrestore(&s->lock, flags); + + timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0; + + spin_lock_irqsave(&s->lock, flags); + + if(timed_out) { + printk("read: chip lockup? dmasz %d fragsz %d count %d hwptr %d swptr %d\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + } + + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + goto out; + } + continue; + } + + spin_unlock_irqrestore(&s->lock, flags); + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { + ret = ret ? ret : -EFAULT; + return ret; + } + spin_lock_irqsave(&s->lock, flags); + + swptr = (swptr + cnt) % s->dma_adc.dmasize; + s->dma_adc.swptr = swptr; + s->dma_adc.count -= cnt; + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(s); + } + +out: + spin_unlock_irqrestore(&s->lock, flags); + return ret; +} + +static ssize_t +ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_dac.mapped) + return -ENXIO; + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + + spin_lock_irqsave(&s->lock, flags); + + while (count > 0) { + int timed_out; + + if (s->dma_dac.count < 0) { + s->dma_dac.count = 0; + s->dma_dac.swptr = s->dma_dac.hwptr; + } + swptr = s->dma_dac.swptr; + + cnt = s->dma_dac.dmasize-swptr; + + if (s->dma_dac.count + cnt > s->dma_dac.dmasize) + cnt = s->dma_dac.dmasize - s->dma_dac.count; + + if (cnt > count) + cnt = count; + + if (cnt <= 0) { + start_dac(s); + if (file->f_flags & O_NONBLOCK) { + if(!ret) ret = -EAGAIN; + goto out; + } + + spin_unlock_irqrestore(&s->lock, flags); + timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0; + spin_lock_irqsave(&s->lock, flags); + + if(timed_out) { + DPRINTK(DPCRAP,"write: chip lockup? dmasz %d fragsz %d count %d hwptr %d swptr %d\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + } + if (signal_pending(current)) { + if (!ret) ret = -ERESTARTSYS; + goto out; + } + continue; + } + spin_unlock_irqrestore(&s->lock, flags); + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + spin_lock_irqsave(&s->lock, flags); + DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n", + cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr); + + swptr = (swptr + cnt) % s->dma_dac.dmasize; + + s->dma_dac.swptr = swptr; + s->dma_dac.count += cnt; + s->dma_dac.endcleared = 0; + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } +out: + spin_unlock_irqrestore(&s->lock, flags); + return ret; +} + +static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &s->dma_dac.wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &s->dma_adc.wait, wait); + + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + +static int ess_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + struct dmabuf *db; + int ret; + unsigned long size; + + VALIDATE_STATE(s); + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(s, 1)) != 0) + return ret; + db = &s->dma_dac; + } else + if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(s, 0)) != 0) + return ret; + db = &s->dma_adc; + } else + return -EINVAL; + if (SILLY_OFFSET(vma) != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + return -EAGAIN; + db->mapped = 1; + return 0; +} + +/* + * god, what an absolute mess.. + * not all the paths through here are + * properly locked. + * *sob* + */ +static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + unsigned char fmtm, fmtd; + + VALIDATE_STATE(s); + + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + + DPRINTK(DPSYS,"ess_ioctl: cmd %d\n", cmd); + + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(s, file->f_flags & O_NONBLOCK); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + /* XXX fix */ + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); + + case SNDCTL_DSP_RESET: + spin_lock_irqsave(&s->lock, flags); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; + } + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + case SNDCTL_DSP_SPEED: + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + set_adc_rate(s, val); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + set_dac_rate(s, val); + } + } + spin_unlock_irqrestore(&s->lock, flags); + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SNDCTL_DSP_STEREO: + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val) + fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; + else + fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val) + fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; + else + fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); + } + set_fmt(s, fmtm, fmtd); + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + if (val != 0) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val >= 2) + fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; + else + fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val >= 2) + fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; + else + fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); + } + set_fmt(s, fmtm, fmtd); + } + spin_unlock_irqrestore(&s->lock, flags); + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) + : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + if (val != AFMT_QUERY) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT; + else + fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT; + else + fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT); + } + set_fmt(s, fmtm, fmtd); + } + spin_unlock_irqrestore(&s->lock, flags); + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? + (ESS_FMT_16BIT << ESS_ADC_SHIFT) + : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? + AFMT_S16_LE : + AFMT_U8, + (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING)) + val |= PCM_ENABLE_INPUT; + if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + start_adc(s); + } else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + start_dac(s); + } else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_dac.fragsize; + abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_adc.fragsize; + abinfo.bytes = s->dma_adc.count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + val = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_adc.total_bytes; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + cinfo.ptr = s->dma_adc.hwptr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_dac.total_bytes; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + cinfo.ptr = s->dma_dac.hwptr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(s, 0))) + return val; + return put_user(s->dma_dac.fragsize, (int *)arg); + } + if ((val = prog_dmabuf(s, 1))) + return val; + return put_user(s->dma_adc.fragsize, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + if (file->f_mode & FMODE_READ) { + s->dma_adc.ossfragshift = val & 0xffff; + s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_adc.ossfragshift < 4) + s->dma_adc.ossfragshift = 4; + if (s->dma_adc.ossfragshift > 15) + s->dma_adc.ossfragshift = 15; + if (s->dma_adc.ossmaxfrags < 4) + s->dma_adc.ossmaxfrags = 4; + } + if (file->f_mode & FMODE_WRITE) { + s->dma_dac.ossfragshift = val & 0xffff; + s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_dac.ossfragshift < 4) + s->dma_dac.ossfragshift = 4; + if (s->dma_dac.ossfragshift > 15) + s->dma_dac.ossfragshift = 15; + if (s->dma_dac.ossmaxfrags < 4) + s->dma_dac.ossmaxfrags = 4; + } + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + + get_user_ret(val, (int *)arg, -EFAULT); + + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_adc.subdivision = val; + if (file->f_mode & FMODE_WRITE) + s->dma_dac.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) + : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) + : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } + return -EINVAL; +} + +static int +allocate_dmabuf(struct dmabuf *db) +{ + int order; + unsigned long mapend,map; + void *rawbuf = NULL; + + DPRINTK(DPSTR,"allocating for dmabuf %p\n", db); + + /* + * alloc as big a chunk as we can, start with + * 64k 'cause we're insane. + */ + for (order = 16-PAGE_SHIFT; order >= 1; order--) + /* XXX might be able to get rid of gfp_dma */ + if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) + break; + + if (!rawbuf) + return 1; + + /* + * can't cross a 64k boundry.. + */ + if( ((virt_to_bus(rawbuf) & 0xffff) + ((PAGE_SIZE << order) - 1)) > ~0xffff) { + printk(KERN_ERR PFX "DMA buffer crosses 64k: busaddr 0x%lx size %ld\n", + virt_to_bus(rawbuf), PAGE_SIZE << order); + kfree(rawbuf); + free_pages((unsigned long)db->rawbuf,db->buforder); + return 1; + } + + DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n", + PAGE_SIZE<rawbuf = rawbuf; + db->buforder = order; + db->ready = 0; + db->mapped = 0; + + return 0; +} + +static void +nuke_lists(struct ess_card *card, struct dmabuf *db) +{ + m3_remove_list(card, &(card->dma_list), db->dma_index); + m3_remove_list(card, &(card->msrc_list), db->msrc_index); + db->in_lists = 0; +} + +static void +free_dmabuf(struct dmabuf *db) +{ + unsigned long map, mapend; + + DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db); + + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &mem_map[map].flags); + + free_pages((unsigned long)db->rawbuf,db->buforder); + + db->rawbuf = NULL; + db->buforder = 0; + db->mapped = 0; + db->ready = 0; +} + +static int +ess_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_card *c; + struct ess_state *s = NULL; + int i; + int ret = 0; + unsigned char fmtm = ~0, fmts = 0; + unsigned long flags; + + /* + * Scan the cards and find the channel. We only + * do this at open time so it is ok + */ + for(c = devs ; c != NULL ; c = c->next) { + + for(i=0;ichannels[i].dev_audio < 0) + continue; + if((c->channels[i].dev_audio ^ minor) & ~0xf) + continue; + + s = &c->channels[i]; + break; + } + } + + if (!s) + return -ENODEV; + + VALIDATE_STATE(s); + + file->private_data = s; + + /* wait for device to become free */ + down(&s->open_sem); + while (s->open_mode & file->f_mode) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EWOULDBLOCK; + } + up(&s->open_sem); + interruptible_sleep_on(&s->open_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + + spin_lock_irqsave(&s->lock, flags); + + if (file->f_mode & FMODE_READ) { + if(allocate_dmabuf(&(s->dma_adc))) { + ret = -ENOMEM; + goto out; + } + fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; + + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + set_adc_rate(s, 8000); + } + if (file->f_mode & FMODE_WRITE) { + if(allocate_dmabuf(&(s->dma_dac))) { + ret = -ENOMEM; + goto out; + } + + fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT; + + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + set_dac_rate(s, 8000); + } + set_fmt(s, fmtm, fmts); + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + + MOD_INC_USE_COUNT; +out: + spin_unlock_irqrestore(&s->lock, flags); + up(&s->open_sem); + return ret; +} + +static int +ess_release(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + + down(&s->open_sem); + spin_lock_irqsave(&s->lock, flags); + + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + if(s->dma_dac.in_lists) { + m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index); + nuke_lists(s->card, &(s->dma_dac)); + } + free_dmabuf(&(s->dma_dac)); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + if(s->dma_adc.in_lists) { + m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index); + nuke_lists(s->card, &(s->dma_adc)); + } + free_dmabuf(&(s->dma_adc)); + } + + s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + + spin_unlock_irqrestore(&s->lock, flags); + up(&s->open_sem); + wake_up(&s->open_wait); + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Wait for the ac97 serial bus to be free. + * return nonzero if the bus is still busy. + */ +static int m3_ac97_wait(struct ess_card *card) +{ + int i = 10000; + + while( (m3_inb(card, 0x30) & 1) && i--) ; + + return i == 0; +} + +u16 m3_ac97_read(struct ac97_codec *codec, u8 reg) +{ + u16 ret = 0; + struct ess_card *card = codec->private_data; + + spin_lock(&card->ac97_lock); + + if(m3_ac97_wait(card)) { + printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg); + goto out; + } + + m3_outb(card, 0x80 | (reg & 0x7f), 0x30); + + if(m3_ac97_wait(card)) { + printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg); + goto out; + } + + ret = m3_inw(card, 0x32); + DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg); + +out: + spin_unlock(&card->ac97_lock); + return ret; +} + +void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) +{ + struct ess_card *card = codec->private_data; + + spin_lock(&card->ac97_lock); + + if(m3_ac97_wait(card)) { + printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg); + goto out; + } + DPRINTK(DPCRAP,"writing 0x%04x to 0x%02x\n", val, reg); + + m3_outw(card, val, 0x32); + m3_outb(card, reg & 0x7f, 0x30); +out: + spin_unlock(&card->ac97_lock); +} +/* OSS /dev/mixer file operation methods */ +static int m3_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_card *card = devs; + + MOD_INC_USE_COUNT; + for (card = devs; card != NULL; card = card->next) { + if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor)) + break; + } + + if (!card) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + file->private_data = card->ac97; + + return 0; +} + +static int m3_release_mixdev(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int m3_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + + return codec->mixer_ioctl(codec, cmd, arg); +} + +static /*const*/ struct file_operations m3_mixer_fops = { +llseek: m3_llseek, +ioctl: m3_ioctl_mixdev, +open: m3_open_mixdev, +release: m3_release_mixdev, +}; + +void remote_codec_config(int io, int isremote) +{ + isremote = isremote ? 1 : 0; + + outw( (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote, + io + RING_BUS_CTRL_B); + outw( (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote, + io + SDO_OUT_DEST_CTRL); + outw( (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote, + io + SDO_IN_DEST_CTRL); +} + +/* + * hack, returns non zero on err + */ +static int try_read_vendor(struct ess_card *card) +{ + u16 ret; + + if(m3_ac97_wait(card)) + return 1; + + m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30); + + if(m3_ac97_wait(card)) + return 1; + + ret = m3_inw(card, 0x32); + + return (ret == 0) || (ret == 0xffff); +} + +static void m3_codec_reset(struct ess_card *card, int busywait) +{ + u16 dir; + int delay1 = 0, delay2 = 0, i; + int io = card->iobase; + + switch (card->card_type) { + /* + * the onboard codec on the allegro seems + * to want to wait a very long time before + * coming back to life + */ + case ESS_ALLEGRO: + delay1 = 50; + delay2 = 800; + break; + case ESS_MAESTRO3: + delay1 = 20; + delay2 = 500; + break; + } + + for(i = 0; i < 5; i ++) { + dir = inw(io + GPIO_DIRECTION); + dir |= 0x10; /* assuming pci bus master? */ + + remote_codec_config(io, 0); + + outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A); + udelay(20); + + outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION); + outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK); + outw(0, io + GPIO_DATA); + outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION); + + if(busywait) { + mdelay(delay1); + } else { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((delay1 * HZ) / 1000); + } + + outw(GPO_PRIMARY_AC97, io + GPIO_DATA); + udelay(5); + /* ok, bring back the ac-link */ + outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A); + outw(~0, io + GPIO_MASK); + + if(busywait) { + mdelay(delay2); + } else { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((delay2 * HZ) / 1000); + } + if(! try_read_vendor(card)) + break; + + delay1 += 10; + delay2 += 100; + + DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n", + delay1, delay2); + } + +#if 0 + /* more gung-ho reset that doesn't + * seem to work anywhere :) + */ + tmp = inw(io + RING_BUS_CTRL_A); + outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A); + mdelay(20); + outw(tmp, io + RING_BUS_CTRL_A); + mdelay(50); +#endif +} + +static int __init m3_codec_install(struct ess_card *card) +{ + struct ac97_codec *codec; + + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(codec, 0, sizeof(struct ac97_codec)); + + codec->private_data = card; + codec->codec_read = m3_ac97_read; + codec->codec_write = m3_ac97_write; + + if (ac97_probe_codec(codec) == 0) { + printk(KERN_ERR PFX "codec probe failed\n"); + kfree(codec); + return -1; + } + + if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) { + printk(KERN_ERR PFX "couldn't register mixer!\n"); + kfree(codec); + return -1; + } + + card->ac97 = codec; + + return 0; +} + + +#define MINISRC_LPF_LEN 10 +static u16 minisrc_lpf[MINISRC_LPF_LEN] = { + 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C, + 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F +}; +static void m3_assp_init(struct ess_card *card) +{ + int i; + + /* zero kernel data */ + for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_BASE_ADDR + i, 0); + + /* zero mixer data? */ + for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_BASE_ADDR2 + i, 0); + + /* init dma pointer */ + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_CURRENT_DMA, + KDATA_DMA_XFER0); + + /* write kernel into code memory.. */ + for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) { + m3_assp_write(card, MEMTYPE_INTERNAL_CODE, + REV_B_CODE_MEMORY_BEGIN + i, + assp_kernel_image[i]); + } + + /* + * We only have this one client and we know that 0x400 + * is free in our kernel's mem map, so lets just + * drop it there. It seems that the minisrc doesn't + * need vectors, so we won't bother with them.. + */ + for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) { + m3_assp_write(card, MEMTYPE_INTERNAL_CODE, + 0x400 + i, + assp_minisrc_image[i]); + } + + /* + * write the coefficients for the low pass filter? + */ + for(i = 0; i < MINISRC_LPF_LEN ; i++) { + m3_assp_write(card, MEMTYPE_INTERNAL_CODE, + 0x400 + MINISRC_COEF_LOC + i, + minisrc_lpf[i]); + } + + m3_assp_write(card, MEMTYPE_INTERNAL_CODE, + 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN, + 0x8000); + + /* + * the minisrc is the only thing on + * our task list.. + */ + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_TASK0, + 0x400); + + /* + * init the mixer number.. + */ + + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_MIXER_TASK_NUMBER,0); + + /* + * EXTREME KERNEL MASTER VOLUME + */ + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_DAC_LEFT_VOLUME, ARB_VOLUME); + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME); + + card->mixer_list.mem_addr = KDATA_MIXER_XFER0; + card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS; + card->adc1_list.mem_addr = KDATA_ADC1_XFER0; + card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS; + card->dma_list.mem_addr = KDATA_DMA_XFER0; + card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS; + card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC; + card->msrc_list.max = MAX_INSTANCE_MINISRC; +} + +static int setup_msrc(struct ess_card *card, + struct assp_instance *inst, int index) +{ + int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + + MINISRC_IN_BUFFER_SIZE / 2 + + 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 ); + int address, i; + + /* + * the revb memory map has 0x1100 through 0x1c00 + * free. + */ + + /* + * align instance mem so that the shifted list + * addresses are aligned. + */ + data_bytes = (data_bytes + 255) & ~255; + address = 0x1100 + ((data_bytes/2) * index); + + if((address + (data_bytes/2)) >= 0x1c00) { + printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n", + data_bytes, index, address); + return -1; + } + + for(i = 0; i < data_bytes/2 ; i++) + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + address + i, 0); + + inst->code = 0x400; + inst->data = address; + + return 0; +} + +static int m3_assp_client_init(struct ess_state *s) +{ + setup_msrc(s->card, &(s->dac_inst), s->index * 2); + setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1); + + return 0; +} + +static void +m3_amp_enable(struct ess_card *card, int enable) +{ + /* + * this works for the reference board, have to find + * out about others + * + * this needs more magic for 4 speaker, but.. + */ + int io = card->iobase; + u16 gpo, polarity_port, polarity; + + if(!external_amp) + return; + + switch (card->card_type) { + case ESS_ALLEGRO: + polarity_port = 0x1800; + break; + default: + /* presumably this is for all 'maestro3's.. */ + polarity_port = 0x1100; + break; + } + + gpo = (polarity_port >> 8) & 0x0F; + polarity = polarity_port >> 12; + if ( enable ) + polarity = !polarity; + polarity = polarity << gpo; + gpo = 1 << gpo; + + outw(~gpo , io + GPIO_MASK); + + outw( inw(io + GPIO_DIRECTION) | gpo , + io + GPIO_DIRECTION); + + outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) , + io + GPIO_DATA); + + outw(0xffff , io + GPIO_MASK); +} + +static int +maestro_config(struct ess_card *card) +{ + struct pci_dev *pcidev = card->pcidev; + u32 n; + u8 t; /* makes as much sense as 'n', no? */ + + pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); + n &= REDUCED_DEBOUNCE; + n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; + pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); + + outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B); + pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); + n &= ~INT_CLK_SELECT; + if(card->card_type == ESS_MAESTRO3) { + n &= ~INT_CLK_MULT_ENABLE; + n |= INT_CLK_SRC_NOT_PCI; + } + n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 ); + pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); + + if(card->card_type <= ESS_ALLEGRO) { + pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n); + n |= IN_CLK_12MHZ_SELECT; + pci_write_config_dword(pcidev, PCI_USER_CONFIG, n); + } + + t = inb(card->iobase + ASSP_CONTROL_A); + t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT); + switch(global_dsp_speed) { + case 33: + break; + case 36: + t |= DSP_CLK_36MHZ_SELECT; + break; + case 49: + t |= ASSP_CLK_49MHZ_SELECT; + break; + } + t |= ASSP_0_WS_ENABLE; + outb(t, card->iobase + ASSP_CONTROL_A); + + outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B); + + return 0; +} + +static void +m3_enable_ints(struct ess_card *card) +{ + unsigned long io = card->iobase; + + outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL); + outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, + io + ASSP_CONTROL_C); +} + +static struct file_operations ess_audio_fops = { + &m3_llseek, + &ess_read, + &ess_write, + NULL, /* readdir */ + &ess_poll, + &ess_ioctl, + &ess_mmap, + &ess_open, + NULL, /* flush */ + &ess_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +#ifdef CONFIG_APM +int alloc_dsp_savemem(struct ess_card *card) +{ + int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH); + + if( (card->suspend_dsp_mem = vmalloc(len)) == NULL) + return 1; + + return 0; +} +void free_dsp_savemem(struct ess_card *card) +{ + if(card->suspend_dsp_mem) + vfree(card->suspend_dsp_mem); +} + +#else +#define alloc_dsp_savemem(args...) 0 +#define free_dsp_savemem(args...) +#endif + +/* + * great day! this function is ugly as hell. + */ +static int +maestro_install(struct pci_dev *pcidev, struct card_type *ct) +{ + u32 n; + int i; + int iobase; + struct ess_card *card = NULL; + int num = 0; + + /* don't pick up modems */ + if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) + return 1; + + DPRINTK(DPMOD, "in maestro_install\n"); + + iobase = SILLY_PCI_BASE_ADDRESS(pcidev); + + if(check_region(iobase, 256)) + { + printk(KERN_WARNING PFX "can't allocate 256 bytes I/O at 0x%4.4x\n", iobase); + return 1; + } + /* stake our claim on the iospace */ + request_region(iobase, 256, ct->name); + + /* this was tripping up some machines */ + if(pcidev->irq == 0) + printk(KERN_WARNING PFX "pci subsystem reports irq 0, this might not be correct.\n"); + + /* just to be sure */ + pci_set_master(pcidev); + + card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); + if(card == NULL) + { + printk(KERN_WARNING PFX "out of memory\n"); + release_region(card->iobase, 256); + return 1; + } + + memset(card, 0, sizeof(*card)); + card->pcidev = pcidev; + + if(alloc_dsp_savemem(card)) { + printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n", + REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH); + release_region(card->iobase, 256); + free_dsp_savemem(card); + kfree(card); + return 1; + } + + if (register_reboot_notifier(&maestro_nb)) { + printk(KERN_WARNING PFX "reboot notifier registration failed\n"); + release_region(card->iobase, 256); + free_dsp_savemem(card); + kfree(card); + return 1; + } + + card->iobase = iobase; + card->card_type = ct->type; + card->irq = pcidev->irq; + card->next = devs; + card->magic = M3_CARD_MAGIC; + spin_lock_init(&card->lock); + spin_lock_init(&card->ac97_lock); + devs = card; + + printk(KERN_INFO PFX "Configuring %s found at IO 0x%04X IRQ %d\n", + ct->name,iobase,card->irq); + pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n); + printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n); + + maestro_config(card); + m3_assp_halt(card); + + m3_codec_reset(card, 0); + + if(m3_codec_install(card)) { + unregister_reboot_notifier(&maestro_nb); + release_region(card->iobase, 256); + free_dsp_savemem(card); + kfree(card); + return 1; + } + + m3_assp_init(card); + m3_amp_enable(card, 1); + + for(i=0;ichannels[i]; + + s->index = i; + + s->card = card; + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + spin_lock_init(&s->lock); + SILLY_INIT_SEM(s->open_sem); + s->magic = M3_STATE_MAGIC; + + m3_assp_client_init(s); + + if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) + printk("maestro: BOTCH!\n"); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0) + break; + } + + num = i; + + /* clear the rest if we ran out of slots to register */ + for(;ichannels[i]; + s->dev_audio = -1; + } + + + if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, ct->name, card)) + { + printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq); + for(i=0;ichannels[i]; + if(s->dev_audio != -1) + unregister_sound_dsp(s->dev_audio); + } + unregister_reboot_notifier(&maestro_nb); + unregister_sound_mixer(card->ac97->dev_mixer); + kfree(card->ac97); + release_region(card->iobase, 256); + free_dsp_savemem(card); + kfree(card); + return 1; + } + +#ifdef CONFIG_APM + if (apm_register_callback(m3_apm_callback)) { + printk(KERN_WARNING PFX "couldn't register apm callback, suspend/resume might not work.\n"); + } +#endif + + m3_enable_ints(card); + m3_assp_continue(card); + + printk(KERN_INFO PFX "%d channels configured.\n", num); + + return 0; +} + +#ifdef MODULE +int init_module(void) +#else +SILLY_MAKE_INIT(int init_maestro3(void)) +#endif +{ + struct pci_dev *pcidev = NULL; + int found = 0; + int i; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + + printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n"); + + switch(global_dsp_speed) { + case 33: case 36: case 49: + break; + default: + printk(KERN_INFO PFX "invalid global_dsp_speed: %d, must be 33, 36, or 49.\n", + global_dsp_speed); + return -EINVAL; + break; + } + +#ifdef CONFIG_APM + init_waitqueue_head(&suspend_queue); +#endif + + for(i = 0; i < NUM_CARD_TYPES; i++) { + struct card_type *ct = &m3_card_types[i]; + + pcidev = NULL; + while( (pcidev = pci_find_device(PCI_VENDOR_ESS, ct->pci_id, pcidev)) != NULL ) { + if (! maestro_install(pcidev, ct)) + found++; + } + } + + printk(KERN_INFO PFX "%d maestros installed.\n",found); + + if(found == 0 ) + return -ENODEV; + + return 0; +} + +void nuke_maestros(void) +{ + struct ess_card *card; + + unregister_reboot_notifier(&maestro_nb); +#ifdef CONFIG_APM + apm_unregister_callback(m3_apm_callback); +#endif + + while ((card = devs)) { + int i; + devs = devs->next; + + free_irq(card->irq, card); + unregister_sound_mixer(card->ac97->dev_mixer); + kfree(card->ac97); + + for(i=0;ichannels[i]; + if(ess->dev_audio != -1) + unregister_sound_dsp(ess->dev_audio); + } + + release_region(card->iobase, 256); + free_dsp_savemem(card); + kfree(card); + } + devs = NULL; +} + +static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf) +{ + /* this notifier is called when the kernel is really shut down. */ + DPRINTK(DPMOD,"shutting down\n"); + nuke_maestros(); + return NOTIFY_OK; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE +MODULE_AUTHOR("Zach Brown "); +MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver"); +#ifdef M_DEBUG +MODULE_PARM(debug,"i"); +MODULE_PARM(global_dsp_speed,"i"); +#endif +MODULE_PARM(external_amp,"i"); + +void cleanup_module(void) { + DPRINTK(DPMOD,"unloading\n"); + nuke_maestros(); +} + +#endif /* MODULE */ + +#ifdef CONFIG_APM +void +check_suspend(void) +{ + DECLARE_WAITQUEUE(wait, current); + + if(!in_suspend) + return; + + in_suspend++; + add_wait_queue(&suspend_queue, &wait); + current->state = TASK_UNINTERRUPTIBLE; + schedule(); + remove_wait_queue(&suspend_queue, &wait); + current->state = TASK_RUNNING; +} + +static int +m3_suspend(void) +{ + struct ess_card *card; + unsigned long flags; + int index; + + save_flags(flags); + cli(); + + for (card = devs; card ; card = card->next) { + int i; + + DPRINTK(DPMOD, "apm in dev %p\n",card); + + for(i=0;ichannels[i]; + + if(s->dev_audio == -1) + continue; + + DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i); + stop_dac(s); + stop_adc(s); + } + + mdelay(10); /* give the assp a chance to idle.. */ + + m3_assp_halt(card); + + index = 0; + DPRINTK(DPMOD, "saving code\n"); + for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++) + card->suspend_dsp_mem[index++] = + m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i); + DPRINTK(DPMOD, "saving data\n"); + for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) + card->suspend_dsp_mem[index++] = + m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i); + + DPRINTK(DPMOD, "powering down apci regs\n"); + m3_outw(card, 0xffff, 0x54); + m3_outw(card, 0xffff, 0x56); + } + in_suspend=1; + + restore_flags(flags); + + return 0; +} + +static int +m3_resume(void) +{ + struct ess_card *card; + unsigned long flags; + int index; + + save_flags(flags); /* paranoia */ + cli(); + in_suspend=0; + + DPRINTK(DPMOD, "resuming\n"); + + /* first lets just bring everything back. .*/ + for (card = devs; card ; card = card->next) { + int i; + + DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card); + m3_outw(card, 0, 0x54); + m3_outw(card, 0, 0x56); + + DPRINTK(DPMOD, "restoring pci configs and reseting codec\n"); + maestro_config(card); + m3_assp_halt(card); + m3_codec_reset(card, 1); + + DPRINTK(DPMOD, "restoring dsp code\n"); + index = 0; + for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++) + m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i, + card->suspend_dsp_mem[index++]); + for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i, + card->suspend_dsp_mem[index++]); + + /* tell the dma engine to restart itself */ + m3_assp_write(card, MEMTYPE_INTERNAL_DATA, + KDATA_DMA_ACTIVE, 0); + + DPRINTK(DPMOD, "resuming dsp\n"); + m3_assp_continue(card); + + DPRINTK(DPMOD, "enabling ints\n"); + m3_enable_ints(card); + + /* bring back the old school flavor */ + for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) { + int state = card->ac97->mixer_state[i]; + if (!supported_mixer(card->ac97, i)) + continue; + + card->ac97->write_mixer(card->ac97, i, + state & 0xff, (state >> 8) & 0xff); + } + + m3_amp_enable(card, 1); + } + + /* + * now we flip on the music + */ + for (card = devs; card ; card = card->next) { + int i; + + + for(i=0;ichannels[i]; + if(s->dev_audio == -1) + continue; + /* + * db->ready makes it so these guys can be + * called unconditionally.. + */ + DPRINTK(DPMOD, "turning on dacs ind %d\n",i); + start_dac(s); + start_adc(s); + } + } + + restore_flags(flags); + + /* + * all right, we think things are ready, + * wake up people who were using the device + * when we suspended + */ + wake_up(&suspend_queue); + + return 0; +} + +int +m3_apm_callback(apm_event_t ae) { + + DPRINTK(DPMOD, "APM event received: 0x%x\n",ae); + + switch(ae) { + case APM_SYS_SUSPEND: + case APM_CRITICAL_SUSPEND: + case APM_USER_SUSPEND: + + m3_suspend(); + break; + + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + case APM_STANDBY_RESUME: + + m3_resume(); + break; + + default: + break; + } + + return 0; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/maestro3.h linux/drivers/sound/maestro3.h --- v2.2.18/drivers/sound/maestro3.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/sound/maestro3.h Sun Mar 25 11:37:37 2001 @@ -0,0 +1,821 @@ +/* + * ESS Technology allegro audio driver. + * + * Copyright (C) 1992-2000 Don Kim (don.kim@esstech.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Hacked for the maestro3 driver by zab + */ + +// Allegro PCI configuration registers +#define PCI_LEGACY_AUDIO_CTRL 0x40 +#define SOUND_BLASTER_ENABLE 0x00000001 +#define FM_SYNTHESIS_ENABLE 0x00000002 +#define GAME_PORT_ENABLE 0x00000004 +#define MPU401_IO_ENABLE 0x00000008 +#define MPU401_IRQ_ENABLE 0x00000010 +#define ALIAS_10BIT_IO 0x00000020 +#define SB_DMA_MASK 0x000000C0 +#define SB_DMA_0 0x00000040 +#define SB_DMA_1 0x00000040 +#define SB_DMA_R 0x00000080 +#define SB_DMA_3 0x000000C0 +#define SB_IRQ_MASK 0x00000700 +#define SB_IRQ_5 0x00000000 +#define SB_IRQ_7 0x00000100 +#define SB_IRQ_9 0x00000200 +#define SB_IRQ_10 0x00000300 +#define MIDI_IRQ_MASK 0x00003800 +#define SERIAL_IRQ_ENABLE 0x00004000 +#define DISABLE_LEGACY 0x00008000 + +#define PCI_ALLEGRO_CONFIG 0x50 +#define SB_ADDR_240 0x00000004 +#define MPU_ADDR_MASK 0x00000018 +#define MPU_ADDR_330 0x00000000 +#define MPU_ADDR_300 0x00000008 +#define MPU_ADDR_320 0x00000010 +#define MPU_ADDR_340 0x00000018 +#define USE_PCI_TIMING 0x00000040 +#define POSTED_WRITE_ENABLE 0x00000080 +#define DMA_POLICY_MASK 0x00000700 +#define DMA_DDMA 0x00000000 +#define DMA_TDMA 0x00000100 +#define DMA_PCPCI 0x00000200 +#define DMA_WBDMA16 0x00000400 +#define DMA_WBDMA4 0x00000500 +#define DMA_WBDMA2 0x00000600 +#define DMA_WBDMA1 0x00000700 +#define DMA_SAFE_GUARD 0x00000800 +#define HI_PERF_GP_ENABLE 0x00001000 +#define PIC_SNOOP_MODE_0 0x00002000 +#define PIC_SNOOP_MODE_1 0x00004000 +#define SOUNDBLASTER_IRQ_MASK 0x00008000 +#define RING_IN_ENABLE 0x00010000 +#define SPDIF_TEST_MODE 0x00020000 +#define CLK_MULT_MODE_SELECT_2 0x00040000 +#define EEPROM_WRITE_ENABLE 0x00080000 +#define CODEC_DIR_IN 0x00100000 +#define HV_BUTTON_FROM_GD 0x00200000 +#define REDUCED_DEBOUNCE 0x00400000 +#define HV_CTRL_ENABLE 0x00800000 +#define SPDIF_ENABLE 0x01000000 +#define CLK_DIV_SELECT 0x06000000 +#define CLK_DIV_BY_48 0x00000000 +#define CLK_DIV_BY_49 0x02000000 +#define CLK_DIV_BY_50 0x04000000 +#define CLK_DIV_RESERVED 0x06000000 +#define PM_CTRL_ENABLE 0x08000000 +#define CLK_MULT_MODE_SELECT 0x30000000 +#define CLK_MULT_MODE_SHIFT 28 +#define CLK_MULT_MODE_0 0x00000000 +#define CLK_MULT_MODE_1 0x10000000 +#define CLK_MULT_MODE_2 0x20000000 +#define CLK_MULT_MODE_3 0x30000000 +#define INT_CLK_SELECT 0x40000000 +#define INT_CLK_MULT_RESET 0x80000000 + +// M3 +#define INT_CLK_SRC_NOT_PCI 0x00100000 +#define INT_CLK_MULT_ENABLE 0x80000000 + +#define PCI_ACPI_CONTROL 0x54 +#define PCI_ACPI_D0 0x00000000 +#define PCI_ACPI_D1 0xB4F70000 +#define PCI_ACPI_D2 0xB4F7B4F7 + +#define PCI_USER_CONFIG 0x58 +#define EXT_PCI_MASTER_ENABLE 0x00000001 +#define SPDIF_OUT_SELECT 0x00000002 +#define TEST_PIN_DIR_CTRL 0x00000004 +#define AC97_CODEC_TEST 0x00000020 +#define TRI_STATE_BUFFER 0x00000080 +#define IN_CLK_12MHZ_SELECT 0x00000100 +#define MULTI_FUNC_DISABLE 0x00000200 +#define EXT_MASTER_PAIR_SEL 0x00000400 +#define PCI_MASTER_SUPPORT 0x00000800 +#define STOP_CLOCK_ENABLE 0x00001000 +#define EAPD_DRIVE_ENABLE 0x00002000 +#define REQ_TRI_STATE_ENABLE 0x00004000 +#define REQ_LOW_ENABLE 0x00008000 +#define MIDI_1_ENABLE 0x00010000 +#define MIDI_2_ENABLE 0x00020000 +#define SB_AUDIO_SYNC 0x00040000 +#define HV_CTRL_TEST 0x00100000 +#define SOUNDBLASTER_TEST 0x00400000 + +#define PCI_USER_CONFIG_C 0x5C + +#define PCI_DDMA_CTRL 0x60 +#define DDMA_ENABLE 0x00000001 + + +// Allegro registers +#define HOST_INT_CTRL 0x18 +#define SB_INT_ENABLE 0x0001 +#define MPU401_INT_ENABLE 0x0002 +#define ASSP_INT_ENABLE 0x0010 +#define RING_INT_ENABLE 0x0020 +#define HV_INT_ENABLE 0x0040 +#define CLKRUN_GEN_ENABLE 0x0100 +#define HV_CTRL_TO_PME 0x0400 +#define SOFTWARE_RESET_ENABLE 0x8000 + +/* + * should be using the above defines, probably. + */ +#define REGB_ENABLE_RESET 0x01 +#define REGB_STOP_CLOCK 0x10 + +#define HOST_INT_STATUS 0x1A +#define SB_INT_PENDING 0x01 +#define MPU401_INT_PENDING 0x02 +#define ASSP_INT_PENDING 0x10 +#define RING_INT_PENDING 0x20 +#define HV_INT_PENDING 0x40 + +#define HARDWARE_VOL_CTRL 0x1B +#define SHADOW_MIX_REG_VOICE 0x1C +#define HW_VOL_COUNTER_VOICE 0x1D +#define SHADOW_MIX_REG_MASTER 0x1E +#define HW_VOL_COUNTER_MASTER 0x1F + +#define CODEC_COMMAND 0x30 +#define CODEC_READ_B 0x80 + +#define CODEC_STATUS 0x30 +#define CODEC_BUSY_B 0x01 + +#define CODEC_DATA 0x32 + +#define RING_BUS_CTRL_A 0x36 +#define RAC_PME_ENABLE 0x0100 +#define RAC_SDFS_ENABLE 0x0200 +#define LAC_PME_ENABLE 0x0400 +#define LAC_SDFS_ENABLE 0x0800 +#define SERIAL_AC_LINK_ENABLE 0x1000 +#define IO_SRAM_ENABLE 0x2000 +#define IIS_INPUT_ENABLE 0x8000 + +#define RING_BUS_CTRL_B 0x38 +#define SECOND_CODEC_ID_MASK 0x0003 +#define SPDIF_FUNC_ENABLE 0x0010 +#define SECOND_AC_ENABLE 0x0020 +#define SB_MODULE_INTF_ENABLE 0x0040 +#define SSPE_ENABLE 0x0040 +#define M3I_DOCK_ENABLE 0x0080 + +#define SDO_OUT_DEST_CTRL 0x3A +#define COMMAND_ADDR_OUT 0x0003 +#define PCM_LR_OUT_LOCAL 0x0000 +#define PCM_LR_OUT_REMOTE 0x0004 +#define PCM_LR_OUT_MUTE 0x0008 +#define PCM_LR_OUT_BOTH 0x000C +#define LINE1_DAC_OUT_LOCAL 0x0000 +#define LINE1_DAC_OUT_REMOTE 0x0010 +#define LINE1_DAC_OUT_MUTE 0x0020 +#define LINE1_DAC_OUT_BOTH 0x0030 +#define PCM_CLS_OUT_LOCAL 0x0000 +#define PCM_CLS_OUT_REMOTE 0x0040 +#define PCM_CLS_OUT_MUTE 0x0080 +#define PCM_CLS_OUT_BOTH 0x00C0 +#define PCM_RLF_OUT_LOCAL 0x0000 +#define PCM_RLF_OUT_REMOTE 0x0100 +#define PCM_RLF_OUT_MUTE 0x0200 +#define PCM_RLF_OUT_BOTH 0x0300 +#define LINE2_DAC_OUT_LOCAL 0x0000 +#define LINE2_DAC_OUT_REMOTE 0x0400 +#define LINE2_DAC_OUT_MUTE 0x0800 +#define LINE2_DAC_OUT_BOTH 0x0C00 +#define HANDSET_OUT_LOCAL 0x0000 +#define HANDSET_OUT_REMOTE 0x1000 +#define HANDSET_OUT_MUTE 0x2000 +#define HANDSET_OUT_BOTH 0x3000 +#define IO_CTRL_OUT_LOCAL 0x0000 +#define IO_CTRL_OUT_REMOTE 0x4000 +#define IO_CTRL_OUT_MUTE 0x8000 +#define IO_CTRL_OUT_BOTH 0xC000 + +#define SDO_IN_DEST_CTRL 0x3C +#define STATUS_ADDR_IN 0x0003 +#define PCM_LR_IN_LOCAL 0x0000 +#define PCM_LR_IN_REMOTE 0x0004 +#define PCM_LR_RESERVED 0x0008 +#define PCM_LR_IN_BOTH 0x000C +#define LINE1_ADC_IN_LOCAL 0x0000 +#define LINE1_ADC_IN_REMOTE 0x0010 +#define LINE1_ADC_IN_MUTE 0x0020 +#define MIC_ADC_IN_LOCAL 0x0000 +#define MIC_ADC_IN_REMOTE 0x0040 +#define MIC_ADC_IN_MUTE 0x0080 +#define LINE2_DAC_IN_LOCAL 0x0000 +#define LINE2_DAC_IN_REMOTE 0x0400 +#define LINE2_DAC_IN_MUTE 0x0800 +#define HANDSET_IN_LOCAL 0x0000 +#define HANDSET_IN_REMOTE 0x1000 +#define HANDSET_IN_MUTE 0x2000 +#define IO_STATUS_IN_LOCAL 0x0000 +#define IO_STATUS_IN_REMOTE 0x4000 + +#define SPDIF_IN_CTRL 0x3E +#define SPDIF_IN_ENABLE 0x0001 + +#define GPIO_DATA 0x60 +#define GPIO_DATA_MASK 0x0FFF +#define GPIO_HV_STATUS 0x3000 +#define GPIO_PME_STATUS 0x4000 + +#define GPIO_MASK 0x64 +#define GPIO_DIRECTION 0x68 +#define GPO_PRIMARY_AC97 0x0001 +#define GPI_LINEOUT_SENSE 0x0004 +#define GPO_SECONDARY_AC97 0x0008 +#define GPI_VOL_DOWN 0x0010 +#define GPI_VOL_UP 0x0020 +#define GPI_IIS_CLK 0x0040 +#define GPI_IIS_LRCLK 0x0080 +#define GPI_IIS_DATA 0x0100 +#define GPI_DOCKING_STATUS 0x0100 +#define GPI_HEADPHONE_SENSE 0x0200 +#define GPO_EXT_AMP_SHUTDOWN 0x1000 + +// M3 +#define GPO_M3_EXT_AMP_SHUTDN 0x0002 + +#define ASSP_INDEX_PORT 0x80 +#define ASSP_MEMORY_PORT 0x82 +#define ASSP_DATA_PORT 0x84 + +#define MPU401_DATA_PORT 0x98 +#define MPU401_STATUS_PORT 0x99 + +#define CLK_MULT_DATA_PORT 0x9C + +#define ASSP_CONTROL_A 0xA2 +#define ASSP_0_WS_ENABLE 0x01 +#define ASSP_CTRL_A_RESERVED1 0x02 +#define ASSP_CTRL_A_RESERVED2 0x04 +#define ASSP_CLK_49MHZ_SELECT 0x08 +#define FAST_PLU_ENABLE 0x10 +#define ASSP_CTRL_A_RESERVED3 0x20 +#define DSP_CLK_36MHZ_SELECT 0x40 + +#define ASSP_CONTROL_B 0xA4 +#define RESET_ASSP 0x00 +#define RUN_ASSP 0x01 +#define ENABLE_ASSP_CLOCK 0x00 +#define STOP_ASSP_CLOCK 0x10 +#define RESET_TOGGLE 0x40 + +#define ASSP_CONTROL_C 0xA6 +#define ASSP_HOST_INT_ENABLE 0x01 +#define FM_ADDR_REMAP_DISABLE 0x02 +#define HOST_WRITE_PORT_ENABLE 0x08 + +#define ASSP_HOST_INT_STATUS 0xAC +#define DSP2HOST_REQ_PIORECORD 0x01 +#define DSP2HOST_REQ_I2SRATE 0x02 +#define DSP2HOST_REQ_TIMER 0x04 + +// AC97 registers +// XXX fix this crap up +/*#define AC97_RESET 0x00*/ + +#define AC97_VOL_MUTE_B 0x8000 +#define AC97_VOL_M 0x1F +#define AC97_LEFT_VOL_S 8 + +#define AC97_MASTER_VOL 0x02 +#define AC97_LINE_LEVEL_VOL 0x04 +#define AC97_MASTER_MONO_VOL 0x06 +#define AC97_PC_BEEP_VOL 0x0A +#define AC97_PC_BEEP_VOL_M 0x0F +#define AC97_SROUND_MASTER_VOL 0x38 +#define AC97_PC_BEEP_VOL_S 1 + +/*#define AC97_PHONE_VOL 0x0C +#define AC97_MIC_VOL 0x0E*/ +#define AC97_MIC_20DB_ENABLE 0x40 + +/*#define AC97_LINEIN_VOL 0x10 +#define AC97_CD_VOL 0x12 +#define AC97_VIDEO_VOL 0x14 +#define AC97_AUX_VOL 0x16*/ +#define AC97_PCM_OUT_VOL 0x18 +/*#define AC97_RECORD_SELECT 0x1A*/ +#define AC97_RECORD_MIC 0x00 +#define AC97_RECORD_CD 0x01 +#define AC97_RECORD_VIDEO 0x02 +#define AC97_RECORD_AUX 0x03 +#define AC97_RECORD_MONO_MUX 0x02 +#define AC97_RECORD_DIGITAL 0x03 +#define AC97_RECORD_LINE 0x04 +#define AC97_RECORD_STEREO 0x05 +#define AC97_RECORD_MONO 0x06 +#define AC97_RECORD_PHONE 0x07 + +/*#define AC97_RECORD_GAIN 0x1C*/ +#define AC97_RECORD_VOL_M 0x0F + +/*#define AC97_GENERAL_PURPOSE 0x20*/ +#define AC97_POWER_DOWN_CTRL 0x26 +#define AC97_ADC_READY 0x0001 +#define AC97_DAC_READY 0x0002 +#define AC97_ANALOG_READY 0x0004 +#define AC97_VREF_ON 0x0008 +#define AC97_PR0 0x0100 +#define AC97_PR1 0x0200 +#define AC97_PR2 0x0400 +#define AC97_PR3 0x0800 +#define AC97_PR4 0x1000 + +#define AC97_RESERVED1 0x28 + +#define AC97_VENDOR_TEST 0x5A + +#define AC97_CLOCK_DELAY 0x5C +#define AC97_LINEOUT_MUX_SEL 0x0001 +#define AC97_MONO_MUX_SEL 0x0002 +#define AC97_CLOCK_DELAY_SEL 0x1F +#define AC97_DAC_CDS_SHIFT 6 +#define AC97_ADC_CDS_SHIFT 11 + +#define AC97_MULTI_CHANNEL_SEL 0x74 + +/*#define AC97_VENDOR_ID1 0x7C +#define AC97_VENDOR_ID2 0x7E*/ + +/* + * ASSP control regs + */ +#define DSP_PORT_TIMER_COUNT 0x06 + +#define DSP_PORT_MEMORY_INDEX 0x80 + +#define DSP_PORT_MEMORY_TYPE 0x82 +#define MEMTYPE_INTERNAL_CODE 0x0002 +#define MEMTYPE_INTERNAL_DATA 0x0003 +#define MEMTYPE_MASK 0x0003 + +#define DSP_PORT_MEMORY_DATA 0x84 + +#define DSP_PORT_CONTROL_REG_A 0xA2 +#define DSP_PORT_CONTROL_REG_B 0xA4 +#define DSP_PORT_CONTROL_REG_C 0xA6 + +#define REV_A_CODE_MEMORY_BEGIN 0x0000 +#define REV_A_CODE_MEMORY_END 0x0FFF +#define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040 +#define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1) + +#define REV_B_CODE_MEMORY_BEGIN 0x0000 +#define REV_B_CODE_MEMORY_END 0x0BFF +#define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040 +#define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1) + +#define REV_A_DATA_MEMORY_BEGIN 0x1000 +#define REV_A_DATA_MEMORY_END 0x2FFF +#define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080 +#define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1) + +#define REV_B_DATA_MEMORY_BEGIN 0x1000 +#define REV_B_DATA_MEMORY_END 0x2BFF +#define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080 +#define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1) + + +#define NUM_UNITS_KERNEL_CODE 16 +#define NUM_UNITS_KERNEL_DATA 2 + +#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16 +#define NUM_UNITS_KERNEL_DATA_WITH_HSP 5 + +/* + * Kernel data layout + */ + +#define DP_SHIFT_COUNT 7 + +#define KDATA_BASE_ADDR 0x1000 +#define KDATA_BASE_ADDR2 0x1080 + +#define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000) +#define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001) +#define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002) +#define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003) +#define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004) +#define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005) +#define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006) +#define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007) +#define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008) + +#define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009) +#define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A) + +#define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B) +#define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C) +#define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D) +#define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E) +#define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F) +#define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010) +#define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011) +#define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012) +#define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013) +#define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014) + +#define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015) +#define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016) + +#define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017) +#define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018) + +#define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019) +#define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A) + +#define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B) +#define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C) +#define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D) + +#define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E) +#define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F) +#define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020) +#define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021) +#define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022) + +#define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023) +#define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024) +#define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025) + +#define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026) +#define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027) +#define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028) + +#define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029) +#define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A) +#define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B) +#define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C) +#define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D) +#define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E) +#define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F) +#define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030) +#define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031) +#define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032) + +#define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033) +#define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034) +#define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035) + +#define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036) +#define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037) + +#define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038) +#define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039) +#define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A) + +#define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B) +#define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C) +#define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D) +#define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E) +#define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F) +#define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040) + +#define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041) +#define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042) +#define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043) +#define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044) +#define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045) +#define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046) + +#define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047) +#define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048) +#define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049) +#define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A) +#define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B) +#define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C) + +#define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D) +#define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E) +#define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F) +#define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050) + +#define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051) +#define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052) + +#define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053) +#define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054) + +#define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055) +#define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056) +#define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057) +#define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058) +#define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059) + +#define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A) +#define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B) + +#define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C) +#define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D) +#define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E) + +#define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F) +#define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060) + +#define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061) + +#define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062) +#define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063) +#define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064) +#define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065) +#define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066) +#define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067) +#define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068) +#define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069) +#define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A) +#define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B) +#define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C) +#define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D) + +#define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E) +#define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F) +#define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070) +#define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071) + +#define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072) +#define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073) + +#define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074) +#define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075) +#define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076) +#define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077) + +#define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078) +#define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079) +#define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A) +#define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B) +#define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C) + +/* + * second 'segment' (?) reserved for mixer + * buffers.. + */ + +#define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000) +#define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001) +#define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002) +#define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003) +#define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004) +#define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005) +#define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006) +#define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007) +#define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008) +#define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009) +#define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A) +#define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B) +#define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C) +#define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D) +#define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E) +#define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F) + +#define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010) +#define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011) +#define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012) +#define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013) +#define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014) +#define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015) +#define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016) +#define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017) +#define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018) +#define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019) +#define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A) + +#define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B) +#define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C) +#define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D) +#define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E) +#define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F) +#define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020) + +#define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC) +#define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0) +#define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0) +#define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0) + +/* + * client data area offsets + */ +#define CDATA_INSTANCE_READY 0x00 + +#define CDATA_HOST_SRC_ADDRL 0x01 +#define CDATA_HOST_SRC_ADDRH 0x02 +#define CDATA_HOST_SRC_END_PLUS_1L 0x03 +#define CDATA_HOST_SRC_END_PLUS_1H 0x04 +#define CDATA_HOST_SRC_CURRENTL 0x05 +#define CDATA_HOST_SRC_CURRENTH 0x06 + +#define CDATA_IN_BUF_CONNECT 0x07 +#define CDATA_OUT_BUF_CONNECT 0x08 + +#define CDATA_IN_BUF_BEGIN 0x09 +#define CDATA_IN_BUF_END_PLUS_1 0x0A +#define CDATA_IN_BUF_HEAD 0x0B +#define CDATA_IN_BUF_TAIL 0x0C +#define CDATA_OUT_BUF_BEGIN 0x0D +#define CDATA_OUT_BUF_END_PLUS_1 0x0E +#define CDATA_OUT_BUF_HEAD 0x0F +#define CDATA_OUT_BUF_TAIL 0x10 + +#define CDATA_DMA_CONTROL 0x11 +#define CDATA_RESERVED 0x12 + +#define CDATA_FREQUENCY 0x13 +#define CDATA_LEFT_VOLUME 0x14 +#define CDATA_RIGHT_VOLUME 0x15 +#define CDATA_LEFT_SUR_VOL 0x16 +#define CDATA_RIGHT_SUR_VOL 0x17 + +#define CDATA_HEADER_LEN 0x18 + +#define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN +#define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1) +#define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2) +#define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3) +#define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8) +#define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10) +#define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16) +#define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17) + +#define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 ) +#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) +#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) +#define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 ) +#define MINISRC_BIQUAD_STAGE 2 +#define MINISRC_COEF_LOC 0X175 + +#define DMACONTROL_BLOCK_MASK 0x000F +#define DMAC_BLOCK0_SELECTOR 0x0000 +#define DMAC_BLOCK1_SELECTOR 0x0001 +#define DMAC_BLOCK2_SELECTOR 0x0002 +#define DMAC_BLOCK3_SELECTOR 0x0003 +#define DMAC_BLOCK4_SELECTOR 0x0004 +#define DMAC_BLOCK5_SELECTOR 0x0005 +#define DMAC_BLOCK6_SELECTOR 0x0006 +#define DMAC_BLOCK7_SELECTOR 0x0007 +#define DMAC_BLOCK8_SELECTOR 0x0008 +#define DMAC_BLOCK9_SELECTOR 0x0009 +#define DMAC_BLOCKA_SELECTOR 0x000A +#define DMAC_BLOCKB_SELECTOR 0x000B +#define DMAC_BLOCKC_SELECTOR 0x000C +#define DMAC_BLOCKD_SELECTOR 0x000D +#define DMAC_BLOCKE_SELECTOR 0x000E +#define DMAC_BLOCKF_SELECTOR 0x000F +#define DMACONTROL_PAGE_MASK 0x00F0 +#define DMAC_PAGE0_SELECTOR 0x0030 +#define DMAC_PAGE1_SELECTOR 0x0020 +#define DMAC_PAGE2_SELECTOR 0x0010 +#define DMAC_PAGE3_SELECTOR 0x0000 +#define DMACONTROL_AUTOREPEAT 0x1000 +#define DMACONTROL_STOPPED 0x2000 +#define DMACONTROL_DIRECTION 0x0100 + + +/* + * DSP Code images + */ + +u16 assp_kernel_image[] = { + 0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4, + 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, + 0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, + 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4, + 0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08, + 0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909, + 0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41, + 0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308, + 0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910, + 0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00, + 0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026, + 0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0, + 0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012, + 0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A, + 0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000, + 0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05, + 0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26, + 0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300, + 0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88, + 0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008, + 0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80, + 0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71, + 0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A, + 0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100, + 0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900, + 0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903, + 0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309, + 0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B, + 0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540, + 0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C, + 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380, + 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340, + 0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041, + 0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18, + 0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, + 0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9, + 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8, + 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A, + 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80, + 0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, + 0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80, + 0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A, + 0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F, + 0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1, + 0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034, + 0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E, + 0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977, + 0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B, + 0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388, + 0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, + 0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473, + 0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473, + 0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880, + 0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80, + 0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6, + 0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909, + 0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED, + 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005, + 0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, + 0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4, + 0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, + 0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10, + 0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070, + 0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71, + 0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A, + 0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061, + 0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A, + 0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6, + 0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A, + 0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6, + 0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358, + 0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6, + 0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9, + 0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379, + 0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6, + 0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C, + 0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166, + 0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B, + 0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A, + 0xBE3A, +}; + +/* + * Mini sample rate converter code image + * that is to be loaded at 0x400 on the DSP. + */ +u16 assp_minisrc_image[] = { + + 0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412, + 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41, + 0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907, + 0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01, + 0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904, + 0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D, + 0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD, + 0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22, + 0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0, + 0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9, + 0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89, + 0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0, + 0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484, + 0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80, + 0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624, + 0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4, + 0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027, + 0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903, + 0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809, + 0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46, + 0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47, + 0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0, + 0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516, + 0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E, + 0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C, + 0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180, + 0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E, + 0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0, + 0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0, + 0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0, + 0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F, + 0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.2.18/drivers/sound/sonicvibes.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/sonicvibes.c Sun Mar 25 11:37:37 2001 @@ -77,11 +77,15 @@ * 24.08.1999 0.19 get rid of the dmaio kludge, replace with allocate_resource * 31.08.1999 0.20 add spin_lock_init * __initlocaldata to fix gcc 2.7.x problems - * use new resource allocation to allocate DDMA IO space * replaced current->state = x with set_current_state(x) * 03.09.1999 0.21 change read semantics for MIDI to match * OSS more closely; remove possible wakeup race * 28.10.1999 0.22 More waitqueue races fixed + * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun; + * Tim Janik's BSE (Bedevilled Sound Engine) found this + * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask + * 12.12.2000 0.28 More dma buffer initializations, patch from + * Tjeerd Mulder * */ @@ -1543,6 +1547,7 @@ unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int count; int val, mapped, ret; unsigned char fmtm, fmtd; @@ -1578,7 +1583,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -1594,7 +1600,8 @@ return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { @@ -1617,7 +1624,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { fmtd = 0; fmtm = ~0; @@ -1646,7 +1654,8 @@ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { fmtd = 0; fmtm = ~0; @@ -1683,7 +1692,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) @@ -1705,12 +1715,15 @@ case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!(s->enable & SV_CENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0) + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + count = s->dma_dac.count; + if (count < 0) + count = 0; + abinfo.bytes = s->dma_dac.dmasize - count; abinfo.fragstotal = s->dma_dac.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1719,12 +1732,15 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!(s->enable & SV_CENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0) + if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; + count = s->dma_adc.count; + if (count < 0) + count = 0; + abinfo.bytes = count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); @@ -1737,19 +1753,28 @@ case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); - val = s->dma_dac.count; + count = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *)arg); + if (count < 0) + count = 0; + return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; + if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + count = s->dma_adc.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1759,10 +1784,15 @@ case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; + if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) + return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + count = s->dma_dac.count; + if (count < 0) + count = 0; + cinfo.blocks = count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; @@ -1780,7 +1810,8 @@ return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -1807,7 +1838,8 @@ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -2432,7 +2464,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.22 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.28 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.2.18/drivers/sound/sound_core.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/sound_core.c Sun Mar 25 11:37:37 2001 @@ -52,6 +52,7 @@ struct sound_unit *next; }; +extern int init_cmpci(void); extern int init_sonicvibes(void); extern int init_maestro(void); extern int init_trident(void); @@ -63,7 +64,6 @@ extern int init_solo1(void); extern int init_ymf7xxsb_module(void); extern int cs_probe(void); -extern int init_emu10k1(void); extern int cs4281_probe(void); extern void init_vwsnd(void); extern int ymf_probe(void); @@ -396,6 +396,9 @@ /* * Now init non OSS drivers */ +#ifdef CONFIG_SOUND_CMPCI + init_cmpci(); +#endif #ifdef CONFIG_SOUND_VWSND init_vwsnd(); #endif @@ -411,6 +414,9 @@ #ifdef CONFIG_SOUND_MAESTRO init_maestro(); #endif +#ifdef CONFIG_SOUND_MAESTRO3 + init_maestro3(); +#endif #ifdef CONFIG_SOUND_TRIDENT init_trident(); #endif @@ -434,9 +440,6 @@ #endif #ifdef CONFIG_SOUND_CS4281 cs4281_probe(); -#endif -#ifdef CONFIG_SOUND_EMU10K1 - init_emu10k1(); #endif #ifdef CONFIG_SOUND_YMFPCI ymf_probe(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.2.18/drivers/sound/trident.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/trident.c Sun Mar 25 11:37:37 2001 @@ -2789,7 +2789,7 @@ u16 w; unsigned long iobase; struct trident_card *card; - + unsigned long flags; iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; if (check_region(iobase, 256)) { @@ -2882,10 +2882,17 @@ /* reset command */ while (inb(card->iobase + ALI_MPUR1) & 0x40); + + /* After the out the chip goes into irq jammed on + mode. We have to keep irqs off until it shuts up + again */ + save_flags(flags); + cli(); outb(0xff, card->iobase + ALI_MPUR1); while (inb(card->iobase + ALI_MPUR1) & 0x80); while ((inb(card->iobase + ALI_MPUR0) != 0xfe) && (inb(card->iobase+ALI_MPUR1) != 0x10)) while (inb(card->iobase + ALI_MPUR1) & 0x80); + restore_flags(flags); midi->ird = midi->iwr = midi->icnt = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/ymf_sb.c linux/drivers/sound/ymf_sb.c --- v2.2.18/drivers/sound/ymf_sb.c Sun Mar 25 11:13:05 2001 +++ linux/drivers/sound/ymf_sb.c Wed Dec 31 19:00:00 1969 @@ -1,995 +0,0 @@ -/* - Legacy audio driver for YMF724, 740, 744, 754 series. - Copyright 2000 Daisuke Nagano - - Based on the VIA 82Cxxx driver by Jeff Garzik - - Distribued under the GNU PUBLIC LICENSE (GPL) Version 2. - See the "COPYING" file distributed with kernel source tree for more info. - - ------------------------------------------------------------------------- - - It only supports SBPro compatible function of YMF7xx series s.t. - * 22.05kHz, 8-bit and stereo sample - * OPL3-compatible FM synthesizer - * MPU-401 compatible "external" MIDI interface - - and AC'97 mixer of these cards. - - ------------------------------------------------------------------------- - - Revision history - - Tue May 14 19:00:00 2000 0.0.1 - * initial release - - Tue May 16 19:29:29 2000 0.0.2 - - * add a little delays for reset devices. - * fixed addressing bug. - - Sun May 21 15:14:37 2000 0.0.3 - - * Add 'master_vol' module parameter to change 'PCM out Vol' of AC'97. - * remove native UART401 support. External MIDI port should be supported - by sb_midi driver. - * add support for SPDIF OUT. Module parameter 'spdif_out' is now available. - - Wed May 31 00:13:57 2000 0.0.4 - - * remove entries in Hwmcode.h. Now YMF744 / YMF754 sets instructions - in 724hwmcode.h. - * fixed wrong legacy_io setting on YMF744/YMF754 . - - Sat Jun 3 23:44:08 2000 0.0.5 - - * correct all return value -1 to appropriate -E* value. - * add pci_enable_device() for linux-2.3.x. - - Sat Jun 7 00:17:32 2000 0.1.0 - - * Remove SBPro mixer support. - * Added AC'97 mixer support and remove option 'master_volume'. - * Correct all separated valuables into struct ymf_cards. - - Mon Jun 12 21:36:50 2000 0.1.1 - - * Invalid dma setting fixed. - -- John A. Boyd Jr. - - * ymfsb only compiled as module: fixed - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sound_config.h" -#include "soundmodule.h" -#include "sb.h" -#include "724hwmcode.h" - -#include "ac97.h" - -#undef YMF_DEBUG - -/* ---------------------------------------------------------------------- */ - -#ifndef SOUND_LOCK -# define SOUND_LOCK do {} while (0) -# define SOUND_LOCK_END do {} while (0) -#endif - -#ifndef PCI_VENDOR_ID_YAMAHA -# define PCI_VENDOR_ID_YAMAHA 0x1073 -#endif -#ifndef PCI_DEVICE_ID_YMF724 -# define PCI_DEVICE_ID_YMF724 0x0004 -#endif -#ifndef PCI_DEVICE_ID_YMF740 -# define PCI_DEVICE_ID_YMF740 0x000A -#endif -#ifndef PCI_DEVICE_ID_YMF740C -# define PCI_DEVICE_ID_YMF740C 0x000C -#endif -#ifndef PCI_DEVICE_ID_YMF724F -# define PCI_DEVICE_ID_YMF724F 0x000D -#endif -#ifndef PCI_DEVICE_ID_YMF744 -# define PCI_DEVICE_ID_YMF744 0x0010 -#endif -#ifndef PCI_DEVICE_ID_YMF754 -# define PCI_DEVICE_ID_YMF754 0x0012 -#endif - -/* ---------------------------------------------------------------------- */ - -#define YMFSB_RESET_DELAY 5 - -#define YMFSB_REGSIZE 0x8000 - -#define YMFSB_AC97TIMEOUT 2000 - -#define YMFSB_WORKBITTIMEOUT 250000 - -#define YMFSB_DSPLENGTH 0x0080 -#define YMFSB_CTRLLENGTH 0x3000 - -#define YMFSB_PCIR_VENDORID 0x00 -#define YMFSB_PCIR_DEVICEID 0x02 -#define YMFSB_PCIR_CMD 0x04 -#define YMFSB_PCIR_REVISIONID 0x08 -#define YMFSB_PCIR_BASEADDR 0x10 -#define YMFSB_PCIR_IRQ 0x3c - -#define YMFSB_PCIR_LEGCTRL 0x40 -#define YMFSB_PCIR_ELEGCTRL 0x42 -#define YMFSB_PCIR_DSXGCTRL 0x48 -#define YMFSB_PCIR_OPLADR 0x60 -#define YMFSB_PCIR_SBADR 0x62 -#define YMFSB_PCIR_MPUADR 0x64 - -#define YMFSB_INTFLAG 0x0004 -#define YMFSB_ACTIVITY 0x0006 -#define YMFSB_GLOBALCTRL 0x0008 -#define YMFSB_ZVCTRL 0x000A -#define YMFSB_TIMERCTRL 0x0010 -#define YMFSB_TIMERCOUNT 0x0012 -#define YMFSB_SPDIFOUTCTRL 0x0018 -#define YMFSB_SPDIFOUTSTATUS 0x001C -#define YMFSB_EEPROMCTRL 0x0020 -#define YMFSB_SPDIFINCTRL 0x0034 -#define YMFSB_SPDIFINSTATUS 0x0038 -#define YMFSB_DSPPROGRAMDL 0x0048 -#define YMFSB_DLCNTRL 0x004C -#define YMFSB_GPIOININTFLAG 0x0050 -#define YMFSB_GPIOININTENABLE 0x0052 -#define YMFSB_GPIOINSTATUS 0x0054 -#define YMFSB_GPIOOUTCTRL 0x0056 -#define YMFSB_GPIOFUNCENABLE 0x0058 -#define YMFSB_GPIOTYPECONFIG 0x005A -#define YMFSB_AC97CMDDATA 0x0060 -#define YMFSB_AC97CMDADR 0x0062 -#define YMFSB_PRISTATUSDATA 0x0064 -#define YMFSB_PRISTATUSADR 0x0066 -#define YMFSB_SECSTATUSDATA 0x0068 -#define YMFSB_SECSTATUSADR 0x006A -#define YMFSB_SECCONFIG 0x0070 -#define YMFSB_LEGACYOUTVOL 0x0080 -#define YMFSB_LEGACYOUTVOLL 0x0080 -#define YMFSB_LEGACYOUTVOLR 0x0082 -#define YMFSB_NATIVEDACOUTVOL 0x0084 -#define YMFSB_NATIVEDACOUTVOLL 0x0084 -#define YMFSB_NATIVEDACOUTVOLR 0x0086 -#define YMFSB_SPDIFOUTVOL 0x0088 -#define YMFSB_SPDIFOUTVOLL 0x0088 -#define YMFSB_SPDIFOUTVOLR 0x008A -#define YMFSB_AC3OUTVOL 0x008C -#define YMFSB_AC3OUTVOLL 0x008C -#define YMFSB_AC3OUTVOLR 0x008E -#define YMFSB_PRIADCOUTVOL 0x0090 -#define YMFSB_PRIADCOUTVOLL 0x0090 -#define YMFSB_PRIADCOUTVOLR 0x0092 -#define YMFSB_LEGACYLOOPVOL 0x0094 -#define YMFSB_LEGACYLOOPVOLL 0x0094 -#define YMFSB_LEGACYLOOPVOLR 0x0096 -#define YMFSB_NATIVEDACLOOPVOL 0x0098 -#define YMFSB_NATIVEDACLOOPVOLL 0x0098 -#define YMFSB_NATIVEDACLOOPVOLR 0x009A -#define YMFSB_SPDIFLOOPVOL 0x009C -#define YMFSB_SPDIFLOOPVOLL 0x009E -#define YMFSB_SPDIFLOOPVOLR 0x009E -#define YMFSB_AC3LOOPVOL 0x00A0 -#define YMFSB_AC3LOOPVOLL 0x00A0 -#define YMFSB_AC3LOOPVOLR 0x00A2 -#define YMFSB_PRIADCLOOPVOL 0x00A4 -#define YMFSB_PRIADCLOOPVOLL 0x00A4 -#define YMFSB_PRIADCLOOPVOLR 0x00A6 -#define YMFSB_NATIVEADCINVOL 0x00A8 -#define YMFSB_NATIVEADCINVOLL 0x00A8 -#define YMFSB_NATIVEADCINVOLR 0x00AA -#define YMFSB_NATIVEDACINVOL 0x00AC -#define YMFSB_NATIVEDACINVOLL 0x00AC -#define YMFSB_NATIVEDACINVOLR 0x00AE -#define YMFSB_BUF441OUTVOL 0x00B0 -#define YMFSB_BUF441OUTVOLL 0x00B0 -#define YMFSB_BUF441OUTVOLR 0x00B2 -#define YMFSB_BUF441LOOPVOL 0x00B4 -#define YMFSB_BUF441LOOPVOLL 0x00B4 -#define YMFSB_BUF441LOOPVOLR 0x00B6 -#define YMFSB_SPDIFOUTVOL2 0x00B8 -#define YMFSB_SPDIFOUTVOL2L 0x00B8 -#define YMFSB_SPDIFOUTVOL2R 0x00BA -#define YMFSB_SPDIFLOOPVOL2 0x00BC -#define YMFSB_SPDIFLOOPVOL2L 0x00BC -#define YMFSB_SPDIFLOOPVOL2R 0x00BE -#define YMFSB_ADCSLOTSR 0x00C0 -#define YMFSB_RECSLOTSR 0x00C4 -#define YMFSB_ADCFORMAT 0x00C8 -#define YMFSB_RECFORMAT 0x00CC -#define YMFSB_P44SLOTSR 0x00D0 -#define YMFSB_STATUS 0x0100 -#define YMFSB_CTRLSELECT 0x0104 -#define YMFSB_MODE 0x0108 -#define YMFSB_SAMPLECOUNT 0x010C -#define YMFSB_NUMOFSAMPLES 0x0110 -#define YMFSB_CONFIG 0x0114 -#define YMFSB_PLAYCTRLSIZE 0x0140 -#define YMFSB_RECCTRLSIZE 0x0144 -#define YMFSB_EFFCTRLSIZE 0x0148 -#define YMFSB_WORKSIZE 0x014C -#define YMFSB_MAPOFREC 0x0150 -#define YMFSB_MAPOFEFFECT 0x0154 -#define YMFSB_PLAYCTRLBASE 0x0158 -#define YMFSB_RECCTRLBASE 0x015C -#define YMFSB_EFFCTRLBASE 0x0160 -#define YMFSB_WORKBASE 0x0164 -#define YMFSB_DSPINSTRAM 0x1000 -#define YMFSB_CTRLINSTRAM 0x4000 - - -/* ---------------------------------------------------------------------- */ - -#define MAX_CARDS 4 - -#define PFX "ymf_sb: " - -#define YMFSB_VERSION "0.1.1" -#define YMFSB_CARD_NAME "YMF7xx Legacy Audio driver " YMFSB_VERSION - -#define ymf7xxsb_probe_midi probe_sbmpu -#define ymf7xxsb_attach_midi attach_sbmpu -#define ymf7xxsb_unload_midi unload_sbmpu - -/* ---------------------------------------------------------------------- */ - -static struct ymf_card { - int card; - unsigned short *ymfbase; - - struct address_info sb_data, opl3_data, mpu_data; - - struct ac97_hwint ac97_dev; - int mixer_oss_dev; -} ymf_cards[MAX_CARDS]; - -static unsigned int cards = 0; - -/* ---------------------------------------------------------------------- */ - -#ifdef MODULE -static int mpu_io = 0; -static int synth_io = 0; -static int io = 0; -static int dma = 0; -static int spdif_out = 1; -MODULE_PARM(mpu_io, "i"); -MODULE_PARM(synth_io, "i"); -MODULE_PARM(io,"i"); -MODULE_PARM(dma,"i"); -MODULE_PARM(spdif_out,"i"); -#else -static int mpu_io = 0x330; -static int synth_io = 0x388; -static int io = 0x220; -static int dma = 1; -static int spdif_out = 1; -#endif - -/* ---------------------------------------------------------------------- */ - -static int readRegWord( struct ymf_card *card, int adr ) { - - if (card->ymfbase==NULL) return 0; - - return readw(card->ymfbase+adr/2); -} - -static void writeRegWord( struct ymf_card *card, int adr, int val ) { - - if (card->ymfbase==NULL) return; - - writew((unsigned short)(val&0xffff), card->ymfbase + adr/2); - - return; -} - -static int readRegDWord( struct ymf_card *card, int adr ) { - - if (card->ymfbase==NULL) return 0; - - return (readl(card->ymfbase+adr/2)); -} - -static void writeRegDWord( struct ymf_card *card, int adr, int val ) { - - if (card->ymfbase==NULL) return; - - writel((unsigned int)(val&0xffffffff), card->ymfbase+adr/2); - - return; -} - -/* ---------------------------------------------------------------------- */ - -static int checkPrimaryBusy( struct ymf_card *card ) -{ - int timeout=0; - - while ( timeout++ < YMFSB_AC97TIMEOUT ) - { - if ( (readRegWord(card, YMFSB_PRISTATUSADR) & 0x8000) == 0x0000 ) - return 0; - } - return -EBUSY; -} - -static int checkCodec( struct ymf_card *card, struct pci_dev *pcidev ) -{ - u8 tmp8; - - pci_read_config_byte( pcidev, YMFSB_PCIR_DSXGCTRL, &tmp8 ); - if ( tmp8 & 0x03 ) { - pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc); - mdelay(YMFSB_RESET_DELAY); - pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8|0x03); - mdelay(YMFSB_RESET_DELAY); - pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc); - mdelay(YMFSB_RESET_DELAY); - } - - if ( checkPrimaryBusy( card ) ) return -EBUSY; - - return 0; -} - -static int setupLegacyIO( struct ymf_card *card, struct pci_dev *pcidev ) -{ - int v; - int sbio=0, mpuio=0, oplio=0,dma=0; - - switch(card->sb_data.io_base) { - case 0x220: - sbio = 0; - break; - case 0x240: - sbio = 1; - break; - case 0x260: - sbio = 2; - break; - case 0x280: - sbio = 3; - break; - default: - return -EINVAL; - break; - } -#ifdef YMF_DEBUG - printk(PFX "set SBPro I/O at 0x%x\n",card->sb_data.io_base); -#endif - - switch(card->mpu_data.io_base) { - case 0x330: - mpuio = 0; - break; - case 0x300: - mpuio = 1; - break; - case 0x332: - mpuio = 2; - break; - case 0x334: - mpuio = 3; - break; - default: - mpuio = 0; - break; - } -#ifdef YMF_DEBUG - printk(PFX "set MPU401 I/O at 0x%x\n",card->mpu_data.io_base); -#endif - - switch(card->opl3_data.io_base) { - case 0x388: - oplio = 0; - break; - case 0x398: - oplio = 1; - break; - case 0x3a0: - oplio = 2; - break; - case 0x3a8: - oplio = 3; - break; - default: - return -EINVAL; - break; - } -#ifdef YMF_DEBUG - printk(PFX "set OPL3 I/O at 0x%x\n",card->opl3_data.io_base); -#endif - - dma = card->sb_data.dma; -#ifdef YMF_DEBUG - printk(PFX "set DMA address at 0x%x\n",card->sb_data.dma); -#endif - - v = 0x0000 | ((dma&0x03)<<6) | 0x003f; - pci_write_config_word(pcidev, YMFSB_PCIR_LEGCTRL, v); -#ifdef YMF_DEBUG - printk(PFX "LEGCTRL: 0x%x\n",v); -#endif - switch( pcidev->device ) { - case PCI_DEVICE_ID_YMF724: - case PCI_DEVICE_ID_YMF740: - case PCI_DEVICE_ID_YMF724F: - case PCI_DEVICE_ID_YMF740C: - v = 0x8800 | ((mpuio<<4)&0x03) | ((sbio<<2)&0x03) | (oplio&0x03); - pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v); -#ifdef YMF_DEBUG - printk(PFX "ELEGCTRL: 0x%x\n",v); -#endif - break; - - case PCI_DEVICE_ID_YMF744: - case PCI_DEVICE_ID_YMF754: - v = 0x8800; - pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v); - pci_write_config_word(pcidev, YMFSB_PCIR_OPLADR, card->opl3_data.io_base); - pci_write_config_word(pcidev, YMFSB_PCIR_SBADR, card->sb_data.io_base); - pci_write_config_word(pcidev, YMFSB_PCIR_MPUADR, card->mpu_data.io_base); - break; - - default: - printk(KERN_ERR PFX "Invalid device ID: %d\n",pcidev->device); - return -EINVAL; - break; - } - - return 0; -} - -/* ---------------------------------------------------------------------- */ -/* AC'97 stuff */ -static int ymfsb_readAC97Reg( struct ac97_hwint *dev, u8 reg ) -{ - struct ymf_card *card = (struct ymf_card *)dev->driver_private; - unsigned long flags; - int ret; - - if ( reg > 0x7f ) return -EINVAL; - - save_flags(flags); - cli(); - writeRegWord( card, YMFSB_AC97CMDADR, 0x8000 | reg ); - if ( checkPrimaryBusy( card ) ) { - restore_flags(flags); - return -EBUSY; - } - ret = readRegWord( card, YMFSB_AC97CMDDATA ); - restore_flags(flags); - - return ret; -} - -static int ymfsb_writeAC97Reg( struct ac97_hwint *dev, u8 reg, u16 value ) -{ - struct ymf_card *card = (struct ymf_card *)dev->driver_private; - unsigned long flags; - - if ( reg > 0x7f ) return -EINVAL; - - save_flags(flags); - cli(); - if ( checkPrimaryBusy( card ) ) { - restore_flags(flags); - return -EBUSY; - } - - writeRegWord( card, YMFSB_AC97CMDADR, 0x0000 | reg ); - writeRegWord( card, YMFSB_AC97CMDDATA, value ); - - restore_flags(flags); - return 0; -} - -struct initialValues -{ - unsigned short port; - unsigned short value; -}; - -static struct initialValues ymfsb_ac97_initial_values[] = -{ - { AC97_RESET, 0x0000 }, - { AC97_MASTER_VOL_STEREO, 0x0000 }, - { AC97_HEADPHONE_VOL, 0x8000 }, - { AC97_PCMOUT_VOL, 0x0606 }, - { AC97_MASTER_VOL_MONO, 0x0000 }, - { AC97_PCBEEP_VOL, 0x0000 }, - { AC97_PHONE_VOL, 0x0008 }, - { AC97_MIC_VOL, 0x8000 }, - { AC97_LINEIN_VOL, 0x8808 }, - { AC97_CD_VOL, 0x8808 }, - { AC97_VIDEO_VOL, 0x8808 }, - { AC97_AUX_VOL, 0x8808 }, - { AC97_RECORD_SELECT, 0x0000 }, - { AC97_RECORD_GAIN, 0x0B0B }, - { AC97_GENERAL_PURPOSE, 0x0000 }, - { 0xffff, 0xffff } -}; - -static int ymfsb_resetAC97( struct ac97_hwint *dev ) -{ - int i; - - for ( i=0 ; ymfsb_ac97_initial_values[i].port != 0xffff ; i++ ) - { - ac97_put_register ( dev, - ymfsb_ac97_initial_values[i].port, - ymfsb_ac97_initial_values[i].value ); - } - - return 0; -} - -static int ymfsb_ac97_mixer_ioctl( int dev, unsigned int cmd, caddr_t arg ) -{ - int i; - - for ( i=0 ; i < MAX_CARDS ; i++ ) - { - if ( ymf_cards[i].mixer_oss_dev == dev ) break; - } - - if ( i < MAX_CARDS ) - return ac97_mixer_ioctl(&(ymf_cards[i].ac97_dev), cmd, arg); - else - return -ENODEV; -} - -static struct mixer_operations ymfsb_ac97_mixer_operations = { - "YAMAHA", - "YAMAHA PCI", - ymfsb_ac97_mixer_ioctl -}; - -static struct ac97_mixer_value_list ymfsb_ac97_mixer_defaults[] = { - { SOUND_MIXER_VOLUME, { { 85, 85 } } }, - { SOUND_MIXER_SPEAKER, { { 100 } } }, - { SOUND_MIXER_PCM, { { 65, 65 } } }, - { SOUND_MIXER_CD, { { 65, 65 } } }, - { -1, { { 0, 0 } } } -}; - -/* ---------------------------------------------------------------------- */ - -static void enableDSP( struct ymf_card *card ) -{ - writeRegDWord( card, YMFSB_CONFIG, 0x00000001 ); - return; -} - -static void disableDSP( struct ymf_card *card ) -{ - int val; - int i; - - val = readRegDWord( card, YMFSB_CONFIG ); - if ( val ) { - writeRegDWord( card, YMFSB_CONFIG, 0 ); - } - - i=0; - while( ++i < YMFSB_WORKBITTIMEOUT ) { - val = readRegDWord( card, YMFSB_STATUS ); - if ( (val & 0x00000002) == 0x00000000 ) break; - } - - return; -} - -static int setupInstruction( struct ymf_card *card, struct pci_dev *pcidev ) -{ - int i; - int val; - - writeRegDWord( card, YMFSB_NATIVEDACOUTVOL, 0 ); /* mute dac */ - disableDSP( card ); - - writeRegDWord( card, YMFSB_MODE, 0x00010000 ); - - /* DS-XG Software Reset */ - writeRegDWord( card, YMFSB_MODE, 0x00000000 ); - writeRegDWord( card, YMFSB_MAPOFREC, 0x00000000 ); - writeRegDWord( card, YMFSB_MAPOFEFFECT, 0x00000000 ); - writeRegDWord( card, YMFSB_PLAYCTRLBASE, 0x00000000 ); - writeRegDWord( card, YMFSB_RECCTRLBASE, 0x00000000 ); - writeRegDWord( card, YMFSB_EFFCTRLBASE, 0x00000000 ); - - val = readRegWord( card, YMFSB_GLOBALCTRL ); - writeRegWord( card, YMFSB_GLOBALCTRL, (val&~0x0007) ); - - /* setup DSP instruction code */ - for ( i=0 ; i>2] ); - } - - switch( pcidev->device ) { - case PCI_DEVICE_ID_YMF724: - case PCI_DEVICE_ID_YMF740: - /* setup Control instruction code */ - for ( i=0 ; i>2] ); - } - break; - - case PCI_DEVICE_ID_YMF724F: - case PCI_DEVICE_ID_YMF740C: - case PCI_DEVICE_ID_YMF744: - case PCI_DEVICE_ID_YMF754: - /* setup Control instruction code */ - - for ( i=0 ; i>2] ); - } - break; - - default: - return -ENXIO; - } - - enableDSP( card ); - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static int __init ymf7xx_init( struct ymf_card *card, struct pci_dev *pcidev ) -{ - unsigned short v; - int mixer; - - /* Read hardware information */ -#ifdef YMF_DEBUG - unsigned int dv; - pci_read_config_word(pcidev, YMFSB_PCIR_VENDORID, &v); - printk(KERN_INFO PFX "Vendor ID = 0x%x\n",v); - pci_read_config_word(pcidev, YMFSB_PCIR_DEVICEID, &v); - printk(KERN_INFO PFX "Device ID = 0x%x\n",v); - pci_read_config_word(pcidev, YMFSB_PCIR_REVISIONID, &v); - printk(KERN_INFO PFX "Revision ID = 0x%x\n",v&0xff); - pci_read_config_dword(pcidev, YMFSB_PCIR_BASEADDR, &dv); - printk(KERN_INFO PFX "Base address = 0x%x\n",dv); - pci_read_config_word(pcidev, YMFSB_PCIR_IRQ, &v); - printk(KERN_INFO PFX "IRQ line = 0x%x\n",v&0xff); -#endif - - /* enables memory space access / bus mastering */ - pci_read_config_word(pcidev, YMFSB_PCIR_CMD, &v); - pci_write_config_word(pcidev, YMFSB_PCIR_CMD, v|0x06); - - /* check codec */ -#ifdef YMF_DEBUG - printk(KERN_INFO PFX "check codec...\n"); -#endif - if (checkCodec(card, pcidev)) return -EBUSY; - - /* setup legacy I/O */ -#ifdef YMF_DEBUG - printk(KERN_INFO PFX "setup legacy I/O...\n"); -#endif - if (setupLegacyIO(card, pcidev)) return -EBUSY; - - /* setup instruction code */ -#ifdef YMF_DEBUG - printk(KERN_INFO PFX "setup instructions...\n"); -#endif - if (setupInstruction(card, pcidev)) return -EBUSY; - - /* AC'97 setup */ -#ifdef YMF_DEBUG - printk(KERN_INFO PFX "setup AC'97...\n"); -#endif - if ( ac97_init( &card->ac97_dev ) ) return -EBUSY; - - mixer = sound_alloc_mixerdev(); - if ( num_mixers >= MAX_MIXER_DEV ) return -EBUSY; - - mixer_devs[mixer] = &ymfsb_ac97_mixer_operations; - card->mixer_oss_dev = mixer; - ac97_set_values( &card->ac97_dev, ymfsb_ac97_mixer_defaults ); - -#ifdef YMF_DEBUG - printk(KERN_INFO PFX "setup Legacy Volume...\n"); -#endif - /* Legacy Audio Output Volume L & R ch */ - writeRegDWord( card, YMFSB_LEGACYOUTVOL, 0x3fff3fff ); - -#ifdef YMF_DEBUG - printk(KERN_INFO PFX "setup SPDIF output control...\n"); -#endif - /* SPDIF Output control */ - v = spdif_out != 0 ? 0x0001 : 0x0000; - writeRegWord( card, YMFSB_SPDIFOUTCTRL, v ); - /* no copyright protection, - sample-rate converted, - re-recorded software comercially available (the 1st generation), - original */ - writeRegWord( card, YMFSB_SPDIFOUTSTATUS, 0x9a04 ); - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static void __init ymf7xxsb_attach_sb(struct address_info *hw_config) -{ - hw_config->driver_use_1 |= SB_NO_MIXER; - if(!sb_dsp_init(hw_config)) - hw_config->slots[0] = -1; -} - -static int __init ymf7xxsb_probe_sb(struct address_info *hw_config) -{ - if (check_region(hw_config->io_base, 16)) - { - printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n", - hw_config->io_base); - return 0; - } - return sb_dsp_detect(hw_config, SB_PCI_YAMAHA, 0); -} - - -static void ymf7xxsb_unload_sb(struct address_info *hw_config, int unload_mpu) -{ - if(hw_config->slots[0]!=-1) - sb_dsp_unload(hw_config, unload_mpu); -} - -/* ---------------------------------------------------------------------- */ - -static int __init ymf7xxsb_install (struct pci_dev *pcidev) -{ - struct { - unsigned short deviceid; - char *devicename; - } devicetable[] = - { - { PCI_DEVICE_ID_YMF724, "YMF724A-E" }, - { PCI_DEVICE_ID_YMF724F, "YMF724F" }, - { PCI_DEVICE_ID_YMF740, "YMF740A-B" }, - { PCI_DEVICE_ID_YMF740C, "YMF740C" }, - { PCI_DEVICE_ID_YMF744, "YMF744" }, - { PCI_DEVICE_ID_YMF754, "YMF754" }, - }; - - char *devicename = "unknown"; - int i; - unsigned long iobase; - struct ymf_card *card; - - if ( pcidev->irq == 0 ) return -ENODEV; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - if ( pci_enable_device(pcidev) ) { - printk (KERN_ERR PFX "cannot enable PCI device\n"); - return -EIO; - } -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) - iobase = pcidev->base_address[0]&PCI_BASE_ADDRESS_MEM_MASK; -#else - iobase = pcidev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK; -#endif - if ( iobase == 0x00000000 ) return -ENODEV; - - for ( i=0 ; idevice) - { - devicename = devicetable[i].devicename; - break; - } - } - - card = &ymf_cards[cards]; - - /* remap memory mapped I/O onto kernel virtual memory */ - if ( (card->ymfbase = ioremap_nocache(iobase, YMFSB_REGSIZE)) == 0 ) - { - printk(KERN_ERR PFX "ioremap (0x%lx) returns zero\n", iobase); - return -ENODEV; - } - printk(KERN_INFO PFX "found %s at 0x%lx\n", devicename, iobase); -#ifdef YMF_DEBUG - printk(KERN_INFO PFX "remappling to 0x%p\n", card->ymfbase); -#endif - - memset (&card->sb_data, 0, sizeof (struct address_info)); - memset (&card->opl3_data, 0, sizeof (struct address_info)); - memset (&card->mpu_data, 0, sizeof (struct address_info)); - memset (&card->ac97_dev, 0, sizeof (struct ac97_hwint)); - - card->card = cards; - - card->sb_data.name = YMFSB_CARD_NAME; - card->opl3_data.name = YMFSB_CARD_NAME; - card->mpu_data.name = YMFSB_CARD_NAME; - - card->sb_data.card_subtype = MDL_YMPCI; - - if ( io == 0 ) io = 0x220; - card->sb_data.io_base = io; - card->sb_data.irq = pcidev->irq; - card->sb_data.dma = dma; - - if ( synth_io == 0 ) synth_io = 0x388; - card->opl3_data.io_base = synth_io; - card->opl3_data.irq = -1; - - if ( mpu_io == 0 ) mpu_io = 0x330; - card->mpu_data.io_base = mpu_io; - card->mpu_data.irq = -1; - - card->ac97_dev.reset_device = ymfsb_resetAC97; - card->ac97_dev.read_reg = ymfsb_readAC97Reg; - card->ac97_dev.write_reg = ymfsb_writeAC97Reg; - card->ac97_dev.driver_private = (void *)card; - - if ( ymf7xx_init(card, pcidev) ) { - printk (KERN_ERR PFX - "Cannot initialize %s, aborting\n", - devicename); - return -ENODEV; - } - - /* regist legacy SoundBlaster Pro */ - if (!ymf7xxsb_probe_sb(&card->sb_data)) { - printk (KERN_ERR PFX - "SB probe at 0x%X failed, aborting\n", - io); - return -ENODEV; - } - ymf7xxsb_attach_sb (&card->sb_data); - - /* regist legacy MIDI */ - if ( mpu_io > 0 && 0) - { - if (!ymf7xxsb_probe_midi (&card->mpu_data)) { - printk (KERN_ERR PFX - "MIDI probe @ 0x%X failed, aborting\n", - mpu_io); - ymf7xxsb_unload_sb (&card->sb_data, 0); - return -ENODEV; - } - ymf7xxsb_attach_midi (&card->mpu_data); - } - - /* regist legacy OPL3 */ - - cards++; - return 0; -} - -static int __init probe_ymf7xxsb (void) -{ - struct pci_dev *pcidev = NULL; - int i; - - for (i=0 ; i= 0 ) - sound_unload_mixerdev( ymf_cards[i].mixer_oss_dev ); - } - - free_iomaps(); - - /* - * Final clean up with the sound layer - */ - SOUND_LOCK_END; -} - -#ifdef MODULE - -MODULE_AUTHOR("Daisuke Nagano, breeze.nagano@nifty.ne.jp"); -MODULE_DESCRIPTION("YMF7xx Legacy Audio Driver"); - -int init_module(void) -{ - return init_ymf7xxsb_module(); -} - -void cleanup_module(void) -{ - cleanup_ymf7xxsb_module(); -} - -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c --- v2.2.18/drivers/sound/ymfpci.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/ymfpci.c Sun Mar 25 11:37:37 2001 @@ -46,6 +46,9 @@ #include #include +#ifdef CONFIG_SOUND_YMFPCI_LEGACY +# include "sound_config.h" +#endif #include "ymfpci.h" #define snd_magic_cast(t, p, err) ((t *)(p)) @@ -59,7 +62,7 @@ int pair, ymfpci_voice_t **rvoice); static int ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice); static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state); -static int ymf_state_alloc(ymfpci_t *unit, int nvirt, int instance); +static int ymf_state_alloc(ymfpci_t *unit, int nvirt); static ymfpci_t *ymf_devs = NULL; @@ -600,11 +603,9 @@ char silence; if ((ypcm = voice->ypcm) == NULL) { -/* P3 */ printk("ymf_pcm_interrupt: voice %d: no ypcm\n", voice->number); return; } if ((state = ypcm->state) == NULL) { -/* P3 */ printk("ymf_pcm_interrupt: voice %d: no state\n", voice->number); ypcm->running = 0; // lock it return; } @@ -626,7 +627,7 @@ if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */ printk(KERN_ERR "ymfpci%d: %d: runaway: hwptr %d dmasize %d\n", - codec->inst, voice->number, + codec->dev_audio, voice->number, dmabuf->hwptr, dmabuf->dmasize); pos = 0; } @@ -643,7 +644,7 @@ if (dmabuf->count == 0) { printk("ymfpci%d: %d: strain: hwptr %d\n", - codec->inst, voice->number, dmabuf->hwptr); + codec->dev_audio, voice->number, dmabuf->hwptr); ymf_playback_trigger(codec, ypcm, 0); } @@ -662,7 +663,7 @@ */ printk("ymfpci%d: %d: lost: delta %d" " hwptr %d swptr %d distance %d count %d\n", - codec->inst, voice->number, delta, + codec->dev_audio, voice->number, delta, dmabuf->hwptr, swptr, distance, dmabuf->count); } else { /* @@ -670,7 +671,7 @@ */ // printk("ymfpci%d: %d: done: delta %d" // " hwptr %d swptr %d distance %d count %d\n", -// codec->inst, voice->number, delta, +// codec->dev_audio, voice->number, delta, // dmabuf->hwptr, swptr, distance, dmabuf->count); } played = dmabuf->count; @@ -736,7 +737,6 @@ { if (ypcm->voices[0] == NULL) { -/* P3 */ printk("ymfpci: trigger %d no voice\n", cmd); return -EINVAL; } if (cmd != 0) { @@ -826,8 +826,8 @@ end >>= 1; if (w_16) end >>= 1; -/* P3 */ // printk("ymf_pcm_init_voice: %d: Rate %d Format 0x%08x Delta 0x%x End 0x%x\n", -// voice->number, rate, format, delta, end); +/* P3 */ /** printk("ymf_pcm_init_voice: %d: Rate %d Format 0x%08x Delta 0x%x End 0x%x\n", + voice->number, rate, format, delta, end); **/ for (nbank = 0; nbank < 2; nbank++) { bank = &voice->bank[nbank]; bank->format = format; @@ -909,7 +909,7 @@ if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) { /* Cannot be unless we leak voices in ymf_release! */ printk(KERN_ERR "ymfpci%d: cannot allocate voice!\n", - codec->inst); + codec->dev_audio); return err; } @@ -1027,6 +1027,12 @@ if (voice->interrupt) voice->interrupt(codec, voice); } +#if HAVE_RECORD + for (nvoice = 0; nvoice < 5; nvoice++) { + if (codec->capture_substream[nvoice]) + snd_ymfpci_pcm_capture_interrupt(codec->capture_substream[nvoice]); + } +#endif spin_unlock(&codec->voice_lock); } @@ -1050,7 +1056,7 @@ } } -static int ymf_state_alloc(ymfpci_t *unit, int nvirt, int instance) +static int ymf_state_alloc(ymfpci_t *unit, int nvirt) { ymfpci_pcm_t *ypcm; struct ymf_state *state; @@ -1536,12 +1542,13 @@ return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_RESET: - /* FIXME: spin_lock ? */ if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); + // spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; + // spin_unlock_irqrestore(&state->unit->reg_lock, flags); } #if HAVE_RECORD if (file->f_mode & FMODE_READ) { @@ -1570,9 +1577,7 @@ case SNDCTL_DSP_SPEED: /* set smaple rate */ get_user_ret(val, (int *)arg, -EFAULT); - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SPEED %d\n", val); */ if (val >= 8000 && val <= 48000) { - spin_lock_irqsave(&state->unit->reg_lock, flags); if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); } @@ -1581,6 +1586,7 @@ stop_adc(state); } #endif + spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; state->format.rate = val; ymf_pcm_update_shift(&state->format); @@ -1596,7 +1602,6 @@ */ case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ get_user_ret(val, (int *)arg, -EFAULT); - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_STEREO %d\n", val); */ if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); spin_lock_irqsave(&state->unit->reg_lock, flags); @@ -1618,7 +1623,6 @@ return 0; case SNDCTL_DSP_GETBLKSIZE: - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETBLKSIZE\n"); */ if (file->f_mode & FMODE_WRITE) { if ((val = prog_dmabuf(state, 0))) return val; @@ -1632,14 +1636,11 @@ return -EINVAL; case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETFMTS\n"); */ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ get_user_ret(val, (int *)arg, -EFAULT); - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SETFMT 0x%x\n", val); */ if (val == AFMT_S16_LE || val == AFMT_U8) { - spin_lock_irqsave(&state->unit->reg_lock, flags); if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); } @@ -1648,6 +1649,7 @@ stop_adc(state); } #endif + spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; state->format.format = val; ymf_pcm_update_shift(&state->format); @@ -1657,15 +1659,15 @@ case SNDCTL_DSP_CHANNELS: get_user_ret(val, (int *)arg, -EFAULT); - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_CHANNELS 0x%x\n", val); */ if (val != 0) { - spin_lock_irqsave(&state->unit->reg_lock, flags); if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); if (val == 1 || val == 2) { + spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->ready = 0; state->format.voices = val; ymf_pcm_update_shift(&state->format); + spin_unlock_irqrestore(&state->unit->reg_lock, flags); } } #if HAVE_RECORD @@ -1674,7 +1676,6 @@ dmabuf->ready = 0; } #endif - spin_unlock_irqrestore(&state->unit->reg_lock, flags); } return put_user(state->format.voices, (int *)arg); @@ -1690,7 +1691,6 @@ * The paragraph above is a clumsy way to say "flush ioctl". * This ioctl is used by mpg123. */ - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_POST\n"); */ spin_lock_irqsave(&state->unit->reg_lock, flags); if (dmabuf->count != 0 && !state->ypcm.running) { ymf_start_dac(state); @@ -1726,7 +1726,6 @@ return 0; case SNDCTL_DSP_GETOSPACE: - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETOSPACE\n"); */ if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) @@ -1757,12 +1756,10 @@ #endif case SNDCTL_DSP_NONBLOCK: - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_NONBLOCK\n"); */ file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETCAPS: - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETCAPS\n"); */ /* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, (int *)arg); */ return put_user(0, (int *)arg); @@ -1814,7 +1811,6 @@ #endif case SNDCTL_DSP_GETOPTR: - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETOPTR\n"); */ if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&state->unit->reg_lock, flags); @@ -1828,7 +1824,6 @@ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */ - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SETDUPLEX\n"); */ return -EINVAL; #if 0 /* old */ @@ -1859,7 +1854,7 @@ return -ENOTTY; default: - /* P3 */ printk("ymfpci: ioctl cmd 0x%x\n", cmd); + /* P3 */ /* printk("ymfpci: ioctl cmd 0x%x\n", cmd); */ /* * Some programs mix up audio devices and ioctls * or perhaps they expect "universal" ioctls, @@ -1870,10 +1865,94 @@ return -ENOTTY; } +#ifdef CONFIG_SOUND_YMFPCI_LEGACY +/* MIDI stuff */ + +/* */ + +static int ymfpci_setup_legacy( ymfpci_t *codec, struct pci_dev *pcidev ) +{ + int v; + int mpuio=-1, oplio=-1; + + switch(codec->iomidi) { + case 0x330: + mpuio = 0; + break; + case 0x300: + mpuio = 1; + break; + case 0x332: + mpuio = 2; + break; + case 0x334: + mpuio = 3; + break; + default: + break; + } + + switch(codec->iosynth) { + case 0x388: + oplio = 0; + break; + case 0x398: + oplio = 1; + break; + case 0x3a0: + oplio = 2; + break; + case 0x3a8: + oplio = 3; + break; + default: + break; + } + + if ( mpuio >= 0 || oplio >= 0 ) { + v = 0x003e; + pci_write_config_word(pcidev, PCIR_LEGCTRL, v); + + switch( pcidev->device ) { + case PCI_DEVICE_ID_YAMAHA_724: + case PCI_DEVICE_ID_YAMAHA_740: + case PCI_DEVICE_ID_YAMAHA_724F: + case PCI_DEVICE_ID_YAMAHA_740C: + v = 0x8800; + if ( mpuio >= 0 ) { v|= mpuio<<4; } + if ( oplio >= 0 ) { v|= oplio; } + pci_write_config_word(pcidev, PCIR_ELEGCTRL, v); + break; + + case PCI_DEVICE_ID_YAMAHA_744: + case PCI_DEVICE_ID_YAMAHA_754: + v = 0x8800; + pci_write_config_word(pcidev, PCIR_ELEGCTRL, v); + if ( oplio >= 0 ) { + pci_write_config_word(pcidev, PCIR_OPLADR, codec->iosynth); + } + if ( mpuio >= 0 ) { + pci_write_config_word(pcidev, PCIR_MPUADR, codec->iomidi); + } + break; + + default: + printk(KERN_ERR "ymfpci: Invalid device ID: %d\n",pcidev->device); + return -EINVAL; + break; + } + } + + return 0; +} +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ + +/* */ + static int ymf_open(struct inode *inode, struct file *file) { ymfpci_t *unit; - int minor, instance; + int minor; struct ymf_state *state; int nvirt; int err; @@ -1890,21 +1969,21 @@ } else { return -ENXIO; } - instance = (minor >> 4) & 0x0F; nvirt = 0; /* Such is the partitioning of minor */ - /* XXX Semaphore here! */ for (unit = ymf_devs; unit != NULL; unit = unit->next) { - if (unit->inst == instance) break; + if (((unit->dev_audio ^ minor) & ~0x0f) == 0) break; } if (unit == NULL) return -ENODEV; + down(&unit->open_sem); if (unit->states[nvirt] != NULL) { - /* P3 */ printk("ymfpci%d: busy\n", unit->inst); + up(&unit->open_sem); return -EBUSY; } - if ((err = ymf_state_alloc(unit, nvirt, instance)) != 0) { + if ((err = ymf_state_alloc(unit, nvirt)) != 0) { + up(&unit->open_sem); return err; } state = unit->states[nvirt]; @@ -1912,11 +1991,12 @@ file->private_data = state; /* - * XXX This ymf_playback_prepare is totally unneeded here. - * The question is if we want to allow write to fail if - * prog_dmabuf fails... Say, no memory in DMA zone? + * ymf_read and ymf_write that we borrowed from cs46xx + * allocate buffers with prog_dmabuf(). We call prog_dmabuf + * here so that in case of DMA memory exhaustion open + * fails rather than write. */ - if ((err = ymf_playback_prepare(unit, state)) != 0) { + if (!state->dmabuf.ready && (err = prog_dmabuf(state, 0))) { /* XXX This recovery is ugly as hell. */ ymf_pcm_free_substream(&state->ypcm); @@ -1924,6 +2004,7 @@ unit->states[state->virt] = NULL; kfree(state); + up(&unit->open_sem); return err; } @@ -1933,6 +2014,9 @@ (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN)); #endif + up(&unit->open_sem); + /* XXX Ask Alan why MOD_INC_USE_COUNT is outside the semaphore. */ + MOD_INC_USE_COUNT; return 0; } @@ -1946,14 +2030,14 @@ ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0); #endif - /* XXX Use the semaphore to unrace us with opens */ - if (state != codec->states[state->virt]) { printk(KERN_ERR "ymfpci%d.%d: state mismatch\n", - state->unit->inst, state->virt); + state->unit->dev_audio, state->virt); return -EIO; } + down(&codec->open_sem); + /* * XXX Solve the case of O_NONBLOCK close - don't deallocate here. * Deallocate when unloading the driver and we can wait. @@ -1965,6 +2049,8 @@ codec->states[state->virt] = NULL; kfree(state); + up(&codec->open_sem); + MOD_DEC_USE_COUNT; return 0; } @@ -2057,8 +2143,7 @@ if (val) ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000); while (timeout-- > 0) { - val = ymfpci_readl(codec, YDSXGR_CONFIG); - if ((val & 0x00000002) == 0) + if ((ymfpci_readl(codec, YDSXGR_STATUS) & 2) == 0) break; } } @@ -2135,6 +2220,12 @@ ptr += 0x00ff; (long)ptr &= ~0x00ff; + /* + * Hardware requires only ptr[playback_ctrl_size] zeroed, + * but in our judgement it is a wrong kind of savings, so clear it all. + */ + memset(ptr, 0, size); + codec->bank_base_playback = ptr; codec->ctrl_playback = (u32 *)ptr; codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES; @@ -2207,7 +2298,6 @@ codec->codec_write = ymfpci_codec_write; if (ac97_probe_codec(codec) == 0) { - /* Alan does not have this printout. P3 */ printk("ymfpci: ac97_probe_codec failed\n"); return -ENODEV; } @@ -2234,6 +2324,20 @@ return 0; } +/* */ +#ifdef CONFIG_SOUND_YMFPCI_LEGACY +# ifdef MODULE +static int mpu_io = 0; +static int synth_io = 0; +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(synth_io, "i"); +# else +static int mpu_io = 0x330; +static int synth_io = 0x388; +# endif +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ +/* */ + static int /* __init */ ymf_install(struct pci_dev *pcidev, int instance, int devx) { @@ -2249,17 +2353,17 @@ spin_lock_init(&codec->reg_lock); spin_lock_init(&codec->voice_lock); + codec->open_sem = MUTEX; codec->pci = pcidev; - codec->inst = instance; codec->irq = pcidev->irq; codec->device_id = pcidev->device; - pci_read_config_byte(pcidev, PCI_REVISION_ID, (u8 *)&codec->rev); + pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev); codec->reg_area_phys = pcidev->base_address[0]&PCI_BASE_ADDRESS_MEM_MASK; codec->reg_area_virt = (unsigned long)ioremap(codec->reg_area_phys, 0x8000); pci_set_master(pcidev); - /* XXX KERN_INFO */ - printk("ymfpci%d: %s at 0x%lx IRQ %d\n", instance, + /* Not printing instance number because we use dev_audio elsewhere. */ + printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n", ymf_devv[devx].name, codec->reg_area_phys, codec->irq); ymfpci_aclink_reset(pcidev); @@ -2268,6 +2372,17 @@ return -ENODEV; } +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + if (instance == 0) { + codec->iomidi = mpu_io; + codec->iosynth = synth_io; + if (ymfpci_setup_legacy(codec, pcidev) < 0) { + ymfpci_free(codec); + return -ENODEV; + } + } +#endif + ymfpci_download_image(codec); udelay(100); /* seems we need some delay after downloading image.. */ @@ -2280,15 +2395,15 @@ /* ymfpci_proc_init(card, codec); */ if (request_irq(codec->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) { - printk(KERN_ERR "ymfpci%d: unable to request IRQ %d\n", - codec->inst, codec->irq); + printk(KERN_ERR "ymfpci: unable to request IRQ %d\n", + codec->irq); ymfpci_free(codec); return -ENODEV; } /* register /dev/dsp */ if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) { - printk(KERN_ERR "ymfpci%d: unable to register dsp\n", codec->inst); + printk(KERN_ERR "ymfpci: unable to register dsp\n"); free_irq(codec->irq, codec); ymfpci_free(codec); return -ENODEV; @@ -2304,6 +2419,24 @@ return err; } +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + + codec->opl3_data.name = "ymfpci"; + codec->mpu_data.name = "ymfpci"; + + codec->opl3_data.io_base = codec->iosynth; + codec->opl3_data.irq = -1; + + codec->mpu_data.io_base = codec->iomidi; + codec->mpu_data.irq = -1; /* XXX Make it ours. */ + + if (codec->iomidi) { + if (probe_uart401(&codec->mpu_data)) { + attach_uart401(&codec->mpu_data); + } + } +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ + codec->next = ymf_devs; ymf_devs = codec; @@ -2339,6 +2472,11 @@ unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer); kfree(codec->ac97_codec[0]); } +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + if (codec->iomidi) { + unload_uart401(&(codec->mpu_data)); + } +#endif /* CONFIG_SOUND_YMFPCI_LEGACY */ kfree(codec); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/sound/ymfpci.h linux/drivers/sound/ymfpci.h --- v2.2.18/drivers/sound/ymfpci.h Sun Mar 25 11:28:31 2001 +++ linux/drivers/sound/ymfpci.h Sun Mar 25 11:37:37 2001 @@ -131,7 +131,12 @@ #define YDSXG_AC97READCMD 0x8000 #define YDSXG_AC97WRITECMD 0x0000 +#define PCIR_LEGCTRL 0x40 +#define PCIR_ELEGCTRL 0x42 #define PCIR_DSXGCTRL 0x48 +#define PCIR_OPLADR 0x60 +#define PCIR_SBADR 0x62 +#define PCIR_MPUADR 0x64 #define YDSXG_DSPLENGTH 0x0080 #define YDSXG_CTRLLENGTH 0x3000 @@ -242,27 +247,27 @@ ymfpci_pcm_type_t type; struct ymf_state *state; ymfpci_voice_t *voices[2]; /* playback only */ - int running; // + + int running; int spdif; }; struct ymf_unit { unsigned int device_id; /* PCI device ID */ - unsigned int rev; /* PCI revision */ + unsigned char rev; /* PCI revision */ unsigned long reg_area_phys; unsigned long reg_area_virt; - void *work_ptr; // + + void *work_ptr; unsigned int bank_size_playback; unsigned int bank_size_capture; unsigned int bank_size_effect; unsigned int work_size; - void *bank_base_playback; // + - void *bank_base_capture; // + - void *bank_base_effect; // + - void *work_base; // + + void *bank_base_playback; + void *bank_base_capture; + void *bank_base_effect; + void *work_base; u32 *ctrl_playback; ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2]; @@ -279,16 +284,22 @@ struct pci_dev *pci; int irq; - int inst; /* Unit number (instance) */ + +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + /* legacy hardware resources */ + unsigned int iosynth, iomidi; + struct address_info opl3_data, mpu_data; +#endif spinlock_t reg_lock; spinlock_t voice_lock; /* soundcore stuff */ int dev_audio; + struct semaphore open_sem; - ymfpci_t *next; // * - struct ymf_state *states[1]; // * + ymfpci_t *next; + struct ymf_state *states[1]; /* ypcm may be the same thing as state, but not for record, effects. */ }; @@ -336,16 +347,12 @@ struct ymf_state { struct ymf_unit *unit; /* backpointer */ - /* single open lock mechanism, only used for recording */ - struct semaphore open_sem; - struct wait_queue *open_wait; - /* virtual channel number */ int virt; // * unused a.t.m. - struct ymf_pcm ypcm; // * - struct ymf_dmabuf dmabuf; // * - struct ymf_pcm_format format; // * + struct ymf_pcm ypcm; + struct ymf_dmabuf dmabuf; + struct ymf_pcm_format format; }; #endif /* __YMFPCI_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.2.18/drivers/usb/Config.in Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/Config.in Sun Mar 25 11:37:37 2001 @@ -10,7 +10,6 @@ comment 'Miscellaneous USB options' bool ' Preliminary USB device filesystem' CONFIG_USB_DEVICEFS - bool ' Support for hot-pluggable USB devices' CONFIG_HOTPLUG if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH else @@ -26,75 +25,58 @@ fi dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB -comment 'USB Devices' - dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB - dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB + comment 'USB Device Class drivers' dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND - dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB - dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB - if [ "$CONFIG_USB_SERIAL" != "n" ]; then - bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL - dep_tristate ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL - dep_tristate ' USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL - if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL - dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL - dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL - dep_tristate ' USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL - if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then - bool ' USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 - bool ' USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X - bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19 - bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X - bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W - fi - dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL - dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL - fi - bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL - fi - dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB - dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI - if [ "$CONFIG_USB_STORAGE" != "n" ]; then - bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG - fi - fi -# dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT - dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET - dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET - dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB - dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV -# dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_SCSI - dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB - fi - if [ "$CONFIG_NET" = "y" ]; then - dep_tristate ' Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB + dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL + dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL + if [ "$CONFIG_USB_STORAGE" = "y" -o "$CONFIG_USB_STORAGE" = "m" ]; then + bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG fi + dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB + dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB -comment 'USB HID' - dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB + comment 'USB Human Interface Devices (HID)' + dep_tristate ' USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB if [ "$CONFIG_USB_HID" != "y" ]; then - dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB - dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB + dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB + dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB fi - dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB - dep_tristate ' Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB if [ "$CONFIG_VT" = "y" ]; then - dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB + dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB $CONFIG_USB_HID fi - dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB - if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then + dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB $CONFIG_USB_HID + if [ "$CONFIG_INPUT_MOUSEDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "m" ]; then int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 fi - dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB - dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB + dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB $CONFIG_USB_HID + dep_tristate ' Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB $CONFIG_USB_HID + dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_USB_HID + dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB $CONFIG_USB_HID + + comment 'USB Imaging devices' + dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB + dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL + dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB + dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL + + comment 'USB Multimedia devices' + dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL + dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB + + comment 'USB Network adaptors' + dep_tristate ' Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB + dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL + + comment 'USB port drivers' +# dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT + source drivers/usb/serial/Config.in + + comment 'USB misc drivers' + dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.2.18/drivers/usb/acm.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/acm.c Sun Mar 25 11:37:37 2001 @@ -503,12 +503,12 @@ if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) { ifcom = cfacm->interface[1].altsetting + 0; ifdata = cfacm->interface[0].altsetting + 0; - if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) + if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) continue; } if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 || - ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1) + ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1) continue; epctrl = ifcom->endpoint + 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.2.18/drivers/usb/audio.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/audio.c Sun Mar 25 11:37:37 2001 @@ -174,6 +174,7 @@ #include #include #include +#include #include #include #include @@ -562,7 +563,8 @@ rem = db->dmasize - ptr; if (pgrem > rem) pgrem = rem; - copy_from_user_ret((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem, -EFAULT); + if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem)) + return -EFAULT; size -= pgrem; (char *)buffer += pgrem; ptr += pgrem; @@ -586,7 +588,8 @@ rem = db->dmasize - ptr; if (pgrem > rem) pgrem = rem; - copy_to_user_ret(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem, -EFAULT); + if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem)) + return -EFAULT; size -= pgrem; (char *)buffer += pgrem; ptr += pgrem; @@ -1957,10 +1960,13 @@ static int usb_audio_release_mixdev(struct inode *inode, struct file *file) { struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data; - struct usb_audio_state *s = ms->state; + struct usb_audio_state *s; + lock_kernel(); + s = ms->state; down(&open_sem); release(s); + unlock_kernel(); return 0; } @@ -2038,7 +2044,8 @@ ms->modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; return set_rec_src(ms, val); default: @@ -2048,7 +2055,8 @@ for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++); if (j >= ms->numch) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (wrmixer(ms, j, val)) return -EIO; return put_user(ms->ch[j].value, (int *)arg); @@ -2295,20 +2303,24 @@ { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; struct dmabuf *db; - int ret; + int ret = -EINVAL; + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf_out(as)) != 0) - return ret; + goto out; db = &as->usbout.dma; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf_in(as)) != 0) - return ret; + goto out; db = &as->usbin.dma; } else - return -EINVAL; + goto out; - return dmabuf_mmap(db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); + ret = dmabuf_mmap(db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); +out: + unlock_kernel(); + return ret; } static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2352,7 +2364,8 @@ return 0; case SNDCTL_DSP_SPEED: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val >= 0) { if (val < 4000) val = 4000; @@ -2370,7 +2383,8 @@ return 0; case SNDCTL_DSP_CHANNELS: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 0) { val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; if (val == 1) @@ -2388,7 +2402,8 @@ AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != AFMT_QUERY) { if (hweight32(val) != 1) return -EINVAL; @@ -2415,7 +2430,8 @@ return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as))) @@ -2509,7 +2525,8 @@ return put_user(as->usbin.dma.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (file->f_mode & FMODE_READ) { as->usbin.dma.ossfragshift = val & 0xffff; as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff; @@ -2536,7 +2553,8 @@ if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) || (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision)) return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); + if (get_user(val, (int *)arg)) + return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -2624,10 +2642,13 @@ static int usb_audio_release(struct inode *inode, struct file *file) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - struct usb_audio_state *s = as->state; - struct usb_device *dev = s->usbdev; + struct usb_audio_state *s; + struct usb_device *dev; struct usb_interface *iface; + lock_kernel(); + s = as->state; + dev = s->usbdev; if (file->f_mode & FMODE_WRITE) drain_out(as, file->f_flags & O_NONBLOCK); down(&open_sem); @@ -2652,6 +2673,7 @@ as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); release(s); wake_up(&open_wait); + unlock_kernel(); return 0; } @@ -2672,12 +2694,10 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr); static struct usb_driver usb_audio_driver = { - "audio", - usb_audio_probe, - usb_audio_disconnect, - LIST_HEAD_INIT(usb_audio_driver.driver_list), - NULL, - 0 + name: "audio", + probe: usb_audio_probe, + disconnect: usb_audio_disconnect, + driver_list: LIST_HEAD_INIT(usb_audio_driver.driver_list), }; static void *find_descriptor(void *descstart, unsigned int desclen, void *after, @@ -3641,6 +3661,7 @@ #endif return NULL; } + /* * audiocontrol interface found * find which configuration number is active @@ -3721,21 +3742,21 @@ wake_up(&open_wait); } -int usb_audio_init(void) +static int __init usb_audio_init(void) { usb_register(&usb_audio_driver); return 0; } -#ifdef MODULE -int init_module(void) -{ - return usb_audio_init(); -} -void cleanup_module(void) +static void __exit usb_audio_cleanup(void) { usb_deregister(&usb_audio_driver); } -#endif +module_init(usb_audio_init); +module_exit(usb_audio_cleanup); + +MODULE_AUTHOR("Alan Cox , Thomas Sailer (sailer@ife.ee.ethz.ch)"); +MODULE_DESCRIPTION("USB Audio Class driver"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c --- v2.2.18/drivers/usb/bluetooth.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/bluetooth.c Sun Mar 25 11:37:37 2001 @@ -1,11 +1,15 @@ /* - * bluetooth.c Version 0.6 + * bluetooth.c Version 0.7 * * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B * + * (11/29/2000) Version 0.7 gkh + * Fixed problem with overrunning the tty flip buffer. + * Removed unneeded NULL pointer initialization. + * * (10/05/2000) Version 0.6 gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -73,9 +77,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -199,8 +203,7 @@ static struct tty_struct * bluetooth_tty[BLUETOOTH_TTY_MINORS]; static struct termios * bluetooth_termios[BLUETOOTH_TTY_MINORS]; static struct termios * bluetooth_termios_locked[BLUETOOTH_TTY_MINORS]; -static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, }; - +static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS]; static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function) @@ -315,6 +318,11 @@ tty->driver_data = bluetooth; bluetooth->tty = tty; + /* force low_latency on so that our tty_push actually forces the data through, + * otherwise it is scheduled, and with high data rates (like with OHCI) data + * can get lost. */ + bluetooth->tty->low_latency = 1; + bluetooth->active = 1; /* Reset the packet position counters */ @@ -774,9 +782,14 @@ return; } - if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){ - for (i = 0; i < bluetooth->int_packet_pos; ++i) + if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) { + for (i = 0; i < bluetooth->int_packet_pos; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */ + if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(bluetooth->tty); + } tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0); + } tty_flip_buffer_push(bluetooth->tty); bluetooth->int_packet_pos = 0; @@ -888,8 +901,13 @@ } if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) { - for (i = 0; i < bluetooth->bulk_packet_pos; ++i) + for (i = 0; i < bluetooth->bulk_packet_pos; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ + if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(bluetooth->tty); + } tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0); + } tty_flip_buffer_push(bluetooth->tty); bluetooth->bulk_packet_pos = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c --- v2.2.18/drivers/usb/dabusb.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/dabusb.c Sun Mar 25 11:37:37 2001 @@ -173,8 +173,8 @@ // process if URB was not killed if (purb->status != -ENOENT) { - unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE); - int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); + unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE); + int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe)); for (i = 0; i < purb->number_of_packets; i++) if (!purb->iso_frame_desc[i].status) { len = purb->iso_frame_desc[i].actual_length; @@ -455,6 +455,8 @@ dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list); end = list_entry (s->rec_buff_list.prev, buff_t, buff_list); + + end->purb->dev=s->usbdev; ret = usb_submit_urb (end->purb); if (ret) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c --- v2.2.18/drivers/usb/dc2xx.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/dc2xx.c Sun Mar 25 11:37:37 2001 @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2000 by David Brownell + * Copyright (C) 1999-2000 by David Brownell * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -59,13 +59,17 @@ #include #include #include -#undef DEBUG +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif #include /* current USB framework handles max of 16 USB devices per driver */ -#define MAX_CAMERAS 8 +#define MAX_CAMERAS 16 /* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */ #define USB_CAMERA_MINOR_BASE 80 @@ -90,6 +94,8 @@ /* These have the same application level protocol */ { 0x040a, 0x0120 }, // Kodak DC-240 { 0x040a, 0x0130 }, // Kodak DC-280 + { 0x040a, 0x0131 }, // Kodak DC-5000 + { 0x040a, 0x0132 }, // Kodak DC-3400 /* These have a different application level protocol which * is part of the Flashpoint "DigitaOS". That supports some @@ -435,7 +441,8 @@ goto error; } - info ("USB Camera #%d connected", camera->subminor); + info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor, + USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor); camera->dev = dev; usb_inc_dev_use (dev); @@ -475,12 +482,13 @@ } static /* const */ struct usb_driver camera_driver = { - "dc2xx", - camera_probe, - camera_disconnect, - { NULL, NULL }, - &usb_camera_fops, - USB_CAMERA_MINOR_BASE + name: "dc2xx", + + probe: camera_probe, + disconnect: camera_disconnect, + + fops: &usb_camera_fops, + minor: USB_CAMERA_MINOR_BASE }; @@ -497,7 +505,7 @@ } -MODULE_AUTHOR("David Brownell, david-b@pacbell.net"); +MODULE_AUTHOR("David Brownell, dbrownell@users.sourceforge.net"); MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras"); module_init (usb_dc2xx_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/devices.c linux/drivers/usb/devices.c --- v2.2.18/drivers/usb/devices.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/devices.c Sun Mar 25 11:37:37 2001 @@ -496,8 +496,10 @@ lock_kernel(); if (!st) { st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); - if (!st) + if (!st) { + unlock_kernel(); return POLLIN; + } /* * need to prevent the module from being unloaded, since * proc_unregister does not call the release method and diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.2.18/drivers/usb/devio.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/devio.c Sun Mar 25 11:37:37 2001 @@ -55,113 +55,6 @@ urb_t urb; }; -/* - * my own sync control and bulk methods. Here to experiment - * and because the kernel ones set the process to TASK_UNINTERRUPTIBLE. - */ - -struct sync { - wait_queue_head_t wait; -}; - -static void sync_completed(purb_t urb) -{ - struct sync *s = (struct sync *)urb->context; - - wake_up(&s->wait); -} - -static int do_sync(purb_t urb, int timeout) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long tm; - signed long tmdiff; - struct sync s; - int ret; - - tm = jiffies+timeout; - init_waitqueue_head(&s.wait); - add_wait_queue(&s.wait, &wait); - urb->context = &s; - urb->complete = sync_completed; - set_current_state(TASK_INTERRUPTIBLE); - if ((ret = usb_submit_urb(urb))) - goto out; - while (urb->status == -EINPROGRESS) { - tmdiff = tm - jiffies; - if (tmdiff <= 0) { - ret = -ETIMEDOUT; - goto out; - } - if (signal_pending(current)) { - ret = -EINTR; - goto out; - } - schedule_timeout(tmdiff); - } - ret = urb->status; - out: - set_current_state(TASK_RUNNING); - usb_unlink_urb(urb); - remove_wait_queue(&s.wait, &wait); - return ret; -} - -static int my_usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, - __u16 value, __u16 index, void *data, __u16 size, int timeout) -{ - urb_t *urb; - int ret; - - if (!(urb = usb_alloc_urb(0))) - return -ENOMEM; - if (!(urb->setup_packet = kmalloc(8, GFP_KERNEL))) { - usb_free_urb(urb); - return -ENOMEM; - } - urb->setup_packet[0] = requesttype; - urb->setup_packet[1] = request; - urb->setup_packet[2] = value; - urb->setup_packet[3] = value >> 8; - urb->setup_packet[4] = index; - urb->setup_packet[5] = index >> 8; - urb->setup_packet[6] = size; - urb->setup_packet[7] = size >> 8; - urb->dev = dev; - urb->pipe = pipe; - urb->transfer_buffer = data; - urb->transfer_buffer_length = size; - ret = do_sync(urb, timeout); - //if (ret >= 0) - // ret = urb->status; - if (ret >= 0) - ret = urb->actual_length; - kfree(urb->setup_packet); - usb_free_urb(urb); - return ret; -} - -static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) -{ - urb_t *urb; - int ret; - - if (!(urb = usb_alloc_urb(0))) - return -ENOMEM; - urb->dev = dev; - urb->pipe = pipe; - urb->transfer_buffer = data; - urb->transfer_buffer_length = len; - ret = do_sync(urb, timeout); - //if (ret >= 0) - // ret = urb->status; - if (ret >= 0 && actual_length != NULL) - *actual_length = urb->actual_length; - usb_free_urb(urb); - return ret; -} - static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) { switch (orig) { @@ -289,6 +182,8 @@ { if (as->urb.transfer_buffer) kfree(as->urb.transfer_buffer); + if (as->urb.setup_packet) + kfree(as->urb.setup_packet); kfree(as); } @@ -536,6 +431,28 @@ } #endif +static int check_ctrlrecip(struct dev_state *ps, unsigned int recip, unsigned int index) +{ + int ret; + + switch (recip & USB_RECIP_MASK) { + case USB_RECIP_ENDPOINT: + if ((ret = findintfep(ps->dev, index & 0xff)) < 0) + return ret; + if ((ret = checkintf(ps, ret))) + return ret; + break; + + case USB_RECIP_INTERFACE: + if ((ret = findintfif(ps->dev, index & 0xff)) < 0) + return ret; + if ((ret = checkintf(ps, ret))) + return ret; + break; + } + return 0; +} + /* * file operations */ @@ -609,21 +526,8 @@ if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) return -EFAULT; - switch (ctrl.requesttype & 0x1f) { - case USB_RECIP_ENDPOINT: - if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0) - return ret; - if ((ret = checkintf(ps, ret))) - return ret; - break; - - case USB_RECIP_INTERFACE: - if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0) - return ret; - if ((ret = checkintf(ps, ret))) - return ret; - break; - } + if ((ret = check_ctrlrecip(ps, ctrl.requesttype, ctrl.index))) + return ret; if (ctrl.length > PAGE_SIZE) return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) @@ -634,7 +538,7 @@ free_page((unsigned long)tbuf); return -EINVAL; } - i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, + i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); if ((i > 0) && ctrl.length) { if (copy_to_user(ctrl.data, tbuf, ctrl.length)) { @@ -649,7 +553,7 @@ return -EFAULT; } } - i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); } free_page((unsigned long)tbuf); @@ -683,7 +587,7 @@ return -EINVAL; len1 = bulk.len; if (len1 > PAGE_SIZE) - len1 = PAGE_SIZE; + return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; tmo = (bulk.timeout * HZ + 999) / 1000; @@ -692,7 +596,7 @@ free_page((unsigned long)tbuf); return -EINVAL; } - i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { free_page((unsigned long)tbuf); @@ -706,7 +610,7 @@ return -EFAULT; } } - i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); } free_page((unsigned long)tbuf); if (i < 0) { @@ -847,23 +751,61 @@ { struct usbdevfs_urb uurb; struct usbdevfs_iso_packet_desc *isopkt = NULL; + struct usb_endpoint_descriptor *ep_desc; struct async *as; + devrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret; if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; - if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD)) + if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD|USBDEVFS_URB_QUEUE_BULK)) return -EINVAL; if (!uurb.buffer) return -EINVAL; if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX)) return -EINVAL; - if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0) - return ret; - if ((ret = checkintf(ps, ret))) - return ret; + if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { + if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0) + return ret; + if ((ret = checkintf(ps, ret))) + return ret; + } switch(uurb.type) { + case USBDEVFS_URB_TYPE_CONTROL: + if ((uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) != 0) { + if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint))) + return -ENOENT; + if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL) + return -EINVAL; + } + /* min 8 byte setup packet, max arbitrary */ + if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE) + return -EINVAL; + if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL))) + return -ENOMEM; + if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) { + kfree(dr); + return -EFAULT; + } + if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) { + kfree(dr); + return -EINVAL; + } + if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) { + kfree(dr); + return ret; + } + uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK); + uurb.number_of_packets = 0; + uurb.buffer_length = le16_to_cpup(&dr->length); + uurb.buffer += 8; + if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) { + kfree(dr); + return -EFAULT; + } + break; + case USBDEVFS_URB_TYPE_BULK: uurb.number_of_packets = 0; if (uurb.buffer_length > 16384) @@ -903,11 +845,15 @@ if (!(as = alloc_async(uurb.number_of_packets))) { if (isopkt) kfree(isopkt); + if (dr) + kfree(dr); return -ENOMEM; } if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) { if (isopkt) kfree(isopkt); + if (dr) + kfree(dr); free_async(as); return -ENOMEM; } @@ -916,6 +862,7 @@ as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN); as->urb.transfer_flags = uurb.flags; as->urb.transfer_buffer_length = uurb.buffer_length; + as->urb.setup_packet = (unsigned char*)dr; as->urb.start_frame = uurb.start_frame; as->urb.number_of_packets = uurb.number_of_packets; as->urb.context = as; @@ -1089,17 +1036,19 @@ int retval = 0; /* get input parameters and alloc buffer */ - if (copy_from_user (&ctrl, (void *) arg, sizeof (ctrl))) + if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl))) return -EFAULT; if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { if ((buf = kmalloc (size, GFP_KERNEL)) == 0) return -ENOMEM; - if ((_IOC_DIR (ctrl.ioctl_code) & _IOC_WRITE) != 0 - && copy_from_user (buf, ctrl.data, size) != 0) { - kfree (buf); - return -EFAULT; - } else - memset (arg, 0, size); + if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) { + if (copy_from_user (buf, ctrl.data, size)) { + kfree (buf); + return -EFAULT; + } + } else { + memset (buf, 0, size); + } } /* ioctl to device */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.2.18/drivers/usb/hid.c Sun Mar 25 11:28:31 2001 +++ linux/drivers/usb/hid.c Sun Mar 25 11:37:37 2001 @@ -698,7 +698,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n) { __s32 a = value >> (n - 1); - if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1; + if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; return value & ((1 << n) - 1); } @@ -856,7 +856,7 @@ case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ switch (usage->hid & HID_USAGE) { - + case 0x000: usage->code = 0; break; case 0x034: usage->code = KEY_SLEEP; break; case 0x036: usage->code = BTN_MISC; break; case 0x08a: usage->code = KEY_WWW; break; @@ -981,6 +981,9 @@ input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); } + if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */ + return; + input_event(input, usage->type, usage->code, value); if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) @@ -1013,9 +1016,15 @@ __s32 max = field->logical_maximum; __s32 value[count]; /* WARNING: gcc specific */ - for (n = 0; n < count; n++) + for (n = 0; n < count; n++) { value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : extract(data, offset + n * size, size); + /* Handle the ErrorRollOver code (1) by simply ignoring this report */ + if (!(field->flags & HID_MAIN_ITEM_VARIABLE) + && value[n] >= min && value[n] <= max + && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) + return; + } for (n = 0; n < count; n++) { @@ -1228,9 +1237,10 @@ static int hid_submit_out(struct hid_device *hid) { - hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; + hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length); hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); + hid->urbout.dev = hid->dev; if (usb_submit_urb(&hid->urbout)) { err("usb_submit_urb(out) failed"); @@ -1267,8 +1277,8 @@ hid_set_field(field, offset, value); hid_output_report(field->report, hid->out[hid->outhead].buffer); - hid->out[hid->outhead].dr.value = 0x200 | field->report->id; - hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1; + hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | field->report->id); + hid->out[hid->outhead].dr.length = cpu_to_le16((field->report->size + 7) >> 3); hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); @@ -1288,7 +1298,9 @@ if (hid->open++) return 0; - if (usb_submit_urb(&hid->urb)) + hid->urb.dev = hid->dev; + + if (usb_submit_urb(&hid->urb)) return -EIO; return 0; @@ -1442,7 +1454,7 @@ for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; hid->out[n].dr.request = USB_REQ_SET_REPORT; - hid->out[n].dr.index = hid->ifnum; + hid->out[n].dr.index = cpu_to_le16(hid->ifnum); } hid->input.name = hid->name; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/hub.h linux/drivers/usb/hub.h --- v2.2.18/drivers/usb/hub.h Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/hub.h Sun Mar 25 11:37:37 2001 @@ -111,7 +111,8 @@ /* Interrupt polling pipe */ struct urb *urb; - char buffer[USB_MAXCHILDREN / 8]; + char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */ + /* and add 7 bits to round up to byte boundary */ /* List of hubs */ struct list_head hub_list; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.2.18/drivers/usb/keybdev.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/keybdev.c Sun Mar 25 11:37:37 2001 @@ -60,6 +60,7 @@ }; #ifdef CONFIG_INPUT_ADBHID +#ifdef CONFIG_MAC_ADBKEYCODES extern int mac_hid_keyboard_sends_linux_keycodes(void); static unsigned char mac_keycodes[256] = { @@ -76,19 +77,20 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102 }; - -#ifdef CONFIG_INPUT_MOUSEDEV +#endif /* CONFIG_MAC_ADBKEYCODES */ +#ifdef CONFIG_MAC_EMUMOUSEBTN extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int); -#endif /* CONFIG_INPUT_MOUSEDEV */ +#endif /* CONFIG_MAC_EMUMOUSEBTN */ #endif /* CONFIG_INPUT_ADBHID */ static int emulate_raw(unsigned int keycode, int down) { #ifdef CONFIG_INPUT_ADBHID -#ifdef CONFIG_INPUT_MOUSEDEV +#ifdef CONFIG_MAC_EMUMOUSEBTN if (mac_hid_mouse_emulate_buttons(1, keycode, down)) return 0; -#endif /* CONFIG_INPUT_MOUSEDEV */ +#endif /* CONFIG_MAC_EMUMOUSEBTN */ +#ifdef CONFIG_MAC_ADBKEYCODES if (!mac_hid_keyboard_sends_linux_keycodes()) { if (keycode > 255 || !mac_keycodes[keycode]) return -1; @@ -97,6 +99,7 @@ return 0; } +#endif /* CONFIG_MAC_ADBKEYCODES */ #endif /* CONFIG_INPUT_ADBHID */ if (keycode > 255 || !x86_keycodes[keycode]) return -1; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.2.18/drivers/usb/printer.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/printer.c Sun Mar 25 11:37:37 2001 @@ -17,6 +17,7 @@ * v0.4 - fixes in unidirectional mode * v0.5 - add DEVICE_ID string support * v0.6 - never time out + * v0.? - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com) */ /* @@ -52,6 +53,7 @@ #define IOCNR_GET_DEVICE_ID 1 #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* get device_id string */ +#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ /* * A DEVICE_ID string may include the printer's serial number. @@ -81,6 +83,7 @@ int readcount; /* Counter for reads */ int ifnum; /* Interface number */ int minor; /* minor number of device */ + unsigned int quirks; /* quirks flags */ unsigned char used; /* True if open */ unsigned char bidir; /* interface is bidirectional */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ @@ -89,6 +92,26 @@ static struct usblp *usblp_table[USBLP_MINORS]; +/* Quirks: various printer quirks are handled by this table & its flags. */ + +struct quirk_printer_struct { + __u16 vendorId; + __u16 productId; + unsigned int quirks; +}; + +#define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ +#define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ + +static struct quirk_printer_struct quirk_printers[] = { + { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ + { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */ + { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ + { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ + { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ + { 0, 0 } +}; + /* * Functions for usblp control messages. */ @@ -179,10 +202,19 @@ if (usblp->used) goto out; + /* + * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? + * This is #if 0-ed because we *don't* want to fail an open + * just because the printer is off-line. + */ +#if 0 if ((retval = usblp_check_status(usblp, 0))) { retval = retval > 1 ? -EIO : -ENOSPC; goto out; } +#else + retval = 0; +#endif usblp->used = 1; file->private_data = usblp; @@ -192,6 +224,7 @@ if (usblp->bidir) { usblp->readcount = 0; + usblp->readurb.dev = usblp->dev; usb_submit_urb(&usblp->readurb); } out: @@ -224,37 +257,66 @@ { struct usblp *usblp = file->private_data; poll_wait(file, &usblp->wait, wait); - return ((usblp->bidir || usblp->readurb.status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM) - | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM); + return ((!usblp->bidir || usblp->readurb.status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM) + | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM); } static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct usblp *usblp = file->private_data; - int length; - - if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ)) - return -EINVAL; - - switch (_IOC_NR(cmd)) { + int length, err; + unsigned char status; - case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ + if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ + + switch (_IOC_NR(cmd)) { + + case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ + if (_IOC_DIR(cmd) != _IOC_READ) + return -EINVAL; + + err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + if (err < 0) { + dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string", + usblp->minor, err); + usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; + return -EIO; + } + + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ + if (length < DEVICE_ID_SIZE) + usblp->device_id_string[length] = '\0'; + else + usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; + + dbg ("usblp%d Device ID string [%d/max %d]='%s'", + usblp->minor, length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); + + if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ + if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length)) + return -EFAULT; - dbg ("usblp_ioctl GET_DEVICE_ID actlen: %d, size: %d, string: '%s'", - length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); + break; - if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ + default: + return -EINVAL; + } + else /* old-style ioctl value */ + switch (cmd) { - if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length)) - return -EFAULT; + case LPGETSTATUS: + if (usblp_read_status(usblp, &status)) { + err("usblp%d: failed reading printer status", usblp->minor); + return -EIO; + } + if (copy_to_user ((unsigned char *)arg, &status, 1)) + return -EFAULT; + break; - break; - - default: - return -EINVAL; - } + default: + return -EINVAL; + } return 0; } @@ -285,8 +347,17 @@ return -ENODEV; if (usblp->writeurb.status) { - err = usblp_check_status(usblp, err); - continue; + if (usblp->quirks & USBLP_QUIRK_BIDIR) { + if (usblp->writeurb.status != -EINPROGRESS) + err("usblp%d: error %d writing to printer", + usblp->minor, usblp->writeurb.status); + err = usblp->writeurb.status; + continue; + } + else { + err = usblp_check_status(usblp, err); + continue; + } } writecount += usblp->writeurb.transfer_buffer_length; @@ -301,6 +372,7 @@ if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount, usblp->writeurb.transfer_buffer_length)) return -EFAULT; + usblp->writeurb.dev = usblp->dev; usb_submit_urb(&usblp->writeurb); } @@ -332,6 +404,8 @@ if (usblp->readurb.status) { err("usblp%d: error %d reading from printer", usblp->minor, usblp->readurb.status); + usblp->readurb.dev = usblp->dev; + usblp->readcount = 0; usb_submit_urb(&usblp->readurb); return -EIO; } @@ -342,21 +416,55 @@ if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) return -EFAULT; - if ((usblp->readcount += count) == usblp->readurb.actual_length) + if ((usblp->readcount += count) == usblp->readurb.actual_length) { + usblp->readcount = 0; + usblp->readurb.dev = usblp->dev; usb_submit_urb(&usblp->readurb); + } return count; } +/* + * Checks for printers that have quirks, such as requiring unidirectional + * communication but reporting bidirectional; currently some HP printers + * have this flaw (HP 810, 880, 895, etc.), or needing an init string + * sent at each open (like some Epsons). + * Returns 1 if found, 0 if not found. + * + * HP recommended that we use the bidirectional interface but + * don't attempt any bulk IN transfers from the IN endpoint. + * Here's some more detail on the problem: + * The problem is not that it isn't bidirectional though. The problem + * is that if you request a device ID, or status information, while + * the buffers are full, the return data will end up in the print data + * buffer. For example if you make sure you never request the device ID + * while you are sending print data, and you don't try to query the + * printer status every couple of milliseconds, you will probably be OK. + */ +static unsigned int usblp_quirks (__u16 vendor, __u16 product) +{ + int i; + + for (i = 0; quirk_printers[i].vendorId; i++) { + if (vendor == quirk_printers[i].vendorId && + product == quirk_printers[i].productId) + return quirk_printers[i].quirks; + } + return 0; +} + static void *usblp_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *epread, *epwrite; struct usblp *usblp; - int minor, i, alts = -1, bidir = 0; + int minor, i, bidir = 0, quirks; + int alts = dev->actconfig->interface[ifnum].act_altsetting; int length, err; char *buf; + /* If a bidirectional interface exists, use it. */ for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) { interface = &dev->actconfig->interface[ifnum].altsetting[i]; @@ -366,18 +474,13 @@ (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2)) continue; - if (alts == -1) - alts = i; - - if (!bidir && interface->bInterfaceProtocol > 1) { + if (interface->bInterfaceProtocol > 1) { bidir = 1; alts = i; + break; } } - if (alts == -1) - return NULL; - interface = &dev->actconfig->interface[ifnum].altsetting[alts]; if (usb_set_interface(dev, ifnum, alts)) err("can't set desired altsetting %d on interface %d", alts, ifnum); @@ -410,10 +513,21 @@ } memset(usblp, 0, sizeof(struct usblp)); + /* lookup quirks for this printer */ + quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct); + + if (bidir && (quirks & USBLP_QUIRK_BIDIR)) { + bidir = 0; + epread = NULL; + info ("Disabling reads from problem bidirectional printer on usblp%d", + minor); + } + usblp->dev = dev; usblp->ifnum = ifnum; usblp->minor = minor; usblp->bidir = bidir; + usblp->quirks = quirks; init_waitqueue_head(&usblp->wait); @@ -455,7 +569,7 @@ } #ifdef DEBUG - usblp_check_status(usblp); + usblp_check_status(usblp, 0); #endif info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", @@ -503,7 +617,7 @@ probe: usblp_probe, disconnect: usblp_disconnect, fops: &usblp_fops, - minor: USBLP_MINOR_BASE + minor: USBLP_MINOR_BASE, }; static int __init usblp_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/rio500.c linux/drivers/usb/rio500.c --- v2.2.18/drivers/usb/rio500.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/rio500.c Sun Mar 25 11:37:37 2001 @@ -36,6 +36,7 @@ #include #include #include +#include #include "rio500_usb.h" @@ -57,6 +58,7 @@ char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ wait_queue_head_t wait_q; /* for timeouts */ + struct semaphore lock; /* general race avoidance */ }; static struct rio_usb_data rio_instance; @@ -65,7 +67,10 @@ { struct rio_usb_data *rio = &rio_instance; + lock_kernel(); + if (rio->isopen || !rio->present) { + unlock_kernel(); return -EBUSY; } rio->isopen = 1; @@ -74,6 +79,8 @@ MOD_INC_USE_COUNT; + unlock_kernel(); + info("Rio opened."); return 0; @@ -101,6 +108,7 @@ unsigned char *buffer; int result, requesttype; int retries; + int retval; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || @@ -120,8 +128,10 @@ buffer = (unsigned char *) __get_free_page(GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) + if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { + free_page((unsigned long) buffer); return -EFAULT; + } requesttype = rio_cmd.requesttype | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; @@ -131,6 +141,7 @@ rio_cmd.index, rio_cmd.length); /* Send rio control message */ retries = 3; + down(&(rio->lock)); while (retries) { result = usb_control_msg(rio->rio_dev, usb_rcvctrlpipe(rio-> rio_dev, 0), @@ -151,8 +162,12 @@ le32_to_cpu(result), le32_to_cpu(*((long *) buffer))); if (copy_to_user(rio_cmd.buffer, buffer, - rio_cmd.length)) - return -EFAULT; + rio_cmd.length)) { + up(&(rio->lock)); + free_page((unsigned long) buffer); + retval = -EFAULT; + goto err_out; + } retries = 0; } @@ -164,6 +179,7 @@ be swapped at the app level */ } + up(&(rio->lock)); free_page((unsigned long) buffer); break; @@ -178,8 +194,10 @@ buffer = (unsigned char *) __get_free_page(GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) + if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { + free_page((unsigned long)buffer); return -EFAULT; + } requesttype = rio_cmd.requesttype | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; @@ -188,6 +206,7 @@ rio_cmd.index, rio_cmd.length); /* Send rio control message */ retries = 3; + down(&(rio->lock)); while (retries) { result = usb_control_msg(rio->rio_dev, usb_sndctrlpipe(rio-> rio_dev, 0), @@ -211,6 +230,7 @@ } } + up(&(rio->lock)); free_page((unsigned long) buffer); break; @@ -220,6 +240,10 @@ } return 0; + +err_out: + up(&(rio->lock)); + return retval; } static ssize_t @@ -234,6 +258,7 @@ int result = 0; int maxretry; + int errn = 0; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || @@ -241,19 +266,26 @@ rio->rio_dev == NULL ) return -1; + down(&(rio->lock)); + do { unsigned long thistime; char *obuf = rio->obuf; thistime = copy_size = (count >= OBUF_SIZE) ? OBUF_SIZE : count; - if (copy_from_user(rio->obuf, buffer, copy_size)) - return -EFAULT; + if (copy_from_user(rio->obuf, buffer, copy_size)) { + errn = -EFAULT; + goto error; + } maxretry = 5; while (thistime) { - if (!rio->rio_dev) - return -ENODEV; + if (!rio->rio_dev) { + errn = -ENODEV; + goto error; + } if (signal_pending(current)) { + up(&(rio->lock)); return bytes_written ? bytes_written : -EINTR; } @@ -266,7 +298,8 @@ if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */ if (!maxretry--) { - return -ETIME; + errn = -ETIME; + goto error; } interruptible_sleep_on_timeout(&rio-> wait_q, NAK_TIMEOUT); continue; @@ -278,14 +311,21 @@ }; if (result) { err("Write Whoops - %x", result); - return -EIO; + errn = -EIO; + goto error; } bytes_written += copy_size; count -= copy_size; buffer += copy_size; } while (count > 0); + up(&(rio->lock)); + return bytes_written ? bytes_written : -EIO; + +error: + up(&(rio->lock)); + return errn; } static ssize_t @@ -307,12 +347,17 @@ read_count = 0; + down(&(rio->lock)); + while (count > 0) { if (signal_pending(current)) { + up(&(rio->lock)); return read_count ? read_count : -EINTR; } - if (!rio->rio_dev) + if (!rio->rio_dev) { + up(&(rio->lock)); return -ENODEV; + } this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; result = usb_bulk_msg(rio->rio_dev, @@ -327,6 +372,7 @@ count = this_read = partial; } else if (result == USB_ST_TIMEOUT || result == 15) { /* FIXME: 15 ??? */ if (!maxretry--) { + up(&(rio->lock)); err("read_rio: maxretry timeout"); return -ETIME; } @@ -334,21 +380,26 @@ NAK_TIMEOUT); continue; } else if (result != USB_ST_DATAUNDERRUN) { + up(&(rio->lock)); err("Read Whoops - result:%u partial:%u this_read:%u", result, partial, this_read); return -EIO; } else { + up(&(rio->lock)); return (0); } if (this_read) { - if (copy_to_user(buffer, ibuf, this_read)) + if (copy_to_user(buffer, ibuf, this_read)) { + up(&(rio->lock)); return -EFAULT; + } count -= this_read; read_count += this_read; buffer += this_read; } } + up(&(rio->lock)); return read_count; } @@ -383,6 +434,8 @@ } dbg("probe_rio: ibuf address:%p", rio->ibuf); + init_MUTEX(&(rio->lock)); + return rio; } @@ -415,12 +468,11 @@ static struct usb_driver rio_driver = { - "rio500", - probe_rio, - disconnect_rio, - {NULL, NULL}, - &usb_rio_fops, - RIO_MINOR + name: "rio500", + probe: probe_rio, + disconnect: disconnect_rio, + fops: &usb_rio_fops, + minor: RIO_MINOR, }; int usb_rio_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/scanner.c linux/drivers/usb/scanner.c --- v2.2.18/drivers/usb/scanner.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/scanner.c Sun Mar 25 11:37:37 2001 @@ -174,7 +174,7 @@ * . * - Added iVina 1200U ID. Thanks to Dyson Lin . * - Added access time update for the device file courtesy of Paul - * Mackerras . This allows a user space daemon + * Mackerras . This allows a user space daemon * to turn the lamp off for a Umax 1220U scanner after a prescribed * time. * - Fixed HP S20 ID's. Thanks to Ruud Linders . diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/scanner.h linux/drivers/usb/scanner.h --- v2.2.18/drivers/usb/scanner.h Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/scanner.h Sun Mar 25 11:37:37 2001 @@ -151,6 +151,7 @@ { 0x04b8, 0x0101 }, /* Perfection 636U and 636Photo */ { 0x04b8, 0x0103 }, /* Perfection 610 */ { 0x04b8, 0x0104 }, /* Perfection 1200U and 1200Photo */ + { 0x04b8, 0x010b }, /* Perfection 1240U and 1240Photo */ /* Umax */ { 0x1606, 0x0010 }, /* Astra 1220U */ { 0x1606, 0x0002 }, /* Astra 1236U */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in --- v2.2.18/drivers/usb/serial/Config.in Wed Dec 31 19:00:00 1969 +++ linux/drivers/usb/serial/Config.in Sun Mar 25 11:37:37 2001 @@ -0,0 +1,30 @@ +# +# USB Serial device configuration +# +mainmenu_option next_comment +comment 'USB Serial Converter support' + +tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB +if [ "$CONFIG_USB_SERIAL" != "n" ]; then + bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG + bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC + dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL + dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL + dep_tristate ' USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL + dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL + dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL + dep_tristate ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL + dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL + dep_tristate ' USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL + if [ "$CONFIG_USB_SERIAL_KEYSPAN" = "y" -o "$CONFIG_USB_SERIAL_KEYSPAN" = "m" ]; then + bool ' USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 + bool ' USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X + bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19 + bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X + bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W + bool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W + fi + dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL +fi + +endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile --- v2.2.18/drivers/usb/serial/Makefile Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/Makefile Sun Mar 25 11:37:37 2001 @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o +obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o # Objects that export symbols. export-objs := usbserial.o diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c --- v2.2.18/drivers/usb/serial/empeg.c Wed Dec 31 19:00:00 1969 +++ linux/drivers/usb/serial/empeg.c Sun Mar 25 11:37:37 2001 @@ -0,0 +1,703 @@ +/* + * USB Empeg empeg-car player driver + * + * Copyright (C) 2000 + * Gary Brubaker (xavyer@ix.netcom.com) + * + * Copyright (C) 1999, 2000 + * Greg Kroah-Hartman (greg@kroah.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, as published by + * the Free Software Foundation, version 2. + * + * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * (01/22/2001) gb + * Added write_room() and chars_in_buffer() support. + * + * (12/21/2000) gb + * Moved termio stuff inside the port->active check. + * Moved MOD_DEC_USE_COUNT to end of empeg_close(). + * + * (12/03/2000) gb + * Added port->tty->ldisc.set_termios(port->tty, NULL) to empeg_open() + * This notifies the tty driver that the termios have changed. + * + * (11/13/2000) gb + * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open() + * (It only needs to be set once - Doh!) + * + * (11/11/2000) gb + * Updated to work with id_table structure. + * + * (11/04/2000) gb + * Forked this from visor.c, and hacked it up to work with an + * Empeg ltd. empeg-car player. Constructive criticism welcomed. + * I would like to say, 'Thank You' to Greg Kroah-Hartman for the + * use of his code, and for his guidance, advice and patience. :) + * A 'Thank You' is in order for John Ripley of Empeg ltd for his + * advice, and patience too. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_USB_SERIAL_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif +#include + +#include "usb-serial.h" + +#define EMPEG_VENDOR_ID 0x084f +#define EMPEG_PRODUCT_ID 0x0001 + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +/* function prototypes for an empeg-car player */ +static int empeg_open (struct usb_serial_port *port, struct file *filp); +static void empeg_close (struct usb_serial_port *port, struct file *filp); +static int empeg_write (struct usb_serial_port *port, + int from_user, + const unsigned char *buf, + int count); +static int empeg_write_room (struct usb_serial_port *port); +static int empeg_chars_in_buffer (struct usb_serial_port *port); +static void empeg_throttle (struct usb_serial_port *port); +static void empeg_unthrottle (struct usb_serial_port *port); +static int empeg_startup (struct usb_serial *serial); +static void empeg_shutdown (struct usb_serial *serial); +static int empeg_ioctl (struct usb_serial_port *port, + struct file * file, + unsigned int cmd, + unsigned long arg); +static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void empeg_write_bulk_callback (struct urb *urb); +static void empeg_read_bulk_callback (struct urb *urb); + +static __u16 empeg_vendor_id = EMPEG_VENDOR_ID; +static __u16 empeg_product_id = EMPEG_PRODUCT_ID; +struct usb_serial_device_type empeg_device = { + name: "Empeg", + idVendor: &empeg_vendor_id, + idProduct: &empeg_product_id, + needs_interrupt_in: MUST_HAVE_NOT, /* must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: empeg_open, + close: empeg_close, + throttle: empeg_throttle, + unthrottle: empeg_unthrottle, + startup: empeg_startup, + shutdown: empeg_shutdown, + ioctl: empeg_ioctl, + set_termios: empeg_set_termios, + write: empeg_write, + write_room: empeg_write_room, + chars_in_buffer: empeg_chars_in_buffer, + write_bulk_callback: empeg_write_bulk_callback, + read_bulk_callback: empeg_read_bulk_callback, +}; + +#define NUM_URBS 16 +#define URB_TRANSFER_BUFFER_SIZE 4096 + +static struct urb *write_urb_pool[NUM_URBS]; +static spinlock_t write_urb_pool_lock; +static int bytes_in; +static int bytes_out; + +/****************************************************************************** + * Empeg specific driver functions + ******************************************************************************/ +static int empeg_open (struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + unsigned long flags; + int result; + + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + + /* gb - 2000/11/05 + * personally, I think these termios should be set in + * empeg_startup(), but it appears doing so leads to one + * of those chicken/egg problems. :) + */ + port->tty->termios->c_iflag + &= ~(IGNBRK + | BRKINT + | PARMRK + | ISTRIP + | INLCR + | IGNCR + | ICRNL + | IXON); + + port->tty->termios->c_oflag + &= ~OPOST; + + port->tty->termios->c_lflag + &= ~(ECHO + | ECHONL + | ICANON + | ISIG + | IEXTEN); + + port->tty->termios->c_cflag + &= ~(CSIZE + | PARENB); + + port->tty->termios->c_cflag + |= CS8; + + /* gb - 2000/12/03 + * Contributed by Borislav Deianov + * Notify the tty driver that the termios have changed!! + */ + port->tty->ldisc.set_termios(port->tty, NULL); + + /* gb - 2000/11/05 + * force low_latency on + * + * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually + * force the data through if low_latency is set. Otherwise the pushes are + * scheduled; this is bad as it opens up the possibility of dropping bytes + * on the floor. We are trying to sustain high data transfer rates; and + * don't want to drop bytes on the floor. + * Moral: use low_latency - drop no bytes - life is good. :) + */ + port->tty->low_latency = 1; + + port->active = 1; + bytes_in = 0; + bytes_out = 0; + + /* Start reading from the device */ + FILL_BULK_URB( + port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + empeg_read_bulk_callback, + port); + + port->read_urb->transfer_flags |= USB_QUEUE_BULK; + + result = usb_submit_urb(port->read_urb); + + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", result); + + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + return 0; +} + + +static void empeg_close (struct usb_serial_port *port, struct file * filp) +{ + struct usb_serial *serial; + unsigned char *transfer_buffer; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + + spin_lock_irqsave (&port->port_lock, flags); + + --port->open_count; + + if (port->open_count <= 0) { + transfer_buffer = kmalloc (0x12, GFP_KERNEL); + + if (!transfer_buffer) { + err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); + } else { + kfree (transfer_buffer); + } + + /* shutdown our bulk read */ + usb_unlink_urb (port->read_urb); + port->active = 0; + port->open_count = 0; + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + /* Uncomment the following line if you want to see some statistics in your syslog */ + /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ + + MOD_DEC_USE_COUNT; + +} + + +static int empeg_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) +{ + struct usb_serial *serial = port->serial; + struct urb *urb; + const unsigned char *current_position = buf; + unsigned long flags; + int status; + int i; + int bytes_sent = 0; + int transfer_size; + + dbg(__FUNCTION__ " - port %d", port->number); + + usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); + + while (count > 0) { + + /* try to find a free urb in our list of them */ + urb = NULL; + + spin_lock_irqsave (&write_urb_pool_lock, flags); + + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]->status != -EINPROGRESS) { + urb = write_urb_pool[i]; + break; + } + } + + spin_unlock_irqrestore (&write_urb_pool_lock, flags); + + if (urb == NULL) { + dbg (__FUNCTION__ " - no more free urbs"); + goto exit; + } + + if (urb->transfer_buffer == NULL) { + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + if (urb->transfer_buffer == NULL) { + err(__FUNCTION__" no more kernel memory..."); + goto exit; + } + } + + transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE); + + if (from_user) { + copy_from_user (urb->transfer_buffer, current_position, transfer_size); + } else { + memcpy (urb->transfer_buffer, current_position, transfer_size); + } + + /* build up our urb */ + FILL_BULK_URB ( + urb, + serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, + transfer_size, + empeg_write_bulk_callback, + port); + + urb->transfer_flags |= USB_QUEUE_BULK; + + /* send it down the pipe */ + status = usb_submit_urb(urb); + if (status) + dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + + current_position += transfer_size; + bytes_sent += transfer_size; + count -= transfer_size; + bytes_out += transfer_size; + + } + +exit: + return bytes_sent; + +} + + +static int empeg_write_room (struct usb_serial_port *port) +{ + unsigned long flags; + int i; + int room = 0; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + /* tally up the number of bytes available */ + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]->status != -EINPROGRESS) { + room += URB_TRANSFER_BUFFER_SIZE; + } + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + dbg(__FUNCTION__ " - returns %d", room); + + return (room); + +} + + +static int empeg_chars_in_buffer (struct usb_serial_port *port) +{ + unsigned long flags; + int i; + int chars = 0; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + /* tally up the number of bytes waiting */ + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]->status == -EINPROGRESS) { + chars += URB_TRANSFER_BUFFER_SIZE; + } + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + dbg (__FUNCTION__ " - returns %d", chars); + + return (chars); + +} + + +static void empeg_write_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + return; + } + + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return; + +} + + +static void empeg_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int i; + int result; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); + return; + } + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + return; + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + tty = port->tty; + + if (urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + /* gb - 2000/11/13 + * If we insert too many characters we'll overflow the buffer. + * This means we'll lose bytes - Decidedly bad. + */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + tty_insert_flip_char(tty, data[i], 0); + } + /* gb - 2000/11/13 + * Goes straight through instead of scheduling - if tty->low_latency is set. + */ + tty_flip_buffer_push(tty); + bytes_in += urb->actual_length; + } + + /* Continue trying to always read */ + FILL_BULK_URB( + port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + empeg_read_bulk_callback, + port); + + port->read_urb->transfer_flags |= USB_QUEUE_BULK; + + result = usb_submit_urb(port->read_urb); + + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + + return; + +} + + +static void empeg_throttle (struct usb_serial_port *port) +{ + unsigned long flags; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + usb_unlink_urb (port->read_urb); + + spin_unlock_irqrestore (&port->port_lock, flags); + + return; + +} + + +static void empeg_unthrottle (struct usb_serial_port *port) +{ + unsigned long flags; + int result; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + port->read_urb->dev = port->serial->dev; + + result = usb_submit_urb(port->read_urb); + + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", result); + + spin_unlock_irqrestore (&port->port_lock, flags); + + return; + +} + + +static int empeg_startup (struct usb_serial *serial) +{ + + dbg(__FUNCTION__); + + dbg(__FUNCTION__ " - Set config to 1"); + usb_set_configuration (serial->dev, 1); + + /* continue on with initialization */ + return 0; + +} + + +static void empeg_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + empeg_close (&serial->port[i], NULL); + } + } + +} + + +static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd); + + return -ENOIOCTLCMD; +} + + +/* This function is all nice and good, but we don't change anything based on it :) */ +static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios) +{ + unsigned int cflag = port->tty->termios->c_cflag; + + dbg(__FUNCTION__ " - port %d", port->number); + + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg(__FUNCTION__ " - nothing to change..."); + return; + } + } + + if ((!port->tty) || (!port->tty->termios)) { + dbg(__FUNCTION__" - no tty structures"); + return; + } + + /* get the byte size */ + switch (cflag & CSIZE) { + case CS5: dbg(__FUNCTION__ " - data bits = 5"); break; + case CS6: dbg(__FUNCTION__ " - data bits = 6"); break; + case CS7: dbg(__FUNCTION__ " - data bits = 7"); break; + default: + case CS8: dbg(__FUNCTION__ " - data bits = 8"); break; + } + + /* determine the parity */ + if (cflag & PARENB) + if (cflag & PARODD) + dbg(__FUNCTION__ " - parity = odd"); + else + dbg(__FUNCTION__ " - parity = even"); + else + dbg(__FUNCTION__ " - parity = none"); + + /* figure out the stop bits requested */ + if (cflag & CSTOPB) + dbg(__FUNCTION__ " - stop bits = 2"); + else + dbg(__FUNCTION__ " - stop bits = 1"); + + /* figure out the flow control settings */ + if (cflag & CRTSCTS) + dbg(__FUNCTION__ " - RTS/CTS is enabled"); + else + dbg(__FUNCTION__ " - RTS/CTS is disabled"); + + /* determine software flow control */ + if (I_IXOFF(port->tty)) + dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty)); + else + dbg(__FUNCTION__ " - XON/XOFF is disabled"); + + /* get the baud rate wanted */ + dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty)); + + return; + +} + + +static int __init empeg_init (void) +{ + struct urb *urb; + int i; + + usb_serial_register (&empeg_device); + + /* create our write urb pool and transfer buffers */ + spin_lock_init (&write_urb_pool_lock); + for (i = 0; i < NUM_URBS; ++i) { + urb = usb_alloc_urb(0); + write_urb_pool[i] = urb; + if (urb == NULL) { + err("No more urbs???"); + continue; + } + + urb->transfer_buffer = NULL; + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + if (!urb->transfer_buffer) { + err (__FUNCTION__ " - out of memory for urb buffers."); + continue; + } + } + + return 0; + +} + + +static void __exit empeg_exit (void) +{ + int i; + unsigned long flags; + + usb_serial_deregister (&empeg_device); + + spin_lock_irqsave (&write_urb_pool_lock, flags); + + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]) { + /* FIXME - uncomment the following usb_unlink_urb call when + * the host controllers get fixed to set urb->dev = NULL after + * the urb is finished. Otherwise this call oopses. */ + /* usb_unlink_urb(write_urb_pool[i]); */ + if (write_urb_pool[i]->transfer_buffer) + kfree(write_urb_pool[i]->transfer_buffer); + usb_free_urb (write_urb_pool[i]); + } + } + + spin_unlock_irqrestore (&write_urb_pool_lock, flags); + +} + + +module_init(empeg_init); +module_exit(empeg_exit); + +MODULE_AUTHOR("Gary Brubaker "); +MODULE_DESCRIPTION("USB Empeg Mark I/II Driver"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.2.18/drivers/usb/serial/ftdi_sio.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/ftdi_sio.c Sun Mar 25 11:37:37 2001 @@ -12,6 +12,28 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info + * and extra documentation + * + * (12/3/2000) Bill Ryder + * Added support for 8U232AM device. + * Moved PID and VIDs into header file only. + * Turned on low-latency for the tty (device will do high baudrates) + * Added shutdown routine to close files when device removed. + * More debug and error message cleanups. + * + * + * (11/13/2000) Bill Ryder + * Added spinlock protected open code and close code. + * Multiple opens work (sort of - see webpage mentioned above). + * Cleaned up comments. Removed multiple PID/VID definitions. + * Factorised cts/dtr code + * Made use of __FUNCTION__ in dbg's + * + * (10/05/2000) gkh + * Fixed bug with urb->dev not being set properly, now that the usb + * core needs it. + * * (09/11/2000) gkh * Removed DEBUG #ifdefs with call to usb_serial_debug_data * @@ -20,11 +42,11 @@ * driver is a loadable module now. * * (04/04/2000) Bill Ryder - * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are - * handled elsewhere in the serial driver chain). + * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are + * handled elsewhere in the tty io driver chain). * * (03/30/2000) Bill Ryder - * Implemented lots of ioctls + * Implemented lots of ioctls * Fixed a race condition in write * Changed some dbg's to errs * @@ -36,6 +58,7 @@ /* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */ /* Thanx to FTDI for so kindly providing details of the protocol required */ /* to talk to the device */ +/* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */ #include @@ -64,11 +87,19 @@ #include "ftdi_sio.h" -#define FTDI_VENDOR_ID 0x0403 -#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372 + + +struct ftdi_private { + ftdi_type_t ftdi_type; + char last_status_byte; /* device sends this every 40ms when open */ + + +}; /* function prototypes for a FTDI serial converter */ static int ftdi_sio_startup (struct usb_serial *serial); +static int ftdi_8U232AM_startup (struct usb_serial *serial); +static void ftdi_sio_shutdown (struct usb_serial *serial); static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp); static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp); static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); @@ -78,8 +109,9 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); /* All of the device info needed for the FTDI SIO serial converter */ -static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; -static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID; +static __u16 ftdi_vendor_id = FTDI_VID; +static __u16 ftdi_sio_product_id = FTDI_SIO_PID; +static __u16 ftdi_8U232AM_product_id = FTDI_8U232AM_PID; struct usb_serial_device_type ftdi_sio_device = { name: "FTDI SIO", idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */ @@ -99,6 +131,29 @@ ioctl: ftdi_sio_ioctl, set_termios: ftdi_sio_set_termios, startup: ftdi_sio_startup, + shutdown: ftdi_sio_shutdown, +}; + +struct usb_serial_device_type ftdi_8U232AM_device = { + name: "FTDI 8U232AM", + idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */ + idProduct: &ftdi_8U232AM_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 0, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: ftdi_sio_open, + close: ftdi_sio_close, + write: ftdi_sio_write, + read_bulk_callback: ftdi_sio_read_bulk_callback, + write_bulk_callback: ftdi_sio_write_bulk_callback, + ioctl: ftdi_sio_ioctl, + set_termios: ftdi_sio_set_termios, + startup: ftdi_8U232AM_startup, + shutdown: ftdi_sio_shutdown, }; @@ -106,119 +161,151 @@ * *************************************************************************** * FTDI SIO Serial Converter specific driver functions * *************************************************************************** - * - * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code - * Thanx to FTDI for so kindly providing details of the protocol required - * to talk to the device - http://www.ftdi.co.uk - * - * Tested as at this version - other stuff might work - * 23 March 2000 - * Works: - * Baudrates - 9600, 38400,19200, 57600, 115200 - * TIOCMBIC - TIOCM_DTR / TIOCM_RTS - * TIOCMBIS - TIOCM_DTR / TIOCM_RTS - * TIOCMSET - DTR on/RTSon / DTR off, RTS off - * no parity:CS8 even parity:CS7 odd parity:CS7 - * CRTSCTS flow control - * - * Pilot-xfer zillions of times - * - * cu works with dir option - * - * Not Tested (ie might not work): - * xon/xoff flow control - * ppp (modem handling in general) - * - * KNOWN BUGS: - * Multiple Opens - * ============== - * Seems to have problem when opening an already open port, - * Get I/O error on first attempt, then it lets you in. - * Need to do proper usage counting - keep registered callbacks for first opener. - * - * Reproduce with: - * cu -l /dev/ttyUSB0 dir - * whilst cu is running do: - * stty -a < /dev/ttyUSB0 - * - * from stty get: 'bash: /dev/ttyUSB0: Invalid argument ' - * from cu get - * write: Invalid argument - * - * Initialisation Problem - * ====================== - * Pilot transfer required me to run the serial_loopback program before it would work. - * Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio - * */ #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */ -/* do some startup allocations not currently performed by usb_serial_probe() */ +/* utility functions to set and unset dtr and rts */ +#define HIGH 1 +#define LOW 0 +static int set_rts(struct usb_device *dev, + unsigned int pipe, + int high_or_low) +{ + static char buf[1]; + unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH : + FTDI_SIO_SET_RTS_LOW); + return(usb_control_msg(dev, pipe, + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + ftdi_high_or_low, 0, + buf, 0, WDR_TIMEOUT)); +} +static int set_dtr(struct usb_device *dev, + unsigned int pipe, + int high_or_low) +{ + static char buf[1]; + unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH : + FTDI_SIO_SET_DTR_LOW); + return(usb_control_msg(dev, pipe, + FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + ftdi_high_or_low, 0, + buf, 0, WDR_TIMEOUT)); +} + + + static int ftdi_sio_startup (struct usb_serial *serial) { + struct ftdi_private *priv; + init_waitqueue_head(&serial->port[0].write_wait); + priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); + if (!priv){ + err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private)); + return -ENOMEM; + } + + priv->ftdi_type = sio; + + return (0); +} + + +static int ftdi_8U232AM_startup (struct usb_serial *serial) +{ + struct ftdi_private *priv; + + init_waitqueue_head(&serial->port[0].write_wait); + + priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); + if (!priv){ + err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private)); + return -ENOMEM; + } + + priv->ftdi_type = F8U232AM; + return (0); } +static void ftdi_sio_shutdown (struct usb_serial *serial) +{ + + dbg (__FUNCTION__); + + /* Close ports if they are open */ + while (serial->port[0].open_count > 0) { + ftdi_sio_close (&serial->port[0], NULL); + } + if (serial->port->private){ + kfree(serial->port->private); + serial->port->private = NULL; + } +} + + + static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp) { /* ftdi_sio_open */ struct termios tmp_termios; struct usb_serial *serial = port->serial; + unsigned long flags; /* Used for spinlock */ + int result; char buf[1]; /* Needed for the usb_control_msg I think */ - dbg("ftdi_sio_open port %d", port->number); - - /* FIXME - multiple concurrent opens cause trouble */ - if (port->active) { - err ("port already open"); - return -EINVAL; - } - port->active = 1; /* FIXME - For multiple open this should increment */ - - /* See ftdi_sio.h for description of what is reset */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, - FTDI_SIO_RESET_SIO, - 0, buf, 0, WDR_TIMEOUT); - - /* Setup termios */ - port->tty->termios->c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; + dbg(__FUNCTION__); + spin_lock_irqsave (&port->port_lock, flags); - ftdi_sio_set_termios(port, &tmp_termios); + MOD_INC_USE_COUNT; + ++port->open_count; - /* Disable flow control */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("error from flowcontrol urb"); - return(-EINVAL); - } - - /* Turn on RTS and DTR since we are not flow controlling*/ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from DTR HIGH urb"); + if (!port->active){ + port->active = 1; + + spin_unlock_irqrestore (&port->port_lock, flags); + + /* do not allow a task to be queued to deliver received data */ + port->tty->low_latency = 1; + + /* No error checking for this (will get errors later anyway) */ + /* See ftdi_sio.h for description of what is reset */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_SIO, + 0, buf, 0, WDR_TIMEOUT); + + /* Setup termios defaults. According to tty_io.c the + settings are driver specific */ + port->tty->termios->c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + + /* ftdi_sio_set_termios will send usb control messages */ + ftdi_sio_set_termios(port, &tmp_termios); + + /* Turn on RTS and DTR since we are not flow controlling by default */ + if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) { + err(__FUNCTION__ " Error from DTR HIGH urb"); + } + if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){ + err(__FUNCTION__ " Error from RTS HIGH urb"); + } + + /* Start reading from the device */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + ftdi_sio_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", result); + } else { /* the port was already active - so no initialisation is done */ + spin_unlock_irqrestore (&port->port_lock, flags); } - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from RTS HIGH urb"); - } - - /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) - err("usb_submit_urb(read bulk) failed"); return (0); } /* ftdi_sio_open */ @@ -229,41 +316,52 @@ struct usb_serial *serial = port->serial; unsigned int c_cflag = port->tty->termios->c_cflag; char buf[1]; + unsigned long flags; - dbg("ftdi_sio_close port %d", port->number); - - if (c_cflag & HUPCL){ - /* Disable flow control */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("error from flowcontrol urb"); - } + dbg( __FUNCTION__); - /* drop DTR */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_DTR_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from DTR LOW urb"); + spin_lock_irqsave (&port->port_lock, flags); + --port->open_count; + + if (port->open_count <= 0) { + spin_unlock_irqrestore (&port->port_lock, flags); + if (c_cflag & HUPCL){ + /* Disable flow control */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, 0, + buf, 0, WDR_TIMEOUT) < 0) { + err("error from flowcontrol urb"); + } + + /* drop DTR */ + if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){ + err("Error from DTR LOW urb"); + } + /* drop RTS */ + if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) { + err("Error from RTS LOW urb"); + } + } /* Note change no line is hupcl is off */ + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); + port->active = 0; + port->open_count = 0; + } else { + spin_unlock_irqrestore (&port->port_lock, flags); + + /* Send a HUP if necessary */ + if (!(port->tty->termios->c_cflag & CLOCAL)){ + tty_hangup(port->tty); } - /* drop RTS */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_RTS_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from RTS LOW urb"); - } + } - /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - port->active = 0; + MOD_DEC_USE_COUNT; + } /* ftdi_sio_close */ @@ -277,32 +375,37 @@ const unsigned char *buf, int count) { /* ftdi_sio_write */ struct usb_serial *serial = port->serial; - const int data_offset = 1; + struct ftdi_private *priv = (struct ftdi_private *)port->private; + int data_offset ; int rc; + int result; DECLARE_WAITQUEUE(wait, current); - dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count); + dbg(__FUNCTION__ " port %d, %d bytes", port->number, count); if (count == 0) { err("write request of 0 bytes"); return 0; } + + if (priv->ftdi_type == sio){ + data_offset = 1; + } else { + data_offset = 0; + } + dbg("data_offset set to %d",data_offset); /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { unsigned char *first_byte = port->write_urb->transfer_buffer; /* Was seeing a race here, got a read callback, then write callback before - hitting interuptible_sleep_on - so wrapping in add_wait_queue stuff */ + hitting interuptible_sleep_on - so wrapping in a wait_queue */ add_wait_queue(&port->write_wait, &wait); set_current_state (TASK_INTERRUPTIBLE); while (port->write_urb->status == -EINPROGRESS) { - dbg("ftdi_sio - write in progress - retrying"); - if (0 /* file->f_flags & O_NONBLOCK */) { - rc = -EAGAIN; - goto err; - } + dbg(__FUNCTION__ " write in progress - retrying"); if (signal_pending(current)) { current->state = TASK_RUNNING; remove_wait_queue(&port->write_wait, &wait); @@ -330,20 +433,28 @@ buf, count - data_offset ); } - /* Write the control byte at the front of the packet*/ first_byte = port->write_urb->transfer_buffer; - *first_byte = 1 | ((count-data_offset) << 2) ; + if (data_offset > 0){ + /* Write the control byte at the front of the packet*/ + *first_byte = 1 | ((count-data_offset) << 2) ; + } - dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]); + dbg(__FUNCTION__ " Bytes: %d, First Byte: 0o%03o",count, first_byte[0]); usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte); /* send the data out the bulk port */ - port->write_urb->transfer_buffer_length = count; - - if (usb_submit_urb(port->write_urb)) - err("usb_submit_urb(write bulk) failed"); + FILL_BULK_URB(port->write_urb, serial->dev, + usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, count, + ftdi_sio_write_bulk_callback, port); + + result = usb_submit_urb(port->write_urb); + if (result) { + err(__FUNCTION__ " - failed submitting write urb, error %d", result); + return 0; + } - dbg("write returning: %d", count - data_offset); + dbg(__FUNCTION__ " write returning: %d", count - data_offset); return (count - data_offset); } @@ -387,14 +498,16 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) { /* ftdi_sio_serial_buld_callback */ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct ftdi_private *priv = (struct ftdi_private *)port->private; struct usb_serial *serial; struct tty_struct *tty = port->tty ; unsigned char *data = urb->transfer_buffer; const int data_offset = 2; int i; + int result; - dbg("ftdi_sio read callback"); + dbg(__FUNCTION__); if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) { return; @@ -404,10 +517,6 @@ if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) { return; } - - /* TO DO -- check for hung up line and handle appropriately: */ - /* send hangup (need to find out how to do this) */ - if (urb->status) { /* This will happen at close every time so it is a dbg not an err */ @@ -421,6 +530,14 @@ dbg("Just status"); } + priv->last_status_byte = data[0]; /* this has modem control lines */ + + /* TO DO -- check for hung up line and handle appropriately: */ + /* send hangup */ + /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */ + /* if CD is dropped and the line is not CLOCAL then we should hangup */ + + if (urb->actual_length > data_offset) { for (i = data_offset ; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); @@ -429,12 +546,65 @@ } /* Continue trying to always read */ - if (usb_submit_urb(urb)) - err("failed resubmitting read urb"); + FILL_BULK_URB(urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + urb->transfer_buffer, urb->transfer_buffer_length, + ftdi_sio_read_bulk_callback, port); + + result = usb_submit_urb(urb); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; } /* ftdi_sio_serial_read_bulk_callback */ + +__u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) +{ /* translate_baudrate_to_ftdi */ + + __u16 urb_value = ftdi_sio_b9600; + + if (ftdi_type == sio){ + switch(cflag & CBAUD){ + case B0: break; /* ignored by this */ + case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break; + case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break; + case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break; + case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break; + case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break; + case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break; + case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break; + case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break; + case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break; + case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break; + default: dbg(__FUNCTION__ " FTDI_SIO does not support the baudrate (%d) requested", + (cflag & CBAUD)); + break; + } + } else { /* it is 8U232AM */ + switch(cflag & CBAUD){ + case B0: break; /* ignored by this */ + case B300: urb_value = ftdi_8U232AM_48MHz_b300; dbg("Set to 300"); break; + case B600: urb_value = ftdi_8U232AM_48MHz_b600; dbg("Set to 600") ; break; + case B1200: urb_value = ftdi_8U232AM_48MHz_b1200; dbg("Set to 1200") ; break; + case B2400: urb_value = ftdi_8U232AM_48MHz_b2400; dbg("Set to 2400") ; break; + case B4800: urb_value = ftdi_8U232AM_48MHz_b4800; dbg("Set to 4800") ; break; + case B9600: urb_value = ftdi_8U232AM_48MHz_b9600; dbg("Set to 9600") ; break; + case B19200: urb_value = ftdi_8U232AM_48MHz_b19200; dbg("Set to 19200") ; break; + case B38400: urb_value = ftdi_8U232AM_48MHz_b38400; dbg("Set to 38400") ; break; + case B57600: urb_value = ftdi_8U232AM_48MHz_b57600; dbg("Set to 57600") ; break; + case B115200: urb_value = ftdi_8U232AM_48MHz_b115200; dbg("Set to 115200") ; break; + case B230400: urb_value = ftdi_8U232AM_48MHz_b230400; dbg("Set to 230400") ; break; + case B460800: urb_value = ftdi_8U232AM_48MHz_b460800; dbg("Set to 460800") ; break; + case B921600: urb_value = ftdi_8U232AM_48MHz_b921600; dbg("Set to 921600") ; break; + default: dbg(__FUNCTION__ " The baudrate (%d) requested is not implemented", + (cflag & CBAUD)); + break; + } + } + return(urb_value); +} + /* As I understand this - old_termios contains the original termios settings */ /* and tty->termios contains the new setting to be used */ /* */ @@ -444,10 +614,12 @@ { /* ftdi_sio_set_termios */ struct usb_serial *serial = port->serial; unsigned int cflag = port->tty->termios->c_cflag; - __u16 urb_value; /* Will hold the new flags */ + struct ftdi_private *priv = (struct ftdi_private *)port->private; + __u16 urb_value; /* will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ - dbg("ftdi_sio_set_termios port %d", port->number); + + dbg(__FUNCTION__); /* FIXME -For this cut I don't care if the line is really changing or @@ -481,26 +653,12 @@ FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , 0, buf, 0, 100) < 0) { - err("FAILED to set databits/stopbits/parity"); + err(__FUNCTION__ " FAILED to set databits/stopbits/parity"); } /* Now do the baudrate */ - - switch(cflag & CBAUD){ - case B0: break; /* Handled below */ - case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break; - case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break; - case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break; - case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break; - case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break; - case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break; - case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break; - case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break; - case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break; - case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break; - default: dbg("FTDI_SIO does not support the baudrate requested"); - /* FIXME - how to return an error for this? */ break; - } + urb_value = translate_baudrate_to_ftdi((cflag & CBAUD), priv->ftdi_type); + if ((cflag & CBAUD) == B0 ) { /* Disable flow control */ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -508,38 +666,31 @@ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, 0, buf, 0, WDR_TIMEOUT) < 0) { - err("error from disable flowcontrol urb"); + err(__FUNCTION__ " error from disable flowcontrol urb"); } /* Drop RTS and DTR */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_DTR_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from DTR LOW urb"); + if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){ + err(__FUNCTION__ " Error from DTR LOW urb"); } - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - (unsigned)FTDI_SIO_SET_RTS_LOW, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("Error from RTS LOW urb"); + if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){ + err(__FUNCTION__ " Error from RTS LOW urb"); } } else { + /* set the baudrate determined before */ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, urb_value, 0, buf, 0, 100) < 0) { - err("urb failed to set baurdrate"); + err(__FUNCTION__ " urb failed to set baurdrate"); } } /* Set flow control */ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ if (cflag & CRTSCTS) { - dbg("Setting to CRTSCTS flow control"); + dbg(__FUNCTION__ " Setting to CRTSCTS flow control"); if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -550,9 +701,8 @@ } } else { - /* CHECK Assuming XON/XOFF handled by stack - not by device */ - /* Disable flow control */ - dbg("Turning off hardware flow control"); + /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ + dbg(__FUNCTION__ " Turning off hardware flow control"); if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -569,26 +719,38 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) { struct usb_serial *serial = port->serial; + struct ftdi_private *priv = (struct ftdi_private *)port->private; __u16 urb_value=0; /* Will hold the new flags */ char buf[1]; int ret, mask; - dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd); + dbg(__FUNCTION__ " cmd 0x%04x", cmd); /* Based on code from acm.c and others */ switch (cmd) { case TIOCMGET: - dbg("TIOCMGET"); - /* Request the status from the device */ - if ((ret = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, - FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, - buf, 1, HZ * 5)) < 0 ) { - dbg("Get not get modem status of device"); - return(ret); + dbg(__FUNCTION__ " TIOCMGET"); + /* The MODEM_STATUS_REQUEST works for the sio but not the 232 */ + if (priv->ftdi_type == sio){ + /* TO DECIDE - use the 40ms status packets or not? */ + /* PRO: No need to send urb */ + /* CON: Could be 40ms out of date */ + + /* Request the status from the device */ + if ((ret = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, + 0, 0, + buf, 1, WDR_TIMEOUT)) < 0 ) { + err(__FUNCTION__ " Could not get modem status of device - err: %d", + ret); + return(ret); + } + } else { + /* This gets updated every 40ms - so just copy it in */ + buf[0] = priv->last_status_byte; } return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | @@ -599,51 +761,33 @@ break; case TIOCMSET: /* Turns on and off the lines as specified by the mask */ - dbg("TIOCMSET"); + dbg(__FUNCTION__ " TIOCMSET"); if ((ret = get_user(mask, (unsigned long *) arg))) return ret; - urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW); - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - urb_value , 0, - buf, 0, WDR_TIMEOUT)) < 0){ - err("Urb to set DTR failed"); - return(ret); - } - urb_value = ((mask & TIOCM_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW); - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - urb_value , 0, - buf, 0, WDR_TIMEOUT)) < 0){ - err("Urb to set RTS failed"); - return(ret); - } + urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW); + if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){ + err("Error from DTR set urb (TIOCMSET)"); + } + urb_value = ((mask & TIOCM_RTS) ? HIGH : LOW); + if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){ + err("Error from RTS set urb (TIOCMSET)"); + } break; case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ - dbg("TIOCMBIS"); + dbg(__FUNCTION__ " TIOCMBIS"); if ((ret = get_user(mask, (unsigned long *) arg))) return ret; if (mask & TIOCM_DTR){ - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_DTR_HIGH , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + if ((ret = set_dtr(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + HIGH)) < 0) { err("Urb to set DTR failed"); return(ret); - } } - if (mask & TIOCM_RTS) { - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_RTS_HIGH , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + } + if (mask & TIOCM_RTS) { + if ((ret = set_rts(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + HIGH)) < 0){ err("Urb to set RTS failed"); return(ret); } @@ -651,26 +795,20 @@ break; case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ - dbg("TIOCMBIC"); + dbg(__FUNCTION__ " TIOCMBIC"); if ((ret = get_user(mask, (unsigned long *) arg))) return ret; if (mask & TIOCM_DTR){ - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_DTR_LOW , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + if ((ret = set_dtr(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + LOW)) < 0){ err("Urb to unset DTR failed"); return(ret); } } if (mask & TIOCM_RTS) { - if ((ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - FTDI_SIO_SET_RTS_LOW , 0, - buf, 0, WDR_TIMEOUT)) < 0){ + if ((ret = set_rts(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + LOW)) < 0){ err("Urb to unset RTS failed"); return(ret); } @@ -690,25 +828,28 @@ /* This is not an error - turns out the higher layers will do * some ioctls itself (see comment above) */ - dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd); + dbg(__FUNCTION__ " arg not supported - it was 0x%04x",cmd); return(-ENOIOCTLCMD); break; } - dbg("ftdi_sio_ioctl returning 0"); return 0; } /* ftdi_sio_ioctl */ static int __init ftdi_sio_init (void) { + dbg(__FUNCTION__); usb_serial_register (&ftdi_sio_device); + usb_serial_register (&ftdi_8U232AM_device); return 0; } static void __exit ftdi_sio_exit (void) { + dbg(__FUNCTION__); usb_serial_deregister (&ftdi_sio_device); + usb_serial_deregister (&ftdi_8U232AM_device); } @@ -716,4 +857,4 @@ module_exit(ftdi_sio_exit); MODULE_AUTHOR("Greg Kroah-Hartman , Bill Ryder "); -MODULE_DESCRIPTION("USB FTDI SIO driver"); +MODULE_DESCRIPTION("USB FTDI RS232 converters driver"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/ftdi_sio.h linux/drivers/usb/serial/ftdi_sio.h --- v2.2.18/drivers/usb/serial/ftdi_sio.h Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/ftdi_sio.h Sun Mar 25 11:37:37 2001 @@ -20,9 +20,9 @@ */ #define FTDI_VID 0x0403 /* Vendor Id */ -#define FTDI_SIO_PID 0x8372 /* Product Id */ +#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ +#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ -/* Vendor Request Interface */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ #define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ @@ -86,6 +86,12 @@ */ typedef enum { + sio = 1, + F8U232AM = 2, +} ftdi_type_t; + + +typedef enum { ftdi_sio_b300 = 0, ftdi_sio_b600 = 1, ftdi_sio_b1200 = 2, @@ -97,6 +103,38 @@ ftdi_sio_b57600 = 8, ftdi_sio_b115200 = 9 } FTDI_SIO_baudrate_t ; + + +typedef enum { + ftdi_8U232AM_12MHz_b300 = 0x09c4, + ftdi_8U232AM_12MHz_b600 = 0x04E2, + ftdi_8U232AM_12MHz_b1200 = 0x0271, + ftdi_8U232AM_12MHz_b2400 = 0x4138, + ftdi_8U232AM_12MHz_b4800 = 0x809c, + ftdi_8U232AM_12MHz_b9600 = 0xc04e, + ftdi_8U232AM_12MHz_b19200 = 0x0027, + ftdi_8U232AM_12MHz_b38400 = 0x4013, + ftdi_8U232AM_12MHz_b57600 = 0x000d, + ftdi_8U232AM_12MHz_b115200 = 0x4006, + ftdi_8U232AM_12MHz_b230400 = 0x8003, +} FTDI_8U232AM_12MHz_baudrate_t; +/* Apparently all devices are 48MHz */ +typedef enum { + ftdi_8U232AM_48MHz_b300 = 0x2710, + ftdi_8U232AM_48MHz_b600 = 0x1388, + ftdi_8U232AM_48MHz_b1200 = 0x09c4, + ftdi_8U232AM_48MHz_b2400 = 0x04e2, + ftdi_8U232AM_48MHz_b4800 = 0x0271, + ftdi_8U232AM_48MHz_b9600 = 0x4138, + ftdi_8U232AM_48MHz_b19200 = 0x809c, + ftdi_8U232AM_48MHz_b38400 = 0xc04e, + ftdi_8U232AM_48MHz_b57600 = 0x0034, + ftdi_8U232AM_48MHz_b115200 = 0x001a, + ftdi_8U232AM_48MHz_b230400 = 0x000d, + ftdi_8U232AM_48MHz_b460800 = 0x4006, + ftdi_8U232AM_48MHz_b921600 = 0x8003, + +} FTDI_8U232AM_48MHz_baudrate_t; #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA #define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c --- v2.2.18/drivers/usb/serial/keyspan.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/keyspan.c Sun Mar 25 11:37:37 2001 @@ -19,21 +19,33 @@ and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. Thanks Guys :) + Thanks to Paulus for miscellaneous tidy ups, some largish chunks + of much nicer and/or completely new code and (perhaps most uniquely) + having the patience to sit down and explain why and where he'd changed + stuff. + Tip 'o the hat to Linuxcare for supporting staff in their work on open source projects. - Wed Jul 19 14:00:42 EST 2000 gkh - Added module_init and module_exit functions to handle the fact that this - driver is a loadable module now. - - Tue Jul 18 16:14:52 EST 2000 Hugh - Basic character input/output for USA-19 now mostly works, - fixed at 9600 baud for the moment. - + Change History + Tue Oct 10 23:15:33 EST 2000 Hugh + Merged Paul's changes with my USA-49W mods. Work in progress + still... + + Wed Jul 19 14:00:42 EST 2000 gkh + Added module_init and module_exit functions to handle the fact that + this driver is a loadable module now. + + Tue Jul 18 16:14:52 EST 2000 Hugh + Basic character input/output for USA-19 now mostly works, + fixed at 9600 baud for the moment. + + Sat Jul 8 11:11:48 EST 2000 Hugh + First public release - nothing works except the firmware upload. + Tested on PPC and x86 architectures, seems to behave... */ -#include #include #include #include @@ -42,59 +54,136 @@ #include #include #include +#include #include #include -#include #include #include -#ifdef CONFIG_USB_SERIAL_DEBUG +#define DEBUG +/* #ifdef CONFIG_USB_SERIAL_DEBUG */ #define DEBUG -#else - #undef DEBUG -#endif +/* #endif */ #include #include "usb-serial.h" #include "keyspan.h" +#define INSTAT_BUFLEN 32 +#define GLOCONT_BUFLEN 64 + /* Per device and per port private data */ struct keyspan_serial_private { - struct urb *in_urbs[8]; - struct urb *out_urbs[8]; - char out_buffer[64]; - char in_buffer[64]; + /* number of active ports */ + atomic_t active_count; + + const keyspan_device_details *device_details; + + urb_t *instat_urb; + char instat_buf[INSTAT_BUFLEN]; + + /* XXX this one probably will need a lock */ + urb_t *glocont_urb; + char glocont_buf[GLOCONT_BUFLEN]; }; struct keyspan_port_private { - /* Keep track of which output endpoint to use */ + /* Keep track of which input & output endpoints to use */ + int in_flip; int out_flip; - /* Settings for the port */ + /* Keep duplicate of device details in each port + structure as well - simplifies some of the + callback functions etc. */ + const keyspan_device_details *device_details; + + /* Input endpoints and buffer for this port */ + urb_t *in_urbs[2]; + char in_buffer[2][64]; + /* Output endpoints and buffer for this port */ + urb_t *out_urbs[2]; + char out_buffer[2][64]; + + /* Input ack endpoint */ + urb_t *inack_urb; + char inack_buffer[1]; + + /* Output control endpoint */ + urb_t *outcont_urb; + char outcont_buffer[64]; + + /* Settings for the port */ int baud; int old_baud; - enum {parity_none, parity_odd, parity_even} parity; + unsigned int cflag; enum {flow_none, flow_cts, flow_xon} flow_control; - int rts_state; + int rts_state; /* Handshaking pins (outputs) */ int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; + unsigned long tx_start_time[2]; + int resend_cont; /* need to resend control packet */ }; - - /* FIXME this will break if multiple physical interfaces used */ -static wait_queue_head_t out_wait; - /* Include Keyspan message headers (not both yet, need some tweaks - to get clean build) */ -/*#include "keyspan_usa26msg.h"*/ +/* Include Keyspan message headers. All current Keyspan Adapters + make use of one of three message formats which are referred + to as USA-26, USA-28 and USA-49 by Keyspan and within this driver. */ +#include "keyspan_usa26msg.h" #include "keyspan_usa28msg.h" +#include "keyspan_usa49msg.h" - /* If you don't get debugging output, uncomment the following - two lines to enable cheat. */ -#undef dbg -#define dbg printk +/* If you don't get debugging output, uncomment the following + two lines to enable cheat. */ +#if 0 + #undef dbg + #define dbg printk +#endif + +static void keyspan_send_setup(struct usb_serial_port *port); + +/* Functions used by new usb-serial code. */ +int keyspan_init (void) +{ + usb_serial_register (&keyspan_usa18x_pre_device); + usb_serial_register (&keyspan_usa19_pre_device); + usb_serial_register (&keyspan_usa19w_pre_device); + usb_serial_register (&keyspan_usa28_pre_device); + usb_serial_register (&keyspan_usa28x_pre_device); + usb_serial_register (&keyspan_usa49w_pre_device); + + usb_serial_register (&keyspan_usa18x_device); + usb_serial_register (&keyspan_usa19_device); + usb_serial_register (&keyspan_usa19w_device); + usb_serial_register (&keyspan_usa28_device); + usb_serial_register (&keyspan_usa28x_device); + usb_serial_register (&keyspan_usa49w_device); + return 0; +} + +void keyspan_exit (void) +{ + usb_serial_deregister (&keyspan_usa18x_pre_device); + usb_serial_deregister (&keyspan_usa19_pre_device); + usb_serial_deregister (&keyspan_usa19w_pre_device); + usb_serial_deregister (&keyspan_usa28_pre_device); + usb_serial_deregister (&keyspan_usa28x_pre_device); + usb_serial_deregister (&keyspan_usa49w_pre_device); + + usb_serial_deregister (&keyspan_usa18x_device); + usb_serial_deregister (&keyspan_usa19_device); + usb_serial_deregister (&keyspan_usa19w_device); + usb_serial_deregister (&keyspan_usa28_device); + usb_serial_deregister (&keyspan_usa28x_device); + usb_serial_deregister (&keyspan_usa49w_device); +} + +module_init(keyspan_init); +module_exit(keyspan_exit); - /* Functions - mostly stubs for now */ static void keyspan_rx_throttle (struct usb_serial_port *port) { dbg("keyspan_rx_throttle port %d", port->number); @@ -116,180 +205,597 @@ static void keyspan_set_termios (struct usb_serial_port *port, struct termios *old_termios) { - dbg("keyspan_set_termios"); + int baud_rate; + struct keyspan_port_private *p_priv; + const keyspan_device_details *d_details; + unsigned int cflag; + + /* dbg(__FUNCTION__ "."); */ + + p_priv = (struct keyspan_port_private *)(port->private); + d_details = p_priv->device_details; + cflag = port->tty->termios->c_cflag; + + /* Baud rate calculation takes baud rate as an integer + so other rates can be generated if desired. */ + baud_rate = tty_get_baud_rate(port->tty); + /* If no match or invalid, don't change */ + if (baud_rate >= 0 + && d_details->calculate_baud_rate(baud_rate, d_details->baudclk, + NULL, NULL, NULL) == KEYSPAN_BAUD_RATE_OK) { + /* FIXME - more to do here to ensure rate changes cleanly */ + p_priv->baud = baud_rate; + } + + /* set CTS/RTS handshake etc. */ + p_priv->cflag = cflag; + p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none; + + keyspan_send_setup(port); } static int keyspan_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned int value; + unsigned int value, set; + struct keyspan_port_private *p_priv; - dbg("keyspan_ioctl_info"); + p_priv = (struct keyspan_port_private *)(port->private); switch (cmd) { case TIOCMGET: - value = TIOCM_DTR | TIOCM_RNG; - if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) { + value = ((p_priv->rts_state) ? TIOCM_RTS : 0) | + ((p_priv->dtr_state) ? TIOCM_DTR : 0) | + ((p_priv->cts_state) ? TIOCM_CTS : 0) | + ((p_priv->dsr_state) ? TIOCM_DSR : 0) | + ((p_priv->dcd_state) ? TIOCM_CAR : 0) | + ((p_priv->ri_state) ? TIOCM_RNG : 0); + + if (put_user(value, (unsigned int *) arg)) return -EFAULT; - } - else { - return 0; - } - - default: - return -ENOIOCTLCMD; + return 0; + + case TIOCMSET: + if (get_user(value, (unsigned int *) arg)) + return -EFAULT; + p_priv->rts_state = ((value & TIOCM_RTS) ? 1 : 0); + p_priv->dtr_state = ((value & TIOCM_DTR) ? 1 : 0); + keyspan_send_setup(port); + return 0; + + case TIOCMBIS: + case TIOCMBIC: + if (get_user(value, (unsigned int *) arg)) + return -EFAULT; + set = (cmd == TIOCMBIS); + if (value & TIOCM_RTS) + p_priv->rts_state = set; + if (value & TIOCM_DTR) + p_priv->dtr_state = set; + keyspan_send_setup(port); + return 0; } return -ENOIOCTLCMD; } + /* Write function is generic for the three protocols used + with only a minor change for usa49 required */ static int keyspan_write(struct usb_serial_port *port, int from_user, - const unsigned char *buf, int count) + const unsigned char *buf, int count) { - struct usb_serial *serial = port->serial; - struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; - int current_urb; - int i; + const keyspan_device_details *d_details; + int flip; + int left, todo; + urb_t *this_urb; + int err; - s_priv = (struct keyspan_serial_private *)(serial->private); p_priv = (struct keyspan_port_private *)(port->private); - - if (p_priv->out_flip == 0) { - current_urb = 0; - p_priv->out_flip = 1; + d_details = p_priv->device_details; + +#if 0 + dbg(__FUNCTION__ " for port %d (%d chars [%x]), flip=%d", + port->number, count, buf[0], p_priv->out_flip); +#endif + + for (left = count; left > 0; left -= todo) { + todo = left; + if (todo > 63) + todo = 63; + + flip = p_priv->out_flip; + + /* Check we have a valid urb/endpoint before we use it... */ + if ((this_urb = p_priv->out_urbs[flip]) == 0) { + /* no bulk out, so return 0 bytes written */ + dbg(__FUNCTION__ " no output urb :("); + return count; + } + + if (this_urb->status == -EINPROGRESS) { + if (this_urb->transfer_flags & USB_ASYNC_UNLINK) + break; + if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ) + break; + this_urb->transfer_flags |= USB_ASYNC_UNLINK; + usb_unlink_urb(this_urb); + break; + } + + /* First byte in buffer is "last flag" - unused so + for now so set to zero */ + ((char *)this_urb->transfer_buffer)[0] = 0; + + if (from_user) { + copy_from_user(this_urb->transfer_buffer + 1, buf, todo); + } else { + memcpy (this_urb->transfer_buffer + 1, buf, todo); + } + buf += todo; + + /* send the data out the bulk port */ + this_urb->transfer_buffer_length = todo + 1; + + this_urb->transfer_flags &= ~USB_ASYNC_UNLINK; + this_urb->dev = port->serial->dev; + if ((err = usb_submit_urb(this_urb)) != 0) { + dbg("usb_submit_urb(write bulk) failed (%d)", err); + } + p_priv->tx_start_time[flip] = jiffies; + + /* Flip for next time if usa26 or usa28 interface + (not used on usa49) */ + p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip; } - else { - current_urb = 1; - p_priv->out_flip = 0; + + return count - left; +} + +static void usa26_indat_callback(struct urb *urb) +{ + int i, err; + int endpoint; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + + /* dbg (__FUNCTION__); */ + + endpoint = usb_pipeendpoint(urb->pipe); + + if (urb->status) { + dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.", + urb->status, endpoint); + return; + } + + port = (struct usb_serial_port *) urb->context; + tty = port->tty; + if (urb->actual_length) { + if (data[0] == 0) { + /* no error on any byte */ + for (i = 1; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + } else { + /* some bytes had errors, every byte has status */ + for (i = 0; i + 1 < urb->actual_length; i += 2) { + int stat = data[i], flag = 0; + if (stat & RXERROR_OVERRUN) + flag |= TTY_OVERRUN; + if (stat & RXERROR_FRAMING) + flag |= TTY_FRAME; + if (stat & RXERROR_PARITY) + flag |= TTY_PARITY; + /* XXX should handle break (0x10) */ + tty_insert_flip_char(tty, data[i+1], flag); + } + } + tty_flip_buffer_push(tty); + } + + /* Resubmit urb so we continue receiving */ + urb->dev = port->serial->dev; + if ((err = usb_submit_urb(urb)) != 0) { + dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err); + } + return; +} + + /* Outdat handling is common for usa26, usa28 and usa49 messages */ +static void usa2x_outdat_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + + port = (struct usb_serial_port *) urb->context; + p_priv = (struct keyspan_port_private *)(port->private); + /* dbg (__FUNCTION__ " urb %d", urb == p_priv->out_urbs[1]); */ + + if (port->active) { + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } +} + +static void usa26_inack_callback(struct urb *urb) +{ + dbg (__FUNCTION__); + +} + +static void usa26_outcont_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + + port = (struct usb_serial_port *) urb->context; + p_priv = (struct keyspan_port_private *)(port->private); + + if (p_priv->resend_cont) { + /* dbg (__FUNCTION__ " sending setup"); */ + keyspan_usa26_send_setup(port->serial, port); } +} - dbg("keyspan_write called for port %d (%d) chars {", port->number, count); - for (i = 0; i < count ; i++) { - dbg("%02x ", buf[i]); +static void usa26_instat_callback(struct urb *urb) +{ + unsigned char *data = urb->transfer_buffer; + keyspan_usa26_portStatusMessage *msg; + struct usb_serial *serial; + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + int old_dcd_state, err; + + serial = (struct usb_serial *) urb->context; + + if (urb->status) { + dbg(__FUNCTION__ " nonzero status: %x", urb->status); + return; + } + if (urb->actual_length != 9) { + dbg(__FUNCTION__ " %d byte report??", urb->actual_length); + goto exit; } - dbg("}\n"); - if (count == 0) { - dbg("write request of 0 bytes"); - return (0); + msg = (keyspan_usa26_portStatusMessage *)data; + +#if 0 + dbg(__FUNCTION__ " port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d", + msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff, + msg->_txXoff, msg->rxEnabled, msg->controlResponse); +#endif + + /* Now do something useful with the data */ + + + /* Check port number from message and retrieve private data */ + if (msg->port >= serial->num_ports) { + dbg ("Unexpected port number %d", msg->port); + goto exit; } + port = &serial->port[msg->port]; + p_priv = (struct keyspan_port_private *)(port->private); + + /* Update handshaking pin state information */ + old_dcd_state = p_priv->dcd_state; + p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); + p_priv->dsr_state = ((msg->dsr) ? 1 : 0); + p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); + p_priv->ri_state = ((msg->ri) ? 1 : 0); + + if (port->tty && !C_CLOCAL(port->tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ + } + +exit: + /* Resubmit urb so we continue receiving */ + urb->dev = serial->dev; + if ((err = usb_submit_urb(urb)) != 0) { + dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err); + } +} + +static void usa26_glocont_callback(struct urb *urb) +{ + dbg (__FUNCTION__); + +} + + +static void usa28_indat_callback(struct urb *urb) +{ + int i, err; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data; + struct keyspan_port_private *p_priv; + + /* dbg (__FUNCTION__); */ + + port = (struct usb_serial_port *) urb->context; + p_priv = (struct keyspan_port_private *)(port->private); + data = urb->transfer_buffer; + + if (urb != p_priv->in_urbs[p_priv->in_flip]) + return; - /* only send data if we have a bulk out endpoint */ - if (s_priv->out_urbs[current_urb]) { - while (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) { - dbg (__FUNCTION__ " INPROGRES\n"); - interruptible_sleep_on(&out_wait); - if (signal_pending(current)) { - dbg (__FUNCTION__ " signal\n"); - return (-ERESTARTSYS); + do { + if (urb->status) { + dbg(__FUNCTION__ "nonzero status: %x on endpoint +%d.", + urb->status, usb_pipeendpoint(urb->pipe)); + return; + } + + port = (struct usb_serial_port *) urb->context; + p_priv = (struct keyspan_port_private *)(port->private); + data = urb->transfer_buffer; + + tty = port->tty; + if (urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); } + tty_flip_buffer_push(tty); } - /*if (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) { - dbg ("already writing"); - return (-EAGAIN); - }*/ - /* First byte in buffer is "last flag" - unused so - for now so set to zero */ - memset(s_priv->out_urbs[current_urb]->transfer_buffer, 0, 1); - if (from_user) { - copy_from_user(s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count); + /* Resubmit urb so we continue receiving */ + urb->dev = port->serial->dev; + if ((err = usb_submit_urb(urb)) != 0) { + dbg(__FUNCTION__ "resubmit read urb failed. (%d)", +err); } - else { - memcpy (s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count); - } + p_priv->in_flip ^= 1; - /* send the data out the bulk port */ - s_priv->out_urbs[current_urb]->transfer_buffer_length = count + 1; + urb = p_priv->in_urbs[p_priv->in_flip]; + } while (urb->status != -EINPROGRESS); +} - if (usb_submit_urb(s_priv->out_urbs[current_urb])) { - dbg("usb_submit_urb(write bulk) failed"); - } +static void usa28_inack_callback(struct urb *urb) +{ + dbg (__FUNCTION__); +} + +static void usa28_outcont_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; - return (count); + port = (struct usb_serial_port *) urb->context; + p_priv = (struct keyspan_port_private *)(port->private); + + if (p_priv->resend_cont) { + dbg (__FUNCTION__ " sending setup"); + keyspan_usa28_send_setup(port->serial, port); } +} + +static void usa28_instat_callback(struct urb *urb) +{ + int err; + unsigned char *data = urb->transfer_buffer; + keyspan_usa28_portStatusMessage *msg; + struct usb_serial *serial; + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + int old_dcd_state; + + serial = (struct usb_serial *) urb->context; + + if (urb->status) { + dbg(__FUNCTION__ " nonzero status: %x", urb->status); + return; + } + + if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) { + dbg(__FUNCTION__ " bad length %d", urb->actual_length); + goto exit; + } + + /*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x %x", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7], data[8], data[9], data[10], data[11]);*/ - /* no bulk out, so return 0 bytes written */ - return (0); + /* Now do something useful with the data */ + msg = (keyspan_usa28_portStatusMessage *)data; + + + /* Check port number from message and retrieve private data */ + if (msg->port >= serial->num_ports) { + dbg ("Unexpected port number %d", msg->port); + goto exit; + } + port = &serial->port[msg->port]; + p_priv = (struct keyspan_port_private *)(port->private); + + /* Update handshaking pin state information */ + old_dcd_state = p_priv->dcd_state; + p_priv->cts_state = ((msg->cts) ? 1 : 0); + p_priv->dsr_state = ((msg->dsr) ? 1 : 0); + p_priv->dcd_state = ((msg->dcd) ? 1 : 0); + p_priv->ri_state = ((msg->ri) ? 1 : 0); + + if (port->tty && !C_CLOCAL(port->tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ + } + +exit: + /* Resubmit urb so we continue receiving */ + urb->dev = serial->dev; + if ((err = usb_submit_urb(urb)) != 0) { + dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err); + } } +static void usa28_glocont_callback(struct urb *urb) +{ + dbg (__FUNCTION__); +} -static void keyspan_write_bulk_callback (struct urb *urb) + +static void usa49_glocont_callback(struct urb *urb) { - int endpoint; - - endpoint = usb_pipeendpoint(urb->pipe); + struct usb_serial *serial; + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + int i; + + /* dbg (__FUNCTION__); */ + + serial = (struct usb_serial *) urb->context; + for (i = 0; i < serial->num_ports; ++i) { + port = &serial->port[i]; + p_priv = (struct keyspan_port_private *)(port->private); - dbg("keyspan_write_bulk_callback for endpoint %d\n", endpoint); + if (p_priv->resend_cont) { + /* dbg (__FUNCTION__ " sending setup"); */ + keyspan_usa49_send_setup(serial, port); + break; + } + } +} - /* Only do wakeup if this callback is from one of the data - endpoints. */ - if (endpoint == 2 || endpoint == 3) { - wake_up_interruptible(&out_wait); + /* This is actually called glostat in the Keyspan + doco */ +static void usa49_instat_callback(struct urb *urb) +{ + int err; + unsigned char *data = urb->transfer_buffer; + keyspan_usa49_portStatusMessage *msg; + struct usb_serial *serial; + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + int old_dcd_state; + + /* dbg (__FUNCTION__); */ + + serial = (struct usb_serial *) urb->context; + + if (urb->status) { + dbg(__FUNCTION__ " nonzero status: %x", urb->status); + return; + } + + if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) { + dbg(__FUNCTION__ " bad length %d", urb->actual_length); + goto exit; + } + + /*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7], data[8], data[9], data[10]);*/ + + /* Now do something useful with the data */ + msg = (keyspan_usa49_portStatusMessage *)data; + + /* Check port number from message and retrieve private data */ + if (msg->portNumber >= serial->num_ports) { + dbg ("Unexpected port number %d", msg->portNumber); + goto exit; + } + port = &serial->port[msg->portNumber]; + p_priv = (struct keyspan_port_private *)(port->private); + + /* Update handshaking pin state information */ + old_dcd_state = p_priv->dcd_state; + p_priv->cts_state = ((msg->cts) ? 1 : 0); + p_priv->dsr_state = ((msg->dsr) ? 1 : 0); + p_priv->dcd_state = ((msg->dcd) ? 1 : 0); + p_priv->ri_state = ((msg->ri) ? 1 : 0); + + if (port->tty && !C_CLOCAL(port->tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ } +exit: + /* Resubmit urb so we continue receiving */ + urb->dev = serial->dev; + + if ((err = usb_submit_urb(urb)) != 0) { + dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err); + } } +static void usa49_inack_callback(struct urb *urb) +{ + dbg (__FUNCTION__); +} -static void keyspan_read_bulk_callback (struct urb *urb) +static void usa49_indat_callback(struct urb *urb) { - int i; + int i, err; int endpoint; - struct usb_serial *serial; struct usb_serial_port *port; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; - endpoint = usb_pipeendpoint(urb->pipe); + /* dbg (__FUNCTION__); */ + endpoint = usb_pipeendpoint(urb->pipe); if (urb->status) { - dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n", + dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.", urb->status, endpoint); return; } - switch (endpoint) { - - /* If this is one of the data endpoints, stuff it's - contents into the tty flip_buffer. */ - case 1: - case 2: serial = (struct usb_serial *) urb->context; - port = &serial->port[0]; - tty = port->tty; - if (urb->actual_length) { - for (i = 0; i < urb->actual_length ; ++i) { - tty_insert_flip_char(tty, data[i], 0); - } - tty_flip_buffer_push(tty); + port = (struct usb_serial_port *) urb->context; + tty = port->tty; + if (urb->actual_length) { + if (data[0] == 0) { + /* no error on any byte */ + for (i = 1; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); } - break; - - /* INACK endpoint */ - case 3: dbg(__FUNCTION__ " callback for INACK endpoint\n"); - break; - - /* INSTAT endpoint */ - case 4: dbg(__FUNCTION__ " callback for INSTAT endpoint\n"); - break; - - default: - dbg(__FUNCTION__ " callback for unknown endpoint!\n"); - break; + } else { + /* some bytes had errors, every byte has status */ + for (i = 0; i + 1 < urb->actual_length; i += 2) { + int stat = data[i], flag = 0; + if (stat & RXERROR_OVERRUN) + flag |= TTY_OVERRUN; + if (stat & RXERROR_FRAMING) + flag |= TTY_FRAME; + if (stat & RXERROR_PARITY) + flag |= TTY_PARITY; + /* XXX should handle break (0x10) */ + tty_insert_flip_char(tty, data[i+1], flag); + } + } + tty_flip_buffer_push(tty); } /* Resubmit urb so we continue receiving */ - if (usb_submit_urb(urb)) { - dbg(__FUNCTION__ "resubmit read urb failed.\n"); + urb->dev = port->serial->dev; + if ((err = usb_submit_urb(urb)) != 0) { + dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err); } - return; - } +/* not used, usa-49 doesn't have per-port control endpoints */ +static void usa49_outcont_callback(struct urb *urb) +{ + dbg (__FUNCTION__); +} + + + static int keyspan_write_room (struct usb_serial_port *port) { -// dbg("keyspan_write_room called\n"); +// dbg("keyspan_write_room called"); return (32); } @@ -306,62 +812,92 @@ struct keyspan_port_private *p_priv; struct keyspan_serial_private *s_priv; struct usb_serial *serial = port->serial; - int i; + const keyspan_device_details *d_details; + int i, already_active, err; + unsigned long flags; + urb_t *urb; s_priv = (struct keyspan_serial_private *)(serial->private); p_priv = (struct keyspan_port_private *)(port->private); + d_details = s_priv->device_details; - dbg("keyspan_open called.\n"); - - if (port->active) { - dbg(__FUNCTION__ "port->active already true!\n"); - return (-EINVAL); - } + /* dbg("keyspan_open called."); */ + MOD_INC_USE_COUNT; - p_priv = (struct keyspan_port_private *)(port->private); - - p_priv->out_flip = 0; + spin_lock_irqsave (&port->port_lock, flags); + ++port->open_count; + already_active = port->active; port->active = 1; + spin_unlock_irqrestore (&port->port_lock, flags); - /* Start reading from port */ - for (i = 0; i < 4; i++) { - if (s_priv->in_urbs[i]) { - if (usb_submit_urb(s_priv->in_urbs[i])) { - dbg(__FUNCTION__ " submit in urb %d failed", i); - } - } + if (already_active) + return 0; + + p_priv = (struct keyspan_port_private *)(port->private); + /* Set some sane defaults */ + p_priv->rts_state = 1; + p_priv->dtr_state = 1; + + /* Start reading from endpoints */ + for (i = 0; i < 2; i++) { + if ((urb = p_priv->in_urbs[i]) == NULL) + continue; + urb->dev = serial->dev; + if ((err = usb_submit_urb(urb)) != 0) { + dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err); + } } - - keyspan_usa19_send_setup(serial, port); + + keyspan_set_termios(port, NULL); return (0); } +static inline void stop_urb(urb_t *urb) +{ + if (urb && urb->status == -EINPROGRESS) { + urb->transfer_flags &= ~USB_ASYNC_UNLINK; + usb_unlink_urb(urb); + } +} static void keyspan_close(struct usb_serial_port *port, struct file *filp) { int i; struct usb_serial *serial = port->serial; /* FIXME should so sanity check */ struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; + unsigned long flags; + /* dbg("keyspan_close called"); */ s_priv = (struct keyspan_serial_private *)(serial->private); - - /* Stop reading/writing urbs */ - for (i = 0; i < 4; i++) { - if (s_priv->in_urbs[i]) { - usb_unlink_urb(s_priv->in_urbs[i]); - } + p_priv = (struct keyspan_port_private *)(port->private); - } - for (i = 0; i < 3; i++) { - if (s_priv->out_urbs[i]) { - usb_unlink_urb(s_priv->out_urbs[i]); - } + spin_lock_irqsave (&port->port_lock, flags); + if (--port->open_count <= 0) { + if (port->active) { + /* Stop reading/writing urbs */ + stop_urb(p_priv->inack_urb); + stop_urb(p_priv->outcont_urb); + for (i = 0; i < 2; i++) { + stop_urb(p_priv->in_urbs[i]); + stop_urb(p_priv->out_urbs[i]); + } + /* Now done in shutdown + if (atomic_dec_return(&s_priv->active_count) <= 0) { + stop_urb(s_priv->instat_urb); + stop_urb(s_priv->glocont_urb); + } */ + } + port->active = 0; + port->open_count = 0; + port->tty = 0; } - port->active = 0; - dbg("keyspan_close called\n"); + spin_unlock_irqrestore (&port->port_lock, flags); + + MOD_DEC_USE_COUNT; } @@ -372,47 +908,59 @@ const struct ezusb_hex_record *record; char *fw_name; - dbg("Keyspan startup version %04x product %04x\n", serial->dev->descriptor.bcdDevice, - serial->dev->descriptor.idProduct); + dbg("Keyspan startup version %04x product %04x", + serial->dev->descriptor.bcdDevice, + serial->dev->descriptor.idProduct); if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) { - dbg("Firmware already loaded. Quitting.\n"); + dbg("Firmware already loaded. Quitting."); return(1); } /* Select firmware image on the basis of idProduct */ switch (serial->dev->descriptor.idProduct) { - case 0x0101: record = &keyspan_usa28_firmware[0]; - fw_name = "USA28"; - break; - - case 0x0102: record = &keyspan_usa28x_firmware[0]; - fw_name = "USA28X"; - break; - - case 0x0103: record = &keyspan_usa19_firmware[0]; - fw_name = "USA19"; - break; + case 0x0101: + record = &keyspan_usa28_firmware[0]; + fw_name = "USA28"; + break; + + case 0x0102: + record = &keyspan_usa28x_firmware[0]; + fw_name = "USA28X"; + break; + + case 0x0103: + record = &keyspan_usa19_firmware[0]; + fw_name = "USA19"; + break; - case 0x0105: record = &keyspan_usa18x_firmware[0]; - fw_name = "USA18X"; - break; + case 0x0105: + record = &keyspan_usa18x_firmware[0]; + fw_name = "USA18X"; + break; - case 0x0106: record = &keyspan_usa19w_firmware[0]; - fw_name = "USA19W"; - break; + case 0x0106: + record = &keyspan_usa19w_firmware[0]; + fw_name = "USA19W"; + break; - default: record = NULL; - fw_name = "Unknown"; - break; + case 0x0109: + record = &keyspan_usa49w_firmware[0]; + fw_name = "USA49W"; + break; + + default: + record = NULL; + fw_name = "Unknown"; + break; } if (record == NULL) { - err("Required keyspan firmware image (%s) unavailable.\n", fw_name); + err("Required keyspan firmware image (%s) unavailable.", fw_name); return(1); } - dbg("Uploading Keyspan %s firmware.\n", fw_name); + dbg("Uploading Keyspan %s firmware.", fw_name); /* download the firmware image */ response = ezusb_set_reset(serial, 1); @@ -434,72 +982,165 @@ moment and the new device will bind to the real driver */ response = ezusb_set_reset(serial, 0); - /* we don't want this device to have a driver assigned to it. */ + /* we don't want this device to have a driver assigned to it. */ return (1); } - /* USA-19 uses three output endpoints and four input - endpoints. First two output endpoints are for - data (used in an alternating fashion), the third is - output control. First two input endpoints are for - data (again alternating), the third is the ACK - endpoint, the fourth is input status. */ -static void keyspan_usa19_setup_urbs(struct usb_serial *serial) +/* Helper functions used by keyspan_setup_urbs */ +static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint, + int dir, void *ctx, char *buf, int len, + void (*callback)(urb_t *)) +{ + urb_t *urb; + + if (endpoint == -1) + return NULL; /* endpoint not needed */ + + /* dbg (__FUNCTION__ " alloc for endpoint %d.", endpoint); */ + urb = usb_alloc_urb(0); /* No ISO */ + if (urb == NULL) { + dbg (__FUNCTION__ " alloc for endpoint %d failed.", endpoint); + return NULL; + } + + /* Fill URB using supplied data. */ + FILL_BULK_URB(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + + return urb; +} + +struct callbacks { + void (*instat_callback)(urb_t *); + void (*glocont_callback)(urb_t *); + void (*indat_callback)(urb_t *); + void (*outdat_callback)(urb_t *); + void (*inack_callback)(urb_t *); + void (*outcont_callback)(urb_t *); +} keyspan_callbacks[] = { + { + /* msg_usa26 callbacks */ + instat_callback: usa26_instat_callback, + glocont_callback: usa26_glocont_callback, + indat_callback: usa26_indat_callback, + outdat_callback: usa2x_outdat_callback, + inack_callback: usa26_inack_callback, + outcont_callback: usa26_outcont_callback, + }, { + /* msg_usa28 callbacks */ + instat_callback: usa28_instat_callback, + glocont_callback: usa28_glocont_callback, + indat_callback: usa28_indat_callback, + outdat_callback: usa2x_outdat_callback, + inack_callback: usa28_inack_callback, + outcont_callback: usa28_outcont_callback, + }, { + /* msg_usa49 callbacks */ + instat_callback: usa49_instat_callback, + glocont_callback: usa49_glocont_callback, + indat_callback: usa49_indat_callback, + outdat_callback: usa2x_outdat_callback, + inack_callback: usa49_inack_callback, + outcont_callback: usa49_outcont_callback, + } +}; + + /* Generic setup urbs function that uses + data in device_details */ +static void keyspan_setup_urbs(struct usb_serial *serial) { + int i, j; struct keyspan_serial_private *s_priv; - int i; + const keyspan_device_details *d_details; + struct usb_serial_port *port; + struct keyspan_port_private *p_priv; + struct callbacks *cback; + int endp; + + /* dbg (__FUNCTION__); */ s_priv = (struct keyspan_serial_private *)(serial->private); + d_details = s_priv->device_details; - /* Output urbs first */ - dbg(__FUNCTION__ "Allocating output urbs.\n"); - for (i = 0; i < 3; i++) { - - s_priv->out_urbs[i] = usb_alloc_urb (0); /* No ISO */ - if (!s_priv->out_urbs[i]) { - dbg (__FUNCTION__ "Alloc for %d out urb failed.\n", i); - return; - } + /* Setup values for the various callback routines */ + cback = &keyspan_callbacks[d_details->msg_format]; - FILL_BULK_URB(s_priv->out_urbs[i], serial->dev, - usb_sndbulkpipe(serial->dev, i + 1), - &s_priv->out_buffer[i], sizeof(s_priv->out_buffer[i]), - keyspan_write_bulk_callback, - serial); - } + /* Allocate and set up urbs for each one that is in use, + starting with instat endpoints */ + s_priv->instat_urb = keyspan_setup_urb + (serial, d_details->instat_endpoint, USB_DIR_IN, + serial, s_priv->instat_buf, INSTAT_BUFLEN, + cback->instat_callback); + + s_priv->glocont_urb = keyspan_setup_urb + (serial, d_details->glocont_endpoint, USB_DIR_OUT, + serial, s_priv->glocont_buf, GLOCONT_BUFLEN, + cback->glocont_callback); - /* Now input urbs */ - dbg(__FUNCTION__ "Allocating input urbs.\n"); - for (i = 0; i < 4; i++) { - - s_priv->in_urbs[i] = usb_alloc_urb (0); /* No ISO */ - if (!s_priv->in_urbs[i]) { - dbg (__FUNCTION__ "Alloc for %d in urb failed.\n", i); - return; + /* Setup endpoints for each port specific thing */ + for (i = 0; i < d_details->num_ports; i ++) { + port = &serial->port[i]; + p_priv = (struct keyspan_port_private *)(port->private); + + /* Do indat endpoints first, once for each flip */ + endp = d_details->indat_endpoints[i]; + for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) { + p_priv->in_urbs[j] = keyspan_setup_urb + (serial, endp, USB_DIR_IN, port, + p_priv->in_buffer[j], 64, + cback->indat_callback); } + for (; j < 2; ++j) + p_priv->in_urbs[j] = NULL; + + /* outdat endpoints also have flip */ + endp = d_details->outdat_endpoints[i]; + for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) { + p_priv->out_urbs[j] = keyspan_setup_urb + (serial, endp, USB_DIR_OUT, port, + p_priv->out_buffer[j], 64, + cback->outdat_callback); + } + for (; j < 2; ++j) + p_priv->out_urbs[j] = NULL; + + /* inack endpoint */ + p_priv->inack_urb = keyspan_setup_urb + (serial, d_details->inack_endpoints[i], USB_DIR_IN, + port, p_priv->inack_buffer, 1, cback->inack_callback); + + /* outcont endpoint */ + p_priv->outcont_urb = keyspan_setup_urb + (serial, d_details->outcont_endpoints[i], USB_DIR_OUT, + port, p_priv->outcont_buffer, 64, + cback->outcont_callback); + } - FILL_BULK_URB(s_priv->in_urbs[i], serial->dev, - usb_rcvbulkpipe(serial->dev, i + 0x81), - &s_priv->in_buffer[i], sizeof(s_priv->in_buffer[i]), - keyspan_read_bulk_callback, - serial); - } - } -static int keyspan_usa19_calc_baud(u32 baud_rate, u8 *rate_hi, u8 *rate_low) +/* usa19 function doesn't require prescaler */ +static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler) { - u32 b16, /* baud rate times 16 (actual rate used internally) */ + u32 b16, /* baud rate times 16 (actual rate used internally) */ div, /* divisor */ cnt; /* inverse of divisor (programmed into 8051) */ + /* prevent divide by zero... */ if( (b16 = (baud_rate * 16L)) == 0) { return (KEYSPAN_INVALID_BAUD_RATE); } + /* Any "standard" rate over 57k6 is marginal on the USA-19 + as we run out of divisor resolution. */ + if (baud_rate > 57600) { + return (KEYSPAN_INVALID_BAUD_RATE); + } + /* calculate the divisor and the counter (its inverse) */ - if( (div = (USA19_BAUDCLK / b16)) == 0) { + if( (div = (baudclk / b16)) == 0) { return (KEYSPAN_INVALID_BAUD_RATE); } else { @@ -510,216 +1151,520 @@ return (KEYSPAN_INVALID_BAUD_RATE); } - /* return the counter values */ - *rate_low = (u8) (cnt & 0xff); - *rate_hi = (u8) ((cnt >> 8) & 0xff); + /* return the counter values if non-null */ + if (rate_low) { + *rate_low = (u8) (cnt & 0xff); + } + if (rate_hi) { + *rate_hi = (u8) ((cnt >> 8) & 0xff); + } + if (rate_low && rate_hi) { + dbg (__FUNCTION__ " %d %02x %02x.", baud_rate, *rate_hi, *rate_low); + } - dbg(__FUNCTION__ " Baud rate of %d is %02x %02x.\n", baud_rate, *rate_hi, *rate_low); + return (KEYSPAN_BAUD_RATE_OK); +} + +static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler) +{ + u32 b16, /* baud rate times 16 (actual rate used internally) */ + clk, /* clock with 13/8 prescaler */ + div, /* divisor using 13/8 prescaler */ + res, /* resulting baud rate using 13/8 prescaler */ + diff, /* error using 13/8 prescaler */ + smallest_diff; + u8 best_prescaler; + int i; + + /* dbg (__FUNCTION__ " %d.", baud_rate); */ + + /* prevent divide by zero */ + if( (b16 = baud_rate * 16L) == 0) { + return (KEYSPAN_INVALID_BAUD_RATE); + } + /* Calculate prescaler by trying them all and looking + for best fit */ + + /* start with largest possible difference */ + smallest_diff = 0xffffffff; + + /* 0 is an invalid prescaler, used as a flag */ + best_prescaler = 0; + + for(i = 8; i <= 0xff; ++i) + { + clk = (baudclk * 8) / (u32) i; + + if( (div = clk / b16) == 0) { + continue; + } + + res = clk / div; + diff= (res > b16) ? (res-b16) : (b16-res); + + if(diff < smallest_diff) + { + best_prescaler = i; + smallest_diff = diff; + } + } + + if(best_prescaler == 0) { + return (KEYSPAN_INVALID_BAUD_RATE); + } + + clk = (baudclk * 8) / (u32) best_prescaler; + div = clk / b16; + + /* return the divisor and prescaler if non-null */ + if (rate_low) { + *rate_low = (u8) (div & 0xff); + } + if (rate_hi) { + *rate_hi = (u8) ((div >> 8) & 0xff); + } + if (prescaler) { + *prescaler = best_prescaler; + /* dbg(__FUNCTION__ " %d %d", *prescaler, div); */ + } return (KEYSPAN_BAUD_RATE_OK); } -static int keyspan_usa19_send_setup(struct usb_serial *serial, struct usb_serial_port *port) +static int keyspan_usa26_send_setup(struct usb_serial *serial, + struct usb_serial_port *port) { - struct portControlMessage msg; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; + struct keyspan_usa26_portControlMessage msg; + struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; + const keyspan_device_details *d_details; + int outcont_urb; + urb_t *this_urb; + int err; + + /* dbg (__FUNCTION__); */ s_priv = (struct keyspan_serial_private *)(serial->private); p_priv = (struct keyspan_port_private *)(port->private); + d_details = s_priv->device_details; + + outcont_urb = d_details->outcont_endpoints[port->number]; + this_urb = p_priv->outcont_urb; + + /* Make sure we have an urb then send the message */ + if (this_urb == NULL) { + dbg(__FUNCTION__ " oops no urb."); + return -1; + } + + p_priv->resend_cont = 1; + if (this_urb->status == -EINPROGRESS) { + /* dbg (__FUNCTION__ " already writing"); */ + return(-1); + } + + memset(&msg, 0, sizeof (struct keyspan_usa26_portControlMessage)); + + /* Only set baud rate if it's changed */ + if (p_priv->old_baud != p_priv->baud) { + p_priv->old_baud = p_priv->baud; + msg.setClocking = 0xff; + if (d_details->calculate_baud_rate + (p_priv->baud, d_details->baudclk, &msg.baudHi, + &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) { + dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.", + p_priv->baud); + msg.baudLo = 0; + msg.baudHi = 125; /* Values for 9600 baud */ + msg.prescaler = 10; + } + msg.setPrescaler = 0xff; + } + + msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1; + if (p_priv->cflag & PARENB) { + /* note USA_PARITY_NONE == 0 */ + msg.lcr |= (p_priv->cflag & PARODD)? + USA_PARITY_ODD: USA_PARITY_EVEN; + } + msg.setLcr = 0xff; - //memset(msg, 0, sizeof (struct portControlMessage)); + msg.ctsFlowControl = (p_priv->flow_control == flow_cts); + msg.xonFlowControl = 0; + msg.setFlowControl = 0xff; + + msg.forwardingLength = 1; + msg.xonChar = 17; + msg.xoffChar = 19; + + msg._txOn = 1; + msg._txOff = 0; + msg.txFlush = 0; + msg.txBreak = 0; + msg.rxOn = 1; + msg.rxOff = 0; + msg.rxFlush = 0; + msg.rxForward = 0; + /*msg.returnStatus = 1; + msg.resetDataToggle = 0xff;*/ + + /* Do handshaking outputs */ + msg.setTxTriState_setRts = 0xff; + msg.txTriState_rts = p_priv->rts_state; + + msg.setHskoa_setDtr = 0xff; + msg.hskoa_dtr = p_priv->dtr_state; + p_priv->resend_cont = 0; + memcpy (this_urb->transfer_buffer, &msg, sizeof(msg)); + + /* send the data out the device on control endpoint */ + this_urb->transfer_buffer_length = sizeof(msg); + + this_urb->dev = serial->dev; + if ((err = usb_submit_urb(this_urb)) != 0) { + dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err); + } +#if 0 + else { + dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)", + outcont_urb, this_urb->transfer_buffer_length, + usb_pipeendpoint(this_urb->pipe)); + } +#endif + + return (0); +} + +static int keyspan_usa28_send_setup(struct usb_serial *serial, + struct usb_serial_port *port) +{ + struct keyspan_usa28_portControlMessage msg; + struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; + const keyspan_device_details *d_details; + urb_t *this_urb; + int err; + + s_priv = (struct keyspan_serial_private *)(serial->private); + p_priv = (struct keyspan_port_private *)(port->private); + d_details = s_priv->device_details; + + /* only do something if we have a bulk out endpoint */ + if ((this_urb = p_priv->outcont_urb) == NULL) { + dbg(__FUNCTION__ " oops no urb."); + return -1; + } + + p_priv->resend_cont = 1; + if (this_urb->status == -EINPROGRESS) { + dbg (__FUNCTION__ " already writing"); + return(-1); + } + + memset(&msg, 0, sizeof (struct keyspan_usa28_portControlMessage)); + msg.setBaudRate = 1; - if (keyspan_usa19_calc_baud(9600, &msg.baudHi, &msg.baudLo) == - KEYSPAN_INVALID_BAUD_RATE ) { - dbg(__FUNCTION__ "Invalid baud rate requested %d.\n", 9600); + if (keyspan_usa19_calc_baud(p_priv->baud, d_details->baudclk, + &msg.baudHi, &msg.baudLo, NULL) == KEYSPAN_INVALID_BAUD_RATE ) { + dbg(__FUNCTION__ "Invalid baud rate requested %d.", 9600); msg.baudLo = 0xff; msg.baudHi = 0xb2; /* Values for 9600 baud */ } - /* If parity is enabled, we must calculate it ourselves. */ - if (p_priv->parity) { - msg.parity = 1; + /* If parity is enabled, we must calculate it ourselves. */ + msg.parity = 0; /* XXX for now */ + + msg.ctsFlowControl = (p_priv->flow_control == flow_cts); + msg.xonFlowControl = 0; + + /* Do handshaking outputs, DTR is inverted relative to RTS */ + msg.rts = p_priv->rts_state; + msg.dtr = p_priv->dtr_state; + + msg.forwardingLength = 1; + msg.forwardMs = 10; + msg.breakThreshold = 45; + msg.xonChar = 17; + msg.xoffChar = 19; + + msg._txOn = 1; + msg._txOff = 0; + msg.txFlush = 0; + msg.txForceXoff = 0; + msg.txBreak = 0; + msg.rxOn = 1; + msg.rxOff = 0; + msg.rxFlush = 0; + msg.rxForward = 0; + /*msg.returnStatus = 1; + msg.resetDataToggle = 0xff;*/ + + p_priv->resend_cont = 0; + memcpy (this_urb->transfer_buffer, &msg, sizeof(msg)); + + /* send the data out the device on control endpoint */ + this_urb->transfer_buffer_length = sizeof(msg); + + this_urb->dev = serial->dev; + if ((err = usb_submit_urb(this_urb)) != 0) { + dbg(__FUNCTION__ " usb_submit_urb(setup) failed"); } +#if 0 else { - msg.parity = 0; + dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes", + this_urb->transfer_buffer_length); + } +#endif + + return (0); +} + +static int keyspan_usa49_send_setup(struct usb_serial *serial, + struct usb_serial_port *port) +{ + struct keyspan_usa49_portControlMessage msg; + struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; + const keyspan_device_details *d_details; + int glocont_urb; + urb_t *this_urb; + int err; + + /* dbg (__FUNCTION__); */ + + s_priv = (struct keyspan_serial_private *)(serial->private); + p_priv = (struct keyspan_port_private *)(port->private); + d_details = s_priv->device_details; + + glocont_urb = d_details->glocont_endpoint; + this_urb = s_priv->glocont_urb; + + /* dbg(__FUNCTION__ " port %d\n", port->number); */ + + /* Make sure we have an urb then send the message */ + if (this_urb == NULL) { + dbg(__FUNCTION__ " oops no urb for port %d.", port->number); + return -1; + } + + p_priv->resend_cont = 1; + if (this_urb->status == -EINPROGRESS) { + /* dbg (__FUNCTION__ " already writing"); */ + return(-1); + } + + memset(&msg, 0, sizeof (struct keyspan_usa49_portControlMessage)); + + msg.portNumber = port->number; + + /* Only set baud rate if it's changed */ + if (p_priv->old_baud != p_priv->baud) { + p_priv->old_baud = p_priv->baud; + msg.setClocking = 0xff; + if (d_details->calculate_baud_rate + (p_priv->baud, d_details->baudclk, &msg.baudHi, + &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) { + dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.", + p_priv->baud); + msg.baudLo = 0; + msg.baudHi = 125; /* Values for 9600 baud */ + msg.prescaler = 10; + } + //msg.setPrescaler = 0xff; } - msg.ctsFlowControl = 0; + msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1; + if (p_priv->cflag & PARENB) { + /* note USA_PARITY_NONE == 0 */ + msg.lcr |= (p_priv->cflag & PARODD)? + USA_PARITY_ODD: USA_PARITY_EVEN; + } + msg.setLcr = 0xff; + + msg.ctsFlowControl = (p_priv->flow_control == flow_cts); msg.xonFlowControl = 0; - msg.rts = 1; - msg.dtr = 0; + msg.setFlowControl = 0xff; msg.forwardingLength = 1; - msg.forwardMs = 10; - msg.breakThreshold = 45; msg.xonChar = 17; msg.xoffChar = 19; msg._txOn = 1; msg._txOff = 0; msg.txFlush = 0; - msg.txForceXoff = 0; msg.txBreak = 0; msg.rxOn = 1; msg.rxOff = 0; msg.rxFlush = 0; msg.rxForward = 0; - msg.returnStatus = 1; - msg.resetDataToggle = 1; + msg.enablePort = 0xff; + msg.disablePort = 0; + + /* Do handshaking outputs */ + msg.setRts = 0xff; + msg.rts = p_priv->rts_state; + msg.setDtr = 0xff; + msg.dtr = p_priv->dtr_state; - /* only do something if we have a bulk out endpoint */ - if (s_priv->out_urbs[2]) { - if (s_priv->out_urbs[2]->status == -EINPROGRESS) { - dbg (__FUNCTION__ " already writing"); - return(-1); - } - memcpy (s_priv->out_urbs[2]->transfer_buffer, &msg, sizeof(msg)); + p_priv->resend_cont = 0; + memcpy (this_urb->transfer_buffer, &msg, sizeof(msg)); - /* send the data out the device on control endpoint */ - s_priv->out_urbs[2]->transfer_buffer_length = sizeof(msg); + /* send the data out the device on control endpoint */ + this_urb->transfer_buffer_length = sizeof(msg); - if (usb_submit_urb(s_priv->out_urbs[2])) { - dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n"); - } - else { - dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes\n", s_priv->out_urbs[2]->transfer_buffer_length); - } - + this_urb->dev = serial->dev; + if ((err = usb_submit_urb(this_urb)) != 0) { + dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err); } +#if 0 + else { + dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)", + outcont_urb, this_urb->transfer_buffer_length, + usb_pipeendpoint(this_urb->pipe)); + } +#endif + return (0); } +static void keyspan_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct keyspan_serial_private *s_priv; + const keyspan_device_details *d_details; + + s_priv = (struct keyspan_serial_private *)(serial->private); + d_details = s_priv->device_details; - /* Gets called by the "real" driver (ie once firmware is loaded - and renumeration has taken place. */ + switch (d_details->msg_format) { + case msg_usa26: + keyspan_usa26_send_setup(serial, port); + break; + case msg_usa28: + keyspan_usa28_send_setup(serial, port); + break; + case msg_usa49: + keyspan_usa49_send_setup(serial, port); + break; + } +} + +/* Gets called by the "real" driver (ie once firmware is loaded + and renumeration has taken place. */ static int keyspan_startup (struct usb_serial *serial) { - int i; - struct usb_serial_port *port; + int i, err; + struct usb_serial_port *port; + struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; + const keyspan_device_details *d_details; + + /* dbg("keyspan_startup called."); */ - dbg("keyspan_startup called.\n"); + for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i) + if (d_details->product_id == serial->dev->descriptor.idProduct) + break; + if (d_details == NULL) { + printk(KERN_ERR __FUNCTION__ ": unknown product id %x\n", + serial->dev->descriptor.idProduct); + return 1; + } - /* Setup private data for serial driver */ - serial->private = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); + /* Setup private data for serial driver */ + serial->private = kmalloc(sizeof(struct keyspan_serial_private), + GFP_KERNEL); if (!serial->private) { - dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed!.\n"); + dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed."); return (1); } memset(serial->private, 0, sizeof(struct keyspan_serial_private)); + + s_priv = (struct keyspan_serial_private *)(serial->private); + s_priv->device_details = d_details; - init_waitqueue_head(&out_wait); - - /* Now setup per port private data */ + /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = &serial->port[i]; - port->private = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL); + port->private = kmalloc(sizeof(struct keyspan_port_private), + GFP_KERNEL); if (!port->private) { - dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.\n", i); + dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.", i); return (1); } memset(port->private, 0, sizeof(struct keyspan_port_private)); + p_priv = (struct keyspan_port_private *)(port->private); + p_priv->device_details = d_details; } - + keyspan_setup_urbs(serial); - switch (serial->dev->descriptor.idProduct) { - case 0x0107: keyspan_usa19_setup_urbs(serial); - //keyspan_send_usa19_setup(serial); - break; - - default: break; + s_priv->instat_urb->dev = serial->dev; + if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) { + dbg(__FUNCTION__ " submit instat urb failed %d", err); } - return (0); } static void keyspan_shutdown (struct usb_serial *serial) { - int i; + int i, j; struct usb_serial_port *port; struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; - dbg("keyspan_shutdown called freeing "); + /* dbg("keyspan_shutdown called"); */ s_priv = (struct keyspan_serial_private *)(serial->private); - /* Stop reading/writing urbs */ - for (i = 0; i < 4; i++) { - if (s_priv->in_urbs[i]) { - usb_unlink_urb(s_priv->in_urbs[i]); + /* Stop reading/writing urbs */ + stop_urb(s_priv->instat_urb); + stop_urb(s_priv->glocont_urb); + for (i = 0; i < serial->num_ports; ++i) { + port = &serial->port[i]; + p_priv = (struct keyspan_port_private *)(port->private); + stop_urb(p_priv->inack_urb); + stop_urb(p_priv->outcont_urb); + for (j = 0; j < 2; j++) { + stop_urb(p_priv->in_urbs[j]); + stop_urb(p_priv->out_urbs[j]); } - } - for (i = 0; i < 3; i++) { - if (s_priv->out_urbs[i]) { - usb_unlink_urb(s_priv->out_urbs[i]); - } - } - /* Now free them */ - for (i = 0; i < 7; i ++) { - if (s_priv->in_urbs[i] != NULL) { - dbg("in%d ", i); - usb_free_urb(s_priv->in_urbs[i]); - } - - if (s_priv->out_urbs[i] != NULL) { - dbg("out%d ", i); - usb_free_urb(s_priv->out_urbs[i]); + /* Now free them */ + if (s_priv->instat_urb) + usb_free_urb(s_priv->instat_urb); + if (s_priv->glocont_urb) + usb_free_urb(s_priv->glocont_urb); + for (i = 0; i < serial->num_ports; ++i) { + port = &serial->port[i]; + p_priv = (struct keyspan_port_private *)(port->private); + if (p_priv->inack_urb) + usb_free_urb(p_priv->inack_urb); + if (p_priv->outcont_urb) + usb_free_urb(p_priv->outcont_urb); + for (j = 0; j < 2; j++) { + if (p_priv->in_urbs[j]) + usb_free_urb(p_priv->in_urbs[j]); + if (p_priv->out_urbs[j]) + usb_free_urb(p_priv->out_urbs[j]); } } - dbg("urbs.\n"); - dbg("Freeing serial->private.\n"); + /* dbg("Freeing serial->private."); */ kfree(serial->private); - dbg("Freeing port->private.\n"); - /* Now free per port private data */ + /* dbg("Freeing port->private."); */ + /* Now free per port private data */ for (i = 0; i < serial->num_ports; i++) { port = &serial->port[i]; + while (port->open_count > 0) { + --port->open_count; + MOD_DEC_USE_COUNT; + } kfree(port->private); } - } - - -static int __init keyspan_init (void) -{ - usb_serial_register (&keyspan_usa18x_pre_device); - usb_serial_register (&keyspan_usa19_pre_device); - usb_serial_register (&keyspan_usa19w_pre_device); - usb_serial_register (&keyspan_usa28_pre_device); - usb_serial_register (&keyspan_usa28x_pre_device); - usb_serial_register (&keyspan_usa18x_device); - usb_serial_register (&keyspan_usa19_device); - usb_serial_register (&keyspan_usa19w_device); - usb_serial_register (&keyspan_usa28_device); - usb_serial_register (&keyspan_usa28x_device); - return 0; -} - - -static void __exit keyspan_exit (void) -{ - usb_serial_deregister (&keyspan_usa18x_pre_device); - usb_serial_deregister (&keyspan_usa19_pre_device); - usb_serial_deregister (&keyspan_usa19w_pre_device); - usb_serial_deregister (&keyspan_usa28_pre_device); - usb_serial_deregister (&keyspan_usa28x_pre_device); - usb_serial_deregister (&keyspan_usa18x_device); - usb_serial_deregister (&keyspan_usa19_device); - usb_serial_deregister (&keyspan_usa19w_device); - usb_serial_deregister (&keyspan_usa28_device); - usb_serial_deregister (&keyspan_usa28x_device); -} - - -module_init(keyspan_init); -module_exit(keyspan_exit); - -MODULE_AUTHOR("Hugh Blemings "); -MODULE_DESCRIPTION("Keyspan USB to Serial Converter driver"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/keyspan.h linux/drivers/usb/serial/keyspan.h --- v2.2.18/drivers/usb/serial/keyspan.h Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/keyspan.h Sun Mar 25 11:37:37 2001 @@ -19,6 +19,11 @@ and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. Thanks Guys :) + Thanks to Paulus for miscellaneous tidy ups, some largish chunks + of much nicer and/or completely new code and (perhaps most uniquely) + having the patience to sit down and explain why and where he'd changed + stuff. + Tip 'o the hat to Linuxcare for supporting staff in their work on open source projects. @@ -41,12 +46,18 @@ static void keyspan_rx_throttle (struct usb_serial_port *port); static void keyspan_rx_unthrottle (struct usb_serial_port *port); static int keyspan_write_room (struct usb_serial_port *port); + static int keyspan_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); + +#if 0 static void keyspan_write_bulk_callback (struct urb *urb); -static void keyspan_read_bulk_callback (struct urb *urb); +#endif + +//static void keyspan_usa26_read_int_callback (struct urb *urb); +//static void keyspan_usa28_read_int_callback (struct urb *urb); static int keyspan_chars_in_buffer (struct usb_serial_port *port); static int keyspan_ioctl (struct usb_serial_port *port, struct file *file, @@ -58,12 +69,20 @@ int break_state); static int keyspan_fake_startup (struct usb_serial *serial); -static int keyspan_usa19_calc_baud (u32 baud_rate, u8 *rate_hi, - u8 *rate_low); -static void keyspan_usa19_setup_urbs (struct usb_serial *serial); -static int keyspan_usa19_send_setup (struct usb_serial *serial, - struct usb_serial_port *port); +static int keyspan_usa19_calc_baud (u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler); + +static int keyspan_usa19w_calc_baud (u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler); + +//static void keyspan_usa19_setup_urbs (struct usb_serial *serial); +static int keyspan_usa28_send_setup (struct usb_serial *serial, + struct usb_serial_port *port); +static int keyspan_usa26_send_setup (struct usb_serial *serial, + struct usb_serial_port *port); +static int keyspan_usa49_send_setup (struct usb_serial *serial, + struct usb_serial_port *port); /* Functions from usbserial.c for ezusb firmware handling */ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); @@ -109,34 +128,186 @@ static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL; #endif - +#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA49W + #include "keyspan_usa49w_fw.h" +#else + static const struct ezusb_hex_record *keyspan_usa49w_firmware = NULL; +#endif + /* Values used for baud rate calculation - device specific */ #define KEYSPAN_INVALID_BAUD_RATE (-1) #define KEYSPAN_BAUD_RATE_OK (0) -#define USA19_BAUDCLK (12000000L) +#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */ +#define KEYSPAN_USA19_BAUDCLK (12000000L) +#define KEYSPAN_USA19W_BAUDCLK (24000000L) +#define KEYSPAN_USA28X_BAUDCLK (12000000L) +#define KEYSPAN_USA49W_BAUDCLK (48000000L) + + /* Some constants used to characterise each device. + There is a four port device due later in the year, + we allow for it now in the following */ +#define KEYSPAN_MAX_NUM_PORTS (4) +#define KEYSPAN_MAX_FLIPS (2) + +typedef struct { + /* product ID value */ + int product_id; + + enum {msg_usa26, msg_usa28, msg_usa49} msg_format; + + /* Number of physical ports */ + int num_ports; + + /* 1 if endpoint flipping used on input, 0 if not */ + int indat_endp_flip; + + /* 1 if endpoint flipping used on output, 0 if not */ + int outdat_endp_flip; + + /* Table mapping input data endpoint IDs to physical + port number and flip if used */ + int indat_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Same for output endpoints */ + int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Input acknowledge endpoints */ + int inack_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Output control endpoints */ + int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Endpoint used for input status */ + int instat_endpoint; + + /* Endpoint used for global control functions */ + int glocont_endpoint; + + int (*calculate_baud_rate) (u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler); + u32 baudclk; + +} keyspan_device_details; + + /* Now for each device type we setup the device detail + structure with the appropriate information (provided + in Keyspan's documentation) */ + +static const keyspan_device_details usa18x_device_details = { + 0x112, /* product ID */ + msg_usa26, /* msg type*/ + 1, /* num ports */ + 0, /* indat endpoint flip */ + 1, /* outdat endpoint flip */ + {0x81}, /* per port indat */ + {0x01}, /* per port outdat */ + {0x85}, /* per port inack */ + {0x05}, /* per port outcont */ + 0x87, /* instat endpoint */ + 0x07, /* glocont endpoint */ + keyspan_usa19w_calc_baud, /* calc baud rate */ + KEYSPAN_USA18X_BAUDCLK /* base baud clock */ +}; + +static const keyspan_device_details usa19_device_details = { + 0x107, /* product ID */ + msg_usa28, /* msg type*/ + 1, /* num ports */ + 1, /* indat endpoint flip */ + 1, /* outdat endpoint flip */ + {0x81}, /* per port indat */ + {0x01}, /* per port outdat */ + {0x83}, /* per port inack */ + {0x03}, /* per port outcont */ + 0x84, /* instat endpoint */ + -1, /* glocont endpoint */ + keyspan_usa19_calc_baud, /* calc baud rate */ + KEYSPAN_USA19_BAUDCLK /* base baud clock */ +}; + +static const keyspan_device_details usa19w_device_details = { + 0x108, /* product ID */ + msg_usa26, /* msg type*/ + 1, /* num ports */ + 0, /* indat endpoint flip */ + 1, /* outdat endpoint flip */ + {0x81}, /* per port indat */ + {0x01}, /* per port outdat */ + {0x85}, /* per port inack */ + {0x05}, /* per port outcont */ + 0x87, /* instat endpoint */ + 0x07, /* glocont endpoint */ + keyspan_usa19w_calc_baud, /* calc baud rate */ + KEYSPAN_USA19W_BAUDCLK /* base baud clock */ +}; + +static const keyspan_device_details usa28x_device_details = { + 0x110, /* product ID */ + msg_usa26, /* msg type*/ + 2, /* num ports */ + 0, /* indat endpoint flip */ + 1, /* outdat endpoint flip */ + {0x81, 0x83}, /* per port indat */ + {0x01, 0x03}, /* per port outdat */ + {0x85, 0x86}, /* per port inack */ + {0x05, 0x06}, /* per port outcont */ + 0x87, /* instat endpoint */ + 0x07, /* glocont endpoint */ + keyspan_usa19w_calc_baud, /* calc baud rate */ + KEYSPAN_USA28X_BAUDCLK +}; + +static const keyspan_device_details usa49w_device_details = { + 0x010a, /* product ID */ + msg_usa49, /* msg type*/ + 4, /* num ports */ + 0, /* indat endpoint flip */ + 0, /* outdat endpoint flip */ + { 0x81, 0x82, 0x83, 0x84}, /* per port indat */ + { 0x01, 0x02, 0x03, 0x04}, /* per port outdat */ + {-1, -1, -1, -1}, /* per port inack */ + {-1, -1, -1, -1}, /* per port outcont */ + 0x87, /* instat endpoint */ + 0x07, /* glocont endpoint */ + keyspan_usa19w_calc_baud, /* calc baud rate */ + KEYSPAN_USA49W_BAUDCLK +}; + +static const keyspan_device_details *keyspan_devices[] = { + &usa18x_device_details, + &usa19_device_details, + &usa19w_device_details, + &usa28x_device_details, + &usa49w_device_details, + NULL +}; - /* Device info for the Keyspan serial converter */ + /* Device info for the Keyspan serial converter, used + by the overall usb-serial probe function */ #define KEYSPAN_VENDOR_ID (0x06cd) static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; /* Product IDs for the five products supported, pre-renumeration */ -static __u16 keyspan_usa18x_pre_product_id = 0x0105; -static __u16 keyspan_usa19_pre_product_id = 0x0103; -static __u16 keyspan_usa19w_pre_product_id = 0x0106; -static __u16 keyspan_usa28_pre_product_id = 0x0101; -static __u16 keyspan_usa28x_pre_product_id = 0x0102; +static __u16 keyspan_usa18x_pre_product_id = 0x0105; +static __u16 keyspan_usa19_pre_product_id = 0x0103; +static __u16 keyspan_usa19w_pre_product_id = 0x0106; +static __u16 keyspan_usa28_pre_product_id = 0x0101; +static __u16 keyspan_usa28x_pre_product_id = 0x0102; +static __u16 keyspan_usa49w_pre_product_id = 0x0109; /* Product IDs post-renumeration */ -static __u16 keyspan_usa18x_product_id = 0x0112; -static __u16 keyspan_usa19_product_id = 0x0107; -static __u16 keyspan_usa19w_product_id = 0x0108; -static __u16 keyspan_usa28_product_id = 0x010f; -static __u16 keyspan_usa28x_product_id = 0x0110; +static __u16 keyspan_usa18x_product_id = 0x0112; +static __u16 keyspan_usa19_product_id = 0x0107; +static __u16 keyspan_usa19w_product_id = 0x0108; +static __u16 keyspan_usa28_product_id = 0x010f; +static __u16 keyspan_usa28x_product_id = 0x0110; +static __u16 keyspan_usa49w_product_id = 0x010a; + /* Structs for the devices, pre and post renumeration. These are incomplete at present - HAB 20000708 */ struct usb_serial_device_type keyspan_usa18x_pre_device = { - name: "Keyspan USA18X - (prerenumeration)", + name: "Keyspan USA18X - (without firmware)", idVendor: &keyspan_vendor_id, idProduct: &keyspan_usa18x_pre_product_id, needs_interrupt_in: DONT_CARE, @@ -150,7 +321,7 @@ }; struct usb_serial_device_type keyspan_usa19_pre_device = { - name: "Keyspan USA19 - (prerenumeration)", + name: "Keyspan USA19 - (without firmware)", idVendor: &keyspan_vendor_id, idProduct: &keyspan_usa19_pre_product_id, needs_interrupt_in: DONT_CARE, @@ -165,7 +336,7 @@ struct usb_serial_device_type keyspan_usa19w_pre_device = { - name: "Keyspan USA19W - (prerenumeration)", + name: "Keyspan USA19W - (without firmware)", idVendor: &keyspan_vendor_id, idProduct: &keyspan_usa19w_pre_product_id, needs_interrupt_in: DONT_CARE, @@ -180,7 +351,7 @@ struct usb_serial_device_type keyspan_usa28_pre_device = { - name: "Keyspan USA28 - (prerenumeration)", + name: "Keyspan USA28 - (without firmware)", idVendor: &keyspan_vendor_id, idProduct: &keyspan_usa28_pre_product_id, needs_interrupt_in: DONT_CARE, @@ -194,7 +365,7 @@ }; struct usb_serial_device_type keyspan_usa28x_pre_device = { - name: "Keyspan USA28X - (prerenumeration)", + name: "Keyspan USA28X - (without firmware)", idVendor: &keyspan_vendor_id, idProduct: &keyspan_usa28x_pre_product_id, needs_interrupt_in: DONT_CARE, @@ -207,23 +378,45 @@ startup: keyspan_fake_startup }; +struct usb_serial_device_type keyspan_usa49w_pre_device = { + name: "Keyspan USA49W - (without firmware)", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa49w_pre_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 4, + startup: keyspan_fake_startup +}; struct usb_serial_device_type keyspan_usa18x_device = { name: "Keyspan USA18X", idVendor: &keyspan_vendor_id, idProduct: &keyspan_usa18x_product_id, needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, + num_bulk_in: 3, + num_bulk_out: 4, num_ports: 1, open: keyspan_open, close: keyspan_close, + write: keyspan_write, + write_room: keyspan_write_room, + //write_bulk_callback: Not used - we define our own herbs + //read_int_callback: keyspan_usa26_read_int_callback, + chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, + ioctl: keyspan_ioctl, set_termios: keyspan_set_termios, + break_ctl: keyspan_break_ctl, + startup: keyspan_startup, + shutdown: keyspan_shutdown, }; struct usb_serial_device_type keyspan_usa19_device = { @@ -241,8 +434,8 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, - write_bulk_callback: keyspan_write_bulk_callback, - read_int_callback: keyspan_read_bulk_callback, +// write_bulk_callback: keyspan_write_bulk_callback, +// read_int_callback: keyspan_usa28_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, @@ -259,17 +452,26 @@ idVendor: &keyspan_vendor_id, idProduct: &keyspan_usa19w_product_id, needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, + num_bulk_in: 3, + num_bulk_out: 4, num_ports: 1, open: keyspan_open, close: keyspan_close, + write: keyspan_write, + write_room: keyspan_write_room, + //write_bulk_callback: Not used - we define our own herbs + //read_int_callback: keyspan_usa26_read_int_callback, + chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, + ioctl: keyspan_ioctl, set_termios: keyspan_set_termios, + break_ctl: keyspan_break_ctl, + startup: keyspan_startup, + shutdown: keyspan_shutdown, }; @@ -307,8 +509,8 @@ close: keyspan_close, write: keyspan_write, write_room: keyspan_write_room, - write_bulk_callback: keyspan_write_bulk_callback, - read_int_callback: keyspan_read_bulk_callback, +// write_bulk_callback: keyspan_write_bulk_callback, +// read_int_callback: keyspan_usa26_read_int_callback, chars_in_buffer: keyspan_chars_in_buffer, throttle: keyspan_rx_throttle, unthrottle: keyspan_rx_unthrottle, @@ -318,10 +520,35 @@ startup: keyspan_startup, shutdown: keyspan_shutdown, +}; +struct usb_serial_device_type keyspan_usa49w_device = { + name: "Keyspan USA49W", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa49w_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: 5, + num_bulk_out: 5, + num_ports: 4, + open: keyspan_open, + close: keyspan_close, + write: keyspan_write, + write_room: keyspan_write_room, + //write_bulk_callback: Not used - we define our own herbs + //read_int_callback: keyspan_usa26_read_int_callback, + chars_in_buffer: keyspan_chars_in_buffer, + throttle: keyspan_rx_throttle, + unthrottle: keyspan_rx_unthrottle, + ioctl: keyspan_ioctl, + set_termios: keyspan_set_termios, + break_ctl: keyspan_break_ctl, + startup: keyspan_startup, + shutdown: keyspan_shutdown, }; - #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/keyspan_usa26msg.h linux/drivers/usb/serial/keyspan_usa26msg.h --- v2.2.18/drivers/usb/serial/keyspan_usa26msg.h Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/keyspan_usa26msg.h Sun Mar 25 11:37:37 2001 @@ -92,16 +92,8 @@ #ifndef __USA26MSG__ #define __USA26MSG__ -#ifndef __stubs__ -#include "datadefs.h" -#endif -typedef struct txAckMessage -{ - u8 dummy; -} txAckMessage; - -typedef struct portControlMessage +typedef struct keyspan_usa26_portControlMessage { /* there are three types of "commands" sent in the control message: @@ -172,7 +164,7 @@ returnStatus, // BOTH: return current status (even if it hasn't changed) resetDataToggle;// BOTH: reset data toggle state to DATA0 -} portControlMessage; +} keyspan_usa26_portControlMessage; // defines for bits in lcr #define USA_DATABITS_5 0x00 @@ -190,7 +182,7 @@ // all things called "StatusMessage" are sent on the status endpoint -typedef struct portStatusMessage // one for each port +typedef struct keyspan_usa26_portStatusMessage // one for each port { u8 port, // BOTH: 0=first, 1=second, other=see below hskia_cts, // USA26: reports HSKIA pin @@ -203,7 +195,7 @@ _txXoff, // port is in XOFF state (either host or RX XOFF) rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off controlResponse;// 1=a control message has been processed -} portStatusMessage; +} keyspan_usa26_portStatusMessage; // bits in RX data message when STAT byte is included #define RXERROR_OVERRUN 0x02 @@ -211,28 +203,28 @@ #define RXERROR_FRAMING 0x08 #define RXERROR_BREAK 0x10 -typedef struct globalControlMessage +typedef struct keyspan_usa26_globalControlMessage { u8 sendGlobalStatus, // 2=request for two status responses resetStatusToggle, // 1=reset global status toggle resetStatusCount; // a cycling value -} globalControlMessage; +} keyspan_usa26_globalControlMessage; -typedef struct globalStatusMessage +typedef struct keyspan_usa26_globalStatusMessage { u8 port, // 3 sendGlobalStatus, // from request, decremented resetStatusCount; // as in request -} globalStatusMessage; +} keyspan_usa26_globalStatusMessage; -typedef struct globalDebugMessage +typedef struct keyspan_usa26_globalDebugMessage { u8 port, // 2 a, b, c, d; -} globalDebugMessage; +} keyspan_usa26_globalDebugMessage; // ie: the maximum length of an EZUSB endpoint buffer #define MAX_DATA_LEN 64 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/keyspan_usa28msg.h linux/drivers/usb/serial/keyspan_usa28msg.h --- v2.2.18/drivers/usb/serial/keyspan_usa28msg.h Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/keyspan_usa28msg.h Sun Mar 25 11:37:37 2001 @@ -94,16 +94,8 @@ #ifndef __USA28MSG__ #define __USA28MSG__ -/*#ifndef STUBS -#include "datadefs.h" -#endif*/ -typedef struct txAckMessage -{ - u8 dummy; -} txAckMessage; - -typedef struct portControlMessage +typedef struct keyspan_usa28_portControlMessage { /* there are four types of "commands" sent in the control message: @@ -153,9 +145,9 @@ returnStatus, // return current status n times (1 or 2) resetDataToggle;// reset data toggle state to DATA0 -} portControlMessage; +} keyspan_usa28_portControlMessage; -typedef struct portStatusMessage +typedef struct keyspan_usa28_portStatusMessage { u8 port, // 0=first, 1=second, 2=global (see below) cts, @@ -171,32 +163,32 @@ rxBreak, // 1=we're in break state rs232invalid, // 1=no valid signals on rs-232 inputs controlResponse;// 1=a control messages has been processed -} portStatusMessage; +} keyspan_usa28_portStatusMessage; // bit defines in txState #define TX_OFF 0x01 // requested by host txOff command #define TX_XOFF 0x02 // either real, or simulated by host -typedef struct globalControlMessage +typedef struct keyspan_usa28_globalControlMessage { u8 sendGlobalStatus, // 2=request for two status responses resetStatusToggle, // 1=reset global status toggle resetStatusCount; // a cycling value -} globalControlMessage; +} keyspan_usa28_globalControlMessage; -typedef struct globalStatusMessage +typedef struct keyspan_usa28_globalStatusMessage { u8 port, // 3 sendGlobalStatus, // from request, decremented resetStatusCount; // as in request -} globalStatusMessage; +} keyspan_usa28_globalStatusMessage; -typedef struct globalDebugMessage +typedef struct keyspan_usa28_globalDebugMessage { u8 port, // 2 n, // typically a count/status byte b; // typically a data byte -} globalDebugMessage; +} keyspan_usa28_globalDebugMessage; // ie: the maximum length of an EZUSB endpoint buffer #define MAX_DATA_LEN 64 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/keyspan_usa49msg.h linux/drivers/usb/serial/keyspan_usa49msg.h --- v2.2.18/drivers/usb/serial/keyspan_usa49msg.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/usb/serial/keyspan_usa49msg.h Sun Mar 25 11:37:37 2001 @@ -0,0 +1,255 @@ +/* + usa49msg.h + + Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + This file is available under a BSD-style copyright + + Keyspan USB Async Firmware to run on Anchor EZ-USB + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain this licence text + without modification, this list of conditions, and the following + disclaimer. The following copyright notice must appear immediately at + the beginning of all source files: + + Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + + This file is available under a BSD-style copyright + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of InnoSys Incorprated may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + 4th revision: USA49W version + + See usa26msg.h for description of message formats + + Third revision: USA28X version (aka USA26) + + Buffer formats for RX/TX data messages are not defined by + a structure, but are described here: + + USB OUT (host -> USA26, transmit) messages contain a + REQUEST_ACK indicator (set to 0xff to request an ACK at the + completion of transmit; 0x00 otherwise), followed by data: + + RQSTACK DAT DAT DAT ... + + with a total data length of 63. + + USB IN (USA26 -> host, receive) messages contain either a zero + flag (indicating no error in any data bytes): + + 00 DAT DAT DAT ... + + for a total of 63 data bytes, or a non-zero status flag (indicating + that all data bytes will be preceded by status flag): + + STAT DAT STAT DAT STAT DAT ... + + for a total of 32 data bytes. The valid bits in the STAT bytes are: + + OVERRUN 0x02 + PARITY 0x04 + FRAMING 0x08 + BREAK 0x10 + + Notes: + + 1. a "no status" RX data message (first byte zero) can serve as + a "break off" indicator. + 2. a control message specifying disablePort will be answered + with a status message, but no further status will be sent + until a control messages with enablePort is sent + + revision history: + + 1999feb10 add reportHskiaChanges to allow us to ignore them + 1999feb10 add txAckThreshold for fast+loose throughput enhancement + 1999mar30 beef up support for RX error reporting + 1999apr14 add resetDataToggle to control message + 2000jan04 merge with usa17msg.h + 2000mar08 clone from usa26msg.h -> usa49msg.h + 2000mar09 change to support 4 ports + 2000may03 change external clocking to match USA-49W hardware + 2000jun01 add extended BSD-style copyright text +*/ + +#ifndef __USA49MSG__ +#define __USA49MSG__ + + +/* + Host->device messages sent on the global control endpoint: + + portNumber message + ---------- -------------------- + 0,1,2,3 portControlMessage + 0x80 globalControlMessage +*/ + +typedef struct keyspan_usa49_portControlMessage +{ + /* + 0. 0/1/2/3 port control message follows + 0x80 set non-port control message follows + */ + u8 portNumber, + + /* + there are three types of "commands" sent in the control message: + + 1. configuration changes which must be requested by setting + the corresponding "set" flag (and should only be requested + when necessary, to reduce overhead on the USA26): + */ + setClocking, // host requests baud rate be set + baudLo, // host does baud divisor calculation + baudHi, // baudHi is only used for first port (gives lower rates) + prescaler, // specified as N/8; values 8-ff are valid + // must be set any time internal baud rate is set; + txClocking, // 0=internal, 1=external/DSR + rxClocking, // 0=internal, 1=external/DSR + + setLcr, // host requests lcr be set + lcr, // use PARITY, STOPBITS, DATABITS below + + setFlowControl, // host requests flow control be set + ctsFlowControl, // 1=use CTS flow control, 0=don't + xonFlowControl, // 1=use XON/XOFF flow control, 0=don't + xonChar, // specified in current character format + xoffChar, // specified in current character format + + setRts, // host requests RTS output be set + rts, // 1=active, 0=inactive + + setDtr, // host requests DTR output be set + dtr; // 1=on, 0=off + + + /* + 3. configuration data which is simply used as is (no overhead, + but must be specified correctly in every host message). + */ + u8 forwardingLength, // forward when this number of chars available + dsrFlowControl, // 1=use DSR flow control, 0=don't + txAckThreshold, // 0=not allowed, 1=normal, 2-255 deliver ACK faster + loopbackMode; // 0=no loopback, 1=loopback enabled + + /* + 4. commands which are flags only; these are processed in order + (so that, e.g., if both _txOn and _txOff flags are set, the + port ends in a TX_OFF state); any non-zero value is respected + */ + u8 _txOn, // enable transmitting (and continue if there's data) + _txOff, // stop transmitting + txFlush, // toss outbound data + txBreak, // turn on break (cleared by _txOn) + rxOn, // turn on receiver + rxOff, // turn off receiver + rxFlush, // toss inbound data + rxForward, // forward all inbound data, NOW (as if fwdLen==1) + returnStatus, // return current status (even if it hasn't changed) + resetDataToggle,// reset data toggle state to DATA0 + enablePort, // start servicing port (move data, check status) + disablePort; // stop servicing port (does implicit tx/rx flush/off) + +} keyspan_usa49_portControlMessage; + +// defines for bits in lcr +#define USA_DATABITS_5 0x00 +#define USA_DATABITS_6 0x01 +#define USA_DATABITS_7 0x02 +#define USA_DATABITS_8 0x03 +#define STOPBITS_5678_1 0x00 // 1 stop bit for all byte sizes +#define STOPBITS_5_1p5 0x04 // 1.5 stop bits for 5-bit byte +#define STOPBITS_678_2 0x04 // 2 stop bits for 6/7/8-bit byte +#define USA_PARITY_NONE 0x00 +#define USA_PARITY_ODD 0x08 +#define USA_PARITY_EVEN 0x18 +#define PARITY_1 0x28 +#define PARITY_0 0x38 + +typedef struct keyspan_usa49_globalControlMessage +{ + u8 portNumber, // 0x80 + sendGlobalStatus, // 1/2=number of status responses requested + resetStatusToggle, // 1=reset global status toggle + resetStatusCount, // a cycling value + remoteWakeupEnable; // 0x10=P1, 0x20=P2, 0x40=P3, 0x80=P3 +} keyspan_usa49_globalControlMessage; + +/* + Device->host messages send on the global status endpoint + + portNumber message + ---------- -------------------- + 0x00,0x01,0x02,0x03 portStatusMessage + 0x80 globalStatusMessage + 0x81 globalDebugMessage +*/ + +typedef struct keyspan_usa49_portStatusMessage // one for each port +{ + u8 portNumber, // 0,1,2,3 + cts, // reports CTS pin + dcd, // reports DCD pin + dsr, // reports DSR pin + ri, // reports RI pin + _txOff, // transmit has been disabled (by host) + _txXoff, // transmit is in XOFF state (either host or RX XOFF) + rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off + controlResponse,// 1=a control message has been processed + txAck, // ACK (data TX complete) + rs232valid; // RS-232 signal valid +} keyspan_usa49_portStatusMessage; + +// bits in RX data message when STAT byte is included +#define RXERROR_OVERRUN 0x02 +#define RXERROR_PARITY 0x04 +#define RXERROR_FRAMING 0x08 +#define RXERROR_BREAK 0x10 + +typedef struct keyspan_usa49_globalStatusMessage +{ + u8 portNumber, // 0x80=globalStatusMessage + sendGlobalStatus, // from request, decremented + resetStatusCount; // as in request +} keyspan_usa49_globalStatusMessage; + +typedef struct keyspan_usa49_globalDebugMessage +{ + u8 portNumber, // 0x81=globalDebugMessage + n, // typically a count/status byte + b; // typically a data byte +} keyspan_usa49_globalDebugMessage; + +// ie: the maximum length of an EZUSB endpoint buffer +#define MAX_DATA_LEN 64 + +// update status approx. 60 times a second (16.6666 ms) +#define STATUS_UPDATE_INTERVAL 16 + +// status rationing tuning value (each port gets checked each n ms) +#define STATUS_RATION 10 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/keyspan_usa49w_fw.h linux/drivers/usb/serial/keyspan_usa49w_fw.h --- v2.2.18/drivers/usb/serial/keyspan_usa49w_fw.h Wed Dec 31 19:00:00 1969 +++ linux/drivers/usb/serial/keyspan_usa49w_fw.h Sun Mar 25 11:37:37 2001 @@ -0,0 +1,457 @@ +/* keyspan_usa49w_fw.h + + Generated from Keyspan firmware image Thu Sep 28 09:13:26 2000 EST + This firmware is for the Keyspan USA-49W Serial Adaptor + + "The firmware contained herein as keyspan_usa49w_fw.h is + Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated + ("Keyspan"), as an unpublished work. This notice does not imply + unrestricted or public access to this firmware which is a trade secret of + Keyspan, and which may not be reproduced, used, sold or transferred to any + third party without Keyspan's prior written consent. All Rights Reserved. + + This firmware may not be modified and may only be used with the Keyspan + USA-49W Serial Adapter. Distribution and/or Modification of the + keyspan.c driver which includes this firmware, in whole or in part, + requires the inclusion of this statement." + +*/ + +static const struct ezusb_hex_record keyspan_usa49w_firmware[] = { +{ 0x0000, 3, {0x02, 0x10, 0x36} }, +{ 0x0003, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} }, +{ 0x0013, 16, {0x01, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} }, +{ 0x0023, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} }, +{ 0x0033, 3, {0x02, 0x17, 0xf0} }, +{ 0x0036, 12, {0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} }, +{ 0x0043, 3, {0x02, 0x18, 0x00} }, +{ 0x0046, 16, {0xe4, 0xff, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xfe, 0xe5, 0x27} }, +{ 0x0056, 16, {0x24, 0x04, 0xfd, 0xe4, 0x35, 0x26, 0xfa, 0xa9, 0x05, 0x7b, 0x01, 0xef, 0x7c, 0x00, 0x29, 0xf9} }, +{ 0x0066, 16, {0xec, 0x3a, 0xfa, 0xee, 0x12, 0x11, 0x90, 0x0f, 0xbf, 0x22, 0xd7, 0xe5, 0x27, 0x24, 0x05, 0xf5} }, +{ 0x0076, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x01, 0x4f, 0x7f, 0x01, 0xe5, 0x27} }, +{ 0x0086, 16, {0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27} }, +{ 0x0096, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0x6c, 0xe5, 0x27} }, +{ 0x00a6, 16, {0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x00, 0x03, 0xe5, 0x27} }, +{ 0x00b6, 16, {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x30, 0xf0, 0x7d, 0x04, 0x44} }, +{ 0x00c6, 16, {0x20, 0xf0, 0xe5, 0x27, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x12} }, +{ 0x00d6, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} }, +{ 0x00e6, 16, {0x05, 0xc0, 0xe5, 0x27, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x14} }, +{ 0x00f6, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} }, +{ 0x0106, 16, {0x05, 0x0b, 0x80, 0x03, 0x43, 0x05, 0x02, 0x7f, 0x03, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x39} }, +{ 0x0116, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04} }, +{ 0x0126, 16, {0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00} }, +{ 0x0136, 16, {0xf0, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0146, 16, {0xf5, 0x83, 0xe0, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0b, 0xf5, 0x82, 0xe4} }, +{ 0x0156, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x32, 0xe5, 0x27, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0166, 16, {0xf5, 0x83, 0xe0, 0x54, 0x3f, 0xff, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x0176, 16, {0x83, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4} }, +{ 0x0186, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0d, 0xf5, 0x82, 0xe4} }, +{ 0x0196, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x02, 0x6a, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82} }, +{ 0x01a6, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x01b6, 16, {0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4} }, +{ 0x01c6, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfb, 0xf0, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82} }, +{ 0x01d6, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x0e, 0xf5, 0x82} }, +{ 0x01e6, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x01f6, 16, {0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4} }, +{ 0x0206, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x0216, 16, {0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x27, 0x24, 0x0f, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0226, 16, {0xf5, 0x83, 0xe0, 0x60, 0x2f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} }, +{ 0x0236, 16, {0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x0246, 16, {0xff, 0x12, 0x14, 0xdd, 0xe5, 0x27, 0x24, 0x11, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x0256, 16, {0xff, 0x12, 0x15, 0x0d, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x0266, 16, {0xff, 0x12, 0x14, 0xad, 0xe5, 0x27, 0x24, 0x14, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x0276, 16, {0x60, 0x44, 0xe5, 0x27, 0x24, 0x15, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11} }, +{ 0x0286, 16, {0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80} }, +{ 0x0296, 16, {0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0} }, +{ 0x02a6, 16, {0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x02b6, 16, {0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x12, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x02c6, 16, {0x83, 0xe0, 0x60, 0x44, 0xe5, 0x27, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x02d6, 16, {0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x02} }, +{ 0x02e6, 16, {0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54} }, +{ 0x02f6, 16, {0xfd, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x0306, 16, {0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x16, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x0316, 16, {0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} }, +{ 0x0326, 16, {0xef, 0xf0, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe0} }, +{ 0x0336, 16, {0x11, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40, 0xf0} }, +{ 0x0346, 16, {0x80, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf} }, +{ 0x0356, 16, {0xf0, 0xe5, 0x27, 0x24, 0x18, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27} }, +{ 0x0366, 16, {0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x27, 0x24, 0x19, 0xf5} }, +{ 0x0376, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4} }, +{ 0x0386, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82} }, +{ 0x0396, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5} }, +{ 0x03a6, 16, {0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5} }, +{ 0x03b6, 16, {0x27, 0x24, 0x1a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x6b, 0xe5, 0x27, 0x24} }, +{ 0x03c6, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} }, +{ 0x03d6, 16, {0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f} }, +{ 0x03e6, 16, {0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0xfe} }, +{ 0x03f6, 16, {0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x0406, 16, {0x54, 0xfd, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} }, +{ 0x0416, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0426, 16, {0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1b, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x0436, 16, {0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x0446, 16, {0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x0456, 16, {0x44, 0x02, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82} }, +{ 0x0466, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1c} }, +{ 0x0476, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} }, +{ 0x0486, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x2c, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27} }, +{ 0x0496, 16, {0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0} }, +{ 0x04a6, 16, {0xe4, 0xff, 0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} }, +{ 0x04b6, 16, {0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x1d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x04c6, 16, {0x60, 0x27, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40} }, +{ 0x04d6, 16, {0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x04e6, 16, {0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x1e, 0xf5, 0x82, 0xe4} }, +{ 0x04f6, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0506, 16, {0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24} }, +{ 0x0516, 16, {0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5} }, +{ 0x0526, 16, {0x27, 0x24, 0x1f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24} }, +{ 0x0536, 16, {0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x27, 0xe5, 0x27, 0x24, 0x32, 0xf5} }, +{ 0x0546, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15} }, +{ 0x0556, 16, {0x3d, 0xe5, 0x27, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28} }, +{ 0x0566, 16, {0x42, 0x25, 0xe5, 0x27, 0x24, 0x20, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e} }, +{ 0x0576, 16, {0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x18, 0x90, 0x78} }, +{ 0x0586, 16, {0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x0596, 16, {0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x21, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x05a6, 16, {0x83, 0xe0, 0x60, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x05b6, 16, {0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x22, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60} }, +{ 0x05c6, 16, {0x1f, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5} }, +{ 0x05d6, 16, {0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25} }, +{ 0x05e6, 16, {0xe5, 0x27, 0x24, 0x23, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x12, 0x17} }, +{ 0x05f6, 16, {0x4e, 0xe5, 0x27, 0x24, 0x24, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x1b, 0xe5} }, +{ 0x0606, 16, {0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f} }, +{ 0x0616, 16, {0x98, 0xe0, 0xff, 0xe5, 0x28, 0xf4, 0xfe, 0xef, 0x5e, 0xf0, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} }, +{ 0x0626, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x16, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x0636, 14, {0x26, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0} }, +{ 0x0644, 1, {0x22} }, +{ 0x0645, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x11, 0xa2, 0x07, 0x42, 0x00, 0x07, 0xb6, 0x01, 0x08, 0x22, 0x03} }, +{ 0x0655, 16, {0x06, 0x68, 0x06, 0x07, 0x35, 0x08, 0x07, 0x2f, 0x09, 0x07, 0x17, 0x0a, 0x07, 0x26, 0x0b, 0x00} }, +{ 0x0665, 16, {0x00, 0x08, 0x71, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x77, 0x24, 0x02} }, +{ 0x0675, 16, {0x60, 0x03, 0x02, 0x07, 0x0d, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} }, +{ 0x0685, 16, {0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0} }, +{ 0x0695, 16, {0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe0, 0x04, 0x7f, 0x03, 0x80, 0x02, 0x7f, 0x02, 0x75, 0x82, 0x82} }, +{ 0x06a5, 16, {0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x6d, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75} }, +{ 0x06b5, 16, {0x83, 0x19, 0xf0, 0x75, 0x82, 0x5f, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19} }, +{ 0x06c5, 16, {0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe1, 0x04, 0x7f, 0x64, 0x80, 0x02, 0x7f, 0x32, 0x75, 0x82} }, +{ 0x06d5, 16, {0x1a, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f} }, +{ 0x06e5, 16, {0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x13, 0x54, 0xea, 0x49, 0x60} }, +{ 0x06f5, 16, {0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f} }, +{ 0x0705, 16, {0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02} }, +{ 0x0715, 16, {0x08, 0x78, 0x90, 0x7f, 0x00, 0xe5, 0x0a, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x08} }, +{ 0x0725, 16, {0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0a, 0x02, 0x08, 0x78, 0x12, 0x0a, 0x6a, 0x02, 0x08, 0x78} }, +{ 0x0735, 16, {0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xe8} }, +{ 0x0745, 16, {0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33} }, +{ 0x0755, 16, {0xff, 0x25, 0xe0, 0xff, 0xa2, 0x06, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0} }, +{ 0x0765, 16, {0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0} }, +{ 0x0775, 16, {0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80} }, +{ 0x0785, 16, {0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4} }, +{ 0x0795, 16, {0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f} }, +{ 0x07a5, 16, {0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08} }, +{ 0x07b5, 16, {0x78, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x08, 0x78} }, +{ 0x07c5, 16, {0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0} }, +{ 0x07d5, 16, {0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0} }, +{ 0x07e5, 16, {0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} }, +{ 0x07f5, 16, {0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff} }, +{ 0x0805, 16, {0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44} }, +{ 0x0815, 16, {0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8} }, +{ 0x0825, 16, {0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} }, +{ 0x0835, 16, {0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea} }, +{ 0x0845, 16, {0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} }, +{ 0x0855, 16, {0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} }, +{ 0x0865, 16, {0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0} }, +{ 0x0875, 10, {0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} }, +{ 0x087f, 1, {0x22} }, +{ 0x0880, 16, {0xe5, 0x23, 0x54, 0x0f, 0x70, 0x03, 0x02, 0x09, 0x5f, 0x12, 0x15, 0x9b, 0xef, 0x20, 0xe1, 0x63} }, +{ 0x0890, 16, {0x12, 0x15, 0xf9, 0xef, 0x14, 0xf5, 0x1a, 0x12, 0x17, 0xc1, 0xef, 0x25, 0x1a, 0xff, 0xe4, 0x33} }, +{ 0x08a0, 16, {0xfe, 0xc3, 0xef, 0x94, 0x80, 0xee, 0x64, 0x80, 0x94, 0x80, 0x50, 0x47, 0x85, 0x27, 0x82, 0x85} }, +{ 0x08b0, 16, {0x26, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x30, 0xe0, 0x11, 0xe5} }, +{ 0x08c0, 16, {0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f} }, +{ 0x08d0, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x85} }, +{ 0x08e0, 16, {0x1a, 0x08, 0xef, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12, 0x13, 0xd6, 0xe4, 0xff} }, +{ 0x08f0, 16, {0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30} }, +{ 0x0900, 16, {0xe7, 0x5d, 0x12, 0x17, 0xc1, 0xe5, 0x27, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} }, +{ 0x0910, 16, {0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x48, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0920, 16, {0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} }, +{ 0x0930, 16, {0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4} }, +{ 0x0940, 16, {0xf0, 0xe5, 0x28, 0x42, 0x25, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x10, 0xe5, 0x27, 0x24, 0x26} }, +{ 0x0950, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xf5, 0x09, 0x80, 0x03, 0x12, 0x12, 0x3d, 0x12} }, +{ 0x0960, 16, {0x15, 0xca, 0xef, 0x30, 0xe1, 0x03, 0x02, 0x0a, 0x69, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4} }, +{ 0x0970, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x80, 0xf0, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x0980, 16, {0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x17, 0xcd, 0xee, 0x4f, 0xd0, 0x82} }, +{ 0x0990, 16, {0xd0, 0x83, 0xf0, 0x12, 0x16, 0xd1, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x09a0, 16, {0x26, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x28, 0x12, 0x17, 0xa9, 0xef, 0x30, 0xe0} }, +{ 0x09b0, 16, {0x21, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe7, 0x12} }, +{ 0x09c0, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x03, 0x02} }, +{ 0x09d0, 16, {0x0a, 0x69, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfd} }, +{ 0x09e0, 16, {0xf0, 0xe5, 0x1a, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} }, +{ 0x09f0, 16, {0xe4, 0xf0, 0x22, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff} }, +{ 0x0a00, 16, {0x30, 0xe7, 0x29, 0xe5, 0x1a, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x1a, 0x20, 0x85, 0x1a, 0x08} }, +{ 0x0a10, 16, {0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0x8c, 0x0f, 0xf5, 0x10} }, +{ 0x0a20, 16, {0x12, 0x13, 0x06, 0xe5, 0x1a, 0x25, 0xe0, 0xff, 0x12, 0x14, 0x42, 0x22, 0xe5, 0x1a, 0xd3, 0x94} }, +{ 0x0a30, 16, {0x3f, 0x40, 0x03, 0x75, 0x1a, 0x3f, 0x85, 0x1a, 0x08, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3} }, +{ 0x0a40, 16, {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x85, 0x27, 0x82, 0x85, 0x26} }, +{ 0x0a50, 16, {0x83, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12} }, +{ 0x0a60, 9, {0x13, 0x95, 0xe5, 0x1a, 0x04, 0xff, 0x12, 0x14, 0x42} }, +{ 0x0a69, 1, {0x22} }, +{ 0x0a6a, 16, {0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} }, +{ 0x0a7a, 16, {0x90, 0x7f, 0x94, 0xf0, 0x90, 0x78, 0x4a, 0x04, 0xf0, 0xf5, 0x8e, 0x90, 0x7f, 0x95, 0x74, 0xc0} }, +{ 0x0a8a, 16, {0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x1f, 0xf0, 0x90, 0x78, 0x43} }, +{ 0x0a9a, 16, {0x74, 0xff, 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x9f, 0xf0, 0x90, 0x7f} }, +{ 0x0aaa, 16, {0xde, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b} }, +{ 0x0aba, 16, {0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x0e, 0xb3, 0x7e} }, +{ 0x0aca, 16, {0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} }, +{ 0x0ada, 16, {0x28, 0x01, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0x7e} }, +{ 0x0aea, 16, {0x7e, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x40, 0xf0} }, +{ 0x0afa, 16, {0x7e, 0x7e, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3} }, +{ 0x0b0a, 16, {0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96} }, +{ 0x0b1a, 16, {0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} }, +{ 0x0b2a, 16, {0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0xe5, 0x27, 0x24, 0x26} }, +{ 0x0b3a, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x7e, 0x7d, 0x7f, 0xc0, 0x85, 0x27} }, +{ 0x0b4a, 16, {0x82, 0x85, 0x26, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0xc0, 0xf0, 0x7e, 0x7e, 0x7f, 0x00, 0x85} }, +{ 0x0b5a, 16, {0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0x7e, 0x7c} }, +{ 0x0b6a, 16, {0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} }, +{ 0x0b7a, 16, {0x04, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} }, +{ 0x0b8a, 16, {0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0b9a, 16, {0xf5, 0x83, 0x74, 0x02, 0xf0, 0x7e, 0x7d, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74} }, +{ 0x0baa, 16, {0x7d, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7d, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83} }, +{ 0x0bba, 16, {0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c} }, +{ 0x0bca, 16, {0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x0e, 0xb3, 0x7e} }, +{ 0x0bda, 16, {0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75} }, +{ 0x0bea, 16, {0x28, 0x08, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0} }, +{ 0x0bfa, 16, {0x7e, 0x7c, 0x7f, 0xc0, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7c, 0xf0, 0xa3, 0x74, 0xc0} }, +{ 0x0c0a, 16, {0xf0, 0x7e, 0x7d, 0x7f, 0x00, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0} }, +{ 0x0c1a, 7, {0xa3, 0x74, 0x00, 0xf0, 0xd2, 0x02, 0x22} }, +{ 0x0c21, 16, {0xe5, 0x22, 0x04, 0x54, 0x03, 0xf5, 0x22, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x31, 0x14, 0x60, 0x43} }, +{ 0x0c31, 16, {0x24, 0x03, 0x70, 0x52, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f} }, +{ 0x0c41, 16, {0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x80, 0x3d, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} }, +{ 0x0c51, 16, {0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x80, 0x28, 0x7e, 0x7c} }, +{ 0x0c61, 16, {0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} }, +{ 0x0c71, 16, {0x04, 0x80, 0x13, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} }, +{ 0x0c81, 16, {0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0xe5, 0x15, 0x55, 0x28, 0x70, 0x03, 0x02, 0x0d, 0xbf, 0xe5} }, +{ 0x0c91, 16, {0x28, 0xf4, 0xff, 0x52, 0x15, 0xe5, 0x0b, 0x54, 0x7f, 0xfe, 0x70, 0x0f, 0xe5, 0x0d, 0x55, 0x28} }, +{ 0x0ca1, 16, {0x60, 0x24, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0, 0x80, 0x1b, 0xbe, 0x20, 0x18, 0xe5, 0x27} }, +{ 0x0cb1, 16, {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe3, 0x09, 0xe4, 0xf5, 0x0d} }, +{ 0x0cc1, 16, {0x90, 0x7f, 0x98, 0xe0, 0x5f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x0cd1, 16, {0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe5, 0x27, 0x24, 0x34, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0ce1, 16, {0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe0, 0x60, 0x03, 0x02, 0x0d, 0xbf, 0x74, 0x0a} }, +{ 0x0cf1, 16, {0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0x01, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} }, +{ 0x0d01, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} }, +{ 0x0d11, 16, {0x12, 0x17, 0xd9, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x27, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} }, +{ 0x0d21, 16, {0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x10, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25} }, +{ 0x0d31, 16, {0xe5, 0x27, 0x24, 0x28, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54} }, +{ 0x0d41, 16, {0x80, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x29, 0xf5} }, +{ 0x0d51, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x20, 0xfe, 0x6f, 0x60, 0x15} }, +{ 0x0d61, 16, {0xee, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe4} }, +{ 0x0d71, 16, {0x04, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x24, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2a} }, +{ 0x0d81, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x16, 0xe5, 0x1a, 0xf0, 0xe5, 0x27} }, +{ 0x0d91, 16, {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe5, 0x04, 0xe5, 0x28, 0x42} }, +{ 0x0da1, 16, {0x25, 0xe5, 0x29, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x30, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x0db1, 14, {0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} }, +{ 0x0dbf, 1, {0x22} }, +{ 0x0dc0, 16, {0xe5, 0x09, 0x14, 0x60, 0x2a, 0x14, 0x60, 0x41, 0x14, 0x60, 0x58, 0x14, 0x60, 0x6f, 0x24, 0x04} }, +{ 0x0dd0, 16, {0x60, 0x03, 0x02, 0x0e, 0x77, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90} }, +{ 0x0de0, 16, {0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x01, 0x22, 0x7e} }, +{ 0x0df0, 16, {0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75} }, +{ 0x0e00, 16, {0x28, 0x02, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x02, 0x22, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c} }, +{ 0x0e10, 16, {0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x12, 0x3d, 0x75} }, +{ 0x0e20, 16, {0x09, 0x03, 0x22, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} }, +{ 0x0e30, 16, {0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x04, 0x22, 0x30, 0x04, 0x33} }, +{ 0x0e40, 16, {0xc2, 0x04, 0x53, 0x25, 0xdf, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x11, 0x25, 0x1a} }, +{ 0x0e50, 16, {0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4} }, +{ 0x0e60, 16, {0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3} }, +{ 0x0e70, 16, {0x74, 0x03, 0xf0, 0x75, 0x09, 0x05, 0x22, 0xe5, 0x17, 0x60, 0x34, 0xd5, 0x17, 0x03, 0x53, 0x25} }, +{ 0x0e80, 16, {0xef, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x16, 0x25, 0x1a, 0xf9, 0xee, 0x34, 0x00} }, +{ 0x0e90, 16, {0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} }, +{ 0x0ea0, 16, {0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4} }, +{ 0x0eb0, 2, {0xf5, 0x09} }, +{ 0x0eb2, 1, {0x22} }, +{ 0x0eb3, 16, {0xe4, 0xf5, 0x19, 0x7e, 0x00, 0x7b, 0x01, 0xe5, 0x27, 0x25, 0x19, 0xf9, 0xee, 0x35, 0x26, 0xfa} }, +{ 0x0ec3, 16, {0xe4, 0x12, 0x11, 0x90, 0x05, 0x19, 0xe5, 0x19, 0xb4, 0x3c, 0xe8, 0xe5, 0x27, 0x24, 0x35, 0xf5} }, +{ 0x0ed3, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5} }, +{ 0x0ee3, 16, {0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00} }, +{ 0x0ef3, 16, {0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x15, 0x3d, 0x7f, 0x10, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82} }, +{ 0x0f03, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x14, 0xad, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0} }, +{ 0x0f13, 16, {0x7f, 0x01, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x44} }, +{ 0x0f23, 16, {0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5} }, +{ 0x0f33, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd} }, +{ 0x0f43, 16, {0x12, 0x15, 0x3d, 0xe4, 0xff, 0x7e, 0xa3, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} }, +{ 0x0f53, 16, {0xf5, 0x83, 0xee, 0xf0, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0} }, +{ 0x0f63, 16, {0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x15, 0x3d, 0x7f, 0x01, 0x12, 0x14, 0x78, 0x7f} }, +{ 0x0f73, 6, {0x03, 0x7d, 0x07, 0x12, 0x15, 0x3d} }, +{ 0x0f79, 1, {0x22} }, +{ 0x0f7a, 16, {0x53, 0x25, 0x3f, 0x90, 0x7b, 0xf1, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26} }, +{ 0x0f8a, 16, {0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x08, 0x80} }, +{ 0x0f9a, 16, {0x90, 0x7c, 0x31, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} }, +{ 0x0faa, 16, {0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x08, 0x80, 0x90, 0x7c, 0x71} }, +{ 0x0fba, 16, {0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} }, +{ 0x0fca, 16, {0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x08, 0x80, 0x90, 0x7c, 0xb1, 0xe0, 0x30, 0xe3} }, +{ 0x0fda, 16, {0x16, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f} }, +{ 0x0fea, 16, {0xf0, 0x75, 0x28, 0x08, 0x12, 0x08, 0x80, 0x05, 0x23, 0xe5, 0x23, 0x54, 0x0f, 0xf5, 0x19, 0x70} }, +{ 0x0ffa, 16, {0x1f, 0x90, 0x78, 0x41, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf5, 0x29, 0x90, 0x78} }, +{ 0x100a, 16, {0x41, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf4, 0xf5, 0x24, 0x12, 0x10, 0xc2, 0x22} }, +{ 0x101a, 16, {0xe5, 0x19, 0xb4, 0x01, 0x04, 0x12, 0x0c, 0x21, 0x22, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x08} }, +{ 0x102a, 11, {0xe5, 0x25, 0x60, 0x04, 0x12, 0x0d, 0xc0, 0x22, 0x12, 0x0c, 0x21} }, +{ 0x1035, 1, {0x22} }, +{ 0x1036, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x29, 0x02, 0x10, 0x7d} }, +{ 0x1042, 16, {0x02, 0x11, 0xc8, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} }, +{ 0x1052, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} }, +{ 0x1062, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} }, +{ 0x1072, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x17, 0x67, 0xe4, 0x7e} }, +{ 0x1082, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} }, +{ 0x1092, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} }, +{ 0x10a2, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} }, +{ 0x10b2, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} }, +{ 0x10c2, 16, {0x90, 0x7f, 0xd2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0x49, 0x90, 0x7b, 0x40, 0xe0, 0x14, 0x60} }, +{ 0x10d2, 16, {0x26, 0x14, 0x60, 0x3b, 0x14, 0x60, 0x50, 0x24, 0x83, 0x60, 0x64, 0x24, 0x80, 0x70, 0x63, 0x7e} }, +{ 0x10e2, 16, {0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} }, +{ 0x10f2, 16, {0x28, 0x01, 0x12, 0x00, 0x46, 0x80, 0x4b, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} }, +{ 0x1102, 16, {0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x00, 0x46, 0x80, 0x33, 0x7e} }, +{ 0x1112, 16, {0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75} }, +{ 0x1122, 16, {0x28, 0x04, 0x12, 0x00, 0x46, 0x80, 0x1b, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27} }, +{ 0x1132, 16, {0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x00, 0x46, 0x80, 0x03, 0x12} }, +{ 0x1142, 8, {0x16, 0x56, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x22} }, +{ 0x114a, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} }, +{ 0x115a, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} }, +{ 0x1163, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} }, +{ 0x1173, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} }, +{ 0x1183, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} }, +{ 0x1190, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} }, +{ 0x11a0, 2, {0xf3, 0x22} }, +{ 0x11a2, 16, {0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} }, +{ 0x11b2, 16, {0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} }, +{ 0x11c2, 6, {0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} }, +{ 0x11c8, 16, {0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x00, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8} }, +{ 0x11d8, 16, {0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab} }, +{ 0x11e8, 16, {0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} }, +{ 0x11f8, 16, {0xaf, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x09, 0x12, 0x17} }, +{ 0x1208, 16, {0x13, 0xc2, 0x01, 0xe4, 0xf5, 0x0e, 0xf5, 0x14, 0xc2, 0x07, 0xc2, 0x02, 0x90, 0x7f, 0xd8, 0xe0} }, +{ 0x1218, 16, {0x65, 0x0b, 0x60, 0x06, 0x75, 0x15, 0x0f, 0xe0, 0xf5, 0x0b, 0x30, 0x02, 0x03, 0x12, 0x0f, 0x7a} }, +{ 0x1228, 16, {0x30, 0x01, 0x07, 0xc2, 0x01, 0x12, 0x06, 0x45, 0x80, 0xe2, 0x30, 0x08, 0xdf, 0xc2, 0x08, 0x12} }, +{ 0x1238, 5, {0x17, 0x95, 0x80, 0xd8, 0x22} }, +{ 0x123d, 16, {0xe5, 0x25, 0x55, 0x28, 0x60, 0x6a, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x124d, 16, {0x83, 0xe0, 0x70, 0x5c, 0xe5, 0x28, 0xf4, 0x52, 0x25, 0xe5, 0x27, 0x24, 0x26, 0xff, 0xe4, 0x35} }, +{ 0x125d, 16, {0x26, 0xfe, 0xe4, 0xfd, 0x0f, 0xef, 0xaa, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8a, 0x83} }, +{ 0x126d, 16, {0xe0, 0xfc, 0x74, 0x80, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0xbd} }, +{ 0x127d, 16, {0x0b, 0xe2, 0x90, 0x7f, 0xc3, 0x74, 0x0b, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35} }, +{ 0x128d, 16, {0x26, 0xf5, 0x83, 0x74, 0x10, 0xf0, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x129d, 16, {0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0} }, +{ 0x12ad, 1, {0x22} }, +{ 0x12ae, 16, {0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} }, +{ 0x12be, 16, {0x90, 0x78, 0x4a, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90} }, +{ 0x12ce, 16, {0x7f, 0x97, 0xf0, 0xe5, 0x0c, 0x54, 0xf0, 0x44, 0x08, 0x90, 0x78, 0x41, 0xf0, 0xe4, 0x90, 0x7f} }, +{ 0x12de, 16, {0x98, 0xf0, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98} }, +{ 0x12ee, 16, {0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} }, +{ 0x12fe, 8, {0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x22} }, +{ 0x1306, 16, {0x8f, 0x1b, 0x05, 0x10, 0xe5, 0x10, 0xae, 0x0f, 0x70, 0x02, 0x05, 0x0f, 0x14, 0xf5, 0x82, 0x8e} }, +{ 0x1316, 16, {0x83, 0xe5, 0x1b, 0xf0, 0x12, 0x17, 0xe5, 0x05, 0x10, 0xe5, 0x10, 0xac, 0x0f, 0x70, 0x02, 0x05} }, +{ 0x1326, 16, {0x0f, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x1f, 0xe5, 0x27} }, +{ 0x1336, 16, {0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12} }, +{ 0x1346, 14, {0x17, 0xcd, 0x8f, 0x1b, 0xee, 0x4f, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x80, 0xb5, 0x22} }, +{ 0x1354, 2, {0x8f, 0x19} }, +{ 0x1356, 16, {0xe4, 0xf5, 0x1a, 0x75, 0x1b, 0xff, 0x75, 0x1c, 0x19, 0x75, 0x1d, 0x86, 0xab, 0x1b, 0xaa, 0x1c} }, +{ 0x1366, 16, {0xa9, 0x1d, 0x90, 0x00, 0x01, 0x12, 0x11, 0x63, 0xb4, 0x03, 0x1d, 0xaf, 0x1a, 0x05, 0x1a, 0xef} }, +{ 0x1376, 16, {0xb5, 0x19, 0x01, 0x22, 0x12, 0x11, 0x4a, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} }, +{ 0x1386, 14, {0x1b, 0xff, 0xf5, 0x1c, 0x89, 0x1d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} }, +{ 0x1394, 1, {0x22} }, +{ 0x1395, 16, {0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x78, 0x4f, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x50, 0xf0} }, +{ 0x13a5, 16, {0xe5, 0x0f, 0x90, 0x78, 0x51, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} }, +{ 0x13b5, 16, {0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x10} }, +{ 0x13c5, 16, {0xf0, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa} }, +{ 0x13d5, 1, {0x22} }, +{ 0x13d6, 16, {0xe4, 0x90, 0x78, 0x41, 0xf0, 0xe5, 0x0f, 0x90, 0x78, 0x4f, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90} }, +{ 0x13e6, 16, {0x78, 0x50, 0xf0, 0x90, 0x78, 0x51, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} }, +{ 0x13f6, 16, {0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90} }, +{ 0x1406, 6, {0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22} }, +{ 0x140c, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} }, +{ 0x141c, 16, {0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} }, +{ 0x142c, 16, {0xc9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xcb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xcd, 0xef} }, +{ 0x143c, 6, {0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} }, +{ 0x1442, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} }, +{ 0x1452, 16, {0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xb7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} }, +{ 0x1462, 16, {0xb9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xbb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xbd, 0xef} }, +{ 0x1472, 6, {0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} }, +{ 0x1478, 16, {0xae, 0x07, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} }, +{ 0x1488, 16, {0x54, 0x7f, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xee} }, +{ 0x1498, 16, {0xf0, 0xe4, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80} }, +{ 0x14a8, 5, {0xfd, 0x12, 0x15, 0x3d, 0x22} }, +{ 0x14ad, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} }, +{ 0x14bd, 16, {0x02, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} }, +{ 0x14cd, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} }, +{ 0x14dd, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} }, +{ 0x14ed, 16, {0x04, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} }, +{ 0x14fd, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} }, +{ 0x150d, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} }, +{ 0x151d, 16, {0x06, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} }, +{ 0x152d, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} }, +{ 0x153d, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} }, +{ 0x154d, 16, {0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x07, 0xf0, 0x90, 0xc0} }, +{ 0x155d, 15, {0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22} }, +{ 0x156c, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0xe4, 0x90, 0x78, 0x41} }, +{ 0x157c, 16, {0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37} }, +{ 0x158c, 15, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} }, +{ 0x159b, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} }, +{ 0x15ab, 16, {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc8} }, +{ 0x15bb, 15, {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xca, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcc, 0xe0, 0xff, 0x22} }, +{ 0x15ca, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} }, +{ 0x15da, 16, {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xb6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xb8} }, +{ 0x15ea, 15, {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xba, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xbc, 0xe0, 0xff, 0x22} }, +{ 0x15f9, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} }, +{ 0x1609, 16, {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc9} }, +{ 0x1619, 15, {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcb, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcd, 0xe0, 0xff, 0x22} }, +{ 0x1628, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} }, +{ 0x1638, 16, {0x05, 0x04, 0xc2, 0x05, 0x80, 0x02, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} }, +{ 0x1648, 14, {0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} }, +{ 0x1656, 16, {0x90, 0x7b, 0x41, 0xe0, 0xf5, 0x17, 0x43, 0x25, 0x10, 0xa3, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7} }, +{ 0x1666, 16, {0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0x90, 0x7b, 0x43, 0xe0, 0xf5, 0x18, 0x30, 0x00, 0x07, 0xa3} }, +{ 0x1676, 10, {0xe0, 0x54, 0xf0, 0xf5, 0x0c, 0x22, 0xe4, 0xf5, 0x0c, 0x22} }, +{ 0x1680, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} }, +{ 0x1690, 16, {0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} }, +{ 0x16a0, 10, {0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} }, +{ 0x16aa, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} }, +{ 0x16ba, 16, {0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} }, +{ 0x16ca, 7, {0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} }, +{ 0x16d1, 16, {0x12, 0x17, 0xb5, 0xae, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0xee, 0x6d, 0x60, 0x10, 0x12, 0x17} }, +{ 0x16e1, 16, {0xb5, 0xae, 0x07, 0xee, 0x6d, 0x60, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0x80, 0xec, 0xaf, 0x06} }, +{ 0x16f1, 1, {0x22} }, +{ 0x16f2, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} }, +{ 0x1702, 1, {0x22} }, +{ 0x1703, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} }, +{ 0x1713, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x04, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x09, 0x04, 0xe0, 0x44} }, +{ 0x1723, 16, {0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x17, 0x34, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} }, +{ 0x1733, 1, {0x22} }, +{ 0x1734, 16, {0x8e, 0x19, 0x8f, 0x1a, 0xe5, 0x1a, 0x15, 0x1a, 0xae, 0x19, 0x70, 0x02, 0x15, 0x19, 0x4e, 0x60} }, +{ 0x1744, 10, {0x08, 0x12, 0x16, 0xf2, 0x12, 0x16, 0xf2, 0x80, 0xeb, 0x22} }, +{ 0x174e, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x04, 0xff, 0x44, 0x10} }, +{ 0x175e, 9, {0x90, 0x7f, 0xd7, 0xf0, 0xef, 0x44, 0x30, 0xf0, 0x22} }, +{ 0x1767, 16, {0x03, 0x16, 0x80, 0x00, 0x00, 0x03, 0x11, 0x81, 0x00, 0x00, 0xc1, 0x85, 0xc1, 0x81, 0xc1, 0x08} }, +{ 0x1777, 7, {0xc1, 0x00, 0xc1, 0x86, 0x01, 0x09, 0x00} }, +{ 0x177e, 1, {0x00} }, +{ 0x177f, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x17, 0x34, 0x90, 0x7f} }, +{ 0x178f, 6, {0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} }, +{ 0x1795, 16, {0x12, 0x12, 0xae, 0x12, 0x17, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x03, 0x12, 0x17, 0x7f} }, +{ 0x17a5, 4, {0x12, 0x0a, 0x6a, 0x22} }, +{ 0x17a9, 12, {0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} }, +{ 0x17b5, 12, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} }, +{ 0x17c1, 12, {0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} }, +{ 0x17cd, 12, {0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} }, +{ 0x17d9, 12, {0x90, 0x78, 0x41, 0x74, 0x06, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} }, +{ 0x17e5, 11, {0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} }, +{ 0x17f0, 4, {0x53, 0xd8, 0xef, 0x32} }, +{ 0x1800, 15, {0x02, 0x16, 0xaa, 0x00, 0x02, 0x18, 0x04, 0x00, 0x02, 0x16, 0x80, 0x00, 0x02, 0x16, 0x28} }, +{ 0x1900, 16, {0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x01, 0x02} }, +{ 0x1910, 16, {0x00, 0x04, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} }, +{ 0x1920, 16, {0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} }, +{ 0x1930, 16, {0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} }, +{ 0x1940, 16, {0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} }, +{ 0x1950, 16, {0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02} }, +{ 0x1960, 16, {0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} }, +{ 0x1970, 16, {0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07} }, +{ 0x1980, 16, {0x05, 0x87, 0x02, 0x40, 0x00, 0x01, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} }, +{ 0x1990, 16, {0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} }, +{ 0x19a0, 16, {0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} }, +{ 0x19b0, 16, {0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} }, +{ 0x19c0, 16, {0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} }, +{ 0x19d0, 16, {0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} }, +{ 0x19e0, 16, {0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} }, +{ 0x19f0, 16, {0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} }, +{ 0x1a00, 10, {0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} }, +{ 0xffff, 0, {0x00} } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h --- v2.2.18/drivers/usb/serial/usb-serial.h Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/usb-serial.h Sun Mar 25 11:37:37 2001 @@ -11,6 +11,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (10/05/2000) gkh + * Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help + * fix bug with urb->dev not being set properly, now that the usb core + * needs it. + * * (09/11/2000) gkh * Added usb_serial_debug_data function to help get rid of #DEBUG in the * drivers. @@ -57,9 +62,11 @@ unsigned char * interrupt_in_buffer; struct urb * interrupt_in_urb; + __u8 interrupt_in_endpointAddress; unsigned char * bulk_in_buffer; struct urb * read_urb; + __u8 bulk_in_endpointAddress; unsigned char * bulk_out_buffer; int bulk_out_size; @@ -118,7 +125,9 @@ struct list_head driver_list; /* function call to make before accepting driver */ - int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ + /* return 0 to continue initialization, anything else to abort */ + int (*startup) (struct usb_serial *serial); + void (*shutdown) (struct usb_serial *serial); /* serial function calls */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.2.18/drivers/usb/serial/usbserial.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/usbserial.c Sun Mar 25 11:37:37 2001 @@ -14,6 +14,23 @@ * based on a driver by Brad Keryan) * * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * 2001_02_05 gkh + * Fixed buffer overflows bug with the generic serial driver. Thanks to + * Todd Squires for fixing this. + * + * (12/12/2000) gkh + * Removed MOD_INC and MOD_DEC from poll and disconnect functions, and + * moved them to the serial_open and serial_close functions. + * Also fixed bug with there not being a MOD_DEC for the generic driver + * (thanks to Gary Brubaker for finding this.) + * + * (12/29/2000) gkh + * Small NULL pointer initialization cleanup which saves a bit of disk image + * + * (10/05/2000) gkh + * Fixed bug with urb->dev not being set properly, now that the usb + * core needs it. * * (09/11/2000) gkh * Removed DEBUG #ifdefs with call to usb_serial_debug_data @@ -239,9 +256,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -327,7 +344,7 @@ static struct tty_struct * serial_tty[SERIAL_TTY_MINORS]; static struct termios * serial_termios[SERIAL_TTY_MINORS]; static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; -static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, }; +static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ LIST_HEAD(usb_serial_driver_list); @@ -449,6 +466,8 @@ return -ENODEV; } + MOD_INC_USE_COUNT; + /* set up our port structure making the tty driver remember our port object, and us it */ portNumber = MINOR(tty->device) - serial->minor; port = &serial->port[portNumber]; @@ -486,6 +505,8 @@ } else { generic_close(port, filp); } + + MOD_DEC_USE_COUNT; } @@ -694,25 +715,40 @@ { struct usb_serial *serial = port->serial; unsigned long flags; + int result; if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; + MOD_INC_USE_COUNT; + dbg(__FUNCTION__ " - port %d", port->number); spin_lock_irqsave (&port->port_lock, flags); ++port->open_count; - MOD_INC_USE_COUNT; if (!port->active) { port->active = 1; + /* force low_latency on so that our tty_push actually forces the data through, + otherwise it is scheduled, and with high data rates (like with OHCI) data + can get lost. */ + port->tty->low_latency = 1; + /* if we have a bulk interrupt, start reading from it */ if (serial->num_bulk_in) { - /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + /* Start reading from the device */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + ((serial->type->read_bulk_callback) ? + serial->type->read_bulk_callback : + generic_read_bulk_callback), + port); + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } } @@ -745,6 +781,7 @@ } spin_unlock_irqrestore (&port->port_lock, flags); + MOD_DEC_USE_COUNT; } @@ -752,6 +789,7 @@ { struct usb_serial *serial = port->serial; unsigned long flags; + int result; dbg(__FUNCTION__ " - port %d", port->number); @@ -779,11 +817,19 @@ memcpy (port->write_urb->transfer_buffer, buf, count); } - /* send the data out the bulk port */ - port->write_urb->transfer_buffer_length = count; + /* set up our urb */ + FILL_BULK_URB(port->write_urb, serial->dev, + usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, count, + ((serial->type->write_bulk_callback) ? + serial->type->write_bulk_callback : + generic_write_bulk_callback), + port); - if (usb_submit_urb(port->write_urb)) { - dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed"); + /* send the data out the bulk port */ + result = usb_submit_urb(port->write_urb); + if (result) { + err(__FUNCTION__ " - failed submitting write urb, error %d", result); spin_unlock_irqrestore (&port->port_lock, flags); return 0; } @@ -836,6 +882,7 @@ struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; + int result; dbg(__FUNCTION__ " - port %d", port->number); @@ -854,16 +901,27 @@ tty = port->tty; if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { - tty_insert_flip_char(tty, data[i], 0); - } + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* this doesn't actually push the data through unless tty->low_latency is set */ + tty_insert_flip_char(tty, data[i], 0); + } tty_flip_buffer_push(tty); } /* Continue trying to always read */ - if (usb_submit_urb(urb)) - dbg(__FUNCTION__ " - failed resubmitting read urb"); - - return; + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + ((serial->type->read_bulk_callback) ? + serial->type->read_bulk_callback : + generic_read_bulk_callback), + port); + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } @@ -1024,7 +1082,6 @@ } /* found all that we need */ - MOD_INC_USE_COUNT; info("%s converter detected", type->name); #ifdef CONFIG_USB_SERIAL_GENERIC @@ -1032,7 +1089,6 @@ num_ports = num_bulk_out; if (num_ports == 0) { err("Generic device with no bulk out, not allowed."); - MOD_DEC_USE_COUNT; return NULL; } } else @@ -1042,7 +1098,6 @@ serial = get_free_serial (num_ports, &minor); if (serial == NULL) { err("No more free serial devices"); - MOD_DEC_USE_COUNT; return NULL; } @@ -1072,6 +1127,7 @@ goto probe_error; } buffer_size = endpoint->wMaxPacketSize; + port->bulk_in_endpointAddress = endpoint->bEndpointAddress; port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->bulk_in_buffer) { err("Couldn't allocate bulk_in_buffer"); @@ -1120,6 +1176,7 @@ goto probe_error; } buffer_size = endpoint->wMaxPacketSize; + port->interrupt_in_endpointAddress = endpoint->bEndpointAddress; port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->interrupt_in_buffer) { err("Couldn't allocate interrupt_in_buffer"); @@ -1137,6 +1194,7 @@ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = MAX(num_bulk_in, num_bulk_out); max_endpoints = MAX(max_endpoints, num_interrupt_in); + dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = &serial->port[i]; port->number = i + serial->minor; @@ -1185,7 +1243,6 @@ /* free up any memory that we allocated */ kfree (serial); - MOD_DEC_USE_COUNT; return NULL; } @@ -1252,14 +1309,13 @@ info("device disconnected"); } - MOD_DEC_USE_COUNT; } static struct tty_driver serial_tty_driver = { magic: TTY_DRIVER_MAGIC, driver_name: "usb-serial", - name: "usb/tts/%d", + name: "ttyUSB", major: SERIAL_TTY_MAJOR, minor_start: 0, num: SERIAL_TTY_MINORS, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.2.18/drivers/usb/serial/visor.c Sun Mar 25 11:28:32 2001 +++ linux/drivers/usb/serial/visor.c Sun Mar 25 11:37:37 2001 @@ -10,11 +10,26 @@ * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * (01/21/2000) gkh + * Added write_room and chars_in_buffer, as they were previously using the + * generic driver versions which is all wrong now that we are using an urb + * pool. Thanks to Wolfgang Grandegger for pointing this out to me. + * Removed count assignment in the write function, which was not needed anymore + * either. Thanks to Al Borchers for pointing this out. + * + * (12/12/2000) gkh + * Moved MOD_DEC to end of visor_close to be nicer, as the final write + * message can sleep. * * (11/12/2000) gkh * Fixed bug with data being dropped on the floor by forcing tty->low_latency * to be on. This fixes the OHCI issue! * + * (10/05/2000) gkh + * Fixed bug with urb->dev not being set properly, now that the usb + * core needs it. + * * (09/11/2000) gkh * Got rid of always calling kmalloc for every urb we wrote out to the * device. @@ -69,9 +84,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -92,6 +107,8 @@ static int visor_open (struct usb_serial_port *port, struct file *filp); static void visor_close (struct usb_serial_port *port, struct file *filp); static int visor_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static int visor_write_room (struct usb_serial_port *port); +static int visor_chars_in_buffer (struct usb_serial_port *port); static void visor_throttle (struct usb_serial_port *port); static void visor_unthrottle (struct usb_serial_port *port); static int visor_startup (struct usb_serial *serial); @@ -124,6 +141,8 @@ ioctl: visor_ioctl, set_termios: visor_set_termios, write: visor_write, + write_room: visor_write_room, + chars_in_buffer: visor_chars_in_buffer, write_bulk_callback: visor_write_bulk_callback, read_bulk_callback: visor_read_bulk_callback, }; @@ -142,7 +161,9 @@ ******************************************************************************/ static int visor_open (struct usb_serial_port *port, struct file *filp) { + struct usb_serial *serial = port->serial; unsigned long flags; + int result; if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; @@ -160,13 +181,18 @@ bytes_out = 0; /* force low_latency on so that our tty_push actually forces the data through, - otherwise it is scheduled, and with high data rates (like with OHCI) data - can get lost. */ + otherwise it is scheduled, and with high data rates (like with OHCI) data + can get lost. */ port->tty->low_latency = 1; - - /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + + /* Start reading from the device */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + visor_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", result); } spin_unlock_irqrestore (&port->port_lock, flags); @@ -193,7 +219,6 @@ spin_lock_irqsave (&port->port_lock, flags); --port->open_count; - MOD_DEC_USE_COUNT; if (port->open_count <= 0) { transfer_buffer = kmalloc (0x12, GFP_KERNEL); @@ -216,6 +241,8 @@ /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ + + MOD_DEC_USE_COUNT; } @@ -263,8 +290,6 @@ else memcpy (urb->transfer_buffer, current_position, transfer_size); - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - /* build up our urb */ FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port); @@ -286,6 +311,52 @@ } +static int visor_write_room (struct usb_serial_port *port) +{ + unsigned long flags; + int i; + int room = 0; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]->status != -EINPROGRESS) { + room += URB_TRANSFER_BUFFER_SIZE; + } + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + dbg(__FUNCTION__ " - returns %d", room); + return (room); +} + + +static int visor_chars_in_buffer (struct usb_serial_port *port) +{ + unsigned long flags; + int i; + int chars = 0; + + dbg(__FUNCTION__ " - port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]->status == -EINPROGRESS) { + chars += URB_TRANSFER_BUFFER_SIZE; + } + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + dbg (__FUNCTION__ " - returns %d", chars); + return (chars); +} + + static void visor_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -310,15 +381,22 @@ static void visor_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; + int result; if (port_paranoia_check (port, __FUNCTION__)) return; dbg(__FUNCTION__ " - port %d", port->number); + if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); + return; + } + if (urb->status) { dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); return; @@ -341,8 +419,13 @@ } /* Continue trying to always read */ - if (usb_submit_urb(urb)) - dbg(__FUNCTION__ " - failed resubmitting read urb"); + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + visor_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; } @@ -366,13 +449,16 @@ static void visor_unthrottle (struct usb_serial_port *port) { unsigned long flags; + int result; dbg(__FUNCTION__ " - port %d", port->number); spin_lock_irqsave (&port->port_lock, flags); - if (usb_submit_urb (port->read_urb)) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + port->read_urb->dev = port->serial->dev; + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", result); spin_unlock_irqrestore (&port->port_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.2.18/drivers/usb/usb.c Sun Mar 25 11:28:33 2001 +++ linux/drivers/usb/usb.c Sun Mar 25 11:37:37 2001 @@ -187,6 +187,19 @@ return NULL; } +struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) +{ + int i, j, k; + + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) + for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++) + for (k = 0; k < dev->actconfig->interface[i].altsetting[j].bNumEndpoints; k++) + if (epnum == dev->actconfig->interface[i].altsetting[j].endpoint[k].bEndpointAddress) + return &dev->actconfig->interface[i].altsetting[j].endpoint[k]; + + return NULL; +} + /* * usb_calc_bus_time: * @@ -283,11 +296,13 @@ else dev->bus->bandwidth_int_reqs++; urb->bandwidth = bustime; - - dbg("bw_alloc increased by %d to %d for %d requesters", + +#ifdef USB_BANDWIDTH_MESSAGES + dbg("bandwidth alloc increased by %d to %d for %d requesters", bustime, dev->bus->bandwidth_allocated, dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif } /* @@ -303,10 +318,12 @@ else dev->bus->bandwidth_int_reqs--; - dbg("bw_alloc reduced by %d to %d for %d requesters", +#ifdef USB_BANDWIDTH_MESSAGES + dbg("bandwidth alloc reduced by %d to %d for %d requesters", urb->bandwidth, dev->bus->bandwidth_allocated, dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif urb->bandwidth = 0; } @@ -484,12 +501,17 @@ tmp = tmp->next; down(&driver->serialize); + if (usb_interface_claimed(interface)) { + up(&driver->serialize); + return -1; + } private = driver->probe(dev, ifnum); - up(&driver->serialize); - if (!private) + if (!private) { + up(&driver->serialize); continue; + } usb_driver_claim_interface(driver, interface, private); - + up(&driver->serialize); return 0; } @@ -737,7 +759,7 @@ dbg("unhandled interfaces on device"); if (!claimed) { - warn("USB device %d (prod/vend 0x%x/0x%x) is not claimed by any active driver.", + warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.", dev->devnum, dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -2037,6 +2059,7 @@ * then these symbols need to be exported for the modules to use. */ EXPORT_SYMBOL(usb_ifnum_to_if); +EXPORT_SYMBOL(usb_epnum_to_ep_desc); EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/video/Config.in linux/drivers/video/Config.in --- v2.2.18/drivers/video/Config.in Sun Mar 25 11:28:33 2001 +++ linux/drivers/video/Config.in Sun Mar 25 11:37:37 2001 @@ -50,7 +50,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then bool 'Atari native chipset support' CONFIG_FB_ATARI fi - if [ "$CONFIG_ATARI" = "y" -o "$CONFIG_PCI" != "n" ]; then + if [ "$CONFIG_ATARI" = "y" -o "$CONFIG_PCI" = "y" ]; then tristate 'ATI Mach64 display support' CONFIG_FB_ATY fi if [ "$CONFIG_PPC" = "y" ]; then @@ -86,7 +86,7 @@ define_bool CONFIG_BUS_I2C y fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_PCI" != "n" -a "$ARCH" != "sparc" -a "$ARCH" != "sparc64" ]; then + if [ "$CONFIG_PCI" = "y" -a "$ARCH" != "sparc" -a "$ARCH" != "sparc64" ]; then tristate 'Matrox acceleration' CONFIG_FB_MATROX if [ "$CONFIG_FB_MATROX" != "n" ]; then bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM @@ -114,7 +114,7 @@ fi fi if [ "$ARCH" = "sparc" ]; then - if [ "$CONFIG_PCI" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then bool 'PCI framebuffers' CONFIG_FB_PCI if [ "$CONFIG_FB_PCI" != "n" ]; then bool ' IGA 168x display support' CONFIG_FB_IGA @@ -188,7 +188,8 @@ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ - "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then + "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ + "$CONFIG_FB_ATY128" = "y" ]; then define_bool CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -202,14 +203,15 @@ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ + "$CONFIG_FB_ATY128" = "m" ]; then define_bool CONFIG_FBCON_CFB8 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ - "$CONFIG_FB_Q40" = "y" -o \ + "$CONFIG_FB_Q40" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ @@ -221,7 +223,7 @@ if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ - "$CONFIG_FB_Q40" = "m" -o \ + "$CONFIG_FB_Q40" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ @@ -234,13 +236,13 @@ if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ - "$CONFIG_FB_CYBER2000" = "y" ]; then + "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_ATY128" = "y" ]; then define_bool CONFIG_FBCON_CFB24 y else if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_CYBER2000" = "m" ]; then + "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_ATY128" = "m" ]; then define_bool CONFIG_FBCON_CFB24 m fi fi @@ -249,7 +251,8 @@ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ - "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" ]; then + "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_ATY128" = "y" ]; then define_bool CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -257,7 +260,7 @@ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" ]; then + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_ATY128" = "m" ]; then define_bool CONFIG_FBCON_CFB32 m fi fi diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/video/Makefile linux/drivers/video/Makefile --- v2.2.18/drivers/video/Makefile Sun Mar 25 11:28:33 2001 +++ linux/drivers/video/Makefile Sun Mar 25 11:37:37 2001 @@ -106,6 +106,10 @@ ifeq ($(CONFIG_FB_ATY128),y) L_OBJS += aty128fb.o +else + ifeq ($(CONFIG_FB_ATY128),m) + M_OBJS += aty128fb.o + endif endif ifeq ($(CONFIG_FB_IGA),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.2.18/drivers/video/aty128fb.c Sun Mar 25 11:28:33 2001 +++ linux/drivers/video/aty128fb.c Sun Mar 25 11:37:37 2001 @@ -262,7 +262,6 @@ int chip_gen; struct aty128fb_par default_par, current_par; struct display disp; - struct display_switch dispsw; /* for cursor and font */ struct { u8 red, green, blue, pad; } palette[256]; #ifdef CONFIG_PMAC_PBOOK unsigned char *save_framebuffer; @@ -1436,29 +1435,25 @@ switch (bpp) { #ifdef FBCON_HAS_CFB8 case 8: - info->dispsw = accel ? fbcon_aty128_8 : fbcon_cfb8; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8; break; #endif #ifdef FBCON_HAS_CFB16 case 15: case 16: - info->dispsw = accel ? fbcon_aty128_16 : fbcon_cfb16; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16; disp->dispsw_data = info->fbcon_cmap.cfb16; break; #endif #ifdef FBCON_HAS_CFB24 case 24: - info->dispsw = accel ? fbcon_aty128_24 : fbcon_cfb24; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24; disp->dispsw_data = info->fbcon_cmap.cfb24; break; #endif #ifdef FBCON_HAS_CFB32 case 32: - info->dispsw = accel ? fbcon_aty128_32 : fbcon_cfb32; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32; disp->dispsw_data = info->fbcon_cmap.cfb32; break; #endif @@ -1752,18 +1747,17 @@ memset(&var, 0, sizeof(var)); #ifdef CONFIG_FB_OF - if (default_vmode == VMODE_CHOOSE) { -#endif /* CONFIG_FB_OF */ + /* New iBook */ + if (default_vmode == VMODE_CHOOSE && + machine_is_compatible("PowerBook2,2")) + default_vmode = VMODE_800_600_60; + + if (default_vmode == VMODE_CHOOSE) + var = default_var; + else if (mac_vmode_to_var(default_vmode, default_cmode, &var)) + var = default_var; +#else /* CONFIG_FB_OF */ var = default_var; - -#ifdef CONFIG_FB_OF - /* New iBook */ - if (machine_is_compatible("PowerBook2,2")) - default_vmode = VMODE_800_600_60; - } else { - if (mac_vmode_to_var(default_vmode, default_cmode, &var)) - var = default_var; - } #endif /* CONFIG_FB_OF */ #endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/video/mdacon.c linux/drivers/video/mdacon.c --- v2.2.18/drivers/video/mdacon.c Sun Mar 25 11:13:10 2001 +++ linux/drivers/video/mdacon.c Sun Mar 25 11:37:38 2001 @@ -75,14 +75,10 @@ static struct vc_data *mda_display_fg = NULL; -#ifdef MODULE_PARM MODULE_PARM(mda_first_vc, "1-255i"); MODULE_PARM(mda_last_vc, "1-255i"); -#endif - -/* MDA register values - */ +/* MDA register values */ #define MDA_CURSOR_BLINKING 0x00 #define MDA_CURSOR_OFF 0x20 @@ -200,11 +196,7 @@ } #endif -#ifdef MODULE -static int mda_detect(void) -#else __initfunc(static int mda_detect(void)) -#endif { int count=0; u16 *p, p_save; @@ -287,11 +279,7 @@ return 1; } -#ifdef MODULE -static void mda_initialize(void) -#else __initfunc(static void mda_initialize(void)) -#endif { write_mda_b(97, 0x00); /* horizontal total */ write_mda_b(80, 0x01); /* horizontal displayed */ @@ -316,11 +304,7 @@ outb_p(0x00, mda_gfx_port); } -#ifdef MODULE -static const char *mdacon_startup(void) -#else __initfunc(static const char *mdacon_startup(void)) -#endif { mda_num_columns = 80; mda_num_lines = 25; @@ -606,11 +590,7 @@ mdacon_invert_region, /* con_invert_region */ }; -#ifdef MODULE -void mda_console_init(void) -#else __initfunc(void mda_console_init(void)) -#endif { if (mda_first_vc > mda_last_vc) return; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/video/promcon.c linux/drivers/video/promcon.c --- v2.2.18/drivers/video/promcon.c Sun Mar 25 11:13:09 2001 +++ linux/drivers/video/promcon.c Sun Mar 25 11:37:38 2001 @@ -1,4 +1,4 @@ -/* $Id: promcon.c,v 1.15 1999/04/22 06:35:32 davem Exp $ +/* $Id: promcon.c,v 1.14 1999/03/09 14:02:42 davem Exp $ * Console driver utilizing PROM sun terminal emulation * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/video/tgafb.c linux/drivers/video/tgafb.c --- v2.2.18/drivers/video/tgafb.c Sun Mar 25 11:13:09 2001 +++ linux/drivers/video/tgafb.c Sun Mar 25 11:37:38 2001 @@ -59,7 +59,7 @@ static int current_par_valid = 0; static struct display disp; -static char __initdata default_fontname[40] = { 0 }; +static char default_fontname[40] __initdata = { 0 }; static struct fb_var_screeninfo default_var; static int default_var_valid = 0; @@ -1083,6 +1083,11 @@ fb_info.gen.info.modename); } + /* + * Modularisation + */ + +#ifdef MODULE /* * Cleanup @@ -1093,12 +1098,6 @@ unregister_framebuffer(info); } - - /* - * Modularisation - */ - -#ifdef MODULE int init_module(void) { tgafb_init(); @@ -1107,7 +1106,7 @@ void cleanup_module(void) { - tgafb_cleanup(void); + tgafb_cleanup(&fb_info.gen.info); } #endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/Config.in linux/fs/Config.in --- v2.2.18/fs/Config.in Sun Mar 25 11:28:33 2001 +++ linux/fs/Config.in Sun Mar 25 11:37:38 2001 @@ -76,9 +76,11 @@ bool ' Root file system on NFS' CONFIG_ROOT_NFS fi tristate 'NFS server support' CONFIG_NFSD - if [ "$CONFIG_NFSD" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' NFS Version 3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3 - bool ' NFS server TCP support (VERY EXPERIMENTAL)' CONFIG_NFSD_TCP + if [ "$CONFIG_NFSD" != "n" ]; then + bool ' NFS Version 3 server support' CONFIG_NFSD_V3 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' NFS server TCP support (VERY EXPERIMENTAL)' CONFIG_NFSD_TCP + fi fi if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_bool CONFIG_SUNRPC y @@ -115,6 +117,7 @@ bool 'BSD disklabel (BSD partition tables) support' CONFIG_BSD_DISKLABEL bool 'Macintosh partition map support' CONFIG_MAC_PARTITION +bool 'Minix subpartition support' CONFIG_MINIX_SUBPARTITION bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL bool 'Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v2.2.18/fs/binfmt_aout.c Sun Mar 25 11:12:32 2001 +++ linux/fs/binfmt_aout.c Sun Mar 25 11:37:38 2001 @@ -62,9 +62,9 @@ static int dump_write(struct file *file, const void *addr, int nr) { int r; - down(&file->f_dentry->d_inode->i_sem); + fs_down(&file->f_dentry->d_inode->i_sem); r = file->f_op->write(file, addr, nr, &file->f_pos) == nr; - up(&file->f_dentry->d_inode->i_sem); + fs_up(&file->f_dentry->d_inode->i_sem); return r; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.2.18/fs/binfmt_elf.c Sun Mar 25 11:28:33 2001 +++ linux/fs/binfmt_elf.c Sun Mar 25 11:37:38 2001 @@ -113,6 +113,7 @@ char *k_platform, *u_platform; long hwcap; size_t platform_len = 0; + long len; /* * Get hold of platform and hardware capabilities masks for @@ -191,13 +192,21 @@ current->mm->arg_start = (unsigned long) p; while (argc-->0) { __put_user((elf_caddr_t)(unsigned long)p,argv++); - p += strlen_user(p); + len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); + /* "can't happen" */ + if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) + return NULL; + p += len; } __put_user(NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { __put_user((elf_caddr_t)(unsigned long)p,envp++); - p += strlen_user(p); + len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); + /* "can't happen" */ + if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) + return NULL; + p += len; } __put_user(NULL, envp); current->mm->env_end = (unsigned long) p; @@ -706,7 +715,7 @@ elf_interpreter); kfree(elf_interpreter); kfree(elf_phdata); - send_sig(SIGSEGV, current, 0); + force_sig(SIGSEGV, current); return 0; } @@ -729,9 +738,6 @@ if (current->binfmt && current->binfmt->module) __MOD_INC_USE_COUNT(current->binfmt->module); -#ifndef VM_STACK_FLAGS - current->executable = dget(bprm->dentry); -#endif compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; bprm->p = (unsigned long) @@ -742,6 +748,10 @@ load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); + if (!bprm->p) { + force_sig(SIGSEGV, current); + return 0; + } /* N.B. passed_fileno might not be initialized? */ if (interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; @@ -948,9 +958,9 @@ static int dump_write(struct file *file, const void *addr, int nr) { int r; - down(&file->f_dentry->d_inode->i_sem); + fs_down(&file->f_dentry->d_inode->i_sem); r = file->f_op->write(file, addr, nr, &file->f_pos) == nr; - up(&file->f_dentry->d_inode->i_sem); + fs_up(&file->f_dentry->d_inode->i_sem); return r; } @@ -1056,7 +1066,7 @@ #undef DUMP_SEEK #define DUMP_WRITE(addr, nr) \ - if (!dump_write(file, (addr), (nr))) \ + if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ goto close_coredump; #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ @@ -1078,7 +1088,7 @@ char corefile[6+sizeof(current->comm)]; int segs; int i; - size_t size; + size_t size = 0; struct vm_area_struct *vma; struct elfhdr elf; off_t offset = 0, dataoff; @@ -1099,24 +1109,10 @@ MOD_INC_USE_COUNT; #endif - /* Count what's needed to dump, up to the limit of coredump size */ - segs = 0; - size = 0; - for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { - if (maydump(vma)) - { - unsigned long sz = vma->vm_end-vma->vm_start; - - if (size+sz >= limit) - break; - else - size += sz; - } + segs = current->mm->map_count; - segs++; - } #ifdef DEBUG - printk("elf_core_dump: %d segs taking %d bytes\n", segs, size); + printk("elf_core_dump: %d segs %lu limit\n", segs, limit); #endif /* Set up header */ @@ -1294,13 +1290,10 @@ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); /* Write program headers for segments dump */ - for(vma = current->mm->mmap, i = 0; - i < segs && vma != NULL; vma = vma->vm_next) { + for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; - i++; - sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; @@ -1326,19 +1319,36 @@ DUMP_SEEK(dataoff); - for(i = 0, vma = current->mm->mmap; - i < segs && vma != NULL; - vma = vma->vm_next) { - unsigned long addr = vma->vm_start; - unsigned long len = vma->vm_end - vma->vm_start; + for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + unsigned long addr; - i++; if (!maydump(vma)) continue; #ifdef DEBUG printk("elf_core_dump: writing %08lx %lx\n", addr, len); #endif - DUMP_WRITE((void *)addr, len); + for (addr = vma->vm_start; + addr < vma->vm_end; + addr += PAGE_SIZE) { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset(vma->vm_mm, addr); + pmd = pmd_alloc(pgd, addr); + + if (!pmd) + goto end_coredump; + pte = pte_alloc(pmd, addr); + if (!pte) + goto end_coredump; + if (!pte_present(*pte) && + pte_none(*pte)) { + DUMP_SEEK (file->f_pos + PAGE_SIZE); + } else { + DUMP_WRITE((void*)addr, PAGE_SIZE); + } + } } if ((off_t) file->f_pos != offset) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/binfmt_misc.c linux/fs/binfmt_misc.c --- v2.2.18/fs/binfmt_misc.c Sun Mar 25 11:28:33 2001 +++ linux/fs/binfmt_misc.c Sun Mar 25 11:37:38 2001 @@ -41,9 +41,11 @@ #error You really need /proc support for binfmt_misc. Please reconfigure! #endif -#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */ +enum { + VERBOSE_STATUS = 1 /* define as zero to save 400 bytes kernel memory */ +}; -struct binfmt_entry { +typedef struct binfmt_entry { struct binfmt_entry *next; long id; int flags; /* type, status, etc. */ @@ -52,16 +54,15 @@ char *magic; /* magic or filename extension */ char *mask; /* mask, NULL for exact match */ char *interpreter; /* filename of interpreter */ - char *proc_name; + char *name; struct proc_dir_entry *proc_dir; -}; +} Node; -#define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */ -#define ENTRY_MAGIC 8 /* not filename detection */ +enum { Enabled, Magic }; static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs); -static void entry_proc_cleanup(struct binfmt_entry *e); -static int entry_proc_setup(struct binfmt_entry *e); +static void entry_proc_cleanup(Node *e); +static int entry_proc_setup(Node *e); static struct linux_binfmt misc_format = { #ifndef MODULE @@ -73,7 +74,7 @@ static struct proc_dir_entry *bm_dir = NULL; -static struct binfmt_entry *entries = NULL; +static Node *entries = NULL; static int free_id = 1; static int enabled = 1; @@ -85,7 +86,7 @@ */ static void clear_entry(int id) { - struct binfmt_entry **ep, *e; + Node **ep, *e; write_lock(&entries_lock); ep = &entries; @@ -106,7 +107,7 @@ */ static void clear_entries(void) { - struct binfmt_entry *e, *n; + Node *e, *n; write_lock(&entries_lock); n = entries; @@ -123,9 +124,9 @@ /* * Find entry through id and lock it */ -static struct binfmt_entry *get_entry(int id) +static Node *get_entry(int id) { - struct binfmt_entry *e; + Node *e; read_lock(&entries_lock); e = entries; @@ -139,7 +140,7 @@ /* * unlock entry */ -static inline void put_entry(struct binfmt_entry *e) +static inline void put_entry(Node *e) { if (e) read_unlock(&entries_lock); @@ -148,19 +149,19 @@ /* * Check if we support the binfmt - * if we do, return the binfmt_entry, else NULL + * if we do, return the node, else NULL * locking is done in load_misc_binary */ -static struct binfmt_entry *check_file(struct linux_binprm *bprm) +static Node *check_file(struct linux_binprm *bprm) { - struct binfmt_entry *e; + Node *e; char *p = strrchr(bprm->filename, '.'); int j; e = entries; while (e) { - if (e->flags & ENTRY_ENABLED) { - if (!(e->flags & ENTRY_MAGIC)) { + if (test_bit(Enabled, &e->flags)) { + if (!test_bit(Magic, &e->flags)) { if (p && !strcmp(e->magic, p + 1)) return e; } else { @@ -183,7 +184,7 @@ */ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) { - struct binfmt_entry *fmt; + Node *fmt; struct dentry * dentry; char iname[128]; char *iname_addr = iname; @@ -233,46 +234,44 @@ return retval; } - - -/* - * /proc handling routines - */ - /* * parses and copies one argument enclosed in del from *sp to *dp, * recognising the \x special. * returns pointer to the copied argument or NULL in case of an * error (and sets err) or null argument length. */ -static char *copyarg(char **dp, const char **sp, int *count, - char del, int special, int *err) +static char *scanarg(char *s, char del) { - char c = 0, *res = *dp; + char c; - while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) { - switch (c) { - case '\\': - if (special && (**sp == 'x')) { - if (!isxdigit(c = toupper(*(++*sp)))) - *err = -EINVAL; - **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16; - if (!isxdigit(c = toupper(*(++*sp)))) - *err = -EINVAL; - *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10); - ++*sp; - *count -= 3; - break; - } - default: - *((*dp)++) = c; + while ((c = *s++) != del) { + if (c == '\\' && *s == 'x') { + s++; + if (!isxdigit(*s++)) + return NULL; + if (!isxdigit(*s++)) + return NULL; + } + } + return s; +} + +static int unquote(char *from) +{ + char c = 0, *s = from, *p = from; + + while ((c = *s++) != '\0') { + if (c == '\\' && *s == 'x') { + s++; + c = toupper(*s++); + *p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4; + c = toupper(*s++); + *p++ |= c - (isdigit(c) ? '0' : 'A' - 10); + continue; } + *p++ = c; } - if (*err || (c != del) || (res == *dp)) - res = NULL; - else if (!special) - *((*dp)++) = '\0'; - return res; + return p - from; } /* @@ -280,59 +279,197 @@ * ':name:type:offset:magic:mask:interpreter:' * where the ':' is the IFS, that can be chosen with the first char */ -static int proc_write_register(struct file *file, const char *buffer, - unsigned long count, void *data) +static Node *create_entry(const char *buffer, size_t count) { - const char *sp; - char del, *dp; - struct binfmt_entry *e; - int memsize, cnt = count - 1, err; + Node *e; + int memsize, err; + char *buf, *p; + char del; /* some sanity checks */ err = -EINVAL; if ((count < 11) || (count > 256)) - goto _err; + goto out; err = -ENOMEM; - memsize = sizeof(struct binfmt_entry) + count; - if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) - goto _err; - - err = 0; - sp = buffer + 1; - del = buffer[0]; - dp = (char *)e + sizeof(struct binfmt_entry); - - e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err); - - /* we can use bit 3 of type for ext/magic - flag due to the nice encoding of E and M */ - if ((*sp & ~('E' | 'M')) || (sp[1] != del)) - err = -EINVAL; - else - e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED)); - cnt -= 2; sp++; + memsize = sizeof(Node) + count + 8; + e = (Node *) kmalloc(memsize, GFP_USER); + if (!e) + goto out; - e->offset = 0; - while (cnt-- && isdigit(*sp)) - e->offset = e->offset * 10 + *sp++ - '0'; - if (*sp++ != del) - err = -EINVAL; - - e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err); - e->size = dp - e->magic; - e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err); - if (e->mask && ((dp - e->mask) != e->size)) - err = -EINVAL; - e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err); - e->id = free_id++; + p = buf = (char *)e + sizeof(Node); + + memset(e, 0, sizeof(Node)); + if (copy_from_user(buf, buffer, count)) + goto Efault; + + del = *p++; /* delimeter */ + + memset(buf+count, del, 8); + + e->name = p; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + if (!e->name[0] || + !strcmp(e->name, ".") || + !strcmp(e->name, "..") || + strchr(e->name, '/')) + goto Einval; + switch (*p++) { + case 'E': e->flags = 1<flags = (1<flags)) { + char *s = strchr(p, del); + if (!s) + goto Einval; + *s++ = '\0'; + e->offset = simple_strtoul(p, &p, 10); + if (*p++) + goto Einval; + e->magic = p; + p = scanarg(p, del); + if (!p) + goto Einval; + p[-1] = '\0'; + if (!e->magic[0]) + goto Einval; + e->mask = p; + p = scanarg(p, del); + if (!p) + goto Einval; + p[-1] = '\0'; + if (!e->mask[0]) + e->mask = NULL; + e->size = unquote(e->magic); + if (e->mask && unquote(e->mask) != e->size) + goto Einval; + if (e->size + e->offset > 128) + goto Einval; + } else { + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + e->magic = p; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + if (!e->magic[0] || strchr(e->magic, '/')) + goto Einval; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + } + e->interpreter = p; + p = strchr(p, del); + if (!p) + goto Einval; + *p++ = '\0'; + if (!e->interpreter[0]) + goto Einval; + + if (*p == '\n') + p++; + if (p != buf + count) + goto Einval; + return e; + +out: + return ERR_PTR(err); + +Efault: + kfree(e); + return ERR_PTR(-EFAULT); +Einval: + kfree(e); + return ERR_PTR(-EINVAL); +} + +/* + * Set status of entry/binfmt_misc: + * '1' enables, '0' disables and '-1' clears entry/binfmt_misc + */ +static int parse_command(const char *buffer, size_t count) +{ + char s[4]; + + if (!count) + return 0; + if (count > 3) + return -EINVAL; + if (copy_from_user(s, buffer, count)) + return -EFAULT; + if (s[count-1] == '\n') + count--; + if (count == 1 && s[0] == '0') + return 1; + if (count == 1 && s[0] == '1') + return 2; + if (count == 2 && s[0] == '-' && s[1] == '1') + return 3; + return -EINVAL; +} + +static void entry_status(Node *e, char *page) +{ + char *dp; + char *status = "disabled"; - /* more sanity checks */ - if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) || - (e->size < 1) || ((e->size + e->offset) > 127) || - !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e)) + if (test_bit(Enabled, &e->flags)) + status = "enabled"; + + if (!VERBOSE_STATUS) { + sprintf(page, "%s\n", status); + return; + } + + sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter); + dp = page + strlen(page); + if (!test_bit(Magic, &e->flags)) { + sprintf(dp, "extension .%s\n", e->magic); + } else { + int i; + + sprintf(dp, "offset %i\nmagic ", e->offset); + dp = page + strlen(page); + for (i = 0; i < e->size; i++) { + sprintf(dp, "%02x", 0xff & (int) (e->magic[i])); + dp += 2; + } + if (e->mask) { + sprintf(dp, "\nmask "); + dp += 6; + for (i = 0; i < e->size; i++) { + sprintf(dp, "%02x", 0xff & (int) (e->mask[i])); + dp += 2; + } + } + *dp++ = '\n'; + *dp = '\0'; + } +} + +static int proc_write_register(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + Node *e = create_entry(buffer, count); + int err; + + if (IS_ERR(e)) + return PTR_ERR(e); + + if (entry_proc_setup(e)) goto free_err; + e->id = free_id++; write_lock(&entries_lock); e->next = entries; entries = e; @@ -355,68 +492,24 @@ static int proc_read_status(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct binfmt_entry *e; - char *dp; - int elen, i, err; + Node *e; + int elen; -#ifndef VERBOSE_STATUS - if (data) { - if (!(e = get_entry((int) data))) { - err = -ENOENT; - goto _err; - } - i = e->flags & ENTRY_ENABLED; - put_entry(e); - } else { - i = enabled; - } - sprintf(page, "%s\n", (i ? "enabled" : "disabled")); -#else - if (!data) + if (!data) { sprintf(page, "%s\n", (enabled ? "enabled" : "disabled")); - else { - if (!(e = get_entry((long) data))) { - err = -ENOENT; - goto _err; - } - sprintf(page, "%s\ninterpreter %s\n", - (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"), - e->interpreter); - dp = page + strlen(page); - if (!(e->flags & ENTRY_MAGIC)) { - sprintf(dp, "extension .%s\n", e->magic); - dp = page + strlen(page); - } else { - sprintf(dp, "offset %i\nmagic ", e->offset); - dp = page + strlen(page); - for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->magic[i])); - dp += 2; - } - if (e->mask) { - sprintf(dp, "\nmask "); - dp += 6; - for (i = 0; i < e->size; i++) { - sprintf(dp, "%02x", 0xff & (int) (e->mask[i])); - dp += 2; - } - } - *dp++ = '\n'; - *dp = '\0'; - } + } else { + if (!(e = get_entry((long) data))) + return -ENOENT; + entry_status(e, page); put_entry(e); } -#endif elen = strlen(page) - off; if (elen < 0) elen = 0; *eof = (elen <= count) ? 1 : 0; *start = page + off; - err = elen; - -_err: - return err; + return elen; } /* @@ -426,45 +519,50 @@ static int proc_write_status(struct file *file, const char *buffer, unsigned long count, void *data) { - struct binfmt_entry *e; - int res = count; + Node *e; + int res = parse_command(buffer, count); - if (buffer[count-1] == '\n') - count--; - if ((count == 1) && !(buffer[0] & ~('0' | '1'))) { - if (data) { - if ((e = get_entry((long) data))) - e->flags = (e->flags & ~ENTRY_ENABLED) - | (int)(buffer[0] - '0'); - put_entry(e); - } else { - enabled = buffer[0] - '0'; - } - } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) { - if (data) - clear_entry((long) data); - else - clear_entries(); - } else { - res = -EINVAL; + switch(res) { + case 1: if (data) { + if ((e = get_entry((long) data))) + clear_bit(Enabled, &e->flags); + put_entry(e); + } else { + enabled = 0; + } + break; + case 2: if (data) { + if ((e = get_entry((long) data))) + set_bit(Enabled, &e->flags); + put_entry(e); + } else { + enabled = 1; + } + break; + case 3: if (data) + clear_entry((long) data); + else + clear_entries(); + break; + default: return res; } - return res; + return count; } /* * Remove the /proc-dir entries of one binfmt */ -static void entry_proc_cleanup(struct binfmt_entry *e) +static void entry_proc_cleanup(Node *e) { - remove_proc_entry(e->proc_name, bm_dir); + remove_proc_entry(e->name, bm_dir); } /* * Create the /proc-dir entry for binfmt */ -static int entry_proc_setup(struct binfmt_entry *e) +static int entry_proc_setup(Node *e) { - if (!(e->proc_dir = create_proc_entry(e->proc_name, + if (!(e->proc_dir = create_proc_entry(e->name, S_IFREG | S_IRUGO | S_IWUSR, bm_dir))) { printk(KERN_WARNING "Unable to create /proc entry.\n"); @@ -545,4 +643,3 @@ remove_proc_entry("sys/fs/binfmt_misc", NULL); } #endif -#undef VERBOSE_STATUS diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/buffer.c linux/fs/buffer.c --- v2.2.18/fs/buffer.c Sun Mar 25 11:28:33 2001 +++ linux/fs/buffer.c Sun Mar 25 11:37:38 2001 @@ -83,6 +83,7 @@ static int nr_buffers = 0; static int nr_buffers_type[NR_LIST] = {0,}; +static unsigned long size_buffers_type[NR_LIST]; static int nr_buffer_heads = 0; static int nr_unused_buffer_heads = 0; static int nr_hashed_buffers = 0; @@ -359,9 +360,9 @@ goto out_putf; /* We need to protect against concurrent writers.. */ - down(&inode->i_sem); + fs_down(&inode->i_sem); err = file->f_op->fsync(file, dentry); - up(&inode->i_sem); + fs_up(&inode->i_sem); out_putf: fput(file); @@ -396,9 +397,9 @@ goto out_putf; /* this needs further work, at the moment it is identical to fsync() */ - down(&inode->i_sem); + fs_down(&inode->i_sem); err = file->f_op->fsync(file, dentry); - up(&inode->i_sem); + fs_up(&inode->i_sem); out_putf: fput(file); @@ -474,6 +475,7 @@ return; } nr_buffers_type[bh->b_list]--; + size_buffers_type[bh->b_list] -= bh->b_size; remove_from_hash_queue(bh); remove_from_lru_list(bh); } @@ -523,6 +525,7 @@ (*bhp)->b_prev_free = bh; nr_buffers_type[bh->b_list]++; + size_buffers_type[bh->b_list] += bh->b_size; /* Put the buffer in new hash-queue if it has a device. */ bh->b_next = NULL; @@ -571,8 +574,10 @@ { struct buffer_head * bh; bh = find_buffer(dev,block,size); - if (bh) + if (bh) { bh->b_count++; + touch_buffer(bh); + } return bh; } @@ -816,6 +821,46 @@ insert_into_queues(bh); } +/* -1 -> no need to flush + 0 -> async flush + 1 -> sync flush (wait for I/O completation) */ +static int balance_dirty_state(kdev_t dev) +{ + unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit; + + dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT; + tot = (buffermem >> PAGE_SHIFT) + nr_free_pages; + tot -= size_buffers_type[BUF_PROTECTED] >> PAGE_SHIFT; + + dirty *= 200; + soft_dirty_limit = tot * bdf_prm.b_un.nfract; + hard_dirty_limit = soft_dirty_limit * 2; + + if (dirty > soft_dirty_limit) + { + if (dirty > hard_dirty_limit) + return 1; + return 0; + } + return -1; +} + +/* + * if a new dirty buffer is created we need to balance bdflush. + * + * in the future we might want to make bdflush aware of different + * pressures on different devices - thus the (currently unused) + * 'dev' parameter. + */ +void balance_dirty(kdev_t dev) +{ + int state = balance_dirty_state(dev); + + if (state < 0) + return; + wakeup_bdflush(state); +} + /* * A buffer may need to be moved from one buffer list to another * (e.g. in case it is not shared any more). Handle this. @@ -828,7 +873,9 @@ printk("Attempt to refile free buffer\n"); return; } - if (buffer_dirty(buf)) + if (buffer_protected(buf)) + dispose = BUF_PROTECTED; + else if (buffer_dirty(buf)) dispose = BUF_DIRTY; else if (buffer_locked(buf)) dispose = BUF_LOCKED; @@ -837,13 +884,7 @@ if(dispose != buf->b_list) { file_buffer(buf, dispose); if(dispose == BUF_DIRTY) { - int too_many = (nr_buffers * bdf_prm.b_un.nfract/100); - - /* This buffer is dirty, maybe we need to start flushing. - * If too high a percentage of the buffers are dirty... - */ - if (nr_buffers_type[BUF_DIRTY] > too_many) - wakeup_bdflush(1); + balance_dirty(buf->b_dev); /* If this is a loop device, and * more than half of the buffers are dirty... @@ -864,7 +905,6 @@ /* If dirty, mark the time this buffer should be written back. */ set_writetime(buf, 0); refile_buffer(buf); - touch_buffer(buf); if (buf->b_count) { buf->b_count--; @@ -1457,6 +1497,7 @@ } tmp->b_this_page = bh; free_list[isize] = bh; + mem_map[MAP_NR(page)].flags = 0; mem_map[MAP_NR(page)].buffers = bh; buffermem += PAGE_SIZE; return 1; @@ -1468,33 +1509,34 @@ #define BUFFER_BUSY_BITS ((1<b_count || ((bh)->b_state & BUFFER_BUSY_BITS)) -static int sync_page_buffers(struct page * page, int wait) +static void sync_page_buffers(struct page * page) { - struct buffer_head * bh = page->buffers; - struct buffer_head * tmp = bh; + struct buffer_head * tmp, * bh = page->buffers; + /* + * Here we'll probably sleep and so we must make sure that + * the page doesn't go away from under us. We also prefer any + * concurrent try_to_free_buffers() not to work in any way on + * our current page from under us since we're just working on it. + * As always in 2.2.x we're serialized by the big kernel lock + * during those hacky page-visibility manipulations. + * + * SUBTLE NOTE: for things like LVM snapshotting WRITEA will block too! + */ page->buffers = NULL; + tmp = bh; do { struct buffer_head *p = tmp; tmp = tmp->b_this_page; - if (buffer_locked(p)) { - if (wait) - __wait_on_buffer(p); - } else if (buffer_dirty(p)) - ll_rw_block(WRITE, 1, &p); - } while (tmp != bh); - - page->buffers = bh; - do { - struct buffer_head *p = tmp; - tmp = tmp->b_this_page; - if (buffer_busy(p)) - return 1; + if (buffer_dirty(p)) + if (test_and_set_bit(BH_Wait_IO, &p->b_state)) + ll_rw_block(WRITE, 1, &p); } while (tmp != bh); - return 0; + /* Restore the visibility of the page before returning. */ + page->buffers = bh; } /* @@ -1504,10 +1546,9 @@ * Wake up bdflush() if this fails - if we're running low on memory due * to dirty buffers, we need to flush them out as quickly as possible. */ -int try_to_free_buffers(struct page * page_map, int wait) +int try_to_free_buffers(struct page * page_map, int gfp_mask) { struct buffer_head * tmp, * bh = page_map->buffers; - int too_many; tmp = bh; do { @@ -1516,8 +1557,6 @@ tmp = tmp->b_this_page; } while (tmp != bh); - succeed: - tmp = bh; do { struct buffer_head * p = tmp; tmp = tmp->b_this_page; @@ -1536,25 +1575,12 @@ return 1; busy: - too_many = (nr_buffers * bdf_prm.b_un.nfract/100); - - if (!sync_page_buffers(page_map, wait)) { - - /* If a high percentage of the buffers are dirty, - * wake kflushd - */ - if (nr_buffers_type[BUF_DIRTY] > too_many) - wakeup_bdflush(0); - - /* - * We can jump after the busy check because - * we rely on the kernel lock. - */ - goto succeed; - } + if (gfp_mask & __GFP_IO) + sync_page_buffers(page_map); - if(nr_buffers_type[BUF_DIRTY] > too_many) + if (balance_dirty_state(NODEV) >= 0) wakeup_bdflush(0); + return 0; } @@ -1566,7 +1592,7 @@ int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0; int protected = 0; int nlist; - static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"}; + static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY","PROTECTED",}; printk("Buffer memory: %8ldkB\n",buffermem>>10); printk("Buffer heads: %6d\n",nr_buffer_heads); @@ -1590,7 +1616,7 @@ used++, lastused = found; bh = bh->b_next_free; } while (bh != lru_list[nlist]); - printk("%8s: %d buffers, %d used (last=%d), " + printk("%9s: %d buffers, %d used (last=%d), " "%d locked, %d protected, %d dirty\n", buf_types[nlist], found, used, lastused, locked, protected, dirty); @@ -1935,7 +1961,8 @@ /* If there are still a lot of dirty buffers around, skip the sleep and flush some more */ - if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) { + if (!ndirty || balance_dirty_state(NODEV) < 0) + { spin_lock_irq(¤t->sigmask_lock); flush_signals(current); spin_unlock_irq(¤t->sigmask_lock); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/coda/file.c linux/fs/coda/file.c --- v2.2.18/fs/coda/file.c Sun Mar 25 11:12:35 2001 +++ linux/fs/coda/file.c Sun Mar 25 11:37:38 2001 @@ -190,10 +190,10 @@ return -1; } - down(&cont_inode->i_sem); + fs_down(&cont_inode->i_sem); result = cont_file.f_op->write(&cont_file , buff, count, &(cont_file.f_pos)); - up(&cont_inode->i_sem); + fs_up(&cont_inode->i_sem); coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file); if (result) @@ -228,14 +228,14 @@ coda_prepare_openfile(coda_inode, coda_file, cont_inode, &cont_file, &cont_dentry); - down(&cont_inode->i_sem); + fs_down(&cont_inode->i_sem); result = file_fsync(&cont_file ,&cont_dentry); if ( result == 0 ) { result = venus_fsync(coda_inode->i_sb, &(cnp->c_fid)); } - up(&cont_inode->i_sem); + fs_up(&cont_inode->i_sem); coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file); return result; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/dcache.c linux/fs/dcache.c --- v2.2.18/fs/dcache.c Sun Mar 25 11:12:32 2001 +++ linux/fs/dcache.c Sun Mar 25 11:37:38 2001 @@ -253,10 +253,15 @@ if (tmp == &dentry_unused) break; - dentry_stat.nr_unused--; list_del(tmp); - INIT_LIST_HEAD(tmp); dentry = list_entry(tmp, struct dentry, d_lru); + if (dentry->d_flags & DCACHE_REFERENCED) { + dentry->d_flags &= ~DCACHE_REFERENCED; + list_add(&dentry->d_lru, &dentry_unused); + continue; + } + dentry_stat.nr_unused--; + INIT_LIST_HEAD(tmp); if (!dentry->d_count) { i_nr -= prune_one_dentry(dentry); if (!i_nr) @@ -475,9 +480,9 @@ */ void shrink_dcache_memory(int priority, unsigned int gfp_mask) { - if (gfp_mask & __GFP_IO) { + if (gfp_mask & __GFP_IO && !current->fs_locks) { int count = 0; - if (priority) + if (priority > 1) count = dentry_stat.nr_unused / priority; prune_dcache(count, -1); } @@ -568,7 +573,7 @@ static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash) { hash += (unsigned long) parent / L1_CACHE_BYTES; - hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2); + hash = hash ^ (hash >> D_HASHBITS); return dentry_hashtable + (hash & D_HASHMASK); } @@ -598,6 +603,7 @@ if (memcmp(dentry->d_name.name, str, len)) continue; } + dentry->d_flags |= DCACHE_REFERENCED; return dget(dentry); } return NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/dquot.c linux/fs/dquot.c --- v2.2.18/fs/dquot.c Sun Mar 25 11:28:33 2001 +++ linux/fs/dquot.c Sun Mar 25 11:37:38 2001 @@ -570,7 +570,7 @@ */ if (prune_dcache(0, 128)) { - free_inode_memory(10); + free_inode_memory(); goto repeat; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/exec.c linux/fs/exec.c --- v2.2.18/fs/exec.c Sun Mar 25 11:28:33 2001 +++ linux/fs/exec.c Sun Mar 25 11:37:38 2001 @@ -517,8 +517,9 @@ current->sas_ss_sp = current->sas_ss_size = 0; + bprm->dumpable = 0; if (current->euid == current->uid && current->egid == current->gid) - current->dumpable = 1; + bprm->dumpable = !bprm->priv_change; name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -531,10 +532,10 @@ flush_thread(); - if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || - permission(bprm->dentry->d_inode,MAY_READ)) - current->dumpable = 0; - + if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || + permission(bprm->dentry->d_inode, MAY_READ)) + bprm->dumpable = 0; + current->self_exec_id++; flush_signal_handlers(current); @@ -646,7 +647,8 @@ } } - if (id_change || cap_raised) { + bprm->priv_change = id_change || cap_raised; + if (bprm->priv_change) { /* We can't suid-execute if we're sharing parts of the executable */ /* or if we're being traced (or if suid execs are not allowed) */ /* (current->mm->count > 1 is ok, as we'll get a new mm anyway) */ @@ -704,7 +706,7 @@ current->sgid = current->egid = current->fsgid = bprm->e_gid; if (current->euid != current->uid || current->egid != current->gid || !cap_issubset(new_permitted, current->cap_permitted)) - current->dumpable = 0; + bprm->dumpable = 0; current->keep_capabilities = 0; } @@ -823,6 +825,7 @@ { struct linux_binprm bprm; struct dentry * dentry; + int was_dumpable; int retval; int i; @@ -851,6 +854,9 @@ return bprm.envc; } + was_dumpable = current->dumpable; + current->dumpable = 0; + retval = prepare_binprm(&bprm); if (retval >= 0) { @@ -864,9 +870,12 @@ if (retval >= 0) retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + + if (retval >= 0) { /* execve success */ + current->dumpable = bprm.dumpable; return retval; + } /* Something went wrong, return the inode and free the argument pages*/ if (bprm.dentry) @@ -874,6 +883,8 @@ for (i=0 ; idumpable = was_dumpable; return retval; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/fat/misc.c linux/fs/fat/misc.c --- v2.2.18/fs/fat/misc.c Sun Mar 25 11:12:32 2001 +++ linux/fs/fat/misc.c Sun Mar 25 11:37:38 2001 @@ -2,6 +2,8 @@ * linux/fs/fat/misc.c * * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) */ #include @@ -288,7 +290,9 @@ { int month,year,secs; - month = ((date >> 5) & 15)-1; + /* first subtract and mask after that... Otherwise, if + date == 0, bad things happen */ + month = ((date >> 5) - 1) & 15; year = date >> 9; secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && @@ -309,6 +313,10 @@ unix_date -= sys_tz.tz_minuteswest*60; if (sys_tz.tz_dsttime) unix_date += 3600; + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (unix_date < 315532800) + unix_date = 315532800; *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ (((unix_date/3600) % 24) << 11); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/file_table.c linux/fs/file_table.c --- v2.2.18/fs/file_table.c Sun Mar 25 11:12:31 2001 +++ linux/fs/file_table.c Sun Mar 25 11:37:38 2001 @@ -13,9 +13,7 @@ static kmem_cache_t *filp_cache; /* sysctl tunables... */ -int nr_files = 0; /* read only */ -int nr_free_files = 0; /* read only */ -int max_files = NR_FILE;/* tunable */ +struct files_stat_struct files_stat = {0, 0, NR_FILE}; /* Free list management, if you are here you must have f_count == 0 */ static struct file * free_filps = NULL; @@ -26,7 +24,7 @@ free_filps->f_pprev = &file->f_next; free_filps = file; file->f_pprev = &free_filps; - nr_free_files++; + files_stat.nr_free_files++; } /* The list of in-use filp's must be exported (ugh...) */ @@ -72,11 +70,11 @@ static int old_max = 0; struct file * f; - if (nr_free_files > NR_RESERVED_FILES) { + if (files_stat.nr_free_files > NR_RESERVED_FILES) { used_one: f = free_filps; remove_filp(f); - nr_free_files--; + files_stat.nr_free_files--; new_one: memset(f, 0, sizeof(*f)); f->f_count = 1; @@ -89,23 +87,23 @@ /* * Use a reserved one if we're the superuser */ - if (nr_free_files && !current->euid) + if (files_stat.nr_free_files && !current->euid) goto used_one; /* * Allocate a new one if we're below the limit. */ - if (nr_files < max_files) { + if (files_stat.nr_files < files_stat.max_files) { f = kmem_cache_alloc(filp_cache, SLAB_KERNEL); if (f) { - nr_files++; + files_stat.nr_files++; goto new_one; } /* Big problems... */ printk("VFS: filp allocation failed\n"); - } else if (max_files > old_max) { - printk("VFS: file-max limit %d reached\n", max_files); - old_max = max_files; + } else if (files_stat.max_files > old_max) { + printk("VFS: file-max limit %d reached\n", files_stat.max_files); + old_max = files_stat.max_files; } return NULL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/inode.c linux/fs/inode.c --- v2.2.18/fs/inode.c Sun Mar 25 11:28:33 2001 +++ linux/fs/inode.c Sun Mar 25 11:37:38 2001 @@ -435,7 +435,7 @@ * This is the externally visible routine for * inode memory management. */ -void free_inode_memory(int goal) +void free_inode_memory(void) { spin_lock(&inode_lock); free_inodes(); @@ -681,7 +681,7 @@ static inline unsigned long hash(struct super_block *sb, unsigned long i_ino) { unsigned long tmp = i_ino | (unsigned long) sb; - tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2); + tmp = tmp + (tmp >> HASH_BITS); return tmp & HASH_MASK; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/isofs/dir.c linux/fs/isofs/dir.c --- v2.2.18/fs/isofs/dir.c Sun Mar 25 11:12:31 2001 +++ linux/fs/isofs/dir.c Sun Mar 25 11:37:38 2001 @@ -67,14 +67,18 @@ NULL /* permission */ }; -static int isofs_name_translate(char * old, int len, char * new) +int isofs_name_translate(struct iso_directory_record *de, char *new, + struct inode *inode) { - int i, c; + char * old = de->name; + int len = de->name_len[0]; + int i; for (i = 0; i < len; i++) { - c = old[i]; + unsigned char c = old[i]; if (!c) break; + if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */ @@ -101,8 +105,7 @@ { int std; unsigned char * chr; - int retnamlen = isofs_name_translate(de->name, - de->name_len[0], retname); + int retnamlen = isofs_name_translate(de, retname, inode); if (retnamlen == 0) return 0; std = sizeof(struct iso_directory_record) + de->name_len[0]; if (std & 1) std++; @@ -122,7 +125,9 @@ } /* - * This should _really_ be cleaned up some day.. + * Read directory and call the filldir() argument until either + * all entries were handled, or filldir() returns an error. + * Return 0. */ static int do_isofs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir, @@ -132,7 +137,7 @@ unsigned char bufbits = ISOFS_BUFFER_BITS(inode); unsigned int block, offset; int inode_number = 0; /* Quiet GCC */ - struct buffer_head *bh; + struct buffer_head *bh = NULL; int len; int map; int high_sierra; @@ -140,78 +145,59 @@ char *p = NULL; /* Quiet GCC */ struct iso_directory_record *de; - if (filp->f_pos >= inode->i_size) - return 0; - offset = filp->f_pos & (bufsize - 1); - block = isofs_bmap(inode, filp->f_pos >> bufbits); + block = filp->f_pos >> bufbits; high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; - if (!block) - return 0; - - if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size))) - return 0; - while (filp->f_pos < inode->i_size) { int de_len; -#ifdef DEBUG - printk("Block, offset, f_pos: %x %x %x\n", - block, offset, filp->f_pos); - printk("inode->i_size = %x\n",inode->i_size); -#endif + + if (!bh) { + bh = isofs_bread(inode, bufsize, block); + if (!bh) + return 0; + } + de = (struct iso_directory_record *) (bh->b_data + offset); - if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1)); + if (first_de) + inode_number = (bh->b_blocknr << bufbits) + offset; - /* Check boundaries and get length. by GO! */ - if (offset < bufsize) de_len = *(unsigned char *) de; -#ifdef DEBUG - if (offset < bufsize) printk("de_len = %ld\n", de_len); - else printk("Move to next sector\n"); -#endif - + de_len = *(unsigned char *) de; /* If the length byte is zero, we should move on to the next CDROM sector. If we are at the end of the directory, we kick out of the while loop. */ - if ((offset >= bufsize) || (de_len == 0) ) { + if (de_len == 0) { brelse(bh); - if (offset >= bufsize) { /*Check first. by GO!*/ - offset -= bufsize; - filp->f_pos += offset; - } else { - filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1)) - + ISOFS_BLOCK_SIZE); - offset = 0; - } - - if (filp->f_pos >= inode->i_size) - return 0; - - block = isofs_bmap(inode, (filp->f_pos) >> bufbits); - if (!block) - return 0; - bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size); - if (!bh) - return 0; + bh = NULL; + filp->f_pos = (filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1)) + + ISOFS_BLOCK_SIZE; + block = filp->f_pos >> bufbits; + offset = 0; continue; } - offset += de_len; - if (offset > bufsize) { - /* - * This would only normally happen if we had - * a buggy cdrom image. All directory - * entries should terminate with a null size - * or end exactly at the end of the sector. - */ - printk("next_offset (%x) > bufsize (%lx)\n", - offset,bufsize); - break; + offset += de_len; + + /* Make sure we have a full directory entry */ + if (offset >= bufsize) { + int slop = bufsize - offset + de_len; + memcpy(tmpde, de, slop); + offset &= bufsize - 1; + block++; + brelse(bh); + bh = NULL; + if (offset) { + bh = isofs_bread(inode, bufsize, block); + if (!bh) + return 0; + memcpy((void *) tmpde + slop, bh->b_data, offset); + } + de = tmpde; } - if(de->flags[-high_sierra] & 0x80) { + if (de->flags[-high_sierra] & 0x80) { first_de = 0; filp->f_pos += de_len; continue; @@ -250,7 +236,7 @@ map = 1; if (inode->i_sb->u.isofs_sb.s_rock) { len = get_rock_ridge_filename(de, tmpname, inode); - if (len != 0) { + if (len != 0) { /* may be -1 */ p = tmpname; map = 0; } @@ -258,7 +244,7 @@ if (map) { #ifdef CONFIG_JOLIET if (inode->i_sb->u.isofs_sb.s_joliet_level) { - len = get_joliet_filename(de, inode, tmpname); + len = get_joliet_filename(de, tmpname, inode); p = tmpname; } else #endif @@ -267,8 +253,7 @@ p = tmpname; } else if (inode->i_sb->u.isofs_sb.s_mapping == 'n') { - len = isofs_name_translate(de->name, - de->name_len[0], tmpname); + len = isofs_name_translate(de, tmpname, inode); p = tmpname; } else { p = de->name; @@ -283,7 +268,8 @@ continue; } - brelse(bh); + if (bh) + brelse(bh); return 0; } @@ -296,17 +282,17 @@ void *dirent, filldir_t filldir) { int result; - char * tmpname; + char * page; struct iso_directory_record * tmpde; struct inode *inode = filp->f_dentry->d_inode; - tmpname = (char *) __get_free_page(GFP_KERNEL); - if (!tmpname) + page = (char *) __get_free_page(GFP_KERNEL); + if (!page) return -ENOMEM; - tmpde = (struct iso_directory_record *) (tmpname+1024); + tmpde = (struct iso_directory_record *) (page+1024); - result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde); + result = do_isofs_readdir(inode, filp, dirent, filldir, page, tmpde); - free_page((unsigned long) tmpname); + free_page((unsigned long) page); return result; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.2.18/fs/isofs/inode.c Sun Mar 25 11:12:31 2001 +++ linux/fs/isofs/inode.c Sun Mar 25 11:37:38 2001 @@ -54,7 +54,7 @@ static int isofs_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); #endif -void isofs_put_super(struct super_block *sb) +static void isofs_put_super(struct super_block *sb) { #ifdef CONFIG_JOLIET if (sb->u.isofs_sb.s_nls_iocharset) { @@ -72,6 +72,9 @@ return; } +static void isofs_read_inode(struct inode *); +static int isofs_statfs (struct super_block *, struct statfs *, int); + static struct super_operations isofs_sops = { isofs_read_inode, NULL, /* write_inode */ @@ -452,7 +455,7 @@ (unsigned long) &ms_info); set_fs(old_fs); #if 0 - printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); + printk("isofs.inode: CDROMMULTISESSION: rc=%d\n", i); if (i==0) { printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no"); @@ -474,8 +477,8 @@ * Note: a check_disk_change() has been done immediately prior * to this call, so we don't need to check again. */ -struct super_block *isofs_read_super(struct super_block *s, void *data, - int silent) +static struct super_block *isofs_read_super(struct super_block *s, void *data, + int silent) { kdev_t dev = s->s_dev; struct buffer_head * bh = NULL, *pri_bh = NULL; @@ -521,15 +524,13 @@ * that value. */ blocksize = get_hardblocksize(dev); - if( (blocksize != 0) - && (blocksize > opt.blocksize) ) - { + if (blocksize > opt.blocksize) { /* * Force the blocksize we are going to use to be the * hardware blocksize. */ opt.blocksize = blocksize; - } + } blocksize_bits = 0; { @@ -625,9 +626,7 @@ pri_bh = NULL; root_found: - brelse(pri_bh); - - if (joliet_level && opt.rock == 'n') { + if (joliet_level && (pri == NULL || opt.rock == 'n')) { /* This is the case of Joliet with the norock mount flag. * A disc with both Joliet and Rock Ridge is handled later */ @@ -724,6 +723,7 @@ * We're all done using the volume descriptor, and may need * to change the device blocksize, so release the buffer now. */ + brelse(pri_bh); brelse(bh); /* @@ -776,8 +776,9 @@ s->u.isofs_sb.s_gid = opt.gid; s->u.isofs_sb.s_utf8 = opt.utf8; /* - * It would be incredibly stupid to allow people to mark every file on the disk - * as suid, so we merely allow them to set the default permissions. + * It would be incredibly stupid to allow people to mark every file + * on the disk as suid, so we merely allow them to set the default + * permissions. */ s->u.isofs_sb.s_mode = opt.mode & 0777; @@ -880,8 +881,8 @@ return NULL; } -int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz) -{ +static int +isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz) { struct statfs tmp; tmp.f_type = ISOFS_SUPER_MAGIC; @@ -896,6 +897,15 @@ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } +struct buffer_head *isofs_bread(struct inode *inode, unsigned int bufsize, + unsigned int block) +{ + unsigned int blknr = isofs_bmap(inode, block); + if (!blknr) + return NULL; + return bread(inode->i_dev, blknr, bufsize); +} + int isofs_bmap(struct inode * inode,int block) { off_t b_off, offset, size; @@ -942,10 +952,6 @@ firstext = inode->u.isofs_i.i_first_extent; size = inode->u.isofs_i.i_section_size; nextino = inode->u.isofs_i.i_next_section_ino; -#ifdef DEBUG - printk("first inode: inode=%x nextino=%x firstext=%u size=%lu\n", - inode->i_ino, nextino, firstext, size); -#endif i = 0; if (nextino) { while(b_off >= offset + size) { @@ -956,10 +962,6 @@ if(!ino) return 0; firstext = ino->u.isofs_i.i_first_extent; size = ino->u.isofs_i.i_section_size; -#ifdef DEBUG - printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n", - inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size); -#endif nextino = ino->u.isofs_i.i_next_section_ino; iput(ino); @@ -971,10 +973,6 @@ } } } -#ifdef DEBUG - printk("isofs_bmap: mapped inode:block %x:%d to block %lu\n", - inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode)); -#endif return firstext + ((b_off - offset) >> ISOFS_BUFFER_BITS(inode)); } @@ -995,118 +993,144 @@ static int isofs_read_level3_size(struct inode * inode) { - unsigned long ino = inode->i_ino; + unsigned long f_pos = inode->i_ino; unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); int high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; struct buffer_head * bh = NULL; - int block = 0; + unsigned long block, offset; int i = 0; int more_entries = 0; - void *cpnt; - struct iso_directory_record * raw_inode; + struct iso_directory_record * tmpde = NULL; inode->i_size = 0; inode->u.isofs_i.i_next_section_ino = 0; + + block = f_pos >> ISOFS_BUFFER_BITS(inode); + offset = f_pos & (bufsize-1); + do { - unsigned char *pnt; - unsigned int reclen; - int offset = (ino & (bufsize - 1)); - - cpnt = NULL; - /* Check whether to update our buffer */ - if (block != ino >> ISOFS_BUFFER_BITS(inode)) { - block = ino >> ISOFS_BUFFER_BITS(inode); + struct iso_directory_record * de; + unsigned int de_len; + + if (!bh) { brelse(bh); bh = bread(inode->i_dev, block, bufsize); if (!bh) goto out_noread; } - pnt = ((unsigned char *) bh->b_data + offset); - /* - * Note: this is invariant even if the record - * spans buffers and must be copied ... - */ - reclen = *pnt; - /* N.B. this test doesn't trigger the i++ code ... */ - if(reclen == 0) { - ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE; + de = (struct iso_directory_record *) (bh->b_data + offset); + de_len = *(unsigned char *) de; + + if (de_len == 0) { + brelse(bh); + bh = NULL; + f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1); + block = f_pos >> ISOFS_BUFFER_BITS(inode); + offset = 0; continue; } - raw_inode = ((struct iso_directory_record *) pnt); - /* Check whether the raw inode spans the buffer ... */ - if (offset + reclen > bufsize){ - int frag1 = bufsize - offset; - - cpnt = kmalloc(reclen, GFP_KERNEL); - if (cpnt == NULL) - goto out_nomem; - memcpy(cpnt, pnt, frag1); + offset += de_len; + + /* Make sure we have a full directory entry */ + if (offset >= bufsize) { + int slop = bufsize - offset + de_len; + if (!tmpde) { + tmpde = kmalloc(256, GFP_KERNEL); + if (!tmpde) + goto out_nomem; + } + memcpy(tmpde, de, slop); + offset &= bufsize - 1; + block++; brelse(bh); - bh = bread(inode->i_dev, ++block, bufsize); - if (!bh) - goto out_noread; - offset += reclen - bufsize; - memcpy((char *)cpnt+frag1, bh->b_data, offset); - raw_inode = ((struct iso_directory_record *) cpnt); + bh = NULL; + if (offset) { + bh = bread(inode->i_dev, ++block, bufsize); + if (!bh) + goto out_noread; + memcpy((void *) tmpde + slop, bh->b_data, offset); + } + de = tmpde; } - inode->i_size += isonum_733 (raw_inode->size); - if(i == 1) inode->u.isofs_i.i_next_section_ino = ino; + inode->i_size += isonum_733 (de->size); + if(i == 1) + inode->u.isofs_i.i_next_section_ino = f_pos; + + more_entries = de->flags[-high_sierra] & 0x80; + + f_pos += de_len; - more_entries = raw_inode->flags[-high_sierra] & 0x80; - - ino += reclen; - if (cpnt) - kfree (cpnt); i++; if(i > 100) goto out_toomany; } while(more_entries); out: - brelse(bh); + if (tmpde) + kfree(tmpde); + if (bh) + brelse(bh); return 0; out_nomem: - printk(KERN_INFO "ISOFS: NoMem ISO inode %lu\n", inode->i_ino); - brelse(bh); - return 1; + if (bh) + brelse(bh); + return -ENOMEM; + out_noread: - printk(KERN_INFO "ISOFS: unable to read i-node block %d\n", block); - if (cpnt) - kfree(cpnt); - return 1; + printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block); + if (tmpde) + kfree(tmpde); + return -EIO; + out_toomany: printk(KERN_INFO "isofs_read_level3_size: " "More than 100 file sections ?!?, aborting...\n" "isofs_read_level3_size: inode=%lu ino=%lu\n", - inode->i_ino, ino); + inode->i_ino, f_pos); goto out; } -void isofs_read_inode(struct inode * inode) +static void isofs_read_inode(struct inode * inode) { struct super_block *sb = inode->i_sb; unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); int block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); int high_sierra = sb->u.isofs_sb.s_high_sierra; - struct buffer_head * bh; - struct iso_directory_record * raw_inode; - unsigned char *pnt; - int volume_seq_no, i; + struct buffer_head * bh = NULL; + struct iso_directory_record * de; + struct iso_directory_record * tmpde = NULL; + unsigned int de_len; + int volume_seq_no, i, offset; bh = bread(inode->i_dev, block, bufsize); - if (!bh) { - printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); - goto fail; - } + if (!bh) + goto out_badread; - pnt = ((unsigned char *) bh->b_data - + (inode->i_ino & (bufsize - 1))); - raw_inode = ((struct iso_directory_record *) pnt); + offset = (inode->i_ino & (bufsize - 1)); + de = (struct iso_directory_record *) (bh->b_data + offset); + de_len = *(unsigned char *) de; + + if (offset + de_len > bufsize){ + int frag1 = bufsize - offset; + + tmpde = kmalloc(de_len, GFP_KERNEL); + if (tmpde == NULL) { + printk(KERN_INFO "isofs_read_inode: out of memory\n"); + goto fail; + } + memcpy(tmpde, bh->b_data + offset, frag1); + brelse(bh); + bh = bread(inode->i_dev, ++block, bufsize); + if (!bh) + goto out_badread; + memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1); + de = tmpde; + } - if (raw_inode->flags[-high_sierra] & 2) { + if (de->flags[-high_sierra] & 2) { inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; inode->i_nlink = 1; /* Set to 1. We know there are 2, but the find utility tries to optimize @@ -1121,10 +1145,10 @@ /* If there are no periods in the name, * then set the execute permission bit */ - for(i=0; i< raw_inode->name_len[0]; i++) - if(raw_inode->name[i]=='.' || raw_inode->name[i]==';') + for(i=0; i< de->name_len[0]; i++) + if(de->name[i]=='.' || de->name[i]==';') break; - if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';') + if(i == de->name_len[0] || de->name[i] == ';') inode->i_mode |= S_IXUGO; /* execute permission */ } inode->i_uid = inode->i_sb->u.isofs_sb.s_uid; @@ -1132,49 +1156,54 @@ inode->i_blocks = inode->i_blksize = 0; - inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size); - if(raw_inode->flags[-high_sierra] & 0x80) { + inode->u.isofs_i.i_section_size = isonum_733 (de->size); + if(de->flags[-high_sierra] & 0x80) { if(isofs_read_level3_size(inode)) goto fail; } else { - inode->i_size = isonum_733 (raw_inode->size); + inode->i_size = isonum_733 (de->size); } /* There are defective discs out there - we do this to protect ourselves. A cdrom will never contain more than 800Mb .. but a DVD may be up to 1Gig (Ulrich Habel) */ + if((inode->i_size < 0 || inode->i_size > 1073741824) && - inode->i_sb->u.isofs_sb.s_cruft == 'n') { - printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n"); - inode->i_sb->u.isofs_sb.s_cruft = 'y'; + inode->i_sb->u.isofs_sb.s_cruft == 'n') { + printk(KERN_WARNING "Warning: defective cdrom. " + "Enabling \"cruft\" mount option.\n"); + inode->i_sb->u.isofs_sb.s_cruft = 'y'; } -/* Some dipshit decided to store some other bit of information in the high - byte of the file length. Catch this and holler. WARNING: this will make - it impossible for a file to be > 16Mb on the CDROM!!!*/ + /* + * Some dipshit decided to store some other bit of information + * in the high byte of the file length. Catch this and holler. + * WARNING: this will make it impossible for a file to be > 16MB + * on the CDROM. + */ if(inode->i_sb->u.isofs_sb.s_cruft == 'y' && inode->i_size & 0xff000000){ -/* printk("Illegal format on cdrom. Pester manufacturer.\n"); */ - inode->i_size &= 0x00ffffff; + inode->i_size &= 0x00ffffff; } - if (raw_inode->interleave[0]) { + if (de->interleave[0]) { printk("Interleaved files not (yet) supported.\n"); inode->i_size = 0; } /* I have no idea what file_unit_size is used for, so we will flag it for now */ - if(raw_inode->file_unit_size[0] != 0){ - printk("File unit size != 0 for ISO file (%ld).\n",inode->i_ino); + if (de->file_unit_size[0] != 0){ + printk("File unit size != 0 for ISO file (%ld).\n", + inode->i_ino); } /* I have no idea what other flag bits are used for, so we will flag it for now */ #ifdef DEBUG - if((raw_inode->flags[-high_sierra] & ~2)!= 0){ + if ((de->flags[-high_sierra] & ~2)!= 0){ printk("Unusual flag settings for ISO file (%ld %x).\n", - inode->i_ino, raw_inode->flags[-high_sierra]); + inode->i_ino, de->flags[-high_sierra]); } #endif @@ -1184,32 +1213,25 @@ #endif inode->i_mtime = inode->i_atime = inode->i_ctime = - iso_date(raw_inode->date, high_sierra); + iso_date(de->date, high_sierra); - inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) + - isonum_711 (raw_inode->ext_attr_length)); + inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) + + isonum_711 (de->ext_attr_length)); -/* Now test for possible Rock Ridge extensions which will override some of - these numbers in the inode structure. */ + /* + * Now test for possible Rock Ridge extensions which will override + * some of these numbers in the inode structure. + */ if (!high_sierra) { - parse_rock_ridge_inode(raw_inode, inode); - /* hmm..if we want uid or gid set, override the rock ridge setting */ - test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid); - test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid); + parse_rock_ridge_inode(de, inode); + /* if we want uid/gid set, override the rock ridge setting */ + test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid); + test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid); } -#ifdef DEBUG - printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent); -#endif - /* get the volume sequence number */ - volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ; - - /* - * All done with buffer ... no more references to buffer memory! - */ - brelse(bh); + volume_seq_no = isonum_723 (de->volume_sequence_number) ; /* * Disable checking if we see any volume number other than 0 or 1. @@ -1219,8 +1241,10 @@ */ if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && (volume_seq_no != 0) && (volume_seq_no != 1)) { - printk("Warning: defective cdrom (volume sequence number). Enabling \"cruft\" mount option.\n"); - inode->i_sb->u.isofs_sb.s_cruft = 'y'; + printk("Warning: defective cdrom " + "(volume sequence number %d). " + "Enabling \"cruft\" mount option.\n", volume_seq_no); + inode->i_sb->u.isofs_sb.s_cruft = 'y'; } /* Install the inode operations vector */ @@ -1228,26 +1252,34 @@ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && (volume_seq_no != 0) && (volume_seq_no != 1)) { - printk("Multi volume CD somehow got mounted.\n"); + printk(KERN_WARNING "Multi volume CD somehow got mounted.\n"); } else #endif IGNORE_WRONG_MULTI_VOLUME_SPECS { - if (S_ISREG(inode->i_mode)) - inode->i_op = &isofs_file_inode_operations; - else if (S_ISDIR(inode->i_mode)) - inode->i_op = &isofs_dir_inode_operations; - else if (S_ISLNK(inode->i_mode)) - inode->i_op = &isofs_symlink_inode_operations; - else if (S_ISCHR(inode->i_mode)) - inode->i_op = &chrdev_inode_operations; - else if (S_ISBLK(inode->i_mode)) - inode->i_op = &blkdev_inode_operations; - else if (S_ISFIFO(inode->i_mode)) - init_fifo(inode); + if (S_ISREG(inode->i_mode)) + inode->i_op = &isofs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &isofs_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &isofs_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); } + + out: + if (tmpde) + kfree(tmpde); + if (bh) + brelse(bh); return; - fail: + out_badread: + printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); + fail: /* With a data error we return this information */ inode->i_mtime = inode->i_atime = inode->i_ctime = 0; inode->u.isofs_i.i_first_extent = 0; @@ -1257,144 +1289,7 @@ inode->i_uid = inode->i_gid = 0; inode->i_mode = S_IFREG; /*Regular file, no one gets to read*/ inode->i_op = NULL; - return; -} - -/* There are times when we need to know the inode number of a parent of - a particular directory. When control passes through a routine that - has access to the parent information, it fills it into the inode structure, - but sometimes the inode gets flushed out of the queue, and someone - remembers the number. When they try to open up again, we have lost - the information. The '..' entry on the disc points to the data area - for a particular inode, so we can follow these links back up, but since - we do not know the inode number, we do not actually know how large the - directory is. The disc is almost always correct, and there is - enough error checking on the drive itself, but an open ended search - makes me a little nervous. - - The BSD iso filesystem uses the extent number for an inode, and this - would work really nicely for us except that the read_inode function - would not have any clean way of finding the actual directory record - that goes with the file. If we had such info, then it would pay - to change the inode numbers and eliminate this function. -*/ - -int isofs_lookup_grandparent(struct inode * parent, int extent) -{ - unsigned long bufsize = ISOFS_BUFFER_SIZE(parent); - unsigned char bufbits = ISOFS_BUFFER_BITS(parent); - unsigned int block,offset; - int parent_dir, inode_number; - int result; - int directory_size; - struct buffer_head * bh; - struct iso_directory_record * de; - - offset = 0; - block = extent << (ISOFS_ZONE_BITS(parent) - bufbits); - if (!(bh = bread(parent->i_dev, block, bufsize))) return -1; - - while (1 == 1) { - de = (struct iso_directory_record *) (bh->b_data + offset); - if (*((unsigned char *) de) == 0) - { - brelse(bh); - printk("Directory .. not found\n"); - return -1; - } - - offset += *((unsigned char *) de); - - if (offset >= bufsize) - { - printk(".. Directory not in first block" - " of directory.\n"); - brelse(bh); - return -1; - } - - if (de->name_len[0] == 1 && de->name[0] == 1) - { - parent_dir = find_rock_ridge_relocation(de, parent); - directory_size = isonum_733 (de->size); - brelse(bh); - break; - } - } -#ifdef DEBUG - printk("Parent dir:%x\n",parent_dir); -#endif - /* Now we know the extent where the parent dir starts on. */ - - result = -1; - - offset = 0; - block = parent_dir << (ISOFS_ZONE_BITS(parent) - bufbits); - if (!block || !(bh = bread(parent->i_dev,block, bufsize))) - { - return -1; - } - - for(;;) - { - de = (struct iso_directory_record *) (bh->b_data + offset); - inode_number = (block << bufbits)+(offset & (bufsize - 1)); - - /* If the length byte is zero, we should move on to the next - CDROM sector. If we are at the end of the directory, we - kick out of the while loop. */ - - if ((*((unsigned char *) de) == 0) || (offset == bufsize) ) - { - brelse(bh); - offset = 0; - block++; - directory_size -= bufsize; - if(directory_size < 0) return -1; - if((block & 1) && (ISOFS_ZONE_BITS(parent) - bufbits) == 1) - { - return -1; - } - if((block & 3) && (ISOFS_ZONE_BITS(parent) - bufbits) == 2) - { - return -1; - } - if (!block - || !(bh = bread(parent->i_dev,block, bufsize))) - { - return -1; - } - continue; - } - - /* Make sure that the entire directory record is in the current - bh block. If not, we malloc a buffer, and put the two - halves together, so that we can cleanly read the block. */ - - offset += *((unsigned char *) de); - - if (offset > bufsize) - { - printk("Directory overrun\n"); - goto out; - } - - if (find_rock_ridge_relocation(de, parent) == extent){ - result = inode_number; - goto out; - } - - } - - /* We go here for any condition we cannot handle. - We also drop through to here at the end of the directory. */ - - out: - brelse(bh); -#ifdef DEBUG - printk("Resultant Inode %d\n",result); -#endif - return result; + goto out; } #ifdef LEAK_CHECK diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/isofs/joliet.c linux/fs/isofs/joliet.c --- v2.2.18/fs/isofs/joliet.c Sun Mar 25 11:12:31 2001 +++ linux/fs/isofs/joliet.c Sun Mar 25 11:37:38 2001 @@ -19,8 +19,6 @@ struct nls_table *nls) { unsigned char *ip, *op; - unsigned char ch, cl; - unsigned char *uni_page; ip = uni; op = ascii; @@ -68,8 +66,8 @@ } int -get_joliet_filename(struct iso_directory_record * de, struct inode * inode, - unsigned char *outname) +get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, + struct inode * inode) { unsigned char utf8; struct nls_table *nls; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/isofs/namei.c linux/fs/isofs/namei.c --- v2.2.18/fs/isofs/namei.c Sun Mar 25 11:12:31 2001 +++ linux/fs/isofs/namei.c Sun Mar 25 11:37:38 2001 @@ -53,200 +53,130 @@ * isofs_find_entry() * * finds an entry in the specified directory with the wanted name. It - * returns the cache buffer in which the entry was found, and the entry - * itself (as an inode number). It does NOT read the inode of the - * entry - you'll have to do that yourself if you want to. + * returns the inode number of the found entry, or 0 on error. */ -static struct buffer_head * -isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino) +static unsigned long +isofs_find_entry(struct inode *dir, struct dentry *dentry, + char *tmpname, struct iso_directory_record *tmpde) { + unsigned long inode_number; unsigned long bufsize = ISOFS_BUFFER_SIZE(dir); unsigned char bufbits = ISOFS_BUFFER_BITS(dir); - unsigned int block, i, f_pos, offset, - inode_number = 0; /* shut gcc up */ - struct buffer_head * bh , * retval = NULL; - unsigned int old_offset; - int dlen, match; - char * dpnt; - unsigned char *page = NULL; - struct iso_directory_record * de = NULL; /* shut gcc up */ - char de_not_in_buf = 0; /* true if de is in kmalloc'd memory */ - char c; - - *ino = 0; - - if (!(block = dir->u.isofs_i.i_first_extent)) return NULL; + unsigned int block, f_pos, offset; + struct buffer_head * bh = NULL; + + if (!dir->u.isofs_i.i_first_extent) + return 0; f_pos = 0; + offset = 0; + block = 0; - offset = f_pos & (bufsize - 1); - block = isofs_bmap(dir,f_pos >> bufbits); + while (f_pos < dir->i_size) { + struct iso_directory_record * de; + int de_len, match, i, dlen; + char *dpnt; - if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL; + if (!bh) { + bh = isofs_bread(dir, bufsize, block); + if (!bh) + return 0; + } - while (f_pos < dir->i_size) { + de = (struct iso_directory_record *) (bh->b_data + offset); + inode_number = (bh->b_blocknr << bufbits) + offset; - /* if de is in kmalloc'd memory, do not point to the - next de, instead we will move to the next sector */ - if(!de_not_in_buf) { - de = (struct iso_directory_record *) - (bh->b_data + offset); - } - inode_number = (block << bufbits) + (offset & (bufsize - 1)); - - /* If byte is zero, or we had to fetch this de past - the end of the buffer, this is the end of file, or - time to move to the next sector. Usually 2048 byte - boundaries. */ - - if (*((unsigned char *) de) == 0 || de_not_in_buf) { - if(de_not_in_buf) { - /* james@bpgc.com: Since we slopped - past the end of the last buffer, we - must start some way into the new - one */ - de_not_in_buf = 0; - kfree(de); - f_pos += offset; - } - else { - offset = 0; - f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1)) - + ISOFS_BLOCK_SIZE); - } + de_len = *(unsigned char *) de; + if (!de_len) { brelse(bh); bh = NULL; - - if (f_pos >= dir->i_size) - break; - - block = isofs_bmap(dir,f_pos>>bufbits); - if (!block || !(bh = bread(dir->i_dev,block,bufsize))) - break; - - continue; /* Will kick out if past end of directory */ + f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1); + block = f_pos >> bufbits; + offset = 0; + continue; } - old_offset = offset; - offset += *((unsigned char *) de); - f_pos += *((unsigned char *) de); + offset += de_len; + f_pos += de_len; - /* james@bpgc.com: new code to handle case where the - directory entry spans two blocks. Usually 1024 - byte boundaries */ + /* Make sure we have a full directory entry */ if (offset >= bufsize) { - struct buffer_head *bh_next; - - /* james@bpgc.com: read the next block, and - copy the split de into a newly kmalloc'd - buffer */ - block = isofs_bmap(dir,f_pos>>bufbits); - if (!block || - !(bh_next = bread(dir->i_dev,block,bufsize))) - break; - - de = (struct iso_directory_record *) - kmalloc(offset - old_offset, GFP_KERNEL); - if(de==NULL) - break; - memcpy((char *)de, bh->b_data + old_offset, - bufsize - old_offset); - memcpy((char *)de + bufsize - old_offset, - bh_next->b_data, offset - bufsize); - brelse(bh_next); - de_not_in_buf = 1; - offset -= bufsize; + int slop = bufsize - offset + de_len; + memcpy(tmpde, de, slop); + offset &= bufsize - 1; + block++; + brelse(bh); + bh = NULL; + if (offset) { + bh = isofs_bread(dir, bufsize, block); + if (!bh) + return 0; + memcpy((void *) tmpde + slop, bh->b_data, offset); + } + de = tmpde; } + dlen = de->name_len[0]; dpnt = de->name; - if (dir->i_sb->u.isofs_sb.s_rock || - dir->i_sb->u.isofs_sb.s_joliet_level || - dir->i_sb->u.isofs_sb.s_mapping == 'n' || - dir->i_sb->u.isofs_sb.s_mapping == 'a') { - if (! page) { - page = (unsigned char *) - __get_free_page(GFP_KERNEL); - if (!page) break; - } - } if (dir->i_sb->u.isofs_sb.s_rock && - ((i = get_rock_ridge_filename(de, page, dir)))) { - dlen = i; - dpnt = page; + ((i = get_rock_ridge_filename(de, tmpname, dir)))) { + dlen = i; /* possibly -1 */ + dpnt = tmpname; #ifdef CONFIG_JOLIET } else if (dir->i_sb->u.isofs_sb.s_joliet_level) { - dlen = get_joliet_filename(de, dir, page); - dpnt = page; + dlen = get_joliet_filename(de, tmpname, dir); + dpnt = tmpname; #endif } else if (dir->i_sb->u.isofs_sb.s_mapping == 'a') { - dlen = get_acorn_filename(de, page, dir); - dpnt = page; + dlen = get_acorn_filename(de, tmpname, dir); + dpnt = tmpname; } else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') { - for (i = 0; i < dlen; i++) { - c = dpnt[i]; - /* lower case */ - if (c >= 'A' && c <= 'Z') c |= 0x20; - if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') { - dlen -= 2; - break; - } - if (c == ';') c = '.'; - page[i] = c; - } - /* This allows us to match with and without - * a trailing period. */ - if(page[dlen-1] == '.' && dentry->d_name.len == dlen-1) - dlen--; - dpnt = page; + dlen = isofs_name_translate(de, tmpname, dir); + dpnt = tmpname; } + /* * Skip hidden or associated files unless unhide is set */ match = 0; - if ((!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5) - || dir->i_sb->u.isofs_sb.s_unhide == 'y') && dlen) + if (dlen > 0 && + (!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5) + || dir->i_sb->u.isofs_sb.s_unhide == 'y')) { match = (isofs_cmp(dentry,dpnt,dlen) == 0); } if (match) { - if(inode_number == -1) { - /* Should only happen for the '..' entry */ - inode_number = - isofs_lookup_grandparent(dir, - find_rock_ridge_relocation(de,dir)); - } - *ino = inode_number; - retval = bh; - bh = NULL; - break; + if (bh) + brelse(bh); + return inode_number; } } - if (page) free_page((unsigned long) page); - if (bh) brelse(bh); - if(de_not_in_buf) - kfree(de); - return retval; + if (bh) + brelse(bh); + return 0; } struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry) { unsigned long ino; - struct buffer_head * bh; struct inode *inode; + char *page; + struct iso_directory_record * tmpde; -#ifdef DEBUG - printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name); -#endif dentry->d_op = dir->i_sb->s_root->d_op; - bh = isofs_find_entry(dir, dentry, &ino); + page = (char *) __get_free_page(GFP_USER); + if (!page) + return ERR_PTR(-ENOMEM); + tmpde = (struct iso_directory_record *) (page+1024); - inode = NULL; - if (bh) { - brelse(bh); + ino = isofs_find_entry(dir, dentry, page, tmpde); + free_page((unsigned long) page); - inode = iget(dir->i_sb,ino); + inode = NULL; + if (ino) { + inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/isofs/rock.c linux/fs/isofs/rock.c --- v2.2.18/fs/isofs/rock.c Sun Mar 25 11:12:31 2001 +++ linux/fs/isofs/rock.c Sun Mar 25 11:37:38 2001 @@ -70,7 +70,7 @@ cont_size = 0; \ cont_offset = 0; \ goto LABEL; \ - }; \ + } \ printk("Unable to read rock-ridge attributes\n"); \ }} @@ -118,22 +118,16 @@ CHECK_SP(goto out); break; case SIG('C','L'): -#ifdef DEBUG - printk("RR: CL\n"); -#endif if (flag == 0) { retval = isonum_733(rr->u.CL.location); goto out; - }; + } break; case SIG('P','L'): -#ifdef DEBUG - printk("RR: PL\n"); -#endif if (flag != 0) { retval = isonum_733(rr->u.PL.location); goto out; - }; + } break; case SIG('C','E'): CHECK_CE; /* This tells is if there is a continuation record */ @@ -141,8 +135,8 @@ default: break; } - }; - }; + } + } MAYBE_CONTINUE(repeat, inode); return retval; out: @@ -150,6 +144,7 @@ return retval; } +/* return length of name field; 0: not found, -1: to be ignored */ int get_rock_ridge_filename(struct iso_directory_record * de, char * retname, struct inode * inode) { @@ -200,24 +195,21 @@ if (rr->u.NM.flags & ~1) { printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags); break; - }; + } if((strlen(retname) + rr->len - 5) >= 254) { truncate = 1; break; - }; + } strncat(retname, rr->u.NM.name, rr->len - 5); retnamlen += rr->len - 5; break; case SIG('R','E'): -#ifdef DEBUG - printk("RR: RE (%x)\n", inode->i_ino); -#endif if (buffer) kfree(buffer); return -1; default: break; } - }; + } } MAYBE_CONTINUE(repeat,inode); return retnamlen; /* If 0, this file did not have a NM field */ @@ -263,10 +255,10 @@ break; case SIG('E','R'): inode->i_sb->u.isofs_sb.s_rock = 1; - printk(KERN_DEBUG"ISO 9660 Extensions: "); + printk(KERN_DEBUG "ISO 9660 Extensions: "); { int p; for(p=0;pu.ER.len_id;p++) printk("%c",rr->u.ER.data[p]); - }; + } printk("\n"); break; case SIG('P','X'): @@ -337,27 +329,24 @@ slp = (struct SL_component *) (((char *) slp) + slp->len + 2); if(slen < 2) { - if( ((rr->u.SL.flags & 1) != 0) - && ((oldslp->flags & 1) == 0) ) inode->i_size += 1; + if((rr->u.SL.flags & 1) != 0 && (oldslp->flags & 1) == 0) + inode->i_size += 1; break; } /* * If this component record isn't continued, then append a '/'. */ - if( (!rootflag) - && ((oldslp->flags & 1) == 0) ) inode->i_size += 1; + if(!rootflag && (oldslp->flags & 1) == 0) + inode->i_size += 1; } } symlink_len = inode->i_size; break; case SIG('R','E'): - printk("Attempt to read inode for relocated directory\n"); + printk(KERN_WARNING "Attempt to read inode for relocated directory\n"); goto out; case SIG('C','L'): -#ifdef DEBUG - printk("RR CL (%x)\n",inode->i_ino); -#endif inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location); reloc = iget(inode->i_sb, (inode->u.isofs_i.i_first_extent << @@ -378,7 +367,7 @@ default: break; } - }; + } } MAYBE_CONTINUE(repeat,inode); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/isofs/util.c linux/fs/isofs/util.c --- v2.2.18/fs/isofs/util.c Sun Mar 25 11:12:31 2001 +++ linux/fs/isofs/util.c Sun Mar 25 11:37:38 2001 @@ -98,7 +98,7 @@ int iso_date(char * p, int flag) { - int year, month, day, hour ,minute, second, tz; + int year, month, day, hour, minute, second, tz; int crtime, days, i; year = p[0] - 70; @@ -114,7 +114,6 @@ crtime = 0; } else { int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; - extern struct timezone sys_tz; days = year * 365; if (year > 2) @@ -126,8 +125,6 @@ days += day - 1; crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second; - if (sys_tz.tz_dsttime) - crtime -= 3600; /* sign extend */ if (tz & 0x80) @@ -149,7 +146,7 @@ * NOTE: mkisofs in versions prior to mkisofs-1.10 had * the sign wrong on the timezone offset. This has now * been corrected there too, but if you are getting screwy - * results this may be the explaination. If enough people + * results this may be the explanation. If enough people * complain, a user configuration option could be added * to add the timezone offset in with the wrong sign * for 'compatibility' with older discs, but I cannot see how diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c --- v2.2.18/fs/lockd/clntlock.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/clntlock.c Sun Mar 25 11:37:38 2001 @@ -138,18 +138,15 @@ void nlmclnt_recovery(struct nlm_host *host, u32 newstate) { - if (!host->h_reclaiming++) { + if (host->h_reclaiming++) { if (host->h_nsmstate == newstate) return; printk(KERN_WARNING "lockd: Uh-oh! Interfering reclaims for host %s", host->h_name); - host->h_monitored = 0; host->h_nsmstate = newstate; host->h_state++; - nlm_release_host(host); } else { - host->h_monitored = 0; host->h_nsmstate = newstate; host->h_state++; nlm_get_host(host); @@ -168,7 +165,11 @@ /* This one ensures that our parent doesn't terminate while the * reclaim is in progress */ lock_kernel(); + daemonize(); + lockd_up(); + + exit_files(current); /* First, reclaim all locks that have been granted previously. */ do { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.2.18/fs/lockd/clntproc.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/clntproc.c Sun Mar 25 11:37:38 2001 @@ -46,13 +46,11 @@ { struct nlm_args *argp = &req->a_args; struct nlm_lock *lock = &argp->lock; - struct dentry *dentry = fl->fl_file->f_dentry; - struct nfs_fh *fh = NFS_FH(dentry); memset(argp, 0, sizeof(*argp)); nlmclnt_next_cookie(&argp->cookie); argp->state = nsm_local_state; - memcpy(&lock->fh, fh, sizeof(*fh)); + memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(lock->fh)); lock->caller = system_utsname.nodename; lock->oh.data = req->a_owner; lock->oh.len = sprintf(req->a_owner, "%d@%s", diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/host.c linux/fs/lockd/host.c --- v2.2.18/fs/lockd/host.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/host.c Sun Mar 25 11:37:38 2001 @@ -26,7 +26,6 @@ #define NLM_HOST_REBIND (60 * HZ) #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) -#define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr) static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; static unsigned long next_gc = 0; @@ -37,24 +36,6 @@ static void nlm_gc_hosts(void); /* - * Find an NLM server handle in the cache. If there is none, create it. - */ -struct nlm_host * -nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version) -{ - return nlm_lookup_host(NULL, sin, proto, version); -} - -/* - * Find an NLM client handle in the cache. If there is none, create it. - */ -struct nlm_host * -nlmsvc_lookup_host(struct svc_rqst *rqstp) -{ - return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr, 0, 0); -} - -/* * Match the given host against client/address */ static inline int @@ -67,60 +48,33 @@ } /* - * Common host lookup routine for server & client + * Hash the host */ -struct nlm_host * -nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, - int proto, int version) +static inline int +nlm_hash_host(struct svc_client *clnt, struct sockaddr_in *sin) { - struct nlm_host *host, **hp; - u32 addr; - int hash; - - if (!clnt && !sin) { - printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n"); - return NULL; - } - - dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n", - (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version); - if (clnt) - hash = NLM_PTRHASH(clnt); - else - hash = NLM_ADDRHASH(sin->sin_addr.s_addr); + return NLM_PTRHASH(clnt); + return NLM_ADDRHASH(sin->sin_addr.s_addr); +} - /* Lock hash table */ - down(&nlm_host_sema); +static struct nlm_host * +nlm_create_host(struct svc_client *clnt, struct sockaddr_in *sin, + int proto, int version) +{ + struct nlm_host *host; + u32 addr; + int hash; if (time_after_eq(jiffies, next_gc)) nlm_gc_hosts(); - for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) { - if (host->h_version != version || host->h_proto != proto) - continue; - - if (nlm_match_host(host, clnt, sin)) { - if (hp != nlm_hosts + hash) { - *hp = host->h_next; - host->h_next = nlm_hosts[hash]; - nlm_hosts[hash] = host; - } - nlm_get_host(host); - up(&nlm_host_sema); - return host; - } + if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL))) { + dprintk("lockd: attempt to create host entry failed.\n"); + return NULL; } - /* special hack for nlmsvc_invalidate_client */ - if (sin == NULL) - goto nohost; - - /* Ooops, no host found, create it */ - dprintk("lockd: creating host entry\n"); - - if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL))) - goto nohost; + dprintk("lockd: creating host entry.\n"); memset(host, 0, sizeof(*host)); addr = sin->sin_addr.s_addr; @@ -135,22 +89,103 @@ host->h_version = version; host->h_proto = proto; host->h_authflavor = RPC_AUTH_UNIX; - host->h_rpcclnt = NULL; host->h_sema = MUTEX; - host->h_nextrebind = jiffies + NLM_HOST_REBIND; host->h_expires = jiffies + NLM_HOST_EXPIRE; host->h_count = 1; - host->h_state = 0; /* pseudo NSM state */ - host->h_nsmstate = 0; /* real NSM state */ host->h_exportent = clnt; + hash = nlm_hash_host(clnt, sin); host->h_next = nlm_hosts[hash]; nlm_hosts[hash] = host; if (++nrhosts > NLM_HOST_MAX) - next_gc = 0; + next_gc = jiffies; + + return host; +} + +static struct nlm_host * +__nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, + int proto, int version) +{ + struct nlm_host *host, **hp; + int hash; + + if (!clnt && !sin) { + printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n"); + return NULL; + } + + dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n", + (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version); + + hash = nlm_hash_host(clnt, sin); + for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) { + if (proto && host->h_proto != proto) + continue; + if (version && host->h_version != version) + continue; + + if (nlm_match_host(host, clnt, sin)) { + if (hp != nlm_hosts + hash) { + *hp = host->h_next; + host->h_next = nlm_hosts[hash]; + nlm_hosts[hash] = host; + } + nlm_get_host(host); + break; + } + } + return host; +} + +/* + * Common host lookup routine for server & client + */ +struct nlm_host * +nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, + int proto, int version) +{ + struct nlm_host *host; -nohost: + /* Lock hash table */ + down(&nlm_host_sema); + host = __nlm_lookup_host(clnt, sin, proto, version); + up(&nlm_host_sema); + return host; +} + +/* + * Find an NLM server handle in the cache. If there is none, create it. + */ +struct nlm_host * +nlmclnt_lookup_host(struct sockaddr_in *sin, int prot, int vers) +{ + struct nlm_host *host; + + /* Lock hash table */ + down(&nlm_host_sema); + if ((host = __nlm_lookup_host(NULL, sin, prot, vers)) == NULL) + host = nlm_create_host(NULL, sin, prot, vers); + up(&nlm_host_sema); + return host; +} + +/* + * Find an NLM client handle in the cache. If there is none, create it. + */ +struct nlm_host * +nlmsvc_lookup_host(struct svc_rqst *rqstp) +{ + struct nlm_host *host; + struct svc_client *clnt = rqstp->rq_client; + int prot = rqstp->rq_prot, + vers = rqstp->rq_vers; + + /* Lock hash table */ + down(&nlm_host_sema); + if ((host = __nlm_lookup_host(clnt, NULL, prot, vers)) == NULL) + host = nlm_create_host(clnt, &rqstp->rq_addr, prot, vers); up(&nlm_host_sema); return host; } @@ -206,6 +241,7 @@ clnt->cl_autobind = 1; /* turn on pmap queries */ xprt->nocong = 1; /* No congestion control for NLM */ + host->h_nextrebind = jiffies + NLM_HOST_REBIND; host->h_rpcclnt = clnt; } @@ -272,7 +308,7 @@ dprintk("lockd: nuking all hosts...\n"); for (i = 0; i < NLM_HOST_NRHASH; i++) { for (host = nlm_hosts[i]; host; host = host->h_next) - host->h_expires = 0; + host->h_expires = jiffies; } /* Then, perform a garbage collection pass */ @@ -326,15 +362,8 @@ *q = host->h_next; if (host->h_monitored) nsm_unmonitor(host); - if ((clnt = host->h_rpcclnt) != NULL) { - if (atomic_read(&clnt->cl_users)) { - printk(KERN_WARNING - "lockd: active RPC handle\n"); - clnt->cl_dead = 1; - } else { - rpc_destroy_client(host->h_rpcclnt); - } - } + if ((clnt = host->h_rpcclnt) != NULL) + rpc_shutdown_client(clnt); kfree(host); nrhosts--; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/mon.c linux/fs/lockd/mon.c --- v2.2.18/fs/lockd/mon.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/mon.c Sun Mar 25 11:37:38 2001 @@ -47,7 +47,7 @@ args.addr = host->h_addr.sin_addr.s_addr; args.prog = NLM_PROGRAM; - args.vers = 1; + args.vers = host->h_version; args.proc = NLMPROC_NSM_NOTIFY; memset(res, 0, sizeof(*res)); @@ -76,8 +76,10 @@ if (status < 0 || res.status != 0) printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); - else + else { host->h_monitored = 1; + host->h_nsmstate = res.state; + } return status; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/svc.c linux/fs/lockd/svc.c --- v2.2.18/fs/lockd/svc.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/svc.c Sun Mar 25 11:37:38 2001 @@ -77,9 +77,7 @@ nlmsvc_pid = current->pid; up(&lockd_start); - exit_mm(current); - current->session = 1; - current->pgrp = 1; + daemonize(); sprintf(current->comm, "lockd"); /* Process request with signals blocked. */ @@ -105,12 +103,8 @@ #ifdef RPC_DEBUG nlmsvc_grace_period = 10 * HZ; #else - if (nlm_grace_period) { - nlmsvc_grace_period += (1 + nlm_grace_period / nlm_timeout) - * nlm_timeout * HZ; - } else { - nlmsvc_grace_period += 5 * nlm_timeout * HZ; - } + nlmsvc_grace_period = (1 + nlm_grace_period / nlm_timeout) + * nlm_timeout * HZ; #endif grace_period_expire = nlmsvc_grace_period + jiffies; @@ -138,8 +132,11 @@ */ if (!nlmsvc_grace_period) { timeout = nlmsvc_retry_blocked(); - } else if (time_before(nlmsvc_grace_period, jiffies)) + } else if (time_before(grace_period_expire, jiffies)) { nlmsvc_grace_period = 0; + continue; + } else + timeout = nlmsvc_timeout; /* * Find a socket with data available and call its @@ -349,7 +346,7 @@ * Define NLM program and procedures */ static struct svc_version nlmsvc_version1 = { - 1, 16, nlmsvc_procedures, NULL + 1, 17, nlmsvc_procedures, NULL }; static struct svc_version nlmsvc_version3 = { 3, 24, nlmsvc_procedures, NULL diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/svc4proc.c linux/fs/lockd/svc4proc.c --- v2.2.18/fs/lockd/svc4proc.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/svc4proc.c Sun Mar 25 11:37:38 2001 @@ -422,6 +422,8 @@ void *resp) { struct sockaddr_in saddr = rqstp->rq_addr; + int vers = rqstp->rq_vers; + int prot = rqstp->rq_prot; struct nlm_host *host; dprintk("lockd: SM_NOTIFY called\n"); @@ -438,7 +440,7 @@ * reclaim all locks we hold on this server. */ saddr.sin_addr.s_addr = argp->addr; - if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) { + if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { nlmclnt_recovery(host, argp->state); nlm_release_host(host); } @@ -448,7 +450,7 @@ struct svc_client *clnt; saddr.sin_addr.s_addr = argp->addr; if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL - && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) { + && (host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) { nlmsvc_free_host_resources(host); nlm_release_host(host); } @@ -551,7 +553,8 @@ PROC(cancel_res, cancelres, norep, res, void), PROC(unlock_res, unlockres, norep, res, void), PROC(granted_res, grantedres, norep, res, void), - PROC(none, void, void, void, void), + /* statd callback */ + PROC(sm_notify, reboot, void, reboot, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), @@ -560,6 +563,4 @@ PROC(nm_lock, lockargs, res, args, res), PROC(free_all, notify, void, args, void), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void), }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/svclock.c linux/fs/lockd/svclock.c --- v2.2.18/fs/lockd/svclock.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/svclock.c Sun Mar 25 11:37:38 2001 @@ -53,9 +53,15 @@ dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); if (block->b_queued) nlmsvc_remove_block(block); - for (bp = &nlm_blocked; (b = *bp); bp = &b->b_next) - if (when < b->b_when) - break; + bp = &nlm_blocked; + if (when != NLM_NEVER) { + if ((when += jiffies) == NLM_NEVER) + when ++; + while ((b = *bp) && time_before_eq(b->b_when,when)) + bp = &b->b_next; + } else + while ((b = *bp)) + bp = &b->b_next; block->b_queued = 1; block->b_when = when; @@ -159,8 +165,7 @@ struct nlm_rqst *call; /* Create host handle for callback */ - host = nlmclnt_lookup_host(&rqstp->rq_addr, - rqstp->rq_prot, rqstp->rq_vers); + host = nlmsvc_lookup_host(rqstp); if (host == NULL) return NULL; @@ -169,10 +174,11 @@ goto failed; memset(block, 0, sizeof(*block)); - /* Set notifier function for VFS, and init args */ - lock->fl.fl_notify = nlmsvc_notify_blocked; if (!nlmclnt_setgrantargs(&block->b_call, lock)) goto failed_free; + + /* Set notifier function for VFS, and init args */ + block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked; block->b_call.a_args.cookie = *cookie; /* see above */ dprintk("lockd: created block %p...\n", block); @@ -263,12 +269,12 @@ down(&file->f_sema); for (block = file->f_blocks; block; block = next) { next = block->b_fnext; + if (host && block->b_host != host) + continue; if (action == NLM_ACT_MARK) block->b_host->h_inuse = 1; - else if (action == NLM_ACT_UNLOCK) { - if (host == NULL || host == block->b_host) - nlmsvc_delete_block(block, 1); - } + else if (action == NLM_ACT_UNLOCK) + nlmsvc_delete_block(block, 1); } up(&file->f_sema); return 0; @@ -455,8 +461,8 @@ posix_unblock_lock(fl); for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) { if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) { - svc_wake_up(block->b_daemon); nlmsvc_insert_block(block, 0); + svc_wake_up(block->b_daemon); return; } } @@ -516,7 +522,7 @@ if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) { printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", -error, __FUNCTION__); - nlmsvc_insert_block(block, jiffies + 10 * HZ); + nlmsvc_insert_block(block, 10 * HZ); up(&file->f_sema); return; } @@ -528,7 +534,7 @@ block->b_incall = 1; /* Schedule next grant callback in 30 seconds */ - nlmsvc_insert_block(block, jiffies + 30 * HZ); + nlmsvc_insert_block(block, 30 * HZ); /* Call the client */ nlm_get_host(block->b_call.a_host); @@ -566,13 +572,13 @@ * can be done, though. */ if (task->tk_status < 0) { /* RPC error: Re-insert for retransmission */ - timeout = jiffies + 10 * HZ; + timeout = 10 * HZ; } else if (block->b_done) { /* Block already removed, kill it for real */ timeout = 0; } else { /* Call was successful, now wait for client callback */ - timeout = jiffies + 60 * HZ; + timeout = 60 * HZ; } nlmsvc_insert_block(block, timeout); svc_wake_up(block->b_daemon); @@ -600,7 +606,7 @@ if ((block = nlmsvc_find_block(cookie)) != NULL) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { /* Try again in a couple of seconds */ - nlmsvc_insert_block(block, jiffies + 10 * HZ); + nlmsvc_insert_block(block, 10 * HZ); block = NULL; } else { /* Lock is now held by client, or has been rejected. @@ -631,7 +637,11 @@ dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", nlm_blocked, nlm_blocked? nlm_blocked->b_when : 0); - while ((block = nlm_blocked) && block->b_when <= jiffies) { + while ((block = nlm_blocked)) { + if (block->b_when == NLM_NEVER) + break; + if (time_after(block->b_when,jiffies)) + break; dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", block, block->b_when, block->b_done); if (block->b_done) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/svcproc.c linux/fs/lockd/svcproc.c --- v2.2.18/fs/lockd/svcproc.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/svcproc.c Sun Mar 25 11:37:38 2001 @@ -435,6 +435,8 @@ void *resp) { struct sockaddr_in saddr = rqstp->rq_addr; + int vers = rqstp->rq_vers; + int prot = rqstp->rq_prot; struct nlm_host *host; dprintk("lockd: SM_NOTIFY called\n"); @@ -450,8 +452,8 @@ /* Obtain the host pointer for this NFS server and try to * reclaim all locks we hold on this server. */ - saddr.sin_addr.s_addr = argp->addr; - if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) { + saddr.sin_addr.s_addr = htonl(argp->addr); + if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { nlmclnt_recovery(host, argp->state); nlm_release_host(host); } @@ -461,7 +463,7 @@ struct svc_client *clnt; saddr.sin_addr.s_addr = argp->addr; if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL - && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) { + && (host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) { nlmsvc_free_host_resources(host); nlm_release_host(host); } @@ -585,7 +587,8 @@ PROC(cancel_res, cancelres, norep, res, void), PROC(unlock_res, unlockres, norep, res, void), PROC(granted_res, grantedres, norep, res, void), - PROC(none, void, void, void, void), + /* statd callback */ + PROC(sm_notify, reboot, void, reboot, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), PROC(none, void, void, void, void), @@ -594,6 +597,4 @@ PROC(nm_lock, lockargs, res, args, res), PROC(free_all, notify, void, args, void), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void), }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/svcshare.c linux/fs/lockd/svcshare.c --- v2.2.18/fs/lockd/svcshare.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/svcshare.c Sun Mar 25 11:37:38 2001 @@ -95,14 +95,16 @@ shpp = &file->f_shares; while ((share = *shpp) != NULL) { + if (host && host != share->s_host) { + shpp = &share->s_next; + continue; + } if (action == NLM_ACT_MARK) share->s_host->h_inuse = 1; else if (action == NLM_ACT_UNLOCK) { - if (host == NULL || host == share->s_host) { - *shpp = share->s_next; - kfree(share); - continue; - } + *shpp = share->s_next; + kfree(share); + continue; } shpp = &share->s_next; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/lockd/svcsubs.c linux/fs/lockd/svcsubs.c --- v2.2.18/fs/lockd/svcsubs.c Sun Mar 25 11:28:33 2001 +++ linux/fs/lockd/svcsubs.c Sun Mar 25 11:37:38 2001 @@ -44,6 +44,10 @@ * Note that we open the file O_RDONLY even when creating write locks. * This is not quite right, but for now, we assume the client performs * the proper R/W checking. + * + * BEWARE: + * The cast to struct knfs_fh in this routine, imposes an alignment + * requirement on (struct nfs_fh)->data for some platforms. */ u32 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, @@ -63,8 +67,7 @@ down(&nlm_file_sema); for (file = nlm_files[hash]; file; file = file->f_next) { - if (file->f_handle.fh_dcookie == fh->fh_dcookie && - !memcmp(&file->f_handle, fh, sizeof(*fh))) + if (!memcmp(&file->f_handle, fh, sizeof(*fh))) goto found; } @@ -147,6 +150,7 @@ struct inode *inode = nlmsvc_file_inode(file); struct file_lock *fl; struct nlm_host *lockhost; + int status = 0; again: file->f_locks = 0; @@ -157,29 +161,27 @@ /* update current lock count */ file->f_locks++; lockhost = (struct nlm_host *) fl->fl_owner; + if (host && lockhost != host) + continue; if (action == NLM_ACT_MARK) lockhost->h_inuse = 1; else if (action == NLM_ACT_CHECK) - return 1; + status = 1; else if (action == NLM_ACT_UNLOCK) { - struct file_lock lock = *fl; - - if (host && lockhost != host) - continue; + struct file_lock lock; + lock = *fl; lock.fl_type = F_UNLCK; - lock.fl_start = 0; - lock.fl_end = NLM_OFFSET_MAX; if (posix_lock_file(&file->f_file, &lock, 0) < 0) { printk("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__); - return 1; - } - goto again; + status = 1; + } else + goto again; } } - return 0; + return status; } /* @@ -208,6 +210,7 @@ { struct nlm_file *file, **fp; int i; + int res = 0; down(&nlm_file_sema); for (i = 0; i < FILE_NRHASH; i++) { @@ -215,24 +218,21 @@ while ((file = *fp) != NULL) { /* Traverse locks, blocks and shares of this file * and update file->f_locks count */ - if (nlm_inspect_file(host, file, action)) { - up(&nlm_file_sema); - return 1; - } + if (nlm_inspect_file(host, file, action)) + res = 1; - /* No more references to this file. Let go of it. */ - if (!file->f_blocks && !file->f_locks - && !file->f_shares && !file->f_count) { - *fp = file->f_next; - nlmsvc_ops->fclose(&file->f_file); - kfree(file); - } else { + if (file->f_blocks || file->f_locks + || file->f_shares || file->f_count) { fp = &file->f_next; + continue; } + *fp = file->f_next; + nlmsvc_ops->fclose(&file->f_file); + kfree(file); } } up(&nlm_file_sema); - return 0; + return res; } /* @@ -298,7 +298,7 @@ if ((host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) { dprintk("lockd: invalidating client for %s\n", host->h_name); nlmsvc_free_host_resources(host); - host->h_expires = 0; + host->h_expires = jiffies; nlm_release_host(host); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/locks.c linux/fs/locks.c --- v2.2.18/fs/locks.c Sun Mar 25 11:28:33 2001 +++ linux/fs/locks.c Sun Mar 25 11:37:38 2001 @@ -268,20 +268,22 @@ while ((waiter = blocker->fl_nextblock) != NULL) { /* N.B. Is it possible for the notify function to block?? */ + if (!wait) { + /* Remove waiter from the block list, because by the + * time it wakes up blocker won't exist any more. + */ + locks_delete_block(blocker, waiter); + } if (waiter->fl_notify) waiter->fl_notify(waiter); - wake_up(&waiter->fl_wait); + else + wake_up(&waiter->fl_wait); if (wait) { /* Let the blocked process remove waiter from the * block list when it gets scheduled. */ current->policy |= SCHED_YIELD; schedule(); - } else { - /* Remove waiter from the block list, because by the - * time it wakes up blocker won't exist any more. - */ - locks_delete_block(blocker, waiter); } } return; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.2.18/fs/nfs/dir.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/dir.c Sun Mar 25 11:37:38 2001 @@ -45,6 +45,7 @@ static int nfs_safe_remove(struct dentry *); static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *); +static loff_t nfs_dir_llseek(struct file *, loff_t, int); static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *); static int nfs_create(struct inode *, struct dentry *, int); @@ -58,7 +59,7 @@ struct inode *, struct dentry *); static struct file_operations nfs_dir_operations = { - NULL, /* lseek - default */ + nfs_dir_llseek, /* llseek */ nfs_dir_read, /* read - bad */ NULL, /* write - bad */ nfs_readdir, /* readdir */ @@ -131,7 +132,7 @@ struct file *file = desc->file; struct dentry *dir = file->f_dentry; struct inode *inode = dir->d_inode; - struct nfs_fattr dir_attr; + struct rpc_cred *cred = nfs_file_cred(file); void *buffer = (void *)page_address(page); int plus = NFS_USE_READDIRPLUS(inode); int error; @@ -139,11 +140,9 @@ dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->offset); again: - error = NFS_CALL(readdir, inode, (dir, &dir_attr, - nfs_file_cred(file), + error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer, - NFS_SERVER(inode)->dtsize, plus)); - nfs_refresh_inode(inode, &dir_attr); + NFS_SERVER(inode)->dtsize, plus); /* We requested READDIRPLUS, but the server doesn't grok it */ if (desc->plus && error == -ENOTSUPP) { NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; @@ -339,7 +338,7 @@ struct file *file = desc->file; struct dentry *dir = file->f_dentry; struct inode *inode = dir->d_inode; - struct nfs_fattr dir_attr; + struct rpc_cred *cred = nfs_file_cred(file); struct page *page = NULL; unsigned long cache_page; u32 *p; @@ -358,11 +357,8 @@ } page = page_cache_entry(cache_page); p = (u32 *)page_address(page); - status = NFS_CALL(readdir, inode, (dir, &dir_attr, - nfs_file_cred(file), - desc->target, p, - NFS_SERVER(inode)->dtsize, 0)); - nfs_refresh_inode(inode, &dir_attr); + status = NFS_PROTO(inode)->readdir(inode, cred, desc->target, p, + NFS_SERVER(inode)->dtsize, 0); if (status >= 0) { p = desc->decode(p, desc->entry, 0); if (IS_ERR(p)) @@ -452,6 +448,22 @@ return 0; } +/* + * nfs_dir_llseek(): cater for the fact that NFS(v2|v3) readdir + * cookies take (32|64)-bit unsigned values. + */ +static loff_t nfs_dir_llseek(struct file *file, loff_t offset, int origin) +{ + /* We disallow SEEK_CUR and SEEK_END */ + if (origin != 0) + return -EINVAL; + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++global_event; + } + return (offset > 0) ? offset : 0; +} /* * Whenever an NFS operation succeeds, we know that the dentry @@ -521,11 +533,10 @@ */ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) { - struct dentry *dir = dentry->d_parent; - struct inode *inode = dentry->d_inode, - *dir_i = dir->d_inode; + struct inode *dir = dentry->d_parent->d_inode; + struct inode *inode = dentry->d_inode; struct nfs_fh fhandle; - struct nfs_fattr fattr, dir_attr; + struct nfs_fattr fattr; int error; /* @@ -541,7 +552,7 @@ if (is_bad_inode(inode)) { dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n", - dir->d_name.name, dentry->d_name.name); + dentry->d_parent->d_name.name, dentry->d_name.name); goto out_bad; } @@ -549,7 +560,7 @@ goto out_valid; if (IS_ROOT(dentry)) { - __nfs_revalidate_inode(dentry); + __nfs_revalidate_inode(NFS_SERVER(inode), inode); goto out_valid_renew; } @@ -559,8 +570,7 @@ /* * Do a new lookup and check the dentry attributes. */ - error = NFS_CALL(lookup, dir_i, (dir, &dir_attr, - &dentry->d_name, &fhandle, &fattr)); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error < 0) goto out_bad; @@ -570,18 +580,12 @@ NFS_FILEID(inode) != fattr.fileid) goto out_bad; - /* Filehandle matches? */ - if (NFS_FH(dentry)->size == 0) - goto out_bad; + /* Ok, remember that we successfully checked it.. */ + nfs_refresh_inode(inode, &fattr); - if (NFS_FH(dentry)->size != fhandle.size || - memcmp(NFS_FH(dentry)->data, fhandle.data, fhandle.size)) + if (nfs_inode_is_stale(inode, &fhandle, &fattr)) goto out_bad; - /* Ok, remeber that we successfully checked it.. */ - nfs_refresh_inode(inode, &fattr); - nfs_refresh_inode(dir_i, &dir_attr); - out_valid_renew: nfs_renew_times(dentry); out_valid: @@ -593,10 +597,9 @@ if (have_submounts(dentry)) goto out_valid; d_drop(dentry); - if (dentry->d_parent->d_inode) - NFS_CACHEINV(dentry->d_parent->d_inode); + nfs_zap_caches(dir); if (inode && S_ISDIR(inode->i_mode)) - NFS_CACHEINV(inode); + nfs_zap_caches(inode); return 0; } @@ -611,33 +614,6 @@ } } -__inline__ struct nfs_fh *nfs_fh_alloc(void) -{ - struct nfs_fh *p; - - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return NULL; - memset(p, 0, sizeof(*p)); - return p; -} - -__inline__ void nfs_fh_free(struct nfs_fh *p) -{ - kfree(p); -} - -/* - * Called when the dentry is being freed to release private memory. - */ -static void nfs_dentry_release(struct dentry *dentry) -{ - if (dentry->d_fsdata) { - nfs_fh_free(dentry->d_fsdata); - dentry->d_fsdata = NULL; - } -} - /* * Called when the dentry loses inode. * We use it to clean up silly-renamed files. @@ -654,44 +630,33 @@ NULL, /* d_hash */ NULL, /* d_compare */ nfs_dentry_delete, /* d_delete(struct dentry *) */ - nfs_dentry_release, /* d_release(struct dentry *) */ + NULL, /* d_release(struct dentry *) */ nfs_dentry_iput /* d_iput */ }; -static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry) +static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry) { - struct dentry *dir = dentry->d_parent; struct inode *inode; int error; struct nfs_fh fhandle; - struct nfs_fattr fattr, dir_attr; + struct nfs_fattr fattr; dfprintk(VFS, "NFS: lookup(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen) + if (dentry->d_name.len > NFS_SERVER(dir)->namelen) goto out; dentry->d_op = &nfs_dentry_operations; - if (!dentry->d_fsdata) { - dentry->d_fsdata = nfs_fh_alloc(); - if (!dentry->d_fsdata) { - error = -ENOMEM; - goto out; - } - } - #if NFS_FIXME inode = nfs_dircache_lookup(dir_i, dentry); if (inode) goto no_entry; #endif - error = NFS_CALL(lookup, dir_i, (dir, &dir_attr, - &dentry->d_name, &fhandle, &fattr)); - nfs_refresh_inode(dir_i, &dir_attr); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); inode = NULL; if (error == -ENOENT) goto no_entry; @@ -734,16 +699,15 @@ * that the operation succeeded on the server, but an error in the * reply path made it appear to have failed. */ -static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode) +static int nfs_create(struct inode *dir, struct dentry *dentry, int mode) { - struct dentry *dir = dentry->d_parent; struct iattr attr; - struct nfs_fattr fattr, dir_attr; + struct nfs_fattr fattr; struct nfs_fh fhandle; int error; dfprintk(VFS, "NFS: create(%x/%ld, %s\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); #ifdef NFSD_BROKEN_UID /* We set uid/gid in the request because IBM's broken nfsd @@ -767,10 +731,9 @@ * select the appropriate create strategy. Currently open_namei * does not pass the create flags. */ - nfs_zap_caches(dir_i); - error = NFS_CALL(create, dir_i, (dir, &dir_attr, &dentry->d_name, - &attr, 0, &fhandle, &fattr)); - nfs_refresh_inode(dir_i, &dir_attr); + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->create(dir, &dentry->d_name, + &attr, 0, &fhandle, &fattr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error || fhandle.size == 0) @@ -781,16 +744,15 @@ /* * See comments for nfs_proc_create regarding failed operations. */ -static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev) +static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) { - struct dentry *dir = dentry->d_parent; struct iattr attr; - struct nfs_fattr fattr, dir_attr; + struct nfs_fattr fattr; struct nfs_fh fhandle; int error; dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); #ifdef NFSD_BROKEN_UID attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID; @@ -803,10 +765,9 @@ #endif - nfs_zap_caches(dir_i); - error = NFS_CALL(mknod, dir_i, (dir, &dir_attr, &dentry->d_name, - &attr, rdev, &fhandle, &fattr)); - nfs_refresh_inode(dir_i, &dir_attr); + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, + &attr, rdev, &fhandle, &fattr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error || fhandle.size == 0) @@ -817,16 +778,15 @@ /* * See comments for nfs_proc_create regarding failed operations. */ -static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode) +static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - struct dentry *dir = dentry->d_parent; struct iattr attr; - struct nfs_fattr fattr, dir_attr; + struct nfs_fattr fattr; struct nfs_fh fhandle; int error; dfprintk(VFS, "NFS: mkdir(%x/%ld, %s)\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); #ifdef NFSD_BROKEN_UID attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID; @@ -838,10 +798,8 @@ attr.ia_mode = mode | S_IFDIR; #endif - nfs_zap_caches(dir_i); - error = NFS_CALL(mkdir, dir_i, (dir, &dir_attr, - &dentry->d_name, &attr, &fhandle, &fattr)); - nfs_refresh_inode(dir_i, &dir_attr); + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle, &fattr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); @@ -850,18 +808,15 @@ return error; } -static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry) +static int nfs_rmdir(struct inode *dir, struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; - struct nfs_fattr dir_attr; int error; dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); - nfs_zap_caches(dir_i); - error = NFS_CALL(rmdir, dir_i, (dir, &dir_attr, &dentry->d_name)); - nfs_refresh_inode(dir_i, &dir_attr); + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); /* Free the inode */ if (!error) @@ -925,12 +880,10 @@ return sdentry; } -static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry) +static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; static unsigned int sillycounter = 0; - struct nfs_fattr dir_attr; - const int i_inosize = sizeof(dir_i->i_ino)*2; + const int i_inosize = sizeof(dir->i_ino)*2; const int countersize = sizeof(sillycounter)*2; const int slen = strlen(".nfs") + i_inosize + countersize; struct qstr qsilly; @@ -985,12 +938,10 @@ goto out; } while(sdentry->d_inode != NULL); /* need negative lookup */ - nfs_zap_caches(dir_i); + nfs_zap_caches(dir); qsilly.name = silly; qsilly.len = strlen(silly); - error = NFS_CALL(rename, dir_i, (dir, &dir_attr, &dentry->d_name, - dir, &dir_attr, &qsilly)); - nfs_refresh_inode(dir_i, &dir_attr); + error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly); if (!error) { nfs_renew_times(dentry); d_move(dentry, sdentry); @@ -1011,9 +962,7 @@ */ static int nfs_safe_remove(struct dentry *dentry) { - struct nfs_fattr dir_attr; - struct dentry *dir = dentry->d_parent; - struct inode *dir_i = dir->d_inode, + struct inode *dir = dentry->d_parent->d_inode, *inode = dentry->d_inode; int error = 0, rehash = 0; @@ -1049,11 +998,10 @@ goto out; } - nfs_zap_caches(dir_i); + nfs_zap_caches(dir); if (inode) NFS_CACHEINV(inode); - error = NFS_CALL(remove, dir_i, (dir, &dir_attr, &dentry->d_name)); - nfs_refresh_inode(dir_i, &dir_attr); + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); if (error < 0) goto out; @@ -1096,20 +1044,19 @@ } static int -nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname) +nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { - struct dentry *dir = dentry->d_parent; - struct nfs_fattr dir_attr, sym_attr; + struct nfs_fattr sym_attr; struct nfs_fh sym_fh; struct iattr attr; struct qstr qsymname; int error, mode, maxlen; dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname); + dir->i_dev, dir->i_ino, dentry->d_name.name, symname); error = -ENAMETOOLONG; - maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN; + maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN; if (strlen(symname) > maxlen) goto out; @@ -1137,11 +1084,9 @@ qsymname.name = symname; qsymname.len = strlen(symname); - nfs_zap_caches(dir_i); - error = NFS_CALL(symlink, dir_i, (dir, &dir_attr, - &dentry->d_name, &qsymname, &attr, - &sym_fh, &sym_attr)); - nfs_refresh_inode(dir_i, &dir_attr); + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname, + &attr, &sym_fh, &sym_attr); if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) { error = nfs_instantiate(dentry, &sym_fh, &sym_attr); } else { @@ -1157,11 +1102,9 @@ } static int -nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) +nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; struct inode *inode = old_dentry->d_inode; - struct nfs_fattr old_attr, dir_attr; int error; dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n", @@ -1174,12 +1117,9 @@ * we can't use the existing dentry. */ d_drop(dentry); - nfs_zap_caches(dir_i); + nfs_zap_caches(dir); NFS_CACHEINV(inode); - error = NFS_CALL(link, inode, (old_dentry, &old_attr, - dir, &dir_attr, &dentry->d_name)); - nfs_refresh_inode(inode, &old_attr); - nfs_refresh_inode(dir_i, &dir_attr); + error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); return error; } @@ -1214,7 +1154,6 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct nfs_fattr old_attr, new_attr; struct inode * old_inode = old_dentry->d_inode; struct inode * new_inode = new_dentry->d_inode; struct dentry * dentry = NULL, *rehash = NULL; @@ -1296,12 +1235,8 @@ nfs_zap_caches(new_dir); nfs_zap_caches(old_dir); - error = NFS_CALL(rename, old_dir, - (old_dentry->d_parent, &old_attr, &old_dentry->d_name, - new_dentry->d_parent, &new_attr, &new_dentry->d_name)); - nfs_refresh_inode(old_dir, &old_attr); - nfs_refresh_inode(new_dir, &new_attr); - + error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, + new_dir, &new_dentry->d_name); out: /* Update the dcache if needed */ if (rehash) @@ -1315,14 +1250,11 @@ } int -nfs_permission(struct inode *i, int msk) +nfs_permission(struct inode *inode, int mask) { - struct nfs_fattr fattr; - struct dentry *de = NULL; - int err = vfs_permission(i, msk); - struct list_head *start, *tmp; + int error = vfs_permission(inode, mask); - if (!NFS_PROTO(i)->access) + if (!NFS_PROTO(inode)->access) goto out; /* * Trust UNIX mode bits except: @@ -1332,28 +1264,18 @@ * 3) When ACLs may overturn a negative answer */ if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH) && (current->fsuid != 0) && (current->fsgid != 0) - && err != -EACCES) + && error != -EACCES) goto out; - tmp = start = &i->i_dentry; - while ((tmp = tmp->next) != start) { - de = list_entry(tmp, struct dentry, d_alias); - if (de->d_inode == i) - break; - } - if (!de || de->d_inode != i) - return 0; + error = NFS_PROTO(inode)->access(inode, mask, 0); - err = NFS_CALL(access, i, (de, msk, &fattr, 0)); - - if (err == -EACCES && NFS_CLIENT(i)->cl_droppriv && + if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv && current->uid != 0 && current->gid != 0 && (current->fsuid != current->uid || current->fsgid != current->gid)) - err = NFS_CALL(access, i, (de, msk, &fattr, 1)); + error = NFS_PROTO(inode)->access(inode, mask, 1); - nfs_refresh_inode(i, &fattr); out: - return err; + return error; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/file.c linux/fs/nfs/file.c --- v2.2.18/fs/nfs/file.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/file.c Sun Mar 25 11:37:38 2001 @@ -111,13 +111,14 @@ nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos) { struct dentry * dentry = file->f_dentry; + struct inode * inode = dentry->d_inode; ssize_t result; dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long) count, (unsigned long) *ppos); - result = nfs_revalidate_inode(dentry); + result = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (!result) result = generic_file_read(file, buf, count, ppos); return result; @@ -127,12 +128,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) { struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; int status; dfprintk(VFS, "nfs: mmap(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); - status = nfs_revalidate_inode(dentry); + status = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (!status) status = generic_file_mmap(file, vma); return status; @@ -182,10 +184,8 @@ rpages = NFS_SERVER(inode)->rpages; result = nfs_pagein_inode(inode, index, rpages); if (result < 0) - goto out_bad; + return result; return 0; - out_bad: - return result; } /* @@ -205,7 +205,7 @@ result = -EBUSY; if (IS_SWAPFILE(inode)) goto out_swapfile; - result = nfs_revalidate_inode(dentry); + result = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (result) goto out; @@ -265,7 +265,9 @@ * Flush all pending writes before doing anything * with locks.. */ + down(&inode->i_sem); status = nfs_wb_all(inode); + up(&inode->i_sem); if (status < 0) goto out_unlock; @@ -280,8 +282,10 @@ out_unlock: out_ok: if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type != F_UNLCK) { + down(&inode->i_sem); nfs_wb_all(inode); /* we may have slept */ nfs_zap_caches(inode); + up(&inode->i_sem); } return status; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.2.18/fs/nfs/inode.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/inode.c Sun Mar 25 11:37:38 2001 @@ -40,11 +40,10 @@ #include #include -#define CONFIG_NFS_SNAPSHOT 1 #define NFSDBG_FACILITY NFSDBG_VFS #define NFS_PARANOIA 1 -static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *); +static struct inode * __nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); static void nfs_read_inode(struct inode *); static void nfs_put_inode(struct inode *); @@ -53,8 +52,6 @@ static void nfs_put_super(struct super_block *); static int nfs_statfs(struct super_block *, struct statfs *, int); static void nfs_umount_begin(struct super_block *); -static struct nfs_file *nfs_file_alloc(void); -static void nfs_file_free(struct nfs_file *p); static struct super_operations nfs_sops = { nfs_read_inode, /* read inode */ @@ -256,7 +253,7 @@ return NULL; } - inode = __nfs_fhget(sb, &fattr); + inode = __nfs_fhget(sb, rootfh, &fattr); return inode; } @@ -273,9 +270,7 @@ struct nfs_server *server; struct rpc_xprt *xprt = 0; struct rpc_clnt *clnt = 0; - struct nfs_fh *root_fh = NULL, - *root = &data->root, - fh; + struct nfs_fh fh; struct inode *root_inode = NULL; unsigned int authflavor; struct sockaddr_in srvaddr; @@ -290,7 +285,6 @@ goto failure; } - memset(&fh, 0, sizeof(fh)); if (data->version != NFS_MOUNT_VERSION) { printk(KERN_WARNING "nfs warning: mount version %s than kernel\n", data->version < NFS_MOUNT_VERSION ? "older" : "newer"); @@ -298,12 +292,21 @@ data->namlen = 0; if (data->version < 3) data->bsize = 0; - if (data->version < 4) { + if (data->version < 4) data->flags &= ~NFS_MOUNT_VER3; - root = &fh; - root->size = NFS2_FHSIZE; - memcpy(root->data, data->old_root.data, NFS2_FHSIZE); + } + + memset(&fh, 0, sizeof(fh)); + if (data->version < 4) { + fh.size = NFS2_FHSIZE; + memcpy(fh.data, data->old_root.data, NFS2_FHSIZE); + } else { + fh.size = (data->flags & NFS_MOUNT_VER3) ? data->root.size : NFS2_FHSIZE; + if (fh.size > sizeof(fh.data)) { + printk(KERN_WARNING "NFS: mount program passes invalid filehandle!\n"); + goto failure; } + memcpy(fh.data, data->root.data, fh.size); } /* We now require that the mount process passes the remote address */ @@ -351,19 +354,15 @@ if (data->flags & NFS_MOUNT_VER3) { #ifdef CONFIG_NFS_V3 server->rpc_ops = &nfs_v3_clientops; - NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS3_FHSIZE; + NFS_SB_FHSIZE(sb) = NFS3_FHSIZE; version = 3; - if (data->version < 4) { - printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n"); - goto failure_unlock; - } #else printk(KERN_NOTICE "NFS: NFSv3 not supported.\n"); goto failure_unlock; #endif } else { server->rpc_ops = &nfs_v2_clientops; - NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS2_FHSIZE; + NFS_SB_FHSIZE(sb) = NFS2_FHSIZE; version = 2; } @@ -419,17 +418,12 @@ * Keep the super block locked while we try to get * the root fh attributes. */ - root_fh = nfs_fh_alloc(); - if (!root_fh) - goto out_no_fh; - memcpy((u8*)root_fh, (u8*)root, sizeof(*root_fh)); - /* Did getting the root inode fail? */ - if ((root->size > NFS_SB_FHSIZE(sb) - || ! (root_inode = nfs_get_root(sb, root))) + if ((fh.size > NFS_SB_FHSIZE(sb) + || ! (root_inode = nfs_get_root(sb, &fh))) && (data->flags & NFS_MOUNT_VER3)) { data->flags &= ~NFS_MOUNT_VER3; - nfs_fh_free(root_fh); + fh.size = NFS2_FHSIZE; rpciod_down(); rpc_shutdown_client(server->client); goto nfsv3_try_again; @@ -441,11 +435,9 @@ goto failure_put_root; sb->s_root->d_op = &nfs_dentry_operations; - sb->s_root->d_fsdata = root_fh; - sb->u.nfs_sb.s_root = root_fh; /* Get some general file system info */ - if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) { + if (server->rpc_ops->statfs(server, &fh, &fsinfo) >= 0) { if (server->namelen == 0) server->namelen = fsinfo.namelen; } else { @@ -518,9 +510,6 @@ failure_put_root: if (root_inode) iput(root_inode); - if (root_fh) - nfs_fh_free(root_fh); - out_no_fh: rpciod_down(); failure_unlock: @@ -552,7 +541,7 @@ struct nfs_fsinfo res; struct statfs tmp; - error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res); + error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res); if (error) { printk(KERN_NOTICE "nfs_statfs: statfs error = %d\n", -error); memset(&res, 0, sizeof(res)); @@ -590,46 +579,6 @@ #endif /* - * Free all unused dentries in an inode's alias list. - * - * Subtle note: we have to be very careful not to cause - * any IO operations with the stale dentries, as this - * could cause file corruption. But since the dentry - * count is 0 and all pending IO for a dentry has been - * flushed when the count went to 0, we're safe here. - * Also returns the number of unhashed dentries - */ -static int -nfs_free_dentries(struct inode *inode) -{ - struct list_head *tmp, *head = &inode->i_dentry; - int unhashed; - -restart: - tmp = head->next; - unhashed = 0; - while (tmp != head) { - struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); - dget(dentry); - if (!list_empty(&dentry->d_subdirs)) - shrink_dcache_parent(dentry); - dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - dentry->d_count, !list_empty(&dentry->d_hash)); - if (dentry->d_count == 1) { - d_drop(dentry); - dput(dentry); - goto restart; - } - if (list_empty(&dentry->d_hash)) - unhashed++; - tmp = tmp->next; - dput(dentry); - } - return unhashed; -} - -/* * Zap the caches. */ void nfs_zap_caches(struct inode *inode) @@ -657,7 +606,7 @@ * Fill in inode information from the fattr. */ static void -nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr) +nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr) { /* * Check whether the mode has been set, as we only want to @@ -697,25 +646,15 @@ NFS_CACHE_ISIZE(inode) = fattr->size; NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; + memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)); } nfs_refresh_inode(inode, fattr); } -static struct inode * -nfs_make_new_inode(struct super_block *sb, struct nfs_fattr *fattr) -{ - struct inode *inode = get_empty_inode(); - - if (!inode) - return NULL; - inode->i_sb = sb; - inode->i_dev = sb->s_dev; - inode->i_flags = 0; - inode->i_ino = nfs_fattr_to_ino_t(fattr); - nfs_read_inode(inode); - nfs_fill_inode(inode, fattr); - return inode; -} +struct nfs_find_desc { + struct nfs_fh *fh; + struct nfs_fattr *fattr; +}; /* * In NFSv3 we can have 64bit inode numbers. In order to support @@ -726,50 +665,39 @@ static int nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque) { - struct nfs_fattr *fattr = (struct nfs_fattr *)opaque; + struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; + struct nfs_fh *fh = desc->fh; + struct nfs_fattr *fattr = desc->fattr; + if (NFS_FSID(inode) != fattr->fsid) return 0; if (NFS_FILEID(inode) != fattr->fileid) return 0; - if (inode->i_mode && - (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT)) - return 0; - if (is_bad_inode(inode)) - return 0; - if (NFS_FLAGS(inode) & NFS_INO_STALE) + if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0) return 0; return 1; } -static int -nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr) +int +nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr) { - int unhashed; - int is_stale = 0; - if (inode->i_mode && - (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT)) - is_stale = 1; + /* Empty inodes are not stale */ + if (!inode->i_mode) + return 0; - if (is_bad_inode(inode)) - is_stale = 1; + if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT)) + return 1; - /* - * If the inode seems stale, free up cached dentries. - */ - unhashed = nfs_free_dentries(inode); + if (is_bad_inode(inode)) + return 1; - /* Assume we're holding an i_count - * - * NB: sockets sometimes have volatile file handles - * don't invalidate their inodes even if all dentries are - * unhashed. - */ - if (unhashed && inode->i_count == unhashed + 1 - && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode)) - is_stale = 1; + /* Has the filehandle changed? If so is the old one stale? */ + if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 && + __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE) + return 1; - return is_stale; + return 0; } /* @@ -778,8 +706,6 @@ * the vfs read_inode function because there is no way to pass the * file handle or current attributes into the read_inode function. * - * We provide a special check for NetApp .snapshot directories to avoid - * inode aliasing problems. All snapshot inodes are anonymous (unhashed). */ struct inode * nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle, @@ -791,40 +717,16 @@ dentry->d_parent->d_name.name, dentry->d_name.name, (long long) fattr->fileid); - /* Install the file handle in the dentry */ - memcpy(NFS_FH(dentry), (u8*)fhandle, sizeof(*fhandle)); - -#ifdef CONFIG_NFS_SNAPSHOT - /* - * Check for NetApp snapshot dentries, and get an - * unhashed inode to avoid aliasing problems. - */ - if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) || - (dentry->d_name.len == 9 && - memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) { - struct inode *inode = nfs_make_new_inode(sb, fattr); - if (!inode) - goto out; - inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT; - dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino); - out: - return inode; - } -#endif - return __nfs_fhget(sb, fattr); + return __nfs_fhget(sb, fhandle, fattr); } /* * Look up the inode by super block and fattr->fileid. - * - * Note carefully the special handling of busy inodes (i_count > 1). - * With the kernel 2.1.xx dcache all inodes except hard links must - * have i_count == 1 after iget(). Otherwise, it indicates that the - * server has reused a fileid (i_ino) and we have a stale inode. */ static struct inode * -__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr) +__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) { + struct nfs_find_desc desc = { fh, fattr }; struct inode *inode = NULL; unsigned long ino; @@ -833,34 +735,12 @@ ino = nfs_fattr_to_ino_t(fattr); - while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) { - - /* - * Check for busy inodes, and attempt to get rid of any - * unused local references. If successful, we release the - * inode and try again. - * - * Note that the busy test uses the values in the fattr, - * as the inode may have become a different object. - * (We can probably handle modes changes here, too.) - */ - if (!nfs_inode_is_stale(inode,fattr)) - break; - - dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n", - inode->i_ino, inode->i_count); - /* Mark the inode as being stale */ - NFS_FLAGS(inode) |= NFS_INO_STALE; - nfs_zap_caches(inode); - iput(inode); - } - - if (!inode) + if (!(inode = iget4(sb, ino, nfs_find_actor, &desc))) goto out_no_inode; - nfs_fill_inode(inode, fattr); - dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n", - inode->i_dev, inode->i_ino, inode->i_count); + nfs_fill_inode(inode, fh, fattr); + dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n", + inode->i_dev, (long long)NFS_FILEID(inode), inode->i_count); out: return inode; @@ -896,7 +776,7 @@ goto out; /* Now perform the setattr call */ - error = NFS_CALL(setattr, inode, (dentry, &fattr, attr)); + error = NFS_PROTO(inode)->setattr(inode, &fattr, attr); if (error || !(fattr.valid & NFS_ATTR_FATTR)) { nfs_zap_caches(inode); goto out; @@ -954,52 +834,27 @@ int nfs_revalidate(struct dentry *dentry) { - return nfs_revalidate_inode(dentry); -} - -static __inline__ struct nfs_file *nfs_file_alloc(void) -{ - struct nfs_file *p; - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (p) { - memset(p, 0, sizeof(*p)); - p->magic = NFS_FILE_MAGIC; - } - return p; -} - -static __inline__ void nfs_file_free(struct nfs_file *p) -{ - if (p->magic == NFS_FILE_MAGIC) { - p->magic = 0; - kfree(p); - } else - printk(KERN_ERR "NFS: extra file info corrupted!\n"); + struct inode *inode = dentry->d_inode; + return nfs_revalidate_inode(NFS_SERVER(inode), inode); } int nfs_open(struct inode *inode, struct file *filp) { struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth; - struct nfs_file *data; + struct rpc_cred *cred = rpcauth_lookupcred(auth, 0); - data = nfs_file_alloc(); - if (!data) - return -ENOMEM; - data->cred = rpcauth_lookupcred(auth, 0); - filp->private_data = data; + filp->private_data = cred; return 0; } int nfs_release(struct inode *inode, struct file *filp) { - struct nfs_file *data = NFS_FILE(filp); struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth; struct rpc_cred *cred; cred = nfs_file_cred(filp); if (cred) rpcauth_releasecred(auth, cred); - nfs_file_free(data); return 0; } @@ -1008,17 +863,15 @@ * the cached attributes have to be refreshed. */ int -__nfs_revalidate_inode(struct dentry *dentry) +__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) { - struct inode *inode = dentry->d_inode; struct nfs_fattr fattr; int status = 0; - dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - inode->i_ino); + dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n", + inode->i_dev, (long long)NFS_FILEID(inode)); - if (!inode || is_bad_inode(inode)) + if (!inode || is_bad_inode(inode) || NFS_STALE(inode)) return -ESTALE; while (NFS_REVALIDATING(inode)) { @@ -1026,58 +879,30 @@ if (status < 0) return status; if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) - return 0; + return NFS_STALE(inode) ? -ESTALE : 0; } NFS_FLAGS(inode) |= NFS_INO_REVALIDATING; - status = NFS_CALL(getattr, inode, (dentry, &fattr)); + status = NFS_PROTO(inode)->getattr(inode, &fattr); if (status) { - int error; - u32 *fh; - struct dentry *dir = dentry->d_parent; - struct nfs_fh fhandle; - struct nfs_fattr dir_attr; - - dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - inode->i_ino, status); - nfs_zap_caches(inode); - - if (status != -ESTALE) - goto out; - - /* - * A "stale filehandle" error ... show the current fh - * and find out what the filehandle should be. - */ - fh = (u32 *) NFS_FH(dentry); - dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n", - fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); - error = NFS_CALL(lookup, dir->d_inode, (dir, &dir_attr, - &dentry->d_name, &fhandle, &fattr)); - nfs_refresh_inode(dir->d_inode, &dir_attr); - if (error) { - dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error); - goto out; + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n", + inode->i_dev, (long long)NFS_FILEID(inode), status); + if (status == -ESTALE) { + NFS_FLAGS(inode) |= NFS_INO_STALE; + remove_inode_hash(inode); } - fh = (u32 *) &fhandle; - dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n", - fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); - if (!IS_ROOT(dentry) && !have_submounts(dentry)) - d_drop(dentry); goto out; } status = nfs_refresh_inode(inode, &fattr); if (status) { - dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - inode->i_ino, status); + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n", + inode->i_dev, (long long)NFS_FILEID(inode), status); goto out; } + dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n", + inode->i_dev, (long long)NFS_FILEID(inode)); - dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n", - dentry->d_parent->d_name.name, dentry->d_name.name); out: NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; wake_up(&inode->i_wait); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c --- v2.2.18/fs/nfs/mount_clnt.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/mount_clnt.c Sun Mar 25 11:37:38 2001 @@ -33,23 +33,23 @@ */ static int nfs_gen_mount(struct sockaddr_in *, char *, - struct nfs_fh *, int); + struct nfs3_fh *, int); static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *, int); extern struct rpc_program mnt_program; struct mnt_fhstatus { unsigned int status; - struct nfs_fh * fh; + struct nfs3_fh * fh; }; int -nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh) +nfs_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh) { return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION); } int -nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh) +nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh) { return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION); } @@ -58,7 +58,7 @@ * Obtain an NFS file handle for the given host and path */ static int -nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version) +nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh, int version) { struct rpc_clnt *mnt_clnt; struct mnt_fhstatus result = { 0, fh }; @@ -122,7 +122,7 @@ static int xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) { - struct nfs_fh *fh = res->fh; + struct nfs3_fh *fh = res->fh; memset((void *)fh, 0, sizeof(*fh)); if ((res->status = ntohl(*p++)) == 0) { @@ -135,7 +135,7 @@ static int xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) { - struct nfs_fh *fh = res->fh; + struct nfs3_fh *fh = res->fh; memset((void *)fh, 0, sizeof(*fh)); if ((res->status = ntohl(*p++)) == 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/nfs3proc.c linux/fs/nfs/nfs3proc.c --- v2.2.18/fs/nfs/nfs3proc.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/nfs3proc.c Sun Mar 25 11:37:38 2001 @@ -46,65 +46,67 @@ * One function for each procedure in the NFS protocol. */ static int -nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr) +nfs3_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) { int status; dprintk("NFS call getattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR, - NFS_FH(dentry), fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_GETATTR, + NFS_FH(inode), fattr, 0); dprintk("NFS reply getattr\n"); return status; } static int -nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, +nfs3_proc_setattr(struct inode *inode, struct nfs_fattr *fattr, struct iattr *sattr) { - struct nfs3_sattrargs arg = { NFS_FH(dentry), sattr, 0, 0 }; + struct nfs3_sattrargs arg = { NFS_FH(inode), sattr, 0, 0 }; int status; dprintk("NFS call setattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); dprintk("NFS reply setattr\n"); return status; } static int -nfs3_proc_lookup(struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name, +nfs3_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len }; - struct nfs3_diropres res = { dir_attr, fhandle, fattr }; + struct nfs3_diropres res = { &dir_attr, fhandle, fattr }; int status; dprintk("NFS call lookup %s\n", name->name); - dir_attr->valid = 0; + dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR, + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR, fhandle, fattr, 0); dprintk("NFS reply lookup: %d\n", status); + nfs_refresh_inode(dir, &dir_attr); return status; } static int -nfs3_proc_access(struct dentry *dentry, int mode, struct nfs_fattr *fattr, int ruid) +nfs3_proc_access(struct inode *inode, int mode, int ruid) { - struct nfs3_accessargs arg = { NFS_FH(dentry), 0 }; - struct nfs3_accessres res = { fattr, 0 }; + struct nfs_fattr fattr; + struct nfs3_accessargs arg = { NFS_FH(inode), 0 }; + struct nfs3_accessres res = { &fattr, 0 }; int status, flags; dprintk("NFS call access\n"); - fattr->valid = 0; + fattr.valid = 0; if (mode & MAY_READ) arg.access |= NFS3_ACCESS_READ; - if (S_ISDIR(dentry->d_inode->i_mode)) { + if (S_ISDIR(inode->i_mode)) { if (mode & MAY_WRITE) arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE; if (mode & MAY_EXEC) @@ -116,7 +118,7 @@ arg.access |= NFS3_ACCESS_EXECUTE; } flags = (ruid) ? RPC_CALL_REALUID : 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags); + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, &arg, &res, flags); dprintk("NFS reply access\n"); if (status == 0 && (arg.access & res.access) != arg.access) @@ -125,28 +127,28 @@ } static int -nfs3_proc_readlink(struct dentry *dentry, struct nfs_fattr *fattr, - void *buffer, unsigned int buflen) +nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen) { - struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen }; - struct nfs3_readlinkres res = { fattr, buffer, buflen }; + struct nfs_fattr fattr; + struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen }; + struct nfs3_readlinkres res = { &fattr, buffer, buflen }; int status; dprintk("NFS call readlink\n"); - fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK, + fattr.valid = 0; + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, &args, &res, 0); dprintk("NFS reply readlink: %d\n", status); return status; } static int -nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, - struct rpc_cred *cred, int flags, +nfs3_proc_read(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, int flags, unsigned long offset, unsigned int count, void *buffer, int *eofp) { - struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1, + struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; struct nfs_readres res = { fattr, count, 0 }; @@ -155,19 +157,19 @@ dprintk("NFS call read %d @ %ld\n", count, offset); fattr->valid = 0; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); dprintk("NFS reply read: %d\n", status); *eofp = res.eof; return status; } static int -nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, - struct rpc_cred *cred, int flags, +nfs3_proc_write(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, int flags, unsigned long offset, unsigned int count, void *buffer, struct nfs_writeverf *verf) { - struct nfs_writeargs arg = { NFS_FH(dentry), offset, count, + struct nfs_writeargs arg = { NFS_FH(inode), offset, count, NFS_FILE_SYNC, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; @@ -181,7 +183,7 @@ rpcflags |= NFS_RPC_SWAPFLAGS; arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); dprintk("NFS reply read: %d\n", status); return status < 0? status : res.count; @@ -192,17 +194,17 @@ * For now, we don't implement O_EXCL. */ static int -nfs3_proc_create(struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name, struct iattr *sattr, int flags, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +nfs3_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, + int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct nfs_fattr dir_attr; struct nfs3_createargs arg = { NFS_FH(dir), name->name, name->len, sattr, 0, { 0, 0 } }; - struct nfs3_diropres res = { dir_attr, fhandle, fattr }; + struct nfs3_diropres res = { &dir_attr, fhandle, fattr }; int status; dprintk("NFS call create %s\n", name->name); - dir_attr->valid = 0; + dir_attr.valid = 0; fattr->valid = 0; arg.createmode = NFS3_CREATE_UNCHECKED; @@ -213,7 +215,8 @@ } again: - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); /* If the server doesn't support the exclusive creation semantics, * try again with simple 'guarded' mode. */ @@ -246,7 +249,7 @@ * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR, + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR, &arg, fattr, 0); dprintk("NFS reply setattr (post-create): %d\n", status); } @@ -255,16 +258,17 @@ } static int -nfs3_proc_remove(struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name) +nfs3_proc_remove(struct inode *dir, struct qstr *name) { + struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len }; - struct rpc_message msg = {NFS3PROC_REMOVE, &arg, dir_attr, NULL }; + struct rpc_message msg = {NFS3PROC_REMOVE, &arg, &dir_attr, NULL }; int status; dprintk("NFS call remove %s\n", name->name); - dir_attr->valid = 0; - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); + dir_attr.valid = 0; + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); return status; } @@ -281,7 +285,7 @@ return -ENOMEM; memset(arg, 0, size); res = (struct nfs_fattr*)(arg + 1); - arg->fh = NFS_FH(dir); + arg->fh = NFS_FH(dir->d_inode); arg->name = name->name; arg->len = name->len; msg->rpc_proc = NFS3PROC_REMOVE; @@ -303,91 +307,96 @@ static int -nfs3_proc_rename(struct dentry *old_dir, struct nfs_fattr *old_attr, - struct qstr *old_name, - struct dentry *new_dir, struct nfs_fattr *new_attr, - struct qstr *new_name) +nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, + struct inode *new_dir, struct qstr *new_name) { + struct nfs_fattr old_dir_attr, new_dir_attr; struct nfs3_renameargs arg = { NFS_FH(old_dir), old_name->name, old_name->len, NFS_FH(new_dir), new_name->name, new_name->len }; - struct nfs3_renameres res = { old_attr, new_attr }; + struct nfs3_renameres res = { &old_dir_attr, &new_dir_attr }; int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - old_attr->valid = 0; - new_attr->valid = 0; - status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0); + old_dir_attr.valid = 0; + new_dir_attr.valid = 0; + status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0); + nfs_refresh_inode(old_dir, &old_dir_attr); + nfs_refresh_inode(new_dir, &new_dir_attr); dprintk("NFS reply rename: %d\n", status); return status; } static int -nfs3_proc_link(struct dentry *dentry, struct nfs_fattr *fattr, - struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name) +nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { - struct nfs3_linkargs arg = { NFS_FH(dentry), NFS_FH(dir), + struct nfs_fattr dir_attr, fattr; + struct nfs3_linkargs arg = { NFS_FH(inode), NFS_FH(dir), name->name, name->len }; - struct nfs3_linkres res = { dir_attr, fattr }; + struct nfs3_linkres res = { &dir_attr, &fattr }; int status; dprintk("NFS call link %s\n", name->name); - dir_attr->valid = 0; - fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0); + dir_attr.valid = 0; + fattr.valid = 0; + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); + nfs_refresh_inode(inode, &fattr); dprintk("NFS reply link: %d\n", status); return status; } static int -nfs3_proc_symlink(struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name, struct qstr *path, - struct iattr *sattr, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, + struct iattr *sattr, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) { + struct nfs_fattr dir_attr; struct nfs3_symlinkargs arg = { NFS_FH(dir), name->name, name->len, path->name, path->len, sattr }; - struct nfs3_diropres res = { dir_attr, fhandle, fattr }; + struct nfs3_diropres res = { &dir_attr, fhandle, fattr }; int status; dprintk("NFS call symlink %s -> %s\n", name->name, path->name); - dir_attr->valid = 0; + dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply symlink: %d\n", status); return status; } static int -nfs3_proc_mkdir(struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name, struct iattr *sattr, +nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct nfs_fattr dir_attr; struct nfs3_createargs arg = { NFS_FH(dir), name->name, name->len, sattr, 0, { 0, 0 } }; - struct nfs3_diropres res = { dir_attr, fhandle, fattr }; + struct nfs3_diropres res = { &dir_attr, fhandle, fattr }; int status; dprintk("NFS call mkdir %s\n", name->name); - dir_attr->valid = 0; + dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply mkdir: %d\n", status); return status; } static int -nfs3_proc_rmdir(struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name) +nfs3_proc_rmdir(struct inode *dir, struct qstr *name) { + struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len }; int status; dprintk("NFS call rmdir %s\n", name->name); - dir_attr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, dir_attr, 0); + dir_attr.valid = 0; + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply rmdir: %d\n", status); return status; } @@ -402,14 +411,14 @@ * readdirplus. */ static int -nfs3_proc_readdir(struct dentry *dir, struct nfs_fattr *dir_attr, - struct rpc_cred *cred, +nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred, u64 cookie, void *entry, unsigned int size, int plus) { + struct nfs_fattr dir_attr; struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 }; - struct nfs3_readdirres res = { dir_attr, 0, 0, 0, 0 }; + struct nfs3_readdirres res = { &dir_attr, 0, 0, 0, 0 }; struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, cred }; - u32 *verf = NFS_COOKIEVERF(dir->d_inode); + u32 *verf = NFS_COOKIEVERF(dir); int status; arg.buffer = entry; @@ -428,20 +437,21 @@ dprintk("NFS call readdir%s %d\n", plus? "plus" : "", (unsigned int) cookie); - dir_attr->valid = 0; - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); + dir_attr.valid = 0; + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply readdir: %d\n", status); return status; } static int -nfs3_proc_mknod(struct dentry *dir, struct nfs_fattr *dir_attr, - struct qstr *name, struct iattr *sattr, +nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr) { + struct nfs_fattr dir_attr; struct nfs3_mknodargs arg = { NFS_FH(dir), name->name, name->len, 0, sattr, rdev }; - struct nfs3_diropres res = { dir_attr, fh, fattr }; + struct nfs3_diropres res = { &dir_attr, fh, fattr }; int status; switch (sattr->ia_mode & S_IFMT) { @@ -453,9 +463,10 @@ } dprintk("NFS call mknod %s %x\n", name->name, rdev); - dir_attr->valid = 0; + dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply mknod: %d\n", status); return status; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.2.18/fs/nfs/proc.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/proc.c Sun Mar 25 11:37:38 2001 @@ -77,34 +77,34 @@ * One function for each procedure in the NFS protocol. */ static int -nfs_proc_getattr(struct dentry *dentry, fattr *fattr) +nfs_proc_getattr(struct inode *inode, fattr *fattr) { int status; dprintk("NFS call getattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR, - NFS_FH(dentry), fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFSPROC_GETATTR, + NFS_FH(inode), fattr, 0); dprintk("NFS reply getattr\n"); return status; } static int -nfs_proc_setattr(struct dentry *dentry, fattr *fattr, +nfs_proc_setattr(struct inode *inode, fattr *fattr, struct iattr *sattr) { - struct nfs_sattrargs arg = { NFS_FH(dentry), sattr }; + struct nfs_sattrargs arg = { NFS_FH(inode), sattr }; int status; dprintk("NFS call setattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); dprintk("NFS reply setattr\n"); return status; } static int -nfs_proc_lookup(struct dentry *dir, fattr *dir_attr, qstr *name, +nfs_proc_lookup(struct inode *dir, qstr *name, struct nfs_fh *fhandle, fattr *fattr) { struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len }; @@ -112,36 +112,32 @@ int status; dprintk("NFS call lookup %s\n", name->name); - dir_attr->valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0); dprintk("NFS reply lookup: %d\n", status); return status; } static int -nfs_proc_readlink(struct dentry *dentry, fattr *fattr, - void *buffer, unsigned int bufsiz) +nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz) { - struct nfs_readlinkargs args = { NFS_FH(dentry), buffer, bufsiz }; + struct nfs_readlinkargs args = { NFS_FH(inode), buffer, bufsiz }; struct nfs_readlinkres res = { buffer, bufsiz }; int status; dprintk("NFS call readlink\n"); - fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK, + status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, &res, 0); dprintk("NFS reply readlink: %d\n", status); return status; } static int -nfs_proc_read(struct dentry *dentry, fattr *fattr, - struct rpc_cred *cred, int flags, - unsigned long offset, unsigned int count, +nfs_proc_read(struct inode *inode, struct rpc_cred *cred, fattr *fattr, + int flags, unsigned long offset, unsigned int count, void *buffer, int *eofp) { - struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1, + struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1, {{ buffer, count }, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; struct nfs_readres res = { fattr, count, 0}; @@ -150,7 +146,7 @@ dprintk("NFS call read %d @ %ld\n", count, offset); fattr->valid = 0; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); dprintk("NFS reply read: %d\n", status); *eofp = res.eof; @@ -158,12 +154,11 @@ } static int -nfs_proc_write(struct dentry *dentry, fattr *fattr, - struct rpc_cred *cred, int how, - unsigned long offset, unsigned int count, +nfs_proc_write(struct inode *inode, struct rpc_cred *cred, fattr *fattr, + int how, unsigned long offset, unsigned int count, void *buffer, struct nfs_writeverf *verf) { - struct nfs_writeargs arg = {NFS_FH(dentry), offset, count, + struct nfs_writeargs arg = {NFS_FH(inode), offset, count, NFS_FILE_SYNC, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}}; @@ -175,7 +170,7 @@ fattr->valid = 0; if (how & NFS_RW_SWAP) flags |= NFS_RPC_SWAPFLAGS; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); dprintk("NFS reply write: %d\n", status); verf->committed = NFS_FILE_SYNC; /* NFSv2 always syncs data */ @@ -183,8 +178,7 @@ } static int -nfs_proc_create(struct dentry *dir, fattr *dir_attr, - qstr *name, struct iattr *sattr, int flags, +nfs_proc_create(struct inode *dir, qstr *name, struct iattr *sattr, int flags, struct nfs_fh *fhandle, fattr *fattr) { struct nfs_createargs arg = { NFS_FH(dir), name->name, @@ -192,10 +186,9 @@ struct nfs_diropok res = { fhandle, fattr }; int status; - dir_attr->valid = 0; fattr->valid = 0; dprintk("NFS call create %s\n", name->name); - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); dprintk("NFS reply create: %d\n", status); return status; } @@ -204,8 +197,7 @@ * In NFSv2, mknod is grafted onto the create call. */ static int -nfs_proc_mknod(struct dentry *dir, fattr *dir_attr, - qstr *name, struct iattr *sattr, dev_t rdev, +nfs_proc_mknod(struct inode *dir, qstr *name, struct iattr *sattr, dev_t rdev, struct nfs_fh *fhandle, fattr *fattr) { struct nfs_createargs arg = { NFS_FH(dir), name->name, @@ -224,30 +216,27 @@ sattr->ia_size = rdev; /* get out your barf bag */ } - dir_attr->valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; - dir_attr->valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); } dprintk("NFS reply mknod: %d\n", status); return status; } static int -nfs_proc_remove(struct dentry *dir, fattr *dir_attr, qstr *name) +nfs_proc_remove(struct inode *dir, qstr *name) { struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len }; struct rpc_message msg = { NFSPROC_REMOVE, &arg, NULL, NULL }; int status; - dir_attr->valid = 0; dprintk("NFS call remove %s\n", name->name); - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply remove: %d\n", status); return status; @@ -262,7 +251,7 @@ if (!arg) return -ENOMEM; memset(arg, 0, sizeof(*arg)); - arg->fh = NFS_FH(dir); + arg->fh = NFS_FH(dir->d_inode); arg->name = name->name; arg->len = name->len; msg->rpc_proc = NFSPROC_REMOVE; @@ -280,8 +269,8 @@ } static int -nfs_proc_rename(struct dentry *old_dir, fattr *old_attr, qstr *old_name, - struct dentry *new_dir, fattr *new_attr, qstr *new_name) +nfs_proc_rename(struct inode *old_dir, qstr *old_name, + struct inode *new_dir, qstr *new_name) { struct nfs_renameargs arg = { NFS_FH(old_dir), old_name->name, old_name->len, @@ -290,32 +279,26 @@ int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - old_attr->valid = 0; - new_attr->valid = 0; - status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0); dprintk("NFS reply rename: %d\n", status); return status; } static int -nfs_proc_link(struct dentry *dentry, fattr *attr, - struct dentry *dir, fattr *dir_attr, qstr *name) +nfs_proc_link(struct inode *inode, struct inode *dir, qstr *name) { - struct nfs_linkargs arg = { NFS_FH(dentry), NFS_FH(dir), + struct nfs_linkargs arg = { NFS_FH(inode), NFS_FH(dir), name->name, name->len }; int status; dprintk("NFS call link %s\n", name->name); - dir_attr->valid = 0; - attr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0); dprintk("NFS reply link: %d\n", status); return status; } static int -nfs_proc_symlink(struct dentry *dir, fattr *dir_attr, qstr *name, - qstr *path, struct iattr *sattr, +nfs_proc_symlink(struct inode *dir, qstr *name, qstr *path, struct iattr *sattr, struct nfs_fh *sym_fh, fattr *sym_attr) { struct nfs_symlinkargs arg = { NFS_FH(dir), name->name, name->len, @@ -323,16 +306,14 @@ int status; dprintk("NFS call symlink %s -> %s\n", name->name, path->name); - dir_attr->valid = 0; sym_attr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); dprintk("NFS reply symlink: %d\n", status); return status; } static int -nfs_proc_mkdir(struct dentry *dir, fattr *dir_attr, qstr *name, - struct iattr *sattr, +nfs_proc_mkdir(struct inode *dir, qstr *name, struct iattr *sattr, struct nfs_fh *fhandle, fattr *fattr) { struct nfs_createargs arg = { NFS_FH(dir), name->name, name->len, @@ -341,22 +322,20 @@ int status; dprintk("NFS call mkdir %s\n", name->name); - dir_attr->valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); dprintk("NFS reply mkdir: %d\n", status); return status; } static int -nfs_proc_rmdir(struct dentry *dir, fattr *dir_attr, qstr *name) +nfs_proc_rmdir(struct inode *dir, qstr *name) { struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len }; int status; dprintk("NFS call rmdir %s\n", name->name); - dir_attr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0); dprintk("NFS reply rmdir: %d\n", status); return status; } @@ -369,8 +348,7 @@ * from nfs_readdir by calling the decode_entry function directly. */ static int -nfs_proc_readdir(struct dentry *dir, fattr *dir_attr, - struct rpc_cred *cred, +nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred, __u64 cookie, void *entry, unsigned int size, int plus) { struct nfs_readdirargs arg; @@ -378,7 +356,6 @@ struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, cred }; int status; - dir_attr->valid = 0; arg.fh = NFS_FH(dir); arg.cookie = cookie; arg.buffer = entry; @@ -386,9 +363,8 @@ res.buffer = entry; res.bufsiz = size; - dir_attr->valid = 0; dprintk("NFS call readdir %d\n", (unsigned int)cookie); - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply readdir: %d\n", status); return status; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/read.c linux/fs/nfs/read.c --- v2.2.18/fs/nfs/read.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/read.c Sun Mar 25 11:37:38 2001 @@ -42,7 +42,7 @@ struct nfs_read_data { struct rpc_task task; - struct dentry *dentry; + struct inode *inode; struct rpc_cred *cred; struct nfs_readargs args; /* XDR argument struct */ struct nfs_readres res; /* ... and result struct */ @@ -87,11 +87,9 @@ * Read a page synchronously. */ static int -nfs_readpage_sync(struct file *file, struct page *page) +nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - struct rpc_cred *cred = nfs_file_cred(file); + struct rpc_cred *cred = NULL; struct nfs_fattr fattr; unsigned long offset = nfs_page_offset(page); char *buffer = (char *) page_address(page); @@ -104,19 +102,23 @@ flags |= NFS_RPC_SWAPFLAGS; dprintk("NFS: nfs_readpage_sync(%p)\n", page); + + if (file) + cred = nfs_file_cred(file); + clear_bit(PG_error, &page->flags); do { if ((chunk = rsize) > count) chunk = count; - dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n", + dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %ld, %d, %p)\n", NFS_SERVER(inode)->hostname, - dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_dev, (long long)NFS_FILEID(inode), offset, chunk, buffer); - result = NFS_CALL(read, inode, (dentry, &fattr, cred, flags, - offset, chunk, buffer, &eof)); + result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags, + offset, chunk, buffer, &eof); nfs_refresh_inode(inode, &fattr); /* @@ -180,7 +182,7 @@ static inline void nfs_mark_request_read(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; if (list_empty(&req->wb_list)) { nfs_list_add_request(req, &inode->u.nfs_i.read); @@ -190,9 +192,8 @@ } static int -nfs_readpage_async(struct file *file, struct page *page) +nfs_readpage_async(struct file *file, struct inode *inode, struct page *page) { - struct inode *inode = file->f_dentry->d_inode; struct nfs_page *req, *new = NULL; int result; @@ -222,7 +223,7 @@ } result = -ENOMEM; - new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE); + new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE); if (!new) break; } @@ -258,9 +259,9 @@ data->args.nriov++; } req = nfs_list_entry(data->pages.next); - data->dentry = req->wb_dentry; + data->inode = req->wb_inode; data->cred = req->wb_cred; - data->args.fh = NFS_FH(req->wb_dentry); + data->args.fh = NFS_FH(req->wb_inode); data->args.offset = nfs_page_offset(req->wb_page) + req->wb_offset; data->args.count = count; data->res.fattr = &data->fattr; @@ -286,9 +287,8 @@ } static int -nfs_pagein_one(struct list_head *head, struct dentry *dentry) +nfs_pagein_one(struct list_head *head, struct inode *inode) { - struct inode *inode = dentry->d_inode; struct rpc_task *task; struct rpc_clnt *clnt = NFS_CLIENT(inode); struct nfs_read_data *data; @@ -322,9 +322,9 @@ msg.rpc_cred = data->cred; /* Start the async call */ - dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n", + dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n", task->tk_pid, - dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_dev, (long long)NFS_FILEID(inode), data->args.count, data->args.nriov); rpc_clnt_sigmask(clnt, &oldset); @@ -349,7 +349,7 @@ while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, rpages); req = nfs_list_entry(one_request.next); - error = nfs_pagein_one(&one_request, req->wb_dentry); + error = nfs_pagein_one(&one_request, req->wb_inode); if (error < 0) break; } @@ -419,8 +419,7 @@ nfs_readpage_result(struct rpc_task *task) { struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; - struct dentry *dentry = data->dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = data->inode; int count = data->res.count; dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", @@ -440,9 +439,9 @@ set_bit(PG_error, &page->flags); nfs_unlock_page(page); - dprintk("NFS: read (%s/%s %d@%ld)\n", - req->wb_dentry->d_parent->d_name.name, - req->wb_dentry->d_name.name, + dprintk("NFS: read (%x/%Ld %d@%ld)\n", + req->wb_inode->i_dev, + (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (nfs_page_offset(page) + req->wb_offset)); nfs_unlock_request(req); @@ -465,16 +464,19 @@ int nfs_readpage(struct file *file, struct page *page) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - int error = 0, - rsize = NFS_SERVER(inode)->rsize; + struct inode *inode; + int error = 0; while (!nfs_lock_page(page)) wait_on_page(page); - dprintk("NFS: nfs_readpage (%p %d@%ld)\n", - page, rsize, page->offset); + if (!file) + inode = page->inode; + else + inode = file->f_dentry->d_inode; + + dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", + page, PAGE_CACHE_SIZE, page->offset); /* * Try to flush any pending writes to the file @@ -484,13 +486,13 @@ goto out_unlock; error = -1; - if (!IS_SWAPFILE(inode) && !PageError(page) && rsize >= PAGE_CACHE_SIZE) - error = nfs_readpage_async(file, page); + if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) + error = nfs_readpage_async(file, inode, page); if (error >= 0) goto out; - error = nfs_readpage_sync(file, page); + error = nfs_readpage_sync(file, inode, page); if (error < 0 && IS_SWAPFILE(inode)) printk(KERN_ERR "Aiee.. nfs swap-in of page failed!\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/symlink.c linux/fs/nfs/symlink.c --- v2.2.18/fs/nfs/symlink.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/symlink.c Sun Mar 25 11:37:38 2001 @@ -57,19 +57,16 @@ /* Symlink caching in the page cache is even more simplistic * and straight-forward than readdir caching. */ -static int nfs_symlink_filler(struct dentry *dentry, struct page *page) +static int nfs_symlink_filler(struct inode *inode, struct page *page) { - struct inode *inode = dentry->d_inode; - struct nfs_fattr fattr; void * buffer = (void *)page_address(page); unsigned int error; /* We place the length at the beginning of the page, * in client byte order, followed by the string. */ - error = NFS_CALL(readlink, inode, (dentry, &fattr, buffer, - PAGE_CACHE_SIZE-sizeof(u32)-4)); - nfs_refresh_inode(inode, &fattr); + error = NFS_PROTO(inode)->readlink(inode, buffer, + PAGE_CACHE_SIZE-sizeof(u32)-4); if (error < 0) goto error; flush_dcache_page(page_address(page)); /* Is this correct? */ @@ -90,7 +87,7 @@ /* Caller revalidated the directory inode already. */ page = read_cache_page(inode, 0, - (filler_t *)nfs_symlink_filler, dentry); + (filler_t *)nfs_symlink_filler, inode); if (IS_ERR(page)) goto read_failed; @@ -115,7 +112,7 @@ /* Caller revalidated the directory inode already. */ page = read_cache_page(inode, 0, - (filler_t *)nfs_symlink_filler, dentry); + (filler_t *)nfs_symlink_filler, inode); if (IS_ERR(page)) goto read_failed; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfs/write.c linux/fs/nfs/write.c --- v2.2.18/fs/nfs/write.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfs/write.c Sun Mar 25 11:37:38 2001 @@ -66,7 +66,7 @@ */ struct nfs_write_data { struct rpc_task task; - struct dentry *dentry; + struct inode *inode; struct rpc_cred *cred; struct nfs_writeargs args; /* argument struct */ struct nfs_writeres res; /* result struct */ @@ -143,20 +143,21 @@ * Offset is the data offset within the page. */ static int -nfs_writepage_sync(struct file *file, struct page *page, +nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page, unsigned long offset, unsigned int count) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - struct rpc_cred *cred = nfs_file_cred(file); + struct rpc_cred *cred = NULL; unsigned int wsize = NFS_SERVER(inode)->wsize; int result, refresh = 0, written = 0, flags; u8 *buffer; struct nfs_fattr fattr; struct nfs_writeverf verifier; - dprintk("NFS: nfs_writepage_sync(%s/%s %d@%ld)\n", - dentry->d_parent->d_name.name, dentry->d_name.name, + if (file) + cred = nfs_file_cred(file); + + dprintk("NFS: nfs_writepage_sync(%x/%Ld %d@%ld)\n", + inode->i_dev, (long long)NFS_FILEID(inode), count, nfs_page_offset(page) + offset); buffer = (u8 *) page_address(page) + offset; @@ -168,7 +169,7 @@ if (count < wsize && !IS_SWAPFILE(inode)) wsize = count; - result = NFS_PROTO(inode)->write(dentry, &fattr, cred, flags, + result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags, offset, wsize, buffer, &verifier); nfs_write_attributes(inode, &fattr); @@ -205,14 +206,18 @@ int nfs_writepage(struct file * file, struct page *page) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode; unsigned offset = PAGE_CACHE_SIZE; + if (!file) + inode = page->inode; + else + inode = file->f_dentry->d_inode; if (page->offset >= inode->i_size) return -EIO; if (page->offset + offset > inode->i_size) offset = inode->i_size & (PAGE_CACHE_SIZE-1); - return nfs_writepage_sync(file, page, 0, offset); + return nfs_writepage_sync(file, inode, page, 0, offset); } /* @@ -252,6 +257,8 @@ return; if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted hashed!\n"); + if (list_empty(&inode->u.nfs_i.writeback)) + inode->i_count++; inode->u.nfs_i.npages++; list_add(&req->wb_hash, &inode->u.nfs_i.writeback); req->wb_count++; @@ -269,12 +276,14 @@ if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n"); - inode = req->wb_dentry->d_inode; + inode = req->wb_inode; list_del(&req->wb_hash); INIT_LIST_HEAD(&req->wb_hash); inode->u.nfs_i.npages--; if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n"); + if (list_empty(&inode->u.nfs_i.writeback)) + iput(inode); if (!nfs_have_writebacks(inode) && !nfs_have_read(inode)) inode_remove_flushd(inode); nfs_release_request(req); @@ -354,7 +363,7 @@ static inline void nfs_mark_request_dirty(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; if (list_empty(&req->wb_list)) { nfs_list_add_request(req, &inode->u.nfs_i.dirty); @@ -369,7 +378,7 @@ static inline int nfs_dirty_request(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty; } @@ -380,7 +389,7 @@ static inline void nfs_mark_request_commit(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; if (list_empty(&req->wb_list)) { nfs_list_add_request(req, &inode->u.nfs_i.commit); @@ -396,11 +405,10 @@ * two different requests for the same page, and avoids possible deadlock * when we reach the hard limit on the number of dirty pages. */ -struct nfs_page *nfs_create_request(struct file *file, struct page *page, +struct nfs_page *nfs_create_request(struct file *file, struct inode *inode, + struct page *page, unsigned int offset, unsigned int count) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct nfs_page *req = NULL; long timeout; @@ -452,9 +460,12 @@ req->wb_offset = offset; req->wb_bytes = count; req->wb_file = file; - file->f_count++; - req->wb_dentry = dentry; - req->wb_cred = nfs_file_cred(file); + if (file) { + file->f_count++; + req->wb_cred = nfs_file_cred(file); + } else + req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + req->wb_inode = inode; req->wb_count = 1; /* register request's existence */ @@ -471,7 +482,7 @@ void nfs_release_request(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct page *page = req->wb_page; @@ -489,7 +500,10 @@ if (NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: Request released while still locked!\n"); - fput(req->wb_file); + if (req->wb_file) + fput(req->wb_file); + else + rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred); page_cache_release(page); nfs_page_free(req); /* wake up anyone waiting to allocate a request */ @@ -506,7 +520,7 @@ static int nfs_wait_on_request(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; struct rpc_clnt *clnt = NFS_CLIENT(inode); int retval; @@ -716,10 +730,9 @@ * Note: Should always be called with the Page Lock held! */ static struct nfs_page * -nfs_update_request(struct file* file, struct page *page, +nfs_update_request(struct file* file, struct inode *inode, struct page *page, unsigned int offset, unsigned int bytes) { - struct inode *inode = file->f_dentry->d_inode; struct nfs_page *req, *new = NULL; unsigned long rqend, end; @@ -754,7 +767,7 @@ */ if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT) nfs_wb_file(inode, file); - new = nfs_create_request(file, page, offset, bytes); + new = nfs_create_request(file, inode, page, offset, bytes); if (!new) return ERR_PTR(-ENOMEM); /* If the region is locked, adjust the timeout */ @@ -891,7 +904,7 @@ * page synchronously. */ if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) - return nfs_writepage_sync(file, page, offset, count); + return nfs_writepage_sync(file, inode, page, offset, count); /* * Try to find an NFS request corresponding to this page @@ -900,7 +913,7 @@ * it out now. */ do { - req = nfs_update_request(file, page, offset, count); + req = nfs_update_request(file, inode, page, offset, count); if (IS_ERR(req)) status = PTR_ERR(req); if (status != -EBUSY) @@ -967,9 +980,9 @@ data->args.nriov++; } req = nfs_list_entry(data->pages.next); - data->dentry = req->wb_dentry; + data->inode = req->wb_inode; data->cred = req->wb_cred; - data->args.fh = NFS_FH(req->wb_dentry); + data->args.fh = NFS_FH(req->wb_inode); data->args.offset = nfs_page_offset(req->wb_page) + req->wb_offset; data->args.count = count; data->res.fattr = &data->fattr; @@ -987,9 +1000,8 @@ * that has been written but not committed. */ static int -nfs_flush_one(struct list_head *head, struct dentry *dentry, int how) +nfs_flush_one(struct list_head *head, struct inode *inode, int how) { - struct inode *inode = dentry->d_inode; struct rpc_clnt *clnt = NFS_CLIENT(inode); struct nfs_write_data *data; struct rpc_task *task; @@ -1033,10 +1045,10 @@ msg.rpc_resp = &data->res; msg.rpc_cred = data->cred; - dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n", + dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n", task->tk_pid, - dentry->d_parent->d_name.name, - dentry->d_name.name, + inode->i_dev, + (long long)NFS_FILEID(inode), data->args.count, data->args.nriov); rpc_clnt_sigmask(clnt, &oldset); @@ -1066,7 +1078,7 @@ while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, wpages); req = nfs_list_entry(one_request.next); - error = nfs_flush_one(&one_request, req->wb_dentry, how); + error = nfs_flush_one(&one_request, req->wb_inode, how); if (error < 0) break; } @@ -1092,8 +1104,7 @@ struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct nfs_writeargs *argp = &data->args; struct nfs_writeres *resp = &data->res; - struct dentry *dentry = data->dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = data->inode; struct nfs_page *req; struct page *page; @@ -1138,9 +1149,9 @@ nfs_list_remove_request(req); page = req->wb_page; - dprintk("NFS: write (%s/%s %d@%Ld)", - req->wb_dentry->d_parent->d_name.name, - req->wb_dentry->d_name.name, + dprintk("NFS: write (%x/%Ld %d@%Ld)", + req->wb_inode->i_dev, + (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(nfs_page_offset(page) + req->wb_offset)); @@ -1181,7 +1192,6 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) { struct nfs_page *req; - struct dentry *dentry; struct inode *inode; unsigned long start, end, len; @@ -1191,10 +1201,7 @@ end = 0; start = ~0; req = nfs_list_entry(head->next); - dentry = req->wb_dentry; - data->dentry = dentry; - data->cred = req->wb_cred; - inode = dentry->d_inode; + inode = req->wb_inode; while (!list_empty(head)) { struct nfs_page *req; unsigned long rqstart, rqend; @@ -1208,7 +1215,9 @@ if (rqend > end) end = rqend; } - data->args.fh = NFS_FH(dentry); + data->inode = inode; + data->cred = req->wb_cred; + data->args.fh = NFS_FH(inode); data->args.offset = start; len = end - start; if (end >= inode->i_size || len > (~((u32)0) >> 1)) @@ -1243,7 +1252,7 @@ /* Set up the argument struct */ nfs_commit_rpcsetup(head, data); req = nfs_list_entry(data->pages.next); - clnt = NFS_CLIENT(req->wb_dentry->d_inode); + clnt = NFS_CLIENT(req->wb_inode); rpc_init_task(task, clnt, nfs_commit_done, flags); task->tk_calldata = data; @@ -1279,8 +1288,7 @@ struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; struct nfs_writeres *resp = &data->res; struct nfs_page *req; - struct dentry *dentry = data->dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = data->inode; dprintk("NFS: %4d nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); @@ -1290,9 +1298,9 @@ req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); - dprintk("NFS: commit (%s/%s %d@%ld)", - req->wb_dentry->d_parent->d_name.name, - req->wb_dentry->d_name.name, + dprintk("NFS: commit (%x/%Ld %d@%ld)", + req->wb_inode->i_dev, + (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, nfs_page_offset(req->wb_page) + req->wb_offset); if (task->tk_status < 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/auth.c linux/fs/nfsd/auth.c --- v2.2.18/fs/nfsd/auth.c Sun Mar 25 11:12:33 2001 +++ linux/fs/nfsd/auth.c Sun Mar 25 11:37:38 2001 @@ -10,6 +10,7 @@ #include #include +#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) void nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) { @@ -50,10 +51,10 @@ current->ngroups = i; if ((cred->cr_uid)) { - cap_t(current->cap_effective) &= ~CAP_FS_MASK; + cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; } else { - cap_t(current->cap_effective) |= (CAP_FS_MASK & - current->cap_permitted); + cap_t(current->cap_effective) |= (CAP_NFSD_MASK & + current->cap_permitted); } rqstp->rq_userset = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/export.c linux/fs/nfsd/export.c --- v2.2.18/fs/nfsd/export.c Sun Mar 25 11:28:33 2001 +++ linux/fs/nfsd/export.c Sun Mar 25 11:37:38 2001 @@ -9,8 +9,6 @@ * creates a client control block and adds it to the hash * table. Then, you call NFSCTL_EXPORT for each fs. * - * You cannot currently read the export information from the - * kernel. It would be nice to have a /proc file though. * * Copyright (C) 1995, 1996 Olaf Kirch, */ @@ -447,7 +445,7 @@ if (path) { if (!(dentry = lookup_dentry(path, NULL, 0))) { printk("nfsd: exp_rootfh path not found %s", path); - return -EPERM; + return err; } dev = dentry->d_inode->i_dev; ino = dentry->d_inode->i_ino; @@ -611,7 +609,7 @@ { NFSEXP_SUNSECURE, { "sunsecure", ""}}, { NFSEXP_CROSSMNT, {"nohide", ""}}, { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, - { NFSEXP_NOAUTHNLM, {"no_auth_nlm", ""}}, + { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, { 0, {"", ""}} }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/nfs3proc.c linux/fs/nfsd/nfs3proc.c --- v2.2.18/fs/nfsd/nfs3proc.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/nfs3proc.c Sun Mar 25 11:37:38 2001 @@ -29,7 +29,7 @@ #define NFSDDBG_FACILITY NFSDDBG_PROC -#define RETURN(st) { resp->status = (st); return (st); } +#define RETURN_STATUS(st) { resp->status = (st); return (st); } static int nfs3_ftypes[] = { 0, /* NF3NON */ @@ -76,7 +76,7 @@ fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -94,7 +94,7 @@ fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -116,7 +116,7 @@ argp->name, argp->len, &resp->fh); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -136,7 +136,7 @@ fh_copy(&resp->fh, &argp->fh); resp->access = argp->access; nfserr = nfsd_access(rqstp, &resp->fh, &resp->access); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -161,7 +161,7 @@ fh_copy(&resp->fh, &argp->fh); resp->len = NFS3_MAXPATHLEN; nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -202,7 +202,7 @@ resp->eof = (argp->offset + resp->count) >= inode->i_size; } - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -222,14 +222,14 @@ argp->stable? " stable" : ""); fh_copy(&resp->fh, &argp->fh); + resp->committed = argp->stable; nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, argp->data, argp->len, - argp->stable); - resp->committed = argp->stable; + &resp->committed); resp->count = argp->count; - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -257,7 +257,7 @@ /* Get the directory inode */ nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE); if (nfserr) - RETURN(nfserr); + RETURN_STATUS(nfserr); /* Unfudge the mode bits */ attr->ia_mode &= ~S_IFMT; @@ -273,7 +273,7 @@ attr, newfhp, argp->createmode, argp->verf); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -296,7 +296,7 @@ nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, &argp->attrs, S_IFDIR, 0, &resp->fh); - RETURN(nfserr); + RETURN_STATUS(nfserr); } static int @@ -315,7 +315,7 @@ nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, argp->tname, argp->tlen, &resp->fh, &argp->attrs); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -337,22 +337,22 @@ fh_init(&resp->fh); if (argp->ftype == 0 || argp->ftype >= NF3BAD) - return nfserr_inval; + RETURN_STATUS(nfserr_inval); if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) { if ((argp->ftype == NF3CHR && argp->major >= MAX_CHRDEV) || (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV) || argp->minor > 0xFF) - return nfserr_inval; + RETURN_STATUS(nfserr_inval); rdev = ((argp->major) << 8) | (argp->minor); } else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) - return nfserr_inval; + RETURN_STATUS(nfserr_inval); type = nfs3_ftypes[argp->ftype]; nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, &argp->attrs, type, rdev, &resp->fh); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -372,7 +372,7 @@ /* Unlink. -S_IFDIR means file must not be a directory */ fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -391,7 +391,7 @@ fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); - RETURN(nfserr); + RETURN_STATUS(nfserr); } static int @@ -412,7 +412,7 @@ fh_copy(&resp->tfh, &argp->tfh); nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, &resp->tfh, argp->tname, argp->tlen); - RETURN(nfserr); + RETURN_STATUS(nfserr); } static int @@ -432,7 +432,7 @@ fh_copy(&resp->tfh, &argp->tfh); nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, &resp->fh); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -468,7 +468,7 @@ memcpy(resp->verf, argp->verf, 8); resp->count = count; - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -504,7 +504,7 @@ memcpy(resp->verf, argp->verf, 8); resp->count = count; - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -522,7 +522,7 @@ nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); fh_put(&argp->fh); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -563,7 +563,7 @@ } fh_put(&argp->fh); - RETURN(nfserr); + RETURN_STATUS(nfserr); } /* @@ -606,7 +606,7 @@ } fh_put(&argp->fh); - RETURN(nfserr); + RETURN_STATUS(nfserr); } @@ -626,12 +626,12 @@ (unsigned long) argp->offset); if (argp->offset > NFS_OFFSET_MAX) - return nfserr_inval; + RETURN_STATUS(nfserr_inval); fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count); - RETURN(nfserr); + RETURN_STATUS(nfserr); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c --- v2.2.18/fs/nfsd/nfs3xdr.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/nfs3xdr.c Sun Mar 25 11:37:38 2001 @@ -36,17 +36,6 @@ NF3SOCK, NF3BAD, NF3LNK, NF3BAD, }; -/* - * XDR functions for basic NFS types - */ -static inline u32 * -dec64(u32 *p, u64 *valp) -{ - *valp = ((u64) ntohl(*p++)) << 32; - *valp |= ntohl(*p++); - return p; -} - static inline u32 * encode_time3(u32 *p, time_t secs) { @@ -140,7 +129,7 @@ u64 newsize; iap->ia_valid |= ATTR_SIZE; - p = dec64(p, &newsize); + p = xdr_decode_hyper(p, &newsize); if (newsize <= NFS_OFFSET_MAX) iap->ia_size = (u32) newsize; else @@ -177,24 +166,24 @@ *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid)); *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid)); if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) { - p = enc64(p, (u64) NFS3_MAXPATHLEN); + p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { - p = enc64(p, (u64) inode->i_size); + p = xdr_encode_hyper(p, (u64) inode->i_size); } /* * For the 'used' member, we take i_blocks if set; assuming 512-byte * units. Some FSs don't set this, so all we can do then is * use the size. */ - if (inode->i_blocks) { - p = enc64(p, ((u64)inode->i_blocks)<<9 ); - } else { - p = enc64(p, (u64) inode->i_size); - } + if (inode->i_blocks) + p = xdr_encode_hyper(p, ((u64)inode->i_blocks)<<9 ); + else + p = xdr_encode_hyper(p, (u64) inode->i_size); + *p++ = htonl((u32) MAJOR(inode->i_rdev)); *p++ = htonl((u32) MINOR(inode->i_rdev)); - p = enc64(p, (u64) inode->i_dev); - p = enc64(p, (u64) inode->i_ino); + p = xdr_encode_hyper(p, (u64) inode->i_dev); + p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, inode->i_atime); p = encode_time3(p, inode->i_mtime); p = encode_time3(p, inode->i_ctime); @@ -216,19 +205,19 @@ *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { - p = enc64(p, (u64) NFS3_MAXPATHLEN); + p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { - p = enc64(p, (u64) fhp->fh_post_size); + p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); } if (fhp->fh_post_blocks) { - p = enc64(p, ((u64)fhp->fh_post_blocks)<<9); + p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks)<<9); } else { - p = enc64(p, (u64) fhp->fh_post_size); + p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); } *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev)); *p++ = htonl((u32) MINOR(fhp->fh_post_rdev)); - p = enc64(p, (u64) inode->i_dev); - p = enc64(p, (u64) inode->i_ino); + p = xdr_encode_hyper(p, (u64) inode->i_dev); + p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, fhp->fh_post_atime); p = encode_time3(p, fhp->fh_post_mtime); p = encode_time3(p, fhp->fh_post_ctime); @@ -263,7 +252,7 @@ if (dentry && dentry->d_inode && fhp->fh_post_saved) { if (fhp->fh_pre_saved) { *p++ = xdr_one; - p = enc64(p, (u64) fhp->fh_pre_size); + p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); p = encode_time3(p, fhp->fh_pre_mtime); p = encode_time3(p, fhp->fh_pre_ctime); } else { @@ -350,7 +339,7 @@ struct nfsd3_readargs *args) { if (!(p = decode_fh(p, &args->fh)) - || !(p = dec64(p, &args->offset))) + || !(p = xdr_decode_hyper(p, &args->offset))) return 0; args->count = ntohl(*p++); @@ -362,7 +351,7 @@ struct nfsd3_writeargs *args) { if (!(p = decode_fh(p, &args->fh)) - || !(p = dec64(p, &args->offset))) + || !(p = xdr_decode_hyper(p, &args->offset))) return 0; args->count = ntohl(*p++); @@ -478,7 +467,7 @@ { if (!(p = decode_fh(p, &args->fh))) return 0; - p = dec64(p, &args->cookie); + p = xdr_decode_hyper(p, &args->cookie); args->verf = p; p += 2; args->dircount = ~0; args->count = ntohl(*p++); @@ -492,7 +481,7 @@ { if (!(p = decode_fh(p, &args->fh))) return 0; - p = dec64(p, &args->cookie); + p = xdr_decode_hyper(p, &args->cookie); args->verf = p; p += 2; args->dircount = ntohl(*p++); args->count = ntohl(*p++); @@ -506,7 +495,7 @@ { if (!(p = decode_fh(p, &args->fh))) return 0; - p = dec64(p, &args->offset); + p = xdr_decode_hyper(p, &args->offset); args->count = ntohl(*p++); return xdr_argsize_check(rqstp, p); @@ -682,7 +671,7 @@ int buflen, slen, elen; if (cd->offset) - enc64(cd->offset, (u64) offset); + xdr_encode_hyper(cd->offset, (u64) offset); /* nfsd_readdir calls us with name == 0 when it wants us to * set the last offset entry. */ @@ -705,20 +694,12 @@ cd->eob = 1; return -EINVAL; } - *p++ = xdr_one; /* mark entry present */ - p = enc64(p, ino); /* file id */ -#ifdef XDR_ENCODE_STRING_TAKES_LENGTH - p = xdr_encode_string(p, name, namlen); /* name length & name */ -#else - /* just like nfsproc.c */ - *p++ = htonl((u32) namlen); - p[slen - 1] = 0; /* don't leak kernel data */ - memcpy(p, name, namlen); - p += slen; -#endif + *p++ = xdr_one; /* mark entry present */ + p = xdr_encode_hyper(p, ino); /* file id */ + p = xdr_encode_string(p, name, namlen);/* name length & name */ cd->offset = p; /* remember pointer */ - p = enc64(p, NFS_OFFSET_MAX); /* offset of next entry */ + p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ /* throw in readdirplus baggage */ if (plus) { @@ -769,12 +750,12 @@ *p++ = xdr_zero; /* no post_op_attr */ if (resp->status == 0) { - p = enc64(p, bs * s->f_blocks); /* total bytes */ - p = enc64(p, bs * s->f_bfree); /* free bytes */ - p = enc64(p, bs * s->f_bavail); /* user available bytes */ - p = enc64(p, s->f_files); /* total inodes */ - p = enc64(p, s->f_ffree); /* free inodes */ - p = enc64(p, s->f_ffree); /* user available inodes */ + p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ + p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ + p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ + p = xdr_encode_hyper(p, s->f_files); /* total inodes */ + p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ + p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ *p++ = htonl(resp->invarsec); /* mean unchanged time */ } return xdr_ressize_check(rqstp, p); @@ -795,7 +776,7 @@ *p++ = htonl(resp->f_wtpref); *p++ = htonl(resp->f_wtmult); *p++ = htonl(resp->f_dtpref); - p = enc64(p, resp->f_maxfilesize); + p = xdr_encode_hyper(p, resp->f_maxfilesize); *p++ = xdr_one; *p++ = xdr_zero; *p++ = htonl(resp->f_properties); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/nfscache.c linux/fs/nfsd/nfscache.c --- v2.2.18/fs/nfsd/nfscache.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/nfscache.c Sun Mar 25 11:37:38 2001 @@ -161,7 +161,7 @@ xid == rp->c_xid && proc == rp->c_proc && proto == rp->c_prot && vers == rp->c_vers && time_before(jiffies, rp->c_timestamp + 120*HZ) && - memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, rqstp->rq_addrlen)==0) { + memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, sizeof(rp->c_addr))==0) { nfsdstats.rchits++; goto found_entry; } @@ -217,13 +217,12 @@ found_entry: /* We found a matching entry which is either in progress or done. */ age = jiffies - rp->c_timestamp; + rp->c_timestamp = jiffies; + lru_put_front(rp); /* Request being processed or excessive rexmits */ if (rp->c_state == RC_INPROG || age < RC_DELAY) return RC_DROPIT; - - rp->c_timestamp = jiffies; - lru_put_front(rp); /* From the hall of fame of impractical attacks: * Is this a user who tries to snoop on the cache? */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c --- v2.2.18/fs/nfsd/nfsctl.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/nfsctl.c Sun Mar 25 11:37:38 2001 @@ -131,7 +131,6 @@ static void nfsd_init(void) { - nfsd_xdr_init(); /* XDR */ nfsd_stat_init(); /* Statistics */ nfsd_cache_init(); /* RPC reply cache */ nfsd_export_init(); /* Exports table */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.2.18/fs/nfsd/nfsfh.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/nfsfh.c Sun Mar 25 11:37:38 2001 @@ -183,7 +183,6 @@ if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED)) printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name); #endif - name->hash = full_name_hash(name->name, name->len); tdentry = d_alloc(parent, name); if (tdentry == NULL) return -ENOMEM; @@ -275,7 +274,6 @@ struct qstr qs; char namebuf[256]; struct list_head *lp; - struct dentry *tmp; /* child is an IS_ROOT (anonymous) dentry, but it is hypothesised that * it should be a child of parent. * We see if we can find a name and, if we can - splice it in. @@ -295,8 +293,8 @@ * parent by a lookup. In this case return that dentry. * caller must notice and act accordingly */ - for (lp = child->d_inode->i_dentry.next; lp != &child->d_inode->i_dentry ; lp=lp->next) { - tmp = list_entry(lp,struct dentry, d_alias); + list_for_each(lp, &child->d_inode->i_dentry) { + struct dentry *tmp = list_entry(lp,struct dentry, d_alias); if (tmp->d_parent == parent) { child = dget(tmp); goto out; @@ -308,12 +306,12 @@ err = get_ino_name(parent, &qs, child->d_inode->i_ino); if (err) goto out; - tmp = d_lookup(parent, &qs); - if (tmp) { + + /* find_inode_number calculates the name hash as a side effect */ + if (find_inode_number(parent, &qs) != 0) { /* Now that IS odd. I wonder what it means... */ err = -EEXIST; printk("nfsd-fh: found a name that I didn't expect: %s/%s\n", parent->d_name.name, qs.name); - dput(tmp); goto out; } err = d_splice(child, parent, &qs); @@ -339,7 +337,7 @@ struct dentry *dentry, *result = NULL; struct dentry *tmp; int found =0; - int err; + int err = -ESTALE; /* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free) * dcache path ever exists, as otherwise two partial paths might get * joined together, which would be very confusing. @@ -353,23 +351,21 @@ * Attempt to find the inode. */ retry: + down(&sb->s_nfsd_free_path_sem); result = nfsd_iget(sb, fh->fh_ino, fh->fh_generation); - err = PTR_ERR(result); - if (IS_ERR(result)) - goto err_out; - err = -ESTALE; - if (!result) { - dprintk("find_fh_dentry: No inode found.\n"); - goto err_out; - } - if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) - return result; - - /* result is now an anonymous dentry, which may be adequate as it - * stands, or else will get spliced into the dcache tree */ - - if (!S_ISDIR(result->d_inode->i_mode) && ! needpath) { - nfsdstats.fh_anon++; + if (!result || IS_ERR(result) + || !(result->d_flags & DCACHE_NFSD_DISCONNECTED) + || (!S_ISDIR(result->d_inode->i_mode) && !needpath)) { + up(&sb->s_nfsd_free_path_sem); + if (!result) { + dprintk("find_fh_dentry: No inode found.\n"); + goto err_out; + } + err = PTR_ERR(result); + if (IS_ERR(result)) + goto err_out; + if ( (result->d_flags & DCACHE_NFSD_DISCONNECTED)) + nfsdstats.fh_anon++; return result; } @@ -377,14 +373,6 @@ * location in the tree. */ dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,fh->fh_ino); - down(&sb->s_nfsd_free_path_sem); - - /* claiming the semaphore might have allow things to get fixed up */ - if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { - up(&sb->s_nfsd_free_path_sem); - return result; - } - found = 0; if (!S_ISDIR(result->d_inode->i_mode)) { @@ -466,6 +454,7 @@ if (tmp != dentry) { /* we lost a race, try again */ + dput(pdentry); dput(tmp); dput(dentry); dput(result); /* this will discard the whole free path, so we can up the semaphore */ @@ -563,7 +552,7 @@ !(exp->ex_flags & NFSEXP_NOSUBTREECHECK)); if (IS_ERR(dentry)) { - error = nfserrno(-PTR_ERR(dentry)); + error = nfserrno(PTR_ERR(dentry)); goto out; } #ifdef NFSD_PARANOIA @@ -690,7 +679,7 @@ fhp->fh_handle.fh_dev = kdev_t_to_u32(parent->d_inode->i_dev); fhp->fh_handle.fh_xdev = kdev_t_to_u32(exp->ex_dev); fhp->fh_handle.fh_xino = ino_t_to_u32(exp->ex_ino); - fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca; + fhp->fh_handle.fh_dcookie = 0xfeebbaca; if (inode) { fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino); fhp->fh_handle.fh_generation = inode->i_generation; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c --- v2.2.18/fs/nfsd/nfsproc.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/nfsproc.c Sun Mar 25 11:37:38 2001 @@ -30,10 +30,6 @@ #define NFSDDBG_FACILITY NFSDDBG_PROC -/* Check for dir entries '.' and '..' */ -#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) - -#define RETURN(st) return st static void svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr) @@ -45,7 +41,7 @@ static int nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) { - RETURN(nfs_ok); + return nfs_ok; } /* @@ -60,7 +56,7 @@ SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - RETURN(fh_verify(rqstp, &resp->fh, 0, MAY_NOP)); + return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); } /* @@ -76,7 +72,7 @@ argp->attrs.ia_valid, (long) argp->attrs.ia_size); fh_copy(&resp->fh, &argp->fh); - RETURN(nfsd_setattr(rqstp, &resp->fh, &argp->attrs)); + return nfsd_setattr(rqstp, &resp->fh, &argp->attrs); } /* @@ -98,7 +94,7 @@ &resp->fh); fh_put(&argp->fh); - RETURN(nfserr); + return nfserr; } /* @@ -121,7 +117,7 @@ nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len); fh_put(&argp->fh); - RETURN(nfserr); + return nfserr; } /* @@ -159,7 +155,7 @@ (char *) buffer, &resp->count); - RETURN(nfserr); + return nfserr; } /* @@ -171,6 +167,7 @@ struct nfsd_attrstat *resp) { int nfserr; + int stable = 1; dprintk("nfsd: WRITE %d/%d %d bytes at %d\n", SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), @@ -180,8 +177,8 @@ argp->offset, argp->data, argp->len, - 0); - RETURN(nfserr); + &stable); + return nfserr; } /* @@ -257,8 +254,19 @@ if (attr->ia_valid & ATTR_MODE) { type = attr->ia_mode & S_IFMT; mode = attr->ia_mode & ~S_IFMT; - if (!type) /* HP weirdness */ - type = S_IFREG; + if (!type) { + /* no type, so if target exists, assume same as that, + * else assume a file */ + if (inode) { + type = inode->i_mode & S_IFMT; + if (type == S_IFCHR || type == S_IFBLK) { + /* reserve rdev for later checking */ + attr->ia_size = inode->i_rdev; + attr->ia_valid |= ATTR_SIZE; + } + } else + type = S_IFREG; + } } else if (inode) { type = inode->i_mode & S_IFMT; mode = inode->i_mode & ~S_IFMT; @@ -331,7 +339,7 @@ done: fh_put(dirfhp); - RETURN(nfserr); + return nfserr; } static int @@ -345,7 +353,7 @@ /* Unlink. -SIFDIR means file must not be a directory */ nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len); fh_put(&argp->fh); - RETURN(nfserr); + return nfserr; } static int @@ -362,7 +370,7 @@ &argp->tfh, argp->tname, argp->tlen); fh_put(&argp->ffh); fh_put(&argp->tfh); - RETURN(nfserr); + return nfserr; } static int @@ -380,7 +388,7 @@ &argp->ffh); fh_put(&argp->ffh); fh_put(&argp->tfh); - RETURN(nfserr); + return nfserr; } static int @@ -404,7 +412,7 @@ fh_put(&argp->ffh); fh_put(&newfh); - RETURN(nfserr); + return nfserr; } /* @@ -428,7 +436,7 @@ nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, &argp->attrs, S_IFDIR, 0, &resp->fh); fh_put(&argp->fh); - RETURN(nfserr); + return nfserr; } /* @@ -444,7 +452,7 @@ nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len); fh_put(&argp->fh); - RETURN(nfserr); + return nfserr; } /* @@ -480,7 +488,7 @@ resp->count = count; fh_put(&argp->fh); - RETURN(nfserr); + return nfserr; } /* @@ -496,7 +504,7 @@ nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); fh_put(&argp->fh); - RETURN(nfserr); + return nfserr; } /* @@ -549,36 +557,36 @@ int nfserr; int syserr; } nfs_errtbl[] = { - { NFS_OK, 0 }, - { NFSERR_PERM, EPERM }, - { NFSERR_NOENT, ENOENT }, - { NFSERR_IO, EIO }, - { NFSERR_NXIO, ENXIO }, - { NFSERR_ACCES, EACCES }, - { NFSERR_EXIST, EEXIST }, - { NFSERR_XDEV, EXDEV }, - { NFSERR_MLINK, EMLINK }, - { NFSERR_NODEV, ENODEV }, - { NFSERR_NOTDIR, ENOTDIR }, - { NFSERR_ISDIR, EISDIR }, - { NFSERR_INVAL, EINVAL }, - { NFSERR_FBIG, EFBIG }, - { NFSERR_NOSPC, ENOSPC }, - { NFSERR_ROFS, EROFS }, - { NFSERR_MLINK, EMLINK }, - { NFSERR_NAMETOOLONG, ENAMETOOLONG }, - { NFSERR_NOTEMPTY, ENOTEMPTY }, + { nfs_ok, 0 }, + { nfserr_perm, -EPERM }, + { nfserr_noent, -ENOENT }, + { nfserr_io, -EIO }, + { nfserr_nxio, -ENXIO }, + { nfserr_acces, -EACCES }, + { nfserr_exist, -EEXIST }, + { nfserr_xdev, -EXDEV }, + { nfserr_mlink, -EMLINK }, + { nfserr_nodev, -ENODEV }, + { nfserr_notdir, -ENOTDIR }, + { nfserr_isdir, -EISDIR }, + { nfserr_inval, -EINVAL }, + { nfserr_fbig, -EFBIG }, + { nfserr_nospc, -ENOSPC }, + { nfserr_rofs, -EROFS }, + { nfserr_mlink, -EMLINK }, + { nfserr_nametoolong, -ENAMETOOLONG }, + { nfserr_notempty, -ENOTEMPTY }, #ifdef EDQUOT - { NFSERR_DQUOT, EDQUOT }, + { nfserr_dquot, -EDQUOT }, #endif - { NFSERR_STALE, ESTALE }, - { -1, EIO } + { nfserr_stale, -ESTALE }, + { -1, -EIO } }; int i; for (i = 0; nfs_errtbl[i].nfserr != -1; i++) { if (nfs_errtbl[i].syserr == errno) - return htonl(nfs_errtbl[i].nfserr); + return nfs_errtbl[i].nfserr; } printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno); return nfserr_io; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c --- v2.2.18/fs/nfsd/nfsxdr.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/nfsxdr.c Sun Mar 25 11:37:38 2001 @@ -17,15 +17,6 @@ #define NFSDDBG_FACILITY NFSDDBG_XDR -u32 nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio, - nfserr_acces, nfserr_exist, nfserr_xdev, nfserr_nodev, - nfserr_notdir, nfserr_isdir, nfserr_inval, nfserr_fbig, - nfserr_nospc, nfserr_rofs, nfserr_mlink, - nfserr_nametoolong, nfserr_notempty, nfserr_dquot, nfserr_stale, - nfserr_remote, nfserr_badhandle, nfserr_notsync, - nfserr_badcookie, nfserr_notsupp, nfserr_toosmall, - nfserr_serverfault, nfserr_badtype, nfserr_jukebox; - #ifdef NFSD_OPTIMIZE_SPACE # define inline @@ -35,57 +26,12 @@ * Mapping of S_IF* types to NFS file types */ static u32 nfs_ftypes[] = { - NFNON, NFFIFO, NFCHR, NFBAD, + NFNON, NFCHR, NFCHR, NFBAD, NFDIR, NFBAD, NFBLK, NFBAD, NFREG, NFBAD, NFLNK, NFBAD, NFSOCK, NFBAD, NFLNK, NFBAD, }; -/* - * Initialization of NFS status variables - */ -void -nfsd_xdr_init(void) -{ - static int inited = 0; - - if (inited) - return; - - nfs_ok = htonl(NFS_OK); - nfserr_perm = htonl(NFSERR_PERM); - nfserr_noent = htonl(NFSERR_NOENT); - nfserr_io = htonl(NFSERR_IO); - nfserr_inval = htonl(NFSERR_INVAL); - nfserr_nxio = htonl(NFSERR_NXIO); - nfserr_acces = htonl(NFSERR_ACCES); - nfserr_exist = htonl(NFSERR_EXIST); - nfserr_xdev = htonl(NFSERR_XDEV); - nfserr_nodev = htonl(NFSERR_NODEV); - nfserr_notdir = htonl(NFSERR_NOTDIR); - nfserr_isdir = htonl(NFSERR_ISDIR); - nfserr_inval = htonl(NFSERR_INVAL); - nfserr_fbig = htonl(NFSERR_FBIG); - nfserr_nospc = htonl(NFSERR_NOSPC); - nfserr_rofs = htonl(NFSERR_ROFS); - nfserr_mlink = htonl(NFSERR_MLINK); - nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG); - nfserr_notempty = htonl(NFSERR_NOTEMPTY); - nfserr_dquot = htonl(NFSERR_DQUOT); - nfserr_stale = htonl(NFSERR_STALE); - nfserr_remote = htonl(NFSERR_REMOTE); - nfserr_badhandle = htonl(NFSERR_BADHANDLE); - nfserr_notsync = htonl(NFSERR_NOT_SYNC); - nfserr_badcookie = htonl(NFSERR_BAD_COOKIE); - nfserr_notsupp = htonl(NFSERR_NOTSUPP); - nfserr_toosmall = htonl(NFSERR_TOOSMALL); - nfserr_serverfault = htonl(NFSERR_SERVERFAULT); - nfserr_badtype = htonl(NFSERR_BADTYPE); - nfserr_jukebox = htonl(NFSERR_JUKEBOX); - - - inited = 1; -} /* * XDR functions for basic NFS types @@ -189,20 +135,25 @@ static inline u32 * encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode) { + int type = (inode->i_mode & S_IFMT); if (!inode) return 0; - *p++ = htonl(nfs_ftypes[(inode->i_mode & S_IFMT) >> 12]); + *p++ = htonl(nfs_ftypes[type >> 12]); *p++ = htonl((u32) inode->i_mode); *p++ = htonl((u32) inode->i_nlink); *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid)); *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid)); - if (S_ISLNK(inode->i_mode) && inode->i_size > NFS_MAXPATHLEN) { + + if (S_ISLNK(type) && inode->i_size > NFS_MAXPATHLEN) { *p++ = htonl(NFS_MAXPATHLEN); } else { *p++ = htonl((u32) inode->i_size); } *p++ = htonl((u32) inode->i_blksize); - *p++ = htonl((u32) inode->i_rdev); + if (S_ISCHR(type) || S_ISBLK(type)) + *p++ = htonl((u32) inode->i_rdev); + else + *p++ = htonl(0xffffffff); *p++ = htonl((u32) inode->i_blocks); *p++ = htonl((u32) inode->i_dev); *p++ = htonl((u32) inode->i_ino); @@ -465,11 +416,9 @@ cd->eob = 1; return -EINVAL; } - *p++ = xdr_one; /* mark entry present */ - *p++ = htonl((u32) ino); /* file id */ - *p++ = htonl((u32) namlen); /* name length & name */ - memcpy(p, name, namlen); - p += slen; + *p++ = xdr_one; /* mark entry present */ + *p++ = htonl((u32) ino); /* file id */ + p = xdr_encode_string(p, name, namlen);/* name length & name */ cd->offset = p; /* remember pointer */ *p++ = ~(u32) 0; /* offset of next entry */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.2.18/fs/nfsd/vfs.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nfsd/vfs.c Sun Mar 25 11:37:38 2001 @@ -59,9 +59,6 @@ */ extern long nfsd_time_diff_margin; -/* Check for dir entries '.' and '..' */ -#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) - /* * This is a cache of readahead params that help us choose the proper * readahead strategy. Initially, we set all readahead parameters to 0 @@ -157,15 +154,12 @@ dparent = fhp->fh_dentry; exp = fhp->fh_export; -#if 0 - err = nfsd_permission(exp, dparent, MAY_EXEC); - if (err) - goto out; -#endif err = nfserr_acces; /* Lookup the name, but don't follow links */ - if (strcmp(name, "..")==0) { + if (strcmp(name, ".")==0) { + dchild = dget(dparent); + } else if (strcmp(name, "..")==0) { /* checking mountpoint crossing is very different when stepping up */ if (dparent == exp->ex_dentry) { if (!EX_CROSSMNT(exp)) @@ -230,7 +224,7 @@ return err; out_nfserr: - err = nfserrno(-PTR_ERR(dchild)); + err = nfserrno(PTR_ERR(dchild)); goto out; } @@ -283,11 +277,11 @@ if (delta<0) delta = -delta; if (delta < MAX_TOUCH_TIME_ERROR) { /* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME - * this will cause notify_change to setthese times to "now" + * this will cause notify_change to set these times to "now" */ iap->ia_valid &= ~BOTH_TIME_SET; err = inode_change_ok(inode, iap); - } + } } if (err) @@ -295,8 +289,6 @@ /* The size case is special. It changes the file as well as the attributes. */ if (iap->ia_valid & ATTR_SIZE) { -if (!S_ISREG(inode->i_mode)) -printk("nfsd_setattr: size change??\n"); if (iap->ia_size < inode->i_size) { err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC); if (err) @@ -380,7 +372,7 @@ return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } @@ -412,8 +404,16 @@ }; static struct accessmap nfs3_anyaccess[] = { - /* XXX: should we try to cover read/write here for clients that - * rely on us to do their access checking for special files? */ + /* Some clients - Solaris 2.6 at least, make an access call + * to the server to check for access for things like /dev/null + * (which really, the server doesn't care about). So + * We provide simple access checking for them, looking + * mainly at mode bits + */ + { NFS3_ACCESS_READ, MAY_READ }, + { NFS3_ACCESS_EXECUTE, MAY_EXEC }, + { NFS3_ACCESS_MODIFY, MAY_WRITE }, + { NFS3_ACCESS_EXTEND, MAY_WRITE }, { 0, 0 } }; @@ -425,7 +425,7 @@ struct svc_export *export; struct dentry *dentry; u32 query, result = 0; - int error; + unsigned int error; error = fh_verify(rqstp, fhp, 0, MAY_NOP); if (error) @@ -434,41 +434,45 @@ export = fhp->fh_export; dentry = fhp->fh_dentry; - if (S_ISREG(dentry->d_inode->i_mode)) { + if (S_ISREG(dentry->d_inode->i_mode)) map = nfs3_regaccess; - } else if (S_ISDIR(dentry->d_inode->i_mode)) { + else if (S_ISDIR(dentry->d_inode->i_mode)) map = nfs3_diraccess; - } else { + else map = nfs3_anyaccess; - } + query = *access; - while (map->access) { + for (; map->access; map++) { if (map->access & query) { error = nfsd_permission(export, dentry, (map->how | NO_OWNER_OVERRIDE)); - if (error == 0) + switch(error) { + case 0: result |= map->access; - else if ((error == nfserr_perm) || (error == nfserr_acces)) { + break; + case nfserr_perm: + case nfserr_acces: + case nfserr_rofs: /* * This access type is denyed; but the * access query itself succeeds. */ error = 0; - } else { + break; + default: /* * Some fatal error. Fail the query. */ goto out; } } - map++; } *access = result; out: return error; } -#endif +#endif /* CONFIG_NFSD_V3 */ @@ -532,7 +536,7 @@ } out_nfserr: if (err) - err = nfserrno(-err); + err = nfserrno(err); out: return err; } @@ -553,9 +557,8 @@ dentry->d_parent->d_name.name, dentry->d_name.name); if (filp->f_op && filp->f_op->release) filp->f_op->release(inode, filp); - if (filp->f_mode & FMODE_WRITE) { + if (filp->f_mode & FMODE_WRITE) put_write_access(inode); - } } /* @@ -638,7 +641,7 @@ goto out_close; /* Get readahead parameters */ - ra = nfsd_get_raparms(fhp->fh_handle.fh_dev, fhp->fh_handle.fh_ino); + ra = nfsd_get_raparms(fhp->fh_export->ex_dev, fhp->fh_dentry->d_inode->i_ino); if (ra) { file.f_reada = ra->p_reada; file.f_ramax = ra->p_ramax; @@ -669,7 +672,7 @@ *count = err; err = 0; } else - err = nfserrno(-err); + err = nfserrno(err); out_close: nfsd_close(&file); out: @@ -683,7 +686,7 @@ */ int nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, - char *buf, unsigned long cnt, int stable) + char *buf, unsigned long cnt, int *stablep) { struct svc_export *exp; struct file file; @@ -691,6 +694,7 @@ struct inode *inode; mm_segment_t oldfs; int err = 0; + int stable = *stablep; #ifdef CONFIG_QUOTA uid_t saved_euid; #endif @@ -716,17 +720,16 @@ * When gathered writes have been configured for this volume, * flushing the data to disk is handled separately below. */ -#ifdef CONFIG_NFSD_V3 - if (rqstp->rq_vers == 2) - stable = EX_ISSYNC(exp); - else if (file.f_op->fsync == 0) - stable = 1; + + if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */ + stable = 2; + *stablep = 2; /* FILE_SYNC */ + } + + if (!EX_ISSYNC(exp)) + stable = 0; if (stable && !EX_WGATHER(exp)) file.f_flags |= O_SYNC; -#else - if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp)) - file.f_flags |= O_SYNC; -#endif /* CONFIG_NFSD_V3 */ fh_lock(fhp); /* lock inode */ file.f_pos = offset; /* set write offset */ @@ -787,7 +790,7 @@ dprintk("nfsd: write resume %d\n", current->pid); } - if (inode->i_state & I_DIRTY) { + if (EX_WGATHER(exp) && (inode->i_state & I_DIRTY)) { dprintk("nfsd: write sync %d\n", current->pid); nfsd_sync(&file); } @@ -802,7 +805,7 @@ if (err >= 0) err = 0; else - err = nfserrno(-err); + err = nfserrno(err); out_close: nfsd_close(&file); out: @@ -812,8 +815,8 @@ #ifdef CONFIG_NFSD_V3 /* - * Commit all pendig writes to stable storage. - * Strictly speaking, we could sync just indicated the file region here, + * Commit all pending writes to stable storage. + * Strictly speaking, we could sync just the indicated file region here, * but there's currently no way we can ask the VFS to do so. * * We lock the file to make sure we return full WCC data to the client. @@ -827,14 +830,15 @@ if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0) return err; - - fh_lock(fhp); - if (file.f_op && file.f_op->fsync) { - file.f_op->fsync(&file, file.f_dentry); - } else { - err = nfserr_notsupp; + if (EX_ISSYNC(fhp->fh_export)) { + fh_lock(fhp); + if (file.f_op && file.f_op->fsync) { + file.f_op->fsync(&file, file.f_dentry); + } else { + err = nfserr_notsupp; + } + fh_unlock(fhp); } - fh_unlock(fhp); nfsd_close(&file); return err; @@ -862,6 +866,9 @@ err = nfserr_perm; if (!flen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); if (err) @@ -873,10 +880,6 @@ err = nfserr_notdir; if(!dirp->i_op || !dirp->i_op->lookup) goto out; - - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; /* * Check whether the response file handle has been verified yet. * If it has, the parent directory should already be locked. @@ -901,7 +904,7 @@ dentry->d_name.name); err = -EIO; goto out; - } + } } /* * Make sure the child dentry is still negative ... @@ -959,10 +962,6 @@ write_inode_now(dchild->d_inode); } - /* - * Update the file handle to get the new inode info. - */ - fh_update(resfhp); /* Set file attributes. Mode has already been set and * setting uid/gid works only for root. Irix appears to @@ -972,11 +971,15 @@ err = 0; if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) err = nfsd_setattr(rqstp, resfhp, iap); + /* + * Update the file handle to get the new inode info. + */ + fh_update(resfhp); out: return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } @@ -992,10 +995,15 @@ struct dentry *dentry, *dchild; struct inode *dirp; int err; + __u32 v_mtime=0, v_atime=0; + int v_mode=0; err = nfserr_perm; if (!flen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; if (!(iap->ia_valid & ATTR_MODE)) iap->ia_mode = 0; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); @@ -1014,9 +1022,6 @@ if(!dirp->i_op->create) goto out; - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; /* * Compose the response file handle. */ @@ -1033,6 +1038,19 @@ if (err) goto out; + if (createmode == NFS3_CREATE_EXCLUSIVE) { + /* while the verifier would fit in mtime+atime, + * solaris7 gets confused (bugid 4218508) if these have + * the high bit set, so we use the mode as well + */ + v_mtime = verifier[0]&0x7fffffff; + v_atime = verifier[1]&0x7fffffff; + v_mode = S_IFREG + | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */ + | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */ + ; + } + if (dchild->d_inode) { err = 0; @@ -1050,10 +1068,10 @@ } break; case NFS3_CREATE_EXCLUSIVE: - if ( dchild->d_inode->i_mtime == verifier[0] - && dchild->d_inode->i_atime == verifier[1] - && dchild->d_inode->i_mode == S_IFREG - && dchild->d_inode->i_size == 0 ) + if ( dchild->d_inode->i_mtime == v_mtime + && dchild->d_inode->i_atime == v_atime + && dchild->d_inode->i_mode == v_mode + && dchild->d_inode->i_size == 0 ) break; /* fallthru */ case NFS3_CREATE_GUARDED: @@ -1078,19 +1096,23 @@ err = 0; if (createmode == NFS3_CREATE_EXCLUSIVE) { - /* Cram the verifier into atime/mtime */ - iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET; - iap->ia_mtime = verifier[0]; - iap->ia_atime = verifier[1]; + /* Cram the verifier into atime/mtime/mode */ + iap->ia_valid = ATTR_MTIME|ATTR_ATIME + | ATTR_MTIME_SET|ATTR_ATIME_SET + | ATTR_MODE; + iap->ia_mtime = v_mtime; + iap->ia_atime = v_atime; + iap->ia_mode = v_mode; } - /* Set file attributes. Mode has already been set and - * setting uid/gid works only for root. Irix appears to - * send along the gid when it tries to implement setgid - * directories via NFS. Clear out all that cruft. + /* Set file attributes. + * Mode has already been set but we might need to reset it + * for CREATE_EXCLUSIVE + * Irix appears to send along the gid when it tries to + * implement setgid directories via NFS. Clear out all that cruft. */ set_attr: - if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) + if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) err = nfsd_setattr(rqstp, resfhp, iap); out: @@ -1098,68 +1120,12 @@ return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } #endif /* CONFIG_NFSD_V3 */ /* - * Truncate a file. - * The calling routines must make sure to update the ctime - * field and call notify_change. - * - * XXX Nobody calls this thing? -DaveM - * N.B. After this call fhp needs an fh_put - */ -int -nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size) -{ - struct dentry *dentry; - struct inode *inode; - struct iattr newattrs; - int err; - kernel_cap_t saved_cap = 0; - - err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC); - if (err) - goto out; - - dentry = fhp->fh_dentry; - inode = dentry->d_inode; - - err = get_write_access(inode); - if (err) - goto out_nfserr; - - /* Things look sane, lock and do it. */ - fh_lock(fhp); - DQUOT_INIT(inode); - newattrs.ia_size = size; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - if (current->fsuid != 0) { - saved_cap = current->cap_effective; - cap_clear(current->cap_effective); - } - err = notify_change(dentry, &newattrs); - if (!err) { - vmtruncate(inode, size); - if (inode->i_op && inode->i_op->truncate) - inode->i_op->truncate(inode); - } - if (current->fsuid != 0) - current->cap_effective = saved_cap; - put_write_access(inode); - if (EX_ISSYNC(fhp->fh_export)) - nfsd_sync_dir(dentry); - fh_unlock(fhp); -out_nfserr: - if (err) - err = nfserrno(-err); -out: - return err; -} - -/* * Read a symlink. On entry, *lenp must contain the maximum path length that * fits into the buffer. On return, it contains the true length. * N.B. After this call fhp needs an fh_put @@ -1172,7 +1138,7 @@ mm_segment_t oldfs; int err; - err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ); + err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); if (err) goto out; @@ -1200,7 +1166,7 @@ return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } @@ -1223,15 +1189,15 @@ if (!flen || !plen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); if (err) goto out; dentry = fhp->fh_dentry; - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; - err = nfserr_perm; dirp = dentry->d_inode; if (!dirp->i_op || !dirp->i_op->symlink) @@ -1268,7 +1234,7 @@ } } } else - err = nfserrno(-err); + err = nfserrno(err); } fh_unlock(fhp); @@ -1280,7 +1246,7 @@ return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } @@ -1299,6 +1265,11 @@ err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); if (err) goto out; + + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; + err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP); if (err) goto out; @@ -1307,10 +1278,6 @@ if (!flen) goto out; - err = nfserr_exist; - if (isdotent(fname, flen)) - goto out; - ddir = ffhp->fh_dentry; dirp = ddir->d_inode; @@ -1350,7 +1317,7 @@ write_inode_now(dest); } } else - err = nfserrno(-err); + err = nfserrno(err); out_unlock: fh_unlock(ffhp); @@ -1360,7 +1327,7 @@ return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } @@ -1478,7 +1445,7 @@ return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } @@ -1494,13 +1461,14 @@ struct inode *dirp; int err; - err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); - if (err) - goto out; err = nfserr_acces; if (!flen || isdotent(fname, flen)) goto out; + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); + if (err) + goto out; + dentry = fhp->fh_dentry; dirp = dentry->d_inode; @@ -1520,8 +1488,10 @@ /* It's UNLINK */ err = fh_lock_parent(fhp, rdentry); - if (err) + if (err) { + dput(rdentry); goto out; + } err = vfs_unlink(dirp, rdentry); @@ -1568,7 +1538,7 @@ return err; out_nfserr: - err = nfserrno(-err); + err = nfserrno(err); goto out; } @@ -1610,6 +1580,7 @@ * may choose to do less. */ inode = file.f_dentry->d_inode; + down(&inode->i_sem); while (1) { oldlen = cd.buflen; @@ -1618,9 +1589,7 @@ file.f_inode->i_dev, file.f_inode->i_ino, (int) file.f_pos, (int) oldlen, (int) cd.buflen); */ - down(&inode->i_sem); err = file.f_op->readdir(&file, &cd, (filldir_t) func); - up(&inode->i_sem); if (err < 0) goto out_nfserr; if (oldlen == cd.buflen) @@ -1628,16 +1597,15 @@ if (cd.eob) break; } + up(&inode->i_sem); /* If we didn't fill the buffer completely, we're at EOF */ eof = !cd.eob; if (cd.offset) { -#ifdef CONFIG_NFSD_V3 if (rqstp->rq_vers == 3) - (void)enc64(cd.offset, file.f_pos); + (void)xdr_encode_hyper(cd.offset, file.f_pos); else -#endif /* CONFIG_NFSD_V3 */ *cd.offset = htonl(file.f_pos); } @@ -1656,7 +1624,8 @@ return err; out_nfserr: - err = nfserrno(-err); + up(&inode->i_sem); + err = nfserrno(err); goto out_close; } @@ -1737,12 +1706,17 @@ inode->i_uid, inode->i_gid, current->fsuid, current->fsgid); #endif - if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { - if (EX_RDONLY(exp) || IS_RDONLY(inode)) - return nfserr_rofs; - if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) - return nfserr_perm; - } + /* only care about readonly exports for files and + * directories. links don't have meaningful write access, + * and all else is local to the client + */ + if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) + if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { + if (EX_RDONLY(exp) || IS_RDONLY(inode)) + return nfserr_rofs; + if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) + return nfserr_perm; + } if ((acc & MAY_TRUNC) && IS_APPEND(inode)) return nfserr_perm; @@ -1786,7 +1760,7 @@ if (current->fsuid != 0) current->cap_effective = saved_cap; - return err? nfserrno(-err) : 0; + return err? nfserrno(err) : 0; } void diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nls/Config.in linux/fs/nls/Config.in --- v2.2.18/fs/nls/Config.in Sun Mar 25 11:28:34 2001 +++ linux/fs/nls/Config.in Sun Mar 25 11:37:38 2001 @@ -47,5 +47,6 @@ tristate 'NLS ISO 8859-14 (Latin 8; Celtic)' CONFIG_NLS_ISO8859_14 tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15 tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R + tristate 'NLS KOI8-RU (Belorussia, Ukraine)' CONFIG_NLS_KOI8_RU endmenu fi diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nls/Makefile linux/fs/nls/Makefile --- v2.2.18/fs/nls/Makefile Sun Mar 25 11:12:33 2001 +++ linux/fs/nls/Makefile Sun Mar 25 11:37:38 2001 @@ -342,6 +342,14 @@ endif endif +ifeq ($(CONFIG_NLS_KOI8_RU),y) +NLS += nls_koi8-ru.o +else + ifeq ($(CONFIG_NLS_KOI8_RU),m) + M_OBJS += nls_koi8-ru.o + endif +endif + O_TARGET = nls.o OX_OBJS = $(NLS) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nls/nls_base.c linux/fs/nls/nls_base.c --- v2.2.18/fs/nls/nls_base.c Sun Mar 25 11:28:34 2001 +++ linux/fs/nls/nls_base.c Sun Mar 25 11:37:38 2001 @@ -529,6 +529,9 @@ #ifdef CONFIG_NLS_KOI8_R init_nls_koi8_r(); #endif +#ifdef CONFIG_NLS_KOI8_RU + init_nls_koi8_ru(); +#endif return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/nls/nls_koi8-ru.c linux/fs/nls/nls_koi8-ru.c --- v2.2.18/fs/nls/nls_koi8-ru.c Wed Dec 31 19:00:00 1969 +++ linux/fs/nls/nls_koi8-ru.c Sun Mar 25 11:37:38 2001 @@ -0,0 +1,401 @@ +/* + * linux/fs/nls_koi8-r.c + * + * Charset koi8-r translation tables. + * Generated automatically from the Unicode and charset + * tables from the Unicode Organization (www.unicode.org). + * The Unicode to charset table has only exact mappings. + */ + +#include +#include +#include +#include +#include + +static struct nls_unicode charset2uni[256] = { + /* 0x00*/ + {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00}, + {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00}, + {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00}, + {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00}, + /* 0x10*/ + {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, + {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, + {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00}, + {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00}, + /* 0x20*/ + {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00}, + {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, + {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, + {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00}, + /* 0x30*/ + {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, + {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00}, + {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00}, + {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00}, + /* 0x40*/ + {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00}, + {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00}, + {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00}, + {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00}, + /* 0x50*/ + {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00}, + {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00}, + {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00}, + {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00}, + /* 0x60*/ + {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00}, + {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00}, + {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00}, + {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00}, + /* 0x70*/ + {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00}, + {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00}, + {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00}, + {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00}, + /* 0x80*/ + {0x00, 0x25}, {0x02, 0x25}, {0x0c, 0x25}, {0x10, 0x25}, + {0x14, 0x25}, {0x18, 0x25}, {0x1c, 0x25}, {0x24, 0x25}, + {0x2c, 0x25}, {0x34, 0x25}, {0x3c, 0x25}, {0x80, 0x25}, + {0x84, 0x25}, {0x88, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, + /* 0x90*/ + {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x20, 0x23}, + {0xa0, 0x25}, {0x19, 0x22}, {0x1a, 0x22}, {0x48, 0x22}, + {0x64, 0x22}, {0x65, 0x22}, {0xa0, 0x00}, {0x21, 0x23}, + {0xb0, 0x00}, {0xb2, 0x00}, {0xb7, 0x00}, {0xf7, 0x00}, + /* 0xa0*/ + {0x50, 0x25}, {0x51, 0x25}, {0x52, 0x25}, {0x51, 0x04}, + {0x54, 0x04}, {0x54, 0x25}, {0x56, 0x04}, {0x57, 0x04}, + {0x57, 0x25}, {0x58, 0x25}, {0x59, 0x25}, {0x5a, 0x25}, + {0x5b, 0x25}, {0x91, 0x04}, {0x5e, 0x04}, {0x5e, 0x25}, + /* 0xb0*/ + {0x5f, 0x25}, {0x60, 0x25}, {0x61, 0x25}, {0x01, 0x04}, + {0x04, 0x04}, {0x63, 0x25}, {0x06, 0x04}, {0x07, 0x04}, + {0x66, 0x25}, {0x67, 0x25}, {0x68, 0x25}, {0x69, 0x25}, + {0x6a, 0x25}, {0x90, 0x04}, {0x0e, 0x04}, {0xa9, 0x00}, + /* 0xc0*/ + {0x4e, 0x04}, {0x30, 0x04}, {0x31, 0x04}, {0x46, 0x04}, + {0x34, 0x04}, {0x35, 0x04}, {0x44, 0x04}, {0x33, 0x04}, + {0x45, 0x04}, {0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04}, + {0x3b, 0x04}, {0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04}, + /* 0xd0*/ + {0x3f, 0x04}, {0x4f, 0x04}, {0x40, 0x04}, {0x41, 0x04}, + {0x42, 0x04}, {0x43, 0x04}, {0x36, 0x04}, {0x32, 0x04}, + {0x4c, 0x04}, {0x4b, 0x04}, {0x37, 0x04}, {0x48, 0x04}, + {0x4d, 0x04}, {0x49, 0x04}, {0x47, 0x04}, {0x4a, 0x04}, + /* 0xe0*/ + {0x2e, 0x04}, {0x10, 0x04}, {0x11, 0x04}, {0x26, 0x04}, + {0x14, 0x04}, {0x15, 0x04}, {0x24, 0x04}, {0x13, 0x04}, + {0x25, 0x04}, {0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04}, + {0x1b, 0x04}, {0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04}, + /* 0xf0*/ + {0x1f, 0x04}, {0x2f, 0x04}, {0x20, 0x04}, {0x21, 0x04}, + {0x22, 0x04}, {0x23, 0x04}, {0x16, 0x04}, {0x12, 0x04}, + {0x2c, 0x04}, {0x2b, 0x04}, {0x17, 0x04}, {0x28, 0x04}, + {0x2d, 0x04}, {0x29, 0x04}, {0x27, 0x04}, {0x2a, 0x04}, +}; + +static unsigned char page00[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page04[256] = { + 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0xb7, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, /* 0x08-0x0f */ + 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */ + 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */ + 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */ + 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */ + 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */ + 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */ + 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */ + 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */ + 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa6, 0xa7, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page22[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page23[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char page25[256] = { + 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ + 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */ + 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */ + 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */ + 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */ + 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */ + 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ + 0xa0, 0xa1, 0xa2, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, /* 0x50-0x57 */ + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */ + 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, /* 0x60-0x67 */ + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ + + 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */ + 0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ + 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + +static unsigned char *page_uni2charset[256] = { + page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, page22, page23, NULL, page25, NULL, NULL, +}; + +#if 0 +static unsigned char charset2upper[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ + 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ + 0xa0, 0xa1, 0xa2, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ +}; +#endif + +static void uni2char(unsigned char ch, unsigned char cl, unsigned char *out, int boundlen, int *outlen) +{ + unsigned char *uni2charset; + + if (boundlen <= 0) + return; + + uni2charset = page_uni2charset[ch]; + if (uni2charset && uni2charset[cl]) + out[0] = uni2charset[cl]; + else + out[0] = '?'; + *outlen = 1; + return; +} + +static void char2uni(const unsigned char *rawstring, int *offset, unsigned char *uni1, unsigned char *uni2) +{ + *uni1 = charset2uni[*rawstring].uni1; + *uni2 = charset2uni[*rawstring].uni2; + *offset = 1; + return; +} + +static void inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static struct nls_table table = { + "koi8-ru", + uni2char, + char2uni, + inc_use_count, + dec_use_count, + NULL +}; + +int __init init_nls_koi8_ru(void) +{ + return register_nls(&table); +} + +#ifdef MODULE +int init_module(void) +{ + return init_nls_koi8_ru(); +} + + +void cleanup_module(void) +{ + unregister_nls(&table); + return; +} +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/open.c linux/fs/open.c --- v2.2.18/fs/open.c Sun Mar 25 11:28:36 2001 +++ linux/fs/open.c Sun Mar 25 11:37:38 2001 @@ -73,7 +73,7 @@ if ((off_t) length < 0) return -EINVAL; - down(&inode->i_sem); + fs_down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; error = notify_change(dentry, &newattrs); @@ -83,7 +83,7 @@ if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode); } - up(&inode->i_sem); + fs_up(&inode->i_sem); return error; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/proc/array.c linux/fs/proc/array.c --- v2.2.18/fs/proc/array.c Sun Mar 25 11:28:36 2001 +++ linux/fs/proc/array.c Sun Mar 25 11:37:38 2001 @@ -1329,7 +1329,7 @@ extern int get_ksyms_list(char *, char **, off_t, int); #endif extern int get_device_list(char *); -extern int get_partition_list(char *); +extern int get_partition_list(char *, char **, off_t, int); extern int get_filesystem_list(char *); extern int get_filesystem_info( char * ); #ifndef CONFIG_ARCH_S390 @@ -1397,7 +1397,7 @@ return get_device_list(page); case PROC_PARTITIONS: - return get_partition_list(page); + return get_partition_list(page, start, offset, length); #ifndef CONFIG_ARCH_S390 case PROC_INTERRUPTS: return get_irq_list(page); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/read_write.c linux/fs/read_write.c --- v2.2.18/fs/read_write.c Sun Mar 25 11:12:31 2001 +++ linux/fs/read_write.c Sun Mar 25 11:37:38 2001 @@ -166,9 +166,9 @@ if (!file->f_op || !(write = file->f_op->write)) goto out; - down(&inode->i_sem); + fs_down(&inode->i_sem); ret = write(file, buf, count, &file->f_pos); - up(&inode->i_sem); + fs_up(&inode->i_sem); out: fput(file); bad_file: @@ -314,9 +314,9 @@ if (!file) goto bad_file; if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) { - down(&file->f_dentry->d_inode->i_sem); + fs_down(&file->f_dentry->d_inode->i_sem); ret = do_readv_writev(VERIFY_READ, file, vector, count); - up(&file->f_dentry->d_inode->i_sem); + fs_up(&file->f_dentry->d_inode->i_sem); } fput(file); @@ -386,9 +386,9 @@ if (pos < 0) goto out; - down(&file->f_dentry->d_inode->i_sem); + fs_down(&file->f_dentry->d_inode->i_sem); ret = write(file, buf, count, &pos); - up(&file->f_dentry->d_inode->i_sem); + fs_up(&file->f_dentry->d_inode->i_sem); out: fput(file); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog --- v2.2.18/fs/smbfs/ChangeLog Sun Mar 25 11:28:36 2001 +++ linux/fs/smbfs/ChangeLog Sun Mar 25 11:37:38 2001 @@ -1,5 +1,10 @@ ChangeLog for smbfs. +2000-11-22 Igor Zhbanov + + * proc.c: fixed date_unix2dos for dates earlier than 01/01/1980 + and date_dos2unix for date==0 + 2000-11-04 Urban Widmark * proc.c, sock.c: adjust max parameters & max data to follow max_xmit @@ -41,7 +46,7 @@ * proc.c: removed support for old protocol levels. It didn't work anyway and was cluttering things up a lot. -2000-01-?? cpg@aladdin.de +2000-01-03 Christian Groessler * proc.c: added posix semantics for unlink diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.2.18/fs/smbfs/proc.c Sun Mar 25 11:28:36 2001 +++ linux/fs/smbfs/proc.c Sun Mar 25 11:37:39 2001 @@ -280,7 +280,9 @@ int month, year; time_t secs; - month = ((date >> 5) & 15) - 1; + /* first subtract and mask after that... Otherwise, if + date == 0, bad things happen */ + month = ((date >> 5) - 1) & 15; year = date >> 9; secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 && @@ -299,6 +301,11 @@ int day, year, nl_day, month; unix_date = utc2local(server, unix_date); + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (unix_date < 315532800) + unix_date = 315532800; + *time = (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) + (((unix_date / 3600) % 24) << 11); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h --- v2.2.18/include/asm-alpha/mmu_context.h Sun Mar 25 11:12:39 2001 +++ linux/include/asm-alpha/mmu_context.h Sun Mar 25 11:37:39 2001 @@ -65,12 +65,7 @@ #endif /* __SMP__ */ #define WIDTH_HARDWARE_ASN 8 -#ifdef __SMP__ -#define WIDTH_THIS_PROCESSOR 5 -#else -#define WIDTH_THIS_PROCESSOR 0 -#endif -#define ASN_FIRST_VERSION (1UL << (WIDTH_THIS_PROCESSOR + WIDTH_HARDWARE_ASN)) +#define ASN_FIRST_VERSION (1UL << WIDTH_HARDWARE_ASN) #define HARDWARE_ASN_MASK ((1UL << WIDTH_HARDWARE_ASN) - 1) /* @@ -100,6 +95,7 @@ /* If we've wrapped, flush the whole user TLB. */ if ((asn & HARDWARE_ASN_MASK) >= MAX_ASN) { tbiap(); + imb(); next = (asn & ~HARDWARE_ASN_MASK) + ASN_FIRST_VERSION; } cpu_last_asn(smp_processor_id()) = next; @@ -125,19 +121,21 @@ __EXTERN_INLINE void ev5_get_mmu_context(struct task_struct *p) { - /* Check if our ASN is of an older version, or on a different CPU, - and thus invalid. */ - /* ??? If we have two threads on different cpus, we'll continually - fight over the context. Find a way to record a per-mm, per-cpu - value for the asn. */ - - unsigned long asn = cpu_last_asn(smp_processor_id()); - struct mm_struct *mm = p->mm; - unsigned long mmc = mm->context; + /* Check if our ASN is of an older version, and thus invalid. */ + int cpu; + unsigned long asn; + struct mm_struct *mm; + unsigned long mmc; + cpu = smp_processor_id(); + mm = p->mm; + ctx_cli(); + asn = cpu_last_asn(cpu); + mmc = mm->context[cpu]; + if ((mmc ^ asn) & ~HARDWARE_ASN_MASK) { mmc = __get_new_mmu_context(); - mm->context = mmc; + mm->context[cpu] = mmc; } /* Always update the PCB ASN. Another thread may have allocated @@ -159,7 +157,10 @@ extern inline void init_new_context(struct mm_struct *mm) { - mm->context = 0; + int i; + + for (i = 0; i < smp_num_cpus; i++) + mm->context[cpu_logical_map(i)] = 0; } extern inline void diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/page.h linux/include/asm-alpha/page.h --- v2.2.18/include/asm-alpha/page.h Sun Mar 25 11:28:36 2001 +++ linux/include/asm-alpha/page.h Sun Mar 25 11:37:39 2001 @@ -120,6 +120,10 @@ #endif /* STRICT_MM_TYPECHECKS */ #endif /* !ASSEMBLY */ +#if !defined(BUG) +#define BUG() __asm__ __volatile__("call_pal 129 # bugchk") +#endif + /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h --- v2.2.18/include/asm-alpha/pgtable.h Sun Mar 25 11:12:39 2001 +++ linux/include/asm-alpha/pgtable.h Sun Mar 25 11:37:39 2001 @@ -73,7 +73,13 @@ __EXTERN_INLINE void ev5_flush_tlb_other(struct mm_struct *mm) { - mm->context = 0; + long * mmc = &mm->context[smp_processor_id()]; + /* + * Check it's not zero first to avoid cacheline ping pong when + * possible. + */ + if (*mmc) + *mmc = 0; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/ptrace.h linux/include/asm-alpha/ptrace.h --- v2.2.18/include/asm-alpha/ptrace.h Sun Mar 25 11:12:39 2001 +++ linux/include/asm-alpha/ptrace.h Sun Mar 25 11:37:39 2001 @@ -70,6 +70,7 @@ #define user_mode(regs) (((regs)->ps & 8) != 0) #define instruction_pointer(regs) ((regs)->pc) extern void show_regs(struct pt_regs *); +extern void __show_regs(struct pt_regs *); #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/siginfo.h linux/include/asm-alpha/siginfo.h --- v2.2.18/include/asm-alpha/siginfo.h Sun Mar 25 11:12:39 2001 +++ linux/include/asm-alpha/siginfo.h Sun Mar 25 11:37:39 2001 @@ -89,8 +89,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h --- v2.2.18/include/asm-alpha/smp.h Sun Mar 25 11:28:36 2001 +++ linux/include/asm-alpha/smp.h Sun Mar 25 11:37:39 2001 @@ -4,6 +4,7 @@ #ifdef __SMP__ #include +#include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h --- v2.2.18/include/asm-alpha/softirq.h Sun Mar 25 11:12:39 2001 +++ linux/include/asm-alpha/softirq.h Sun Mar 25 11:37:39 2001 @@ -9,6 +9,7 @@ extern unsigned long local_bh_count; #else #define local_bh_count (cpu_data[smp_processor_id()].bh_count) +extern spinlock_t alpha_bh_lock; #endif #define get_active_bhs() (bh_mask & bh_active) @@ -28,24 +29,6 @@ :"Ir" (x), "m" (bh_active)); } -extern inline void init_bh(int nr, void (*routine)(void)) -{ - bh_base[nr] = routine; - atomic_set(&bh_mask_count[nr], 0); - bh_mask |= 1 << nr; -} - -extern inline void remove_bh(int nr) -{ - bh_base[nr] = NULL; - bh_mask &= ~(1 << nr); -} - -extern inline void mark_bh(int nr) -{ - set_bit(nr, &bh_active); -} - #ifdef __SMP__ /* @@ -113,21 +96,58 @@ #endif /* SMP */ +extern inline void init_bh(int nr, void (*routine)(void)) +{ + unsigned long flags; + + bh_base[nr] = routine; + atomic_set(&bh_mask_count[nr], 0); + + spin_lock_irqsave(&alpha_bh_lock, flags); + bh_mask |= 1 << nr; + spin_unlock_irqrestore(&alpha_bh_lock, flags); +} + +extern inline void remove_bh(int nr) +{ + unsigned long flags; + + spin_lock_irqsave(&alpha_bh_lock, flags); + bh_mask &= ~(1 << nr); + spin_unlock_irqrestore(&alpha_bh_lock, flags); + + synchronize_bh(); + bh_base[nr] = NULL; +} + +extern inline void mark_bh(int nr) +{ + set_bit(nr, &bh_active); +} + /* * These use a mask count to correctly handle * nested disable/enable calls */ extern inline void disable_bh(int nr) { + unsigned long flags; + + spin_lock_irqsave(&alpha_bh_lock, flags); bh_mask &= ~(1 << nr); atomic_inc(&bh_mask_count[nr]); + spin_unlock_irqrestore(&alpha_bh_lock, flags); synchronize_bh(); } extern inline void enable_bh(int nr) { + unsigned long flags; + + spin_lock_irqsave(&alpha_bh_lock, flags); if (atomic_dec_and_test(&bh_mask_count[nr])) bh_mask |= 1 << nr; + spin_unlock_irqrestore(&alpha_bh_lock, flags); } #endif /* _ALPHA_SOFTIRQ_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h --- v2.2.18/include/asm-alpha/spinlock.h Sun Mar 25 11:12:39 2001 +++ linux/include/asm-alpha/spinlock.h Sun Mar 25 11:37:39 2001 @@ -231,6 +231,7 @@ static inline void read_unlock(rwlock_t * lock) { long regx; + mb(); __asm__ __volatile__( "1: ldl_l %1,%0\n" " addl %1,2,%1\n" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/system.h linux/include/asm-alpha/system.h --- v2.2.18/include/asm-alpha/system.h Sun Mar 25 11:28:36 2001 +++ linux/include/asm-alpha/system.h Sun Mar 25 11:37:39 2001 @@ -112,12 +112,21 @@ extern void halt(void) __attribute__((noreturn)); +#ifdef CONFIG_SMP +#define ctx_cli() __cli() +#define ctx_sti() __sti() +#else +#define ctx_cli() do { } while(0) +#define ctx_sti() do { } while(0) +#endif + #define switch_to(prev,next,last) \ do { \ unsigned long pcbb; \ current = (next); \ pcbb = virt_to_phys(¤t->tss); \ (last) = alpha_switch_to(pcbb, (prev)); \ + ctx_sti(); \ } while (0) extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h --- v2.2.18/include/asm-alpha/uaccess.h Sun Mar 25 11:12:39 2001 +++ linux/include/asm-alpha/uaccess.h Sun Mar 25 11:37:39 2001 @@ -479,14 +479,6 @@ return ret; } -/* Returns: 0 if bad, string length+1 (memory size) of string if ok */ -extern long __strlen_user(const char *); - -extern inline long strlen_user(const char *str) -{ - return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0; -} - /* Returns: 0 if exception before NUL or reaching the supplied limit (N), * a value greater than N if the limit would be exceeded, else strlen. */ extern long __strnlen_user(const char *, long); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h --- v2.2.18/include/asm-arm/proc-armo/ptrace.h Sun Mar 25 11:28:36 2001 +++ linux/include/asm-arm/proc-armo/ptrace.h Sun Mar 25 11:37:39 2001 @@ -63,12 +63,6 @@ #define condition_codes(regs) \ ((regs)->ARM_pc & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT)) -#define pc_pointer(v) \ - ((v) & 0x03fffffc) - -#define instruction_pointer(regs) \ - (pc_pointer((regs)->ARM_pc)) - /* Are the current registers suitable for user mode? * (used to maintain security in signal handlers) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-arm/proc-armv/ptrace.h linux/include/asm-arm/proc-armv/ptrace.h --- v2.2.18/include/asm-arm/proc-armv/ptrace.h Sun Mar 25 11:28:36 2001 +++ linux/include/asm-arm/proc-armv/ptrace.h Sun Mar 25 11:37:39 2001 @@ -71,9 +71,6 @@ #define condition_codes(regs) \ ((regs)->ARM_cpsr & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT)) -#define instruction_pointer(regs) ((regs)->ARM_pc) -#define pc_pointer(v) (v) - /* Are the current registers suitable for user mode? * (used to maintain security in signal handlers) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-arm/processor.h linux/include/asm-arm/processor.h --- v2.2.18/include/asm-arm/processor.h Sun Mar 25 11:28:36 2001 +++ linux/include/asm-arm/processor.h Sun Mar 25 11:37:39 2001 @@ -32,13 +32,25 @@ #include #include +struct debug_info { + int nsaved; + struct { + unsigned long address; + unsigned long insn; + } bp[2]; +}; + struct thread_struct { - unsigned long address; /* Address of fault */ - unsigned long trap_no; /* Trap number */ - unsigned long error_code; /* Error code of trap */ - union fp_state fpstate; /* FPE save state */ - unsigned long debug[NR_DEBUGS]; /* Debug/ptrace */ - struct context_save_struct *save; /* context save */ + /* 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; unsigned long memmap; /* page tables */ EXTRA_THREAD_STRUCT }; @@ -62,7 +74,7 @@ */ extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t) { - return t->save ? t->save->pc & ~PCMASK : 0; + return t->save ? pc_pointer(t->save->pc) : 0; } extern __inline__ unsigned long get_css_fp(struct thread_struct *t) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-arm/ptrace.h linux/include/asm-arm/ptrace.h --- v2.2.18/include/asm-arm/ptrace.h Sun Mar 25 11:12:43 2001 +++ linux/include/asm-arm/ptrace.h Sun Mar 25 11:37:39 2001 @@ -3,9 +3,27 @@ #include +#ifndef __ASSEMBLY__ +#define pc_pointer(v) \ + ((v) & ~PCMASK) + +#define instruction_pointer(regs) \ + (pc_pointer((regs)->ARM_pc)) + #ifdef __KERNEL__ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 + extern void show_regs(struct pt_regs *); + +#define predicate(x) (x & 0xf0000000) +#define PREDICATE_ALWAYS 0xe0000000 + #endif + +#endif /* __ASSEMBLY__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-arm/siginfo.h linux/include/asm-arm/siginfo.h --- v2.2.18/include/asm-arm/siginfo.h Sun Mar 25 11:12:43 2001 +++ linux/include/asm-arm/siginfo.h Sun Mar 25 11:37:39 2001 @@ -89,8 +89,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h --- v2.2.18/include/asm-arm/uaccess.h Sun Mar 25 11:28:36 2001 +++ linux/include/asm-arm/uaccess.h Sun Mar 25 11:37:39 2001 @@ -121,8 +121,6 @@ return res; } -#define strlen_user(s) strnlen_user(s, ~0UL >> 1) - extern __inline__ long strnlen_user (const char *s, long n) { unsigned long res = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.2.18/include/asm-i386/bugs.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-i386/bugs.h Sun Mar 25 11:37:39 2001 @@ -188,6 +188,7 @@ __initfunc(static void check_amd_k6(void)) { if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && + boot_cpu_data.x86 == 5 && boot_cpu_data.x86_model == 6 && boot_cpu_data.x86_mask == 1) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-i386/e820.h linux/include/asm-i386/e820.h --- v2.2.18/include/asm-i386/e820.h Wed Dec 31 19:00:00 1969 +++ linux/include/asm-i386/e820.h Sun Mar 25 11:37:39 2001 @@ -0,0 +1,40 @@ +/* + * structures and definitions for the int 15, ax=e820 memory map + * scheme. + * + * In a nutshell, arch/i386/boot/setup.S populates a scratch table + * in the empty_zero_block that contains a list of usable address/size + * duples. In arch/i386/kernel/setup.c, this information is + * transferred into the e820map, and in arch/i386/mm/init.c, that + * new information is used to mark pages reserved or not. + * + */ +#ifndef __E820_HEADER +#define __E820_HEADER + +#define E820MAP 0x2d0 /* our map */ +#define E820MAX 32 /* number of entries in E820MAP */ +#define E820NR 0x1e8 /* # entries in E820MAP */ + +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ +#define E820_NVS 4 + +#define HIGH_MEMORY (1024*1024) + +#ifndef __ASSEMBLY__ + +struct e820map { + int nr_map; + struct e820entry { + unsigned long long addr; /* start of memory segment */ + unsigned long long size; /* size of memory segment */ + unsigned long type; /* type of memory segment */ + } map[E820MAX]; +}; + +extern struct e820map e820; +#endif/*!__ASSEMBLY__*/ + +#endif/*__E820_HEADER*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-i386/msr.h linux/include/asm-i386/msr.h --- v2.2.18/include/asm-i386/msr.h Sun Mar 25 11:12:38 2001 +++ linux/include/asm-i386/msr.h Sun Mar 25 11:37:39 2001 @@ -28,3 +28,7 @@ : "=a" (low), "=d" (high) \ : "c" (counter)) +/* symbolic names for some interesting MSRs */ +#define MSR_IA32_PLATFORM_ID 0x17 +#define MSR_IA32_UCODE_WRITE 0x79 +#define MSR_IA32_UCODE_REV 0x8B diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-i386/processor.h linux/include/asm-i386/processor.h --- v2.2.18/include/asm-i386/processor.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-i386/processor.h Sun Mar 25 11:37:39 2001 @@ -327,6 +327,23 @@ #define init_task (init_task_union.task) #define init_stack (init_task_union.stack) +/* '6' because it used to be for P6 only, now supports P15 too */ +#define MICROCODE_IOCFREE _IO('6',0) + +/* physical layour of IA32 microcode chunks */ +struct microcode { + unsigned int hdrver; + unsigned int rev; + unsigned int date; + unsigned int sig; + unsigned int cksum; + unsigned int ldrver; + unsigned int pf; + unsigned int reserved[5]; + unsigned int bits[500]; +}; + + /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ extern inline void rep_nop(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h --- v2.2.18/include/asm-i386/siginfo.h Sun Mar 25 11:12:38 2001 +++ linux/include/asm-i386/siginfo.h Sun Mar 25 11:37:39 2001 @@ -89,8 +89,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.2.18/include/asm-i386/uaccess.h Sun Mar 25 11:12:38 2001 +++ linux/include/asm-i386/uaccess.h Sun Mar 25 11:37:39 2001 @@ -510,20 +510,20 @@ " popl %0\n" \ " shl $2,%0\n" \ " addl $3,%0\n" \ - " jmp 2b\n" \ + " jmp 3b\n" \ "5: pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " stosw\n" \ " stosb\n" \ " popl %%eax\n" \ " addl $3,%0\n" \ - " jmp 2b\n" \ + " jmp 3b\n" \ "6: pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " stosb\n" \ " popl %%eax\n" \ " incl %0\n" \ - " jmp 2b\n" \ + " jmp 3b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ @@ -597,7 +597,6 @@ long strncpy_from_user(char *dst, const char *src, long count); long __strncpy_from_user(char *dst, const char *src, long count); -#define strlen_user(str) strnlen_user(str, ~0UL >> 1) long strnlen_user(const char *str, long n); unsigned long clear_user(void *mem, unsigned long len); unsigned long __clear_user(void *mem, unsigned long len); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-m68k/siginfo.h linux/include/asm-m68k/siginfo.h --- v2.2.18/include/asm-m68k/siginfo.h Sun Mar 25 11:12:40 2001 +++ linux/include/asm-m68k/siginfo.h Sun Mar 25 11:37:39 2001 @@ -89,8 +89,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-m68k/uaccess.h linux/include/asm-m68k/uaccess.h --- v2.2.18/include/asm-m68k/uaccess.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-m68k/uaccess.h Sun Mar 25 11:37:39 2001 @@ -801,7 +801,6 @@ * * Return 0 for error */ -#define strlen_user(str) strnlen_user(str, ~0UL >> 1) static inline long strnlen_user(const char * src, long n) { long res = -(long) src; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-mips/siginfo.h linux/include/asm-mips/siginfo.h --- v2.2.18/include/asm-mips/siginfo.h Sun Mar 25 11:12:38 2001 +++ linux/include/asm-mips/siginfo.h Sun Mar 25 11:37:39 2001 @@ -97,8 +97,8 @@ #define SI_MESGQ -4 /* sent by real time mesq state change */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h --- v2.2.18/include/asm-ppc/ide.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-ppc/ide.h Sun Mar 25 11:37:39 2001 @@ -36,6 +36,7 @@ extern ide_ioreg_t chrp_idedma_regbase; /* one for both channels */ extern unsigned int chrp_ide_irq; extern void chrp_ide_probe(void); +extern void ide_pmac_init(void); struct ide_machdep_calls { void (*insw)(ide_ioreg_t port, void *buf, int ns); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-ppc/mman.h linux/include/asm-ppc/mman.h --- v2.2.18/include/asm-ppc/mman.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-ppc/mman.h Sun Mar 25 11:37:39 2001 @@ -13,6 +13,7 @@ #define MAP_ANONYMOUS 0x20 /* don't use a file */ #define MAP_RENAME MAP_ANONYMOUS /* In SunOS terminology */ #define MAP_NORESERVE 0x40 /* don't reserve swap pages */ +#define MAP_LOCKED 0x80 #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-ppc/page.h linux/include/asm-ppc/page.h --- v2.2.18/include/asm-ppc/page.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-ppc/page.h Sun Mar 25 11:37:39 2001 @@ -14,6 +14,19 @@ #ifndef __ASSEMBLY__ #ifdef __KERNEL__ +#ifdef CONFIG_XMON +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + xmon(0); \ +} while (0) +#else +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + __asm__ __volatile__(".long 0x0"); \ +} while (0) +#endif +#define PAGE_BUG(page) do { BUG(); } while (0) + #define STRICT_MM_TYPECHECKS #ifdef STRICT_MM_TYPECHECKS diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-ppc/siginfo.h linux/include/asm-ppc/siginfo.h --- v2.2.18/include/asm-ppc/siginfo.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-ppc/siginfo.h Sun Mar 25 11:37:39 2001 @@ -89,8 +89,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-ppc/uaccess.h linux/include/asm-ppc/uaccess.h --- v2.2.18/include/asm-ppc/uaccess.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-ppc/uaccess.h Sun Mar 25 11:37:39 2001 @@ -276,8 +276,6 @@ return __strnlen_user(str, len, top); } -#define strlen_user(str) strnlen_user((str), 0x7ffffffe) - #endif /* __ASSEMBLY__ */ #endif /* _PPC_UACCESS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h --- v2.2.18/include/asm-s390/bitops.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/bitops.h Sun Mar 25 11:37:39 2001 @@ -495,9 +495,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -521,9 +521,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -547,9 +547,9 @@ " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -632,7 +632,7 @@ " lr 2,%1\n" " j 4f\n" "1: l 1,0(2,%2)\n" - " sll 2,3(0)\n" + " sll 2,3\n" " tml 1,0xFFFF\n" " jno 2f\n" " ahi 2,16\n" @@ -804,7 +804,7 @@ " lr 2,%1\n" " j 4f\n" "1: l 1,0(2,%2)\n" - " sll 2,3(0)\n" + " sll 2,3\n" " lhi 0,0xff\n" " ahi 2,24\n" " tmh 1,0xFFFF\n" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h --- v2.2.18/include/asm-s390/ccwcache.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/ccwcache.h Sun Mar 25 11:37:39 2001 @@ -1,5 +1,5 @@ /* - * File...........: linux/drivers/s390/block/ccwcache.c + * File...........: linux/include/asm-s390/ccwcache.h * Author(s)......: Holger Smolinski * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 @@ -34,7 +34,8 @@ devstat_t *dstat; /* The device status in case of an error */ /* these are important for recovering erroneous requests */ - int retries; /* A retry counter to be set when filling */ + short retries; /* A retry counter to be set when filling */ + char lpm; /* logical path mask */ devstat_t *devstat; /* Keeping the device status */ struct ccw_req_t *refers; /* Does this request refer to another one? */ void *function; /* refers to the originating ERP action */ ; @@ -64,6 +65,7 @@ #define CQR_STATUS_DONE 0x08 /* request is completed sucessfully */ #define CQR_STATUS_ERROR 0x10 /* request is completed with error */ #define CQR_STATUS_FAILED 0x20 /* request is finally failed */ +#define CQR_STATUS_PENDING 0x07 /* request is waiting for interrupt - ERP only */ #define CQR_STATUS_FINISHED 0x40 /* request is ready for cleanup */ #ifdef __KERNEL__ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h --- v2.2.18/include/asm-s390/dasd.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/dasd.h Sun Mar 25 11:37:39 2001 @@ -2,12 +2,15 @@ #ifndef DASD_H #define DASD_H +#undef ERP_DEBUG /* enable debug messages */ + /* First of all the external stuff */ #include #include #include #include #include +#include #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) #include #endif @@ -65,6 +68,12 @@ dasd_era_recover = 2 /* recovery action recommended */ } dasd_era_t; +/* BIT DEFINITIONS FOR SENSE DATA */ +#define DASD_SENSE_BIT_0 0x80 +#define DASD_SENSE_BIT_1 0x40 +#define DASD_SENSE_BIT_2 0x20 +#define DASD_SENSE_BIT_3 0x10 + /* * struct dasd_sizes_t * represents all data needed to access dasd with properly set up sectors @@ -97,7 +106,7 @@ struct dasd_device_t; typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); -typedef int (*dasd_erp_postaction_fn_t) (ccw_req_t * cqr, int); +typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); typedef int (*dasd_ck_id_fn_t) (dev_info_t *); typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); @@ -116,6 +125,7 @@ typedef struct dasd_discipline_t { char ebcname[8]; /* a name used for tagging and printks */ char name[8]; /* a name used for tagging and printks */ + int max_blocks; /* how many blocks are allowed to be chained */ struct dasd_discipline_t *next; /* used for list of disciplines */ @@ -165,6 +175,7 @@ struct wait_queue wait; struct wait_queue *wait_q; #endif /* LINUX_IS_24 */ + struct timer_list timer; /* HUM new */ dasd_sizes_t sizes; devstat_t dev_status; char *characteristics; @@ -231,6 +242,24 @@ int dasd_discipline_deq(dasd_discipline_t *); int dasd_start_IO (ccw_req_t *); void dasd_int_handler (int , void *, struct pt_regs *); +ccw_req_t *default_erp_action (ccw_req_t *); +ccw_req_t *default_erp_postaction (ccw_req_t *); +int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); +ccw_req_t *dasd_alloc_request (char *, int, int); +void dasd_free_request (ccw_req_t *); + + +#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ +do { \ + int d_devno = d_device->devinfo.devno; \ + int d_irq = d_device->devinfo.irq; \ + char *d_name = d_device->name; \ + int d_major = MAJOR(d_device->kdev); \ + int d_minor = MINOR(d_device->kdev); \ + printk(d_loglevel PRINTK_HEADER \ + "/dev/%s(%d:%d), 0x%04X on SCH 0x%x: " \ + d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ +} while(0) #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/debug.h linux/include/asm-s390/debug.h --- v2.2.18/include/asm-s390/debug.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/debug.h Sun Mar 25 11:37:39 2001 @@ -9,42 +9,59 @@ #ifndef DEBUG_H #define DEBUG_H -#ifdef __KERNEL__ +/* Note: + * struct __debug_entry must be defined outside of #ifdef __KERNEL__ + * in order to allow a user program to analyze the 'raw'-view. + */ + +struct __debug_entry{ + union { + struct { + unsigned long long clock:52; + unsigned long long exception:1; + unsigned long long level:3; + unsigned long long cpuid:8; + } fields; + + unsigned long long stck; + } id; + void* caller; +} __attribute__((packed)); + -#include +#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */ + +#ifdef __KERNEL__ +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + #include +#else + #include +#endif /* LINUX_VERSION_CODE */ #include #include #include -#define DEBUG_MAX_AREAS 16 /* max number of allowed registers */ #define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */ +#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ #define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ +#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */ + /* the entry information */ + #define STCK(x) asm volatile ("STCK %0":"=m" (x)) -typedef struct { - union { - struct { - unsigned long long clock:52; - unsigned long long unused:2; - unsigned long long cpuid:8; - unsigned long long exception:1; - unsigned long long used:1; - } fields; - - unsigned long long stck; - } id; - void* caller; - char data[4]; -} debug_entry_t; +typedef struct __debug_entry debug_entry_t; struct debug_view; -typedef struct { +typedef struct debug_info { + struct debug_info* next; + struct debug_info* prev; atomic_t ref_count; spinlock_t lock; int level; @@ -54,7 +71,7 @@ int entry_size; debug_entry_t** areas; int active_area; - int active_entry[DEBUG_MAX_AREAS]; + int *active_entry; struct proc_dir_entry* proc_root_entry; struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS]; struct debug_view* views[DEBUG_MAX_VIEWS]; @@ -87,29 +104,97 @@ debug_header_proc_t* header_proc; debug_format_proc_t* format_proc; debug_input_proc_t* input_proc; + void* private_data; }; -extern struct debug_view debug_ascii_view; -extern struct debug_view debug_ebcdic_view; -extern struct debug_view debug_hex_view; +extern struct debug_view debug_hex_ascii_view; +extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +/* do NOT use the _common functions */ + +debug_entry_t* debug_event_common(debug_info_t* id, int level, + const void* data, int length); + +debug_entry_t* debug_exception_common(debug_info_t* id, int level, + const void* data, int length); + +/* Debug Feature API: */ debug_info_t* debug_register(char* name, int pages_index, int nr_areas, - int buf_size); + int buf_size); + void debug_unregister(debug_info_t* id); -debug_entry_t* debug_event(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_event(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_event(debug_info_t* id, int level, - const char* txt); - -debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_exception(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_exception(debug_info_t* id, int level, - const char* txt); +void debug_set_level(debug_info_t* id, int new_level); + +extern inline debug_entry_t* +debug_event(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_event(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * +debug_long_event (debug_info_t* id, int level, unsigned long tag) +{ + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_event(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,txt,strlen(txt)); +} + +extern debug_entry_t * +debug_sprintf_event(debug_info_t* id,int level,char *string,...); + + +extern inline debug_entry_t* +debug_exception(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_exception(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * +debug_long_exception (debug_info_t* id, int level, unsigned long tag) +{ + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_exception(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,txt,strlen(txt)); +} + + +extern debug_entry_t * +debug_sprintf_exception(debug_info_t* id,int level,char *string,...); int debug_register_view(debug_info_t* id, struct debug_view* view); int debug_unregister_view(debug_info_t* id, struct debug_view* view); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/elf.h linux/include/asm-s390/elf.h --- v2.2.18/include/asm-s390/elf.h Sun Mar 25 11:12:43 2001 +++ linux/include/asm-s390/elf.h Sun Mar 25 11:37:39 2001 @@ -22,7 +22,8 @@ /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(x) ((x) == EM_S390) +#define elf_check_arch(x) \ + ((x) == EM_S390 || (x) == EM_S390_OLD) /* * These are used to set parameters in the core dumps. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/idals.h linux/include/asm-s390/idals.h --- v2.2.18/include/asm-s390/idals.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/idals.h Sun Mar 25 11:37:39 2001 @@ -7,19 +7,50 @@ * History of changes * 07/24/00 new file */ - -#define IDAL_NUMBER_CACHES 7 +#include typedef unsigned long idaw_t; -#ifdef CONFIG_ARCH_S390 -extern inline int -normalize_cpa(ccw1_t * ccw, unsigned long address) +static inline idaw_t * +idal_alloc ( int nridaws ) { - return address; + if ( nridaws > 33 ) + BUG(); + return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA ); } + +static inline void +idal_free ( idaw_t *idal ) +{ + kfree (idal); +} + +/* + * Function: set_normalized_cda + * sets the address of the data in CCW + * if necessary it allocates an IDAL and sets sthe appropriate flags + */ +#if defined (CONFIG_ARCH_S390) +static inline void +set_normalized_cda(ccw1_t * ccw, unsigned long address) +{ + ccw->cda = address; +} +#elif defined (CONFIG_ARCH_S390X) +extern void set_normalized_cda(ccw1_t * ccw, unsigned long address); #endif -int idal_alloc ( int nridaws ); -void idal_release ( idaw_t *idal ); +/* + * Function: clear_normalized_cda + * releases any allocated IDAL related to the CCW + */ +static inline void +clear_normalized_cda ( ccw1_t * ccw ) +{ + if ( ccw -> flags & CCW_FLAG_IDA ) { + idal_free ( (idaw_t *) (ccw -> cda )); + ccw -> flags &= ~CCW_FLAG_IDA; + } + ccw -> cda = 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/io.h linux/include/asm-s390/io.h --- v2.2.18/include/asm-s390/io.h Sun Mar 25 11:12:43 2001 +++ linux/include/asm-s390/io.h Sun Mar 25 11:37:39 2001 @@ -25,7 +25,7 @@ extern inline unsigned long virt_to_phys(volatile void * address) { unsigned long real_address; - __asm__ (" lra %0,0(0,%1)\n" + __asm__ (" lra %0,0(%1)\n" " jz 0f\n" " sr %0,%0\n" "0:" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/irq.h linux/include/asm-s390/irq.h --- v2.2.18/include/asm-s390/irq.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/irq.h Sun Mar 25 11:37:39 2001 @@ -183,6 +183,33 @@ #define SNS0_EQUIPMENT_CHECK 0x10 #define SNS0_DATA_CHECK 0x08 #define SNS0_OVERRUN 0x04 +/* 0x02 reserved */ +#define SNS0_INCOMPL_DOMAIN 0x01 + +/* + * architectured values for second sense byte + */ +#define SNS1_PERM_ERR 0x80 +#define SNS1_INV_TRACK_FORMAT 0x40 +#define SNS1_EOC 0x20 +#define SNS1_MESSAGE_TO_OPER 0x10 +#define SNS1_NO_REC_FOUND 0x08 +#define SNS1_FILE_PROTECTED 0x04 +#define SNS1_WRITE_INHIBITED 0x02 +#define SNS1_INPRECISE_END 0x01 + +/* + * architectured values for third sense byte + */ +#define SNS2_REQ_INH_WRITE 0x80 +#define SNS2_CORRECTABLE 0x40 +#define SNS2_FIRST_LOG_ERR 0x20 +#define SNS2_ENV_DATA_PRESENT 0x10 +/* 0x08 reserved */ +#define SNS2_INPRECISE_END 0x04 +/* 0x02 reserved */ +/* 0x01 reserved */ + /* * operation request block @@ -319,6 +346,7 @@ #define CIW_TYPE_SII 0x1 // set interface identifier #define CIW_TYPE_RNI 0x2 // read node identifier +#define MAX_CIWS 8 // // sense-id response buffer layout // @@ -331,7 +359,7 @@ __u8 dev_model; /* device model */ __u8 unused; /* padding byte */ /* extended part */ - ciw_t ciw[16]; /* variable # of CIWs */ + ciw_t ciw[MAX_CIWS]; /* variable # of CIWs */ } __attribute__ ((packed,aligned(4))) senseid_t; #endif /* __KERNEL__ */ @@ -383,6 +411,7 @@ #define DEVSTAT_FINAL_STATUS 0x80000000 #define INTPARM_STATUS_PENDING 0xFFFFFFFF + #ifdef __KERNEL__ typedef void (* io_handler_func1_t) ( int irq, @@ -543,7 +572,7 @@ not_oper_handler_func_t not_oper_handler, unsigned long irqflags, const char *devname, - void *dev_id); + devstat_t *dev_id); extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *); @@ -809,7 +838,7 @@ { if (prof_buffer && current->pid) { addr &= 0x7fffffff; - addr -= (unsigned long)&_stext; + addr -= (unsigned long) &_stext; addr >>= prof_shift; /* * Don't ignore out-of-bounds EIP values silently, @@ -832,8 +861,10 @@ #define s390irq_spin_lock_irqsave(irq,flags) \ spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags) + #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) #endif /* __KERNEL__ */ + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/page.h linux/include/asm-s390/page.h --- v2.2.18/include/asm-s390/page.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/page.h Sun Mar 25 11:37:39 2001 @@ -26,6 +26,11 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + __asm__ __volatile__(".word 0x0000"); \ +} while (0) + extern __inline__ int get_order(unsigned long size) { int order; @@ -103,7 +108,6 @@ #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) - #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h --- v2.2.18/include/asm-s390/pgtable.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/pgtable.h Sun Mar 25 11:37:39 2001 @@ -546,7 +546,7 @@ extern __inline__ pgd_t* get_pgd_slow(void) { int i; - pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2); + pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,1); if (ret) for (i=0,pgd=ret;i global flush - * - * Fixme: To avoid this global flush we should - * use pdg_quicklist as fix lenght fifo list - * and not as stack - */ + pgtable_cache_size -= 2; } else ret = (unsigned long *)get_pgd_slow(); return (pgd_t *)ret; @@ -580,12 +570,12 @@ { *(unsigned long *)pgd = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; - pgtable_cache_size++; + pgtable_cache_size += 2; } extern __inline__ void free_pgd_slow(pgd_t *pgd) { - free_pages((unsigned long)pgd,2); + free_pages((unsigned long)pgd, 1); } extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/siginfo.h linux/include/asm-s390/siginfo.h --- v2.2.18/include/asm-s390/siginfo.h Sun Mar 25 11:12:44 2001 +++ linux/include/asm-s390/siginfo.h Sun Mar 25 11:37:39 2001 @@ -97,8 +97,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/system.h linux/include/asm-s390/system.h --- v2.2.18/include/asm-s390/system.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/system.h Sun Mar 25 11:37:39 2001 @@ -33,14 +33,14 @@ " nr 1,%0\n" /* isolate last 2 bits */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,8,%1\n" /* for ptr&3 == 0 */ - " stcm 0,8,%1\n" - " icm 1,4,%1\n" /* for ptr&3 == 1 */ - " stcm 0,4,%1\n" - " icm 1,2,%1\n" /* for ptr&3 == 2 */ - " stcm 0,2,%1\n" - " icm 1,1,%1\n" /* for ptr&3 == 3 */ - " stcm 0,1,%1\n" + " icm 1,8,3(%1)\n" /* for ptr&3 == 0 */ + " stcm 0,8,3(%1)\n" + " icm 1,4,3(%1)\n" /* for ptr&3 == 1 */ + " stcm 0,4,3(%1)\n" + " icm 1,2,3(%1)\n" /* for ptr&3 == 2 */ + " stcm 0,2,3(%1)\n" + " icm 1,1,3(%1)\n" /* for ptr&3 == 3 */ + " stcm 0,1,3(%1)\n" "0: sll 1,3\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -49,8 +49,9 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); + break; case 2: if(((__u32)ptr)&1) panic("misaligned (__u16 *) in __xchg\n"); @@ -59,10 +60,10 @@ " nr 1,%0\n" /* isolate bit 2^1 */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,12,%1\n" /* for ptr&2 == 0 */ - " stcm 0,12,%1\n" - " icm 1,3,%1\n" /* for ptr&2 == 1 */ - " stcm 0,3,%1\n" + " icm 1,12,2(%1)\n" /* for ptr&2 == 0 */ + " stcm 0,12,2(%1)\n" + " icm 1,3,2(%1)\n" /* for ptr&2 == 1 */ + " stcm 0,3,2(%1)\n" "0: sll 1,2\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -71,7 +72,7 @@ " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); break; case 4: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/todclk.h linux/include/asm-s390/todclk.h --- v2.2.18/include/asm-s390/todclk.h Wed Dec 31 19:00:00 1969 +++ linux/include/asm-s390/todclk.h Sun Mar 25 11:37:39 2001 @@ -0,0 +1,19 @@ +/* + * File...........: linux/include/asm/todclk.h + * Author(s)......: Holger Smolinski + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * + * History of changes (starts July 2000) + */ + +#ifndef __ASM_TODCLK_H +#define __ASM_TODCLK_H + +#define TOD_uSEC (0x1000ULL) +#define TOD_mSEC (1000 * TOD_uSEC) +#define TOD_SEC (1000 * TOD_mSEC) +#define TOD_MIN (60 * TOD_SEC) +#define TOD_HOUR (60 * TOD_MIN) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h --- v2.2.18/include/asm-s390/uaccess.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-s390/uaccess.h Sun Mar 25 11:37:39 2001 @@ -505,7 +505,6 @@ : "cc", "0", "4" ); return n; } -#define strlen_user(str) strnlen_user(str, ~0UL) /* * Zero Userspace diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h --- v2.2.18/include/asm-sparc/asm_offsets.h Sun Mar 25 11:28:37 2001 +++ linux/include/asm-sparc/asm_offsets.h Sun Mar 25 11:37:39 2001 @@ -40,153 +40,163 @@ #define ASIZ_task_next_run 0x00000004 #define AOFF_task_prev_run 0x00000040 #define ASIZ_task_prev_run 0x00000004 -#define AOFF_task_binfmt 0x00000044 +#define AOFF_task_task_exclusive 0x00000044 +#define ASIZ_task_task_exclusive 0x00000004 +#define AOFF_task_binfmt 0x00000048 #define ASIZ_task_binfmt 0x00000004 -#define AOFF_task_exit_code 0x00000048 +#define AOFF_task_exit_code 0x0000004c #define ASIZ_task_exit_code 0x00000004 -#define AOFF_task_exit_signal 0x0000004c +#define AOFF_task_exit_signal 0x00000050 #define ASIZ_task_exit_signal 0x00000004 -#define AOFF_task_pdeath_signal 0x00000050 +#define AOFF_task_pdeath_signal 0x00000054 #define ASIZ_task_pdeath_signal 0x00000004 -#define AOFF_task_personality 0x00000054 +#define AOFF_task_personality 0x00000058 #define ASIZ_task_personality 0x00000004 -#define AOFF_task_pid 0x0000005c +#define AOFF_task_pid 0x00000060 #define ASIZ_task_pid 0x00000004 -#define AOFF_task_pgrp 0x00000060 +#define AOFF_task_pgrp 0x00000064 #define ASIZ_task_pgrp 0x00000004 -#define AOFF_task_tty_old_pgrp 0x00000064 +#define AOFF_task_tty_old_pgrp 0x00000068 #define ASIZ_task_tty_old_pgrp 0x00000004 -#define AOFF_task_session 0x00000068 +#define AOFF_task_session 0x0000006c #define ASIZ_task_session 0x00000004 -#define AOFF_task_leader 0x0000006c +#define AOFF_task_leader 0x00000070 #define ASIZ_task_leader 0x00000004 -#define AOFF_task_p_opptr 0x00000070 +#define AOFF_task_p_opptr 0x00000074 #define ASIZ_task_p_opptr 0x00000004 -#define AOFF_task_p_pptr 0x00000074 +#define AOFF_task_p_pptr 0x00000078 #define ASIZ_task_p_pptr 0x00000004 -#define AOFF_task_p_cptr 0x00000078 +#define AOFF_task_p_cptr 0x0000007c #define ASIZ_task_p_cptr 0x00000004 -#define AOFF_task_p_ysptr 0x0000007c +#define AOFF_task_p_ysptr 0x00000080 #define ASIZ_task_p_ysptr 0x00000004 -#define AOFF_task_p_osptr 0x00000080 +#define AOFF_task_p_osptr 0x00000084 #define ASIZ_task_p_osptr 0x00000004 -#define AOFF_task_pidhash_next 0x00000084 +#define AOFF_task_pidhash_next 0x00000088 #define ASIZ_task_pidhash_next 0x00000004 -#define AOFF_task_pidhash_pprev 0x00000088 +#define AOFF_task_pidhash_pprev 0x0000008c #define ASIZ_task_pidhash_pprev 0x00000004 -#define AOFF_task_tarray_ptr 0x0000008c +#define AOFF_task_tarray_ptr 0x00000090 #define ASIZ_task_tarray_ptr 0x00000004 -#define AOFF_task_wait_chldexit 0x00000090 +#define AOFF_task_wait_chldexit 0x00000094 #define ASIZ_task_wait_chldexit 0x00000004 -#define AOFF_task_vfork_sem 0x00000094 +#define AOFF_task_vfork_sem 0x00000098 #define ASIZ_task_vfork_sem 0x00000004 -#define AOFF_task_policy 0x00000098 +#define AOFF_task_policy 0x0000009c #define ASIZ_task_policy 0x00000004 -#define AOFF_task_rt_priority 0x0000009c +#define AOFF_task_rt_priority 0x000000a0 #define ASIZ_task_rt_priority 0x00000004 -#define AOFF_task_it_real_value 0x000000a0 +#define AOFF_task_it_real_value 0x000000a4 #define ASIZ_task_it_real_value 0x00000004 -#define AOFF_task_it_prof_value 0x000000a4 +#define AOFF_task_it_prof_value 0x000000a8 #define ASIZ_task_it_prof_value 0x00000004 -#define AOFF_task_it_virt_value 0x000000a8 +#define AOFF_task_it_virt_value 0x000000ac #define ASIZ_task_it_virt_value 0x00000004 -#define AOFF_task_it_real_incr 0x000000ac +#define AOFF_task_it_real_incr 0x000000b0 #define ASIZ_task_it_real_incr 0x00000004 -#define AOFF_task_it_prof_incr 0x000000b0 +#define AOFF_task_it_prof_incr 0x000000b4 #define ASIZ_task_it_prof_incr 0x00000004 -#define AOFF_task_it_virt_incr 0x000000b4 +#define AOFF_task_it_virt_incr 0x000000b8 #define ASIZ_task_it_virt_incr 0x00000004 -#define AOFF_task_real_timer 0x000000b8 +#define AOFF_task_real_timer 0x000000bc #define ASIZ_task_real_timer 0x00000014 -#define AOFF_task_times 0x000000cc +#define AOFF_task_times 0x000000d0 #define ASIZ_task_times 0x00000010 -#define AOFF_task_start_time 0x000000dc +#define AOFF_task_start_time 0x000000e0 #define ASIZ_task_start_time 0x00000004 -#define AOFF_task_per_cpu_utime 0x000000e0 +#define AOFF_task_per_cpu_utime 0x000000e4 #define ASIZ_task_per_cpu_utime 0x00000004 -#define AOFF_task_min_flt 0x000000e8 +#define AOFF_task_min_flt 0x000000ec #define ASIZ_task_min_flt 0x00000004 -#define AOFF_task_maj_flt 0x000000ec +#define AOFF_task_maj_flt 0x000000f0 #define ASIZ_task_maj_flt 0x00000004 -#define AOFF_task_nswap 0x000000f0 +#define AOFF_task_nswap 0x000000f4 #define ASIZ_task_nswap 0x00000004 -#define AOFF_task_cmin_flt 0x000000f4 +#define AOFF_task_cmin_flt 0x000000f8 #define ASIZ_task_cmin_flt 0x00000004 -#define AOFF_task_cmaj_flt 0x000000f8 +#define AOFF_task_cmaj_flt 0x000000fc #define ASIZ_task_cmaj_flt 0x00000004 -#define AOFF_task_cnswap 0x000000fc +#define AOFF_task_cnswap 0x00000100 #define ASIZ_task_cnswap 0x00000004 -#define AOFF_task_uid 0x00000102 +#define AOFF_task_uid 0x00000106 #define ASIZ_task_uid 0x00000002 -#define AOFF_task_euid 0x00000104 +#define AOFF_task_euid 0x00000108 #define ASIZ_task_euid 0x00000002 -#define AOFF_task_suid 0x00000106 +#define AOFF_task_suid 0x0000010a #define ASIZ_task_suid 0x00000002 -#define AOFF_task_fsuid 0x00000108 +#define AOFF_task_fsuid 0x0000010c #define ASIZ_task_fsuid 0x00000002 -#define AOFF_task_gid 0x0000010a +#define AOFF_task_gid 0x0000010e #define ASIZ_task_gid 0x00000002 -#define AOFF_task_egid 0x0000010c +#define AOFF_task_egid 0x00000110 #define ASIZ_task_egid 0x00000002 -#define AOFF_task_sgid 0x0000010e +#define AOFF_task_sgid 0x00000112 #define ASIZ_task_sgid 0x00000002 -#define AOFF_task_fsgid 0x00000110 +#define AOFF_task_fsgid 0x00000114 #define ASIZ_task_fsgid 0x00000002 -#define AOFF_task_ngroups 0x00000114 +#define AOFF_task_ngroups 0x00000118 #define ASIZ_task_ngroups 0x00000004 -#define AOFF_task_groups 0x00000118 +#define AOFF_task_groups 0x0000011c #define ASIZ_task_groups 0x00000040 -#define AOFF_task_cap_effective 0x00000158 +#define AOFF_task_cap_effective 0x0000015c #define ASIZ_task_cap_effective 0x00000004 -#define AOFF_task_cap_inheritable 0x0000015c +#define AOFF_task_cap_inheritable 0x00000160 #define ASIZ_task_cap_inheritable 0x00000004 -#define AOFF_task_cap_permitted 0x00000160 +#define AOFF_task_cap_permitted 0x00000164 #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_user 0x00000168 +#define AOFF_task_user 0x0000016c #define ASIZ_task_user 0x00000004 -#define AOFF_task_rlim 0x0000016c +#define AOFF_task_rlim 0x00000170 #define ASIZ_task_rlim 0x00000050 -#define AOFF_task_used_math 0x000001bc +#define AOFF_task_used_math 0x000001c0 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x000001be +#define AOFF_task_comm 0x000001c2 #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x000001d0 +#define AOFF_task_link_count 0x000001d4 #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x000001d4 +#define AOFF_task_tty 0x000001d8 #define ASIZ_task_tty 0x00000004 -#define AOFF_task_semundo 0x000001d8 +#define AOFF_task_semundo 0x000001dc #define ASIZ_task_semundo 0x00000004 -#define AOFF_task_semsleeping 0x000001dc +#define AOFF_task_semsleeping 0x000001e0 #define ASIZ_task_semsleeping 0x00000004 -#define AOFF_task_tss 0x000001e0 +#define AOFF_task_tss 0x000001e8 #define ASIZ_task_tss 0x00000388 -#define AOFF_task_fs 0x00000568 +#define AOFF_task_fs 0x00000570 #define ASIZ_task_fs 0x00000004 -#define AOFF_task_files 0x0000056c +#define AOFF_task_files 0x00000574 #define ASIZ_task_files 0x00000004 -#define AOFF_task_mm 0x00000570 +#define AOFF_task_mm 0x00000578 #define ASIZ_task_mm 0x00000004 -#define AOFF_task_sigmask_lock 0x00000574 +#define AOFF_task_local_pages 0x0000057c +#define ASIZ_task_local_pages 0x00000008 +#define AOFF_task_allocation_order 0x00000584 +#define ASIZ_task_allocation_order 0x00000004 +#define AOFF_task_nr_local_pages 0x00000588 +#define ASIZ_task_nr_local_pages 0x00000004 +#define AOFF_task_fs_locks 0x0000058c +#define ASIZ_task_fs_locks 0x00000004 +#define AOFF_task_sigmask_lock 0x00000590 #define ASIZ_task_sigmask_lock 0x00000001 -#define AOFF_task_sig 0x00000578 +#define AOFF_task_sig 0x00000594 #define ASIZ_task_sig 0x00000004 -#define AOFF_task_signal 0x0000057c +#define AOFF_task_signal 0x00000598 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x00000584 +#define AOFF_task_blocked 0x000005a0 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x0000058c +#define AOFF_task_sigqueue 0x000005a8 #define ASIZ_task_sigqueue 0x00000004 -#define AOFF_task_sigqueue_tail 0x00000590 +#define AOFF_task_sigqueue_tail 0x000005ac #define ASIZ_task_sigqueue_tail 0x00000004 -#define AOFF_task_sas_ss_sp 0x00000594 +#define AOFF_task_sas_ss_sp 0x000005b0 #define ASIZ_task_sas_ss_sp 0x00000004 -#define AOFF_task_sas_ss_size 0x00000598 +#define AOFF_task_sas_ss_size 0x000005b4 #define ASIZ_task_sas_ss_size 0x00000004 -#define AOFF_task_parent_exec_id 0x0000059c +#define AOFF_task_parent_exec_id 0x000005b8 #define ASIZ_task_parent_exec_id 0x00000004 -#define AOFF_task_self_exec_id 0x000005a0 +#define AOFF_task_self_exec_id 0x000005bc #define ASIZ_task_self_exec_id 0x00000004 -#define AOFF_task_oom_kill_try 0x000005a4 +#define AOFF_task_oom_kill_try 0x000005c0 #define ASIZ_task_oom_kill_try 0x00000004 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000004 @@ -321,153 +331,163 @@ #define ASIZ_task_next_run 0x00000004 #define AOFF_task_prev_run 0x00000040 #define ASIZ_task_prev_run 0x00000004 -#define AOFF_task_binfmt 0x00000044 +#define AOFF_task_task_exclusive 0x00000044 +#define ASIZ_task_task_exclusive 0x00000004 +#define AOFF_task_binfmt 0x00000048 #define ASIZ_task_binfmt 0x00000004 -#define AOFF_task_exit_code 0x00000048 +#define AOFF_task_exit_code 0x0000004c #define ASIZ_task_exit_code 0x00000004 -#define AOFF_task_exit_signal 0x0000004c +#define AOFF_task_exit_signal 0x00000050 #define ASIZ_task_exit_signal 0x00000004 -#define AOFF_task_pdeath_signal 0x00000050 +#define AOFF_task_pdeath_signal 0x00000054 #define ASIZ_task_pdeath_signal 0x00000004 -#define AOFF_task_personality 0x00000054 +#define AOFF_task_personality 0x00000058 #define ASIZ_task_personality 0x00000004 -#define AOFF_task_pid 0x0000005c +#define AOFF_task_pid 0x00000060 #define ASIZ_task_pid 0x00000004 -#define AOFF_task_pgrp 0x00000060 +#define AOFF_task_pgrp 0x00000064 #define ASIZ_task_pgrp 0x00000004 -#define AOFF_task_tty_old_pgrp 0x00000064 +#define AOFF_task_tty_old_pgrp 0x00000068 #define ASIZ_task_tty_old_pgrp 0x00000004 -#define AOFF_task_session 0x00000068 +#define AOFF_task_session 0x0000006c #define ASIZ_task_session 0x00000004 -#define AOFF_task_leader 0x0000006c +#define AOFF_task_leader 0x00000070 #define ASIZ_task_leader 0x00000004 -#define AOFF_task_p_opptr 0x00000070 +#define AOFF_task_p_opptr 0x00000074 #define ASIZ_task_p_opptr 0x00000004 -#define AOFF_task_p_pptr 0x00000074 +#define AOFF_task_p_pptr 0x00000078 #define ASIZ_task_p_pptr 0x00000004 -#define AOFF_task_p_cptr 0x00000078 +#define AOFF_task_p_cptr 0x0000007c #define ASIZ_task_p_cptr 0x00000004 -#define AOFF_task_p_ysptr 0x0000007c +#define AOFF_task_p_ysptr 0x00000080 #define ASIZ_task_p_ysptr 0x00000004 -#define AOFF_task_p_osptr 0x00000080 +#define AOFF_task_p_osptr 0x00000084 #define ASIZ_task_p_osptr 0x00000004 -#define AOFF_task_pidhash_next 0x00000084 +#define AOFF_task_pidhash_next 0x00000088 #define ASIZ_task_pidhash_next 0x00000004 -#define AOFF_task_pidhash_pprev 0x00000088 +#define AOFF_task_pidhash_pprev 0x0000008c #define ASIZ_task_pidhash_pprev 0x00000004 -#define AOFF_task_tarray_ptr 0x0000008c +#define AOFF_task_tarray_ptr 0x00000090 #define ASIZ_task_tarray_ptr 0x00000004 -#define AOFF_task_wait_chldexit 0x00000090 +#define AOFF_task_wait_chldexit 0x00000094 #define ASIZ_task_wait_chldexit 0x00000004 -#define AOFF_task_vfork_sem 0x00000094 +#define AOFF_task_vfork_sem 0x00000098 #define ASIZ_task_vfork_sem 0x00000004 -#define AOFF_task_policy 0x00000098 +#define AOFF_task_policy 0x0000009c #define ASIZ_task_policy 0x00000004 -#define AOFF_task_rt_priority 0x0000009c +#define AOFF_task_rt_priority 0x000000a0 #define ASIZ_task_rt_priority 0x00000004 -#define AOFF_task_it_real_value 0x000000a0 +#define AOFF_task_it_real_value 0x000000a4 #define ASIZ_task_it_real_value 0x00000004 -#define AOFF_task_it_prof_value 0x000000a4 +#define AOFF_task_it_prof_value 0x000000a8 #define ASIZ_task_it_prof_value 0x00000004 -#define AOFF_task_it_virt_value 0x000000a8 +#define AOFF_task_it_virt_value 0x000000ac #define ASIZ_task_it_virt_value 0x00000004 -#define AOFF_task_it_real_incr 0x000000ac +#define AOFF_task_it_real_incr 0x000000b0 #define ASIZ_task_it_real_incr 0x00000004 -#define AOFF_task_it_prof_incr 0x000000b0 +#define AOFF_task_it_prof_incr 0x000000b4 #define ASIZ_task_it_prof_incr 0x00000004 -#define AOFF_task_it_virt_incr 0x000000b4 +#define AOFF_task_it_virt_incr 0x000000b8 #define ASIZ_task_it_virt_incr 0x00000004 -#define AOFF_task_real_timer 0x000000b8 +#define AOFF_task_real_timer 0x000000bc #define ASIZ_task_real_timer 0x00000014 -#define AOFF_task_times 0x000000cc +#define AOFF_task_times 0x000000d0 #define ASIZ_task_times 0x00000010 -#define AOFF_task_start_time 0x000000dc +#define AOFF_task_start_time 0x000000e0 #define ASIZ_task_start_time 0x00000004 -#define AOFF_task_per_cpu_utime 0x000000e0 +#define AOFF_task_per_cpu_utime 0x000000e4 #define ASIZ_task_per_cpu_utime 0x00000080 -#define AOFF_task_min_flt 0x000001e0 +#define AOFF_task_min_flt 0x000001e4 #define ASIZ_task_min_flt 0x00000004 -#define AOFF_task_maj_flt 0x000001e4 +#define AOFF_task_maj_flt 0x000001e8 #define ASIZ_task_maj_flt 0x00000004 -#define AOFF_task_nswap 0x000001e8 +#define AOFF_task_nswap 0x000001ec #define ASIZ_task_nswap 0x00000004 -#define AOFF_task_cmin_flt 0x000001ec +#define AOFF_task_cmin_flt 0x000001f0 #define ASIZ_task_cmin_flt 0x00000004 -#define AOFF_task_cmaj_flt 0x000001f0 +#define AOFF_task_cmaj_flt 0x000001f4 #define ASIZ_task_cmaj_flt 0x00000004 -#define AOFF_task_cnswap 0x000001f4 +#define AOFF_task_cnswap 0x000001f8 #define ASIZ_task_cnswap 0x00000004 -#define AOFF_task_uid 0x000001fa +#define AOFF_task_uid 0x000001fe #define ASIZ_task_uid 0x00000002 -#define AOFF_task_euid 0x000001fc +#define AOFF_task_euid 0x00000200 #define ASIZ_task_euid 0x00000002 -#define AOFF_task_suid 0x000001fe +#define AOFF_task_suid 0x00000202 #define ASIZ_task_suid 0x00000002 -#define AOFF_task_fsuid 0x00000200 +#define AOFF_task_fsuid 0x00000204 #define ASIZ_task_fsuid 0x00000002 -#define AOFF_task_gid 0x00000202 +#define AOFF_task_gid 0x00000206 #define ASIZ_task_gid 0x00000002 -#define AOFF_task_egid 0x00000204 +#define AOFF_task_egid 0x00000208 #define ASIZ_task_egid 0x00000002 -#define AOFF_task_sgid 0x00000206 +#define AOFF_task_sgid 0x0000020a #define ASIZ_task_sgid 0x00000002 -#define AOFF_task_fsgid 0x00000208 +#define AOFF_task_fsgid 0x0000020c #define ASIZ_task_fsgid 0x00000002 -#define AOFF_task_ngroups 0x0000020c +#define AOFF_task_ngroups 0x00000210 #define ASIZ_task_ngroups 0x00000004 -#define AOFF_task_groups 0x00000210 +#define AOFF_task_groups 0x00000214 #define ASIZ_task_groups 0x00000040 -#define AOFF_task_cap_effective 0x00000250 +#define AOFF_task_cap_effective 0x00000254 #define ASIZ_task_cap_effective 0x00000004 -#define AOFF_task_cap_inheritable 0x00000254 +#define AOFF_task_cap_inheritable 0x00000258 #define ASIZ_task_cap_inheritable 0x00000004 -#define AOFF_task_cap_permitted 0x00000258 +#define AOFF_task_cap_permitted 0x0000025c #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_user 0x00000260 +#define AOFF_task_user 0x00000264 #define ASIZ_task_user 0x00000004 -#define AOFF_task_rlim 0x00000264 +#define AOFF_task_rlim 0x00000268 #define ASIZ_task_rlim 0x00000050 -#define AOFF_task_used_math 0x000002b4 +#define AOFF_task_used_math 0x000002b8 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x000002b6 +#define AOFF_task_comm 0x000002ba #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x000002c8 +#define AOFF_task_link_count 0x000002cc #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x000002cc +#define AOFF_task_tty 0x000002d0 #define ASIZ_task_tty 0x00000004 -#define AOFF_task_semundo 0x000002d0 +#define AOFF_task_semundo 0x000002d4 #define ASIZ_task_semundo 0x00000004 -#define AOFF_task_semsleeping 0x000002d4 +#define AOFF_task_semsleeping 0x000002d8 #define ASIZ_task_semsleeping 0x00000004 -#define AOFF_task_tss 0x000002d8 +#define AOFF_task_tss 0x000002e0 #define ASIZ_task_tss 0x00000388 -#define AOFF_task_fs 0x00000660 +#define AOFF_task_fs 0x00000668 #define ASIZ_task_fs 0x00000004 -#define AOFF_task_files 0x00000664 +#define AOFF_task_files 0x0000066c #define ASIZ_task_files 0x00000004 -#define AOFF_task_mm 0x00000668 +#define AOFF_task_mm 0x00000670 #define ASIZ_task_mm 0x00000004 -#define AOFF_task_sigmask_lock 0x0000066c +#define AOFF_task_local_pages 0x00000674 +#define ASIZ_task_local_pages 0x00000008 +#define AOFF_task_allocation_order 0x0000067c +#define ASIZ_task_allocation_order 0x00000004 +#define AOFF_task_nr_local_pages 0x00000680 +#define ASIZ_task_nr_local_pages 0x00000004 +#define AOFF_task_fs_locks 0x00000684 +#define ASIZ_task_fs_locks 0x00000004 +#define AOFF_task_sigmask_lock 0x00000688 #define ASIZ_task_sigmask_lock 0x00000001 -#define AOFF_task_sig 0x00000670 +#define AOFF_task_sig 0x0000068c #define ASIZ_task_sig 0x00000004 -#define AOFF_task_signal 0x00000674 +#define AOFF_task_signal 0x00000690 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x0000067c +#define AOFF_task_blocked 0x00000698 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x00000684 +#define AOFF_task_sigqueue 0x000006a0 #define ASIZ_task_sigqueue 0x00000004 -#define AOFF_task_sigqueue_tail 0x00000688 +#define AOFF_task_sigqueue_tail 0x000006a4 #define ASIZ_task_sigqueue_tail 0x00000004 -#define AOFF_task_sas_ss_sp 0x0000068c +#define AOFF_task_sas_ss_sp 0x000006a8 #define ASIZ_task_sas_ss_sp 0x00000004 -#define AOFF_task_sas_ss_size 0x00000690 +#define AOFF_task_sas_ss_size 0x000006ac #define ASIZ_task_sas_ss_size 0x00000004 -#define AOFF_task_parent_exec_id 0x00000694 +#define AOFF_task_parent_exec_id 0x000006b0 #define ASIZ_task_parent_exec_id 0x00000004 -#define AOFF_task_self_exec_id 0x00000698 +#define AOFF_task_self_exec_id 0x000006b4 #define ASIZ_task_self_exec_id 0x00000004 -#define AOFF_task_oom_kill_try 0x0000069c +#define AOFF_task_oom_kill_try 0x000006b8 #define ASIZ_task_oom_kill_try 0x00000004 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000004 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc/audioio.h linux/include/asm-sparc/audioio.h --- v2.2.18/include/asm-sparc/audioio.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc/audioio.h Sun Mar 25 11:37:39 2001 @@ -432,6 +432,7 @@ extern void sparcaudio_input_done(struct sparcaudio_driver *, int); extern int sparcaudio_init(void); extern int amd7930_init(void); +extern int dbri_init(void); extern int cs4231_init(void); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc/page.h linux/include/asm-sparc/page.h --- v2.2.18/include/asm-sparc/page.h Sun Mar 25 11:12:40 2001 +++ linux/include/asm-sparc/page.h Sun Mar 25 11:37:39 2001 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.43 1998/05/11 08:40:11 davem Exp $ +/* $Id: page.h,v 1.43.2.1 2001/02/20 04:21:45 davem Exp $ * page.h: Various defines and such for MMU operations on the Sparc for * the Linux kernel. * @@ -27,6 +27,10 @@ #define TASK_UNION_SIZE 8192 #ifndef __ASSEMBLY__ + +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; \ +} while (0) #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h --- v2.2.18/include/asm-sparc/siginfo.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc/siginfo.h Sun Mar 25 11:37:39 2001 @@ -93,8 +93,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h --- v2.2.18/include/asm-sparc/uaccess.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc/uaccess.h Sun Mar 25 11:37:39 2001 @@ -383,16 +383,7 @@ __sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \ } __sfu_res; }) -extern int __strlen_user(const char *); extern int __strnlen_user(const char *, long len); - -extern __inline__ int strlen_user(const char *str) -{ - if(!access_ok(VERIFY_READ, str, 0)) - return 0; - else - return __strlen_user(str); -} extern __inline__ int strnlen_user(const char *str, long len) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v2.2.18/include/asm-sparc/unistd.h Sun Mar 25 11:12:40 2001 +++ linux/include/asm-sparc/unistd.h Sun Mar 25 11:37:39 2001 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.55 1999/04/07 17:14:15 davem Exp $ */ +/* $Id: unistd.h,v 1.55.2.2 2001/01/11 19:12:10 davem Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -59,7 +59,7 @@ #define __NR_dup 41 /* Common */ #define __NR_pipe 42 /* Common */ #define __NR_times 43 /* Implemented via getrusage() in SunOS */ -/* #define __NR_profil 44 Common */ +/* #define __NR_getuid32 44 Linux Sparc32 Specific */ #define __NR_umount2 45 /* Linux Specific */ #define __NR_setgid 46 /* Implemented via setregid() in SunOS */ #define __NR_getgid 47 /* Common */ @@ -169,8 +169,8 @@ /* #define __NR_getmsg 151 SunOS Specific */ /* #define __NR_putmsg 152 SunOS Specific */ #define __NR_poll 153 /* Common */ -/* #define __NR_ni_syscall 154 ENOSYS under SunOS */ -/* #define __NR_nfssvc 155 SunOS Specific */ +/* #define __NR_getdents64 154 Linux Sparc32 Specific */ +/* #define __NR_fcntl64 155 Linux Sparc32 Specific */ /* #define __NR_getdirentries 156 SunOS Specific */ #define __NR_statfs 157 /* Common */ #define __NR_fstatfs 158 /* Common */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h --- v2.2.18/include/asm-sparc64/asm_offsets.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc64/asm_offsets.h Sun Mar 25 11:37:39 2001 @@ -40,155 +40,165 @@ #define ASIZ_task_next_run 0x00000008 #define AOFF_task_prev_run 0x00000070 #define ASIZ_task_prev_run 0x00000008 -#define AOFF_task_binfmt 0x00000078 +#define AOFF_task_task_exclusive 0x00000078 +#define ASIZ_task_task_exclusive 0x00000004 +#define AOFF_task_binfmt 0x00000080 #define ASIZ_task_binfmt 0x00000008 -#define AOFF_task_exit_code 0x00000080 +#define AOFF_task_exit_code 0x00000088 #define ASIZ_task_exit_code 0x00000004 -#define AOFF_task_exit_signal 0x00000084 +#define AOFF_task_exit_signal 0x0000008c #define ASIZ_task_exit_signal 0x00000004 -#define AOFF_task_pdeath_signal 0x00000088 +#define AOFF_task_pdeath_signal 0x00000090 #define ASIZ_task_pdeath_signal 0x00000004 -#define AOFF_task_personality 0x00000090 +#define AOFF_task_personality 0x00000098 #define ASIZ_task_personality 0x00000008 -#define AOFF_task_pid 0x0000009c +#define AOFF_task_pid 0x000000a4 #define ASIZ_task_pid 0x00000004 -#define AOFF_task_pgrp 0x000000a0 +#define AOFF_task_pgrp 0x000000a8 #define ASIZ_task_pgrp 0x00000004 -#define AOFF_task_tty_old_pgrp 0x000000a4 +#define AOFF_task_tty_old_pgrp 0x000000ac #define ASIZ_task_tty_old_pgrp 0x00000004 -#define AOFF_task_session 0x000000a8 +#define AOFF_task_session 0x000000b0 #define ASIZ_task_session 0x00000004 -#define AOFF_task_leader 0x000000ac +#define AOFF_task_leader 0x000000b4 #define ASIZ_task_leader 0x00000004 -#define AOFF_task_p_opptr 0x000000b0 +#define AOFF_task_p_opptr 0x000000b8 #define ASIZ_task_p_opptr 0x00000008 -#define AOFF_task_p_pptr 0x000000b8 +#define AOFF_task_p_pptr 0x000000c0 #define ASIZ_task_p_pptr 0x00000008 -#define AOFF_task_p_cptr 0x000000c0 +#define AOFF_task_p_cptr 0x000000c8 #define ASIZ_task_p_cptr 0x00000008 -#define AOFF_task_p_ysptr 0x000000c8 +#define AOFF_task_p_ysptr 0x000000d0 #define ASIZ_task_p_ysptr 0x00000008 -#define AOFF_task_p_osptr 0x000000d0 +#define AOFF_task_p_osptr 0x000000d8 #define ASIZ_task_p_osptr 0x00000008 -#define AOFF_task_pidhash_next 0x000000d8 +#define AOFF_task_pidhash_next 0x000000e0 #define ASIZ_task_pidhash_next 0x00000008 -#define AOFF_task_pidhash_pprev 0x000000e0 +#define AOFF_task_pidhash_pprev 0x000000e8 #define ASIZ_task_pidhash_pprev 0x00000008 -#define AOFF_task_tarray_ptr 0x000000e8 +#define AOFF_task_tarray_ptr 0x000000f0 #define ASIZ_task_tarray_ptr 0x00000008 -#define AOFF_task_wait_chldexit 0x000000f0 +#define AOFF_task_wait_chldexit 0x000000f8 #define ASIZ_task_wait_chldexit 0x00000008 -#define AOFF_task_vfork_sem 0x000000f8 +#define AOFF_task_vfork_sem 0x00000100 #define ASIZ_task_vfork_sem 0x00000008 -#define AOFF_task_policy 0x00000100 +#define AOFF_task_policy 0x00000108 #define ASIZ_task_policy 0x00000008 -#define AOFF_task_rt_priority 0x00000108 +#define AOFF_task_rt_priority 0x00000110 #define ASIZ_task_rt_priority 0x00000008 -#define AOFF_task_it_real_value 0x00000110 +#define AOFF_task_it_real_value 0x00000118 #define ASIZ_task_it_real_value 0x00000008 -#define AOFF_task_it_prof_value 0x00000118 +#define AOFF_task_it_prof_value 0x00000120 #define ASIZ_task_it_prof_value 0x00000008 -#define AOFF_task_it_virt_value 0x00000120 +#define AOFF_task_it_virt_value 0x00000128 #define ASIZ_task_it_virt_value 0x00000008 -#define AOFF_task_it_real_incr 0x00000128 +#define AOFF_task_it_real_incr 0x00000130 #define ASIZ_task_it_real_incr 0x00000008 -#define AOFF_task_it_prof_incr 0x00000130 +#define AOFF_task_it_prof_incr 0x00000138 #define ASIZ_task_it_prof_incr 0x00000008 -#define AOFF_task_it_virt_incr 0x00000138 +#define AOFF_task_it_virt_incr 0x00000140 #define ASIZ_task_it_virt_incr 0x00000008 -#define AOFF_task_real_timer 0x00000140 +#define AOFF_task_real_timer 0x00000148 #define ASIZ_task_real_timer 0x00000028 -#define AOFF_task_times 0x00000168 +#define AOFF_task_times 0x00000170 #define ASIZ_task_times 0x00000020 -#define AOFF_task_start_time 0x00000188 +#define AOFF_task_start_time 0x00000190 #define ASIZ_task_start_time 0x00000008 -#define AOFF_task_per_cpu_utime 0x00000190 +#define AOFF_task_per_cpu_utime 0x00000198 #define ASIZ_task_per_cpu_utime 0x00000008 -#define AOFF_task_min_flt 0x000001a0 +#define AOFF_task_min_flt 0x000001a8 #define ASIZ_task_min_flt 0x00000008 -#define AOFF_task_maj_flt 0x000001a8 +#define AOFF_task_maj_flt 0x000001b0 #define ASIZ_task_maj_flt 0x00000008 -#define AOFF_task_nswap 0x000001b0 +#define AOFF_task_nswap 0x000001b8 #define ASIZ_task_nswap 0x00000008 -#define AOFF_task_cmin_flt 0x000001b8 +#define AOFF_task_cmin_flt 0x000001c0 #define ASIZ_task_cmin_flt 0x00000008 -#define AOFF_task_cmaj_flt 0x000001c0 +#define AOFF_task_cmaj_flt 0x000001c8 #define ASIZ_task_cmaj_flt 0x00000008 -#define AOFF_task_cnswap 0x000001c8 +#define AOFF_task_cnswap 0x000001d0 #define ASIZ_task_cnswap 0x00000008 -#define AOFF_task_uid 0x000001d4 +#define AOFF_task_uid 0x000001dc #define ASIZ_task_uid 0x00000004 -#define AOFF_task_euid 0x000001d8 +#define AOFF_task_euid 0x000001e0 #define ASIZ_task_euid 0x00000004 -#define AOFF_task_suid 0x000001dc +#define AOFF_task_suid 0x000001e4 #define ASIZ_task_suid 0x00000004 -#define AOFF_task_fsuid 0x000001e0 +#define AOFF_task_fsuid 0x000001e8 #define ASIZ_task_fsuid 0x00000004 -#define AOFF_task_gid 0x000001e4 +#define AOFF_task_gid 0x000001ec #define ASIZ_task_gid 0x00000004 -#define AOFF_task_egid 0x000001e8 +#define AOFF_task_egid 0x000001f0 #define ASIZ_task_egid 0x00000004 -#define AOFF_task_sgid 0x000001ec +#define AOFF_task_sgid 0x000001f4 #define ASIZ_task_sgid 0x00000004 -#define AOFF_task_fsgid 0x000001f0 +#define AOFF_task_fsgid 0x000001f8 #define ASIZ_task_fsgid 0x00000004 -#define AOFF_task_ngroups 0x000001f4 +#define AOFF_task_ngroups 0x000001fc #define ASIZ_task_ngroups 0x00000004 -#define AOFF_task_groups 0x000001f8 +#define AOFF_task_groups 0x00000200 #define ASIZ_task_groups 0x00000080 -#define AOFF_task_cap_effective 0x00000278 +#define AOFF_task_cap_effective 0x00000280 #define ASIZ_task_cap_effective 0x00000004 -#define AOFF_task_cap_inheritable 0x0000027c +#define AOFF_task_cap_inheritable 0x00000284 #define ASIZ_task_cap_inheritable 0x00000004 -#define AOFF_task_cap_permitted 0x00000280 +#define AOFF_task_cap_permitted 0x00000288 #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_user 0x00000288 +#define AOFF_task_user 0x00000290 #define ASIZ_task_user 0x00000008 -#define AOFF_task_rlim 0x00000290 +#define AOFF_task_rlim 0x00000298 #define ASIZ_task_rlim 0x000000a0 -#define AOFF_task_used_math 0x00000330 +#define AOFF_task_used_math 0x00000338 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x00000332 +#define AOFF_task_comm 0x0000033a #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x00000344 +#define AOFF_task_link_count 0x0000034c #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x00000348 +#define AOFF_task_tty 0x00000350 #define ASIZ_task_tty 0x00000008 -#define AOFF_task_semundo 0x00000350 +#define AOFF_task_semundo 0x00000358 #define ASIZ_task_semundo 0x00000008 -#define AOFF_task_semsleeping 0x00000358 +#define AOFF_task_semsleeping 0x00000360 #define ASIZ_task_semsleeping 0x00000008 -#define AOFF_task_tss 0x00000360 +#define AOFF_task_tss 0x00000370 #define ASIZ_task_tss 0x00000470 -#define AOFF_task_fs 0x000007d0 +#define AOFF_task_fs 0x000007e0 #define ASIZ_task_fs 0x00000008 -#define AOFF_task_files 0x000007d8 +#define AOFF_task_files 0x000007e8 #define ASIZ_task_files 0x00000008 -#define AOFF_task_mm 0x000007e0 +#define AOFF_task_mm 0x000007f0 #define ASIZ_task_mm 0x00000008 -#define AOFF_task_sigmask_lock 0x000007e8 +#define AOFF_task_local_pages 0x000007f8 +#define ASIZ_task_local_pages 0x00000010 +#define AOFF_task_allocation_order 0x00000808 +#define ASIZ_task_allocation_order 0x00000004 +#define AOFF_task_nr_local_pages 0x0000080c +#define ASIZ_task_nr_local_pages 0x00000004 +#define AOFF_task_fs_locks 0x00000810 +#define ASIZ_task_fs_locks 0x00000004 +#define AOFF_task_sigmask_lock 0x00000814 #define ASIZ_task_sigmask_lock 0x00000001 -#define AOFF_task_sig 0x000007f0 +#define AOFF_task_sig 0x00000818 #define ASIZ_task_sig 0x00000008 -#define AOFF_task_signal 0x000007f8 +#define AOFF_task_signal 0x00000820 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x00000800 +#define AOFF_task_blocked 0x00000828 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x00000808 +#define AOFF_task_sigqueue 0x00000830 #define ASIZ_task_sigqueue 0x00000008 -#define AOFF_task_sigqueue_tail 0x00000810 +#define AOFF_task_sigqueue_tail 0x00000838 #define ASIZ_task_sigqueue_tail 0x00000008 -#define AOFF_task_sas_ss_sp 0x00000818 +#define AOFF_task_sas_ss_sp 0x00000840 #define ASIZ_task_sas_ss_sp 0x00000008 -#define AOFF_task_sas_ss_size 0x00000820 +#define AOFF_task_sas_ss_size 0x00000848 #define ASIZ_task_sas_ss_size 0x00000008 -#define AOFF_task_parent_exec_id 0x00000828 +#define AOFF_task_parent_exec_id 0x00000850 #define ASIZ_task_parent_exec_id 0x00000004 -#define AOFF_task_self_exec_id 0x0000082c +#define AOFF_task_self_exec_id 0x00000854 #define ASIZ_task_self_exec_id 0x00000004 -#define AOFF_task_oom_kill_try 0x00000830 +#define AOFF_task_oom_kill_try 0x00000858 #define ASIZ_task_oom_kill_try 0x00000004 -#define ASIZ_task 0x00000840 +#define ASIZ_task 0x00000860 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000008 #define AOFF_mm_mmap_avl 0x00000008 @@ -332,155 +342,165 @@ #define ASIZ_task_next_run 0x00000008 #define AOFF_task_prev_run 0x00000070 #define ASIZ_task_prev_run 0x00000008 -#define AOFF_task_binfmt 0x00000078 +#define AOFF_task_task_exclusive 0x00000078 +#define ASIZ_task_task_exclusive 0x00000004 +#define AOFF_task_binfmt 0x00000080 #define ASIZ_task_binfmt 0x00000008 -#define AOFF_task_exit_code 0x00000080 +#define AOFF_task_exit_code 0x00000088 #define ASIZ_task_exit_code 0x00000004 -#define AOFF_task_exit_signal 0x00000084 +#define AOFF_task_exit_signal 0x0000008c #define ASIZ_task_exit_signal 0x00000004 -#define AOFF_task_pdeath_signal 0x00000088 +#define AOFF_task_pdeath_signal 0x00000090 #define ASIZ_task_pdeath_signal 0x00000004 -#define AOFF_task_personality 0x00000090 +#define AOFF_task_personality 0x00000098 #define ASIZ_task_personality 0x00000008 -#define AOFF_task_pid 0x0000009c +#define AOFF_task_pid 0x000000a4 #define ASIZ_task_pid 0x00000004 -#define AOFF_task_pgrp 0x000000a0 +#define AOFF_task_pgrp 0x000000a8 #define ASIZ_task_pgrp 0x00000004 -#define AOFF_task_tty_old_pgrp 0x000000a4 +#define AOFF_task_tty_old_pgrp 0x000000ac #define ASIZ_task_tty_old_pgrp 0x00000004 -#define AOFF_task_session 0x000000a8 +#define AOFF_task_session 0x000000b0 #define ASIZ_task_session 0x00000004 -#define AOFF_task_leader 0x000000ac +#define AOFF_task_leader 0x000000b4 #define ASIZ_task_leader 0x00000004 -#define AOFF_task_p_opptr 0x000000b0 +#define AOFF_task_p_opptr 0x000000b8 #define ASIZ_task_p_opptr 0x00000008 -#define AOFF_task_p_pptr 0x000000b8 +#define AOFF_task_p_pptr 0x000000c0 #define ASIZ_task_p_pptr 0x00000008 -#define AOFF_task_p_cptr 0x000000c0 +#define AOFF_task_p_cptr 0x000000c8 #define ASIZ_task_p_cptr 0x00000008 -#define AOFF_task_p_ysptr 0x000000c8 +#define AOFF_task_p_ysptr 0x000000d0 #define ASIZ_task_p_ysptr 0x00000008 -#define AOFF_task_p_osptr 0x000000d0 +#define AOFF_task_p_osptr 0x000000d8 #define ASIZ_task_p_osptr 0x00000008 -#define AOFF_task_pidhash_next 0x000000d8 +#define AOFF_task_pidhash_next 0x000000e0 #define ASIZ_task_pidhash_next 0x00000008 -#define AOFF_task_pidhash_pprev 0x000000e0 +#define AOFF_task_pidhash_pprev 0x000000e8 #define ASIZ_task_pidhash_pprev 0x00000008 -#define AOFF_task_tarray_ptr 0x000000e8 +#define AOFF_task_tarray_ptr 0x000000f0 #define ASIZ_task_tarray_ptr 0x00000008 -#define AOFF_task_wait_chldexit 0x000000f0 +#define AOFF_task_wait_chldexit 0x000000f8 #define ASIZ_task_wait_chldexit 0x00000008 -#define AOFF_task_vfork_sem 0x000000f8 +#define AOFF_task_vfork_sem 0x00000100 #define ASIZ_task_vfork_sem 0x00000008 -#define AOFF_task_policy 0x00000100 +#define AOFF_task_policy 0x00000108 #define ASIZ_task_policy 0x00000008 -#define AOFF_task_rt_priority 0x00000108 +#define AOFF_task_rt_priority 0x00000110 #define ASIZ_task_rt_priority 0x00000008 -#define AOFF_task_it_real_value 0x00000110 +#define AOFF_task_it_real_value 0x00000118 #define ASIZ_task_it_real_value 0x00000008 -#define AOFF_task_it_prof_value 0x00000118 +#define AOFF_task_it_prof_value 0x00000120 #define ASIZ_task_it_prof_value 0x00000008 -#define AOFF_task_it_virt_value 0x00000120 +#define AOFF_task_it_virt_value 0x00000128 #define ASIZ_task_it_virt_value 0x00000008 -#define AOFF_task_it_real_incr 0x00000128 +#define AOFF_task_it_real_incr 0x00000130 #define ASIZ_task_it_real_incr 0x00000008 -#define AOFF_task_it_prof_incr 0x00000130 +#define AOFF_task_it_prof_incr 0x00000138 #define ASIZ_task_it_prof_incr 0x00000008 -#define AOFF_task_it_virt_incr 0x00000138 +#define AOFF_task_it_virt_incr 0x00000140 #define ASIZ_task_it_virt_incr 0x00000008 -#define AOFF_task_real_timer 0x00000140 +#define AOFF_task_real_timer 0x00000148 #define ASIZ_task_real_timer 0x00000028 -#define AOFF_task_times 0x00000168 +#define AOFF_task_times 0x00000170 #define ASIZ_task_times 0x00000020 -#define AOFF_task_start_time 0x00000188 +#define AOFF_task_start_time 0x00000190 #define ASIZ_task_start_time 0x00000008 -#define AOFF_task_per_cpu_utime 0x00000190 +#define AOFF_task_per_cpu_utime 0x00000198 #define ASIZ_task_per_cpu_utime 0x00000100 -#define AOFF_task_min_flt 0x00000390 +#define AOFF_task_min_flt 0x00000398 #define ASIZ_task_min_flt 0x00000008 -#define AOFF_task_maj_flt 0x00000398 +#define AOFF_task_maj_flt 0x000003a0 #define ASIZ_task_maj_flt 0x00000008 -#define AOFF_task_nswap 0x000003a0 +#define AOFF_task_nswap 0x000003a8 #define ASIZ_task_nswap 0x00000008 -#define AOFF_task_cmin_flt 0x000003a8 +#define AOFF_task_cmin_flt 0x000003b0 #define ASIZ_task_cmin_flt 0x00000008 -#define AOFF_task_cmaj_flt 0x000003b0 +#define AOFF_task_cmaj_flt 0x000003b8 #define ASIZ_task_cmaj_flt 0x00000008 -#define AOFF_task_cnswap 0x000003b8 +#define AOFF_task_cnswap 0x000003c0 #define ASIZ_task_cnswap 0x00000008 -#define AOFF_task_uid 0x000003c4 +#define AOFF_task_uid 0x000003cc #define ASIZ_task_uid 0x00000004 -#define AOFF_task_euid 0x000003c8 +#define AOFF_task_euid 0x000003d0 #define ASIZ_task_euid 0x00000004 -#define AOFF_task_suid 0x000003cc +#define AOFF_task_suid 0x000003d4 #define ASIZ_task_suid 0x00000004 -#define AOFF_task_fsuid 0x000003d0 +#define AOFF_task_fsuid 0x000003d8 #define ASIZ_task_fsuid 0x00000004 -#define AOFF_task_gid 0x000003d4 +#define AOFF_task_gid 0x000003dc #define ASIZ_task_gid 0x00000004 -#define AOFF_task_egid 0x000003d8 +#define AOFF_task_egid 0x000003e0 #define ASIZ_task_egid 0x00000004 -#define AOFF_task_sgid 0x000003dc +#define AOFF_task_sgid 0x000003e4 #define ASIZ_task_sgid 0x00000004 -#define AOFF_task_fsgid 0x000003e0 +#define AOFF_task_fsgid 0x000003e8 #define ASIZ_task_fsgid 0x00000004 -#define AOFF_task_ngroups 0x000003e4 +#define AOFF_task_ngroups 0x000003ec #define ASIZ_task_ngroups 0x00000004 -#define AOFF_task_groups 0x000003e8 +#define AOFF_task_groups 0x000003f0 #define ASIZ_task_groups 0x00000080 -#define AOFF_task_cap_effective 0x00000468 +#define AOFF_task_cap_effective 0x00000470 #define ASIZ_task_cap_effective 0x00000004 -#define AOFF_task_cap_inheritable 0x0000046c +#define AOFF_task_cap_inheritable 0x00000474 #define ASIZ_task_cap_inheritable 0x00000004 -#define AOFF_task_cap_permitted 0x00000470 +#define AOFF_task_cap_permitted 0x00000478 #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_user 0x00000478 +#define AOFF_task_user 0x00000480 #define ASIZ_task_user 0x00000008 -#define AOFF_task_rlim 0x00000480 +#define AOFF_task_rlim 0x00000488 #define ASIZ_task_rlim 0x000000a0 -#define AOFF_task_used_math 0x00000520 +#define AOFF_task_used_math 0x00000528 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x00000522 +#define AOFF_task_comm 0x0000052a #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x00000534 +#define AOFF_task_link_count 0x0000053c #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x00000538 +#define AOFF_task_tty 0x00000540 #define ASIZ_task_tty 0x00000008 -#define AOFF_task_semundo 0x00000540 +#define AOFF_task_semundo 0x00000548 #define ASIZ_task_semundo 0x00000008 -#define AOFF_task_semsleeping 0x00000548 +#define AOFF_task_semsleeping 0x00000550 #define ASIZ_task_semsleeping 0x00000008 -#define AOFF_task_tss 0x00000550 +#define AOFF_task_tss 0x00000560 #define ASIZ_task_tss 0x00000470 -#define AOFF_task_fs 0x000009c0 +#define AOFF_task_fs 0x000009d0 #define ASIZ_task_fs 0x00000008 -#define AOFF_task_files 0x000009c8 +#define AOFF_task_files 0x000009d8 #define ASIZ_task_files 0x00000008 -#define AOFF_task_mm 0x000009d0 +#define AOFF_task_mm 0x000009e0 #define ASIZ_task_mm 0x00000008 -#define AOFF_task_sigmask_lock 0x000009d8 +#define AOFF_task_local_pages 0x000009e8 +#define ASIZ_task_local_pages 0x00000010 +#define AOFF_task_allocation_order 0x000009f8 +#define ASIZ_task_allocation_order 0x00000004 +#define AOFF_task_nr_local_pages 0x000009fc +#define ASIZ_task_nr_local_pages 0x00000004 +#define AOFF_task_fs_locks 0x00000a00 +#define ASIZ_task_fs_locks 0x00000004 +#define AOFF_task_sigmask_lock 0x00000a04 #define ASIZ_task_sigmask_lock 0x00000001 -#define AOFF_task_sig 0x000009e0 +#define AOFF_task_sig 0x00000a08 #define ASIZ_task_sig 0x00000008 -#define AOFF_task_signal 0x000009e8 +#define AOFF_task_signal 0x00000a10 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x000009f0 +#define AOFF_task_blocked 0x00000a18 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x000009f8 +#define AOFF_task_sigqueue 0x00000a20 #define ASIZ_task_sigqueue 0x00000008 -#define AOFF_task_sigqueue_tail 0x00000a00 +#define AOFF_task_sigqueue_tail 0x00000a28 #define ASIZ_task_sigqueue_tail 0x00000008 -#define AOFF_task_sas_ss_sp 0x00000a08 +#define AOFF_task_sas_ss_sp 0x00000a30 #define ASIZ_task_sas_ss_sp 0x00000008 -#define AOFF_task_sas_ss_size 0x00000a10 +#define AOFF_task_sas_ss_size 0x00000a38 #define ASIZ_task_sas_ss_size 0x00000008 -#define AOFF_task_parent_exec_id 0x00000a18 +#define AOFF_task_parent_exec_id 0x00000a40 #define ASIZ_task_parent_exec_id 0x00000004 -#define AOFF_task_self_exec_id 0x00000a1c +#define AOFF_task_self_exec_id 0x00000a44 #define ASIZ_task_self_exec_id 0x00000004 -#define AOFF_task_oom_kill_try 0x00000a20 +#define AOFF_task_oom_kill_try 0x00000a48 #define ASIZ_task_oom_kill_try 0x00000004 -#define ASIZ_task 0x00000a30 +#define ASIZ_task 0x00000a50 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000008 #define AOFF_mm_mmap_avl 0x00000008 @@ -622,155 +642,165 @@ #define ASIZ_task_next_run 0x00000008 #define AOFF_task_prev_run 0x00000070 #define ASIZ_task_prev_run 0x00000008 -#define AOFF_task_binfmt 0x00000078 +#define AOFF_task_task_exclusive 0x00000078 +#define ASIZ_task_task_exclusive 0x00000004 +#define AOFF_task_binfmt 0x00000080 #define ASIZ_task_binfmt 0x00000008 -#define AOFF_task_exit_code 0x00000080 +#define AOFF_task_exit_code 0x00000088 #define ASIZ_task_exit_code 0x00000004 -#define AOFF_task_exit_signal 0x00000084 +#define AOFF_task_exit_signal 0x0000008c #define ASIZ_task_exit_signal 0x00000004 -#define AOFF_task_pdeath_signal 0x00000088 +#define AOFF_task_pdeath_signal 0x00000090 #define ASIZ_task_pdeath_signal 0x00000004 -#define AOFF_task_personality 0x00000090 +#define AOFF_task_personality 0x00000098 #define ASIZ_task_personality 0x00000008 -#define AOFF_task_pid 0x0000009c +#define AOFF_task_pid 0x000000a4 #define ASIZ_task_pid 0x00000004 -#define AOFF_task_pgrp 0x000000a0 +#define AOFF_task_pgrp 0x000000a8 #define ASIZ_task_pgrp 0x00000004 -#define AOFF_task_tty_old_pgrp 0x000000a4 +#define AOFF_task_tty_old_pgrp 0x000000ac #define ASIZ_task_tty_old_pgrp 0x00000004 -#define AOFF_task_session 0x000000a8 +#define AOFF_task_session 0x000000b0 #define ASIZ_task_session 0x00000004 -#define AOFF_task_leader 0x000000ac +#define AOFF_task_leader 0x000000b4 #define ASIZ_task_leader 0x00000004 -#define AOFF_task_p_opptr 0x000000b0 +#define AOFF_task_p_opptr 0x000000b8 #define ASIZ_task_p_opptr 0x00000008 -#define AOFF_task_p_pptr 0x000000b8 +#define AOFF_task_p_pptr 0x000000c0 #define ASIZ_task_p_pptr 0x00000008 -#define AOFF_task_p_cptr 0x000000c0 +#define AOFF_task_p_cptr 0x000000c8 #define ASIZ_task_p_cptr 0x00000008 -#define AOFF_task_p_ysptr 0x000000c8 +#define AOFF_task_p_ysptr 0x000000d0 #define ASIZ_task_p_ysptr 0x00000008 -#define AOFF_task_p_osptr 0x000000d0 +#define AOFF_task_p_osptr 0x000000d8 #define ASIZ_task_p_osptr 0x00000008 -#define AOFF_task_pidhash_next 0x000000d8 +#define AOFF_task_pidhash_next 0x000000e0 #define ASIZ_task_pidhash_next 0x00000008 -#define AOFF_task_pidhash_pprev 0x000000e0 +#define AOFF_task_pidhash_pprev 0x000000e8 #define ASIZ_task_pidhash_pprev 0x00000008 -#define AOFF_task_tarray_ptr 0x000000e8 +#define AOFF_task_tarray_ptr 0x000000f0 #define ASIZ_task_tarray_ptr 0x00000008 -#define AOFF_task_wait_chldexit 0x000000f0 +#define AOFF_task_wait_chldexit 0x000000f8 #define ASIZ_task_wait_chldexit 0x00000008 -#define AOFF_task_vfork_sem 0x000000f8 +#define AOFF_task_vfork_sem 0x00000100 #define ASIZ_task_vfork_sem 0x00000008 -#define AOFF_task_policy 0x00000100 +#define AOFF_task_policy 0x00000108 #define ASIZ_task_policy 0x00000008 -#define AOFF_task_rt_priority 0x00000108 +#define AOFF_task_rt_priority 0x00000110 #define ASIZ_task_rt_priority 0x00000008 -#define AOFF_task_it_real_value 0x00000110 +#define AOFF_task_it_real_value 0x00000118 #define ASIZ_task_it_real_value 0x00000008 -#define AOFF_task_it_prof_value 0x00000118 +#define AOFF_task_it_prof_value 0x00000120 #define ASIZ_task_it_prof_value 0x00000008 -#define AOFF_task_it_virt_value 0x00000120 +#define AOFF_task_it_virt_value 0x00000128 #define ASIZ_task_it_virt_value 0x00000008 -#define AOFF_task_it_real_incr 0x00000128 +#define AOFF_task_it_real_incr 0x00000130 #define ASIZ_task_it_real_incr 0x00000008 -#define AOFF_task_it_prof_incr 0x00000130 +#define AOFF_task_it_prof_incr 0x00000138 #define ASIZ_task_it_prof_incr 0x00000008 -#define AOFF_task_it_virt_incr 0x00000138 +#define AOFF_task_it_virt_incr 0x00000140 #define ASIZ_task_it_virt_incr 0x00000008 -#define AOFF_task_real_timer 0x00000140 +#define AOFF_task_real_timer 0x00000148 #define ASIZ_task_real_timer 0x00000028 -#define AOFF_task_times 0x00000168 +#define AOFF_task_times 0x00000170 #define ASIZ_task_times 0x00000020 -#define AOFF_task_start_time 0x00000188 +#define AOFF_task_start_time 0x00000190 #define ASIZ_task_start_time 0x00000008 -#define AOFF_task_per_cpu_utime 0x00000190 +#define AOFF_task_per_cpu_utime 0x00000198 #define ASIZ_task_per_cpu_utime 0x00000100 -#define AOFF_task_min_flt 0x00000390 +#define AOFF_task_min_flt 0x00000398 #define ASIZ_task_min_flt 0x00000008 -#define AOFF_task_maj_flt 0x00000398 +#define AOFF_task_maj_flt 0x000003a0 #define ASIZ_task_maj_flt 0x00000008 -#define AOFF_task_nswap 0x000003a0 +#define AOFF_task_nswap 0x000003a8 #define ASIZ_task_nswap 0x00000008 -#define AOFF_task_cmin_flt 0x000003a8 +#define AOFF_task_cmin_flt 0x000003b0 #define ASIZ_task_cmin_flt 0x00000008 -#define AOFF_task_cmaj_flt 0x000003b0 +#define AOFF_task_cmaj_flt 0x000003b8 #define ASIZ_task_cmaj_flt 0x00000008 -#define AOFF_task_cnswap 0x000003b8 +#define AOFF_task_cnswap 0x000003c0 #define ASIZ_task_cnswap 0x00000008 -#define AOFF_task_uid 0x000003c4 +#define AOFF_task_uid 0x000003cc #define ASIZ_task_uid 0x00000004 -#define AOFF_task_euid 0x000003c8 +#define AOFF_task_euid 0x000003d0 #define ASIZ_task_euid 0x00000004 -#define AOFF_task_suid 0x000003cc +#define AOFF_task_suid 0x000003d4 #define ASIZ_task_suid 0x00000004 -#define AOFF_task_fsuid 0x000003d0 +#define AOFF_task_fsuid 0x000003d8 #define ASIZ_task_fsuid 0x00000004 -#define AOFF_task_gid 0x000003d4 +#define AOFF_task_gid 0x000003dc #define ASIZ_task_gid 0x00000004 -#define AOFF_task_egid 0x000003d8 +#define AOFF_task_egid 0x000003e0 #define ASIZ_task_egid 0x00000004 -#define AOFF_task_sgid 0x000003dc +#define AOFF_task_sgid 0x000003e4 #define ASIZ_task_sgid 0x00000004 -#define AOFF_task_fsgid 0x000003e0 +#define AOFF_task_fsgid 0x000003e8 #define ASIZ_task_fsgid 0x00000004 -#define AOFF_task_ngroups 0x000003e4 +#define AOFF_task_ngroups 0x000003ec #define ASIZ_task_ngroups 0x00000004 -#define AOFF_task_groups 0x000003e8 +#define AOFF_task_groups 0x000003f0 #define ASIZ_task_groups 0x00000080 -#define AOFF_task_cap_effective 0x00000468 +#define AOFF_task_cap_effective 0x00000470 #define ASIZ_task_cap_effective 0x00000004 -#define AOFF_task_cap_inheritable 0x0000046c +#define AOFF_task_cap_inheritable 0x00000474 #define ASIZ_task_cap_inheritable 0x00000004 -#define AOFF_task_cap_permitted 0x00000470 +#define AOFF_task_cap_permitted 0x00000478 #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_user 0x00000478 +#define AOFF_task_user 0x00000480 #define ASIZ_task_user 0x00000008 -#define AOFF_task_rlim 0x00000480 +#define AOFF_task_rlim 0x00000488 #define ASIZ_task_rlim 0x000000a0 -#define AOFF_task_used_math 0x00000520 +#define AOFF_task_used_math 0x00000528 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x00000522 +#define AOFF_task_comm 0x0000052a #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x00000534 +#define AOFF_task_link_count 0x0000053c #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x00000538 +#define AOFF_task_tty 0x00000540 #define ASIZ_task_tty 0x00000008 -#define AOFF_task_semundo 0x00000540 +#define AOFF_task_semundo 0x00000548 #define ASIZ_task_semundo 0x00000008 -#define AOFF_task_semsleeping 0x00000548 +#define AOFF_task_semsleeping 0x00000550 #define ASIZ_task_semsleeping 0x00000008 -#define AOFF_task_tss 0x00000550 +#define AOFF_task_tss 0x00000560 #define ASIZ_task_tss 0x00000470 -#define AOFF_task_fs 0x000009c0 +#define AOFF_task_fs 0x000009d0 #define ASIZ_task_fs 0x00000008 -#define AOFF_task_files 0x000009c8 +#define AOFF_task_files 0x000009d8 #define ASIZ_task_files 0x00000008 -#define AOFF_task_mm 0x000009d0 +#define AOFF_task_mm 0x000009e0 #define ASIZ_task_mm 0x00000008 -#define AOFF_task_sigmask_lock 0x000009d8 +#define AOFF_task_local_pages 0x000009e8 +#define ASIZ_task_local_pages 0x00000010 +#define AOFF_task_allocation_order 0x000009f8 +#define ASIZ_task_allocation_order 0x00000004 +#define AOFF_task_nr_local_pages 0x000009fc +#define ASIZ_task_nr_local_pages 0x00000004 +#define AOFF_task_fs_locks 0x00000a00 +#define ASIZ_task_fs_locks 0x00000004 +#define AOFF_task_sigmask_lock 0x00000a04 #define ASIZ_task_sigmask_lock 0x0000000c -#define AOFF_task_sig 0x000009e8 +#define AOFF_task_sig 0x00000a10 #define ASIZ_task_sig 0x00000008 -#define AOFF_task_signal 0x000009f0 +#define AOFF_task_signal 0x00000a18 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x000009f8 +#define AOFF_task_blocked 0x00000a20 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x00000a00 +#define AOFF_task_sigqueue 0x00000a28 #define ASIZ_task_sigqueue 0x00000008 -#define AOFF_task_sigqueue_tail 0x00000a08 +#define AOFF_task_sigqueue_tail 0x00000a30 #define ASIZ_task_sigqueue_tail 0x00000008 -#define AOFF_task_sas_ss_sp 0x00000a10 +#define AOFF_task_sas_ss_sp 0x00000a38 #define ASIZ_task_sas_ss_sp 0x00000008 -#define AOFF_task_sas_ss_size 0x00000a18 +#define AOFF_task_sas_ss_size 0x00000a40 #define ASIZ_task_sas_ss_size 0x00000008 -#define AOFF_task_parent_exec_id 0x00000a20 +#define AOFF_task_parent_exec_id 0x00000a48 #define ASIZ_task_parent_exec_id 0x00000004 -#define AOFF_task_self_exec_id 0x00000a24 +#define AOFF_task_self_exec_id 0x00000a4c #define ASIZ_task_self_exec_id 0x00000004 -#define AOFF_task_oom_kill_try 0x00000a28 +#define AOFF_task_oom_kill_try 0x00000a50 #define ASIZ_task_oom_kill_try 0x00000004 -#define ASIZ_task 0x00000a30 +#define ASIZ_task 0x00000a60 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000008 #define AOFF_mm_mmap_avl 0x00000008 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h --- v2.2.18/include/asm-sparc64/page.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc64/page.h Sun Mar 25 11:37:39 2001 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */ +/* $Id: page.h,v 1.24.2.1 2001/02/20 04:21:45 davem Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H @@ -17,6 +17,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ + +#define BUG() __builtin_trap() extern void clear_page(unsigned long page); extern void copy_page(unsigned long to, unsigned long from); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.2.18/include/asm-sparc64/pgtable.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc64/pgtable.h Sun Mar 25 11:37:39 2001 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.103.2.3 2000/02/27 04:44:47 davem Exp $ +/* $Id: pgtable.h,v 1.103.2.4 2000/12/11 12:31:06 anton Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -171,9 +171,15 @@ #define flush_cache_range(mm, start, end) flushw_user() #define flush_cache_page(vma, page) flushw_user() -/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */ -#define flush_icache_range(start, end) do { } while (0) +/* This is unnecessary on the SpitFire since D-CACHE is write-through. */ #define flush_page_to_ram(page) do { } while (0) + +/* + * icache doesnt snoop local stores and we don't use block commit stores + * (which invalidate icache lines) during module load, so we need this. + */ +extern void flush_icache_range(unsigned long start, unsigned long end); + extern void flush_dcache_page(unsigned long page); extern void __flush_dcache_range(unsigned long start, unsigned long end); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc64/siginfo.h linux/include/asm-sparc64/siginfo.h --- v2.2.18/include/asm-sparc64/siginfo.h Sun Mar 25 11:12:42 2001 +++ linux/include/asm-sparc64/siginfo.h Sun Mar 25 11:37:40 2001 @@ -152,8 +152,8 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) +#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO) +#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO) /* * SIGILL si_codes diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h --- v2.2.18/include/asm-sparc64/uaccess.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc64/uaccess.h Sun Mar 25 11:37:40 2001 @@ -357,10 +357,7 @@ #define strncpy_from_user(dest,src,count) \ __strncpy_from_user((unsigned long)(dest), (unsigned long)(src), (int)(count)) -extern int __strlen_user(const char *); extern int __strnlen_user(const char *, long len); - -#define strlen_user __strlen_user #define strnlen_user __strnlen_user #endif /* __ASSEMBLY__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h --- v2.2.18/include/asm-sparc64/unistd.h Sun Mar 25 11:12:41 2001 +++ linux/include/asm-sparc64/unistd.h Sun Mar 25 11:37:40 2001 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.28 1999/04/07 17:14:19 davem Exp $ */ +/* $Id: unistd.h,v 1.28.2.2 2001/01/11 19:12:11 davem Exp $ */ #ifndef _SPARC64_UNISTD_H #define _SPARC64_UNISTD_H @@ -59,7 +59,7 @@ #define __NR_dup 41 /* Common */ #define __NR_pipe 42 /* Common */ #define __NR_times 43 /* Implemented via getrusage() in SunOS */ -/* #define __NR_profil 44 Common */ +/* #define __NR_getuid32 44 Linux Sparc32 Specific */ #define __NR_umount2 45 /* Linux Specific */ #define __NR_setgid 46 /* Implemented via setregid() in SunOS */ #define __NR_getgid 47 /* Common */ @@ -169,8 +169,8 @@ /* #define __NR_getmsg 151 SunOS Specific */ /* #define __NR_putmsg 152 SunOS Specific */ #define __NR_poll 153 /* Common */ -/* #define __NR_ni_syscall 154 ENOSYS under SunOS */ -/* #define __NR_nfssvc 155 SunOS Specific */ +/* #define __NR_getdents64 154 Linux Sparc32 Specific */ +/* #define __NR_fcntl64 155 Linux Sparc32 Specific */ /* #define __NR_getdirentries 156 SunOS Specific */ #define __NR_statfs 157 /* Common */ #define __NR_fstatfs 158 /* Common */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/asm-sparc64/watchdog.h linux/include/asm-sparc64/watchdog.h --- v2.2.18/include/asm-sparc64/watchdog.h Wed Dec 31 19:00:00 1969 +++ linux/include/asm-sparc64/watchdog.h Sun Mar 25 11:37:40 2001 @@ -0,0 +1,31 @@ +/* $Id: watchdog.h,v 1.1.2.1 2001/01/26 22:26:07 davem Exp $ + * + * watchdog - Driver interface for the hardware watchdog timers + * present on Sun Microsystems boardsets + * + * Copyright (c) 2000 Eric Brower + * + */ + +#ifndef _SPARC64_WATCHDOG_H +#define _SPARC64_WATCHDOG_H + +#include + +/* Solaris compatibility ioctls-- + * Ref. for standard linux watchdog ioctls + */ +#define WIOCSTART _IO (WATCHDOG_IOCTL_BASE, 10) /* Start Timer */ +#define WIOCSTOP _IO (WATCHDOG_IOCTL_BASE, 11) /* Stop Timer */ +#define WIOCGSTAT _IOR(WATCHDOG_IOCTL_BASE, 12, int)/* Get Timer Status */ + +/* Status flags from WIOCGSTAT ioctl + */ +#define WD_FREERUN 0x01 /* timer is running, interrupts disabled */ +#define WD_EXPIRED 0x02 /* timer has expired */ +#define WD_RUNNING 0x04 /* timer is running, interrupts enabled */ +#define WD_STOPPED 0x08 /* timer has not been started */ +#define WD_SERVICED 0x10 /* timer interrupt was serviced */ + +#endif /* ifndef _SPARC64_WATCHDOG_H */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/agp_backend.h linux/include/linux/agp_backend.h --- v2.2.18/include/linux/agp_backend.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/agp_backend.h Sun Mar 25 11:37:40 2001 @@ -45,6 +45,7 @@ INTEL_BX, INTEL_GX, INTEL_I810, + INTEL_I815, INTEL_I840, VIA_GENERIC, VIA_VP3, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/apm_bios.h linux/include/linux/apm_bios.h --- v2.2.18/include/linux/apm_bios.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/apm_bios.h Sun Mar 25 11:37:40 2001 @@ -3,7 +3,7 @@ /* * Include file for the interface to an APM BIOS - * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2001 Stephen Rothwell (sfr@canb.auug.org.au) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -38,7 +38,7 @@ unsigned short dseg_len; }; - /* Results of APM Installation Check */ +/* Results of APM Installation Check */ #define APM_16_BIT_SUPPORT 0x0001 #define APM_32_BIT_SUPPORT 0x0002 #define APM_IDLE_SLOWS_CLOCK 0x0004 @@ -46,6 +46,15 @@ #define APM_BIOS_DISENGAGED 0x0010 /* + * Data for APM that is persistant across module unload/load + */ +struct apm_info { + struct apm_bios_info bios; + unsigned short connection_version; + int get_power_status_broken; +}; + +/* * The APM function codes */ #define APM_FUNC_INST_CHECK 0x5300 @@ -91,9 +100,9 @@ #define APM_FUNC_TIMER_GET 2 /* - * in init/main.c + * in arch/i386/kernel/setup.c */ -extern struct apm_bios_info apm_bios_info; +extern struct apm_info apm_info; extern int apm_register_callback(int (*callback)(apm_event_t)); extern void apm_unregister_callback(int (*callback)(apm_event_t)); @@ -176,7 +185,7 @@ /* * This is the "All Devices" ID communicated to the BIOS */ -#define APM_DEVICE_BALL ((apm_bios_info.version > 0x0100) ? \ +#define APM_DEVICE_BALL ((apm_info.connection_version > 0x0100) ? \ APM_DEVICE_ALL : APM_DEVICE_OLD_ALL) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/binfmts.h linux/include/linux/binfmts.h --- v2.2.18/include/linux/binfmts.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/binfmts.h Sun Mar 25 11:37:40 2001 @@ -28,6 +28,8 @@ int argc, envc; char * filename; /* Name of binary */ unsigned long loader, exec; + int dumpable; + int priv_change; }; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/blk.h linux/include/linux/blk.h --- v2.2.18/include/linux/blk.h Sun Mar 25 11:12:37 2001 +++ linux/include/linux/blk.h Sun Mar 25 11:37:40 2001 @@ -193,6 +193,14 @@ #define DEVICE_ON(device) #define DEVICE_OFF(device) +#elif (MAJOR_NR == OSST_MAJOR) + +#define DEVICE_NAME "onstream" +#define DEVICE_INTR do_osst +#define DEVICE_NR(device) (MINOR(device) & 0x7f) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + #elif (MAJOR_NR == SCSI_CDROM_MAJOR) #define DEVICE_NAME "CD-ROM" @@ -389,7 +397,7 @@ #define LOCAL_END_REQUEST #define DEVICE_NAME "dasd" #define DEVICE_REQUEST do_dasd_request -#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) +#define DEVICE_NR(device) (MINOR(device) >> DASD_PARTN_BITS) #define DEVICE_ON(device) #define DEVICE_OFF(device) @@ -412,7 +420,7 @@ #endif /* MAJOR_NR == whatever */ -#if (MAJOR_NR != SCSI_TAPE_MAJOR) +#if (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR) #if !defined(IDE_DRIVER) #ifndef CURRENT diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/capi.h linux/include/linux/capi.h --- v2.2.18/include/linux/capi.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/capi.h Sun Mar 25 11:37:40 2001 @@ -114,4 +114,18 @@ __u16 errcode; } capi_ioctl_struct; +/* + * Middleware extension + */ + +#define CAPIFLAG_HIGHJACKING 0x0001 + +#define CAPI_GET_FLAGS _IOR('C',0x23, unsigned) +#define CAPI_SET_FLAGS _IOR('C',0x24, unsigned) +#define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned) + +#define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned) + +#define CAPI_NCCI_GETUNIT _IOR('C',0x27, unsigned) + #endif /* __LINUX_CAPI_H__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/cdrom.h linux/include/linux/cdrom.h --- v2.2.18/include/linux/cdrom.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/cdrom.h Sun Mar 25 11:37:40 2001 @@ -528,10 +528,12 @@ __u32 end_sector_l0; }; +#define DVD_LAYERS 4 + struct dvd_physical { __u8 type; __u8 layer_num; - struct dvd_layer layer[4]; + struct dvd_layer layer[DVD_LAYERS]; }; struct dvd_copyright { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/dcache.h linux/include/linux/dcache.h --- v2.2.18/include/linux/dcache.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/dcache.h Sun Mar 25 11:37:40 2001 @@ -106,6 +106,10 @@ * If this dentry points to a directory, then * s_nfsd_free_path semaphore will be down */ +#define DCACHE_REFERENCED 0x0008 /* This dentry is been recently + * referenced so try to keep it in + * cache. + */ /* * d_drop() unhashes the entry from the parent @@ -149,7 +153,7 @@ /* dcache memory management */ extern void shrink_dcache_memory(int, unsigned int); extern void check_dcache_memory(void); -extern void free_inode_memory(int); /* defined in fs/inode.c */ +extern void free_inode_memory(void); /* defined in fs/inode.c */ /* only used at mount-time */ extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/elf.h linux/include/linux/elf.h --- v2.2.18/include/linux/elf.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/elf.h Sun Mar 25 11:37:40 2001 @@ -68,6 +68,8 @@ #define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_S390 22 /* IBM S/390 */ + /* * This is an interim value that we will use until the committee comes * up with a final number. @@ -75,9 +77,9 @@ #define EM_ALPHA 0x9026 /* - * This is an interim value for S390 architecture + * This is the old interim value for S/390 architecture */ -#define EM_S390 0xA390 +#define EM_S390_OLD 0xA390 /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/fs.h linux/include/linux/fs.h --- v2.2.18/include/linux/fs.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/fs.h Sun Mar 25 11:37:40 2001 @@ -47,7 +47,12 @@ /* And dynamically-tunable limits and defaults: */ extern int max_inodes; -extern int max_files, nr_files, nr_free_files; +struct files_stat_struct { + int nr_files; /* read only */ + int nr_free_files; /* read only */ + int max_files; /* tunable */ +}; +extern struct files_stat_struct files_stat; /* fs/file_table.c */ extern int max_super_blocks, nr_super_blocks; #define NR_FILE 4096 /* this can well be larger on a larger system */ @@ -185,6 +190,7 @@ #define BH_Lock 2 /* 1 if the buffer is locked */ #define BH_Req 3 /* 0 if the buffer has been invalidated */ #define BH_Protected 6 /* 1 if the buffer is protected */ +#define BH_Wait_IO 7 /* 1 if we should throttle on this buffer */ /* * Try to keep the most commonly used fields in single cache lines (16 @@ -777,7 +783,7 @@ extern void refile_buffer(struct buffer_head * buf); extern void set_writetime(struct buffer_head * buf, int flag); -extern int try_to_free_buffers(struct page *, int wait); +extern int try_to_free_buffers(struct page *, int); extern int nr_buffers; extern long buffermem; @@ -786,15 +792,25 @@ #define BUF_CLEAN 0 #define BUF_LOCKED 1 /* Buffers scheduled for write */ #define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */ -#define NR_LIST 3 +#define BUF_PROTECTED 3 /* Ramdisk persistent storage */ +#define NR_LIST 4 void mark_buffer_uptodate(struct buffer_head * bh, int on); +extern inline void mark_buffer_protected(struct buffer_head * bh) +{ + if (!test_and_set_bit(BH_Protected, &bh->b_state)) { + if (bh->b_list != BUF_PROTECTED) + refile_buffer(bh); + } +} + extern inline void mark_buffer_clean(struct buffer_head * bh) { if (test_and_clear_bit(BH_Dirty, &bh->b_state)) { if (bh->b_list == BUF_DIRTY) refile_buffer(bh); + clear_bit(BH_Wait_IO, &bh->b_state); } } @@ -935,6 +951,9 @@ extern void inode_setattr(struct inode *, struct iattr *); extern __u32 inode_generation_count; + +#define fs_down(sem) do { current->fs_locks++; down(sem); } while (0) +#define fs_up(sem) do { up(sem); current->fs_locks--; } while (0) #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/hysdn_if.h linux/include/linux/hysdn_if.h --- v2.2.18/include/linux/hysdn_if.h Wed Dec 31 19:00:00 1969 +++ linux/include/linux/hysdn_if.h Sun Mar 25 11:37:40 2001 @@ -0,0 +1,49 @@ +/* $Id: hysdn_if.h,v 1.1 2000/02/10 19:47:50 werner Exp $ + + * Linux driver for HYSDN cards, ioctl definitions shared by hynetmgr and driver. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: hysdn_if.h,v $ + * Revision 1.1 2000/02/10 19:47:50 werner + * + * Initial release + * + * + */ + +/****************/ +/* error values */ +/****************/ +#define ERR_NONE 0 /* no error occured */ +#define ERR_ALREADY_BOOT 1000 /* we are already booting */ +#define EPOF_BAD_MAGIC 1001 /* bad magic in POF header */ +#define ERR_BOARD_DPRAM 1002 /* board DPRAM failed */ +#define EPOF_INTERNAL 1003 /* internal POF handler error */ +#define EPOF_BAD_IMG_SIZE 1004 /* POF boot image size invalid */ +#define ERR_BOOTIMG_FAIL 1005 /* 1. stage boot image did not start */ +#define ERR_BOOTSEQ_FAIL 1006 /* 2. stage boot seq handshake timeout */ +#define ERR_POF_TIMEOUT 1007 /* timeout waiting for card pof ready */ +#define ERR_NOT_BOOTED 1008 /* operation only allowed when booted */ +#define ERR_CONF_LONG 1009 /* conf line is to long */ +#define ERR_INV_CHAN 1010 /* invalid channel number */ +#define ERR_ASYNC_TIME 1011 /* timeout sending async data */ + + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/interrupt.h linux/include/linux/interrupt.h --- v2.2.18/include/linux/interrupt.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/interrupt.h Sun Mar 25 11:37:40 2001 @@ -5,6 +5,7 @@ #include #include #include +#include struct irqaction { void (*handler)(int, void *, struct pt_regs *); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/isdn.h linux/include/linux/isdn.h --- v2.2.18/include/linux/isdn.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/isdn.h Sun Mar 25 11:37:40 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.107 2000/09/10 20:29:18 detabc Exp $ +/* $Id: isdn.h,v 1.111.6.3 2001/02/10 14:44:10 kai Exp $ * Main header for the Linux ISDN subsystem (linklevel). * @@ -66,9 +66,7 @@ #undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE #undef CONFIG_ISDN_WITH_ABC_CONN_ERROR #undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS -#undef CONFIG_ISDN_WITH_ABC_FRAME_LIMIT -#undef CONFIG_ISDN_WITH_ABC_IPV4_RW_SOCKADDR -#undef CONFIG_ISDN_WITH_ABC_IPV4_RWUDP_SOCKADDR +#undef CONFIG_ISDN_WITH_ABC_IPTABLES_NETFILTER /* New ioctl-codes */ @@ -198,7 +196,7 @@ #include #include #include -#include +#include #include #include #include @@ -320,7 +318,7 @@ typedef struct isdn_net_local_s { ulong magic; char name[10]; /* Name of device */ - struct enet_statistics stats; /* Ethernet Statistics */ + struct net_device_stats stats; /* Ethernet Statistics */ int isdn_device; /* Index to isdn-device */ int isdn_channel; /* Index to isdn-channel */ int ppp_slot; /* PPPD device slot number */ @@ -368,7 +366,6 @@ ulong sqfull_stamp; /* Start-Time of overload */ ulong slavedelay; /* Dynamic bundling delaytime */ int triggercps; /* BogoCPS needed for trigger slave */ - struct device *srobin; /* Ptr to Master device for slaves */ isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ /* phone[0] = Incoming Numbers */ /* phone[1] = Outgoing Numbers */ @@ -378,9 +375,15 @@ struct isdn_net_local_s *next; /* Ptr to next link in bundle */ struct isdn_net_local_s *last; /* Ptr to last link in bundle */ struct isdn_net_dev_s *netdev; /* Ptr to netdev */ - struct sk_buff *first_skb; /* Ptr to skb that triggers dialing */ - struct sk_buff *volatile sav_skb; /* Ptr to skb, rejected by LL-driver*/ + struct sk_buff_head super_tx_queue; /* List of supervisory frames to */ + /* be transmitted asap */ + atomic_t frame_cnt; /* number of frames currently */ + /* queued in HL driver */ /* Ptr to orig. hard_header_cache */ + spinlock_t xmit_lock; /* used to protect the xmit path of */ + /* a particular channel (including */ + /* the frame_cnt */ + int (*org_hhc)( struct neighbour *neigh, struct hh_cache *hh); @@ -400,13 +403,17 @@ int cisco_loop; /* Loop counter for Cisco-SLARP */ ulong cisco_myseq; /* Local keepalive seq. for Cisco */ ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */ + struct tq_struct tqueue; } isdn_net_local; /* the interface itself */ typedef struct isdn_net_dev_s { isdn_net_local *local; - isdn_net_local *queue; - void *next; /* Pointer to next isdn-interface */ + isdn_net_local *queue; /* circular list of all bundled + channels, which are currently + online */ + spinlock_t queue_lock; /* lock to protect queue */ + void *next; /* Pointer to next isdn-interface */ struct device dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP ippp_bundle * pb; /* pointer to the common bundle structure @@ -531,8 +538,7 @@ atemu emu; /* AT-emulator data */ struct termios normal_termios; /* For saving termios structs */ struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait, close_wait; struct semaphore write_sem; } modem_info; @@ -583,23 +589,6 @@ char *private; } infostruct; -typedef struct isdn_module { - struct isdn_module *prev; - struct isdn_module *next; - char *name; - int (*get_free_channel)(int, int, int, int, int); - int (*free_channel)(int, int, int); - int (*status_callback)(isdn_ctrl *); - int (*command)(isdn_ctrl *); - int (*receive_callback)(int, int, struct sk_buff *); - int (*writebuf_skb)(int, int, int, struct sk_buff *); - int (*net_start_xmit)(struct sk_buff *, struct device *); - int (*net_receive)(struct device *, struct sk_buff *); - int (*net_open)(struct device *); - int (*net_close)(struct device *); - int priority; -} isdn_module; - #define DRV_FLAG_RUNNING 1 #define DRV_FLAG_REJBUS 2 #define DRV_FLAG_LOADED 4 @@ -610,7 +599,7 @@ ulong flags; /* Misc driver Flags */ int locks; /* Number of locks for this driver */ int channels; /* Number of channels */ - struct wait_queue *st_waitq; /* Wait-Queue for status-read's */ + wait_queue_head_t st_waitq; /* Wait-Queue for status-read's */ int maxbufsize; /* Maximum Buffersize supported */ unsigned long pktcount; /* Until now: unused */ int stavail; /* Chars avail on Status-device */ @@ -621,8 +610,8 @@ unsigned long DLEflag; /* Flags: Insert DLE at next read */ #endif struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */ - struct wait_queue **rcv_waitq; /* Wait-Queues for B-Channel-Reads */ - struct wait_queue **snd_waitq; /* Wait-Queue for B-Channel-Send's */ + wait_queue_head_t *rcv_waitq; /* Wait-Queues for B-Channel-Reads */ + wait_queue_head_t *snd_waitq; /* Wait-Queue for B-Channel-Send's */ char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */ } driver; @@ -638,7 +627,7 @@ /* see ISDN_TIMER_..defines */ int global_flags; infostruct *infochain; /* List of open info-devs. */ - struct wait_queue *info_waitq; /* Wait-Queue for isdninfo */ + wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */ struct timer_list timer; /* Misc.-function Timer */ int chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel */ int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */ @@ -659,43 +648,14 @@ atomic_t v110use[ISDN_MAX_CHANNELS];/* Usage-Semaphore for stream */ isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */ struct semaphore sem; /* serialize list access*/ - isdn_module *modules; unsigned long global_features; } isdn_dev; extern isdn_dev *dev; - /* Utility-Macros */ #define MIN(a,b) ((ab)?a:b) -/* - * Tell upper layers that the network device is ready to xmit more frames. - */ -static void __inline__ netif_wake_queue(struct device * dev) -{ - dev->tbusy = 0; - mark_bh(NET_BH); -} - -/* - * called during net_device open() - */ -static void __inline__ netif_start_queue(struct device * dev) -{ - dev->tbusy = 0; - /* actually, we never use the interrupt flag at all */ - dev->interrupt = 0; - dev->start = 1; -} - -/* - * Ask upper layers to temporarily cease passing us more xmit frames. - */ -static void __inline__ netif_stop_queue(struct device * dev) -{ - dev->tbusy = 1; -} #endif /* __KERNEL__ */ #endif /* isdn_h */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/isdn_compat.h linux/include/linux/isdn_compat.h --- v2.2.18/include/linux/isdn_compat.h Wed Dec 31 19:00:00 1969 +++ linux/include/linux/isdn_compat.h Sun Mar 25 11:37:40 2001 @@ -0,0 +1,81 @@ +/* Compatibility for various Linux kernel versions */ + +#ifndef _LINUX_ISDN_COMPAT_H +#define _LINUX_ISDN_COMPAT_H + +#ifdef __KERNEL__ + + +#include +#ifdef __powerpc__ +static inline int pci_enable_device(struct pci_dev *dev) +{ + u16 cmd; + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_SERR; + cmd &= ~PCI_COMMAND_FAST_BACK; + pci_write_config_word(dev, PCI_COMMAND, cmd); + return(0); +} +#else +static inline int pci_enable_device(struct pci_dev *dev) +{ + return 0; +} +#endif /* __powerpc__ */ + +#define PCI_ANY_ID (~0) + +/* as this is included multiple times, we make it inline */ + +static inline struct pci_dev * pci_find_subsys(unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from) +{ + unsigned short subsystem_vendor, subsystem_device; + + while ((from = pci_find_device(vendor, device, from))) { + pci_read_config_word(from, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); + pci_read_config_word(from, PCI_SUBSYSTEM_ID, &subsystem_device); + if ((ss_vendor == PCI_ANY_ID || subsystem_vendor == ss_vendor) && + (ss_device == PCI_ANY_ID || subsystem_device == ss_device)) + return from; + } + return NULL; +} + +#include + +/* + * Tell upper layers that the network device is ready to xmit more frames. + */ +static void __inline__ netif_wake_queue(struct device * dev) +{ + dev->tbusy = 0; + mark_bh(NET_BH); +} + +/* + * called during net_device open() + */ +static void __inline__ netif_start_queue(struct device * dev) +{ + dev->tbusy = 0; + /* actually, we never use the interrupt flag at all */ + dev->interrupt = 0; + dev->start = 1; +} + +/* + * Ask upper layers to temporarily cease passing us more xmit frames. + */ +static void __inline__ netif_stop_queue(struct device * dev) +{ + dev->tbusy = 1; +} + + + + +#endif /* __KERNEL__ */ +#endif /* _LINUX_ISDN_COMPAT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/isdn_ppp.h linux/include/linux/isdn_ppp.h --- v2.2.18/include/linux/isdn_ppp.h Sun Mar 25 11:12:37 2001 +++ linux/include/linux/isdn_ppp.h Sun Mar 25 11:37:40 2001 @@ -30,8 +30,8 @@ #define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] ) #define PPP_MP 0x003d -#define PPP_LINK_COMP 0x00fb -#define PPP_LINK_CCP 0x80fb +#define PPP_COMPFRAG 0x00fb +#define PPP_CCPFRAG 0x80fb #define SC_MP_PROT 0x00000200 #define SC_REJ_MP_PROT 0x00000400 @@ -68,8 +68,6 @@ #ifdef __KERNEL__ -#include - /* * We need a way for the decompressor to influence the generation of CCP * Reset-Requests in a variety of ways. The decompressor is already returning @@ -203,7 +201,7 @@ struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */ struct ippp_buf_queue *first; /* pointer to (current) first packet */ struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */ - struct wait_queue *wq; + wait_queue_head_t wq; struct task_struct *tk; unsigned int mpppcfg; unsigned int pppcfg; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/isdnif.h linux/include/linux/isdnif.h --- v2.2.18/include/linux/isdnif.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/isdnif.h Sun Mar 25 11:37:40 2001 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.35 2000/06/16 13:19:38 keil Exp $ +/* $Id: isdnif.h,v 1.37 2000/11/19 17:01:54 kai Exp $ * Linux ISDN subsystem * @@ -53,6 +53,7 @@ #define ISDN_PROTO_L2_V11038 9 /* V.110 bitrate adaption 38400 Baud */ #define ISDN_PROTO_L2_MODEM 10 /* Analog Modem on Board */ #define ISDN_PROTO_L2_FAX 11 /* Fax Group 2/3 */ +#define ISDN_PROTO_L2_HDLC_56K 12 /* HDLC 56k */ #define ISDN_PROTO_L2_MAX 15 /* Max. 16 Protocols */ /* @@ -135,6 +136,20 @@ /* STAT_INVOKE_BRD callback. The ll_id is set to 0, the other fields */ /* are supplied by the network and not by the HL. */ /*********************************************************************/ + +/*****************/ +/* NI1 commands */ +/*****************/ +#define NI1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_NI1) /* invoke a supplementary service */ +#define NI1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_NI1) /* abort a invoke cmd */ + +/*******************************/ +/* NI1 Status callback values */ +/*******************************/ +#define NI1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_NI1) /* Result for invocation */ +#define NI1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_NI1) /* Error Return for invocation */ +#define NI1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_NI1) /* Deliver invoke broadcast info */ + typedef struct { ulong ll_id; /* ID supplied by LL when executing */ /* a command and returned by HL for */ @@ -150,7 +165,7 @@ /* error value when error callback */ int datalen; /* length of cmd or stat data */ u_char *data;/* pointer to data delivered or send */ - } dss1_cmd_stat; + } isdn_cmd_stat; /* * Commands from linklevel to lowlevel @@ -239,6 +254,7 @@ #define ISDN_FEATURE_L2_V11038 (0x0001 << ISDN_PROTO_L2_V11038) #define ISDN_FEATURE_L2_MODEM (0x0001 << ISDN_PROTO_L2_MODEM) #define ISDN_FEATURE_L2_FAX (0x0001 << ISDN_PROTO_L2_FAX) +#define ISDN_FEATURE_L2_HDLC_56K (0x0001 << ISDN_PROTO_L2_HDLC_56K) #define ISDN_FEATURE_L2_MASK (0x0FFFF) /* Max. 16 protocols */ #define ISDN_FEATURE_L2_SHIFT (0) @@ -412,13 +428,16 @@ setup_parm setup;/* For SETUP msg */ capi_msg cmsg; /* For CAPI like messages */ char display[85];/* display message data */ - dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */ + isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result */ aux_s aux; /* for modem commands/indications */ #ifdef CONFIG_ISDN_TTY_FAX T30_s *fax; /* Pointer to ttys fax struct */ #endif } parm; } isdn_ctrl; + +#define dss1_io isdn_io +#define ni1_io isdn_io /* * The interface-struct itself (initialized at load-time of lowlevel-driver) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/iso_fs.h linux/include/linux/iso_fs.h --- v2.2.18/include/linux/iso_fs.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/iso_fs.h Sun Mar 25 11:37:40 2001 @@ -177,41 +177,22 @@ extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *); +extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *); extern char * get_rock_ridge_symlink(struct inode *); -extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *); -int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *); +extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *); +int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *); int get_acorn_filename(struct iso_directory_record *, char *, struct inode *); -/* The stuff that follows may be totally unneeded. I have not checked to see - which prototypes we are still using. */ - -extern int isofs_open(struct inode * inode, struct file * filp); -extern void isofs_release(struct inode * inode, struct file * filp); extern struct dentry *isofs_lookup(struct inode * dir, struct dentry *); -extern unsigned long isofs_count_free_inodes(struct super_block *sb); -extern int isofs_new_block(int dev); -extern int isofs_free_block(int dev, int block); extern int isofs_bmap(struct inode *,int); - -extern void isofs_put_super(struct super_block *); -extern struct super_block *isofs_read_super(struct super_block *,void *,int); +extern struct buffer_head *isofs_bread(struct inode *, unsigned int, unsigned int); extern int init_iso9660_fs(void); -extern void isofs_read_inode(struct inode *); -extern void isofs_put_inode(struct inode *); -extern int isofs_statfs(struct super_block *, struct statfs *, int); - -extern int isofs_lseek(struct inode *, struct file *, off_t, int); -extern int isofs_read(struct inode *, struct file *, char *, int); -extern int isofs_lookup_grandparent(struct inode *, int); extern struct inode_operations isofs_file_inode_operations; extern struct inode_operations isofs_dir_inode_operations; extern struct inode_operations isofs_symlink_inode_operations; -extern struct inode_operations isofs_chrdev_inode_operations; -extern struct inode_operations isofs_blkdev_inode_operations; -extern struct inode_operations isofs_fifo_inode_operations; /* The following macros are used to check for memory leaks. */ #ifdef LEAK_CHECK diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/kernelcapi.h linux/include/linux/kernelcapi.h --- v2.2.18/include/linux/kernelcapi.h Sun Mar 25 11:12:37 2001 +++ linux/include/linux/kernelcapi.h Sun Mar 25 11:37:40 2001 @@ -1,58 +1,17 @@ /* - * $Id: kernelcapi.h,v 1.5 2000/01/28 16:45:40 calle Exp $ + * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $ * * Kernel CAPI 2.0 Interface for Linux * * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * - * $Log: kernelcapi.h,v $ - * Revision 1.5 2000/01/28 16:45:40 calle - * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), - * will search named driver and call the add_card function if one exist. - * - * Revision 1.4 1999/09/10 17:24:19 calle - * Changes for proposed standard for CAPI2.0: - * - AK148 "Linux Exention" - * - * Revision 1.3 1999/07/01 15:26:56 calle - * complete new version (I love it): - * + new hardware independed "capi_driver" interface that will make it easy to: - * - support other controllers with CAPI-2.0 (i.e. USB Controller) - * - write a CAPI-2.0 for the passive cards - * - support serial link CAPI-2.0 boxes. - * + wrote "capi_driver" for all supported cards. - * + "capi_driver" (supported cards) now have to be configured with - * make menuconfig, in the past all supported cards where included - * at once. - * + new and better informations in /proc/capi/ - * + new ioctl to switch trace of capi messages per controller - * using "avmcapictrl trace [contr] on|off|...." - * + complete testcircle with all supported cards and also the - * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. - * - * Revision 1.2 1999/06/21 15:24:26 calle - * extend information in /proc. - * - * Revision 1.1 1997/03/04 21:27:33 calle - * First version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * - * */ + #ifndef __KERNELCAPI_H__ #define __KERNELCAPI_H__ -#define CAPI_MAXAPPL 20 /* - * maximum number of applications - */ -#define CAPI_MAXCONTR 10 /* - * maximum number of controller - */ +#define CAPI_MAXAPPL 128 /* maximum number of applications */ +#define CAPI_MAXCONTR 16 /* maximum number of controller */ #define CAPI_MAXDATAWINDOW 8 @@ -94,8 +53,8 @@ __u16 (*capi_put_message) (__u16 applid, struct sk_buff * msg); __u16 (*capi_get_message) (__u16 applid, struct sk_buff ** msgp); __u16 (*capi_set_signal) (__u16 applid, - void (*signal) (__u16 applid, __u32 param), - __u32 param); + void (*signal) (__u16 applid, void *param), + void *param); __u16 (*capi_get_manufacturer) (__u32 contr, __u8 buf[CAPI_MANUFACTURER_LEN]); __u16 (*capi_get_version) (__u32 contr, struct capi_version * verp); __u16(*capi_get_serial) (__u32 contr, __u8 serial[CAPI_SERIAL_LEN]); @@ -108,8 +67,15 @@ }; -#define KCI_CONTRUP 0 -#define KCI_CONTRDOWN 1 +struct capi_ncciinfo { + __u16 applid; + __u32 ncci; +}; + +#define KCI_CONTRUP 0 /* struct capi_profile */ +#define KCI_CONTRDOWN 1 /* NULL */ +#define KCI_NCCIUP 2 /* struct capi_ncciinfo */ +#define KCI_NCCIDOWN 3 /* struct capi_ncciinfo */ struct capi_interface_user { char name[20]; @@ -147,6 +113,47 @@ #define CAPI_MSGNOTINSTALLED 0x1109 #define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a #define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b + +typedef enum { + CapiMessageNotSupportedInCurrentState = 0x2001, + CapiIllContrPlciNcci = 0x2002, + CapiNoPlciAvailable = 0x2003, + CapiNoNcciAvailable = 0x2004, + CapiNoListenResourcesAvailable = 0x2005, + CapiNoFaxResourcesAvailable = 0x2006, + CapiIllMessageParmCoding = 0x2007, +} RESOURCE_CODING_PROBLEM; + +typedef enum { + CapiB1ProtocolNotSupported = 0x3001, + CapiB2ProtocolNotSupported = 0x3002, + CapiB3ProtocolNotSupported = 0x3003, + CapiB1ProtocolParameterNotSupported = 0x3004, + CapiB2ProtocolParameterNotSupported = 0x3005, + CapiB3ProtocolParameterNotSupported = 0x3006, + CapiBProtocolCombinationNotSupported = 0x3007, + CapiNcpiNotSupported = 0x3008, + CapiCipValueUnknown = 0x3009, + CapiFlagsNotSupported = 0x300a, + CapiFacilityNotSupported = 0x300b, + CapiDataLengthNotSupportedByCurrentProtocol = 0x300c, + CapiResetProcedureNotSupportedByCurrentProtocol = 0x300d, + CapiTeiAssignmentFailed = 0x300e, +} REQUESTED_SERVICES_PROBLEM; + +typedef enum { + CapiSuccess = 0x0000, + CapiSupplementaryServiceNotSupported = 0x300e, + CapiRequestNotAllowedInThisState = 0x3010, +} SUPPLEMENTARY_SERVICE_INFO; + +typedef enum { + CapiProtocolErrorLayer1 = 0x3301, + CapiProtocolErrorLayer2 = 0x3302, + CapiProtocolErrorLayer3 = 0x3303, + CapiTimeOut = 0x3303, // SuppServiceReason + CapiCallGivenToOtherApplication = 0x3304, +} CAPI_REASON; #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/lockd/nlm.h linux/include/linux/lockd/nlm.h --- v2.2.18/include/linux/lockd/nlm.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/lockd/nlm.h Sun Mar 25 11:37:40 2001 @@ -45,10 +45,10 @@ #define NLMPROC_CANCEL_RES 13 #define NLMPROC_UNLOCK_RES 14 #define NLMPROC_GRANTED_RES 15 +#define NLMPROC_NSM_NOTIFY 16 /* statd callback */ #define NLMPROC_SHARE 20 #define NLMPROC_UNSHARE 21 #define NLMPROC_NM_LOCK 22 #define NLMPROC_FREE_ALL 23 -#define NLMPROC_NSM_NOTIFY 24 /* statd callback */ #endif /* LINUX_LOCKD_NLM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/locks.h linux/include/linux/locks.h --- v2.2.18/include/linux/locks.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/locks.h Sun Mar 25 11:37:40 2001 @@ -50,10 +50,12 @@ if (sb->s_lock) __wait_on_super(sb); sb->s_lock = 1; + current->fs_locks++; } extern inline void unlock_super(struct super_block * sb) { + current->fs_locks--; sb->s_lock = 0; wake_up(&sb->s_wait); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/major.h linux/include/linux/major.h --- v2.2.18/include/linux/major.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/major.h Sun Mar 25 11:37:40 2001 @@ -133,6 +133,8 @@ #define MSR_MAJOR 202 #define CPUID_MAJOR 203 +#define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */ + /* * Tests for SCSI devices. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h --- v2.2.18/include/linux/mc146818rtc.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/mc146818rtc.h Sun Mar 25 11:37:40 2001 @@ -11,6 +11,7 @@ #ifndef _MC146818RTC_H #define _MC146818RTC_H #include +#include #ifndef RTC_PORT #define RTC_PORT(x) (0x70 + (x)) @@ -26,7 +27,9 @@ outb_p((val),RTC_PORT(1)); \ }) +#ifdef __KERNEL__ extern spinlock_t rtc_lock; /* You must hold this lock to use CMOS_* ops */ +#endif /********************************************************************** * register summary @@ -107,45 +110,5 @@ #ifndef BIN_TO_BCD #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) #endif - -/* - * The struct used to pass data via the following ioctl. Similar to the - * struct tm in , but it needs to be here so that the kernel - * source is self contained, allowing cross-compiles, etc. etc. - */ - -struct rtc_time { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -/* - * ioctl calls that are permitted to the /dev/rtc interface, if - * CONFIG_RTC was enabled. - */ - -#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ -#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ -#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ -#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ -#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ -#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ - -#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ -#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ -#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ -#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ -#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ -#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ - #endif /* _MC146818RTC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/miscdevice.h linux/include/linux/miscdevice.h --- v2.2.18/include/linux/miscdevice.h Sun Mar 25 11:12:37 2001 +++ linux/include/linux/miscdevice.h Sun Mar 25 11:37:40 2001 @@ -17,6 +17,7 @@ #define SUN_OPENPROM_MINOR 139 #define NVRAM_MINOR 144 #define I2O_MINOR 166 +#define MICROCODE_MINOR 184 #define MISC_DYNAMIC_MINOR 255 #define SGI_GRAPHICS_MINOR 146 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/mtio.h linux/include/linux/mtio.h --- v2.2.18/include/linux/mtio.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/mtio.h Sun Mar 25 11:37:40 2001 @@ -105,6 +105,8 @@ #define MT_ISEVEREX_FT40A 0x32 /* Everex FT40A (QIC-40) */ #define MT_ISDDS1 0x51 /* DDS device without partitions */ #define MT_ISDDS2 0x52 /* DDS device with partitions */ +#define MT_ISONSTREAM_SC 0x61 /* OnStream SCSI tape drives (SC-x0) + and SCSI emulated (DI, DP, USB) */ #define MT_ISSCSI1 0x71 /* Generic ANSI SCSI-1 tape unit */ #define MT_ISSCSI2 0x72 /* Generic ANSI SCSI-2 tape unit */ @@ -134,6 +136,7 @@ {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \ {MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \ {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \ + {MT_ISONSTREAM_SC, "OnStream SC-, DI-, DP-, or USB tape drive"}, \ {MT_ISSCSI1, "Generic SCSI-1 tape"}, \ {MT_ISSCSI2, "Generic SCSI-2 tape"}, \ {0, NULL} \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfs.h linux/include/linux/nfs.h --- v2.2.18/include/linux/nfs.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfs.h Sun Mar 25 11:37:40 2001 @@ -94,8 +94,8 @@ */ #define NFS_MAXFHSIZE 64 struct nfs_fh { - unsigned short size; - unsigned char data[NFS_MAXFHSIZE]; + unsigned int size; + unsigned int data[NFS_MAXFHSIZE / sizeof(unsigned int)]; }; enum nfs3_stable_how { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfs3.h linux/include/linux/nfs3.h --- v2.2.18/include/linux/nfs3.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfs3.h Sun Mar 25 11:37:40 2001 @@ -58,6 +58,11 @@ NF3BAD = 8 }; +struct nfs3_fh { + unsigned short size; + unsigned char data[NFS3_FHSIZE]; +}; + #define NFS3_VERSION 3 #define NFS3PROC_NULL 0 #define NFS3PROC_GETATTR 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v2.2.18/include/linux/nfs_fs.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfs_fs.h Sun Mar 25 11:37:40 2001 @@ -54,8 +54,7 @@ /* * Convenience macros */ -#define NFS_FH(dentry) ((struct nfs_fh *) ((dentry)->d_fsdata)) -#define NFS_DSERVER(dentry) (&(dentry)->d_sb->u.nfs_sb.s_server) +#define NFS_FH(inode) (&(inode)->u.nfs_i.fh) #define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server) #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) #define NFS_PROTO(inode) (NFS_SERVER(inode)->rpc_ops) @@ -84,12 +83,11 @@ #define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags) #define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING) +#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE) #define NFS_FILEID(inode) ((inode)->u.nfs_i.fileid) #define NFS_FSID(inode) ((inode)->u.nfs_i.fsid) -#define NFS_FILE(file) ((struct nfs_file *)(file)->private_data) - /* Inode Flags */ #define NFS_USE_READDIRPLUS(inode) ((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0) @@ -114,24 +112,6 @@ #define FLUSH_STABLE 4 /* commit to stable storage */ -/* - * Structure for file->private_data; - */ -struct nfs_file { - unsigned long magic; /* Magic number */ - struct rpc_cred* cred; /* RPC Credentials */ -}; - -static inline int -nfs_check_file(struct file *file) -{ - if (NFS_FILE(file)->magic != NFS_FILE_MAGIC) { - printk(KERN_ERR "NFS: corrupt file structure!\n"); - return 0; - } - return 1; -} - static inline unsigned long nfs_page_offset(struct page *page) { @@ -147,6 +127,8 @@ /* * linux/fs/nfs/inode.c */ +extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *, + struct nfs_fattr *); extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *, struct nfs_fattr *); extern struct super_block *nfs_read_super(struct super_block *, void *, int); @@ -155,7 +137,7 @@ extern int nfs_revalidate(struct dentry *); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); -extern int __nfs_revalidate_inode(struct dentry *); +extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_wait_on_inode(struct inode *, int flag); extern void nfs_unlock_inode(struct inode *); @@ -286,19 +268,18 @@ * linux/fs/mount_clnt.c * (Used only by nfsroot module) */ -extern int nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *); -extern int nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *); +extern int nfs_mount(struct sockaddr_in *, char *, struct nfs3_fh *); +extern int nfs3_mount(struct sockaddr_in *, char *, struct nfs3_fh *); /* * inline functions */ static inline int -nfs_revalidate_inode(struct dentry *dentry) +nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) { - struct inode *inode = dentry->d_inode; if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) return 0; - return __nfs_revalidate_inode(dentry); + return __nfs_revalidate_inode(server, inode); } static inline off_t @@ -325,11 +306,7 @@ static __inline__ struct rpc_cred * nfs_file_cred(struct file *file) { - if (!NFS_FILE(file) || !nfs_check_file(file)) { - printk("nfs_file_cred: invalid file!\n"); - return NULL; - } - return NFS_FILE(file)->cred; + return (struct rpc_cred *)(file->private_data); } /* NFS root */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h --- v2.2.18/include/linux/nfs_fs_i.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfs_fs_i.h Sun Mar 25 11:37:40 2001 @@ -1,6 +1,7 @@ #ifndef _NFS_FS_i #define _NFS_FS_I +#include #include #include @@ -22,6 +23,11 @@ __u64 fileid; /* + * NFS file handle + */ + struct nfs_fh fh; + + /* * Various flags */ unsigned short flags; @@ -79,12 +85,10 @@ /* * Legal inode flag values */ -#define NFS_INO_LOCKED 0x0001 /* locked for revalidation */ +#define NFS_INO_STALE 0x0001 /* We suspect inode is stale */ #define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */ #define NFS_INO_REVALIDATING 0x0004 /* in nfs_revalidate() */ -#define NFS_INO_INVALIDATE 0x0008 /* zap cache on next occasion */ #define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */ -#define NFS_INO_STALE 0x0020 /* We suspect inode is stale */ #define NFS_INO_FLUSH 0x0040 /* inode is due for flushing */ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfs_mount.h linux/include/linux/nfs_mount.h --- v2.2.18/include/linux/nfs_mount.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfs_mount.h Sun Mar 25 11:37:40 2001 @@ -8,9 +8,9 @@ * * structure passed from user-space to kernel-space during an nfs mount */ -#include +#include #include -#include +#include /* * WARNING! Do not delete or change the order of these fields. If @@ -42,7 +42,7 @@ char hostname[256]; /* 1 */ int namlen; /* 2 */ unsigned int bsize; /* 3 */ - struct nfs_fh root; /* 4 */ + struct nfs3_fh root; /* 4 */ }; /* bits in the flags field */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfs_page.h linux/include/linux/nfs_page.h --- v2.2.18/include/linux/nfs_page.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfs_page.h Sun Mar 25 11:37:40 2001 @@ -26,7 +26,7 @@ wb_list, /* Defines state of page: */ *wb_list_head; /* read/write/commit */ struct file *wb_file; - struct dentry *wb_dentry; + struct inode *wb_inode; struct rpc_cred *wb_cred; struct page *wb_page; /* page to read in/write out */ struct wait_queue *wb_wait; /* wait queue */ @@ -41,6 +41,7 @@ #define NFS_WBACK_BUSY(req) ((req)->wb_flags & PG_BUSY) extern struct nfs_page *nfs_create_request(struct file *file, + struct inode *inode, struct page *page, unsigned int offset, unsigned int count); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfs_xdr.h linux/include/linux/nfs_xdr.h --- v2.2.18/include/linux/nfs_xdr.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfs_xdr.h Sun Mar 25 11:37:40 2001 @@ -321,48 +321,43 @@ int (*getroot)(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *); - int (*getattr)(struct dentry *, struct nfs_fattr *); - int (*setattr)(struct dentry *, struct nfs_fattr *, struct iattr *); - int (*lookup)(struct dentry *, struct nfs_fattr *, struct qstr *, + int (*getattr)(struct inode *, struct nfs_fattr *); + int (*setattr)(struct inode *, struct nfs_fattr *, struct iattr *); + int (*lookup)(struct inode *, struct qstr *, struct nfs_fh *, struct nfs_fattr *); - int (*access)(struct dentry *, int fmode, struct nfs_fattr *, int); - int (*readlink)(struct dentry *, struct nfs_fattr *, - void *buffer, unsigned int buflen); - int (*read)(struct dentry *, struct nfs_fattr *, - struct rpc_cred *, + int (*access)(struct inode *, int, int); + int (*readlink)(struct inode *, void *buffer, unsigned int buflen); + int (*read)(struct inode *, struct rpc_cred *, + struct nfs_fattr *, int flags, unsigned long offset, unsigned int count, void *buffer, int *eofp); - int (*write)(struct dentry *, struct nfs_fattr *, - struct rpc_cred *, + int (*write)(struct inode *, struct rpc_cred *, + struct nfs_fattr *, int flags, unsigned long offset, unsigned int count, void *buffer, struct nfs_writeverf *verfp); - int (*commit)(struct dentry *, struct nfs_fattr *, + int (*commit)(struct inode *, struct nfs_fattr *, struct rpc_cred *, unsigned long, unsigned int); - int (*create)(struct dentry *, struct nfs_fattr *, - struct qstr *, struct iattr *, int flags, - struct nfs_fh *, struct nfs_fattr *); - int (*remove)(struct dentry *, struct nfs_fattr *, struct qstr *); + int (*create)(struct inode *, struct qstr *, struct iattr *, + int, struct nfs_fh *, struct nfs_fattr *); + int (*remove)(struct inode *, struct qstr *); int (*unlink_setup) (struct rpc_message *, struct dentry *, struct qstr *); void (*unlink_done) (struct dentry *, struct rpc_message *); - int (*rename)(struct dentry *, struct nfs_fattr *, struct qstr *, - struct dentry *, struct nfs_fattr *, struct qstr *); - int (*link)(struct dentry *, struct nfs_fattr *, - struct dentry *, struct nfs_fattr *, struct qstr *); - int (*symlink)(struct dentry *, struct nfs_fattr *, struct qstr *, - struct qstr *, struct iattr *, - struct nfs_fh *, struct nfs_fattr *); - int (*mkdir)(struct dentry *, struct nfs_fattr *, struct qstr *, - struct iattr *, struct nfs_fh *, struct nfs_fattr *); - int (*rmdir)(struct dentry *, struct nfs_fattr *, struct qstr *); - int (*readdir)(struct dentry *, struct nfs_fattr *, - struct rpc_cred *, - __u64 cookie, void *, unsigned int size, int plus); - int (*mknod)(struct dentry *, struct nfs_fattr *, struct qstr *, - struct iattr *, dev_t, - struct nfs_fh *, struct nfs_fattr *); + int (*rename)(struct inode *, struct qstr *, + struct inode *, struct qstr *); + int (*link)(struct inode *, struct inode *, struct qstr *); + int (*symlink)(struct inode *, struct qstr *, struct qstr *, + struct iattr *, struct nfs_fh *, + struct nfs_fattr *); + int (*mkdir)(struct inode *, struct qstr *, struct iattr *, + struct nfs_fh *, struct nfs_fattr *); + int (*rmdir)(struct inode *, struct qstr *); + int (*readdir)(struct inode *, struct rpc_cred *, + __u64, void *, unsigned int, int); + int (*mknod)(struct inode *, struct qstr *, struct iattr *, + dev_t, struct nfs_fh *, struct nfs_fattr *); int (*statfs)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); __u32 * (*decode_dirent)(__u32 *, struct nfs_entry *, int plus); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfsd/nfsd.h linux/include/linux/nfsd/nfsd.h --- v2.2.18/include/linux/nfsd/nfsd.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfsd/nfsd.h Sun Mar 25 11:37:40 2001 @@ -100,7 +100,7 @@ int nfsd_read(struct svc_rqst *, struct svc_fh *, loff_t, char *, unsigned long *); int nfsd_write(struct svc_rqst *, struct svc_fh *, - loff_t, char *, unsigned long, int); + loff_t, char *, unsigned long, int *); int nfsd_readlink(struct svc_rqst *, struct svc_fh *, char *, int *); int nfsd_symlink(struct svc_rqst *, struct svc_fh *, @@ -145,38 +145,41 @@ #endif /* - * These variables contain pre-xdr'ed values for faster operation. - * FIXME: should be replaced by macros for big-endian machines. + * These macros provide pre-xdr'ed values for faster operation. */ -extern u32 nfs_ok, - nfserr_perm, - nfserr_noent, - nfserr_io, - nfserr_nxio, - nfserr_acces, - nfserr_exist, - nfserr_xdev, - nfserr_nodev, - nfserr_notdir, - nfserr_isdir, - nfserr_inval, - nfserr_fbig, - nfserr_nospc, - nfserr_rofs, - nfserr_mlink, - nfserr_nametoolong, - nfserr_notempty, - nfserr_dquot, - nfserr_stale, - nfserr_remote, - nfserr_badhandle, - nfserr_notsync, - nfserr_badcookie, - nfserr_notsupp, - nfserr_toosmall, - nfserr_serverfault, - nfserr_badtype, - nfserr_jukebox; +#define nfs_ok __constant_htonl(NFS_OK) +#define nfserr_perm __constant_htonl(NFSERR_PERM) +#define nfserr_noent __constant_htonl(NFSERR_NOENT) +#define nfserr_io __constant_htonl(NFSERR_IO) +#define nfserr_nxio __constant_htonl(NFSERR_NXIO) +#define nfserr_acces __constant_htonl(NFSERR_ACCES) +#define nfserr_exist __constant_htonl(NFSERR_EXIST) +#define nfserr_xdev __constant_htonl(NFSERR_XDEV) +#define nfserr_nodev __constant_htonl(NFSERR_NODEV) +#define nfserr_notdir __constant_htonl(NFSERR_NOTDIR) +#define nfserr_isdir __constant_htonl(NFSERR_ISDIR) +#define nfserr_inval __constant_htonl(NFSERR_INVAL) +#define nfserr_fbig __constant_htonl(NFSERR_FBIG) +#define nfserr_nospc __constant_htonl(NFSERR_NOSPC) +#define nfserr_rofs __constant_htonl(NFSERR_ROFS) +#define nfserr_mlink __constant_htonl(NFSERR_MLINK) +#define nfserr_opnotsupp __constant_htonl(NFSERR_OPNOTSUPP) +#define nfserr_nametoolong __constant_htonl(NFSERR_NAMETOOLONG) +#define nfserr_notempty __constant_htonl(NFSERR_NOTEMPTY) +#define nfserr_dquot __constant_htonl(NFSERR_DQUOT) +#define nfserr_stale __constant_htonl(NFSERR_STALE) +#define nfserr_remote __constant_htonl(NFSERR_REMOTE) +#define nfserr_badhandle __constant_htonl(NFSERR_BADHANDLE) +#define nfserr_notsync __constant_htonl(NFSERR_NOTSYNC) +#define nfserr_badcookie __constant_htonl(NFSERR_BADCOOKIE) +#define nfserr_notsupp __constant_htonl(NFSERR_NOTSUPP) +#define nfserr_toosmall __constant_htonl(NFSERR_TOOSMALL) +#define nfserr_serverfault __constant_htonl(NFSERR_SERVERFAULT) +#define nfserr_badtype __constant_htonl(NFSERR_BADTYPE) +#define nfserr_jukebox __constant_htonl(NFSERR_JUKEBOX) + +/* Check for dir entries '.' and '..' */ +#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) /* * Time of server startup diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h --- v2.2.18/include/linux/nfsd/nfsfh.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfsd/nfsfh.h Sun Mar 25 11:37:40 2001 @@ -30,7 +30,7 @@ * ino/dev of the exported inode. */ struct nfs_fhbase { - struct dentry * fb_dentry; /* dentry cookie */ + __u32 fb_dcookie; /* dentry cookie */ __u32 fb_ino; /* our inode number */ __u32 fb_dirino; /* dir inode number */ __u32 fb_dev; /* our device */ @@ -45,7 +45,7 @@ __u8 fh_cookie[NFS_FH_PADDING]; }; -#define fh_dcookie fh_base.fb_dentry +#define fh_dcookie fh_base.fb_dcookie #define fh_ino fh_base.fb_ino #define fh_dirino fh_base.fb_dirino #define fh_dev fh_base.fb_dev diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nfsd/xdr3.h linux/include/linux/nfsd/xdr3.h --- v2.2.18/include/linux/nfsd/xdr3.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nfsd/xdr3.h Sun Mar 25 11:37:40 2001 @@ -296,19 +296,5 @@ int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, int namlen, off_t offset, ino_t ino); -#ifdef __KERNEL__ - -/* - * This is needed in nfs_readdir for encoding NFS3 directory cookies. - */ -static inline u32 * -enc64(u32 *p, u64 val) -{ - *p++ = htonl(val >> 32); - *p++ = htonl(val & 0xffffffff); - return p; -} - -#endif /* __KERNEL__ */ #endif /* _LINUX_NFSD_XDR3_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/nls.h linux/include/linux/nls.h --- v2.2.18/include/linux/nls.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/nls.h Sun Mar 25 11:37:40 2001 @@ -60,3 +60,4 @@ extern int init_nls_cp949(void); extern int init_nls_cp950(void); extern int init_nls_koi8_r(void); +extern int init_nls_koi8_ru(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/pci.h linux/include/linux/pci.h --- v2.2.18/include/linux/pci.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/pci.h Sun Mar 25 11:37:40 2001 @@ -307,6 +307,15 @@ * (and according to card ID within vendor). Send all updates to * . */ +#define PCI_VENDOR_ID_DYNALINK 0x0675 +#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702 + +#define PCI_VENDOR_ID_BERKOM 0x0871 +#define PCI_DEVICE_ID_BERKOM_A1T 0xFFA1 +#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xFFA2 +#define PCI_DEVICE_ID_BERKOM_A4T 0xFFA4 +#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xFFA8 + #define PCI_VENDOR_ID_COMPAQ 0x0e11 #define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508 #define PCI_DEVICE_ID_COMPAQ_1280 0x3033 @@ -477,6 +486,10 @@ #define PCI_DEVICE_ID_CT_65554 0x00e4 #define PCI_DEVICE_ID_CT_65555 0x00e5 +#define PCI_DEVICE_ID_PLX_R685 0x1030 +#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 +#define PCI_DEVICE_ID_PLX_R753 0x1152 + #define PCI_VENDOR_ID_MIRO 0x1031 #define PCI_DEVICE_ID_MIRO_36050 0x5601 @@ -515,6 +528,9 @@ #define PCI_DEVICE_ID_PCTECH_SAMURAI_1 0x3010 #define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020 +#define PCI_VENDOR_ID_ASUSTEK 0x1043 +#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675 + #define PCI_VENDOR_ID_DPT 0x1044 #define PCI_DEVICE_ID_DPT 0xa400 @@ -530,6 +546,10 @@ #define PCI_DEVICE_ID_OPTI_82C861 0xc861 #define PCI_DEVICE_ID_OPTI_82C825 0xd568 +#define PCI_VENDOR_ID_ELSA 0x1048 +#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 +#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 + #define PCI_VENDOR_ID_SGS 0x104a #define PCI_DEVICE_ID_SGS_2000 0x0008 #define PCI_DEVICE_ID_SGS_1764 0x0009 @@ -554,6 +574,10 @@ /* Winbond have two vendor IDs! See 0x10ad as well */ #define PCI_VENDOR_ID_WINBOND2 0x1050 #define PCI_DEVICE_ID_WINBOND2_89C940 0x0940 +#define PCI_DEVICE_ID_WINBOND2_6692 0x6692 + +#define PCI_VENDOR_ID_ANIGMA 0x1051 +#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100 #define PCI_VENDOR_ID_MOTOROLA 0x1057 #define PCI_VENDOR_ID_MOTOROLA_OOPS 0x1507 @@ -873,6 +897,17 @@ #define PCI_DEVICE_ID_PHILIPS_SAA7145 0x7145 #define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146 +#define PCI_VENDOR_ID_EICON 0x1133 +#define PCI_DEVICE_ID_EICON_DIVA20PRO 0xe001 +#define PCI_DEVICE_ID_EICON_DIVA20 0xe002 +#define PCI_DEVICE_ID_EICON_DIVA20PRO_U 0xe003 +#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 +#define PCI_DEVICE_ID_EICON_DIVA201 0xe005 +#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010 +#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012 +#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013 +#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014 + #define PCI_VENDOR_ID_CYCLONE 0x113c #define PCI_DEVICE_ID_CYCLONE_SDK 0x0001 @@ -899,6 +934,10 @@ #define PCI_DEVICE_ID_DIGI_XRJ 0x0009 #define PCI_DEVICE_ID_DIGI_EPCJ 0x000a #define PCI_DEVICE_ID_DIGI_XR_920 0x0027 +#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070 +#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071 +#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072 +#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073 #define PCI_VENDOR_ID_MUTECH 0x1159 #define PCI_DEVICE_ID_MUTECH_MV1000 0x0001 @@ -1023,6 +1062,9 @@ #define PCI_VENDOR_ID_AVM 0x1244 #define PCI_DEVICE_ID_AVM_A1 0x0a00 +#define PCI_DEVICE_ID_AVM_B1 0x0700 +#define PCI_DEVICE_ID_AVM_C4 0x0800 +#define PCI_DEVICE_ID_AVM_T1 0x1200 #define PCI_VENDOR_ID_DIPIX 0x1246 @@ -1039,6 +1081,7 @@ #define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130 #define PCI_VENDOR_ID_SATSAGEM 0x1267 +#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 #define PCI_DEVICE_ID_SATSAGEM_PCR2101 0x5352 #define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b @@ -1082,9 +1125,32 @@ #define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061 #define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 +#define PCI_VENDOR_ID_HYPERCOPE 0x1365 +#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050 +#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104 +#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106 +#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107 +#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108 +#define PCI_SUBDEVICE_ID_HYPERCOPE_PLEXUS 0x0109 + #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a +#define PCI_VENDOR_ID_CCD 0x1397 +#define PCI_DEVICE_ID_CCD_2BD0 0x2BD0 +#define PCI_DEVICE_ID_CCD_B000 0xB000 +#define PCI_DEVICE_ID_CCD_B006 0xB006 +#define PCI_DEVICE_ID_CCD_B007 0xB007 +#define PCI_DEVICE_ID_CCD_B008 0xB008 +#define PCI_DEVICE_ID_CCD_B009 0xB009 +#define PCI_DEVICE_ID_CCD_B00A 0xB00A +#define PCI_DEVICE_ID_CCD_B00B 0xB00B +#define PCI_DEVICE_ID_CCD_B00C 0xB00C +#define PCI_DEVICE_ID_CCD_B100 0xB100 + +#define PCI_VENDOR_ID_ABOCOM 0x13D1 +#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1 + #define PCI_VENDOR_ID_LAVA 0x1407 #define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */ @@ -1102,6 +1168,9 @@ #define PCI_VENDOR_ID_AFAVLAB 0x14db #define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120 +#define PCI_VENDOR_ID_ZOLTRIX 0x15b0 +#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2BD0 + #define PCI_VENDOR_ID_SYMPHONY 0x1c1c #define PCI_DEVICE_ID_SYMPHONY_101 0x0001 @@ -1258,6 +1327,7 @@ #define PCI_VENDOR_ID_TIGERJET 0xe159 #define PCI_DEVICE_ID_TIGERJET_300 0x0001 +#define PCI_DEVICE_ID_TIGERJET_100 0x0002 #define PCI_VENDOR_ID_ARK 0xedd8 #define PCI_DEVICE_ID_ARK_STING 0xa091 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/rtc.h linux/include/linux/rtc.h --- v2.2.18/include/linux/rtc.h Wed Dec 31 19:00:00 1969 +++ linux/include/linux/rtc.h Sun Mar 25 11:37:40 2001 @@ -0,0 +1,43 @@ +#ifndef _LINUX_RTC_H +#define _LINUX_RTC_H_ + + +/* + * The struct used to pass data via the following ioctl. Similar to the + * struct tm in , but it needs to be here so that the kernel + * source is self contained, allowing cross-compiles, etc. etc. + */ + +struct rtc_time { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +/* + * ioctls that are permitted to the /dev/rtc interface. + */ + +#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ +#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ +#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ +#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ +#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ +#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ + +#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ +#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ +#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */ +#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ +#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ +#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ + +#endif /* _LINUX_RTC_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/scc.h linux/include/linux/scc.h --- v2.2.18/include/linux/scc.h Sun Mar 25 11:12:37 2001 +++ linux/include/linux/scc.h Sun Mar 25 11:37:40 2001 @@ -251,6 +251,7 @@ struct timer_list tx_t; /* tx timer for this channel */ struct timer_list tx_wdog; /* tx watchdogs */ + struct timer_list fs_wdog; /* failsafe watchdogs */ }; int scc_init(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/sched.h linux/include/linux/sched.h --- v2.2.18/include/linux/sched.h Sun Mar 25 11:28:38 2001 +++ linux/include/linux/sched.h Sun Mar 25 11:37:40 2001 @@ -79,6 +79,7 @@ #define TASK_ZOMBIE 4 #define TASK_STOPPED 8 #define TASK_SWAPPING 16 +#define TASK_EXCLUSIVE 32 /* * Scheduling policies @@ -119,6 +120,11 @@ extern signed long FASTCALL(schedule_timeout(signed long timeout)); asmlinkage void schedule(void); +extern int schedule_task(struct tq_struct *task); +extern void flush_scheduled_tasks(void); +extern int start_context_thread(void); +extern int current_is_keventd(void); + /* * The default fd array needs to be at least BITS_PER_LONG, * as this is the granularity returned by copy_fdset(). @@ -180,7 +186,11 @@ atomic_t count; int map_count; /* number of VMAs */ struct semaphore mmap_sem; +#ifdef __alpha__ + unsigned long context[NR_CPUS]; +#else unsigned long context; +#endif unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack; unsigned long arg_start, arg_end, env_start, env_end; @@ -196,12 +206,18 @@ void * segments; }; +#ifdef __alpha__ +#define CONTEXT_INIT { 0, } +#else +#define CONTEXT_INIT 0 +#endif + #define INIT_MM { \ &init_mmap, NULL, NULL, \ swapper_pg_dir, \ ATOMIC_INIT(1), 1, \ MUTEX, \ - 0, \ + CONTEXT_INIT, \ 0, 0, 0, 0, \ 0, 0, 0, \ 0, 0, 0, 0, \ @@ -251,13 +267,14 @@ struct task_struct *next_task, *prev_task; struct task_struct *next_run, *prev_run; + unsigned int task_exclusive; /* task wants wake-one semantics in __wake_up() */ /* task state */ struct linux_binfmt *binfmt; int exit_code, exit_signal; int pdeath_signal; /* The signal sent when the parent dies */ /* ??? */ unsigned long personality; - int dumpable:1; + unsigned int dumpable:1; int did_exec:1; pid_t pid; pid_t pgrp; @@ -317,6 +334,9 @@ struct files_struct *files; /* memory management info */ struct mm_struct *mm; + struct list_head local_pages; + int allocation_order, nr_local_pages; + int fs_locks; /* signal handlers */ spinlock_t sigmask_lock; /* Protects signal and blocked */ @@ -349,6 +369,7 @@ #define PF_SIGNALED 0x00000400 /* killed by a signal */ #define PF_MEMALLOC 0x00000800 /* Allocating memory */ #define PF_VFORK 0x00001000 /* Wake up parent in mm_release */ +#define PF_FREE_PAGES 0x00002000 /* The current-> */ #define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k, i386) */ @@ -370,6 +391,7 @@ /* counter */ DEF_PRIORITY,DEF_PRIORITY,0, \ /* SMP */ 0,0,0,-1, \ /* schedlink */ &init_task,&init_task, &init_task, &init_task, \ +/* task_exclusive */ 0, \ /* binfmt */ NULL, \ /* ec,brk... */ 0,0,0,0,0,0, \ /* pid etc.. */ 0,0,0,0,0, \ @@ -397,7 +419,7 @@ /* tss */ INIT_TSS, \ /* fs */ &init_fs, \ /* files */ &init_files, \ -/* mm */ &init_mm, \ +/* mm */ &init_mm, { &init_task.local_pages, &init_task.local_pages}, 0, 0, 0, \ /* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \ /* exec cts */ 0,0, \ /* oom */ 0, \ @@ -496,8 +518,15 @@ signed long timeout)); extern void FASTCALL(wake_up_process(struct task_struct * tsk)); -#define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE) -#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE) +#define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) +#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) + +#define __set_task_state(tsk, state_value) do { (tsk)->state = state_value; } while (0) +#ifdef __SMP__ +#define set_task_state(tsk, state_value) do { __set_task_state(tsk, state_value); mb(); } while (0) +#else +#define set_task_state(tsk, state_value) __set_task_state(tsk, state_value) +#endif #define __set_current_state(state_value) do { current->state = state_value; } while (0) #ifdef __SMP__ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h --- v2.2.18/include/linux/sunrpc/clnt.h Sun Mar 25 11:28:39 2001 +++ linux/include/linux/sunrpc/clnt.h Sun Mar 25 11:37:40 2001 @@ -111,6 +111,8 @@ void rpc_release_client(struct rpc_clnt *); void rpc_getport(struct rpc_task *, struct rpc_clnt *); int rpc_register(u32, u32, int, unsigned short, int *); +u32 * rpc_call_header(struct rpc_task *task); +u32 * rpc_call_verify(struct rpc_task *task); void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); @@ -143,6 +145,11 @@ * Helper function for NFSroot support */ int rpc_getport_external(struct sockaddr_in *, __u32, __u32, int); + +/* + * Ping function + */ +void rpc_ping(struct rpc_task *task); #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_CLNT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h --- v2.2.18/include/linux/sunrpc/sched.h Sun Mar 25 11:28:39 2001 +++ linux/include/linux/sunrpc/sched.h Sun Mar 25 11:37:40 2001 @@ -45,7 +45,7 @@ struct rpc_task * tk_parent; /* parent task */ struct rpc_clnt * tk_client; /* RPC client */ struct rpc_rqst * tk_rqstp; /* RPC request */ - volatile int tk_status; /* result of last operation */ + int tk_status; /* result of last operation */ struct rpc_wait_queue * tk_rpcwait; /* RPC wait queue we're on */ /* @@ -81,8 +81,7 @@ unsigned int tk_lock; /* Task lock counter */ unsigned char tk_active : 1,/* Task has been activated */ tk_wakeup : 1;/* Task waiting to wake up */ - volatile unsigned char tk_running : 1,/* Task is running */ - tk_sleeping : 1;/* Task is truly asleep */ + unsigned int tk_runstate; /* Task run status */ #ifdef RPC_DEBUG unsigned int tk_pid; /* debugging aid */ #endif @@ -112,10 +111,20 @@ #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) -#define RPC_IS_RUNNING(t) ((t)->tk_running) -#define RPC_IS_SLEEPING(t) ((t)->tk_sleeping) #define RPC_IS_ACTIVATED(t) ((t)->tk_active) #define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL) + +#define RPC_TASK_SLEEPING 0 +#define RPC_TASK_RUNNING 1 +#define RPC_IS_SLEEPING(t) (test_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) +#define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) + +#define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) +#define rpc_clear_running(t) (clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) + +#define rpc_set_sleeping(t) (set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) + +#define rpc_clear_sleeping(t) (clear_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) /* * RPC synchronization objects diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/sunrpc/xprt.h linux/include/linux/sunrpc/xprt.h --- v2.2.18/include/linux/sunrpc/xprt.h Sun Mar 25 11:28:39 2001 +++ linux/include/linux/sunrpc/xprt.h Sun Mar 25 11:37:40 2001 @@ -41,12 +41,14 @@ * Come Linux 2.3, we'll handle fragments directly. */ #define RPC_MAXCONG 16 -#define RPC_MAXREQS (RPC_MAXCONG + 1) +#define RPC_MAXREQS (RPC_MAXCONG + 2) #define RPC_CWNDSCALE 256 #define RPC_MAXCWND (RPC_MAXCONG * RPC_CWNDSCALE) #define RPC_INITCWND RPC_CWNDSCALE #define RPCXPRT_CONGESTED(xprt) \ ((xprt)->cong >= (xprt)->cwnd) +#define RPCXPRT_SUPERCONGESTED(xprt) \ + ((xprt)->cwnd < 2*RPC_CWNDSCALE) /* Default timeout values */ #define RPC_MAX_UDP_TIMEOUT (60*HZ) @@ -98,7 +100,7 @@ struct rpc_task * rq_task; /* RPC task data */ __u32 rq_xid; /* request XID */ struct rpc_rqst * rq_next; /* free list */ - volatile unsigned char rq_received : 1;/* receive completed */ + unsigned char rq_received : 1;/* receive completed */ /* * For authentication (e.g. auth_des) @@ -138,10 +140,10 @@ struct rpc_wait_queue pending; /* requests in flight */ struct rpc_wait_queue backlog; /* waiting for slot */ struct rpc_wait_queue reconn; /* waiting for reconnect */ + struct rpc_wait_queue pingwait; /* waiting on ping() */ struct rpc_rqst * free; /* free slots */ struct rpc_rqst slot[RPC_MAXREQS]; - volatile unsigned char connected : 1,/* TCP: connected */ - write_space : 1;/* TCP: can send */ + unsigned int sockstate; /* Socket state */ unsigned char nocong : 1,/* no congestion control */ stream : 1,/* TCP */ shutdown : 1,/* being shut down */ @@ -185,12 +187,14 @@ unsigned long); int xprt_reserve(struct rpc_task *); +int xprt_ping_reserve(struct rpc_task *); int xprt_down_transmit(struct rpc_task *); void xprt_transmit(struct rpc_task *); void xprt_up_transmit(struct rpc_task *); void xprt_receive(struct rpc_task *); int xprt_adjust_timeout(struct rpc_timeout *); void xprt_release(struct rpc_task *); +void xprt_ping_release(struct rpc_task *); void xprt_reconnect(struct rpc_task *); void __rpciod_tcp_dispatcher(void); @@ -209,23 +213,30 @@ __rpciod_tcp_dispatcher(); } -static inline -int xprt_connected(struct rpc_xprt *xprt) -{ - return xprt->connected; -} +#define XPRT_WSPACE 0 +#define XPRT_CONNECT 1 +#define XPRT_PING 2 +#define XPRT_NORESPOND 3 + +#define xprt_wspace(xp) (test_bit(XPRT_WSPACE, &(xp)->sockstate)) +#define xprt_test_and_set_wspace(xp) (test_and_set_bit(XPRT_WSPACE, &(xp)->sockstate)) +#define xprt_clear_wspace(xp) (clear_bit(XPRT_WSPACE, &(xp)->sockstate)) + +#define xprt_connected(xp) (!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) + +#define xprt_pinging(xp) (test_bit(XPRT_PING, &(xp)->sockstate)) +#define xprt_set_pinging(xp) (set_bit(XPRT_PING, &(xp)->sockstate)) +#define xprt_test_and_set_pinging(xp) (test_and_set_bit(XPRT_PING, &(xp)->sockstate)) +#define xprt_clear_pinging(xp) (clear_bit(XPRT_PING, &(xp)->sockstate)) + +#define xprt_norespond(xp) (test_bit(XPRT_NORESPOND, &(xp)->sockstate)) +#define xprt_test_and_set_norespond(xp) (test_and_set_bit(XPRT_NORESPOND, &(xp)->sockstate)) +#define xprt_clear_norespond(xp) (clear_bit(XPRT_NORESPOND, &(xp)->sockstate)) -static inline -void xprt_set_connected(struct rpc_xprt *xprt) -{ - xprt->connected = 1; -} -static inline -void xprt_clear_connected(struct rpc_xprt *xprt) -{ - xprt->connected = 0; -} #endif /* __KERNEL__*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/synclink.h linux/include/linux/synclink.h --- v2.2.18/include/linux/synclink.h Sun Mar 25 11:12:38 2001 +++ linux/include/linux/synclink.h Sun Mar 25 11:37:40 2001 @@ -1,9 +1,9 @@ /* * SyncLink Multiprotocol Serial Adapter Driver * - * ==FILEDATE 19990810== + * $Id: synclink.h,v 2.2 2000/11/08 17:08:30 paul Exp $ * - * Copyright (C) 1998 by Microgate Corporation + * Copyright (C) 1998-2000 by Microgate Corporation * * Redistribution of this file is permitted under * the terms of the GNU Public License (GPL) @@ -11,6 +11,7 @@ #ifndef _SYNCLINK_H_ #define _SYNCLINK_H_ +#define SYNCLINK_H_VERSION 2.2 #define BOOLEAN int #define TRUE 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.2.18/include/linux/sysctl.h Sun Mar 25 11:28:39 2001 +++ linux/include/linux/sysctl.h Sun Mar 25 11:37:40 2001 @@ -30,7 +30,7 @@ struct __sysctl_args { int *name; - int nlen; + unsigned nlen; void *oldval; size_t *oldlenp; void *newval; @@ -465,7 +465,7 @@ typedef struct ctl_table ctl_table; -typedef int ctl_handler (ctl_table *table, int *name, int nlen, +typedef int ctl_handler (ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context); @@ -484,12 +484,12 @@ extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, void *, size_t *); -extern int do_sysctl (int *name, int nlen, +extern int do_sysctl (int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen); extern int do_sysctl_strategy (ctl_table *table, - int *name, int nlen, + int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void ** context); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/tqueue.h linux/include/linux/tqueue.h --- v2.2.18/include/linux/tqueue.h Sun Mar 25 11:12:36 2001 +++ linux/include/linux/tqueue.h Sun Mar 25 11:37:40 2001 @@ -50,6 +50,7 @@ typedef struct tq_struct * task_queue; #define DECLARE_TASK_QUEUE(q) task_queue q = NULL +#define TQ_ACTIVE(q) ((q) != NULL) extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk; @@ -78,19 +79,24 @@ extern spinlock_t tqueue_lock; /* - * queue_task + * Queue a task on a tq. Return non-zero if it was successfully + * added. */ -extern __inline__ void queue_task(struct tq_struct *bh_pointer, +extern __inline__ int queue_task(struct tq_struct *bh_pointer, task_queue *bh_list) { + int ret = 0; if (!test_and_set_bit(0,&bh_pointer->sync)) { unsigned long flags; spin_lock_irqsave(&tqueue_lock, flags); bh_pointer->next = *bh_list; *bh_list = bh_pointer; spin_unlock_irqrestore(&tqueue_lock, flags); + ret = 1; } + return ret; } + /* * Call all "bottom halfs" on a given list. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/usb.h linux/include/linux/usb.h --- v2.2.18/include/linux/usb.h Sun Mar 25 11:28:39 2001 +++ linux/include/linux/usb.h Sun Mar 25 11:37:40 2001 @@ -29,6 +29,7 @@ /* * USB recipients */ +#define USB_RECIP_MASK 0x1f #define USB_RECIP_DEVICE 0x00 #define USB_RECIP_INTERFACE 0x01 #define USB_RECIP_ENDPOINT 0x02 @@ -509,7 +510,7 @@ struct list_head inodes; }; -#define USB_MAXCHILDREN (8) /* This is arbitrary */ +#define USB_MAXCHILDREN (16) /* This is arbitrary */ struct usb_device { int devnum; /* Device number on USB bus */ @@ -554,6 +555,7 @@ }; extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); +extern struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum); extern int usb_register(struct usb_driver *); extern void usb_deregister(struct usb_driver *); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h --- v2.2.18/include/linux/usbdevice_fs.h Sun Mar 25 11:28:39 2001 +++ linux/include/linux/usbdevice_fs.h Sun Mar 25 11:37:40 2001 @@ -80,6 +80,7 @@ #define USBDEVFS_URB_DISABLE_SPD 1 #define USBDEVFS_URB_ISO_ASAP 2 +#define USBDEVFS_URB_QUEUE_BULK 0x10 #define USBDEVFS_URB_TYPE_ISO 0 #define USBDEVFS_URB_TYPE_INTERRUPT 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/wait.h linux/include/linux/wait.h --- v2.2.18/include/linux/wait.h Sun Mar 25 11:28:39 2001 +++ linux/include/linux/wait.h Sun Mar 25 11:37:40 2001 @@ -4,7 +4,8 @@ #define WNOHANG 0x00000001 #define WUNTRACED 0x00000002 -#define __WCLONE 0x80000000 +#define __WALL 0x40000000 /* Wait on all children, regardless of type */ +#define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */ #ifdef __KERNEL__ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/watchdog.h linux/include/linux/watchdog.h --- v2.2.18/include/linux/watchdog.h Sun Mar 25 11:12:37 2001 +++ linux/include/linux/watchdog.h Sun Mar 25 11:37:40 2001 @@ -6,14 +6,17 @@ * */ +#ifndef _LINUX_WATCHDOG_H +#define _LINUX_WATCHDOG_H + #include #define WATCHDOG_IOCTL_BASE 'W' struct watchdog_info { - u32 options; /* Options the card/driver supports */ - u32 firmware_version; /* Firmware version of the card */ - u8 identity[32]; /* Identity of the board */ + __u32 options; /* Options the card/driver supports */ + __u32 firmware_version; /* Firmware version of the card */ + __u8 identity[32]; /* Identity of the board */ }; #define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info) @@ -38,3 +41,5 @@ #define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */ #define WDIOS_ENABLECARD 0x0002 /* Turn on the watchdog timer */ #define WDIOS_TEMPPANIC 0x0004 /* Kernel panic on temperature trip */ + +#endif /* ifndef _LINUX_WATCHDOG_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/linux/wireless.h linux/include/linux/wireless.h --- v2.2.18/include/linux/wireless.h Sun Mar 25 11:12:37 2001 +++ linux/include/linux/wireless.h Sun Mar 25 11:37:40 2001 @@ -63,7 +63,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 9 +#define WIRELESS_EXT 10 /* * Changes : @@ -104,26 +104,33 @@ * - Change encoding to support larger tokens (>64 bits) * - Updated iw_params (disable, flags) and use it for NWID * - Extracted iw_point from iwreq for clarity + * + * V9 to V10 + * --------- + * - Add PM capability to range structure + * - Add PM modifier : MAX/MIN/RELATIVE + * - Add encoding option : IW_ENCODE_NOKEY + * - Add TxPower ioctls (work like TxRate) */ /* -------------------------- IOCTL LIST -------------------------- */ /* Basic operations */ -#define SIOCSIWNAME 0x8B00 /* Unused ??? */ -#define SIOCGIWNAME 0x8B01 /* get name */ +#define SIOCSIWNAME 0x8B00 /* Unused */ +#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ #define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ #define SIOCGIWNWID 0x8B03 /* get network id */ -#define SIOCSIWFREQ 0x8B04 /* set channel/frequency */ -#define SIOCGIWFREQ 0x8B05 /* get channel/frequency */ +#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ +#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ #define SIOCSIWMODE 0x8B06 /* set operation mode */ #define SIOCGIWMODE 0x8B07 /* get operation mode */ -#define SIOCSIWSENS 0x8B08 /* set sensitivity */ -#define SIOCGIWSENS 0x8B09 /* get sensitivity */ +#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ +#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ /* Informative stuff */ -#define SIOCSIWRANGE 0x8B0A /* Unused ??? */ +#define SIOCSIWRANGE 0x8B0A /* Unused */ #define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ -#define SIOCSIWPRIV 0x8B0C /* Unused ??? */ +#define SIOCSIWPRIV 0x8B0C /* Unused */ #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ /* Mobile IP support */ @@ -153,6 +160,8 @@ #define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ #define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ #define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ +#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ +#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ /* Encoding stuff (scrambling, hardware security, WEP...) */ #define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ @@ -205,6 +214,9 @@ /* Maximum bit rates in the range struct */ #define IW_MAX_BITRATES 8 +/* Maximum tx powers in the range struct */ +#define IW_MAX_TXPOWER 8 + /* Maximum of address that you may set with SPY */ #define IW_MAX_SPY 8 @@ -232,11 +244,13 @@ /* Flags for encoding (along with the token) */ #define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ -#define IW_ENCODE_FLAGS 0xF000 /* Flags defined below */ +#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ +#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ #define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ #define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ #define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ #define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ /* Power management flags available (along with the value, if any) */ #define IW_POWER_ON 0x0000 /* No details... */ @@ -249,6 +263,14 @@ #define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ #define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ #define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ +#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ +#define IW_POWER_MIN 0x0001 /* Value is a minimum */ +#define IW_POWER_MAX 0x0002 /* Value is a maximum */ +#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + +/* Transmit Power flags available */ +#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ +#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ /****************************** TYPES ******************************/ @@ -359,6 +381,7 @@ struct iw_param sens; /* signal level threshold */ struct iw_param bitrate; /* default bit rate */ + struct iw_param txpower; /* default transmit power */ struct iw_param rts; /* RTS threshold threshold */ struct iw_param frag; /* Fragmentation threshold */ __u32 mode; /* Operation mode */ @@ -422,15 +445,23 @@ __s32 max_frag; /* Maximal frag threshold */ /* Power Management duration & timeout */ - __s32 min_pmd; /* Minimal PM duration */ - __s32 max_pmd; /* Maximal PM duration */ + __s32 min_pmp; /* Minimal PM period */ + __s32 max_pmp; /* Maximal PM period */ __s32 min_pmt; /* Minimal PM timeout */ __s32 max_pmt; /* Maximal PM timeout */ + __u16 pmp_flags; /* How to decode max/min PM period */ + __u16 pmt_flags; /* How to decode max/min PM timeout */ + __u16 pm_capa; /* What PM options are supported */ /* Encoder stuff */ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ __u8 num_encoding_sizes; /* Number of entry in the list */ __u8 max_encoding_tokens; /* Max number of tokens */ + + /* Transmit power */ + __u16 txpower_capa; /* What options are supported */ + __u8 num_txpower; /* Number of entries in the list */ + __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ }; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/math-emu/op-2.h linux/include/math-emu/op-2.h --- v2.2.18/include/math-emu/op-2.h Sun Mar 25 11:12:44 2001 +++ linux/include/math-emu/op-2.h Sun Mar 25 11:37:40 2001 @@ -79,7 +79,7 @@ else \ { \ X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \ - (((X##_f1 << (sz - (N))) | X##_f0) != 0)); \ + (((X##_f1 << (2*_FP_W_TYPE_SIZE - (N))) | X##_f0) != 0)); \ X##_f1 = 0; \ } \ } while (0) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/net/ip.h linux/include/net/ip.h --- v2.2.18/include/net/ip.h Sun Mar 25 11:28:39 2001 +++ linux/include/net/ip.h Sun Mar 25 11:37:40 2001 @@ -172,7 +172,7 @@ { u16 check = iph->check; check += __constant_htons(0x0100); - iph->check = check + (check>=0xFFFF); + iph->check = check + ((check>=0xFFFF) ? 1 : 0); return --iph->ttl; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/net/ip_masq.h linux/include/net/ip_masq.h --- v2.2.18/include/net/ip_masq.h Sun Mar 25 11:12:41 2001 +++ linux/include/net/ip_masq.h Sun Mar 25 11:37:40 2001 @@ -31,6 +31,32 @@ #define MASQUERADE_EXPIRE_TCP 15*60*HZ #define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ #define MASQUERADE_EXPIRE_UDP 5*60*HZ + +/* + * Debugging stuff + */ + +extern int ip_masq_get_debug_level(void); + +#ifdef CONFIG_IP_MASQ_DEBUG +#define IP_MASQ_DEBUG(level, msg...) do { \ + if (level <= ip_masq_get_debug_level()) \ + printk(KERN_DEBUG "IP_MASQ:" ## msg); \ + } while (0) +#else /* NO DEBUGGING at ALL */ +#define IP_MASQ_DEBUG(level, msg...) do { } while (0) +#endif + +#define IP_MASQ_INFO(msg...) \ + printk(KERN_INFO "IP_MASQ:" ## msg) + +#define IP_MASQ_ERR(msg...) \ + printk(KERN_ERR "IP_MASQ:" ## msg) + +#define IP_MASQ_WARNING(msg...) \ + printk(KERN_WARNING "IP_MASQ:" ## msg) + + /* * ICMP can no longer be modified on the fly using an ioctl - this * define is the only way to change the timeouts @@ -164,7 +190,7 @@ { struct ip_masq_app *next; char *name; /* name of application proxy */ - unsigned type; /* type = proto<<16 | port (host byte order)*/ + unsigned type; /* type = flags | proto<<16 | port (host byte order)*/ int n_attach; int (*masq_init_1) /* ip_masq initializer */ (struct ip_masq_app *, struct ip_masq *); @@ -182,20 +208,60 @@ extern int ip_masq_app_init(void); /* - * ip_masq_app object registration functions (port: host byte order) + * ip_masq_app object registration functions: register_ip_masq_app_type() + * can be used if ip_masq_app has been previously initialized + * (port: host byte order) */ -extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port); +extern int register_ip_masq_app_type(struct ip_masq_app *mapp); +extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned proto, __u16 port); extern int unregister_ip_masq_app(struct ip_masq_app *mapp); /* + * ip_masq_app flags[8bits] (ORed with protocol[8bits] ) + */ +#define IP_MASQ_APP_OUTBOUND 0x01000000 /* dst port matched (in-out) */ +#define IP_MASQ_APP_INBOUND 0x02000000 /* src port matched (in-out) */ +#define IP_MASQ_APP_FWMARK 0x80000000 /* hook by (fwmark & 0xffff) */ +#define IP_MASQ_APP_FLAGS_MASK 0xff000000 /* mask for app flags */ +#define IP_MASQ_APP_PROTO_MASK 0x00ff0000 /* mask for proto value */ +#define IP_MASQ_APP_PORT_MASK 0x0000ffff /* mask for port value */ +#define IP_MASQ_APP_FWMARK_MASK 0x00ffffff /* mask for fwmark value (24bits only) */ + +#define IP_MASQ_APP_TYPE_PP(flags, proto, port) ((flags)|((proto)<<16)|(port)) +#define IP_MASQ_APP_TYPE_FWMARK(flags, fwmark) ((flags)|(fwmark&0x00ffffff)) +#define IP_MASQ_APP_TYPE2PORT(type) ( (type) & 0xffff ) +#define IP_MASQ_APP_TYPE2PROTO(type) ( ((type)>>16) & 0x00ff ) +#define IP_MASQ_APP_TYPE2FWMARK(type) ( (type) & 0x00ffffff ) +#define IP_MASQ_APP_TYPE2FLAGS(type) ( (type) & 0xff000000 ) + +/* Init functions for later register_ip_masq_app_type() */ +static __inline__ int ip_masq_app_init_proto_port(struct ip_masq_app* mapp, unsigned flags, unsigned proto, unsigned port) { + mapp->type = IP_MASQ_APP_TYPE_PP(flags, proto, port); + return 0; +} +static __inline__ int ip_masq_app_init_fwmark(struct ip_masq_app* mapp, unsigned flags, __u32 fwmark) { + if (fwmark&~(IP_MASQ_APP_FWMARK_MASK)) { + IP_MASQ_ERR("ip_masq_app_init_fwmark(): fwmark must be <= %d, sorry (shoot Juanjo)\n", IP_MASQ_APP_FWMARK_MASK); + return -EINVAL; + } + mapp->type = IP_MASQ_APP_TYPE_FWMARK(flags, fwmark); + return 0; +} + +/* * get ip_masq_app obj by proto,port(net_byte_order) */ -extern struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port); +extern struct ip_masq_app * ip_masq_app_get_type(unsigned type); +static __inline__ struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port) { + unsigned type = IP_MASQ_APP_TYPE_PP(0, proto, port); + return ip_masq_app_get_type(type); +} /* * ip_masq TO ip_masq_app (un)binding functions. */ extern struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms); +extern struct ip_masq_app * ip_masq_bind_app_fwmark(struct ip_masq *ms, __u32); extern int ip_masq_unbind_app(struct ip_masq *ms); /* @@ -253,31 +319,6 @@ /* * */ - -/* - * Debugging stuff - */ - -extern int ip_masq_get_debug_level(void); - -#ifdef CONFIG_IP_MASQ_DEBUG -#define IP_MASQ_DEBUG(level, msg...) do { \ - if (level <= ip_masq_get_debug_level()) \ - printk(KERN_DEBUG "IP_MASQ:" ## msg); \ - } while (0) -#else /* NO DEBUGGING at ALL */ -#define IP_MASQ_DEBUG(level, msg...) do { } while (0) -#endif - -#define IP_MASQ_INFO(msg...) \ - printk(KERN_INFO "IP_MASQ:" ## msg) - -#define IP_MASQ_ERR(msg...) \ - printk(KERN_ERR "IP_MASQ:" ## msg) - -#define IP_MASQ_WARNING(msg...) \ - printk(KERN_WARNING "IP_MASQ:" ## msg) - /* * /proc/net entry diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/include/scsi/scsi.h linux/include/scsi/scsi.h --- v2.2.18/include/scsi/scsi.h Sun Mar 25 11:28:39 2001 +++ linux/include/scsi/scsi.h Sun Mar 25 11:37:40 2001 @@ -208,6 +208,9 @@ /* Used to get Fibre Channel WWN and port_id from device */ #define SCSI_IOCTL_FC_TARGET_ADDRESS 0x5387 +/* Used to invoke Target Defice Reset for Fibre Channel */ +#define SCSI_IOCTL_FC_TDR 0x5388 + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/init/main.c linux/init/main.c --- v2.2.18/init/main.c Sun Mar 25 11:28:39 2001 +++ linux/init/main.c Sun Mar 25 11:37:40 2001 @@ -80,7 +80,6 @@ extern int bdflush(void *); extern int kupdate(void *); extern int kswapd(void *); -extern int kpiod(void *); extern void kswapd_setup(void); extern unsigned long init_IRQ( unsigned long); extern void init_modules(void); @@ -204,9 +203,6 @@ #ifdef CONFIG_MDISK extern void mdisk_setup(char *str, int *ints); #endif -#ifdef CONFIG_DASD -extern void dasd_setup(char *str, int *ints); -#endif #ifdef CONFIG_BLK_DEV_XPRAM extern void xpram_setup(char *str, int *ints); #endif @@ -216,6 +212,7 @@ #endif extern void floppy_setup(char *str, int *ints); extern void st_setup(char *str, int *ints); +extern void osst_setup(char *str, int *ints); extern void st0x_setup(char *str, int *ints); extern void advansys_setup(char *str, int *ints); extern void tmc8xx_setup(char *str, int *ints); @@ -624,22 +621,22 @@ { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) }, { "dasdi", (DASD_MAJOR << MINORBITS) + (8 << 2) }, { "dasdj", (DASD_MAJOR << MINORBITS) + (9 << 2) }, - { "dasdk", (DASD_MAJOR << MINORBITS) + (11 << 2) }, - { "dasdl", (DASD_MAJOR << MINORBITS) + (12 << 2) }, - { "dasdm", (DASD_MAJOR << MINORBITS) + (13 << 2) }, - { "dasdn", (DASD_MAJOR << MINORBITS) + (14 << 2) }, - { "dasdo", (DASD_MAJOR << MINORBITS) + (15 << 2) }, - { "dasdp", (DASD_MAJOR << MINORBITS) + (16 << 2) }, - { "dasdq", (DASD_MAJOR << MINORBITS) + (17 << 2) }, - { "dasdr", (DASD_MAJOR << MINORBITS) + (18 << 2) }, - { "dasds", (DASD_MAJOR << MINORBITS) + (19 << 2) }, - { "dasdt", (DASD_MAJOR << MINORBITS) + (20 << 2) }, - { "dasdu", (DASD_MAJOR << MINORBITS) + (21 << 2) }, - { "dasdv", (DASD_MAJOR << MINORBITS) + (22 << 2) }, - { "dasdw", (DASD_MAJOR << MINORBITS) + (23 << 2) }, - { "dasdx", (DASD_MAJOR << MINORBITS) + (24 << 2) }, - { "dasdy", (DASD_MAJOR << MINORBITS) + (25 << 2) }, - { "dasdz", (DASD_MAJOR << MINORBITS) + (26 << 2) }, + { "dasdk", (DASD_MAJOR << MINORBITS) + (10 << 2) }, + { "dasdl", (DASD_MAJOR << MINORBITS) + (11 << 2) }, + { "dasdm", (DASD_MAJOR << MINORBITS) + (12 << 2) }, + { "dasdn", (DASD_MAJOR << MINORBITS) + (13 << 2) }, + { "dasdo", (DASD_MAJOR << MINORBITS) + (14 << 2) }, + { "dasdp", (DASD_MAJOR << MINORBITS) + (15 << 2) }, + { "dasdq", (DASD_MAJOR << MINORBITS) + (16 << 2) }, + { "dasdr", (DASD_MAJOR << MINORBITS) + (17 << 2) }, + { "dasds", (DASD_MAJOR << MINORBITS) + (18 << 2) }, + { "dasdt", (DASD_MAJOR << MINORBITS) + (19 << 2) }, + { "dasdu", (DASD_MAJOR << MINORBITS) + (20 << 2) }, + { "dasdv", (DASD_MAJOR << MINORBITS) + (21 << 2) }, + { "dasdw", (DASD_MAJOR << MINORBITS) + (22 << 2) }, + { "dasdx", (DASD_MAJOR << MINORBITS) + (23 << 2) }, + { "dasdy", (DASD_MAJOR << MINORBITS) + (24 << 2) }, + { "dasdz", (DASD_MAJOR << MINORBITS) + (25 << 2) }, #endif #ifdef CONFIG_BLK_DEV_XPRAM { "xpram0", (XPRAM_MAJOR << MINORBITS) }, @@ -841,6 +838,9 @@ #ifdef CONFIG_CHR_DEV_ST { "st=", st_setup }, #endif +#ifdef CONFIG_CHR_DEV_OSST + { "osst=", osst_setup }, +#endif #ifdef CONFIG_BUSMOUSE { "bmouse=", bmouse_setup }, #endif @@ -1108,9 +1108,6 @@ #ifdef CONFIG_MDISK { "mdisk=", mdisk_setup }, #endif -#ifdef CONFIG_DASD - { "dasd=", dasd_setup }, -#endif #ifdef CONFIG_BLK_DEV_XPRAM { "xpram_parts=", xpram_setup }, #endif @@ -1580,7 +1577,6 @@ kernel_thread(kupdate, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); /* Start the background pageout daemon. */ kswapd_setup(); - kernel_thread(kpiod, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); #if CONFIG_AP1000 @@ -1598,6 +1594,9 @@ if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; else mount_initrd =0; #endif + + /* Start the event daemon thread */ + start_context_thread(); /* Set up devices .. */ device_setup(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/ipc/shm.c linux/ipc/shm.c --- v2.2.18/ipc/shm.c Sun Mar 25 11:12:49 2001 +++ linux/ipc/shm.c Sun Mar 25 11:37:40 2001 @@ -337,6 +337,8 @@ if (current->euid == shp->u.shm_perm.uid || current->euid == shp->u.shm_perm.cuid || capable(CAP_SYS_ADMIN)) { + /* Do not find it any more */ + shp->u.shm_perm.key = IPC_PRIVATE; shp->u.shm_perm.mode |= SHM_DEST; if (shp->u.shm_nattch <= 0) killseg (id); @@ -679,7 +681,7 @@ } /* - * Goes through counter = (shm_rss >> prio) present shm pages. + * Goes through counter = (shm_rss / prio) present shm pages. */ static unsigned long swap_id = 0; /* currently being swapped */ static unsigned long swap_idx = 0; /* next to swap */ @@ -693,7 +695,7 @@ int loop = 0; int counter; - counter = shm_rss >> prio; + counter = shm_rss / prio; if (!counter || !(swap_nr = get_swap_page())) return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/Makefile linux/kernel/Makefile --- v2.2.18/kernel/Makefile Sun Mar 25 11:12:36 2001 +++ linux/kernel/Makefile Sun Mar 25 11:37:40 2001 @@ -15,7 +15,7 @@ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ sysctl.o acct.o capability.o -OX_OBJS += signal.o +OX_OBJS += context.o signal.o ifeq ($(CONFIG_KMOD),y) O_OBJS += kmod.o diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/context.c linux/kernel/context.c --- v2.2.18/kernel/context.c Wed Dec 31 19:00:00 1969 +++ linux/kernel/context.c Sun Mar 25 11:37:40 2001 @@ -0,0 +1,157 @@ +/* + * linux/kernel/context.c + * + * Mechanism for running arbitrary tasks in process context + * + * dwmw2@redhat.com: Genesis + * + * andrewm@uow.edu.au: 2.4.0-test12 + * - Child reaping + * - Support for tasks which re-add themselves + * - flush_scheduled_tasks. + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include + +static DECLARE_TASK_QUEUE(tq_context); +static DECLARE_WAIT_QUEUE_HEAD(context_task_wq); +static DECLARE_WAIT_QUEUE_HEAD(context_task_done); +static int keventd_running; +static struct task_struct *keventd_task; + +static int need_keventd(const char *who) +{ + if (keventd_running == 0) + printk(KERN_ERR "%s(): keventd has not started\n", who); + return keventd_running; +} + +int current_is_keventd(void) +{ + int ret = 0; + if (need_keventd(__FUNCTION__)) + ret = (current == keventd_task); + return ret; +} + +/** + * schedule_task - schedule a function for subsequent execution in process context. + * @task: pointer to a &tq_struct which defines the function to be scheduled. + * + * May be called from interrupt context. The scheduled function is run at some + * time in the near future by the keventd kernel thread. If it can sleep, it + * should be designed to do so for the minimum possible time, as it will be + * stalling all other scheduled tasks. + * + * schedule_task() returns non-zero if the task was successfully scheduled. + * If @task is already residing on a task queue then schedule_task() fails + * to schedule your task and returns zero. + */ +int schedule_task(struct tq_struct *task) +{ + int ret; + need_keventd(__FUNCTION__); + ret = queue_task(task, &tq_context); + wake_up(&context_task_wq); + return ret; +} + +static int context_thread(void *dummy) +{ + struct task_struct *curtask = current; + DECLARE_WAITQUEUE(wait, curtask); + struct k_sigaction sa; + + daemonize(); + strcpy(curtask->comm, "keventd"); + keventd_running = 1; + keventd_task = curtask; + + spin_lock_irq(&curtask->sigmask_lock); + siginitsetinv(&curtask->blocked, sigmask(SIGCHLD)); + recalc_sigpending(curtask); + spin_unlock_irq(&curtask->sigmask_lock); + + /* Install a handler so SIGCLD is delivered */ + sa.sa.sa_handler = SIG_IGN; + sa.sa.sa_flags = 0; + siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD)); + do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0); + + /* + * If one of the functions on a task queue re-adds itself + * to the task queue we call schedule() in state TASK_RUNNING + */ + for (;;) { + set_task_state(curtask, TASK_INTERRUPTIBLE); + add_wait_queue(&context_task_wq, &wait); + if (TQ_ACTIVE(tq_context)) + set_task_state(curtask, TASK_RUNNING); + schedule(); + remove_wait_queue(&context_task_wq, &wait); + run_task_queue(&tq_context); + wake_up(&context_task_done); + if (signal_pending(curtask)) { + while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0) + ; + flush_signals(curtask); + recalc_sigpending(curtask); + } + } +} + +/** + * flush_scheduled_tasks - ensure that any scheduled tasks have run to completion. + * + * Forces execution of the schedule_task() queue and blocks until its completion. + * + * If a kernel subsystem uses schedule_task() and wishes to flush any pending + * tasks, it should use this function. This is typically used in driver shutdown + * handlers. + * + * The caller should hold no spinlocks and should hold no semaphores which could + * cause the scheduled tasks to block. + */ +static struct tq_struct dummy_task; + +void flush_scheduled_tasks(void) +{ + int count; + DECLARE_WAITQUEUE(wait, current); + + /* + * Do it twice. It's possible, albeit highly unlikely, that + * the caller queued a task immediately before calling us, + * and that the eventd thread was already past the run_task_queue() + * but not yet into wake_up(), so it woke us up before completing + * the caller's queued task or our new dummy task. + */ + add_wait_queue(&context_task_done, &wait); + for (count = 0; count < 2; count++) { + set_current_state(TASK_UNINTERRUPTIBLE); + + /* Queue a dummy task to make sure we get kicked */ + schedule_task(&dummy_task); + + /* Wait for it to complete */ + schedule(); + } + remove_wait_queue(&context_task_done, &wait); +} + +int start_context_thread(void) +{ + kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES); + return 0; +} + +EXPORT_SYMBOL(schedule_task); +EXPORT_SYMBOL(flush_scheduled_tasks); + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/exit.c linux/kernel/exit.c --- v2.2.18/kernel/exit.c Sun Mar 25 11:12:36 2001 +++ linux/kernel/exit.c Sun Mar 25 11:37:40 2001 @@ -437,7 +437,7 @@ struct wait_queue wait = { current, NULL }; struct task_struct *p; - if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) + if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL)) return -EINVAL; add_wait_queue(¤t->wait_chldexit,&wait); @@ -462,8 +462,13 @@ if (p->pgrp != -pid) continue; } - /* wait for cloned processes iff the __WCLONE flag is set */ - if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) + /* Wait for all children (clone and not) if __WALL is set; + * otherwise, wait for clone children *only* if __WCLONE is + * set; otherwise, wait for non-clone children *only*. (Note: + * A "clone" child here is one that reports to its parent + * using a signal other than SIGCHLD.) */ + if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) + && !(options & __WALL)) continue; flag = 1; switch (p->state) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/fork.c linux/kernel/fork.c --- v2.2.18/kernel/fork.c Sun Mar 25 11:12:36 2001 +++ linux/kernel/fork.c Sun Mar 25 11:37:40 2001 @@ -665,6 +665,8 @@ p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; + INIT_LIST_HEAD(&p->local_pages); + retval = -ENOMEM; /* copy all the process information */ if (copy_files(clone_flags, p)) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/sched.c linux/kernel/sched.c --- v2.2.18/kernel/sched.c Sun Mar 25 11:28:39 2001 +++ linux/kernel/sched.c Sun Mar 25 11:37:40 2001 @@ -890,8 +890,9 @@ */ void __wake_up(struct wait_queue **q, unsigned int mode) { - struct task_struct *p; + struct task_struct *p, *best_exclusive; struct wait_queue *head, *next; + unsigned int do_exclusive; if (!q) goto out; @@ -906,22 +907,23 @@ if (!next) goto out_unlock; + best_exclusive = 0; + do_exclusive = mode & TASK_EXCLUSIVE; while (next != head) { p = next->task; next = next->next; if (p->state & mode) { - /* - * We can drop the read-lock early if this - * is the only/last process. - */ - if (next == head) { - read_unlock(&waitqueue_lock); + if (do_exclusive && p->task_exclusive) { + if (best_exclusive == NULL) + best_exclusive = p; + } + else { wake_up_process(p); - goto out; } - wake_up_process(p); } } + if (best_exclusive) + wake_up_process(best_exclusive); out_unlock: read_unlock(&waitqueue_lock); out: @@ -1943,7 +1945,7 @@ delay=(t.tv_nsec + 999) / 1000; if(delay>10000) - mdelay(delay); + mdelay((delay+999)/1000); else udelay(delay); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/signal.c linux/kernel/signal.c --- v2.2.18/kernel/signal.c Sun Mar 25 11:12:36 2001 +++ linux/kernel/signal.c Sun Mar 25 11:37:40 2001 @@ -820,7 +820,7 @@ /* Not even root can pretend to send signals from the kernel. Nor can they impersonate a kill(), which adds source info. */ - if (info.si_code >= 0) + if (SI_FROMKERNEL(&info)) return -EPERM; info.si_signo = sig; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/sys.c linux/kernel/sys.c --- v2.2.18/kernel/sys.c Sun Mar 25 11:28:39 2001 +++ linux/kernel/sys.c Sun Mar 25 11:37:40 2001 @@ -381,14 +381,19 @@ else return -EPERM; } + + lock_kernel(); + if (euid != (uid_t) -1) { if ((old_ruid == euid) || (current->euid == euid) || (current->suid == euid) || capable(CAP_SETUID)) current->fsuid = current->euid = euid; - else + else { + unlock_kernel(); return -EPERM; + } } if (ruid != (uid_t) -1 || (euid != (uid_t) -1 && euid != old_ruid)) @@ -407,6 +412,8 @@ current->uid = new_ruid; alloc_uid(current); } + + unlock_kernel(); if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); @@ -433,14 +440,18 @@ int old_euid = current->euid; int old_ruid, old_suid, new_ruid; + lock_kernel(); + old_ruid = new_ruid = current->uid; old_suid = current->suid; if (capable(CAP_SETUID)) new_ruid = current->euid = current->suid = current->fsuid = uid; else if ((uid == current->uid) || (uid == current->suid)) current->fsuid = current->euid = uid; - else + else { + unlock_kernel(); return -EPERM; + } if (current->euid != old_euid) current->dumpable = 0; @@ -452,6 +463,8 @@ alloc_uid(current); } + unlock_kernel(); + if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } @@ -481,6 +494,9 @@ (suid != current->euid) && (suid != current->suid)) return -EPERM; } + + lock_kernel(); + if (ruid != (uid_t) -1) { /* See above commentary about NPROC rlimit issues here. */ free_uid(current); @@ -496,6 +512,8 @@ if (suid != (uid_t) -1) current->suid = suid; + unlock_kernel(); + if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } @@ -565,6 +583,8 @@ { int old_fsuid; + lock_kernel(); + old_fsuid = current->fsuid; if (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || @@ -572,6 +592,8 @@ current->fsuid = uid; if (current->fsuid != old_fsuid) current->dumpable = 0; + + unlock_kernel(); /* We emulate fsuid by essentially doing a scaled-down version * of what we did in setresuid and friends. However, we only diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/kernel/sysctl.c linux/kernel/sysctl.c --- v2.2.18/kernel/sysctl.c Sun Mar 25 11:28:39 2001 +++ linux/kernel/sysctl.c Sun Mar 25 11:37:40 2001 @@ -77,7 +77,7 @@ extern int pgt_cache_water[]; -static int parse_table(int *, int, void *, size_t *, void *, size_t, +static int parse_table(int *, unsigned, void *, size_t *, void *, size_t, ctl_table *, void **); static int proc_doutsstring(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp); @@ -286,9 +286,9 @@ 0444, NULL, &proc_dointvec}, {FS_MAXINODE, "inode-max", &max_inodes, sizeof(int), 0644, NULL, &proc_dointvec}, - {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int), + {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_MAXFILE, "file-max", &max_files, sizeof(int), + {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int), 0644, NULL, &proc_dointvec}, {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int), 0444, NULL, &proc_dointvec}, @@ -320,7 +320,7 @@ } -int do_sysctl (int *name, int nlen, +int do_sysctl (int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen) { @@ -330,10 +330,12 @@ if (nlen == 0 || nlen >= CTL_MAXNAME) return -ENOTDIR; - - if (oldval) - { - int old_len; + + if ((ssize_t)newlen < 0) + return -EINVAL; + + if (oldval) { + size_t old_len; if (!oldlenp) return -EFAULT; if(get_user(old_len, oldlenp)) @@ -387,7 +389,7 @@ return test_perm(table->mode, op); } -static int parse_table(int *name, int nlen, +static int parse_table(int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, ctl_table *table, void **context) @@ -430,11 +432,12 @@ /* Perform the actual read/write of a sysctl table entry. */ int do_sysctl_strategy (ctl_table *table, - int *name, int nlen, + int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { - int op = 0, rc, len; + int op = 0, rc; + size_t len; if (oldval) op |= 004; @@ -642,7 +645,7 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { - int len; + size_t len; char *p, c; if (!table->data || !table->maxlen || !*lenp || @@ -710,7 +713,8 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp, int conv, int op) { - int *i, vleft, first=1, len, left, neg, val; + int *i, neg, val; + size_t len, left, vleft, first=1; #define TMPBUFLEN 20 char buf[TMPBUFLEN], *p; @@ -832,7 +836,8 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { - int *i, *min, *max, vleft, first=1, len, left, neg, val; + int *i, *min, *max, neg, val; + size_t len, left, vleft, first=1; #define TMPBUFLEN 20 char buf[TMPBUFLEN], *p; @@ -974,11 +979,12 @@ */ /* The generic string strategy routine: */ -int sysctl_string(ctl_table *table, int *name, int nlen, +int sysctl_string(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { - int l, len; + unsigned l; + size_t len; if (!table->data || !table->maxlen) return -ENOTDIR; @@ -1017,11 +1023,12 @@ * are between the minimum and maximum values given in the arrays * table->extra1 and table->extra2, respectively. */ -int sysctl_intvec(ctl_table *table, int *name, int nlen, +int sysctl_intvec(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { - int i, length, *vec, *min, *max; + int *vec, *min, *max; + size_t i, length; if (newval && newlen) { if (newlen % sizeof(int) != 0) @@ -1051,7 +1058,7 @@ } /* Strategy function to convert jiffies to seconds */ -int sysctl_jiffies(ctl_table *table, int *name, int nlen, +int sysctl_jiffies(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { @@ -1159,21 +1166,21 @@ return -ENOSYS; } -int sysctl_string(ctl_table *table, int *name, int nlen, +int sysctl_string(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { return -ENOSYS; } -int sysctl_intvec(ctl_table *table, int *name, int nlen, +int sysctl_intvec(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { return -ENOSYS; } -int sysctl_jiffies(ctl_table *table, int *name, int nlen, +int sysctl_jiffies(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/mm/filemap.c linux/mm/filemap.c --- v2.2.18/mm/filemap.c Sun Mar 25 11:28:39 2001 +++ linux/mm/filemap.c Sun Mar 25 11:37:40 2001 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -36,25 +35,6 @@ unsigned int page_hash_bits, page_hash_mask; struct page **page_hash_table; -/* - * Define a request structure for outstanding page write requests - * to the background page io daemon - */ - -struct pio_request -{ - struct pio_request * next; - struct file * file; - unsigned long offset; - unsigned long page; -}; -static struct pio_request *pio_first = NULL, **pio_last = &pio_first; -static kmem_cache_t *pio_request_cache; -static struct wait_queue *pio_wait = NULL; - -static inline void -make_pio_request(struct file *, unsigned long, unsigned long); - static inline int sync_page(struct page *page) { struct inode *inode = page->inode; @@ -150,16 +130,21 @@ unsigned long limit = num_physpages; struct page * page; int count; - int nr_dirty = 0; - + /* Make sure we scan all pages twice at priority 0. */ - count = (limit << 1) >> priority; + count = limit / priority; refresh_clock: page = mem_map + clock; do { int referenced; + if (current->need_resched) { + current->state = TASK_RUNNING; + schedule(); + goto refresh_clock; + } + /* This works even in the presence of PageSkip because * the first two entries at the beginning of a hole will * be marked, not just the first. @@ -176,6 +161,8 @@ clock = page - mem_map; } + count--; + /* We can't free pages unless there's just one user */ if (atomic_read(&page->count) != 1) continue; @@ -185,8 +172,10 @@ if (PageLocked(page)) continue; - if ((gfp_mask & __GFP_DMA) && !PageDMA(page)) + if ((gfp_mask & __GFP_DMA) && !PageDMA(page)) { + count++; continue; + } /* * Is it a page swap page? If so, we want to @@ -205,14 +194,6 @@ /* Is it a buffer page? */ if (page->buffers) { - /* - * Wait for async IO to complete - * at each 64 buffers - */ - - int wait = ((gfp_mask & __GFP_IO) - && (!(nr_dirty++ % 64))); - if (buffer_under_min()) continue; /* @@ -220,10 +201,8 @@ * throttling. */ - if (!try_to_free_buffers(page, wait)) { - if(--count < 0) break; + if (!try_to_free_buffers(page, gfp_mask)) goto refresh_clock; - } return 1; } @@ -234,8 +213,7 @@ remove_inode_page(page); return 1; } - - } while (--count > 0); + } while (count > 0); return 0; } @@ -276,7 +254,8 @@ if (page) { char *dest = (char*) (offset + page_address(page)); - if ((unsigned long)dest != source_address) { + if ((unsigned long)dest != source_address + || !segment_eq(get_fs(), KERNEL_DS)) { wait_on_page(page); memcpy(dest, buf, len); flush_dcache_page(page_address(page)); @@ -302,7 +281,7 @@ struct page **hash) { atomic_inc(&page->count); - page->flags = (page->flags & ~((1 << PG_uptodate) | (1 << PG_error))) | (1 << PG_referenced); + page->flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced)); page->offset = offset; add_page_to_inode_queue(inode, page); __add_page_to_hash_queue(page, hash); @@ -881,12 +860,12 @@ if (size > count) size = count; - down(&inode->i_sem); + fs_down(&inode->i_sem); old_fs = get_fs(); set_fs(KERNEL_DS); written = file->f_op->write(file, area, size, &file->f_pos); set_fs(old_fs); - up(&inode->i_sem); + fs_up(&inode->i_sem); if (written < 0) { desc->error = written; written = 0; @@ -1163,8 +1142,7 @@ static int filemap_write_page(struct vm_area_struct * vma, unsigned long offset, - unsigned long page, - int wait) + unsigned long page) { int result; struct file * file; @@ -1182,20 +1160,9 @@ * and file could be released ... increment the count to be safe. */ file->f_count++; - - /* - * If this is a swapping operation rather than msync(), then - * leave the actual IO, and the restoration of the file count, - * to the kpiod thread. Just queue the request for now. - */ - if (!wait) { - make_pio_request(file, offset, page); - return 0; - } - - down(&inode->i_sem); + fs_down(&inode->i_sem); result = do_write_page(inode, file, (const char *) page, offset); - up(&inode->i_sem); + fs_up(&inode->i_sem); fput(file); return result; } @@ -1208,7 +1175,7 @@ */ int filemap_swapout(struct vm_area_struct * vma, struct page * page) { - return filemap_write_page(vma, page->offset, page_address(page), 0); + return filemap_write_page(vma, page->offset, page_address(page)); } static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma, @@ -1245,7 +1212,7 @@ return 0; } } - error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page, 1); + error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page); page_cache_free(page); return error; } @@ -1417,9 +1384,9 @@ if (file) { struct dentry * dentry = file->f_dentry; struct inode * inode = dentry->d_inode; - down(&inode->i_sem); + fs_down(&inode->i_sem); error = file_fsync(file, dentry); - up(&inode->i_sem); + fs_up(&inode->i_sem); } } return error; @@ -1746,130 +1713,6 @@ clear_bit(PG_locked, &page->flags); wake_up(&page->wait); page_cache_release(page); -} - - -/* Add request for page IO to the queue */ - -static inline void put_pio_request(struct pio_request *p) -{ - *pio_last = p; - p->next = NULL; - pio_last = &p->next; -} - -/* Take the first page IO request off the queue */ - -static inline struct pio_request * get_pio_request(void) -{ - struct pio_request * p = pio_first; - pio_first = p->next; - if (!pio_first) - pio_last = &pio_first; - return p; -} - -/* Make a new page IO request and queue it to the kpiod thread */ - -static inline void make_pio_request(struct file *file, - unsigned long offset, - unsigned long page) -{ - struct pio_request *p; - - atomic_inc(&page_cache_entry(page)->count); - - /* - * We need to allocate without causing any recursive IO in the - * current thread's context. We might currently be swapping out - * as a result of an allocation made while holding a critical - * filesystem lock. To avoid deadlock, we *MUST* not reenter - * the filesystem in this thread. - * - * We can wait for kswapd to free memory, or we can try to free - * pages without actually performing further IO, without fear of - * deadlock. --sct - */ - - while ((p = kmem_cache_alloc(pio_request_cache, GFP_BUFFER)) == NULL) { - if (try_to_free_pages(__GFP_WAIT)) - continue; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - } - - p->file = file; - p->offset = offset; - p->page = page; - - put_pio_request(p); - wake_up(&pio_wait); -} - - -/* - * This is the only thread which is allowed to write out filemap pages - * while swapping. - * - * To avoid deadlock, it is important that we never reenter this thread. - * Although recursive memory allocations within this thread may result - * in more page swapping, that swapping will always be done by queuing - * another IO request to the same thread: we will never actually start - * that IO request until we have finished with the current one, and so - * we will not deadlock. - */ - -int kpiod(void * unused) -{ - struct task_struct *tsk = current; - struct wait_queue wait = { tsk, }; - struct inode * inode; - struct dentry * dentry; - struct pio_request * p; - - tsk->session = 1; - tsk->pgrp = 1; - strcpy(tsk->comm, "kpiod"); - sigfillset(&tsk->blocked); - init_waitqueue(&pio_wait); - /* - * Mark this task as a memory allocator - we don't want to get caught - * up in the regular mm freeing frenzy if we have to allocate memory - * in order to write stuff out. - */ - tsk->flags |= PF_MEMALLOC; - - lock_kernel(); - - pio_request_cache = kmem_cache_create("pio_request", - sizeof(struct pio_request), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (!pio_request_cache) - panic ("Could not create pio_request slab cache"); - - while (1) { - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue(&pio_wait, &wait); - if (!pio_first) - schedule(); - remove_wait_queue(&pio_wait, &wait); - tsk->state = TASK_RUNNING; - - while (pio_first) { - p = get_pio_request(); - dentry = p->file->f_dentry; - inode = dentry->d_inode; - - down(&inode->i_sem); - do_write_page(inode, p->file, - (const char *) p->page, p->offset); - up(&inode->i_sem); - fput(p->file); - page_cache_free(p->page); - kmem_cache_free(pio_request_cache, p); - } - } } void __init page_cache_init(unsigned long memory_size) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/mm/memory.c linux/mm/memory.c --- v2.2.18/mm/memory.c Sun Mar 25 11:28:39 2001 +++ linux/mm/memory.c Sun Mar 25 11:37:41 2001 @@ -935,6 +935,7 @@ pte_t * pte; int ret; + current->state = TASK_RUNNING; pgd = pgd_offset(vma->vm_mm, address); pmd = pmd_alloc(pgd, address); if (!pmd) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/mm/page_alloc.c linux/mm/page_alloc.c --- v2.2.18/mm/page_alloc.c Sun Mar 25 11:12:36 2001 +++ linux/mm/page_alloc.c Sun Mar 25 11:37:41 2001 @@ -93,34 +93,69 @@ */ spinlock_t page_alloc_lock = SPIN_LOCK_UNLOCKED; +#define list(x) (mem_map+(x)) +#define __free_pages_ok(map_nr, mask, area, index) \ + nr_free_pages -= (mask); \ + while ((mask) + (1 << (NR_MEM_LISTS-1))) { \ + if (!test_and_change_bit((index), (area)->map)) \ + break; \ + (area)->count--; \ + remove_mem_queue(list((map_nr) ^ -(mask))); \ + (mask) <<= 1; \ + (area)++; \ + (index) >>= 1; \ + (map_nr) &= (mask); \ + } \ + add_mem_queue(area, list(map_nr)); + +static void free_local_pages(struct page * page) { + unsigned long order = page->offset; + unsigned int type = PageDMA(page) ? 1 : 0; + struct free_area_struct *area; + unsigned long map_nr = page - mem_map; + unsigned long mask = (~0UL) << order; + unsigned long index = map_nr >> (1 + order); + + area = free_area[type] + order; + __free_pages_ok(map_nr, mask, area, index); +} + static inline void free_pages_ok(unsigned long map_nr, unsigned long order, unsigned type) { - struct free_area_struct *area = free_area[type] + order; - unsigned long index = map_nr >> (1 + order); - unsigned long mask = (~0UL) << order; + struct free_area_struct *area; + unsigned long index; + unsigned long mask; unsigned long flags; + struct page * page; - spin_lock_irqsave(&page_alloc_lock, flags); - -#define list(x) (mem_map+(x)) + if (current->flags & PF_FREE_PAGES) + goto local_freelist; + back_local_freelist: + index = map_nr >> (1 + order); + mask = (~0UL) << order; map_nr &= mask; - nr_free_pages -= mask; - while (mask + (1 << (NR_MEM_LISTS-1))) { - if (!test_and_change_bit(index, area->map)) - break; - area->count--; - remove_mem_queue(list(map_nr ^ -mask)); - mask <<= 1; - area++; - index >>= 1; - map_nr &= mask; - } - add_mem_queue(area, list(map_nr)); - -#undef list + spin_lock_irqsave(&page_alloc_lock, flags); + area = free_area[type] + order; + __free_pages_ok(map_nr, mask, area, index); spin_unlock_irqrestore(&page_alloc_lock, flags); + return; + + local_freelist: + /* + * This is a little subtle: if the allocation order + * wanted is major than zero we'd better take all the pages + * local since we must deal with fragmentation too and we + * can't rely on the nr_local_pages information. + */ + if (current->nr_local_pages && !current->allocation_order) + goto back_local_freelist; + + page = mem_map + map_nr; + list_add((struct list_head *) page, ¤t->local_pages); + page->offset = order; + current->nr_local_pages++; } void __free_pages(struct page *page, unsigned long order) @@ -179,13 +214,32 @@ atomic_set(&map->count, 1); \ } while (0) +static void refile_local_pages(void) +{ + if (current->nr_local_pages) { + struct page * page; + struct list_head * entry; + int nr_pages = current->nr_local_pages; + + while ((entry = current->local_pages.next) != ¤t->local_pages) { + list_del(entry); + page = (struct page *) entry; + free_local_pages(page); + if (!nr_pages--) + panic("__get_free_pages local_pages list corrupted I"); + } + if (nr_pages) + panic("__get_free_pages local_pages list corrupted II"); + current->nr_local_pages = 0; + } +} + unsigned long __get_free_pages(int gfp_mask, unsigned long order) { unsigned long flags; - static atomic_t free_before_allocate = ATOMIC_INIT(0); if (order >= NR_MEM_LISTS) - goto nopage; + goto out; #ifdef ATOMIC_MEMORY_DEBUGGING if ((gfp_mask & __GFP_WAIT) && in_interrupt()) { @@ -194,26 +248,24 @@ printk("gfp called nonatomically from interrupt %p\n", __builtin_return_address(0)); } - goto nopage; + goto out; } #endif /* + * Acquire lock before reading nr_free_pages to make sure it + * won't change from under us. + */ + spin_lock_irqsave(&page_alloc_lock, flags); + + /* * If this is a recursive call, we'd better * do our best to just allocate things without * further thought. */ if (!(current->flags & PF_MEMALLOC)) { - int freed; extern struct wait_queue * kswapd_wait; - /* Somebody needs to free pages so we free some of our own. */ - if (atomic_read(&free_before_allocate)) { - current->flags |= PF_MEMALLOC; - try_to_free_pages(gfp_mask); - current->flags &= ~PF_MEMALLOC; - } - if (nr_free_pages > freepages.low) goto ok_to_allocate; @@ -223,35 +275,44 @@ /* Do we have to block or can we proceed? */ if (nr_free_pages > freepages.min) goto ok_to_allocate; + if (gfp_mask & __GFP_WAIT) { + int freed; + /* + * If the task is ok to sleep it's fine also + * if we release irq here. + */ + spin_unlock_irq(&page_alloc_lock); + + current->flags |= PF_MEMALLOC|PF_FREE_PAGES; + current->allocation_order = order; + freed = try_to_free_pages(gfp_mask); + current->flags &= ~(PF_MEMALLOC|PF_FREE_PAGES); + + spin_lock_irq(&page_alloc_lock); + refile_local_pages(); + + /* + * Re-check we're still low on memory after we blocked + * for some time. Somebody may have released lots of + * memory from under us while we was trying to free + * the pages. We check against pages_high to be sure + * to succeed only if lots of memory is been released. + */ + if (nr_free_pages > freepages.high) + goto ok_to_allocate; - current->flags |= PF_MEMALLOC; - atomic_inc(&free_before_allocate); - freed = try_to_free_pages(gfp_mask); - atomic_dec(&free_before_allocate); - current->flags &= ~PF_MEMALLOC; - - /* - * Re-check we're still low on memory after we blocked - * for some time. Somebody may have released lots of - * memory from under us while we was trying to free - * the pages. We check against pages_high to be sure - * to succeed only if lots of memory is been released. - */ - if (nr_free_pages > freepages.high) - goto ok_to_allocate; - - if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH))) - goto nopage; + if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH))) + goto nopage; + } } ok_to_allocate: - spin_lock_irqsave(&page_alloc_lock, flags); /* if it's not a dma request, try non-dma first */ if (!(gfp_mask & __GFP_DMA)) RMQUEUE_TYPE(order, 0); RMQUEUE_TYPE(order, 1); + nopage: spin_unlock_irqrestore(&page_alloc_lock, flags); - -nopage: + out: return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/mm/swap_state.c linux/mm/swap_state.c --- v2.2.18/mm/swap_state.c Sun Mar 25 11:12:36 2001 +++ linux/mm/swap_state.c Sun Mar 25 11:37:41 2001 @@ -63,6 +63,7 @@ return 0; } atomic_inc(&page->count); + page->flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced)); page->inode = &swapper_inode; page->offset = entry; add_page_to_hash_queue(page, &swapper_inode, entry); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/mm/vmscan.c linux/mm/vmscan.c --- v2.2.18/mm/vmscan.c Sun Mar 25 11:12:36 2001 +++ linux/mm/vmscan.c Sun Mar 25 11:37:41 2001 @@ -96,6 +96,9 @@ * some real work in the future in "shrink_mmap()". */ if (!pte_dirty(pte)) { + if (page_map->inode && pgcache_under_min()) + /* unmapping this page would be useless */ + return 0; flush_cache_page(vma, address); pte_clear(page_table); goto drop_pte; @@ -106,7 +109,7 @@ * we cannot do I/O! Avoid recursing on FS * locks etc. */ - if (!(gfp_mask & __GFP_IO)) + if (!(gfp_mask & __GFP_IO) || current->fs_locks) return 0; /* @@ -208,6 +211,8 @@ result = try_to_swap_out(tsk, vma, address, pte, gfp_mask); if (result) return result; + if (current->need_resched) + return 2; address += PAGE_SIZE; pte++; } while (address < end); @@ -327,7 +332,7 @@ * Think of swap_cnt as a "shadow rss" - it tells us which process * we want to page out (always try largest first). */ - counter = nr_tasks / (priority+1); + counter = nr_tasks / priority; if (counter < 1) counter = 1; @@ -361,8 +366,13 @@ goto out; } - if (swap_out_process(pbest, gfp_mask)) + switch (swap_out_process(pbest, gfp_mask)) { + case 1: return 1; + case 2: + current->state = TASK_RUNNING; + schedule(); + } } out: return 0; @@ -377,11 +387,9 @@ * cluster them so that we get good swap-out behaviour. See * the "free_memory()" macro for details. */ -static int do_try_to_free_pages(unsigned int gfp_mask) +int try_to_free_pages(unsigned int gfp_mask) { int priority; - int ret = 0; - int swapcount; int count = SWAP_CLUSTER_MAX; lock_kernel(); @@ -389,41 +397,34 @@ /* Always trim SLAB caches when memory gets low. */ kmem_cache_reap(gfp_mask); - priority = 6; + priority = 5; do { while (shrink_mmap(priority, gfp_mask)) { - ret = 1; if (!--count) goto done; } /* Try to get rid of some shared memory pages.. */ - if (gfp_mask & __GFP_IO) { + if (gfp_mask & __GFP_IO && !current->fs_locks) { while (shm_swap(priority, gfp_mask)) { - ret = 1; if (!--count) goto done; } } /* Then, try to page stuff out.. */ - swapcount = count; while (swap_out(priority, gfp_mask)) { - ret = 1; - if (!--swapcount) - break; + if (!--count) + goto done; } shrink_dcache_memory(priority, gfp_mask); - } while (--priority >= 0); + } while (--priority > 0); done: unlock_kernel(); - if (!ret) - printk("VM: do_try_to_free_pages failed for %s...\n", - current->comm); /* Return success if we freed a page. */ - return ret; + return priority > 0; } /* @@ -499,7 +500,7 @@ while (nr_free_pages < freepages.high) { - if (do_try_to_free_pages(GFP_KSWAPD)) + if (try_to_free_pages(GFP_KSWAPD)) { if (tsk->need_resched) schedule(); @@ -510,17 +511,3 @@ } } } - -/* - * Called by non-kswapd processes when kswapd really cannot - * keep up with the demand for free memory. - */ -int try_to_free_pages(unsigned int gfp_mask) -{ - int retval = 1; - - if (gfp_mask & __GFP_WAIT) - retval = do_try_to_free_pages(gfp_mask); - return retval; -} - diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/Changes linux/net/Changes --- v2.2.18/net/Changes Sun Mar 25 11:12:44 2001 +++ linux/net/Changes Wed Dec 31 19:00:00 1969 @@ -1,45 +0,0 @@ ---------------- Things That Need Doing Before 2.2 ------------------ - -o insw_and_csum - --------------------------- Bugs to fix ------------------------------ - -o Should unix domain connect never block ? -o Screend loadable firewall module -o Fix merging the bridge code -o Remove kernel RARP and replace with user mode daemon. -o Merge ARM half word trap fixes for ethernet headers -o Stop route addition to downed interfaces -o Make sure route add window functionality is back or documented - equivalences are clear -o Merge ATM -o Merge IRDA - -Possible projects for victim^H^H^H^H^Holunteers - -9. Implementing streams. Not as a blind slow SYS5.4 style copy but actually -working out how to do it so it runs like greased lightning. Quite a big -problem. [See the LiS project] - -11. IP over SCSI. [worked on] - -14. Bidirectional PLIP. Also PLIP for the newer style parallel ports. - -15. 802.2LLC and thus Netbeui sockets. Becoming less important since the -rumour is microsoft are phasing out netbeui for netbios/IP. Microsoft have -gone for netbios/funny-ipx-variant it seems in Win95, but TCP is selectable. - -17. PPP multilink. Another nasty job. - -19. IPv4 IP-AH and IP-ESP. - -20. (userspace) GUI interface to the bandwidth allocators so mere - mortals can do this - - -BTW: Don't let the magic words 'kernel programming' worry you. Its like DOS -- you make a mistake you have to reboot. You do at least get dumps and a -kernel logger that is reliable. There is now a loadable module allowing -use of gdb on the kernel (no breakpoints though!). No magic involved. - -Alan diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/Config.in linux/net/Config.in --- v2.2.18/net/Config.in Sun Mar 25 11:28:39 2001 +++ linux/net/Config.in Sun Mar 25 11:37:41 2001 @@ -56,15 +56,16 @@ bool 'Fast switching (read help!)' CONFIG_NET_FASTROUTE bool 'Forwarding between high speed interfaces' CONFIG_NET_HW_FLOWCONTROL bool 'CPU is too slow to handle full bandwidth' CONFIG_CPU_IS_SLOW - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - mainmenu_option next_comment - comment 'QoS and/or fair queueing' - bool 'QoS and/or fair queueing' CONFIG_NET_SCHED - if [ "$CONFIG_NET_SCHED" = "y" ]; then - source net/sched/Config.in - fi -# bool 'Network code profiler' CONFIG_NET_PROFILE - endmenu - fi fi + +mainmenu_option next_comment +comment 'QoS and/or fair queueing' +bool 'QoS and/or fair queueing' CONFIG_NET_SCHED +if [ "$CONFIG_NET_SCHED" = "y" ]; then + source net/sched/Config.in +fi +endmenu + +#bool 'Network code profiler' CONFIG_NET_PROFILE + endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.2.18/net/ax25/af_ax25.c Sun Mar 25 11:28:39 2001 +++ linux/net/ax25/af_ax25.c Sun Mar 25 11:37:41 2001 @@ -720,6 +720,9 @@ if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch (optname) { case AX25_WINDOW: val = sk->protinfo.ax25->window; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v2.2.18/net/ax25/ax25_in.c Sun Mar 25 11:12:44 2001 +++ linux/net/ax25/ax25_in.c Sun Mar 25 11:37:41 2001 @@ -36,6 +36,7 @@ * AX.25 036 Jonathan(G4KLX) Move DAMA code into own file. * Joerg(DL1BKE) Fixed DAMA Slave. * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Thomas(DL9SAU) Fixed missing initialization of skb->protocol. */ #include @@ -159,6 +160,7 @@ skb->nh.raw = skb->data; skb->dev = ax25->ax25_dev->dev; skb->pkt_type = PACKET_HOST; + skb->protocol = htons(ETH_P_IP); ip_rcv(skb, skb->dev, NULL); /* Wrong ptype */ return 1; } @@ -293,6 +295,7 @@ skb->nh.raw = skb->data; skb->dev = dev; skb->pkt_type = PACKET_HOST; + skb->protocol = htons(ETH_P_IP); ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ break; @@ -302,6 +305,7 @@ skb->nh.raw = skb->data; skb->dev = dev; skb->pkt_type = PACKET_HOST; + skb->protocol = htons(ETH_P_ARP); arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ break; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/core/dev.c linux/net/core/dev.c --- v2.2.18/net/core/dev.c Sun Mar 25 11:28:39 2001 +++ linux/net/core/dev.c Sun Mar 25 11:37:41 2001 @@ -649,7 +649,7 @@ /*======================================================================= - Receiver rotutines + Receiver routines =======================================================================*/ int netdev_dropping = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/core/filter.c linux/net/core/filter.c --- v2.2.18/net/core/filter.c Sun Mar 25 11:12:45 2001 +++ linux/net/core/filter.c Sun Mar 25 11:37:41 2001 @@ -196,7 +196,7 @@ case BPF_LD|BPF_W|BPF_ABS: k = fentry->k; load_w: - if(k+sizeof(u32) <= len) { + if((unsigned int)(k+sizeof(u32)) <= len) { A = ntohl(*(u32*)&data[k]); continue; } @@ -215,7 +215,7 @@ case BPF_LD|BPF_H|BPF_ABS: k = fentry->k; load_h: - if(k + sizeof(u16) <= len) { + if((unsigned int) (k + sizeof(u16)) <= len) { A = ntohs(*(u16*)&data[k]); continue; } @@ -234,7 +234,7 @@ case BPF_LD|BPF_B|BPF_ABS: k = fentry->k; load_b: - if(k < len) { + if((unsigned int)k < len) { A = data[k]; continue; } @@ -271,7 +271,7 @@ case BPF_LDX|BPF_B|BPF_MSH: k = fentry->k; - if(k >= len) + if((unsigned int)k >= len) return (0); X = (data[k] & 0xf) << 2; continue; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/core/sock.c linux/net/core/sock.c --- v2.2.18/net/core/sock.c Sun Mar 25 11:28:39 2001 +++ linux/net/core/sock.c Sun Mar 25 11:37:41 2001 @@ -79,6 +79,7 @@ * Jay Schulist : Added SO_ATTACH_FILTER and SO_DETACH_FILTER. * Andi Kleen : Add sock_kmalloc()/sock_kfree_s() * Andi Kleen : Fix write_space callback + * Chris Evans : Security fixes - signedness again * * To Fix: * @@ -381,6 +382,9 @@ if(get_user(len,optlen)) return -EFAULT; + if(len < 0) + return -EINVAL; + switch(optname) { case SO_DEBUG: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.2.18/net/ipv4/icmp.c Sun Mar 25 11:28:39 2001 +++ linux/net/ipv4/icmp.c Sun Mar 25 11:37:41 2001 @@ -3,7 +3,7 @@ * * Alan Cox, * - * Version: $Id: icmp.c,v 1.52.2.6 2000/08/31 23:49:16 davem Exp $ + * Version: $Id: icmp.c,v 1.52.2.7 2001/02/02 01:27:08 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -989,13 +989,21 @@ int icmp_chkaddr(struct sk_buff *skb) { - struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + skb->nh.iph->ihl*4); + unsigned short size = skb->nh.iph->ihl*4; + unsigned short clen = ntohs(skb->nh.iph->tot_len) - size; + struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + size); struct iphdr *iph = (struct iphdr *) (icmph + 1); - void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len) = icmp_pointers[icmph->type].handler; + void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len); + if (clen < sizeof(struct icmphdr)) return 0; + handler = icmp_pointers[icmph->type].handler; if (handler == icmp_unreach || handler == icmp_redirect) { struct sock *sk; - + + clen -= sizeof(struct icmphdr); + if (clen < sizeof(struct iphdr) || + clen < iph->ihl * 4 + sizeof(struct udphdr)) + return 0; switch (iph->protocol) { case IPPROTO_TCP: { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v2.2.18/net/ipv4/igmp.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/igmp.c Sun Mar 25 11:37:41 2001 @@ -8,7 +8,7 @@ * the older version didn't come out right using gcc 2.5.8, the newer one * seems to fall out with gcc 2.6.2. * - * Version: $Id: igmp.c,v 1.30.2.1 1999/07/23 15:29:22 davem Exp $ + * Version: $Id: igmp.c,v 1.30.2.2 2001/01/10 10:04:07 davem Exp $ * * Authors: * Alan Cox @@ -442,8 +442,8 @@ im->timer.function=&igmp_timer_expire; im->unsolicit_count = IGMP_Unsolicited_Report_Count; im->reporter = 0; - im->loaded = 0; #endif + im->loaded = 0; im->next=in_dev->mc_list; in_dev->mc_list=im; igmp_group_added(im); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- v2.2.18/net/ipv4/ip_input.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ip_input.c Sun Mar 25 11:37:41 2001 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.37 1999/04/22 10:38:36 davem Exp $ + * Version: $Id: ip_input.c,v 1.37.2.4 2001/01/04 04:20:16 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- v2.2.18/net/ipv4/ip_masq.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ip_masq.c Sun Mar 25 11:37:41 2001 @@ -4,7 +4,7 @@ * * Copyright (c) 1994 Pauline Middelink * - * $Id: ip_masq.c,v 1.34.2.2 1999/08/07 10:56:28 davem Exp $ + * $Id: ip_masq.c,v 1.34.2.14 2001/02/02 01:27:08 davem Exp $ * * * See ip_fw.c for original log @@ -236,7 +236,7 @@ tcp_state_out: if (new_state!=ms->state) - IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08lX:%04X-%08lX:%04X state: %s->%s\n", + IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08X:%04X-%08X:%04X state: %s->%s\n", masq_proto_name(ms->protocol), output? "output" : "input ", th->syn? 'S' : '.', @@ -798,7 +798,7 @@ */ atomic_inc(&ms->refcnt); - IP_MASQ_DEBUG(1, "Masqueraded %s %08lX:%04X expired\n", + IP_MASQ_DEBUG(1, "Masqueraded %s %08X:%04X expired\n", masq_proto_name(ms->protocol), ntohl(ms->saddr),ntohs(ms->sport)); @@ -846,7 +846,7 @@ } masq_expire_later: - IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X masq.refcnt-1=%d masq.n_control=%d\n", + IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08X:%04X->%08X:%04X masq.refcnt-1=%d masq.n_control=%d\n", masq_proto_name(ms->protocol), ntohl(ms->saddr), ntohs(ms->sport), ntohl(ms->daddr), ntohs(ms->dport), @@ -1223,7 +1223,7 @@ /* h.raw = (char*) iph + iph->ihl * 4; */ - IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n", + IP_MASQ_DEBUG(2, "Outgoing %s %08X:%04X -> %08X:%04X\n", masq_proto_name(iph->protocol), ntohl(iph->saddr), ntohs(h.portp[0]), ntohl(iph->daddr), ntohs(h.portp[1])); @@ -1294,6 +1294,8 @@ 0); if (ms == NULL) return -1; + if (!ms->app && skb->fwmark) + ip_masq_bind_app_fwmark(ms, skb->fwmark); } /* @@ -1387,7 +1389,7 @@ } ip_send_check(iph); - IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n", + IP_MASQ_DEBUG(2, "O-routed from %08X:%04X with masq.addr %08X\n", ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr)); masq_set_state(ms, 1, iph, h.portp); @@ -1485,8 +1487,9 @@ __u16 *pptr; /* port numbers from TCP/UDP contained header */ struct ip_masq *ms; unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); + unsigned short clen, csize; - IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %lX -> %lX\n", + IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %X -> %X\n", icmph->type, ntohs(icmp_id(icmph)), ntohl(iph->saddr), ntohl(iph->daddr)); @@ -1496,7 +1499,7 @@ (icmph->type == ICMP_INFO_REQUEST ) || (icmph->type == ICMP_ADDRESS )) { - IP_MASQ_DEBUG(2, "icmp request rcv %lX->%lX id %d type %d\n", + IP_MASQ_DEBUG(2, "icmp request rcv %X->%X id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), @@ -1547,7 +1550,7 @@ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *)icmph, len); - IP_MASQ_DEBUG(2, "icmp request rwt %lX->%lX id %d type %d\n", + IP_MASQ_DEBUG(2, "icmp request rwt %X->%X id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), @@ -1574,18 +1577,24 @@ return 0; /* Now find the contained IP header */ + clen = len - sizeof(struct icmphdr); + if (clen < sizeof(struct iphdr)) return -1; ciph = (struct iphdr *) (icmph + 1); + csize = ciph->ihl << 2; + if (clen < csize) return -1; #ifdef CONFIG_IP_MASQUERADE_ICMP if (ciph->protocol == IPPROTO_ICMP) { /* * This section handles ICMP errors for ICMP packets */ - struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + - (ciph->ihl<<2)); + struct icmphdr *cicmph; + if (clen < csize + sizeof(struct icmphdr)) return -1; - IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %lX->%lX id %d type %d\n", + cicmph = (struct icmphdr *)((char *)ciph + csize); + + IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %X->%X id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), @@ -1621,7 +1630,7 @@ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %lX->%lX id %d type %d\n", + IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %X->%X id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), @@ -1635,12 +1644,15 @@ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP)) return 0; + /* This is a hack: we need at least the TCP/UDP ports */ + if (clen < csize + sizeof(struct udphdr)) return -1; + /* * Find the ports involved - this packet was * incoming so the ports are right way round * (but reversed relative to outer IP header!) */ - pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); + pptr = (__u16 *)&(((char *)ciph)[csize]); #if 0 if (ntohs(pptr[1]) < PORT_MASQ_BEGIN || ntohs(pptr[1]) > PORT_MASQ_END) @@ -1657,7 +1669,7 @@ } - IP_MASQ_DEBUG(2, "Handling forward ICMP for %08lX:%04X -> %08lX:%04X\n", + IP_MASQ_DEBUG(2, "Handling forward ICMP for %08X:%04X -> %08X:%04X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); @@ -1695,7 +1707,7 @@ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08lX:%04X -> %08lX:%04X\n", + IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08X:%04X -> %08X:%04X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); @@ -1743,9 +1755,10 @@ __u16 *pptr; /* port numbers from TCP/UDP contained header */ struct ip_masq *ms; unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); + unsigned short clen, csize; - IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %lX -> %lX\n", + IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %X -> %X\n", icmph->type, ntohs(icmp_id(icmph)), ntohl(iph->saddr), ntohl(iph->daddr)); @@ -1756,7 +1769,7 @@ (icmph->type == ICMP_INFO_REPLY) || (icmph->type == ICMP_ADDRESSREPLY)) { - IP_MASQ_DEBUG(2, "icmp reply rcv %lX->%lX id %d type %d, req %d\n", + IP_MASQ_DEBUG(2, "icmp reply rcv %X->%X id %d type %d, req %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), @@ -1793,7 +1806,7 @@ - IP_MASQ_DEBUG(2, "icmp reply rwt %lX->%lX id %d type %d\n", + IP_MASQ_DEBUG(2, "icmp reply rwt %X->%X id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), @@ -1817,7 +1830,11 @@ * Now find the contained IP header */ + clen = len - sizeof(struct icmphdr); + if (clen < sizeof(struct iphdr)) return -1; ciph = (struct iphdr *) (icmph + 1); + csize = ciph->ihl << 2; + if (clen < csize) return -1; #ifdef CONFIG_IP_MASQUERADE_ICMP if (ciph->protocol == IPPROTO_ICMP) { @@ -1826,11 +1843,13 @@ * * First get a new ICMP header structure out of the IP packet */ - struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + - (ciph->ihl<<2)); + struct icmphdr *cicmph; + + if (clen < csize + sizeof(struct icmphdr)) return -1; + cicmph = (struct icmphdr *)((char *)ciph + csize); - IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %lX->%lX id %d type %d\n", + IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %X->%X id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), @@ -1872,7 +1891,7 @@ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %lX->%lX id %d type %d\n", + IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %X->%X id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), @@ -1887,11 +1906,14 @@ (ciph->protocol != IPPROTO_TCP)) return 0; + /* This is a hack: we need at least the TCP/UDP ports */ + if (clen < csize + sizeof(struct udphdr)) return -1; + /* * Find the ports involved - remember this packet was * *outgoing* so the ports are reversed (and addresses) */ - pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); + pptr = (__u16 *)&(((char *)ciph)[csize]); if (ntohs(pptr[0]) < PORT_MASQ_BEGIN || ntohs(pptr[0]) > PORT_MASQ_END) return 0; @@ -1906,7 +1928,7 @@ } - IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08lX:%04X -> %08lX:%04X\n", + IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08X:%04X -> %08X:%04X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); @@ -1948,7 +1970,7 @@ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); - IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08lX:%04X -> %08lX:%04X\n", + IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08X:%04X -> %08X:%04X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); @@ -2067,7 +2089,7 @@ - IP_MASQ_DEBUG(2, "Incoming %s %08lX:%04X -> %08lX:%04X\n", + IP_MASQ_DEBUG(2, "Incoming %s %08X:%04X -> %08X:%04X\n", masq_proto_name(iph->protocol), ntohl(iph->saddr), ntohs(h.portp[0]), ntohl(iph->daddr), ntohs(h.portp[1])); @@ -2082,8 +2104,11 @@ * Give additional modules a chance to create an entry */ #ifdef CONFIG_IP_MASQUERADE_MOD - if (!ms) + if (!ms) { ms = ip_masq_mod_in_create(skb, iph, maddr); + if (ms && !ms->app && skb->fwmark) + ip_masq_bind_app_fwmark(ms, skb->fwmark); + } /* * Call module's input update hook @@ -2138,7 +2163,7 @@ write_unlock(&__ip_masq_lock); - IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%lX\n", + IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%X\n", ntohl(ms->daddr)); } @@ -2208,7 +2233,7 @@ } ip_send_check(iph); - IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(h.portp[1])); + IP_MASQ_DEBUG(2, "I-routed to %08X:%04X\n",ntohl(iph->daddr),ntohs(h.portp[1])); masq_set_state (ms, 0, iph, h.portp); ip_masq_put(ms); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c --- v2.2.18/net/ipv4/ip_masq_app.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ip_masq_app.c Sun Mar 25 11:37:41 2001 @@ -2,7 +2,7 @@ * IP_MASQ_APP application masquerading module * * - * $Id: ip_masq_app.c,v 1.16 1998/08/29 23:51:14 davem Exp $ + * $Id: ip_masq_app.c,v 1.16.2.2 2001/01/04 05:28:46 davem Exp $ * * Author: Juan Jose Ciarlante, * @@ -15,7 +15,8 @@ * Fixes: * JJC : Implemented also input pkt hook * Miquel van Smoorenburg : Copy more stuff when resizing skb - * + * Juan Jose Ciarlante : reworked register() (new _init_xxxx() functions for nicer interface) + * Juan Jose Ciarlante : add INBOUND hooks (default to OUTBOUND) * * FIXME: * - ip_masq_skb_replace(): use same skb if space available. @@ -41,13 +42,27 @@ #define IP_MASQ_APP_TAB_SIZE 16 /* must be power of 2 */ -#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1)) -#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port ) -#define IP_MASQ_APP_PORT(type) ( type & 0xffff ) -#define IP_MASQ_APP_PROTO(type) ( (type>>16) & 0x00ff ) +/* + * ip_masq_app->type holds all the values needed to hook + * passing packet + * flags: (uses only upper 8bits: f_bits) + * INBOUND, OUTBOUND + * FWMARK + * + * if (flags & IP_MASQ_APP_FWMARK) + * [ f_bits][ fwmark (24 bits only) ] + * else + * [ f_bits][ proto ][ port ] + * + * <----------- 32 bits ------------> + * + */ + +#define IP_MASQ_APP_HASH(type) (((type>>16)^(type)) & (IP_MASQ_APP_TAB_SIZE-1)) EXPORT_SYMBOL(register_ip_masq_app); +EXPORT_SYMBOL(register_ip_masq_app_type); EXPORT_SYMBOL(unregister_ip_masq_app); EXPORT_SYMBOL(ip_masq_skb_replace); @@ -58,29 +73,53 @@ struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE]; /* - * ip_masq_app registration routine - * port: host byte order. + * "raw" ip_masq_app registration routine if you + * did ip_masq_app_init_xxxx() before to initialize (and check) + * type value */ -int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port) -{ +int register_ip_masq_app_type(struct ip_masq_app *mapp) { unsigned long flags; unsigned hash; +#ifdef CONFIG_IP_MASQ_DEBUG if (!mapp) { IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n"); return -EINVAL; } - mapp->type = IP_MASQ_APP_TYPE(proto, port); +#endif + if (!mapp->type) { + IP_MASQ_DEBUG(1, "ip_masq_app_register_type(): ZERO type passed\n"); + return -EINVAL; + } + mapp->n_attach = 0; - hash = IP_MASQ_APP_HASH(proto, port); + hash = IP_MASQ_APP_HASH(mapp->type); + IP_MASQ_DEBUG(2, "ip_masq_app_register(): type=0x%x hash=0x%x\n", mapp->type, hash); save_flags(flags); cli(); mapp->next = ip_masq_app_base[hash]; ip_masq_app_base[hash] = mapp; restore_flags(flags); + return 0; +} - return 0; +/* + * ip_masq_app registration routine + * port: host byte order. + * proto: (flags<<8) | ipproto + */ +int register_ip_masq_app(struct ip_masq_app *mapp, unsigned proto, __u16 port) +{ +#ifdef CONFIG_IP_MASQ_DEBUG + if (!mapp) { + IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n"); + return -EINVAL; + } +#endif + + ip_masq_app_init_proto_port(mapp, IP_MASQ_APP_OUTBOUND, proto, port); + return register_ip_masq_app_type(mapp); } /* @@ -104,7 +143,7 @@ mapp->n_attach); return -EINVAL; } - hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type)); + hash = IP_MASQ_APP_HASH(mapp->type); save_flags(flags); cli(); @@ -116,24 +155,26 @@ } restore_flags(flags); - IP_MASQ_ERR("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n", - masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type)); + IP_MASQ_ERR("unregister_ip_masq_app(flags=0x%x, proto=%s,port=%u,fwmark=%d): not hashed!\n", + + IP_MASQ_APP_TYPE2FLAGS(mapp->type), + masq_proto_name(IP_MASQ_APP_TYPE2PROTO(mapp->type)), + IP_MASQ_APP_TYPE2PORT(mapp->type), + IP_MASQ_APP_TYPE2FWMARK(mapp->type)); return -EINVAL; } /* - * get ip_masq_app object by its proto and port (net byte order). + * get ip_masq_app object by its proto and port (host byte order). */ -struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port) +struct ip_masq_app * ip_masq_app_get_type(unsigned type) { struct ip_masq_app *mapp; unsigned hash; - unsigned type; - port = ntohs(port); - type = IP_MASQ_APP_TYPE(proto,port); - hash = IP_MASQ_APP_HASH(proto,port); + hash = IP_MASQ_APP_HASH(type); + IP_MASQ_DEBUG(2, "ip_masq_app_get(): type=0x%x hash=0x%x\n", type, hash); for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) { if (type == mapp->type) return mapp; } @@ -159,8 +200,8 @@ if (n_at < 0) { restore_flags(flags); IP_MASQ_ERR("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n", - masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), - IP_MASQ_APP_PORT(mapp->type)); + masq_proto_name(IP_MASQ_APP_TYPE2PROTO(mapp->type)), + IP_MASQ_APP_TYPE2PORT(mapp->type)); return -1; } mapp->n_attach = n_at; @@ -169,41 +210,91 @@ } /* + * Actually bind pointers and call contructor + */ + +static struct ip_masq_app *do_bind_app(struct ip_masq *ms, struct ip_masq_app *mapp) +{ + /* + * don't allow binding if already bound + */ + if (ms->app != NULL) { + IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n"); + goto end; + } + IP_MASQ_DEBUG(1, "ip_masq_bind_app() : bound \"%s\" module\n", mapp->name); + ms->app = mapp; + if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms); + ip_masq_app_bind_chg(mapp, +1); +end: + return ms->app; +} + +/* * Bind ip_masq to its ip_masq_app based on proto and dport ALREADY - * set in ip_masq struct. Also calls constructor. + * set in ip_masq struct. + * Only called from ip_masq_new() when creating NEW masq tunnel, */ struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms) { struct ip_masq_app * mapp; + unsigned type; if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP) return NULL; - mapp = ip_masq_app_get(ms->protocol, ms->dport); + IP_MASQ_DEBUG(1, "ip_masq_bind_app() : called for dst=%d.%d.%d.%d:%d src=%d.%d.%d.%d:%d masq=%d.%d.%d.%d:%d\n", + NIPQUAD(ms->daddr), ntohs(ms->dport), + NIPQUAD(ms->saddr), ntohs(ms->sport), + NIPQUAD(ms->maddr), ntohs(ms->mport)); -#if 0000 -/* #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW */ - if (mapp == NULL) - mapp = ip_masq_app_get(ms->protocol, ms->sport); -/* #endif */ -#endif + /* + * Lookup "normal" case (client's active open inside) + */ + type = IP_MASQ_APP_TYPE_PP(IP_MASQ_APP_OUTBOUND, ms->protocol, ntohs(ms->dport)); + mapp = ip_masq_app_get_type(type); - if (mapp != NULL) { - /* - * don't allow binding if already bound - */ - - if (ms->app != NULL) { - IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n"); - return ms->app; - } + if (mapp==NULL) { + /* + * lookup "reverse" case (server waiting inside, + * for portfw and friends) + */ + type = IP_MASQ_APP_TYPE_PP(IP_MASQ_APP_INBOUND, ms->protocol, ntohs(ms->mport)); + mapp = ip_masq_app_get_type(type); + } - ms->app = mapp; - if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms); - ip_masq_app_bind_chg(mapp, +1); - } - return mapp; + if (mapp != NULL) + mapp=do_bind_app(ms, mapp); + return mapp; +} +/* + * Bind ip_masq to its ip_masq_app based on firewall mark + */ +struct ip_masq_app * ip_masq_bind_app_fwmark(struct ip_masq *ms, __u32 fwmark) { + struct ip_masq_app *mapp; + unsigned type; + + IP_MASQ_DEBUG(1, "ip_masq_bind_app_fwmark() : called for fwmark=0x%x, dst=%d.%d.%d.%d:%d src=%d.%d.%d.%d:%d masq=%d.%d.%d.%d:%d\n", + fwmark, + NIPQUAD(ms->daddr), ntohs(ms->dport), + NIPQUAD(ms->saddr), ntohs(ms->sport), + NIPQUAD(ms->maddr), ntohs(ms->mport)); + + type = IP_MASQ_APP_TYPE_FWMARK(IP_MASQ_APP_OUTBOUND, fwmark); + mapp = ip_masq_app_get_type(type); + + if (mapp==NULL) { + /* + * lookup "reverse" case (server waiting inside, + * for portfw and friends) + */ + type = IP_MASQ_APP_TYPE_FWMARK(IP_MASQ_APP_INBOUND, fwmark); + mapp = ip_masq_app_get_type(type); + } + if (mapp != NULL) + mapp=do_bind_app(ms, mapp); + return mapp; } /* @@ -269,10 +360,14 @@ * Adjust ack_seq with delta-offset for * the packets AFTER most recent resized pkt has caused a shift * for packets before most recent resized pkt, use previous_delta + * + * Compare acks against (remote SEQs space is +delta) + * (ms_seq->init_seq + ms_seq->delta), not ms_seq->init_seq + * -- R.R. 27/08/00 */ if (ms_seq->delta || ms_seq->previous_delta) { - if(after(ack_seq,ms_seq->init_seq)) { + if(after(ack_seq,ms_seq->init_seq + ms_seq->delta)) { th->ack_seq = htonl(ack_seq-ms_seq->delta); IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta); @@ -455,8 +550,8 @@ continue; len += sprintf(buffer+len, "%-3s %-7u %-7d %-17s\n", - masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), - IP_MASQ_APP_PORT(mapp->type), mapp->n_attach, + masq_proto_name(IP_MASQ_APP_TYPE2PROTO(mapp->type)), + IP_MASQ_APP_TYPE2PORT(mapp->type), mapp->n_attach, mapp->name); if(len >= length) @@ -497,7 +592,7 @@ * Replace a segment (of skb->data) with a new one. * FIXME: Should re-use same skb if space available, this could * be done if n_len < o_len, unless some extra space - * were already allocated at driver level :P . + * were already allocated at link level :P . */ static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c --- v2.2.18/net/ipv4/ip_masq_ftp.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ip_masq_ftp.c Sun Mar 25 11:37:41 2001 @@ -2,7 +2,7 @@ * IP_MASQ_FTP ftp masquerading module * * - * Version: @(#)ip_masq_ftp.c 0.04 02/05/96 + * Version: @(#)ip_masq_ftp.c 0.10 20/09/00 * * Author: Wouter Gadeyne * @@ -17,12 +17,15 @@ * Juan Jose Ciarlante : use ip_masq_listen() * Juan Jose Ciarlante : use private app_data for own flag(s) * Bjarni R. Einarsson : Added protection against "extended FTP ALG attack" - * + * Neil Toronto : portfw FTP support + * Juan Jose Ciarlante : reimplemented parsing logic, merged portfw FTP support for PASV (new "in_ports" module param), use th->doff for data offset + * Juan Jose Ciarlante : safe_mem_eq2() and size adjustments for less CPU + * Juan Jose Ciarlante : fwmark hook-able * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * 2 of the License. * * Multiple Port Support * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12) @@ -34,6 +37,16 @@ * /etc/conf.modules (or /etc/modules.conf depending on your config) * where modload will pick it up should you use modload to load your * modules. + * Additional portfw Port Support + * Module parameter "in_ports" specifies the list of forwarded ports + * at firewall (portfw and friends) that must be hooked to allow + * PASV connections to inside servers. + * Same as before: + * in_ports=fw1,fw2,... + * Eg: + * ipmasqadm portfw -a -P tcp -L a.b.c.d 2021 -R 192.168.1.1 21 + * ipmasqadm portfw -a -P tcp -L a.b.c.d 8021 -R 192.168.1.1 21 + * modprobe ip_masq_ftp in_ports=2021,8021 * * Protection against the "extended FTP ALG vulnerability". * This vulnerability was reported in: @@ -66,22 +79,52 @@ /* #define IP_MASQ_NDEBUG */ #include +/* + * paranoid, CPU care offset handling + */ +/* #define MASQ_FTP_RELAXED 1 */ +#ifdef MASQ_FTP_RELAXED +#define _N(x) 0 +#else +#define _N(x) (x) +#endif + +#define IP_MASQ_FTP_RPAREN 0x01 /* stream has ')' char */ +/* + * Eat 1 port (last elem) for holding firewall mark instance + */ +#define MAX_MASQ_FTP_PORTS (MAX_MASQ_APP_PORTS-1) +#define MAX_MASQ_FTP_PORTS_MODPARM 11 /* * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper * First port is set to the default port. */ -static int ports[MAX_MASQ_APP_PORTS] = {21}; /* I rely on the trailing items being set to zero */ -struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS]; +static int ports[MAX_MASQ_FTP_PORTS] = {21}; /* I rely on the trailing items being set to zero */ +static struct ip_masq_app *masq_ftp_objs[MAX_MASQ_APP_PORTS]; + +/* + * in (forwarded) ports + */ +static int in_ports[MAX_MASQ_FTP_PORTS] = {0}; +static struct ip_masq_app *masq_in_ftp_objs[MAX_MASQ_APP_PORTS]; + +#define masq_ftp_mark masq_ftp_objs[MAX_MASQ_APP_PORTS-1] +#define masq_in_ftp_mark masq_in_ftp_objs[MAX_MASQ_APP_PORTS-1] /* * List of ports (up to MAX_MASQ_APP_PORTS) we don't allow ftp-data * connections to. Default is to block connections to port 6000 (X servers). * This is in addition to all ports under 1024. */ -static int noport[MAX_MASQ_APP_PORTS] = {6000, 0}; /* I rely on the trailing items being set to zero */ +static int noport[MAX_MASQ_FTP_PORTS] = {6000, 0}; /* I rely on the trailing items being set to zero */ /* + * Firewall marks for "normal" and "forw" cases + */ +static int mark=0; +static int in_mark=0; +/* * Debug level */ #ifdef CONFIG_IP_MASQ_DEBUG @@ -89,12 +132,56 @@ MODULE_PARM(debug, "i"); #endif -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); -MODULE_PARM(noport, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_FTP_PORTS_MODPARM) "i"); +MODULE_PARM(in_ports, "1-" __MODULE_STRING(MAX_MASQ_FTP_PORTS_MODPARM) "i"); +MODULE_PARM(noport, "1-" __MODULE_STRING(MAX_MASQ_FTP_PORTS_MODPARM) "i"); +MODULE_PARM(mark, "i"); +MODULE_PARM(in_mark, "i"); /* Dummy variable */ static int masq_ftp_pasv; +/* + * This function parses the IP address and Port number found in PORT commands + * and PASV responses. This used to be done in-line, but with four cases it + * seemed worth encapsulating. It returns the IP address, or zero if an + * error is detected. + */ +static __u32 parse_ip_port( char **datap, __u16 *portp ) +{ + char *data = *datap; +#if CONFIG_IP_MASQ_DEBUG + char *data0=data; +#endif + unsigned char p1,p2,p3,p4,p5,p6; + + p1 = simple_strtoul(data, &data, 10); + if (*data != ',') + return 0; + p2 = simple_strtoul(data+1, &data, 10); + if (*data != ',') + return 0; + p3 = simple_strtoul(data+1, &data, 10); + if (*data != ',') + return 0; + p4 = simple_strtoul(data+1, &data, 10); + if (*data != ',') + return 0; + p5 = simple_strtoul(data+1, &data, 10); + if (*data != ',') + return 0; + p6 = simple_strtoul(data+1, &data, 10); + + IP_MASQ_DEBUG(2-debug, "FTP: parse_ip_port() Ok: \"%*s\" size=%d\n", + data-data0, + data0, + data-data0); + *datap = data; + *portp = (p5<<8) | p6; + return (p1<<24) | (p2<<16) | (p3<<8) | p4; +} + + static int masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms) { @@ -109,138 +196,221 @@ return 0; } + +static int masq_ftp_unsafe(__u32 from_ip, __u16 from_port) { + int i; + if (from_port < 1024) + { + IP_MASQ_DEBUG(1-debug, "Unsafe PORT %d.%d.%d.%d:%d detected, ignored\n",NIPQUAD(from_ip),from_port); + return 1; + } + + for (i = 0; (i < MAX_MASQ_FTP_PORTS) && (noport[i]); i++) + if (from_port == noport[i]) + { + IP_MASQ_DEBUG(1-debug, "Unsafe (module parm) PORT %d.%d.%d.%d:%d detected, ignored\n",NIPQUAD(from_ip),from_port); + return 1; + } + return 0; +} +/* + * carefully compare with any of these 2 strings, eating stream pointer + * as it proceeds + * Returns: + * NULL not matched + * !NULL last matched char* + */ +static char* safe_mem_eq2(char *data, const char *data_limit, int size, const char *str1, const char *str2) { +#if CONFIG_IP_MASQ_DEBUG + const char *data0=data; + if (!data) { + IP_MASQ_ERR("FTP: NULL data passed to safe_mem_eq2()!!!"); + return NULL; + } +#endif + IP_MASQ_DEBUG(3-debug, "FTP: safe_mem_equal(): datalimit-data=%d, size=%d\n", data_limit-data, size); + + /* No point in going after data_limit for "size" comparison */ + data_limit -= size; + + while (data <= data_limit) { + if (memcmp(data,str1,size)==0) + goto equal_ok; + if (str2 && memcmp(data,str2,size)==0) + goto equal_ok; + data++; + } + IP_MASQ_DEBUG(2-debug, "FTP: safe_mem_equal(): \"%s\" not matched)\n", str1); + return NULL; +equal_ok: + IP_MASQ_DEBUG(2-debug, "FTP: safe_mem_equal(): \"%s\" matched at offset %d\n", + str1, data-data0); + return data+size; +} int masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr) { struct sk_buff *skb; struct iphdr *iph; struct tcphdr *th; - char *p, *data, *data_limit; - unsigned char p1,p2,p3,p4,p5,p6; - __u32 from; + char *p, *data, *data0, *data_limit; + __u32 from=0; + __u32 from_n; __u16 port; struct ip_masq *n_ms; - char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ + char buf[25]; /* xxx.xxx.xxx.xxx,ppp,ppp)\000 */ + unsigned flags=0; /* processing flags */ unsigned buf_len; - int diff, i, unsafe; + int diff=0; + + /* Only useful for established sessions */ + if (ms->state != IP_MASQ_S_ESTABLISHED) + return 0; skb = *skb_p; iph = skb->nh.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; + data = (char *)th + (((struct tcphdr*)th)->doff << 2); + data0 = data; + data_limit = skb->h.raw + skb->len; + + IP_MASQ_DEBUG(2-debug, "FTP: called masq_ftp_out() for type=0x%x datasize=%d\n", + mapp->type, + data_limit-data); - data_limit = skb->h.raw + skb->len - 18; - if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0)) - ms->app_data = &masq_ftp_pasv; + /* Only useful for actual data */ + if (data_limit<=data) + return 0; - while (data < data_limit) - { - if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) - { - data ++; - continue; + /* + * We are about to hack an OUT (from firewall) packet, + * check if + * OUTBOUND: internal client stream + * INBOUND: internal server stream + */ + + if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_OUTBOUND) { + IP_MASQ_DEBUG(1-debug, "FTP: in->out client stream\n"); + + /* + * Minimum sizes ... + * PORT x,x,x,x,y,y+... + \r\n + * <---------- 11 + 2 = 13 + */ + if (!(data=safe_mem_eq2(data, data_limit-_N(13), + 5, "PORT ", "port ")) ) { + if (safe_mem_eq2(data0, data_limit, 6, "PASV\r\n", "pasv\r\n")) { + /* Flags this tunnel as pasv, return */ + ms->app_data = &masq_ftp_pasv; + } + return 0; } - p = data+5; - p1 = simple_strtoul(data+5,&data,10); - if (*data!=',') - continue; - p2 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p3 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p4 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p5 = simple_strtoul(data+1,&data,10); - if (*data!=',') - continue; - p6 = simple_strtoul(data+1,&data,10); - if (*data!='\r' && *data!='\n') - continue; + p = data; + from = parse_ip_port(&data, &port); + if (masq_ftp_unsafe(from,port)) + return 0; + IP_MASQ_DEBUG(1-debug,"FTP: out: PORT %d.%d.%d.%d:%d detected\n", + NIPQUAD(from), port); - from = (p1<<24) | (p2<<16) | (p3<<8) | p4; - port = (p5<<8) | p6; + } else if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_INBOUND) { + IP_MASQ_DEBUG(1-debug, "FTP: in->out server stream\n"); - if (port < 1024) - { - IP_MASQ_DEBUG(1-debug, "Unsafe PORT %X:%X detected, ignored\n",from,port); - continue; - } + /* + * Minimum sizes... + * Entering Passive Mode (x,x,x,x,y,y)+... + \r\n + * <------------------------- 26 + 2 = 28 + * <----------------- 18 + 2 = 20 + * <------------ 13 + 2 = 15 + */ + if (!(data=safe_mem_eq2(data, data_limit-_N(28), 8, "ntering ", "NTERING "))) + return 0; + if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(20), 7, "assive ", "ASSIVE "))) + return 0; + if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(15), 4, "ode ", "ODE "))) + return 0; + do { + if (data >= data_limit) + return 0; + } while (*data++ != '('); - for (unsafe = i = 0; (i < MAX_MASQ_APP_PORTS) && (noport[i]); i++) - if (port == noport[i]) - { - IP_MASQ_DEBUG(1-debug, "Unsafe PORT %X:%X detected, ignored\n",from,port); - unsafe = 1; - } - if (unsafe) continue; + p = data; + from = parse_ip_port(&data, &port); + if ((from == 0) || (*data++ !=')')) + return 0; - IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port); + flags |= IP_MASQ_FTP_RPAREN; - /* - * Now update or create an masquerade entry for it - */ + } else + return 0; - IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0); + /* no from detected, give up */ + if (from == 0) + return 0; - n_ms = ip_masq_out_get(iph->protocol, - htonl(from), htons(port), - iph->daddr, 0); - if (!n_ms) { - n_ms = ip_masq_new(IPPROTO_TCP, - maddr, 0, - htonl(from), htons(port), - iph->daddr, 0, - IP_MASQ_F_NO_DPORT); + /* store from in network byte order */ + from_n = htonl(from); + /* + * Now update or create an masquerade entry for it + */ - if (n_ms==NULL) - return 0; - ip_masq_control_add(n_ms, ms); - } + IP_MASQ_DEBUG(1-debug, "FTP: out: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", + NIPQUAD(from_n), htons(port), + NIPQUAD(iph->daddr), 0); - /* - * Replace the old PORT with the new one - */ - from = ntohl(n_ms->maddr); - port = ntohs(n_ms->mport); - sprintf(buf,"%d,%d,%d,%d,%d,%d", - from>>24&255,from>>16&255,from>>8&255,from&255, - port>>8&255,port&255); - buf_len = strlen(buf); + n_ms = ip_masq_out_get(iph->protocol, + from_n, htons(port), + iph->daddr, 0); + if (!n_ms) { + n_ms = ip_masq_new(IPPROTO_TCP, + maddr, 0, + from_n, htons(port), + iph->daddr, 0, + IP_MASQ_F_NO_DPORT); - IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port); + if (n_ms==NULL) + return 0; + ip_masq_control_add(n_ms, ms); + } - /* - * Calculate required delta-offset to keep TCP happy - */ - - diff = buf_len - (data-p); - - /* - * No shift. - */ - - if (diff==0) { - /* - * simple case, just replace the old PORT cmd - */ - memcpy(p,buf,buf_len); - } else { + /* + * Replace the old PORT with the new one + */ + from = ntohl(n_ms->maddr); + port = ntohs(n_ms->mport); + sprintf(buf,"%d,%d,%d,%d,%d,%d%c", + from>>24&255,from>>16&255,from>>8&255,from&255, + port>>8&255,port&255, + (flags&IP_MASQ_FTP_RPAREN)? ')':0); + buf_len = strlen(buf); - *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len); - } - /* - * Move tunnel to listen state - */ - ip_masq_listen(n_ms); - ip_masq_put(n_ms); + IP_MASQ_DEBUG(1-debug, "FTP: new PORT %d.%d.%d.%d:%d\n",NIPQUAD(maddr),port); + + /* + * Calculate required delta-offset to keep TCP happy + */ + + diff = buf_len - (data-p); + + /* + * No shift. + */ - return diff; + if (diff==0) { + /* + * simple case, just replace the old PORT cmd + */ + memcpy(p,buf,buf_len); + } else { + *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len); } - return 0; + /* + * Move tunnel to listen state + */ + ip_masq_listen(n_ms); + ip_masq_put(n_ms); + + return diff; } @@ -269,53 +439,92 @@ struct iphdr *iph; struct tcphdr *th; char *data, *data_limit; - unsigned char p1,p2,p3,p4,p5,p6; __u32 to; + __u32 from_n; __u16 port; struct ip_masq *n_ms; - if (ms->app_data != &masq_ftp_pasv) - return 0; /* quick exit if no outstanding PASV */ + /* Only useful for established sessions */ + if (ms->state != IP_MASQ_S_ESTABLISHED) + return 0; skb = *skb_p; iph = skb->nh.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; + data = (char *)th + (((struct tcphdr*)th)->doff << 2); data_limit = skb->h.raw + skb->len; - while (data < data_limit && *data != ' ') - ++data; - while (data < data_limit && *data == ' ') - ++data; - data += 22; - if (data >= data_limit || *data != '(') - return 0; - p1 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p2 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p3 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p4 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p5 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ',') - return 0; - p6 = simple_strtoul(data+1, &data, 10); - if (data >= data_limit || *data != ')') + IP_MASQ_DEBUG(2-debug, "FTP: called masq_ftp_in() for type=0x%x datasize=%d\n", + mapp->type, + data_limit-data); + + /* Only useful for actual data */ + if (data_limit<=data) return 0; - to = (p1<<24) | (p2<<16) | (p3<<8) | p4; - port = (p5<<8) | p6; + /* + * We are about to hack an IN (to firewall) packet, + * check if + * OUTBOUND: internal client stream + * INBOUND: internal server stream + */ + + if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_OUTBOUND) { + IP_MASQ_DEBUG(1-debug, "FTP: out->in client stream\n"); + /* + * For OUTBOUND only parse on input for linking PASV + * data tunnel with control. + * Exit quickly if no outstanding PASV + */ + if (ms->app_data != &masq_ftp_pasv) + return 0; + + /* + * Minimum sizes... + * Entering Passive Mode (x,x,x,x,y,y)+... + \r\n + * <------------------------- 26 + 2 = 28 + * <----------------- 18 + 2 = 20 + * <------------ 13 + 2 = 15 + */ + if (!(data=safe_mem_eq2(data, data_limit-_N(28), 8, "ntering ", "NTERING "))) + return 0; + if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(20), 6, "ssive ", "SSIVE "))) + return 0; + if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(15), 4, "ode ", "ODE "))) + return 0; + do { + if (data >= data_limit) + return 0; + } while (*data++ != '('); + + to = parse_ip_port(&data, &port); + if (to == 0 || *data != ')') + return 0; + + from_n = ntohl(ms->saddr); + IP_MASQ_DEBUG(1-debug, "FTP: PASV response %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d detected\n", + NIPQUAD(from_n), 0, + NIPQUAD(to), port); + } else if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_INBOUND) { + IP_MASQ_DEBUG(1-debug, "FTP: out->in server stream\n"); + + if (!(data=safe_mem_eq2(data, data_limit-_N(13), + 5, "PORT ", "port ")) ) + return 0; + to = parse_ip_port(&data, &port); + if (to == 0 || (*data != '\r' && *data != '\n')) + return 0; + + from_n = ntohl(ms->saddr); + IP_MASQ_DEBUG(1-debug, "FTP: PORT %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d detected\n", + NIPQUAD(from_n), 0, + NIPQUAD(to), port); + } else + return 0; /* * Now update or create an masquerade entry for it */ - IP_MASQ_DEBUG(1-debug, "PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port); n_ms = ip_masq_out_get(iph->protocol, ms->saddr, 0, @@ -356,58 +565,120 @@ masq_ftp_out, /* pkt_out */ masq_ftp_in, /* pkt_in */ }; - -/* - * ip_masq_ftp initialization - */ - -__initfunc(int ip_masq_ftp_init(void)) +static struct ip_masq_app *make_instance(const struct ip_masq_app *mapp_class, int *err) { - int i, j; + struct ip_masq_app *mapp = NULL; + if ((mapp = kmalloc(sizeof(struct ip_masq_app), GFP_KERNEL))) + memcpy(mapp , mapp_class, sizeof(struct ip_masq_app)); + else + *err= -ENOMEM; + return mapp; +} - for (i=0; (itype); } else { /* To be safe, force the incarnation table entry to NULL */ - masq_incarnations[i] = NULL; + mapp_instances[i] = NULL; } } return 0; +end_kfree: + kfree_s(mapp, sizeof(struct ip_masq_app)); +end: + IP_MASQ_ERR("FTP: registration error, quitting\n"); + return err; } - /* - * ip_masq_ftp fin. + * Unregister ALL ports, _including_ the (possible) firewall + * mark. */ - -int ip_masq_ftp_done(void) -{ - int i, j, k; - - k=0; +static int unregister_ports(struct ip_masq_app *mapp_instances[]) { + int i, j, k=0; for (i=0; (itype); + kfree(mapp_instances[i]); + mapp_instances[i] = NULL; } } } return k; +} + +/* + * ip_masq_ftp initialization + */ + +__initfunc(int ip_masq_ftp_init(void)) +{ + int ret=0; + struct ip_masq_app *mapp; + if ( + (ret=register_ports(masq_ftp_objs, ports, IP_MASQ_APP_OUTBOUND)) || + (ret=register_ports(masq_in_ftp_objs, in_ports, IP_MASQ_APP_INBOUND)) + ) + goto end; + + if (mark) { + if (!(mapp=make_instance(&ip_masq_ftp, &ret))) + goto end; + if ((ret=ip_masq_app_init_fwmark(mapp, IP_MASQ_APP_OUTBOUND, mark))) { + kfree_s(mapp, sizeof (struct ip_masq_app)); + goto end; + } + if ((ret=register_ip_masq_app_type(mapp))) + goto end; + masq_ftp_mark=mapp; + } + if (in_mark) { + if (!(mapp=make_instance(&ip_masq_ftp, &ret))) + goto end; + if ((ret=ip_masq_app_init_fwmark(mapp, IP_MASQ_APP_INBOUND, in_mark))) { + kfree_s(mapp, sizeof (struct ip_masq_app)); + goto end; + } + if ((ret=register_ip_masq_app_type(mapp))) + goto end; + masq_in_ftp_mark=mapp; + } +end: + return ret; +} + +/* + * ip_masq_ftp fin. + */ + +int ip_masq_ftp_done(void) +{ + int ret; + ret = unregister_ports(masq_ftp_objs); + ret += unregister_ports(masq_in_ftp_objs); + return ret; } #ifdef MODULE diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_masq_mod.c linux/net/ipv4/ip_masq_mod.c --- v2.2.18/net/ipv4/ip_masq_mod.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ip_masq_mod.c Sun Mar 25 11:37:41 2001 @@ -4,7 +4,7 @@ * * Author: Juan Jose Ciarlante, * - * $Id: ip_masq_mod.c,v 1.5.2.1 1999/07/02 10:10:03 davem Exp $ + * $Id: ip_masq_mod.c,v 1.5.2.3 2001/01/04 04:20:16 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c --- v2.2.18/net/ipv4/ip_masq_raudio.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ip_masq_raudio.c Sun Mar 25 11:37:41 2001 @@ -2,7 +2,7 @@ * IP_MASQ_RAUDIO - Real Audio masquerading module * * - * Version: @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $ + * Version: @(#)$Id: ip_masq_raudio.c,v 1.11.2.1 2001/01/10 01:52:33 davem Exp $ * * Author: Nigel Metheringham * Real Time Streaming code by Progressive Networks @@ -169,7 +169,10 @@ skb = *skb_p; iph = skb->nh.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; + + /* Make sure we take into account the size of the TCP packet. This is + * because there may be TCP options in the TCP packet */ + data = ((char *)&th[0]) + (th->doff * 4); data_limit = skb->h.raw + skb->len; @@ -315,7 +318,10 @@ skb = *skb_p; iph = skb->nh.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); - data = (char *)&th[1]; + + /* Make sure we take into account the size of the TCP packet. This is + * because there may be TCP options in the TCP packet */ + data = ((char *)&th[0]) + (th->doff * 4); data_limit = skb->h.raw + skb->len; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_masq_user.c linux/net/ipv4/ip_masq_user.c --- v2.2.18/net/ipv4/ip_masq_user.c Sun Mar 25 11:28:39 2001 +++ linux/net/ipv4/ip_masq_user.c Sun Mar 25 11:37:41 2001 @@ -2,7 +2,7 @@ * IP_MASQ_USER user space control module * * - * $Id: ip_masq_user.c,v 1.1.2.4 2000/02/29 23:50:24 davem Exp $ + * $Id: ip_masq_user.c,v 1.1.2.6 2001/01/04 04:20:16 davem Exp $ */ #include @@ -35,7 +35,6 @@ */ static int debug=0; -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i"); MODULE_PARM(debug, "i"); /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.2.18/net/ipv4/ip_sockglue.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ip_sockglue.c Sun Mar 25 11:37:41 2001 @@ -636,6 +636,9 @@ if(get_user(len,optlen)) return -EFAULT; + if(len < 0) + return -EINVAL; + switch(optname) { case IP_OPTIONS: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.2.18/net/ipv4/ipmr.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/ipmr.c Sun Mar 25 11:37:41 2001 @@ -877,6 +877,10 @@ return -EFAULT; olr=min(olr,sizeof(int)); + + if(olr < 0) + return -EINVAL; + if(put_user(olr,optlen)) return -EFAULT; if(optname==MRT_VERSION) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.2.18/net/ipv4/raw.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/raw.c Sun Mar 25 11:37:41 2001 @@ -497,6 +497,8 @@ if (get_user(len,optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; if (len > sizeof(struct icmp_filter)) len = sizeof(struct icmp_filter); if (put_user(len, optlen)) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/route.c linux/net/ipv4/route.c --- v2.2.18/net/ipv4/route.c Sun Mar 25 11:28:40 2001 +++ linux/net/ipv4/route.c Sun Mar 25 11:37:41 2001 @@ -1927,7 +1927,7 @@ return -EINVAL; } -static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, int *name, int nlen, +static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.2.18/net/ipv4/sysctl_net_ipv4.c Sun Mar 25 11:28:40 2001 +++ linux/net/ipv4/sysctl_net_ipv4.c Sun Mar 25 11:37:41 2001 @@ -87,7 +87,7 @@ return ret; } -static int ipv4_sysctl_forward_strategy(ctl_table *table, int *name, int nlen, +static int ipv4_sysctl_forward_strategy(ctl_table *table, int *name, unsigned nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.2.18/net/ipv4/tcp.c Sun Mar 25 11:28:40 2001 +++ linux/net/ipv4/tcp.c Sun Mar 25 11:37:41 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.140.2.15 2000/10/06 23:29:33 davem Exp $ + * Version: $Id: tcp.c,v 1.140.2.16 2001/01/04 05:28:46 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1619,6 +1619,7 @@ struct wait_queue wait = { current, NULL }; struct open_request *req; + current->task_exclusive = 1; add_wait_queue(sk->sleep, &wait); for (;;) { current->state = TASK_INTERRUPTIBLE; @@ -1632,6 +1633,8 @@ break; } current->state = TASK_RUNNING; + wmb(); + current->task_exclusive = 0; remove_wait_queue(sk->sleep, &wait); return req; } @@ -1776,6 +1779,9 @@ return -EFAULT; len = min(len, sizeof(int)); + + if(len < 0) + return -EINVAL; switch(optname) { case TCP_MAXSEG: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.2.18/net/ipv4/tcp_input.c Sun Mar 25 11:28:40 2001 +++ linux/net/ipv4/tcp_input.c Sun Mar 25 11:37:41 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.164.2.18 2000/12/08 20:29:33 davem Exp $ + * Version: $Id: tcp_input.c,v 1.164.2.21 2001/03/06 05:39:39 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -246,26 +246,22 @@ } -static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq) +/* Check segment sequence number for validity. + * + * Segment controls are considered valid, if the segment + * fits to the window after truncation to the window. Acceptability + * of data (and SYN, FIN, of course) is checked separately. + * See tcp_data_queue(), for example. + * + * Also, controls (RST is main one) are accepted using last_ack_sent instead + * of RCV.NXT. Peer still did not advance his SND.UNA when we + * delayed ACK, so that hisSND.UNA<=last_ack_sent. + * (borrowed from freebsd) + */ +static inline int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq) { - u32 end_window = tp->rcv_wup + tp->rcv_wnd; - - if (tp->rcv_wnd && - after(end_seq, tp->rcv_nxt) && - before(seq, end_window)) - return 1; - if (seq != end_window) - return 0; - return (seq == end_seq); -} - -/* This functions checks to see if the tcp header is actually acceptable. */ -extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq) -{ - if (seq == tp->rcv_nxt) - return (tp->rcv_wnd || (end_seq == seq)); - - return __tcp_sequence(tp, seq, end_seq); + return !before(end_seq, tp->last_ack_sent) && + !after(seq, tp->rcv_nxt + tcp_receive_window(tp)); } /* When we get a reset we do this. */ @@ -1415,6 +1411,11 @@ if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { /* Ok. In sequence. */ queue_and_out: + if (tcp_receive_window(tp) == 0) + goto out_of_window; + + /* We know it is in window now too. */ + dst_confirm(sk->dst_cache); __skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; @@ -1441,6 +1442,8 @@ /* A retransmit, 2nd most common case. Force an imediate ack. */ SOCK_DEBUG(sk, "retransmit received: seq %X\n", TCP_SKB_CB(skb)->seq); tcp_enter_quickack_mode(tp); +out_of_window: + tp->delayed_acks++; kfree_skb(skb); return; } @@ -1454,6 +1457,16 @@ goto queue_and_out; } + /* Out of window. F.e. zero window probe. + * + * Note: it is highly possible that we may open window and enqueue + * this segment now. However, this will be known only after we queue + * it, which will result in queue full of successive 1 byte BSD + * window probes, it is SWS in fact. So, always reject it and send ACK. + */ + if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt+tcp_receive_window(tp))) + goto out_of_window; + /* Ok. This is an out_of_order segment, force an ack. */ tp->delayed_acks++; tcp_enter_quickack_mode(tp); @@ -1671,6 +1684,9 @@ if (after(tp->copied_seq, ptr)) return; + if (before(ptr, tp->rcv_nxt)) + return; + /* Do we already have a newer (or duplicate) urgent pointer? */ if (tp->urg_data && !after(ptr, tp->urg_seq)) return; @@ -1689,8 +1705,10 @@ * as data, nor can we alter copied_seq until this data arrives * or we break the sematics of SIOCATMARK (and thus sockatmark()) */ - if (tp->urg_seq == tp->copied_seq) - tp->copied_seq++; /* Move the copied sequence on correctly */ + if (tp->urg_seq == tp->copied_seq && tp->urg_data && + !sk->urginline && + tp->copied_seq != tp->rcv_nxt) + tp->copied_seq++; tp->urg_data = URG_NOTYET; tp->urg_seq = ptr; @@ -1709,7 +1727,7 @@ /* Do we wait for any urgent data? - normally not... */ if (tp->urg_data == URG_NOTYET) { - u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4); + u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4) - th->syn; /* Is the urgent pointer pointing into this packet? */ if (ptr < len) { @@ -2197,6 +2215,7 @@ tp->snd_wnd = htons(th->window); tp->snd_wl1 = TCP_SKB_CB(skb)->seq; tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq; + tp->syn_seq = TCP_SKB_CB(skb)->seq; tp->fin_seq = TCP_SKB_CB(skb)->seq; tcp_set_state(sk, TCP_ESTABLISHED); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.2.18/net/ipv4/tcp_ipv4.c Sun Mar 25 11:28:40 2001 +++ linux/net/ipv4/tcp_ipv4.c Sun Mar 25 11:37:41 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.175.2.17 2000/10/31 22:42:58 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.175.2.18 2001/02/02 01:27:08 davem Exp $ * * IPv4 specific functions * @@ -1109,6 +1109,8 @@ struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4); struct sock *sk; + if (ntohs(iph->tot_len) - iph->ihl*4 < sizeof(struct tcphdr)) + return 0; sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest, skb->dev->ifindex); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.2.18/net/ipv4/udp.c Sun Mar 25 11:12:46 2001 +++ linux/net/ipv4/udp.c Sun Mar 25 11:37:41 2001 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.66.2.4 2000/03/10 00:16:05 davem Exp $ + * Version: $Id: udp.c,v 1.66.2.6 2001/02/02 01:27:09 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -159,7 +159,7 @@ next: } result = best; - for(;; result += UDP_HTABLE_SIZE) { + for(i = 0; i < (1 << 16)/UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & @@ -167,6 +167,8 @@ if (!udp_lport_inuse(result)) break; } + if (i >= (1 << 16) / UDP_HTABLE_SIZE) + goto fail; gotit: udp_port_rover = snum = result; } else { @@ -1044,6 +1046,8 @@ struct udphdr *uh = (struct udphdr *)(skb->nh.raw + iph->ihl*4); struct sock *sk; + if (ntohs(iph->tot_len) - iph->ihl*4 < sizeof(struct udphdr)) + return 0; sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev->ifindex); if (!sk) return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.2.18/net/ipv6/ipv6_sockglue.c Sun Mar 25 11:12:47 2001 +++ linux/net/ipv6/ipv6_sockglue.c Sun Mar 25 11:37:41 2001 @@ -230,6 +230,10 @@ if (optlen == 0) goto update; + + retv = -EINVAL; + if(optlen > 1024) + break; opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); retv = -ENOBUFS; @@ -359,6 +363,8 @@ return -ENOPROTOOPT; if (get_user(len, optlen)) return -EFAULT; + if(len < 0) + return -EINVAL; switch (optname) { case IPV6_PKTOPTIONS: { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipv6/raw.c linux/net/ipv6/raw.c --- v2.2.18/net/ipv6/raw.c Sun Mar 25 11:12:47 2001 +++ linux/net/ipv6/raw.c Sun Mar 25 11:37:41 2001 @@ -492,6 +492,8 @@ case ICMPV6_FILTER: if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; if (len > sizeof(struct icmp6_filter)) len = sizeof(struct icmp6_filter); if (put_user(len, optlen)) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.2.18/net/ipx/af_ipx.c Sun Mar 25 11:28:40 2001 +++ linux/net/ipx/af_ipx.c Sun Mar 25 11:37:41 2001 @@ -1769,6 +1769,10 @@ return (-EFAULT); len = min(len, sizeof(int)); + + if(len < 0) + return -EINVAL; + if(put_user(len, optlen)) return (-EFAULT); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.2.18/net/irda/af_irda.c Sun Mar 25 11:12:48 2001 +++ linux/net/irda/af_irda.c Sun Mar 25 11:37:41 2001 @@ -1842,6 +1842,9 @@ if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch (optname) { case IRLMP_ENUMDEVICES: /* Tell IrLMP we want to be notified */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.2.18/net/netrom/af_netrom.c Sun Mar 25 11:12:47 2001 +++ linux/net/netrom/af_netrom.c Sun Mar 25 11:37:41 2001 @@ -407,6 +407,9 @@ if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch (optname) { case NETROM_T1: val = sk->protinfo.nr->t1 / HZ; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/netsyms.c linux/net/netsyms.c --- v2.2.18/net/netsyms.c Sun Mar 25 11:28:40 2001 +++ linux/net/netsyms.c Sun Mar 25 11:37:41 2001 @@ -208,7 +208,7 @@ /* Needed by unix.o */ EXPORT_SYMBOL(scm_fp_dup); -EXPORT_SYMBOL(max_files); +EXPORT_SYMBOL(files_stat); EXPORT_SYMBOL(do_mknod); EXPORT_SYMBOL(memcpy_toiovec); EXPORT_SYMBOL(csum_partial); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.2.18/net/rose/af_rose.c Sun Mar 25 11:12:47 2001 +++ linux/net/rose/af_rose.c Sun Mar 25 11:37:41 2001 @@ -471,6 +471,9 @@ if (get_user(len, optlen)) return -EFAULT; + + if (len < 0) + return -EINVAL; switch (optname) { case ROSE_DEFER: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/sched/cls_u32.c linux/net/sched/cls_u32.c --- v2.2.18/net/sched/cls_u32.c Sun Mar 25 11:12:48 2001 +++ linux/net/sched/cls_u32.c Sun Mar 25 11:37:41 2001 @@ -254,7 +254,7 @@ do { if (++tp_c->hgenerator == 0x7FF) tp_c->hgenerator = 1; - } while (i>0 && u32_lookup_ht(tp_c, (tp_c->hgenerator|0x800)<<20)); + } while (--i>0 && u32_lookup_ht(tp_c, (tp_c->hgenerator|0x800)<<20)); return i > 0 ? (tp_c->hgenerator|0x800)<<20 : 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/socket.c linux/net/socket.c --- v2.2.18/net/socket.c Sun Mar 25 11:28:40 2001 +++ linux/net/socket.c Sun Mar 25 11:37:41 2001 @@ -1048,7 +1048,10 @@ { int err; struct socket *sock; - + + if(optlen < 0) + return -EINVAL; + lock_kernel(); if ((sock = sockfd_lookup(fd, &err))!=NULL) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/sunrpc/Makefile linux/net/sunrpc/Makefile --- v2.2.18/net/sunrpc/Makefile Sun Mar 25 11:12:47 2001 +++ linux/net/sunrpc/Makefile Sun Mar 25 11:37:41 2001 @@ -11,7 +11,7 @@ O_OBJS := clnt.o xprt.o sched.o \ auth.o auth_null.o auth_unix.o \ svc.o svcsock.o svcauth.o \ - pmap_clnt.o xdr.o sysctl.o + pmap_clnt.o ping.o xdr.o sysctl.o OX_OBJS := sunrpc_syms.o ifeq ($(CONFIG_PROC_FS),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.2.18/net/sunrpc/clnt.c Sun Mar 25 11:28:40 2001 +++ linux/net/sunrpc/clnt.c Sun Mar 25 11:37:41 2001 @@ -55,8 +55,8 @@ static void call_refreshresult(struct rpc_task *task); static void call_timeout(struct rpc_task *task); static void call_reconnect(struct rpc_task *task); -static u32 * call_header(struct rpc_task *task); -static u32 * call_verify(struct rpc_task *task); +static void call_ping(struct rpc_task *task); +static void call_pingresult(struct rpc_task *task); /* @@ -487,7 +487,7 @@ /* Encode header and provided arguments */ encode = rpcproc_encode(clnt, task->tk_msg.rpc_proc); - if (!(p = call_header(task))) { + if (!(p = rpc_call_header(task))) { printk(KERN_INFO "RPC: call_header failed, exit EIO\n"); rpc_exit(task, -EIO); } else @@ -592,11 +592,10 @@ task->tk_action = call_reconnect; break; } - /* - * Sleep and dream of an open connection - */ - task->tk_timeout = 5 * HZ; - rpc_sleep_on(&xprt->sending, task, NULL, NULL); + if (RPCXPRT_SUPERCONGESTED(clnt->cl_xprt)) { + task->tk_action = call_ping; + break; + } case -ENOMEM: case -EAGAIN: task->tk_action = call_transmit; @@ -620,6 +619,7 @@ { struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; + int major = 0; if (req) { struct rpc_timeout *to = &req->rq_timeout; @@ -644,16 +644,7 @@ rpc_exit(task, -EIO); return; } - - if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) { - task->tk_flags |= RPC_CALL_MAJORSEEN; - printk(KERN_NOTICE "%s: server %s not responding, timed out\n", - clnt->cl_protname, clnt->cl_server); - } else if (clnt->cl_chatty) { - printk(KERN_NOTICE "%s: server %s not responding, still trying\n", - clnt->cl_protname, clnt->cl_server); - } - + major = 1; if (clnt->cl_autobind) clnt->cl_port = 0; @@ -666,6 +657,8 @@ } else if (clnt->cl_xprt->stream && !xprt_connected(clnt->cl_xprt)) { task->tk_action = call_reconnect; clnt->cl_stats->rpcretrans++; + } else if (major && RPCXPRT_SUPERCONGESTED(clnt->cl_xprt)) { + task->tk_action = call_ping; } else { task->tk_action = call_transmit; clnt->cl_stats->rpcretrans++; @@ -687,21 +680,20 @@ dprintk("RPC: %4d call_decode (status %d)\n", task->tk_pid, task->tk_status); - if (clnt->cl_chatty && (task->tk_flags & RPC_CALL_MAJORSEEN)) { - printk(KERN_NOTICE "%s: server %s OK\n", - clnt->cl_protname, clnt->cl_server); - task->tk_flags &= ~RPC_CALL_MAJORSEEN; - } - if (task->tk_status < 12) { - printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", - clnt->cl_protname, task->tk_status); - rpc_exit(task, -EIO); + if (!clnt->cl_softrtry) { + task->tk_action = call_transmit; + clnt->cl_stats->rpcretrans++; + } else { + printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", + clnt->cl_protname, task->tk_status); + rpc_exit(task, -EIO); + } return; } /* Verify the RPC header */ - if (!(p = call_verify(task))) + if (!(p = rpc_call_verify(task))) return; /* @@ -760,8 +752,8 @@ /* * Call header serialization */ -static u32 * -call_header(struct rpc_task *task) +u32 * +rpc_call_header(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; struct rpc_xprt *xprt = clnt->cl_xprt; @@ -781,10 +773,61 @@ } /* + * Ping a non-responding server + */ +static void +call_ping(struct rpc_task *task) +{ + task->tk_action = call_pingresult; + rpc_ping(task); +} + +/* + * Interpret the result from ping + */ +static void +call_pingresult(struct rpc_task *task) +{ + struct rpc_clnt *clnt = task->tk_client; + struct rpc_xprt *xprt = clnt->cl_xprt; + int status = task->tk_status; + + task->tk_status = 0; + if (status >= 0) { + task->tk_action = call_transmit; + return; + } + switch(status) { + case -ECONNREFUSED: + case -ENOTCONN: + if (clnt->cl_autobind || !clnt->cl_port) { + clnt->cl_port = 0; + task->tk_action = call_bind; + break; + } + if (xprt->stream) { + task->tk_action = call_reconnect; + break; + } + case -ENOMEM: + case -ENOBUFS: + rpc_delay(task, HZ >> 4); + case -ETIMEDOUT: + task->tk_action = call_ping; + break; + default: + if (clnt->cl_chatty) + printk("%s: RPC call returned error %d\n", + clnt->cl_protname, -status); + rpc_exit(task,status); + } +} + +/* * Reply header verification */ -static u32 * -call_verify(struct rpc_task *task) +u32 * +rpc_call_verify(struct rpc_task *task) { u32 *p = task->tk_rqstp->rq_rvec[0].iov_base, n; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/sunrpc/ping.c linux/net/sunrpc/ping.c --- v2.2.18/net/sunrpc/ping.c Wed Dec 31 19:00:00 1969 +++ linux/net/sunrpc/ping.c Sun Mar 25 11:37:41 2001 @@ -0,0 +1,218 @@ +/* + * linux/net/sunrpc/ping.c + * + * Ping routing. + * + * Copyright (C) 2000, Trond Myklebust + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define RPC_SLACK_SPACE 512 /* total overkill */ +#define RPC_PING_DELAY (15*HZ) + +#ifdef RPC_DEBUG +# define RPCDBG_FACILITY RPCDBG_XPRT +#endif + +static void ping_call_reserve(struct rpc_task *); +static void ping_call_allocate(struct rpc_task *); +static void ping_call_encode(struct rpc_task *); +static void ping_call_transmit(struct rpc_task *); +static void ping_call_receive(struct rpc_task *); +static void ping_call_exit(struct rpc_task *); + + +static void +ping_call_reserve(struct rpc_task *task) +{ + dprintk("RPC: %4d, ping_call_reserve\n", task->tk_pid); + task->tk_status = 0; + task->tk_action = ping_call_allocate; + task->tk_timeout = task->tk_client->cl_timeout.to_resrvval; + xprt_ping_reserve(task); +} + +static void +ping_call_allocate(struct rpc_task *task) +{ + struct rpc_clnt *clnt = task->tk_client; + struct rpc_rqst *req = task->tk_rqstp; + unsigned int bufsiz; + + dprintk("RPC: %4d, ping_call_allocate (status %d)\n", + task->tk_pid, task->tk_status); + + task->tk_action = ping_call_exit; + if (task->tk_status < 0) + return; + + bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc) + RPC_SLACK_SPACE; + if (!(task->tk_buffer = rpc_malloc(task, bufsiz << 1))) { + task->tk_status = -ENOMEM; + return; + } + req->rq_svec[0].iov_base = (void *)task->tk_buffer; + req->rq_svec[0].iov_len = bufsiz; + req->rq_slen = 0; + req->rq_snr = 1; + req->rq_rvec[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz); + req->rq_rvec[0].iov_len = bufsiz; + req->rq_rlen = bufsiz; + req->rq_rnr = 1; + task->tk_action = ping_call_encode; +} + +static void +ping_call_encode(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + u32 *p; + + dprintk("RPC: %4d, ping_call_encode (status %d)\n", + task->tk_pid, task->tk_status); + + if (task->tk_status < 0) { + task->tk_action = ping_call_exit; + return; + } + p = rpc_call_header(task); + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + task->tk_action = ping_call_transmit; +} + +static void +ping_call_transmit(struct rpc_task *task) +{ + dprintk("RPC: %4d, ping_call_transmit\n", task->tk_pid); + task->tk_action = ping_call_receive; + xprt_transmit(task); +} + +static void +ping_call_receive(struct rpc_task *task) +{ + struct rpc_clnt *clnt = task->tk_client; + struct rpc_xprt *xprt = clnt->cl_xprt; + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_timeout *to = &req->rq_timeout; + u32 *p; + + dprintk("RPC: %4d, ping_call_receive (status %d)\n", + task->tk_pid, task->tk_status); + + if (task->tk_status >= 0) + p = rpc_call_verify(task); + + task->tk_action = ping_call_exit; + + if (task->tk_status >= 0 || task->tk_status == -EACCES) { + task->tk_status = 0; + if (xprt_norespond(xprt)) { + if (clnt->cl_chatty) + printk(KERN_NOTICE "%s: server %s OK\n", + clnt->cl_protname, clnt->cl_server); + xprt_clear_norespond(xprt); + } + return; + } + + switch (task->tk_status) { + case -ENOTCONN: + break; + case -ENOMEM: + case -EAGAIN: + case -ECONNREFUSED: + case -ETIMEDOUT: + if (!xprt_adjust_timeout(to)) { + task->tk_status = 0; + task->tk_action = ping_call_transmit; + break; + } + default: + if (clnt->cl_softrtry) { + task->tk_status = -EIO; + break; + } + if (clnt->cl_chatty) { + if (!xprt_test_and_set_norespond(xprt)) { + printk(KERN_NOTICE + "%s: server %s is not responding\n", + clnt->cl_protname, clnt->cl_server); + } else { + printk(KERN_NOTICE + "%s: server %s still not responding\n", + clnt->cl_protname, clnt->cl_server); + } + } + rpc_delay(task, RPC_PING_DELAY); + } +} + +static void +ping_call_exit(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; + + dprintk("RPC: %4d, ping_call_exit (status %d)\n", + task->tk_pid, task->tk_status); + + task->tk_action = NULL; + xprt_ping_release(task); + + /* Sigh. rpc_delay() clears task->tk_status */ + if (task->tk_status == 0 && xprt_norespond(xprt)) + task->tk_status = -ETIMEDOUT; + + xprt_clear_pinging(xprt); + rpc_wake_up_status(&xprt->pingwait, task->tk_status); +} + +void +rpc_ping(struct rpc_task *task) +{ + struct rpc_clnt *clnt = task->tk_client; + struct rpc_xprt *xprt = clnt->cl_xprt; + struct rpc_task *child; + struct rpc_message msg = {0, NULL, NULL, NULL}; + + dprintk("RPC: %4d, rpc_ping\n", task->tk_pid); + + again: + if (xprt_test_and_set_pinging(xprt)) { + rpc_sleep_on(&xprt->pingwait, task, NULL, 0); + if (!xprt_pinging(xprt)) { + rpc_wake_up_task(task); + goto again; + } + dprintk("RPC: %4d, rpc_ping, waiting on completion\n", + task->tk_pid); + return; + } + + child = rpc_new_child(clnt, task); + if (!child) { + dprintk("RPC: %4d, rpc_ping, failed to create child process\n", + task->tk_pid); + xprt_clear_pinging(xprt); + rpc_wake_up_status(&xprt->pingwait, -ENOMEM); + task->tk_status = -ENOMEM; + return; + } + rpc_call_setup(child, &msg, 0); + child->tk_action = ping_call_reserve; + + dprintk("RPC: %4d, rpc_ping, running child process %4d\n", + task->tk_pid, child->tk_pid); + rpc_run_child(task, child, NULL); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.2.18/net/sunrpc/sched.c Sun Mar 25 11:28:40 2001 +++ linux/net/sunrpc/sched.c Sun Mar 25 11:37:42 2001 @@ -259,7 +259,7 @@ printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n"); return; } - task->tk_running = 1; + rpc_set_running(task); if (RPC_IS_ASYNC(task)) { if (RPC_IS_SLEEPING(task)) { int status; @@ -267,12 +267,13 @@ if (status < 0) { printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); task->tk_status = status; - } else - task->tk_sleeping = 0; + return; + } + rpc_clear_sleeping(task); + wake_up(&rpciod_idle); } - wake_up(&rpciod_idle); } else { - task->tk_sleeping = 0; + rpc_clear_sleeping(task); wake_up(&task->tk_wait); } } @@ -287,7 +288,7 @@ if (RPC_IS_ACTIVATED(task)) return; task->tk_active = 1; - task->tk_sleeping = 1; + rpc_set_sleeping(task); __rpc_make_runnable(task); } @@ -327,7 +328,7 @@ /* Mark the task as being activated if so needed */ if (!RPC_IS_ACTIVATED(task)) { task->tk_active = 1; - task->tk_sleeping = 1; + rpc_set_sleeping(task); } status = __rpc_add_wait_queue(q, task); @@ -335,7 +336,7 @@ printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); task->tk_status = status; } else { - task->tk_running = 0; + rpc_clear_running(task); task->tk_callback = action; __rpc_add_timer(task, timer); } @@ -609,21 +610,15 @@ /* * Check whether task is sleeping. - * Note that if the task goes to sleep in tk_action, - * and the RPC reply arrives before we get here, it will - * have state RUNNING, but will still be on schedq. - * 27/9/99: The above has been attempted fixed by - * introduction of task->tk_sleeping. */ spin_lock_irqsave(&rpc_queue_lock, oldflags); if (!RPC_IS_RUNNING(task)) { - task->tk_sleeping = 1; + rpc_set_sleeping(task); if (RPC_IS_ASYNC(task)) { spin_unlock_irqrestore(&rpc_queue_lock, oldflags); return 0; } - } else - task->tk_sleeping = 0; + } spin_unlock_irqrestore(&rpc_queue_lock, oldflags); while (RPC_IS_SLEEPING(task)) { @@ -689,18 +684,23 @@ int rpc_execute(struct rpc_task *task) { + int status = -EIO; if (rpc_inhibit) { printk(KERN_INFO "RPC: execution inhibited!\n"); - return -EIO; + goto out_release; } - task->tk_running = 1; if (task->tk_active) { printk(KERN_ERR "RPC: active task was run twice!\n"); - return -EWOULDBLOCK; + goto out_err; } task->tk_active = 1; + rpc_set_running(task); return __rpc_execute(task); + out_release: + rpc_release_task(task); + out_err: + return status; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c --- v2.2.18/net/sunrpc/svcsock.c Sun Mar 25 11:28:40 2001 +++ linux/net/sunrpc/svcsock.c Sun Mar 25 11:37:42 2001 @@ -773,7 +773,6 @@ "svc_recv: service %p, wait queue active!\n", rqstp); -again: /* Initialize the buffers */ rqstp->rq_argbuf = rqstp->rq_defbuf; rqstp->rq_resbuf = rqstp->rq_defbuf; @@ -818,7 +817,7 @@ /* No data, incomplete (TCP) read, or accept() */ if (len == 0 || len == -EAGAIN) { svc_sock_release(rqstp); - goto again; + return -EAGAIN; } rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c --- v2.2.18/net/sunrpc/xprt.c Sun Mar 25 11:28:40 2001 +++ linux/net/sunrpc/xprt.c Sun Mar 25 11:37:42 2001 @@ -1010,7 +1010,8 @@ switch (sk->state) { case TCP_ESTABLISHED: - xprt_set_connected(xprt); + if (xprt_test_and_set_connected(xprt)) + break; if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); rpc_wake_up(&xprt->reconn); @@ -1045,16 +1046,14 @@ if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE)) return; - spin_lock_irqsave(&xprt_sock_lock, oldflags); - if (xprt->write_space) - goto out_unlock; - - xprt->write_space = 1; + if (xprt_test_and_set_wspace(xprt)) + goto out; + spin_lock_irqsave(&xprt_sock_lock, oldflags); if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); - out_unlock: spin_unlock_irqrestore(&xprt_sock_lock, oldflags); + out: wake_up_interruptible(sk->sleep); } @@ -1073,16 +1072,14 @@ if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE)) return; - spin_lock_irqsave(&xprt_sock_lock, oldflags); - if (xprt->write_space) - goto out_unlock; - - xprt->write_space = 1; + if (xprt_test_and_set_wspace(xprt)) + goto out; + spin_lock_irqsave(&xprt_sock_lock, oldflags); if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); - out_unlock: spin_unlock_irqrestore(&xprt_sock_lock, oldflags); + out: wake_up_interruptible(sk->sleep); } @@ -1115,8 +1112,10 @@ { struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; struct rpc_rqst *req = task->tk_rqstp; + unsigned long oldflags; xprt_delete_tcp_timer(xprt); + spin_lock_irqsave(&xprt_sock_lock, oldflags); if (xprt->snd_task && xprt->snd_task != task) { dprintk("RPC: %4d TCP write queue full (task %d)\n", task->tk_pid, xprt->snd_task->tk_pid); @@ -1130,6 +1129,7 @@ #endif req->rq_bytes_sent = 0; } + spin_unlock_irqrestore(&xprt_sock_lock, oldflags); return xprt->snd_task == task; } @@ -1142,9 +1142,12 @@ struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; if (xprt->snd_task && xprt->snd_task == task) { + unsigned long oldflags; + spin_lock_irqsave(&xprt_sock_lock, oldflags); xprt->snd_task = NULL; if (!rpc_wake_up_next(&xprt->sending) && xprt->stream) xprt_add_tcp_timer(xprt, RPCXPRT_TIMEOUT); + spin_unlock_irqrestore(&xprt_sock_lock, oldflags); } } @@ -1209,7 +1212,7 @@ if (!xprt->inet) break; - xprt->write_space = 0; + xprt_clear_wspace(xprt); status = -ENOMEM; if (sock_wspace(xprt->inet) < req->rq_slen + MIN_WRITE_SPACE) break; @@ -1256,20 +1259,12 @@ case -ENOMEM: /* Protect against (udp|tcp)_write_space */ spin_lock_irqsave(&xprt_sock_lock, oldflags); - if (!xprt->write_space) { + if (!xprt_wspace(xprt)) { task->tk_timeout = req->rq_timeout.to_current; rpc_sleep_on(&xprt->sending, task, NULL, NULL); } spin_unlock_irqrestore(&xprt_sock_lock, oldflags); return; - case -EAGAIN: - case -ECONNREFUSED: - case -ENOTCONN: - /* Keep holding the socket if it is blocked */ - if (!xprt->stream) { - rpc_delay(task, HZ>>4); - return; - } default: goto out_release; } @@ -1297,7 +1292,7 @@ dprintk("RPC: %4d xprt_receive\n", task->tk_pid); - req->rq_received= 0; + req->rq_received = 0; task->tk_timeout = 0; rpc_sleep_locked(&xprt->pending, task, NULL, NULL); } @@ -1420,6 +1415,62 @@ } /* + * Reserve a ping RPC call slot. + */ +int +xprt_ping_reserve(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_rqst *req; + + /* We already have an initialized request. */ + if (task->tk_rqstp) + return 0; + if (xprt->shutdown) + task->tk_status = -EIO; + + dprintk("RPC: %4d xprt_ping_reserve cong = %ld cwnd = %ld\n", + task->tk_pid, xprt->cong, xprt->cwnd); + start_bh_atomic(); + if ((req = xprt->free) != NULL) { + xprt->free = req->rq_next; + req->rq_next = NULL; + task->tk_rqstp = req; + xprt_request_init(task, xprt); + } else + task->tk_status = -ENOBUFS; + end_bh_atomic(); + dprintk("RPC: %4d xprt_ping_reserve returns %d\n", + task->tk_pid, task->tk_status); + if (!req) + BUG(); + return task->tk_status; +} + +/* + * Release an RPC call slot + */ +void +xprt_ping_release(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_rqst *req; + + xprt_up_transmit(task); + if (!(req = task->tk_rqstp)) + return; + task->tk_rqstp = NULL; + memset(req, 0, sizeof(*req)); /* mark unused */ + + dprintk("RPC: %4d release request %p\n", task->tk_pid, req); + + start_bh_atomic(); + req->rq_next = xprt->free; + xprt->free = req; + end_bh_atomic(); +} + +/* * Set default timeout parameters */ void @@ -1490,6 +1541,7 @@ xprt->sending = RPC_INIT_WAITQ("xprt_sending"); xprt->backlog = RPC_INIT_WAITQ("xprt_backlog"); xprt->reconn = RPC_INIT_WAITQ("xprt_reconn"); + xprt->pingwait = RPC_INIT_WAITQ("xprt_pingwait"); /* initialize free list */ for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.2.18/net/unix/af_unix.c Sun Mar 25 11:28:40 2001 +++ linux/net/unix/af_unix.c Sun Mar 25 11:37:42 2001 @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.76.2.5 2000/10/17 09:08:37 davem Exp $ + * Version: $Id: af_unix.c,v 1.76.2.6 2001/01/04 05:28:48 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. @@ -417,7 +417,7 @@ { struct sock *sk; - if (atomic_read(&unix_nr_socks) >= 2*max_files) + if (atomic_read(&unix_nr_socks) >= 2*files_stat.max_files) return NULL; MOD_INC_USE_COUNT; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.2.18/net/x25/af_x25.c Sun Mar 25 11:28:40 2001 +++ linux/net/x25/af_x25.c Sun Mar 25 11:37:42 2001 @@ -389,6 +389,9 @@ if (get_user(len, optlen)) return -EFAULT; + if (len < 0) + return -EINVAL; + switch (optname) { case X25_QBITINCL: val = sk->protinfo.x25->qbitincl; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/scripts/Configure linux/scripts/Configure --- v2.2.18/scripts/Configure Sun Mar 25 11:13:33 2001 +++ linux/scripts/Configure Sun Mar 25 11:37:42 2001 @@ -422,7 +422,18 @@ function string () { old=$(eval echo "\${$2}") def=${old:-$3} - readln "$1 ($2) [$def] " "$def" "$old" + while :; do + if [ "$old" = "?" ]; then + readln "$1 ($2) [$def] " "$def" "" + else + readln "$1 ($2) [$def] " "$def" "$old" + fi + if [ "$ans" = "?" ]; then + help "$2" + else + break + fi + done define_string "$2" "$ans" } # diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/scripts/kwhich linux/scripts/kwhich --- v2.2.18/scripts/kwhich Sun Mar 25 11:28:40 2001 +++ linux/scripts/kwhich Sun Mar 25 11:37:42 2001 @@ -7,7 +7,7 @@ exit 1 fi -IFS=: +IFS=":$IFS" for cmd in $* do for path in $PATH diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c --- v2.2.18/scripts/lxdialog/checklist.c Sun Mar 25 11:13:33 2001 +++ linux/scripts/lxdialog/checklist.c Sun Mar 25 11:37:42 2001 @@ -51,6 +51,10 @@ mvwaddch(win, choice, item_x, item[0]); wattrset (win, selected ? item_selected_attr : item_attr); waddstr (win, (char *)item+1); + if (selected) { + wmove (win, choice, check_x+1); + wrefresh (win); + } } /* @@ -104,8 +108,8 @@ print_button (dialog, "Select", y, x, selected == 0); print_button (dialog, " Help ", y, x + 14, selected == 1); - wmove(dialog, y, x+1 + 14*selected); - wrefresh (dialog); + /* wmove(dialog, y, x+1 + 14*selected); + wrefresh (dialog);*/ } /* @@ -215,7 +219,7 @@ print_buttons(dialog, height, width, 0); while (key != ESC) { - key = wgetch (dialog); + key = wgetch (list); for (i = 0; i < max_choice; i++) if (toupper(key) == toupper(items[(scroll+i)*3+1][0])) @@ -245,7 +249,7 @@ print_arrows(dialog, choice, item_no, scroll, box_y, box_x + check_x + 5, list_height); - wrefresh (dialog); + wnoutrefresh (dialog); continue; /* wait for another key press */ } else @@ -273,7 +277,7 @@ print_arrows(dialog, choice, item_no, scroll, box_y, box_x + check_x + 5, list_height); - wrefresh (dialog); + wnoutrefresh (dialog); continue; /* wait for another key press */ } else @@ -288,7 +292,7 @@ print_item (list, items[(scroll + choice) * 3 + 1], status[scroll + choice], choice, TRUE); wnoutrefresh (list); - wrefresh (dialog); + wnoutrefresh (dialog); } continue; /* wait for another key press */ } @@ -306,7 +310,7 @@ ? 1 : (button > 1 ? 0 : button); print_buttons(dialog, height, width, button); - wrefresh (dialog); + wnoutrefresh (dialog); break; case 'S': case 's': @@ -329,7 +333,7 @@ } } wnoutrefresh (list); - wrefresh (dialog); + wnoutrefresh (dialog); for (i = 0; i < item_no; i++) { if (status[i]) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/scripts/lxdialog/menubox.c linux/scripts/lxdialog/menubox.c --- v2.2.18/scripts/lxdialog/menubox.c Sun Mar 25 11:13:33 2001 +++ linux/scripts/lxdialog/menubox.c Sun Mar 25 11:37:42 2001 @@ -91,6 +91,10 @@ wattrset (win, selected ? tag_key_selected_attr : tag_key_attr); mvwaddch(win, choice, item_x+j, menu_item[j]); } + if (selected) { +wmove (win, choice, item_x+1); +wrefresh (win); + } } /* @@ -267,9 +271,11 @@ box_y, box_x+item_x+1, menu_height); print_buttons (dialog, height, width, 0); + wmove (menu, choice, item_x+1); + wrefresh (menu); while (key != ESC) { - key = wgetch(dialog); + key = wgetch(menu); if (key < 256 && isalpha(key)) key = tolower(key); @@ -372,8 +378,8 @@ print_arrows(dialog, item_no, scroll, box_y, box_x+item_x+1, menu_height); - wnoutrefresh (menu); - wrefresh (dialog); + wnoutrefresh (dialog); + wrefresh (menu); continue; /* wait for another key press */ } @@ -386,7 +392,7 @@ ? 2 : (button > 2 ? 0 : button); print_buttons(dialog, height, width, button); - wrefresh (dialog); + wrefresh (menu); break; case ' ': case 's': diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/scripts/makelst linux/scripts/makelst --- v2.2.18/scripts/makelst Sun Mar 25 11:13:33 2001 +++ linux/scripts/makelst Sun Mar 25 11:37:42 2001 @@ -2,7 +2,8 @@ # A script to dump mixed source code & assembly # with correct relocations from System.map # Requires the following lines in Rules.make. -# +# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) +# William Stearns #%.lst: %.c # $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $< # $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP) @@ -16,6 +17,6 @@ t3=`grep $t2 $2/System.map` t4=`echo $t3 | gawk '{ print $1 }'` t5=`echo $t1 | gawk '{ print $1 }'` -t6=`echo $t4 - $t5 | sed s/a/A/g | sed s/b/B/g | sed s/c/C/g | sed s/d/D/g | sed s/e/E/g | sed s/f/F/g` +t6=`echo $t4 - $t5 | sed -e s/a/A/g -e s/b/B/g -e s/c/C/g -e s/d/D/g -e s/e/E/g -e s/f/F/g` t7=`( echo ibase=16 ; echo $t6 ) | bc` $3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/scripts/ver_linux linux/scripts/ver_linux --- v2.2.18/scripts/ver_linux Sun Mar 25 11:13:33 2001 +++ linux/scripts/ver_linux Sun Mar 25 11:37:42 2001 @@ -5,28 +5,64 @@ # differ on your system. # PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH -echo '-- Versions installed: (if some fields are empty or looks' -echo '-- unusual then possibly you have very old versions)' +echo 'If some fields are empty or look unusual you may have an old version.' +echo 'Compare to the current minimal requirements in Documentation/Changes.' +echo ' ' + uname -a -insmod -V 2>&1 | awk 'NR==1 {print "Kernel modules ",$NF}' +echo ' ' + echo "Gnu C " `gcc --version` + +make --version 2>&1 | awk -F, '{print $1}' | awk \ + '/GNU Make/{print "Gnu make ",$NF}' + ld -v 2>&1 | awk -F\) '{print $1}' | awk \ - '/BFD/{print "Binutils ",$NF}' -ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed -e 's/\.so$//' \ - | awk -F'[.-]' '{print "Linux C Library " $(NF-2)"."$(NF-1)"."$NF}' -echo -n "Dynamic linker " -ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1 + '/BFD/{print "binutils ",$NF}' + +mount --version | awk -F\- '{print "util-linux ", $NF}' + +insmod -V 2>&1 | awk 'NR==1 {print "modutils ",$NF}' + +tune2fs 2>&1 | grep tune2fs | sed 's/,//' | awk \ +'NR==1 {print "e2fsprogs ", $2}' + +reiserfsck 2>&1 | grep reiserfsprogs | awk \ +'NR==1{print "reiserfsprogs ", $NF}' + +cardmgr -V 2>&1| grep version | awk \ +'NR==1{print "pcmcia-cs ", $3}' + +pppd --version 2>&1| grep version | awk \ +'NR==1{print "PPP ", $3}' + +isdnctrl 2>&1 | grep version | awk \ +'NR==1{print "isdn4k-utils ", $NF}' + +ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed \ +-e 's/\.so$//' | awk -F'[.-]' '{print "Linux C Library " \ +$(NF-2)"."$(NF-1)"."$NF}' + +ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1 | awk \ +'NR==1{print "Dynamic linker (ldd) ", $NF}' + ls -l /usr/lib/lib{g,stdc}++.so 2>/dev/null | awk -F. \ '{print "Linux C++ Library " $4"."$5"."$6}' + ps --version 2>&1 | awk 'NR==1{print "Procps ", $NF}' -mount --version | awk -F\- '{print "Mount ", $NF}' -hostname -V 2>&1 | awk 'NR==1{print "Net-tools ", $NF}' + +ifconfig --version 2>&1 | grep tools | awk \ +'NR==1{print "Net-tools ", $NF}' + # Kbd needs 'loadkeys -h', loadkeys -h 2>&1 | awk \ '(NR==1 && ($3 !~ /option/)) {print "Kbd ", $3}' + # while console-tools needs 'loadkeys -V'. loadkeys -V 2>&1 | awk \ '(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools ", $3}' -expr --v | awk 'NR==1{print "Sh-utils ", $NF}' + +expr --v 2>&1 | awk 'NR==1{print "Sh-utils ", $NF}' + X=`cat /proc/modules | sed -e "s/ .*$//"` echo "Modules Loaded "$X