diff -u --recursive --new-file v2.3.9/linux/CREDITS linux/CREDITS --- v2.3.9/linux/CREDITS Wed Jun 30 13:38:18 1999 +++ linux/CREDITS Tue Jul 6 10:19:57 1999 @@ -163,7 +163,7 @@ D: Various bugfixes and changes to sound drivers S: USA -M: Krzysztof G. Baranowski +N: Krzysztof G. Baranowski E: kgb@manjak.knm.org.pl P: 1024/FA6F16D1 96 D1 1A CF 5F CA 69 EC F9 4F 36 1F 6D 60 7B DA D: Maintainer of the System V file system. @@ -174,6 +174,17 @@ S: 62-300 Wrzesnia S: Poland +N: Carlos Henrique Bauer +E: chbauer@acm.org +E: bauer@atlas.unisinos.tche.br +D: A test for detection of EPP-1.7 and ECP/EPP parports. +D: Some new sysctl entries for the parport driver. +S: Universidade do Vale do Rio dos Sinos - UNISINOS +S: DSI/IDASI +S: Av. Unisinos, 950 +S: 93022000 Sao Leopoldo RS +S: Brazil + N: Peter Bauer E: 100136.3530@compuserve.com D: Driver for depca-ethernet-board @@ -869,13 +880,11 @@ S: 65760 Eschborn S: Germany -N: Kenji Tsutomu Hollis -E: khollis@bitgate.com -W: http://www.nurk.org/ +N: Kenji Hollis +E: kenji@bitgate.com +W: http://www.bitgate.com/ D: Berkshire PC Watchdog Driver -S: Post Office Box 15 -S: Grants Pass, Oregon 97526 -S: USA +D: Small/Industrial Driver Project N: Nick Holloway E: Nick.Holloway@alfie.demon.co.uk @@ -1660,6 +1669,15 @@ S: 4390 Albany Drive #41A S: San Jose, California 95129 S: USA + +N: Augusto Cesar Radtke +E: bishop@sekure.org +W: http://bishop.sekure.org +D: {copy,get,put}_user calls updates +D: Miscellaneous hacks +S: R. Otto Marquardt, 226 - Garcia +S: 89020-350 Blumenau - Santa Catarina +S: Brazil N: Eric S. Raymond E: esr@thyrsus.com diff -u --recursive --new-file v2.3.9/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.9/linux/Documentation/Changes Fri May 7 09:31:25 1999 +++ linux/Documentation/Changes Thu Jul 1 10:54:31 1999 @@ -191,12 +191,6 @@ users should especially try to use the 2.9.1.0.x releases, as they resolve known issues with glibc2 and binutils-2.8.x releases. - libbfd, libiberty, and /usr/include/bfd.h, which are part of recent -binutils packages, are also required to compile ksymoops. Depending -upon your distribution, this may require you to install both binutils -and binutils-development packages (Debian puts bfd.h in binutils-dev, -for example). - Gnu C ===== diff -u --recursive --new-file v2.3.9/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.9/linux/Documentation/Configure.help Wed Jun 30 13:38:18 1999 +++ linux/Documentation/Configure.help Mon Jul 5 20:37:25 1999 @@ -530,7 +530,7 @@ People with SCSI-only systems should say N here; if unsure say Y. Generic PCI bus-master DMA support -CONFIG_BLK_DEV_IDEDMA +CONFIG_BLK_DEV_IDEDMA_PCI If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and is capable of bus-master DMA operation (most Pentium PCI systems), you will want to say Y here to reduce CPU overhead. You can then use @@ -546,6 +546,26 @@ It is safe to say Y to this question. +Good-Bad DMA Model-Firmware (EXPERIMENTAL) +IDEDMA_NEW_DRIVE_LISTINGS + This test compares both the model and firmware revision for buggy drives + that claim to (U)DMA capable. This is a blanket on/off test with no speed + limit options. Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe; + whereas, many versions of EGCS have a problem and miscompile. + + If in doubt, say N. + +Generic ATA-66 support (DANGEROUS) +CONFIG_IDEDMA_ULTRA_66 + This allows for your Generic IDE control to attempt support for + using ATA-66 or UDMA-66 transfer modes 3/4. If you are not sure what you + are attempting, "DO NOT" even think about this option, unless your + mainboard's chipset is verified. Do not complain to anyone if you + do not know what you are doing and are just playing around. + This option has no known success cases to date. + + Say N, or beware......... + Winbond SL82c105 support CONFIG_BLK_DEV_SL82C105 If you have a Winbond SL82c105 IDE controller, say Y here to enable @@ -562,13 +582,16 @@ improve the usability of some boot managers such as LILO when booting from a drive on an off-board controller. + Requires that all onboard ide controllers be disabled or calling + "pci=reverse" to invert the device scan order. + Note that, if you say Y here, the order of the hd* devices will be rearranged which may require modification of fstab and other files. If in doubt, say N. Use DMA by default when available -CONFIG_IDEDMA_AUTO +CONFIG_IDEDMA_PCI_AUTO Prior to kernel version 2.1.112, Linux used to automatically use DMA for IDE drives and chipsets which support it. Due to concerns about a couple of cases where buggy hardware may have caused damage, @@ -664,7 +687,7 @@ This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. Please read the comments at the top of drivers/block/cy82c693.c @@ -679,7 +702,7 @@ (while running a "cat") provided you enabled "proc" support and set DISPLAY_APOLLO_TIMINGS in via82c586.c - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. If unsure, say N. @@ -693,14 +716,15 @@ onboard chipsets. It also tests for Simplex mode and enables normal dual channel support. - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. Please read the comments at the top of drivers/block/alim15x3.c If unsure, say N. -PROMISE PDC20246 support (EXPERIMENTAL) -CONFIG_BLK_DEV_PDC20246 +PROMISE PDC20246/PDC20262 support +CONFIG_BLK_DEV_PDC202XX + Promise Ultra33 or PDC20246. This driver adds up to 4 more eide devices sharing a single interrupt. This add-on card is a bootable PCI UDMA controller. Since multiple cards can be installed and there are BIOS ROM problems @@ -708,38 +732,49 @@ do not match. Should you be unable to make new BIOS chips with a burner, the driver attempts to dynamic tuning of the chipset at boot-time for max-speed. Ultra33 BIOS 1.25 or new required for more than one card. + This card may require "PDC202XX Special UDMA Feature (EXPERIMENTAL)". - This requires CONFIG_IDEDMA_AUTO to be enabled. - - Please read the comments at the top of drivers/block/pdc202xx.c - - If unsure, say N. - -PROMISE PDC20262 support (EXPERIMENTAL) -CONFIG_BLK_DEV_PDC20262 + Promise Ultra66 or PDC20262. This driver adds up to 4 more eide devices sharing a single interrupt. This add-on card is a bootable PCI UDMA ATA-66 controller. The driver attempts to dynamic tuning of the chipset at boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS 1.11 or newer required. - This requires CONFIG_IDEDMA_AUTO to be enabled. + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. Please read the comments at the top of drivers/block/pdc202xx.c If unsure, say N. +Special UDMA Feature (EXPERIMENTAL) +PDC202XX_FORCE_BURST_BIT + For PDC20246 and PDC20262 Ultra DMA chipsets. + Designed originally for PDC20246/Ultra33 that has BIOS setup failures + when using 3 or more cards. + + Please read the comments at the top of drivers/block/pdc202xx.c + + If unsure, say N. + +Special Mode Feature (DANGEROUS) +PDC202XX_FORCE_MASTER_MODE + For PDC20246 and PDC20262 Ultra DMA chipsets. + This is reserved for possible Hardware RAID 0,1 for the FastTrak Series. + + Say N. + AEC6210 chipset support CONFIG_BLK_DEV_AEC6210 This driver adds up to 4 more eide devices sharing a single interrupt. This add-on card is a bootable PCI UDMA controller. In order to get this card to initialize correctly in some cases, you should include this driver. - This prefers CONFIG_IDEDMA_AUTO to be enabled, regardless. + This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless. Please read the comments at the top of drivers/block/aec6210.c -Intel PIIXn chipsets support (EXPERIMENTAL) +Intel PIIXn chipsets support CONFIG_BLK_DEV_PIIX This driver adds PIO mode setting and tuning for all PIIX IDE controllers by Intel. Since the BIOS can sometimes improperly tune @@ -750,15 +785,31 @@ If unsure, say N. -HPT343 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_HPT343 +PIIXn Tuning support (EXPERIMENTAL) +CONFIG_BLK_DEV_PIIX_TUNING + This driver extension adds DMA mode setting and tuning for all PIIX IDE + controllers by Intel. Since the BIOS can sometimes improperly setup + the device/adapter combination and speed limits, It has become a necessity + to back/forward speed devices as needed. + + Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2 + if the BIOS can to perform this task at INIT. + + If unsure, say N. + +HPT34X chipset support +CONFIG_BLK_DEV_HPT34X This driver adds up to 4 more EIDE devices sharing a single - interrupt. The HPT343 chipset in its current form is a non-bootable - PCI UDMA controller. This driver requires dynamic tuning of the - chipset during the ide-probe at boot. It is reported to support DVD - II drives, by the manufacturer. + interrupt. The HPT343 chipset in its current form is a non-bootable or + HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers. + This driver requires dynamic tuning of the chipset during the ide-probe + at boot. It is reported to support DVD II drives, by the manufacturer. + + Please read the comments at the top of drivers/block/hpt343.c - This requires CONFIG_IDEDMA_AUTO to be enabled. +HPT34X DMA support (DANGEROUS) +CONFIG_BLK_DEV_HPT34X_DMA + This requires CONFIG_IDEDMA_PCI_AUTO to be enabled. Please read the comments at the top of drivers/block/hpt343.c @@ -821,17 +872,17 @@ Say Y if you have an IDE doubler. The driver is enabled at kernel runtime using the "ide=doubler" kernel boot parameter. - Support for PowerMac IDE devices (must also enable IDE) - CONFIG_BLK_DEV_IDE_PMAC - No help for CONFIG_BLK_DEV_IDE_PMAC - - PowerMac IDE DMA support - CONFIG_BLK_DEV_IDEDMA_PMAC - No help for CONFIG_BLK_DEV_IDEDMA_PMAC - - Use DMA by default - CONFIG_PMAC_IDEDMA_AUTO - No help for CONFIG_PMAC_IDEDMA_AUTO +Support for PowerMac IDE devices (must also enable IDE) +CONFIG_BLK_DEV_IDE_PMAC + No help for CONFIG_BLK_DEV_IDE_PMAC + +PowerMac IDE DMA support +CONFIG_BLK_DEV_IDEDMA_PMAC + No help for CONFIG_BLK_DEV_IDEDMA_PMAC + +Use DMA by default +CONFIG_IDEDMA_PMAC_AUTO + No help for CONFIG_IDEDMA_PMAC_AUTO Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE @@ -843,9 +894,21 @@ (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. - RapIDE interface support - CONFIG_BLK_DEV_IDE_RAPIDE - No help for CONFIG_BLK_DEV_IDE_RAPIDE +ICS IDE interface support +CONFIG_BLK_DEV_IDE_ICSIDE + No help for CONFIG_BLK_DEV_IDE_ICSIDE + +ICS DMA support +CONFIG_BLK_DEV_IDEDMA_ICS + No help for CONFIG_BLK_DEV_IDEDMA_ICS + +Use ICS DMA by default +CONFIG_IDEDMA_ICS_AUTO + No help for CONFIG_IDEDMA_ICS_AUTO + +RapIDE interface support +CONFIG_BLK_DEV_IDE_RAPIDE + No help for CONFIG_BLK_DEV_IDE_RAPIDE XT hard disk support CONFIG_BLK_DEV_XD @@ -1611,6 +1674,45 @@ CONFIG_FB_SGIVW SGI Visual Workstation support for framebuffer graphics. +I2O support +CONFIG_I2O + The Intelligent Input/Output (I2O) architecture allows + hardware drivers to be split into two parts: an operating system + specific module called the OSM and an hardware specific module + called the HDM. The OSM can talk to a whole range of HDM's, and + ideally the HDM's are not OS dependent. This allows for the same + driver to be used under different operating systems if the relevant + OSM is in place. If you say Y here, you will get a choice of OSM's + with the following questions. + + This support is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + + If unsure, say N. + +I2O PCI support +CONFIG_I2O_PCI + Build in support for PCI bus I2O interface adapters. Currently this + is the only variety supported. + +I2O Block OSM +CONFIG_I2O_BLOCK + Include support for the I2O Block OSM. The Block OSM presents disk and + other structured block devices to the operating system. + +I2O LAN OSM +CONFIG_I2O_LAN + Include support for the LAN OSM. You will also need to include support + for token ring or fddi if you wish to use token ring or FDDI I2O cards + with this driver. + +I2O SCSI OSM +CONFIG_I2O_SCSI + Allow direct scsi access to scsi devices on a SCSI or FibreChannel I2O + controller. You can use both the SCSI and Block OSM together if you wish. + System V IPC CONFIG_SYSVIPC Inter Process Communication is a suite of library functions and @@ -1977,6 +2079,11 @@ You will get a boot time penguin logo at no additional cost. Please read Documentation/fb/vesafb.txt. If unsure, say Y. +VGA 16-color graphics console +CONFIG_FB_VGA16 + This is the frame buffer device driver for VGA 16 color graphic + cards. Say Y if you have such a card. + Backward compatibility mode for Xpmac CONFIG_FB_COMPAT_XPMAC If you use the Xpmac X server (common with mklinux), you'll need to @@ -2218,12 +2325,12 @@ whenever you want), say M here and read Documentation/modules.txt. 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. + this driver at module load time, take a look at + Documentation/networking/parport.txt. If unsure, say Y. -PC-style hardware +PC-style hardware CONFIG_PARPORT_PC You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style parallel @@ -2236,28 +2343,36 @@ If unsure, say Y. +Use FIFO/DMA if available +CONFIG_PARPORT_PC_FIFO + Many parallel port chipsets provide hardware that can speed up + printing. Say Y here if you want to take advantage of that. + + As well as actually having a FIFO, or DMA capability, the kernel + will need to know which IRQ the parallel port has. By default, + parallel port interrupts will not be used, and so neither will the + FIFO. See Documentation/parport.txt to find out how to specify + which IRQ/DMA to use. + Support foreign hardware CONFIG_PARPORT_OTHER Say Y here if you want to be able to load driver modules to support other non-standard types of parallel ports. This causes a performance loss, so most people say N. -Sun Ultra/AX-style hardware +Sun Ultra/AX-style hardware CONFIG_PARPORT_AX Say Y here if you need support for the parallel port hardware on Sun Ultra/AX machines. This code is also available as a module (say M), called parport_ax.o. If in doubt, saying N is the safe plan. -Plug and Play support -CONFIG_PNP - Plug and Play support allows the kernel to automatically configure - some peripheral devices. Say Y to enable PnP. - -Auto-probe for parallel devices -CONFIG_PNP_PARPORT - Some IEEE-1284 conforming parallel-port devices can identify - themselves when requested. Say Y to enable this feature, or M to - compile it as a module (parport_probe.o). If in doubt, say N. +IEEE1284 transfer modes +CONFIG_PARPORT_1284 + If you have a printer that supports status readback or device ID, or + want to use a device that uses enhanced parallel port transfer modes + such as EPP and ECP, say Y here to enable advanced IEEE 1284 + transfer modes. Also say Y if you want device ID information to + appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N. Enable loadable module support CONFIG_MODULES @@ -5160,6 +5275,17 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +Aironet Arlan 655 & IC2200 DS support +CONFIG_ARLAN + Aironet makes Arlan. www.aironet.com. Uses www.Telxon.com chip, which is + used on several similar cards. Driver is tested on 655 and IC2200 series. + Look for http://www.ylenurme.ee/~elmer/655/ for latest information. + Driver is build as two modules, arlan and arlan-proc. The later is /proc + interface and not needed most of time. + On some computers the card ends up in non-valid state after some time. + Use a ping-reset script to clear it. + + LAPB over Ethernet driver CONFIG_LAPBETHER This is a driver for a pseudo device (typically called /dev/lapb0) @@ -5286,6 +5412,15 @@ module, say M here and read Documentation/modules.txt. If you don't know what to use this for, you don't need it. +Sealevel Systems 4021 support +CONFIG_SEALEVEL_4021 + This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to do that, say M here. The module will be called + sealevel.o. + Frame Relay (DLCI) support CONFIG_DLCI This is support for the frame relay protocol; frame relay is a fast @@ -5692,6 +5827,40 @@ you say N, the PPP support will not be included in the driver (saves about 16 KB of kernel memory). +Cyclom 2X(tm) multiprotocol cards +CONFIG_CYCLADES_SYNC + Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and + http://www.cyclades.com.br; to browse the WWW, you need to have + access to a machine on the Internet that has a program like lynx or + netscape) is an intelligent multiprotocol WAN adapter with data + transfer rates up to 512 Kbps). These cards support the X.25 and SNA + related protocols. If you have one or more of these cards, say Y to + this option. The next questions will ask you about the protocols you + want the driver to support (for now only X.25 is supported). + + While no documentation is available at this time please grab the + wanconfig tarball in http://www.conectiva.com.br/~acme/cycsyn-devel + (with minor changes to make it compile with the current wanrouter + include files; efforts are being made to use the original package + available at ftp://ftp.sangoma.com). + + Feel free to contact me or the cycsyn-devel mailing list at + acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for + aditional details, I hope to have documentation available as soon + as possible. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cyclomx.o. For general information about + modules read Documentation/modules.txt. + +Cyclom 2X X.25 support +CONFIG_CYCLOMX_X25 + Say Y to this option if you are planning to connect a Cyclom 2X card + to an X.25 network. + If you say N, the X.25 support will not be included in the driver + (saves about 11 KB of kernel memory). + Ethernet (10 or 100Mbit) CONFIG_NET_ETHERNET Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common @@ -5905,7 +6074,7 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called yellowfin.o. -Alteon AceNIC / 3Com 3C985 Gigabit Ethernet support. +Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit Ethernet adapter. The driver allows for using the Jumbo Frame @@ -6663,6 +6832,25 @@ The module will be called ibmtr.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +IBM Olympic chipset PCI adapter support +CONFIG_IBMOL + This is support for all non-Lanstreamer IBM PCI Token Ring Cards. + Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II + Wake On Lan, and PCI 100/16/4 adapters. + + If you have such an adapter, say Y and read the Token-Ring mini-HOWTO, + available via FTP (user:anonymous) from + ftp://metalab.unc/edu/pub/Linux/docs/HOWTO. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will will be called olympic.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + Also read the linux/Documentation/networking/olympic.txt or check the + Linux Token Ring Project site for the latest information at + http://www.linuxtr.net + SysKonnect adapter support CONFIG_SKTR This is support for all SysKonnect Token Ring cards, specifically @@ -8316,6 +8504,16 @@ If you haven't heard about it, it's safe to say N. +Cyclades-Z interrupt mode operation (EXPERIMENTAL) +CONFIG_CYZ_INTR + The Cyclades-Z family of multiport cards allows 2 (two) driver + op modes: polling and interrupt. In polling mode, the driver will + check the status of the Cyclades-Z ports every certain amount of + time (which is called polling cycle and is configurable). In + interrupt mode, it will use an interrupt line (IRQ) in order to check + the status of the Cyclades-Z ports. The default op mode is polling. + If unsure, say N. + Stallion multiport serial support CONFIG_STALDRV Stallion cards give you many serial ports. You would need something @@ -8440,7 +8638,8 @@ corresponding drivers into the kernel. If you want to compile this driver as a module however ( = 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 lp.o. + read Documentation/modules.txt and Documentation/parport.txt. The + module will be called lp.o. If you have several parallel ports, you can specify which ports to use with the "lp" kernel command line option. (Try "man bootparam" @@ -8454,11 +8653,18 @@ If you have more than 3 printers, you need to increase the LP_NO variable in lp.c. -Support IEEE1284 status readback -CONFIG_PRINTER_READBACK - If your printer conforms to IEEE 1284, it may be able to provide a - status indication when you read from it (for example, with `cat - /dev/lp1'). To use this feature, say Y here. +Support for console on line printer +CONFIG_LP_CONSOLE + If you want kernel messages to be printed out as they occur, you + can have a console on the printer. This option adds support for + doing that; to actually get it to happen you need to pass the + option "console=lp" to the kernel at boot time. + + Note that kernel messages can get lost if the printer is out of + paper (or off, or unplugged, or too busy..), but this behaviour + can be changed. See drivers/char/lp.c (do this at your own risk). + + If unsure, say N. Mouse Support (not serial mice) CONFIG_MOUSE @@ -9397,7 +9603,7 @@ after the PnP configuration is finished. To do this, say M here and read Documentation/modules.txt as well as Documentation/sound/README.modules; the module will be called - sound.o. + soundcore.o. I'm told that even without a sound card, you can make your computer say more than an occasional beep, by programming the PC speaker. @@ -10943,6 +11149,11 @@ Choose Y here if you have this FM radio card, and then fill in the port address below. + If you have GemTeks combined (PnP) sound- and radio card you must use + this driver as a module and setup the card with isapnptools. You must + also pass the module a suitable io parameter, 0x248 has been reported + to be used by these cards. + 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 @@ -11119,6 +11330,40 @@ Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is 0x34c, if you haven't changed the jumper setting on the card. +PlanB Video-In for PowerMacs +CONFIG_VIDEO_PLANB + PlanB is the V4L driver for the PowerMac 7x00/8x00 series video + input hardware. If you want to experiment with this, say Y. + Otherwise, or if you don't understand a word, say N. + See http://www.cpu.lu/~mlan/planb.html for more info. + + Saying M will compile this driver as a module (planb.o). + +TerraTec ActiveRadio +CONFIG_RADIO_TERRATEC + Choose Y here if you have this FM radio card, and then fill in the + port address below. (TODO) + + Note: This driver is in its early stages. Right now volume and frequency + control and muting works at least for me, but unfortunately i have not + found anybody who wants to use this card with linux. So if it is this + what YOU are trying to do right now, PLEASE DROP ME A NOTE!! + Rolf Offermanns (rolf@offermanns.de) + + 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-terratec.o. + + BT848 Video For Linux CONFIG_VIDEO_BT848 Support for BT848 based frame grabber/overlay boards. This includes @@ -11165,6 +11410,14 @@ from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +Compaq SMART2 support +CONFIG_BLK_CPQ_DA + This is the driver for Compaq Smart Array controllers. + Everyone using these boards should say Y here. + See "linux/Documentation/cpqarray.txt" for the current list of + boards supported by this driver, and for further information + on the use of this driver. + # # ARM options # @@ -11463,6 +11716,21 @@ If unsure, say Y. +IrPORT IrDA Device Driver +CONFIG_IRPORT_SIR + Say Y here if you want to build support for the IrPORT IrDA device + driver. If you want to compile it as a module, say M here and + read Documentation/modules.txt. IrPORT can be used instead of + IrTTY and sometimes this can be better. One example is if your + IrDA port does not have echo-canceling, which will work OK with + IrPORT since this driver is working in half-duplex mode only. You + don't need to use irattach with IrPORT, but you just insert it + the same way as FIR drivers (insmod irport io=0x3e8 irq=11). + Notice that IrPORT is a SIR device driver which means that speed + is limited to 115200 bps. + + If unsure, say Y. + Winbond W83977AF IrDA Device Driver CONFIG_WINBOND_FIR Say Y here if you want to build IrDA support for the Winbond @@ -11486,6 +11754,13 @@ read Documentation/modules.txt. This chipset is used by the Toshiba Tecra laptops. +Toshiba Type-O IR Port Device Driver +CONFIG_TOSHIBA_FIR + Say Y here if you want to build support for the Toshiba Type-O IR + chipset. If you want to compile it as a module, say M here and + read Documentation/modules.txt. This chipset is used by the Toshiba + Libretto 100CT, and many more laptops. + ESI JetEye PC Dongle CONFIG_ESI_DONGLE Say Y here if you want to build support for the Extended Systems @@ -11523,6 +11798,15 @@ by IrTTY. To activate support for Greenwich dongles you will have to insert "irattach -d girbil" in the /etc/irda/drivers script. +Parallax Litelink dongle +CONFIG_LITELINK_DONGLE + Say Y here if you want to build support for the Parallax Litelink + dongle. If you want to compile it as a module, say M here and read + Documentation/modules.txt. The Parallax dongle attaches to the + normal 9-pin serial port connector, and can currently only be used + by IrTTY. To activate support for Parallax dongles you will have to + insert "irattach -d litelink" in the /etc/irda/drivers script. + VME (Motorola and BVM) support CONFIG_VME Say Y here if you want to build a kernel for a 680x0 based VME @@ -11658,6 +11942,16 @@ CONFIG_USB_ACM This driver allows for devices which support the Abstract Control Model, including many USB-based modems, ISDN adapters, and network adapters. + +Support for user-space parallel port device drivers +CONFIG_PPDEV + Saying Y to this adds support for /dev/parport device nodes. + NB. You have to make them before you can use them: + mknod /dev/parport00 c 99 0 + mknod /dev/parport01 c 99 1 + mknod /dev/parport10 c 99 16 + mknod /dev/parport11 c 99 17 + etc.. # # A couple of things I keep forgetting: diff -u --recursive --new-file v2.3.9/linux/Documentation/SMP.txt linux/Documentation/SMP.txt --- v2.3.9/linux/Documentation/SMP.txt Wed Jun 24 14:30:07 1998 +++ linux/Documentation/SMP.txt Thu Jul 1 10:45:57 1999 @@ -1,7 +1,7 @@ SMP on x86/Linux is now an official feature and is not experimental. Experimental SMP support for other architectures is underway. -Please view linux/Documentation/smp for more information about enabling SMP. +Please view linux/Documentation/smp.txt for more information about enabling SMP. SMP support for Linux with up to 16 processors using the Intel MP specification. diff -u --recursive --new-file v2.3.9/linux/Documentation/cpqarray.txt linux/Documentation/cpqarray.txt --- v2.3.9/linux/Documentation/cpqarray.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/cpqarray.txt Mon Jul 5 19:52:13 1999 @@ -0,0 +1,107 @@ +This driver is for Compaq's SMART2 Intellegent Disk Array Controllers. + +WARNING: +-------- + +This driver comes with NO WARRANTY. It is not officially supported by +Compaq. Do not call technical support. Use at your own risk. + +Supported Cards: +---------------- + +This driver is known to work with the following cards: + + * SMART (EISA) + * SMART-2/E (EISA) + * SMART-2/P + * SMART-2DH + * SMART-2SL + * SMART-221 + * SMART-3100ES + * SMART-3200 + * Integrated Smart Array Controller + * SA 4200 + * SA 4250ES + +It should also work with some really old Disk array adapters, but I am +unable to test against these cards: + + * IDA + * IDA-2 + * IAES + +Installing: +----------- + +You need to build a new kernel to use this device, even if you want to +use a loadable module. + +Apply the patch to a 2.2.x kernel: + +# cd linux +# patch -p1 diff -u --recursive --new-file v2.3.9/linux/Documentation/java.txt linux/Documentation/java.txt --- v2.3.9/linux/Documentation/java.txt Tue Apr 28 14:22:04 1998 +++ linux/Documentation/java.txt Thu Jul 1 10:47:08 1999 @@ -21,7 +21,7 @@ 2) You have to compile BINFMT_MISC either as a module or into the kernel (CONFIG_BINFMT_MISC) and set it up properly. If you choose to compile it as a module, you will have - to insert it manually with modprobe/insmod, as kerneld + to insert it manually with modprobe/insmod, as kmod can not easy be supported with binfmt_misc. Read the file 'binfmt_misc.txt' in this directory to know more about the configuration process. @@ -29,14 +29,15 @@ 3) Add the following configuration items to binfmt_misc (you should really have read binfmt_misc.txt now): support for Java applications: - ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' + ':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:' support for Java Applets: - ':Applet:E::html::/usr/local/java/bin/appletviewer:' + ':Applet:E::html::/usr/bin/appletviewer:' or the following, if you want to be more selective: - ':Applet:M:: in the first line @@ -45,42 +46,300 @@ For the compiled Java programs you need a wrapper script like the following (this is because Java is broken in case of the filename handling), again fix the path names, both in the script and in the - above given configuration string: + above given configuration string. + + You, too, need the little program after the script. Compile like + gcc -O2 -o javaclassname javaclassname.c + and stick it to /usr/local/bin. + + Both the javawrapper shellscript and the javaclassname program + were supplied by Colin J. Watson . ====================== Cut here =================== #!/bin/bash -# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java -CLASS=$1 +# /usr/local/bin/javawrapper - the wrapper for binfmt_misc/java -# if classname is a link, we follow it (this could be done easier - how?) -if [ -L "$1" ] ; then - CLASS=`ls --color=no -l $1 | tr -s '\t ' ' ' | cut -d ' ' -f 11` +if [ -z "$1" ]; then + exec 1>&2 + echo Usage: $0 class-file + exit 1 fi -CLASSN=`basename $CLASS .class` -CLASSP=`dirname $CLASS` -FOO=$PATH -PATH=$CLASSPATH -if [ -z "`type -p -a $CLASSN.class`" ] ; then - # class is not in CLASSPATH - if [ -e "$CLASSP/$CLASSN.class" ] ; then - # append dir of class to CLASSPATH - if [ -z "${CLASSPATH}" ] ; then - export CLASSPATH=$CLASSP - else - export CLASSPATH=$CLASSP:$CLASSPATH - fi - else - # uh! now we would have to create a symbolic link - really - # ugly, i.e. print a message that one has to change the setup - echo "Hey! This is not a good setup to run $1 !" - exit 1 - fi +CLASS=$1 +FQCLASS=`/usr/local/bin/javaclassname $1` +FQCLASSN=`echo $FQCLASS | sed -e 's/^.*\.\([^.]*\)$/\1/'` +FQCLASSP=`echo $FQCLASS | sed -e 's-\.-/-g' -e 's-^[^/]*$--' -e 's-/[^/]*$--'` + +# for example: +# CLASS=Test.class +# FQCLASS=foo.bar.Test +# FQCLASSN=Test +# FQCLASSP=foo/bar + +unset CLASSBASE + +declare -i LINKLEVEL=0 + +while :; do + if [ "`basename $CLASS .class`" == "$FQCLASSN" ]; then + # See if this directory works straight off + cd -L `dirname $CLASS` + CLASSDIR=$PWD + cd $OLDPWD + if echo $CLASSDIR | grep -q "$FQCLASSP$"; then + CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."` + break; + fi + # Try dereferencing the directory name + cd -P `dirname $CLASS` + CLASSDIR=$PWD + cd $OLDPWD + if echo $CLASSDIR | grep -q "$FQCLASSP$"; then + CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."` + break; + fi + # If no other possible filename exists + if [ ! -L $CLASS ]; then + exec 1>&2 + echo $0: + echo " $CLASS should be in a" \ + "directory tree called $FQCLASSP" + exit 1 + fi + fi + if [ ! -L $CLASS ]; then break; fi + # Go down one more level of symbolic links + let LINKLEVEL+=1 + if [ $LINKLEVEL -gt 5 ]; then + exec 1>&2 + echo $0: + echo " Too many symbolic links encountered" + exit 1 + fi + CLASS=`ls --color=no -l $CLASS | sed -e 's/^.* \([^ ]*\)$/\1/'` +done + +if [ -z "$CLASSBASE" ]; then + if [ -z "$FQCLASSP" ]; then + GOODNAME=$FQCLASSN.class + else + GOODNAME=$FQCLASSP/$FQCLASSN.class + fi + exec 1>&2 + echo $0: + echo " $FQCLASS should be in a file called $GOODNAME" + exit 1 +fi + +if ! echo $CLASSPATH | grep -q "^\(.*:\)*$CLASSBASE\(:.*\)*"; then + # class is not in CLASSPATH, so prepend dir of class to CLASSPATH + if [ -z "${CLASSPATH}" ] ; then + export CLASSPATH=$CLASSBASE + else + export CLASSPATH=$CLASSBASE:$CLASSPATH + fi fi -PATH=$FOO shift -/usr/local/java/bin/java $CLASSN "$@" +/usr/bin/java $FQCLASS "$@" +====================== Cut here =================== + + +====================== Cut here =================== +/* javaclassname.c + * + * Extracts the class name from a Java class file; intended for use in a Java + * wrapper of the type supported by the binfmt_misc option in the Linux kernel. + * + * Copyright (C) 1999 Colin J. Watson . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +/* From Sun's Java VM Specification, as tag entries in the constant pool. */ + +#define CP_UTF8 1 +#define CP_INTEGER 3 +#define CP_FLOAT 4 +#define CP_LONG 5 +#define CP_DOUBLE 6 +#define CP_CLASS 7 +#define CP_STRING 8 +#define CP_FIELDREF 9 +#define CP_METHODREF 10 +#define CP_INTERFACEMETHODREF 11 +#define CP_NAMEANDTYPE 12 + +/* Define some commonly used error messages */ + +#define seek_error() error("%s: Cannot seek\n", program) +#define corrupt_error() error("%s: Class file corrupt\n", program) +#define eof_error() error("%s: Unexpected end of file\n", program) +#define utf8_error() error("%s: Only ASCII 1-255 supported\n", program); + +char *program; + +long *pool; + +u_int8_t read_8(FILE *classfile); +u_int16_t read_16(FILE *classfile); +void skip_constant(FILE *classfile, u_int16_t *cur); +void error(const char *format, ...); +int main(int argc, char **argv); + +/* Reads in an unsigned 8-bit integer. */ +u_int8_t read_8(FILE *classfile) +{ + int b = fgetc(classfile); + if(b == EOF) + eof_error(); + return (u_int8_t)b; +} + +/* Reads in an unsigned 16-bit integer. */ +u_int16_t read_16(FILE *classfile) +{ + int b1, b2; + b1 = fgetc(classfile); + if(b1 == EOF) + eof_error(); + b2 = fgetc(classfile); + if(b2 == EOF) + eof_error(); + return (u_int16_t)((b1 << 8) | b2); +} + +/* Reads in a value from the constant pool. */ +void skip_constant(FILE *classfile, u_int16_t *cur) +{ + u_int16_t len; + int seekerr = 1; + pool[*cur] = ftell(classfile); + switch(read_8(classfile)) + { + case CP_UTF8: + len = read_16(classfile); + seekerr = fseek(classfile, len, SEEK_CUR); + break; + case CP_CLASS: + case CP_STRING: + seekerr = fseek(classfile, 2, SEEK_CUR); + break; + case CP_INTEGER: + case CP_FLOAT: + case CP_FIELDREF: + case CP_METHODREF: + case CP_INTERFACEMETHODREF: + case CP_NAMEANDTYPE: + seekerr = fseek(classfile, 4, SEEK_CUR); + break; + case CP_LONG: + case CP_DOUBLE: + seekerr = fseek(classfile, 8, SEEK_CUR); + ++(*cur); + break; + default: + corrupt_error(); + } + if(seekerr) + seek_error(); +} + +void error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + exit(1); +} + +int main(int argc, char **argv) +{ + FILE *classfile; + u_int16_t cp_count, i, this_class, classinfo_ptr; + u_int8_t length; + + program = argv[0]; + + if(!argv[1]) + error("%s: Missing input file\n", program); + classfile = fopen(argv[1], "rb"); + if(!classfile) + error("%s: Error opening %s\n", program, argv[1]); + + if(fseek(classfile, 8, SEEK_SET)) /* skip magic and version numbers */ + seek_error(); + cp_count = read_16(classfile); + pool = calloc(cp_count, sizeof(long)); + if(!pool) + error("%s: Out of memory for constant pool\n", program); + + for(i = 1; i < cp_count; ++i) + skip_constant(classfile, &i); + if(fseek(classfile, 2, SEEK_CUR)) /* skip access flags */ + seek_error(); + + this_class = read_16(classfile); + if(this_class < 1 || this_class >= cp_count) + corrupt_error(); + if(!pool[this_class] || pool[this_class] == -1) + corrupt_error(); + if(fseek(classfile, pool[this_class] + 1, SEEK_SET)) + seek_error(); + + classinfo_ptr = read_16(classfile); + if(classinfo_ptr < 1 || classinfo_ptr >= cp_count) + corrupt_error(); + if(!pool[classinfo_ptr] || pool[classinfo_ptr] == -1) + corrupt_error(); + if(fseek(classfile, pool[classinfo_ptr] + 1, SEEK_SET)) + seek_error(); + + length = read_16(classfile); + for(i = 0; i < length; ++i) + { + u_int8_t x = read_8(classfile); + if((x & 0x80) || !x) + { + if((x & 0xE0) == 0xC0) + { + u_int8_t y = read_8(classfile); + if((y & 0xC0) == 0x80) + { + int c = ((x & 0x1f) << 6) + (y & 0x3f); + if(c) putchar(c); + else utf8_error(); + } + else utf8_error(); + } + else utf8_error(); + } + else if(x == '/') putchar('.'); + else putchar(x); + } + putchar('\n'); + free(pool); + fclose(classfile); + return 0; +} ====================== Cut here =================== @@ -116,4 +375,6 @@ originally by Brian A. Lantz, brian@lantz.com -heavily edited for binfmt_misc by Richard Günther. +heavily edited for binfmt_misc by Richard Günther +new scripts by Colin J. Watson . + diff -u --recursive --new-file v2.3.9/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt --- v2.3.9/linux/Documentation/kernel-parameters.txt Wed Jun 2 11:32:45 1999 +++ linux/Documentation/kernel-parameters.txt Mon Jul 5 19:52:52 1999 @@ -37,7 +37,7 @@ SOUND Appropriate sound system support is enabled. VGA The VGA console has been enabled. VT Virtual terminal support is enabled. - XT IBM PC/XT support is enabled. + XT IBM PC/XT MFM hard disk support is enabled. In addition, the following text indicates that the option: diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt --- v2.3.9/linux/Documentation/networking/arcnet-hardware.txt Thu Jan 7 08:41:55 1999 +++ linux/Documentation/networking/arcnet-hardware.txt Mon Jul 5 19:52:52 1999 @@ -20,14 +20,14 @@ ARCnet is a network type which works in a way similar to popular Ethernet networks but which is also different in some very important ways. -First of all, you can get ARCnet cards in at least two speeds: 2.5Mbps -(slower than Ethernet) and 100Mbps (faster than normal Ethernet). In fact, +First of all, you can get ARCnet cards in at least two speeds: 2.5 Mbps +(slower than Ethernet) and 100 Mbps (faster than normal Ethernet). In fact, there are others as well, but these are less common. The different hardware types, as far as I'm aware, are not compatible and so you cannot wire a -100Mbps card to a 2.5Mbps card, and so on. From what I hear, my driver does -work with 100Mbps cards, but I haven't been able to verify this myself, -since I only have the 2.5Mbps variety. It is probably not going to saturate -your 100Mbps card. Stop complaining :) +100 Mbps card to a 2.5 Mbps card, and so on. From what I hear, my driver does +work with 100 Mbps cards, but I haven't been able to verify this myself, +since I only have the 2.5 Mbps variety. It is probably not going to saturate +your 100 Mbps card. Stop complaining. :) You also cannot connect an ARCnet card to any kind of Ethernet card and expect it to work. @@ -52,17 +52,17 @@ useful for realtime networks. In addition, all known ARCnet cards have an (almost) identical programming -interface. This means that with one "arcnet" driver you can support any -card; whereas, with Ethernet, each manufacturer uses what is sometimes a +interface. This means that with one ARCnet driver you can support any +card, whereas with Ethernet each manufacturer uses what is sometimes a completely different programming interface, leading to a lot of different, sometimes very similar, Ethernet drivers. Of course, always using the same programming interface also means that when high-performance hardware -facilities like PCI busmastering DMA appear, it's hard to take advantage of +facilities like PCI bus mastering DMA appear, it's hard to take advantage of them. Let's not go into that. One thing that makes ARCnet cards difficult to program for, however, is the limit on their packet sizes; standard ARCnet can only send packets that are -up to 508 bytes in length. This is smaller than the internet "bare minimum" +up to 508 bytes in length. This is smaller than the Internet "bare minimum" of 576 bytes, let alone the Ethernet MTU of 1500. To compensate, an extra level of encapsulation is defined by RFC1201, which I call "packet splitting," that allows "virtual packets" to grow as large as 64K each, @@ -1005,9 +1005,9 @@ only (the JP0 jumper is hardwired), and BNC only. This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC, -nowhere else, not even on the few xeroxed sheets from the manual). +nowhere else, not even on the few Xeroxed sheets from the manual). -SMC Arcnet Board Type LCS-8830-T +SMC ARCnet Board Type LCS-8830-T ------------------------------------ | | @@ -1070,7 +1070,7 @@ DIP Switches 1-5 of SW2 encode the RAM and ROM Address Range: -Switches Ram Rom +Switches RAM ROM 12345 Address Range Address Range 00000 C:0000-C:07ff C:2000-C:3fff 10000 C:0800-C:0fff @@ -1170,11 +1170,11 @@ DIP Switches: The DIP switches accessible on the accessible end of the card while - it is installed, is used to set the arcnet address. There are 8 + it is installed, is used to set the ARCnet address. There are 8 switches. Use an address from 1 to 254. Switch No. - 12345678 Arcnet address + 12345678 ARCnet address ----------------------------------------- 00000000 FF (Don't use this!) 00000001 FE @@ -1222,7 +1222,7 @@ from the upper memory regions, and then attempting to load ARCETHER using these addresses. - I recommend using an arcnet memory address of 0xD000, and putting + I recommend using an ARCnet memory address of 0xD000, and putting the EMS page frame at 0xC000 while using QEMM stealth mode. That way, you get contiguous high memory from 0xD100 almost all the way the end of the megabyte. @@ -1687,7 +1687,7 @@ |____________________________________________| |__| -UM9065L : Arcnet Controller +UM9065L : ARCnet Controller SW 1 : Shared Memory Address and I/O Base @@ -1800,7 +1800,7 @@ J1-J5 IRQ Select J6-J21 Unknown (Probably extra timeouts & ROM enable ...) LED1 Activity LED -BNC Coax connector (STAR arcnet) +BNC Coax connector (STAR ARCnet) RAM 2k of SRAM ROM Boot ROM socket UFS Unidentified Flying Sockets @@ -1905,7 +1905,7 @@ ------------------------ - from Vojtech Pavlik -This is another SMC 90C65 based arcnet card. I couldn't identify the +This is another SMC 90C65-based ARCnet card. I couldn't identify the manufacturer, but it might be DataPoint, because the card has the original arcNet logo in its upper right corner. @@ -1942,9 +1942,9 @@ SW2 1-8: Node ID Select SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable BNC Coax connector -XTAL 20MHz Crystal +XTAL 20 MHz Crystal Setting the Node ID @@ -2081,11 +2081,11 @@ 6-8 Base I/O Address Select SW2 1-8 Node ID Select (ID0-ID7) J1 IRQ Select -J2 Rom Enable +J2 ROM Enable J3 Extra Timeout LED1 Activity LED -BNC Coax connector (BUS arcnet) -RJ Twisted Pair Connector (daisychain) +BNC Coax connector (BUS ARCnet) +RJ Twisted Pair Connector (daisy chain) Setting the Node ID @@ -2419,7 +2419,7 @@ Legend: -COM90C65: Arcnet Probe +COM90C65: ARCnet Probe S1 1-8: Node ID Select S2 1-3: I/O Base Address Select 4-6: Memory Base Address Select @@ -2791,7 +2791,7 @@ SW2 1-8: Node ID Select (ID0-ID7) SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable JP1 Led connector BNC Coax connector @@ -3089,7 +3089,7 @@ 0 = Jumper Installed 1 = Open -Top Jumper line Bit 7 = Rom Enable 654=Memory location 321=I/O +Top Jumper line Bit 7 = ROM Enable 654=Memory location 321=I/O Settings for Memory Location (Top Jumper Line) 456 Address selected diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt --- v2.3.9/linux/Documentation/networking/arcnet.txt Mon Sep 14 11:32:22 1998 +++ linux/Documentation/networking/arcnet.txt Mon Jul 5 19:52:52 1999 @@ -1,4 +1,3 @@ - ---------------------------------------------------------------------------- NOTE: See also arcnet-hardware.txt in this directory for jumper-setting and cabling information if you're like many of us and didn't happen to get a @@ -92,10 +91,10 @@ http://www.perftech.com/ or ftp to ftp.perftech.com. Novell makes a networking stack for DOS which includes ARCnet drivers. Try -ftp'ing to ftp.novell.com. +FTPing to ftp.novell.com. You can get the Crynwr packet driver collection (including arcether.com, the -one you'll want to use with arcnet cards) from +one you'll want to use with ARCnet cards) from oak.oakland.edu:/simtel/msdos/pktdrvr. It won't work perfectly on a 386+ without patches, though, and also doesn't like several cards. Fixed versions are available on my WWW page, or via e-mail if you don't have WWW @@ -183,7 +182,7 @@ ----------------------- Configure and rebuild Linux. When asked, answer 'm' to "Generic ARCnet -support" and to support for your ARcnet chipset if you want to use the +support" and to support for your ARCnet chipset if you want to use the loadable module. You can also say 'y' to "Generic ARCnet support" and 'm' to the chipset support if you wish. @@ -269,7 +268,7 @@ Arcether client, assuming you remember to load winpkt of course. LAN Manager and Windows for Workgroups: These programs use protocols that - are incompatible with the internet standard. They try to pretend + are incompatible with the Internet standard. They try to pretend the cards are Ethernet, and confuse everyone else on the network. However, v2.00 and higher of the Linux ARCnet driver supports this @@ -288,7 +287,7 @@ you're completely insane, and/or you need to build some kind of hybrid network that uses both encapsulation types. -OS2: I've been told it works under Warp Connect with an ARCnet driver from +OS/2: I've been told it works under Warp Connect with an ARCnet driver from SMC. You need to use the 'arc0e' interface for this. If you get the SMC driver to work with the TCP/IP stuff included in the "normal" Warp Bonus Pack, let me know. @@ -309,7 +308,7 @@ The ARCnet driver v2.10 ALPHA supports three protocols, each on its own "virtual network device": - arc0 - RFC1201 protocol, the official internet standard which just + arc0 - RFC1201 protocol, the official Internet standard which just happens to be 100% compatible with Novell's TRXNET driver. Version 1.00 of the ARCnet driver supported _only_ this protocol. arc0 is the fastest of the three protocols (for @@ -331,13 +330,13 @@ reasons yet to be determined. (Probably it's the smaller MTU that does it.) - arc0s - The "[s]imple" RFC1051 protocol is the "previous" internet + arc0s - The "[s]imple" RFC1051 protocol is the "previous" Internet standard that is completely incompatible with the new standard. Some software today, however, continues to support the old standard (and only the old standard) including NetBSD and AmiTCP. RFC1051 also does not support RFC1201's packet splitting, and the MTU of 507 is still - smaller than the internet "requirement," so it's quite + smaller than the Internet "requirement," so it's quite possible that you may run into problems. It's also slower than RFC1201 by about 25%, for the same reason as arc0e. @@ -388,16 +387,16 @@ Linux but runs the free Microsoft LANMAN Client instead. Worse, one of the Linux computers (freedom) also has a modem and acts as - a router to my internet provider. The other Linux box (insight) also has + a router to my Internet provider. The other Linux box (insight) also has its own IP address and needs to use freedom as its default gateway. The - XT (patience), however, does not have its own internet IP address and so + XT (patience), however, does not have its own Internet IP address and so I assigned it one on a "private subnet" (as defined by RFC1597). To start with, take a simple network with just insight and freedom. Insight needs to: - talk to freedom via RFC1201 (arc0) protocol, because I like it more and it's faster. - - use freedom as its internet gateway. + - use freedom as its Internet gateway. That's pretty easy to do. Set up insight like this: ifconfig arc0 insight @@ -417,20 +416,20 @@ /* and default gateway is configured by pppd */ Great, now insight talks to freedom directly on arc0, and sends packets - to the internet through freedom. If you didn't know how to do the above, + to the Internet through freedom. If you didn't know how to do the above, you should probably stop reading this section now because it only gets worse. Now, how do I add patience into the network? It will be using LANMAN Client, which means I need the arc0e device. It needs to be able to talk to both insight and freedom, and also use freedom as a gateway to the - internet. (Recall that patience has a "private IP address" which won't - work on the internet; that's okay, I configured Linux IP masquerading on + Internet. (Recall that patience has a "private IP address" which won't + work on the Internet; that's okay, I configured Linux IP masquerading on freedom for this subnet). So patience (necessarily; I don't have another IP number from my provider) has an IP address on a different subnet than freedom and - insight, but needs to use freedom as an internet gateway. Worse, most + insight, but needs to use freedom as an Internet gateway. Worse, most DOS networking programs, including LANMAN, have braindead networking schemes that rely completely on the netmask and a 'default gateway' to determine how to route packets. This means that to get to freedom or @@ -449,7 +448,7 @@ This way, freedom will send all packets for patience through arc0e, giving its IP address as gatekeeper (on the private subnet). When it - talks to insight or the internet, it will use its "freedom" internet IP + talks to insight or the Internet, it will use its "freedom" Internet IP address. You will notice that we haven't configured the arc0e device on insight. @@ -473,7 +472,7 @@ [RFC1201 NETWORK] [ETHER-ENCAP NETWORK] - (registered internet subnet) (RFC1597 private subnet) + (registered Internet subnet) (RFC1597 private subnet) (IP Masquerade) /---------------\ * /---------------\ @@ -523,7 +522,7 @@ Once the driver is running, you can run the arcdump shell script (available from me or in the full ARCnet package, if you have it) as root to list the contents of the arcnet buffers at any time. To make any sense at all out of -this, you should grab the pertinent RFC's. (some are listed near the top of +this, you should grab the pertinent RFCs. (some are listed near the top of arcnet.c). arcdump assumes your card is at 0xD0000. If it isn't, edit the script. diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/baycom.txt linux/Documentation/networking/baycom.txt --- v2.3.9/linux/Documentation/networking/baycom.txt Sun Jun 7 11:13:44 1998 +++ linux/Documentation/networking/baycom.txt Tue Jul 6 19:16:55 1999 @@ -31,7 +31,7 @@ Its devices are called bcp0 through bcp3. baycom_epp: - This driver supports the epp modem. + This driver supports the EPP modem. Its devices are called bce0 through bce3. This driver is work-in-progress. @@ -60,10 +60,10 @@ an additional power supply. Furthermore, it incorporates a carrier detect circuitry. -epp: This is a high speed modem adaptor that connects to an enhanced parallel port. +EPP: This is a high-speed modem adaptor that connects to an enhanced parallel port. Its target audience is users working over a high speed hub (76.8kbit/s). -eppfpga: This is a redesign of the epp adaptor. +eppfpga: This is a redesign of the EPP adaptor. diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt --- v2.3.9/linux/Documentation/networking/cs89x0.txt Fri Sep 11 11:21:57 1998 +++ linux/Documentation/networking/cs89x0.txt Tue Jul 6 19:16:55 1999 @@ -203,7 +203,7 @@ * io=### - specify IO address (200h-360h) * irq=## - specify interrupt level * mmode=##### - specify memory base address -* dma=# - specify dma channel +* dma=# - specify DMA channel * media=rj45 - specify media type or media=2 or media=aui @@ -412,33 +412,33 @@ assigned during hardware configuration. The following tests are performed: * IO Register Read/Write Test - The IO Register Read/Write test insures that the CS8900/20 can be + The IO Register Read/Write test ensures that the CS8900/20 can be accessed in IO mode, and that the IO base address is correct. * Shared Memory Test - The Shared Memory test insures the CS8900/20 can be accessed in memory + The Shared Memory test ensures the CS8900/20 can be accessed in memory mode and that the range of memory addresses assigned does not conflict with other devices in the system. * Interrupt Test - The Interrupt test insures there are no conflicts with the assigned IRQ + The Interrupt test ensures there are no conflicts with the assigned IRQ signal. * EEPROM Test - The EEPROM test insures the EEPROM can be read. + The EEPROM test ensures the EEPROM can be read. * Chip RAM Test - The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is working properly. * Internal Loop-back Test - The Internal Loop Back test insures the adapter's transmitter and + The Internal Loop Back test ensures the adapter's transmitter and receiver are operating properly. If this test fails, make sure the adapter's cable is connected to the network (check for LED activity for example). * Boot PROM Test - The Boot PROM test insures the Boot PROM is present, and can be read. + The Boot PROM test ensures the Boot PROM is present, and can be read. Failure indicates the Boot PROM was not successfully read due to a hardware problem or due to a conflicts on the Boot PROM address assignment. (Test only applies if the adapter is configured to use the @@ -564,7 +564,7 @@ Telephone :(800) 888-5016 (from inside U.S. and Canada) :(512) 442-7555 (from outside the U.S. and Canada) Fax :(512) 912-3871 -Email :ethernet@crystal.cirrus.com +E-mail :ethernet@crystal.cirrus.com WWW :http://www.crystal.com diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/olympic.txt linux/Documentation/networking/olympic.txt --- v2.3.9/linux/Documentation/networking/olympic.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/olympic.txt Mon Jul 5 19:54:55 1999 @@ -0,0 +1,75 @@ + +IBM PCI Pit/Pit-Phy/Olympic CHIPSET BASED TOKEN RING CARDS README + +Release 0.2.0 - Release + June 8th 1999 Peter De Schrijver & Mike Phillips + + +Thanks: +Erik De Cock, Adrian Bridgett and Frank Fiene for their +patience and testing. +Paul Norton without whose tr.c code we would have had +a lot more work to do. + +Options: + +The driver accepts three options: ringspeed, pkt_buf_sz, and +message_level. + +These options can be specified differently for each card found. + +ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will +make the card autosense the ringspeed and join at the appropriate speed, +this will be the default option for most people. 4 or 16 allow you to +explicitly force the card to operate at a certain speed. The card will fail +if you try to insert it at the wrong speed. (Although some hubs will allow +this so be *very* careful). The main purpose for explicitly setting the ring +speed is for when the card is first on the ring. In autosense mode, if the card +cannot detect any active monitors on the ring it will not open, so you must +re-init the card at the appropriate speed. Unfortunately at present the only +way of doing this is rmmod and insmod which is a bit tough if it is compiled +in the kernel. + +pkt_buf_sz: This is this initial receive buffer allocation size. This will +default to 4096 if no value is entered. You may increase performance of the +driver by setting this to a value larger than the network packet size, although +the driver now re-sizes buffers based on MTU settings as well. + +message_level: Controls level of messages created by the driver. Defaults to 0: +which only displays start-up and critical messages. Presently any non-zero +value will display all soft messages as well. NB This does not turn +debuging messages on, that must be done by modified the source code. + +Multi-card: + +The driver will detect multiple cards and will work with shared interrupts, +each card is assigned the next token ring device, i.e. tr0 , tr1, tr2. The +driver should also happily reside in the system with other drivers. It has +been tested with ibmtr.c running, and I personnally have had one Olicom PCI +card and two IBM olympic cards (all on the same interrupt), all running +together. + +Variable MTU size: + +The driver can handle a MTU size upto either 4500 or 18000 depending upon +ring speed. The driver also changes the size of the receive buffers as part +of the mtu re-sizing, so if you set mtu = 18000, you will need to be able +to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring +position = 296,000 bytes of memory space, plus of course anything +necessary for the tx sk_buff's. Remember this is per card, so if you are +building routers, gateway's etc, you could start to use a lot of memory +real fast. + +Network Monitor Mode: + +By modifying the #define OLYMPIC_NETWORK_MONITOR from 0 to 1 in the +source code the driver will implement a quasi network monitoring +mode. All unexpected MAC frames (beaconing etc.) will be received +by the driver and the source and destination addresses printed. +Also an entry will be added in /proc/net called olympic_tr. This +displays low level information about the configuration of the ring and +the adapter. This feature has been designed for network adiministrators +to assist in the diagnosis of network / ring problems. + +6/8/99 Peter De Schrijver and Mike Phillips + diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/policy-routing.txt linux/Documentation/networking/policy-routing.txt --- v2.3.9/linux/Documentation/networking/policy-routing.txt Thu May 14 10:26:22 1998 +++ linux/Documentation/networking/policy-routing.txt Tue Jul 6 19:05:48 1999 @@ -83,7 +83,7 @@ 2. Opposite case. Just forget all that you know about routing tables. Every rule is supplied with its own gateway, device info. record. This approach is not appropriate for automated - route maintanance, but it is ideal for manual configuration. + route maintenance, but it is ideal for manual configuration. HOWTO: iproute addrule [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ] diff -u --recursive --new-file v2.3.9/linux/Documentation/networking/z8530drv.txt linux/Documentation/networking/z8530drv.txt --- v2.3.9/linux/Documentation/networking/z8530drv.txt Wed May 20 18:54:34 1998 +++ linux/Documentation/networking/z8530drv.txt Tue Jul 6 19:05:48 1999 @@ -252,7 +252,7 @@ speed 1200 # the default baudrate clock dpll # clock source: - # dpll = normal halfduplex operation + # dpll = normal half duplex operation # external = MODEM provides own Rx/Tx clock # divider = use full duplex divider if # installed (1) diff -u --recursive --new-file v2.3.9/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt --- v2.3.9/linux/Documentation/oops-tracing.txt Tue Jan 5 11:14:24 1999 +++ linux/Documentation/oops-tracing.txt Thu Jul 1 10:54:31 1999 @@ -1,15 +1,16 @@ Quick Summary ------------- -cd /usr/src/linux/scripts/ksymoops -make ksymoops -./ksymoops < the_oops.txt +Install ksymoops from ftp://ftp.ocs.com.au/pub/ksymoops +Read the ksymoops man page. +ksymoops < the_oops.txt and send the output the maintainer of the kernel area that seems to be -involved with the problem. Don't worry too much about getting the wrong -person. If you are unsure send it to the person responsible for the code -relevant to what you were doing. If it occurs repeatably try and describe -how to recreate it. Thats worth even more than the oops +involved with the problem, not to the ksymoops maintainer. Don't worry +too much about getting the wrong person. If you are unsure send it to +the person responsible for the code relevant to what you were doing. +If it occurs repeatably try and describe how to recreate it. Thats +worth even more than the oops If you are totally stumped as to whom to send the report, send it to linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as @@ -41,9 +42,8 @@ same compiler and similar setups. The other thing to do is disassemble the "Code:" part of the bug report: -ksymoops will do this too with the correct tools (and new version of -ksymoops), but if you don't have the tools you can just do a silly -program: +ksymoops will do this too with the correct tools, but if you don't have +the tools you can just do a silly program: char str[] = "\xXX\xXX\xXX..."; main(){} diff -u --recursive --new-file v2.3.9/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.3.9/linux/Documentation/parport.txt Fri Mar 26 13:23:24 1999 +++ linux/Documentation/parport.txt Sun Jul 4 10:14:13 1999 @@ -28,8 +28,8 @@ to tell the parport code that you want three PC-style ports, one at 0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an -auto-detected IRQ. Currently, PC-style (parport_pc) and Sun Ultra/AX -(parport_ax) hardware is supported; more is in the works. +auto-detected IRQ. Currently, PC-style (parport_pc), Sun Ultra/AX +(parport_ax), Amiga, Atari, and MFC3 hardware is supported. KMod @@ -38,7 +38,7 @@ If you use kmod, you will find it useful to edit /etc/conf.modules. Here is an example of the lines that need to be added: - alias parport_lowlevel parport_pc + post-install parport modprobe -k parport_pc options parport_pc io=0x378,0x278 irq=7,auto KMod will then automatically load parport_pc (with the options @@ -49,20 +49,15 @@ Parport probe [optional] ------------- -Once the architecture-dependent part of the parport code is loaded -into the kernel, you can insert the parport_probe module with: - - # insmod parport_probe.o - -This will perform an IEEE1284 probe of any attached devices and log a -message similar to: +In 2.2 kernels there was a module called parport_probe, which was used +for collecting IEEE 1284 device ID information. This has now been +enhanced and now lives with the IEEE 1284 support. When a parallel +port is detected, the devices that are connected to it are analysed, +and information is logged like this: parport0: Printer, BJC-210 (Canon) -(If you are using kmod and have configured parport_probe as a module, -this will just happen.) - -The probe information is available in /proc/parport/?/autoprobe. +The probe information is available from files in /proc/sys/dev/parport/. Parport linked into the kernel statically @@ -85,29 +80,74 @@ ============== If you have configured the /proc filesystem into your kernel, you will -see a new directory entry: /proc/parport. In there will be a +see a new directory entry: /proc/sys/dev/parport. In there will be a directory entry for each parallel port for which parport is -configured. In each of those directories are four files describing -that parallel port. For example: - -File: Contents: - -/proc/parport/0/devices A list of the device drivers using - that port. A "+" will appear by the - name of the device currently using the - port (it might not appear against any). - -/proc/parport/0/hardware Parallel port's base address, IRQ line - and DMA channel. - -/proc/parport/0/irq The IRQ that parport is using for that - port. This is in a separate file to - allow you to alter it by writing a new - value in (IRQ number or "none"). +configured. In each of those directories are a collection of files +describing that parallel port. -/proc/parport/0/autoprobe Any IEEE-1284 device ID information - that has been acquired. +The /proc/sys/dev/parport directory tree looks like: +parport +|-- default +| |-- spintime +| `-- timeslice +|-- parport0 +| |-- autoprobe +| |-- autoprobe0 +| |-- autoprobe1 +| |-- autoprobe2 +| |-- autoprobe3 +| |-- devices +| | |-- active +| | `-- lp +| | `-- timeslice +| |-- hardware +| `-- spintime +`-- parport1 + |-- autoprobe + |-- autoprobe0 + |-- autoprobe1 + |-- autoprobe2 + |-- autoprobe3 + |-- devices + | |-- active + | `-- ppa + | `-- timeslice + |-- hardware + `-- spintime + + +File: Contents: + +devices/active A list of the device drivers using that port. A "+" + will appear by the name of the device currently using + the port (it might not appear against any). The + string "none" means that there are no device drivers + using that port. + +hardware Parallel port's base address, IRQ line and DMA channel. + +autoprobe Any IEEE-1284 device ID information that has been + acquired from the (non-IEEE 1284.3) device. + +autoprobe[0-3] IEEE 1284 device ID information retrieved from + daisy-chain devices that conform to IEEE 1284.3. + +spintime The number of microseconds to busy-loop while waiting + for the peripheral to respond. You might find that + adjusting this improves performance, depending on your + peripherals. This is a port-wide setting, i.e. it + applies to all devices on a particular port. + +timeslice The number of jiffies (FIXME: this should be in + milliseconds or something) that a device driver is + allowed to keep a port claimed for. This is advisory, + and driver can ignore it if it must. + +default/* The defaults for spintime and timeslice. When a new + port is registered, it picks up the default spintime. + When a new device is registered, it picks up the + default timeslice. Device drivers ============== @@ -135,7 +175,7 @@ Also: - * If you selected the IEEE-1284 autoprobe at compile time, you can say + * If you selected the IEEE 1284 support at compile time, you can say `lp=auto' on the kernel command line, and lp will create devices only for those ports that seem to have printers attached. diff -u --recursive --new-file v2.3.9/linux/Documentation/pcwd-watchdog.txt linux/Documentation/pcwd-watchdog.txt --- v2.3.9/linux/Documentation/pcwd-watchdog.txt Sun Jan 19 05:47:24 1997 +++ linux/Documentation/pcwd-watchdog.txt Tue Jul 6 19:05:48 1999 @@ -1,6 +1,6 @@ Berkshire Products PC Watchdog Card Support for ISA Cards Revision A and C - Documentation and Driver by Ken Hollis + Documentation and Driver by Ken Hollis The PC Watchdog is a card that offers the same type of functionality that the WDT card does, only it doesn't require an IRQ to run. Furthermore, @@ -15,7 +15,7 @@ The Watchdog Driver will automatically find your watchdog card, and will attach a running driver for use with that card. After the watchdog drivers have initialized, you can then talk to the card using the PC - Watchdog program, available from ftp.bitgate.com:/pub/bitgate/pcwd. + Watchdog program, available from http://ftp.bitgate.com/pcwd/. I suggest putting a "watchdog -d" before the beginning of an fsck, and a "watchdog -e -t 1" immediately after the end of an fsck. (Remember @@ -128,4 +128,7 @@ And that's all she wrote! -- Ken Hollis - (khollis@nurk.org) + (kenji@bitgate.com) + +(This documentation may be out of date. Check + http://ftp.bitgate.com/pcwd/ for the absolute latest additions.) diff -u --recursive --new-file v2.3.9/linux/Documentation/sound/Introduction linux/Documentation/sound/Introduction --- v2.3.9/linux/Documentation/sound/Introduction Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sound/Introduction Mon Jul 5 20:04:47 1999 @@ -1,6 +1,6 @@ -Soundcore Notes on Modular Sound Drivers and Soundcore +Introduction Notes on Modular Sound Drivers and Soundcore Wade Hampton -11/20/1998 +6/30/1999 Purpose: ======== @@ -10,13 +10,21 @@ Note, some of this probably should be added to the Sound-HOWTO! + Copying: ======== none + History: ======== -0.1.0 11/20/1998 First version +0.1.0 11/20/1998 First version, draft +1.0.0 11/1998 Alan Cox changes, incorporation in 2.2.0 + as /usr/src/linux/Documentation/sound/Introduction +1.1.0 6/30/1999 Second version, added notes on making the drivers, + added info on multiple sound cards of similar types,] + added more diagnostics info, added info about esd. + added info on OSS and ALSA. Modular Sound Drivers: @@ -58,6 +66,53 @@ for the same or a similar feature (dma1= versus dma16=). As a last resort, inspect the code (search for MODULE_PARM). +Notes: + +1. There is a new OpenSource sound driver called ALSA which is + currently under development: http://www.alsa-project.org/ + I have not tried it nor am I aware of its status, but it is + currently under development. + +2. The commercial OSS driver may be obtained from the site: + http://www/opensound.com. This may be used for cards that + are unsupported by the kernel driver, or may be used + by other operating systems. + +3. The enlightenment sound daemon may be used for playing + multiple sounds at the same time via a single card, eliminating + some of the requirements for multiple sound card systems. For + more information, see: http://www.tux.org/~ricdude/EsounD.html + The "esd" program may be used with the real-player and mpeg + players like mpg123 and x11amp. + + +Building the Modules: +===================== + +This document does not provide full details on building the +kernel, etc. The notes below apply only to making the kernel +sound modules. If this conflicts with the kernel's README, +the README takes precedence. + +1. To make the kernel sound modules, cd to your /usr/src/linux + directory (typically) and type make config, make menuconfig, + or make xconfig (to start the command line, dialog, or x-based + configuration tool). + +2. Select the Sound option and a dialog will be displayed. + +3. Select M (module) for "Sound card support". + +4. Select your sound driver(s) as a module. For ProAudio, Sound + Blaster, etc., select M (module) for OSS sound modules. + [thanks to marvin stodolsky ]A + +5. Make the kernel (e.g., make dep ; make bzImage), and install + the kernel. + +6. Make the modules and install them (make modules; make modules_install). + + INSMOD: ======= @@ -82,6 +137,9 @@ /sbin/insmod uart401 /sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP +When using sound as a module, I typically put these commands +in a file such as /root/soundon.sh. + MODPROBE: ========= @@ -117,8 +175,8 @@ soundcore 1968 8 [sb sound] -Removing Sound: -=============== +Removing Sound: +=============== Sound may be removed by using /sbin/rmmod in the reverse order in which you load the modules. Note, if a program has a sound device @@ -134,6 +192,25 @@ /sbin/rmmod soundlow /sbin/rmmod soundcore +When using sound as a module, I typically put these commands +in a script such as /root/soundoff.sh. + + +Removing Sound for use with OSS: +================================ + +If you get really stuck or have a card that the kernel modules +will not support, you can get a commercial sound driver from +http://www.opensound.com. Before loading the commercial sound +driver, you should do the following: + +1. remove sound modules (detailed above) +2. remove the sound modules from /etc/conf.modules +3. move the sound modules from /lib/modules//misc + (for example, I make a /lib/modules//misc/tmp + directory and copy the sound module files to that + directory). + Multiple Sound Cards: ===================== @@ -154,11 +231,30 @@ first (in my case "sb") and then load the other one (in my case "cs4232"). +If you have two cards of the same type that are jumpered +cards or different PnP revisions, you may load the same +module twice. For example, I have a SoundBlaster vibra 16 +and an older SoundBlaster 16 (jumpers). To load the module +twice, you need to do the following: + +1. Copy the sound modules to a new name. For example + sb.o could be copied (or symlinked) to sb1.o for the + second SoundBlasster. + +2. Make a second entry in /etc/conf.modules, for example, + sound1 or sb1. This second entry should refer to the + new module names for example sb1, and should include + the I/O, etc. for the second sound card. + +3. Update your soundon.sh script, etc. + Warning: I have never been able to get two PnP sound cards of the same type to load at the same time. I have tried this several times with the Soundblaster Vibra 16 cards. OSS has indicated that this is a PnP problem.... If anyone has any luck doing this, please -send me an E-MAIL. PCI sound cards should not have this problem. +send me an E-MAIL. PCI sound cards should not have this problem.a +Since this was originally release, I have received a couple of +mails from people who have accomplished this! Sound Problems: @@ -175,6 +271,8 @@ write down what addresses, IRQ, and DMA channels those were using for the same hardware. You probably can use these addresses, IRQs, and DMA channels. + You should really do this BEFORE attempting to get + sound working! B) Check (cat) /proc/interrupts, /proc/ioports, and /proc/dma. Are you trying to use an address, @@ -184,22 +282,44 @@ may need a kernel patch to get this device). D) Inspect your /var/log/messages file. Often that will - indicate what IRQ or IO port could not be obtained + indicate what IRQ or IO port could not be obtained. E) Try another port or IRQ. Note this may involve using the PnP tools to move the sound card to - another location. + another location. Sometimes this is the only way + and it is more or less trial and error. -2) If you get motorboating (the same sound or part of a +2) If you get motor-boating (the same sound or part of a sound clip repeated), you probably have either an IRQ - or DMA conflict. Move the card to another address. This - has happened to me when playing long files when I had - an IRQ conflict. + or DMA conflict. Move the card to another IRQ or DMA + port. This has happened to me when playing long files + when I had an IRQ conflict. + +3. If you get dropouts or pauses when playing high sample + rate files such as using mpg123 or x11amp/xmms, you may + have too slow of a CPU and may have to use the options to + play the files at 1/2 speed. For example, you may use + the -2 or -4 option on mpg123. You may also get this + when trying to play mpeg files stored on a CD-ROM + (my Toshiba T8000 PII/366 sometimes has this problem). + +4. If you get "cannot access device" errors, your /dev/dsp + files, etc. may be set to owner root, mode 600. You + may have to use the command: + chmod 666 /dev/dsp /dev/mixer /dev/audio + +5. If you get "device busy" errors, another program has the + sound device open. For example, if using the Enlightenment + sound daemon "esd", the "esd" program has the sound device. + If using "esd", please RTFM the docs on ESD. For example, + esddsp may be used to play files via a non-esd + aware program. + -3) Ask for help on the sound list or send E-MAIL to the +6) Ask for help on the sound list or send E-MAIL to the sound driver author/maintainer. -4) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB). +7) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB). Configuring Sound: @@ -210,7 +330,8 @@ 1) Hardcoded in the kernel at compile time (not applicable when using sound modules). This was the OLD way! -2) On the command line when using insmod. +2) On the command line when using insmod or in a bash script + using command line calls to load sound. 3) In /etc/conf.modules when using modprobe. @@ -224,7 +345,6 @@ Anyone want to write a linuxconf module for configuring sound? - For More Information (RTFM): ============================ 1) Information on kernel modules: linux/Documentation/modules.txt @@ -242,12 +362,17 @@ 7) The sndconfig and rhsound documentation from Red Hat. -8) The Linux-sound mailing list: sound-list@redhat.com +8) The Linux-sound mailing list: sound-list@redhat.com. + +9) Enlightenment documentation (for info on esd) + http://www.tux.org/~ricdude/EsounD.html. +10) ALSA home page: http://www.alsa-project.org/ Contact Information: ==================== Wade Hampton: (whampton@staffnet.com) + diff -u --recursive --new-file v2.3.9/linux/Documentation/sound/OPL3-SA2 linux/Documentation/sound/OPL3-SA2 --- v2.3.9/linux/Documentation/sound/OPL3-SA2 Thu Jan 14 22:53:02 1999 +++ linux/Documentation/sound/OPL3-SA2 Mon Jul 5 20:04:47 1999 @@ -46,6 +46,21 @@ then email me if you are willing to experiment in an effort to make it work. +************************************************************************ +* I have now had two such machines, and I have fixed this to work +* properly when built into the kernel. The Toshiba Libretto series, or +* at least models 70CT and 110CT which I have owned, use a Yamaha +* OPL3-SAx (OPL3-SA3 according to documentation) sound chip, IRQ 5, +* IO addresses 220/530/388/330/370 and DMA 1,0 (_not_ 0,1). All these +* configuration settings can be gathered by booting another OS which +* recognizes the card already. +* +* I have made things 'just work' for the non-modular case on such +* machines when configured properly. +* +* David Luyer +************************************************************************ + If you are using isapnp, follow the directions in its documentation to produce a configuration file. Here is the relevant excerpt I use for my SAx card from my isapnp.conf: diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/README linux/Documentation/sysctl/README --- v2.3.9/linux/Documentation/sysctl/README Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/README Mon Jul 5 20:04:47 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/ kernel version 2.2.5 +Documentation for /proc/sys/ kernel version 2.2.10 (c) 1998, 1999, Rik van Riel 'Why', I hear you ask, 'would anyone even _want_ documentation diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/fs.txt linux/Documentation/sysctl/fs.txt --- v2.3.9/linux/Documentation/sysctl/fs.txt Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/fs.txt Mon Jul 5 20:04:47 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/fs/* kernel version 2.2.5 +Documentation for /proc/sys/fs/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt --- v2.3.9/linux/Documentation/sysctl/kernel.txt Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/kernel.txt Mon Jul 5 20:04:47 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/kernel/* kernel version 2.2.5 +Documentation for /proc/sys/kernel/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. @@ -76,12 +76,21 @@ domainname & hostname: -These files can be controlled to set the domainname and -hostname of your box. For the classic darkstar.frop.org -a simple: +These files can be used to set the NIS/YP domainname and the +hostname of your box in exactly the same way as the commands +domainname and hostname, i.e.: # echo "darkstar" > /proc/sys/kernel/hostname -# echo "frop.org" > /proc/sys/kernel/domainname -would suffice to set your hostname and domainname. +# echo "mydomain" > /proc/sys/kernel/domainname +has the same effect as +# hostname "darkstar" > /proc/sys/kernel/hostname +# domainname "mydomain" > /proc/sys/kernel/domainname + +Note, however, that the classic darkstar.frop.org has the +hostname "darkstar" and DNS (Internet Domain Name Server) +domainname "frop.org", not to be confused with the NIS (Network +Information Service) or YP (Yellow Pages) domainname. These two +domain names are in general different. For a detailed discussion +see the hostname(1) man page. ============================================================== diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/sunrpc.txt linux/Documentation/sysctl/sunrpc.txt --- v2.3.9/linux/Documentation/sysctl/sunrpc.txt Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/sunrpc.txt Mon Jul 5 20:04:47 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/sunrpc/* kernel version 2.2.5 +Documentation for /proc/sys/sunrpc/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. diff -u --recursive --new-file v2.3.9/linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt --- v2.3.9/linux/Documentation/sysctl/vm.txt Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sysctl/vm.txt Mon Jul 5 20:04:47 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/vm/* kernel version 2.2.5 +Documentation for /proc/sys/vm/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/API.html linux/Documentation/video4linux/API.html --- v2.3.9/linux/Documentation/video4linux/API.html Thu Jan 7 08:41:55 1999 +++ linux/Documentation/video4linux/API.html Mon Jul 5 20:04:47 1999 @@ -1,6 +1,9 @@ -Video4Linux Kernel API Reference v0.1:19980516 +Video4Linux Kernel API Reference v0.1:19990430 + + +

Devices

Video4Linux provides the following sets of device files. These live on the @@ -117,7 +120,7 @@

Merely setting the window does not enable capturing. Overlay capturing -is activatied by passing the VIDIOCCAPTURE ioctl a value of 1, and +is activated by passing the VIDIOCCAPTURE ioctl a value of 1, and disabled by passing it a value of 0.

Some capture devices can capture a subfield of the image they actually see. @@ -150,7 +153,7 @@ nature of the channel itself.

The VIDIOCSCHAN ioctl takes an integer argument and switches the -capture to this input. It is not defined whether paramters such as colour +capture to this input. It is not defined whether parameters such as colour settings or tuning are maintained across a channel switch. The caller should maintain settings as desired for each channel. (This is reasonable as different video inputs may have different properties). @@ -249,6 +252,8 @@ VIDEO_TUNER_LOWFrequency is in a lower range VIDEO_TUNER_NORMThe norm for this tuner is settable VIDEO_TUNER_STEREO_ONThe tuner is seeing stereo audio +VIDEO_TUNER_RDS_ONThe tuner is seeing a RDS datastream +VIDEO_TUNER_MBS_ONThe tuner is seeing a MBS datastream

The following modes are defined @@ -349,6 +354,21 @@ teletextTeletext device

- +

RDS Datastreams

+For radio devices that support it, it is possible to receive Radio Data +System (RDS) data by means of a read() on the device. The data is packed in +groups of three, as follows: + + + + + + +
First OctetLeast Siginificant Byte of RDS Block
Second OctetMost Siginificant Byte of RDS Block +
Third OctetBit 7:Error bit. Indicates that +an uncorrectable error occured during reception of this block.
 Bit 6:Corrected bit. Indicates that +an error was corrected for this data block.
 Bits 5-3:Reeived Offset. Indicates the +offset received by the sync system.
 Bits 2-0:Offset Name. Indicates the +offset applied to this data.
diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/README.buz linux/Documentation/video4linux/README.buz --- v2.3.9/linux/Documentation/video4linux/README.buz Wed Dec 31 16:00:00 1969 +++ linux/Documentation/video4linux/README.buz Mon Jul 5 20:04:47 1999 @@ -0,0 +1,212 @@ +Iomega Buz Driver for Linux +=========================== + +by Rainer Johanni + +Compiling and Loading the Driver +================================ + +You must run a 2.2.x kernel in order to use this driver. + +To compile the driver, just type make. + +Besides the files in this directory, the driver needs the +'videodev' and the 'i2c' module from the Linux kernel. +In order to get these modules available, enable module support +for VIDEODEV and BTTV (which implies i2c) in your kernel +configuration. You find these devices in the menu +"Character Devices" in your Kernel Configuration. + +Before you load the driver you must have a video device +at major device node 81. If you don't have it yet, do the +following (as root!): + +cd /dev +mknod video0 c 81 0 +ln -s video0 video + +Edit the 'update' script if you want to give the driver +special options and then type (as root) + +./update + +to insert all the necessary modules into the kernel. + +If you want to make full use of the Video for Linux uncompressed +grabbing facilities, you must either + +- obtain and install the "big_physarea patch" for your kernel and + set aside the necessary memory during boot time. + There seem to be several versions of this patch against + various kernel versions floating around in the net, + you may obtain one e.g. from: + http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz + You also have to compile your driber AFTER installing that patch + in order to get it working + + or + +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. + For doing this add an entry in lilo.conf (if you use lilo): + append "mem=xxxM" + or add a line in your linux.par file (if you use loadlin): + mem=xxxM + +The second method is by far easier, however it is dangerous +if more than one driver at a time has the idea to use the memory +leftover by setting the mem=xxx parameter below the actual +memory size. + +Read also below how to use this memory! + + + +Driver Options +============== + +You are able to customize the behavior of the driver by giving +it some options at start time. + +default_input, default_norm +--------------------------- + +As soon as the driver is loaded, the Buz samples video signals +from one of its input ports and displays it on its output. +The driver uses the Composite Input and the video norm PAL for this. +If you want to change this default behavior, set default_input=1 +(for S-VHS input) or default_norm=1 for NTSC. + +v4l_nbufs, v4l_bufsize +---------------------- + +In order to make to make full use of the Video for Linux picture +grabbing facilities of the driver (which are needed by many +Video for Linux applications), the driver needs a set of +physically contiguous buffers for grabbing. These parameters +determine how many buffers of which size the driver will +allocate at open (the open will fail if it is unable to do so!). + +These values do not affect the MJPEG grabbing facilities of the driver, +they are needed for uncompressed image grabbing only!!! + +v4l_nbufs is the number of buffers to allocate, a value of 2 (the default) +should be sufficient in allmost all cases. Only special applications +(streaming captures) will need more buffers and then mostly the +MJPEG capturing features of the Buz will be more apropriate. +So leave this parameter at it's default unless you know what you do. + +The things for v4l_bufsize are more complicated: +v4l_bufsize is set by default to 128 [KB] which is the maximum +amount of physically contiguous memory Linux is able to allocate +without kernel changes. This is sufficient for grabbing 24 bit color images +up to sizes of approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072). + +In order to be able to capture bigger images you have either to +- obtain and install the "big_physarea patch" and set aside + the necessary memory during boot time or +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. +In that case, usefull settings for v4l_bufsize are +- 1296 [Kb] for grabbing 24 bit images of max size 768*576 +- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!) +You may reduce these numbers accordingly if you know you are only +grabbing 720 pixels wide images or NTSC images (max height 480). + +In some cases it may happen that Linux isn't even able to obtain +the default 128 KB buffers. If you don't need uncompressed image +grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4) +in order to be able to open the video device. + +vidmem +------ + +The video mem address of the video card. +The driver has a little database for some videocards +to determine it from there. If your video card is not in there +you have either to give it to the driver as a parameter +or set in in a VIDIOCSFBUF ioctl + +The videocard database is contained in the file "videocards.h" +Gernot Ziegler wants to keep an actual version of that file. +If your card is not contained in that file, look at +http://www.lysator.liu.se/~gz/buz/ for an actual version of +"videocards.h". + +triton, natoma +-------------- + +The driver tries to detect if you have a triton or natome chipset +in order to take special messures for these chipsets. +If this detection fails but you are sure you have such a chipset, +set the corresponding variable to 1. +This is a very special option and may go away in the future. + + + +Programming interface +===================== + +This driver should be fully compliant to Video for Linux, so all +tools working with Video for Linux should work with (hopefully) +no problems. + +A description of the Video for Linux programming interace can be found at: +http://roadrunner.swansea.linux.org.uk/v4lapi.shtml + +Besides the Video for Linux interface, the driver has a "proprietary" +interface for accessing the Buz's MJPEG capture and playback facilities. + +The ioctls for that interface are as follows: + +BUZIOC_G_PARAMS +BUZIOC_S_PARAMS + +Get and set the parameters of the buz. The user should allways +do a BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default +settings, change what he likes and then make a BUZIOC_S_PARAMS call. +A typical application should at least set the members +input, norm and decimation of the struct buz_params. +For a full description of all members see "buz.h" + +BUZIOC_REQBUFS + +Before being able to capture/playback, the user has to request +the buffers he is wanting to use. Fill the structure +buz_requestbuffers with the size (recommended: 256*1024) and +the number (recommended 32 up to 256). There are no such restrictions +as for the Video for Linux buffers, you should LEAVE SUFFICIENT +MEMORY for your system however, else strange things will happen .... +On return, the buz_requestbuffers structure contains number and +size of the actually allocated buffers. +You should use these numbers for doing a mmap of the buffers +into the user space. +The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap +maps the MJPEG buffer instead of the V4L buffers. + +BUZIOC_QBUF_CAPT +BUZIOC_QBUF_PLAY + +Queue a buffer for capture or playback. The first call also starts +streaming capture. When streaming capture is going on, you may +only queue further buffers or issue syncs until streaming +capture is switched off again with a argument of -1 to +a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl. + +BUZIOC_SYNC + +Issue this ioctl when all buffers are queued. This ioctl will +block until the first buffer becomes free for saving its +data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY). + +BUZIOC_G_STATUS + +Get the status of the input lines (video source connected/norm). +This ioctl may be subject to change. + + + + + +See the examples directory delivered with this driver +for actual coding examples! diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/bttv/PROBLEMS linux/Documentation/video4linux/bttv/PROBLEMS --- v2.3.9/linux/Documentation/video4linux/bttv/PROBLEMS Sun Aug 23 13:32:25 1998 +++ linux/Documentation/video4linux/bttv/PROBLEMS Mon Jul 5 20:04:47 1999 @@ -17,9 +17,9 @@ If this 64MB area overlaps the IO memory of the Bt848 you also have to remap this. E.g.: insmod bttv vidmem=0xfb0 remap=0xfa0 - If the videomemory is found at the right place and there are no address - conflicts but still no picture (or the computer even crashes.), - try disabling features of your PCI chipset in the BIOS Setup. + If the video memory is found at the right place and there are no address + conflicts but still no picture (or the computer even crashes), + try disabling features of your PCI chipset in the BIOS setup. Frank Kapahnke also reported that problems with his S3 868 went away when he upgraded to XFree 3.2. @@ -50,13 +50,13 @@ Disable backing store by starting X with the option "-bs" -- When using 32bpp in XFree or 24+8bpp mode in AccelX 3.1 the system +- When using 32 bpp in XFree or 24+8bpp mode in AccelX 3.1 the system can sometimes lock up if you use more than 1 bt848 card at the same time. You will always get pixel errors when e.g. using more than 1 card in full screen mode. Maybe we need something faster than the PCI bus ... -- Some S3 cards and the Matrox Mystique will produce pixel erros with - full resolution in 32bit mode. +- Some S3 cards and the Matrox Mystique will produce pixel errors with + full resolution in 32-bit mode. -- Some video cards have problems with Accelerated X 4.1 \ No newline at end of file +- Some video cards have problems with Accelerated X 4.1 diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/bttv/README.RADIO linux/Documentation/video4linux/bttv/README.RADIO --- v2.3.9/linux/Documentation/video4linux/bttv/README.RADIO Sun Aug 23 13:32:25 1998 +++ linux/Documentation/video4linux/bttv/README.RADIO Mon Jul 5 20:04:47 1999 @@ -6,7 +6,7 @@ So you should have TV with (stereo) sound now. Radio does _not_ work. It probably does not work with sat receivers. I can't test this and -therefore hav'nt added support for it yet. If someone needs this and +therefore have not added support for it yet. If someone needs this and can help testing the sat stuff, drop me a note. Gerd diff -u --recursive --new-file v2.3.9/linux/Documentation/video4linux/bttv/THANKS linux/Documentation/video4linux/bttv/THANKS --- v2.3.9/linux/Documentation/video4linux/bttv/THANKS Sun Aug 23 13:32:25 1998 +++ linux/Documentation/video4linux/bttv/THANKS Mon Jul 5 20:04:47 1999 @@ -17,7 +17,7 @@ components on their cards. (E.g. how the tuner type is detected) Without their card I could not have debugged the NTSC mode. -- Hauppauge for telling how the sound input is selected and what compenents +- Hauppauge for telling how the sound input is selected and what components they do and will use on their radio cards. Also many thanks for faxing me the FM1216 data sheet. diff -u --recursive --new-file v2.3.9/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.9/linux/MAINTAINERS Wed Jun 30 13:38:18 1999 +++ linux/MAINTAINERS Tue Jul 6 19:16:55 1999 @@ -16,8 +16,8 @@ SMC etherpower for that.) 3. Make sure your changes compile correctly in multiple - configurations. In paticular check changes work both as a module - and built into the kernel. + configurations. In particular check that changes work both as a + module and built into the kernel. 4. When you are happy with a change make it generally available for testing and await feedback. @@ -28,7 +28,7 @@ and variable names. These aren't as silly as they seem. One job the maintainers (and especially Linus) do is to keep things looking the same. Sometimes this means that the clever hack in - your driver to get around a problem actual needs to become a + your driver to get around a problem actually needs to become a generalized kernel feature ready for next time. See Documentation/CodingStyle for guidance here. @@ -49,8 +49,8 @@ Maintainers List (try to look for most precise areas first) -Note: For the hard of thinking, this list is meant to remain in Alphabetical -order. If you could add yourselves to it in Alphabetical order that would +Note: For the hard of thinking, this list is meant to remain in alphabetical +order. If you could add yourselves to it in alphabetical order that would so much easier [Ed] P: Person @@ -163,6 +163,12 @@ W: http://www.ife.ee.ethz.ch/~sailer/ham/ham.html S: Maintained +BERKSHIRE PRODUCTS PC WATCHDOG DRIVER +P: Kenji Hollis +M: kenji@bitgate.com +W: http://ftp.bitgate.com/pcwd/ +S: Maintained + BUSLOGIC SCSI DRIVER P: Leonard N. Zubkoff M: Leonard N. Zubkoff @@ -271,6 +277,12 @@ L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu S: Maintained +COMPAQ SMART2 RAID DRIVER +P: Charles White +M: Charles White +L: compaqandlinux@yps.org +S: Maintained + EATA ISA/EISA/PCI SCSI DRIVER P: Dario Ballabio M: dario@milano.europe.dg.com @@ -579,6 +591,26 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +OLYMPIC NETWORK DRIVER +P: Peter De Shrijver +M: p2@ace.ulyssis.sutdent.kuleuven.ac.be +P: Mike Phillips +M: phillim@amtrak.com +L: linux-net@vger.rutgers.edu +L: linux-tr@emissary.aus-etc.com +W: http://www.linuxtr.net +S: Maintained + +OLYMPIC NETWORK DRIVER +P: Peter De Shrijver +M: p2@ace.ulyssis.sutdent.kuleuven.ac.be +P: Mike Phillips +M: phillim@amtrak.com +L: linux-net@vger.rutgers.edu +L: linux-tr@emissary.aus-etc.com +W: http://www.linuxtr.net +S: Maintained + OPL3-SA2, SA3, and SAx DRIVER P: Scott Murray M: scottm@interlog.com @@ -645,7 +677,7 @@ REAL TIME CLOCK DRIVER P: Paul Gortmaker -M gpg109@rsphy1.anu.edu.au +M: gpg109@rsphy1.anu.edu.au L: linux-kernel@vger.rutgers.edu S: Maintained @@ -697,9 +729,10 @@ S: Maintained SMB FILESYSTEM -P: Volker Lendecke -M: vl@kki.org -L: samba@listproc.anu.edu.au +P: Andrew Tridgell +M: tridge@samba.org +W: http://samba.org/ +L: samba@samba.org S: Maintained SMP: (except SPARC) diff -u --recursive --new-file v2.3.9/linux/Makefile linux/Makefile --- v2.3.9/linux/Makefile Wed Jun 30 13:38:18 1999 +++ linux/Makefile Thu Jul 1 10:54:31 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 9 +SUBLEVEL = 10 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -351,8 +351,7 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' \ - ! -regex '.*ksymoops/.*' -print` + rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` rm -f core `find . -type f -name 'core' -print` rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map @@ -376,7 +375,6 @@ rm -f .version .config* config.in config.old rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog - rm -f scripts/ksymoops/*.o scripts/ksymoops/ksymoops rm -f .menuconfig.log rm -f include/asm rm -rf include/config diff -u --recursive --new-file v2.3.9/linux/README linux/README --- v2.3.9/linux/README Sun May 30 10:17:43 1999 +++ linux/README Thu Jul 1 10:54:08 1999 @@ -9,9 +9,9 @@ bugs. It is *strongly* recommended that you back up the previous kernel before installing any new 2.3.xx release. -If you need to use a proven and stable Linux kernel, please use 1.2.13, -2.0.36 or 2.2.xx. All features which will be in the 2.3.xx releases will -be contained in 2.4.xx when the code base has stabilized again. +If you need to use a proven and stable Linux kernel, please use 2.0.37 +or 2.2.xx. All features which will be in the 2.3.xx releases will be +contained in 2.4.xx when the code base has stabilized again. If you decide to use 2.3, it is recommended that you join the kernel mailing list. To do this, e-mail majordomo@vger.rutgers.edu, and put in the body @@ -105,7 +105,7 @@ SOFTWARE REQUIREMENTS - Compiling and running the 2.3.x kernels requires up-to-date + Compiling and running the 2.3.xx kernels requires up-to-date versions of various software packages. Consult ./Documentation/Changes for the minimum version numbers required and how to get updates for these packages. Beware that using diff -u --recursive --new-file v2.3.9/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.3.9/linux/arch/alpha/config.in Wed Jun 30 13:38:18 1999 +++ linux/arch/alpha/config.in Thu Jul 1 14:22:56 1999 @@ -188,13 +188,7 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi -fi +source drivers/misc/Config.in endmenu source drivers/pnp/Config.in diff -u --recursive --new-file v2.3.9/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.3.9/linux/arch/alpha/kernel/ptrace.c Mon Jun 7 11:15:33 1999 +++ linux/arch/alpha/kernel/ptrace.c Sun Jul 4 13:41:08 1999 @@ -135,242 +135,18 @@ return 0; } -/* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - */ -static unsigned long -get_long(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long addr) -{ - pgd_t * pgdir; - pmd_t * pgmiddle; - pte_t * pgtable; - unsigned long page; - - DBG(DBG_MEM_ALL, ("getting long at 0x%lx\n", addr)); - repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return 0; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return 0; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - page = pte_page(*pgtable); - /* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) >= max_mapnr) - return 0; - page += addr & ~PAGE_MASK; - return *(unsigned long *) page; -} - -/* - * This routine puts a long into any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * Now keeps R/W state of page so that a text page stays readonly - * even if a debugger scribbles breakpoints into it. -M.U- - */ -static void -put_long(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long addr, unsigned long data) +static inline int +read_int(struct task_struct *task, unsigned long addr, int * data) { - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page; - - repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - page = pte_page(*pgtable); - if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - - /* This is a hack for non-kernel-mapped video buffers and similar. */ - if (MAP_NR(page) < max_mapnr) - *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; - - /* We're bypassing pagetables, so we have to set the dirty bit - ourselves. This should also re-instate whatever read-only - mode there was before. */ - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb(); -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ -static int -read_long(struct task_struct * tsk, unsigned long addr, unsigned long * result) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - DBG(DBG_MEM_ALL, ("in read_long\n")); - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > (PAGE_SIZE - sizeof(long))) { - struct vm_area_struct * vma_high = vma; - unsigned long low, align; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - align = addr & (sizeof(long) - 1); - addr -= align; - low = get_long(tsk, vma, addr); - if (align) { - unsigned long high; - - high = get_long(tsk, vma_high, addr + sizeof(long)); - low >>= align * 8; - low |= high << (64 - align * 8); - } - *result = low; - } else { - long l = get_long(tsk, vma, addr); - - DBG(DBG_MEM_ALL, ("value is 0x%lx\n", l)); - *result = l; - } - return 0; + int copied = access_process_vm(task, addr, data, sizeof(int), 0); + return (copied == sizeof(int)) ? 0 : -EIO; } -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ -static int -write_long(struct task_struct * tsk, unsigned long addr, unsigned long data) +static inline int +write_int(struct task_struct *task, unsigned long addr, int data) { - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low, high, align; - struct vm_area_struct * vma_high = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - align = addr & (sizeof(long) - 1); - addr -= align; - low = get_long(tsk, vma, addr); - high = get_long(tsk, vma_high, addr + sizeof(long)); - low &= ~0UL >> (64 - align * 8); - high &= ~0UL << (align * 8); - low |= data << (align * 8); - high |= data >> (64 - align * 8); - put_long(tsk, vma, addr, low); - put_long(tsk, vma_high, addr + sizeof(long), high); - } else - put_long(tsk, vma, addr, data); - return 0; -} - -/* - * Read a 32bit int from address space TSK. - */ -static int -read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data) -{ - unsigned long l, align; - int res; - - align = addr & 0x7; - addr &= ~0x7; - - res = read_long(tsk, addr, &l); - if (res < 0) - return res; - - if (align == 0) { - *data = l; - } else { - *data = l >> 32; - } - return 0; -} - -/* - * Write a 32bit word to address space TSK. - * - * For simplicity, do a read-modify-write of the 64bit word that - * contains the 32bit word that we are about to write. - */ -static int -write_int(struct task_struct * tsk, unsigned long addr, unsigned int data) -{ - unsigned long l, align; - int res; - - align = addr & 0x7; - addr &= ~0x7; - - res = read_long(tsk, addr, &l); - if (res < 0) - return res; - - if (align == 0) { - l = (l & 0xffffffff00000000UL) | ((unsigned long) data << 0); - } else { - l = (l & 0x00000000ffffffffUL) | ((unsigned long) data << 32); - } - return write_long(tsk, addr, l); + int copied = access_process_vm(task, addr, &data, sizeof(int), 1); + return (copied == sizeof(int)) ? 0 : -EIO; } /* @@ -521,16 +297,17 @@ switch (request) { /* When I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - down(&child->mm->mmap_sem); - ret = read_long(child, addr, &tmp); - up(&child->mm->mmap_sem); - DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp)); - if (ret < 0) + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) goto out; + regs.r0 = 0; /* special return: no errors */ ret = tmp; goto out; + } /* Read register number ADDR. */ case PTRACE_PEEKUSR: @@ -541,12 +318,12 @@ /* When I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data)); - down(&child->mm->mmap_sem); - ret = write_long(child, addr, data); - up(&child->mm->mmap_sem); + case PTRACE_POKEDATA: { + unsigned long tmp = data; + int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1); + ret = (copied == sizeof(tmp)) ? 0 : -EIO; goto out; + } case PTRACE_POKEUSR: /* write the specified register */ DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data)); diff -u --recursive --new-file v2.3.9/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.3.9/linux/arch/alpha/kernel/signal.c Fri May 14 12:41:23 1999 +++ linux/arch/alpha/kernel/signal.c Mon Jul 5 20:35:17 1999 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.3.9/linux/arch/alpha/kernel/smp.c Tue Jun 22 10:46:52 1999 +++ linux/arch/alpha/kernel/smp.c Thu Jul 1 15:09:48 1999 @@ -603,7 +603,7 @@ update_one_process(current, 1, user, !user, cpu); if (current->pid) { - if (--current->counter < 0) { + if (--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff -u --recursive --new-file v2.3.9/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.3.9/linux/arch/arm/kernel/process.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/process.c Mon Jul 5 20:35:17 1999 @@ -27,9 +27,7 @@ #include #include #include -#include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.3.9/linux/arch/arm/kernel/time.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/kernel/time.c Mon Jul 5 20:35:17 1999 @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c --- v2.3.9/linux/arch/arm/nwfpe/fpmodule.c Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpmodule.c Mon Jul 5 20:35:17 1999 @@ -36,7 +36,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.3.9/linux/arch/i386/boot/setup.S Sat Nov 28 17:18:54 1998 +++ linux/arch/i386/boot/setup.S Mon Jul 5 20:04:47 1999 @@ -753,19 +753,29 @@ ! This routine checks that the keyboard command queue is empty ! (after emptying the output buffers) ! -! No timeout is used - if this hangs there is something wrong with -! the machine, and we probably couldn't proceed anyway. +! Some machines have delusions that the keyboard buffer is always full +! with no keyboard attached... + empty_8042: + push ecx + mov ecx,#0xFFFFFF + +empty_8042_loop: + dec ecx + jz empty_8042_end_loop + call delay in al,#0x64 ! 8042 status port test al,#1 ! output buffer? jz no_output call delay in al,#0x60 ! read it - jmp empty_8042 + jmp empty_8042_loop no_output: test al,#2 ! is input buffer full? - jnz empty_8042 ! yes - loop + jnz empty_8042_loop ! yes - loop +empty_8042_end_loop: + pop ecx ret ! diff -u --recursive --new-file v2.3.9/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.9/linux/arch/i386/config.in Wed Jun 30 13:38:18 1999 +++ linux/arch/i386/config.in Thu Jul 1 14:22:56 1999 @@ -92,13 +92,7 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi -fi +source drivers/misc/Config.in bool 'Advanced Power Management BIOS support' CONFIG_APM if [ "$CONFIG_APM" = "y" ]; then diff -u --recursive --new-file v2.3.9/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.9/linux/arch/i386/defconfig Wed Jun 30 13:38:18 1999 +++ linux/arch/i386/defconfig Tue Jul 6 20:31:23 1999 @@ -70,11 +70,6 @@ # CONFIG_I2O_PROC is not set # -# Plug and Play support -# -# CONFIG_PNP is not set - -# # Block devices # CONFIG_BLK_DEV_FD=y @@ -98,7 +93,10 @@ # CONFIG_BLK_DEV_IDEDMA_PCI is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_HPT34X is not set +CONFIG_BLK_DEV_PIIX=y # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -214,9 +212,17 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set CONFIG_DUMMY=m # CONFIG_EQUALIZER is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -236,14 +242,22 @@ # CONFIG_VIA_RHINE is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set -# CONFIG_DLCI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # CONFIG_WAN_DRIVERS is not set # CONFIG_LAPBETHER is not set # CONFIG_X25_ASY is not set diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h --- v2.3.9/linux/arch/i386/kernel/irq.h Tue Jun 22 14:43:14 1999 +++ linux/arch/i386/kernel/irq.h Wed Jul 7 09:22:14 1999 @@ -238,7 +238,7 @@ */ static inline void x86_do_profile (unsigned long eip) { - if (prof_buffer && current->pid) { + if (prof_buffer) { eip -= (unsigned long) &_stext; eip >>= prof_shift; /* diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.3.9/linux/arch/i386/kernel/process.c Fri Apr 30 08:13:37 1999 +++ linux/arch/i386/kernel/process.c Mon Jul 5 20:35:17 1999 @@ -26,9 +26,7 @@ #include #include #include -#include #include -#include #include #include #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.3.9/linux/arch/i386/kernel/ptrace.c Mon Jun 7 11:15:33 1999 +++ linux/arch/i386/kernel/ptrace.c Sun Jul 4 13:41:08 1999 @@ -67,205 +67,6 @@ return 0; } -/* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - */ -static unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) -{ - pgd_t * pgdir; - pmd_t * pgmiddle; - pte_t * pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return 0; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return 0; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) >= max_mapnr) - return 0; - page += addr & ~PAGE_MASK; - return *(unsigned long *) page; -} - -/* - * This routine puts a long into any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * Now keeps R/W state of page so that a text page stays readonly - * even if a debugger scribbles breakpoints into it. -M.U- - */ -static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, - unsigned long data) -{ - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - page = pte_page(*pgtable); - if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) < max_mapnr) - *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; -/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ -/* this should also re-instate whatever read-only mode there was before */ - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb(); -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ -static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_high = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 1: - low >>= 8; - low |= high << 24; - break; - case 2: - low >>= 16; - low |= high << 16; - break; - case 3: - low >>= 24; - low |= high << 8; - break; - } - *result = low; - } else - *result = get_long(tsk, vma, addr); - return 0; -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ -static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_high = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 0: /* shouldn't happen, but safety first */ - low = data; - break; - case 1: - low &= 0x000000ff; - low |= data << 8; - high &= ~0xff; - high |= data >> 24; - break; - case 2: - low &= 0x0000ffff; - low |= data << 16; - high &= ~0xffff; - high |= data >> 16; - break; - case 3: - low &= 0x00ffffff; - low |= data << 24; - high &= ~0xffffff; - high |= data >> 8; - break; - } - put_long(tsk, vma, addr & ~(sizeof(long)-1),low); - put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); - } else - put_long(tsk, vma, addr, data); - return 0; -} - static int putreg(struct task_struct *child, unsigned long regno, unsigned long value) { @@ -402,12 +203,13 @@ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; + int copied; - down(&child->mm->mmap_sem); - ret = read_long(child, addr, &tmp); - up(&child->mm->mmap_sem); - if (ret >= 0) - ret = put_user(tmp,(unsigned long *) data); + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + goto out; + ret = put_user(tmp,(unsigned long *) data); goto out; } @@ -436,9 +238,10 @@ /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - down(&child->mm->mmap_sem); - ret = write_long(child,addr,data); - up(&child->mm->mmap_sem); + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + goto out; + ret = -EIO; goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.9/linux/arch/i386/kernel/setup.c Tue Jun 8 10:42:46 1999 +++ linux/arch/i386/kernel/setup.c Mon Jul 5 20:04:47 1999 @@ -11,7 +11,7 @@ * Zoltan Boszormenyi February 1999. * * Force Centaur C6 processors to report MTRR capability. - * Bart Hartgers , May 199. + * Bart Hartgers , May 1999. * * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999. */ @@ -690,8 +690,8 @@ NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 6, { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", - NULL, "Pentium II (Deschutes)", "Mobile Pentium II", NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)", + "Pentium III (Coppermine)", NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 4, { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", @@ -799,16 +799,15 @@ /* Names for the Pentium II Celeron processors detectable only by also checking the cache size */ if ((cpu_models[i].vendor == X86_VENDOR_INTEL) - && (cpu_models[i].x86 == 6)){ - if(c->x86_model == 6 && c->x86_cache_size == 128) { + && (cpu_models[i].x86 == 6)) + { + if(c->x86_model == 5 && c->x86_cache_size == 0) + p = "Celeron (Covington)"; + else if(c->x86_model == 6 && c->x86_cache_size == 128) p = "Celeron (Mendocino)"; - } - else { - if (c->x86_model == 5 && c->x86_cache_size == 0) { - p = "Celeron (Covington)"; - } - } - } + else if(c->x86_model == 5 && c->x86_cache_size == 256) + p = "Celeron (Dixon)"; + } } } diff -u --recursive --new-file v2.3.9/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.3.9/linux/arch/i386/kernel/smp.c Wed Jun 16 19:26:27 1999 +++ linux/arch/i386/kernel/smp.c Thu Jul 1 15:09:00 1999 @@ -1792,7 +1792,7 @@ update_one_process(p, 1, user, system, cpu); if (p->pid) { p->counter -= 1; - if (p->counter < 0) { + if (p->counter <= 0) { p->counter = 0; p->need_resched = 1; } diff -u --recursive --new-file v2.3.9/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h --- v2.3.9/linux/arch/i386/math-emu/fpu_emu.h Sun Sep 13 12:58:05 1998 +++ linux/arch/i386/math-emu/fpu_emu.h Mon Jul 5 20:35:17 1999 @@ -165,8 +165,6 @@ #define signpositive(a) ( (signbyte(a) & 0x80) == 0 ) #define signnegative(a) (signbyte(a) & 0x80) -#include "fpu_proto.h" - static inline void reg_copy(FPU_REG const *x, FPU_REG *y) { *(short *)&(y->exp) = *(const short *)&(x->exp); diff -u --recursive --new-file v2.3.9/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.3.9/linux/arch/i386/mm/fault.c Tue May 11 17:11:34 1999 +++ linux/arch/i386/mm/fault.c Sat Jul 3 12:04:12 1999 @@ -50,7 +50,8 @@ start &= PAGE_MASK; for (;;) { - handle_mm_fault(current,vma, start, 1); + if (handle_mm_fault(current, vma, start, 1) <= 0) + goto bad_area; if (!size) break; size--; @@ -162,8 +163,13 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ - if (!handle_mm_fault(tsk, vma, address, write)) - goto do_sigbus; + { + int fault = handle_mm_fault(tsk, vma, address, write); + if (fault < 0) + goto out_of_memory; + if (!fault) + goto do_sigbus; + } /* * Did it hit the DOS screen memory VA from vm86 mode? @@ -255,6 +261,13 @@ * We ran out of memory, or some other thing happened to us that made * us unable to handle the page fault gracefully. */ +out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", tsk->comm); + if (error_code & 4) + do_exit(SIGKILL); + goto no_context; + do_sigbus: up(&mm->mmap_sem); diff -u --recursive --new-file v2.3.9/linux/arch/mips/boot/elf2ecoff.c linux/arch/mips/boot/elf2ecoff.c --- v2.3.9/linux/arch/mips/boot/elf2ecoff.c Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/boot/elf2ecoff.c Mon Jul 5 20:35:17 1999 @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.3.9/linux/arch/mips/config.in Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/config.in Mon Jul 5 19:44:57 1999 @@ -93,7 +93,7 @@ bool 'Sysctl support' CONFIG_SYSCTL if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then - tristate 'Parallel port support' CONFIG_PARPORT +source drivers/misc/Config.in fi endmenu diff -u --recursive --new-file v2.3.9/linux/arch/mips/defconfig linux/arch/mips/defconfig --- v2.3.9/linux/arch/mips/defconfig Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/defconfig Mon Jul 5 19:44:57 1999 @@ -63,11 +63,6 @@ # CONFIG_I2O_PROC is not set # -# Plug and Play support -# -# CONFIG_PNP is not set - -# # Block devices # CONFIG_BLK_DEV_FD=m diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c --- v2.3.9/linux/arch/mips/kernel/irixioctl.c Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/kernel/irixioctl.c Tue Jul 6 10:11:40 1999 @@ -29,20 +29,21 @@ unsigned long arg); extern asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count); extern void start_tty(struct tty_struct *tty); - static struct tty_struct *get_tty(int fd) { struct file *filp; + struct tty_struct *ttyp = NULL; - if(!(filp = fcheck(fd))) - return ((struct tty_struct *) 0); - if(filp->private_data) { - struct tty_struct *ttyp = (struct tty_struct *) filp->private_data; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + if(filp && filp->private_data) { + ttyp = (struct tty_struct *) filp->private_data; - if(ttyp->magic == TTY_MAGIC) - return ttyp; + if(ttyp->magic != TTY_MAGIC) + ttyp =NULL; } - return ((struct tty_struct *) 0); + read_unlock(¤t->files->file_lock); + return ttyp; } static struct tty_struct *get_real_tty(struct tty_struct *tp) diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c --- v2.3.9/linux/arch/mips/kernel/ptrace.c Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/kernel/ptrace.c Mon Jul 5 19:44:57 1999 @@ -25,218 +25,6 @@ #include #include -/* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - */ -static unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) -{ - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page, retval; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return 0; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return 0; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - page = pte_page(*pgtable); - /* This is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) >= MAP_NR(high_memory)) - return 0; - page += addr & ~PAGE_MASK; - /* We can't use flush_page_to_ram() since we're running in - * another context ... - */ - flush_cache_all(); - retval = *(unsigned long *) page; - flush_cache_all(); /* VCED avoidance */ - return retval; -} - -/* - * This routine puts a long into any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * Now keeps R/W state of page so that a text page stays readonly - * even if a debugger scribbles breakpoints into it. -M.U- - */ -static void put_long(struct task_struct *tsk, - struct vm_area_struct * vma, unsigned long addr, - unsigned long data) -{ - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - page = pte_page(*pgtable); - if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - /* This is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) < MAP_NR(high_memory)) - flush_cache_all(); - *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; - if (MAP_NR(page) < MAP_NR(high_memory)) - flush_cache_all(); - /* - * We're bypassing pagetables, so we have to set the dirty bit - * ourselves this should also re-instate whatever read-only mode - * there was before - */ - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_page(vma, addr); -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ -static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_high = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 1: - low >>= 8; - low |= high << 24; - break; - case 2: - low >>= 16; - low |= high << 16; - break; - case 3: - low >>= 24; - low |= high << 8; - break; - } - *result = low; - } else - *result = get_long(tsk, vma, addr); - return 0; -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ -static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_high = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_high = vma->vm_next; - if (!vma_high || vma_high->vm_start != vma->vm_end) - return -EIO; - } - low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); - high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 0: /* shouldn't happen, but safety first */ - low = data; - break; - case 1: - low &= 0x000000ff; - low |= data << 8; - high &= ~0xff; - high |= data >> 24; - break; - case 2: - low &= 0x0000ffff; - low |= data << 16; - high &= ~0xffff; - high |= data >> 16; - break; - case 3: - low &= 0x00ffffff; - low |= data << 24; - high &= ~0xffffff; - high |= data >> 8; - break; - } - put_long(tsk, vma, addr & ~(sizeof(long)-1),low); - put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); - } else - put_long(tsk, vma, addr, data); - return 0; -} - asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -322,15 +110,16 @@ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; + int copied; - down(&child->mm->mmap_sem); - res = read_long(child, addr, &tmp); - up(&child->mm->mmap_sem); - if (res < 0) + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + res = -EIO; + if (copied != sizeof(tmp)) goto out; res = put_user(tmp,(unsigned long *) data); + goto out; - } + } /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { @@ -394,9 +183,11 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - down(&child->mm->mmap_sem); - res = write_long(child,addr,data); - up(&child->mm->mmap_sem); + res = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) + == sizeof(data)) + goto out; + res = -EIO; goto out; case PTRACE_POKEUSR: { diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S --- v2.3.9/linux/arch/mips/kernel/r4k_misc.S Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/kernel/r4k_misc.S Mon Jul 5 20:35:17 1999 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c --- v2.3.9/linux/arch/mips/kernel/setup.c Wed Jun 30 13:38:18 1999 +++ linux/arch/mips/kernel/setup.c Mon Jul 5 20:35:17 1999 @@ -30,7 +30,6 @@ #endif #include #ifdef CONFIG_RTC -#include #include #endif diff -u --recursive --new-file v2.3.9/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c --- v2.3.9/linux/arch/mips/mm/fault.c Wed Jun 30 13:38:19 1999 +++ linux/arch/mips/mm/fault.c Mon Jul 5 19:44:57 1999 @@ -43,7 +43,7 @@ * and the problem, and then passes it off to one of the appropriate * routines. */ -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long address) { struct vm_area_struct * vma; @@ -59,7 +59,7 @@ goto no_context; #if 0 printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid, - address, writeaccess, regs->cp0_epc); + address, write, regs->cp0_epc); #endif down(&mm->mmap_sem); vma = find_vma(mm, address); @@ -76,14 +76,26 @@ * we can handle it.. */ good_area: - if (writeaccess) { + if (write) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(tsk, vma, address, writeaccess); + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + { + int fault = handle_mm_fault(tsk, vma, address, write); + if (fault < 0) + goto out_of_memory; + if (!fault) + goto do_sigbus; + } up(&mm->mmap_sem); return; @@ -96,12 +108,12 @@ if (user_mode(regs)) { tsk->tss.cp0_badvaddr = address; - tsk->tss.error_code = writeaccess; + tsk->tss.error_code = write; #if 0 printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n" "%08lx (epc == %08lx, ra == %08lx)\n", tsk->comm, - writeaccess ? "writeaccess to" : "readaccess from", + write ? "write access to" : "read access from", address, (unsigned long) regs->cp0_epc, (unsigned long) regs->regs[31]); @@ -132,6 +144,31 @@ printk(KERN_ALERT "Unable to handle kernel paging request at virtual " "address %08lx, epc == %08lx, ra == %08lx\n", address, regs->cp0_epc, regs->regs[31]); - die("Oops", regs, writeaccess); + die("Oops", regs, write); do_exit(SIGKILL); + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", tsk->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + * XXX Store details about fault for siginfo handling into tss. + */ + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; } diff -u --recursive --new-file v2.3.9/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c --- v2.3.9/linux/arch/mips/sgi/kernel/indy_sc.c Wed Jun 30 13:38:19 1999 +++ linux/arch/mips/sgi/kernel/indy_sc.c Thu Jul 1 10:45:57 1999 @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.3.9/linux/arch/ppc/amiga/amiints.c Thu Jan 7 08:46:58 1999 +++ linux/arch/ppc/amiga/amiints.c Mon Jul 5 20:07:02 1999 @@ -108,7 +108,7 @@ custom.intreq = 0x7fff; #ifdef CONFIG_APUS - /* Clear any inter-CPU interupt requests. Circumvents bug in + /* Clear any inter-CPU interrupt requests. Circumvents bug in Blizzard IPL emulation HW (or so it appears). */ APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); diff -u --recursive --new-file v2.3.9/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c --- v2.3.9/linux/arch/ppc/amiga/config.c Mon Dec 21 08:37:20 1998 +++ linux/arch/ppc/amiga/config.c Mon Jul 5 20:35:17 1999 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.3.9/linux/arch/ppc/config.in Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/config.in Thu Jul 1 14:22:56 1999 @@ -66,13 +66,7 @@ define_bool CONFIG_KERNEL_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi -fi +source drivers/misc/Config.in bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.9/linux/arch/ppc/kernel/irq.c Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/kernel/irq.c Mon Jul 5 20:35:17 1999 @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.3.9/linux/arch/ppc/kernel/pci.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/pci.c Mon Jul 5 20:35:17 1999 @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c --- v2.3.9/linux/arch/ppc/kernel/ppc-stub.c Tue Aug 4 16:06:36 1998 +++ linux/arch/ppc/kernel/ppc-stub.c Mon Jul 5 20:35:17 1999 @@ -107,7 +107,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.3.9/linux/arch/ppc/kernel/prep_setup.c Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/kernel/prep_setup.c Mon Jul 5 20:35:17 1999 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.3.9/linux/arch/ppc/kernel/process.c Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/kernel/process.c Thu Jul 1 10:45:57 1999 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.9/linux/arch/ppc/kernel/setup.c Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/kernel/setup.c Mon Jul 5 20:35:17 1999 @@ -32,7 +32,6 @@ #endif #include #include -#include extern void pmac_init(unsigned long r3, unsigned long r4, diff -u --recursive --new-file v2.3.9/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.3.9/linux/arch/ppc/kernel/smp.c Wed Jun 30 13:38:19 1999 +++ linux/arch/ppc/kernel/smp.c Thu Jul 1 15:09:00 1999 @@ -85,7 +85,7 @@ update_one_process(p, 1, user, system, cpu); p->counter -= 1; - if (p->counter < 0) { + if (p->counter <= 0) { p->counter = 0; current->need_resched = 1; } diff -u --recursive --new-file v2.3.9/linux/arch/sparc/ap1000/aplib.c linux/arch/sparc/ap1000/aplib.c --- v2.3.9/linux/arch/sparc/ap1000/aplib.c Tue Aug 4 16:03:34 1998 +++ linux/arch/sparc/ap1000/aplib.c Mon Jul 5 20:35:17 1999 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c --- v2.3.9/linux/arch/sparc/kernel/pcic.c Wed Jun 9 14:44:25 1999 +++ linux/arch/sparc/kernel/pcic.c Mon Jul 5 20:35:17 1999 @@ -20,7 +20,6 @@ #include #include /* for sanity check... */ #include /* for cache flushing. */ - #include #undef PROM_DEBUG @@ -39,7 +38,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.3.9/linux/arch/sparc/kernel/process.c Tue May 11 08:24:31 1999 +++ linux/arch/sparc/kernel/process.c Mon Jul 5 20:35:17 1999 @@ -37,7 +37,6 @@ #include #include #include -#include #include extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.3.9/linux/arch/sparc/kernel/ptrace.c Mon Jun 7 11:15:33 1999 +++ linux/arch/sparc/kernel/ptrace.c Mon Jul 5 11:30:11 1999 @@ -24,202 +24,6 @@ #define MAGIC_CONSTANT 0x80000000 -/* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - */ -static unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) -{ - pgd_t * pgdir; - pmd_t * pgmiddle; - pte_t * pgtable; - unsigned long page, retval; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return 0; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return 0; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } - page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) >= max_mapnr) - return 0; - page += addr & ~PAGE_MASK; - retval = *(unsigned long *) page; - flush_page_to_ram(page); - return retval; -} - -/* - * This routine puts a long into any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * Now keeps R/W state of page so that a text page stays readonly - * even if a debugger scribbles breakpoints into it. -M.U- - */ -static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long addr, unsigned long data) -{ - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } - page = pte_page(*pgtable); - if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } -/* this is a hack for non-kernel-mapped video buffers and similar */ - flush_cache_page(vma, addr); - if (MAP_NR(page) < max_mapnr) { - *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; - flush_page_to_ram(page); - } -/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ -/* this should also re-instate whatever read-only mode there was before */ - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_page(vma, addr); -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ -static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - *result = get_long(tsk, vma, addr); - return 0; -} - -static int read_byte(struct task_struct *tsk, unsigned long addr, - unsigned char *result) -{ - struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3); - unsigned long tmp; - - if(!vma) - return -EIO; - tmp = get_long(tsk, vma, (addr & ~3)); - switch(addr & 3) { - case 0: - *result = (tmp & 0xff000000)>>24; - break; - case 1: - *result = (tmp & 0x00ff0000)>>16; - break; - case 2: - *result = (tmp & 0x0000ff00)>>8; - break; - case 3: - *result = (tmp & 0x000000ff); - break; - } - return 0; -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ -static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - put_long(tsk, vma, addr, data); - return 0; -} - -static int write_byte(struct task_struct * tsk, unsigned long addr, - unsigned char data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3)); - unsigned long tmp; - - if (!vma) - return -EIO; - tmp = get_long(tsk, vma, (addr & ~3)); - switch(addr & 3) { - case 0: - tmp &= 0x00ffffff; - tmp |= (data << 24); - break; - case 1: - tmp &= 0xff00ffff; - tmp |= ((data << 16) & 0x00ff0000); - break; - case 2: - tmp &= 0xffff00ff; - tmp |= ((data << 8) & 0x0000ff00); - break; - case 3: - tmp &= 0xffffff00; - tmp |= (data & 0x000000ff); - break; - } - put_long(tsk, vma, (addr & ~3), tmp); - return 0; -} /* Returning from ptrace is a bit tricky because the syscall return * low level code assumes any value returned which is negative and @@ -565,24 +369,12 @@ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; - - /* XXX Find out what is really going on. */ - flush_cache_all(); - /* Non-word alignment _not_ allowed on Sparc. */ - if(addr & (sizeof(unsigned long) - 1)) { - pt_error_return(regs, EINVAL); - goto out; - } - down(&child->mm->mmap_sem); - res = read_long(child, addr, &tmp); - up(&child->mm->mmap_sem); - if (res < 0) { - pt_error_return(regs, -res); - goto out; - } - pt_os_succ_return(regs, tmp, (long *) data); + if (access_process_vm(child, addr, + &tmp, sizeof(tmp), 0) == sizeof(tmp)) + pt_os_succ_return(regs, tmp, (long *)data); + else + pt_error_return(regs, EIO); goto out; } @@ -596,22 +388,11 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: { - struct vm_area_struct *vma; - int res; - - /* Non-word alignment _not_ allowed on Sparc. */ - if(addr & (sizeof(unsigned long) - 1)) { - pt_error_return(regs, EINVAL); - goto out; - } - down(&child->mm->mmap_sem); - vma = find_extend_vma(child, addr); - res = write_long(child, addr, data); - up(&child->mm->mmap_sem); - if(res < 0) - pt_error_return(regs, -res); + if (access_process_vm(child, addr, + &data, sizeof(data), 1) == sizeof(data)) + pt_succ_return(regs, 0); else - pt_succ_return(regs, res); + pt_error_return(regs, EIO); goto out; } @@ -737,56 +518,31 @@ case PTRACE_READTEXT: case PTRACE_READDATA: { - unsigned char *dest = (unsigned char *) addr2; - unsigned long src = addr; - unsigned char tmp; - int res, len = data; - - res = verify_area(VERIFY_WRITE, dest, len); - if(res) { - pt_error_return(regs, -res); - goto out; - } - while(len) { - down(&child->mm->mmap_sem); - res = read_byte(child, src, &tmp); - up(&child->mm->mmap_sem); - if(res < 0) { - pt_error_return(regs, -res); - goto out; - } - __put_user(tmp, dest); - src++; dest++; len--; + int res = ptrace_readdata(child, addr, (void *) addr2, data); + + if (res == data) { + pt_succ_return(regs, 0); + goto out; } - pt_succ_return(regs, 0); + /* Partial read is an IO failure */ + if (res >= 0) + res = -EIO; + pt_error_return(regs, -res); goto out; } case PTRACE_WRITETEXT: case PTRACE_WRITEDATA: { - unsigned char *src = (unsigned char *) addr2; - unsigned long dest = addr; - int res, len = data; - - res = verify_area(VERIFY_READ, src, len); - if(res) { - pt_error_return(regs, -res); - goto out; - } - while(len) { - unsigned long tmp; - - __get_user(tmp, src); - down(&child->mm->mmap_sem); - res = write_byte(child, dest, tmp); - up(&child->mm->mmap_sem); - if(res < 0) { - pt_error_return(regs, -res); - goto out; - } - src++; dest++; len--; + int res = ptrace_writedata(child, (void *) addr2, addr, data); + + if (res == data) { + pt_succ_return(regs, 0); + goto out; } - pt_succ_return(regs, 0); + /* Partial write is an IO failure */ + if (res >= 0) + res = -EIO; + pt_error_return(regs, -res); goto out; } diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v2.3.9/linux/arch/sparc/kernel/sparc-stub.c Tue Apr 14 17:44:19 1998 +++ linux/arch/sparc/kernel/sparc-stub.c Mon Jul 5 20:35:17 1999 @@ -105,7 +105,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.3.9/linux/arch/sparc/kernel/sparc_ksyms.c Sun Mar 21 07:23:38 1999 +++ linux/arch/sparc/kernel/sparc_ksyms.c Mon Jul 5 20:35:17 1999 @@ -40,7 +40,6 @@ #include #endif #include -#include #include struct poll { diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.3.9/linux/arch/sparc/kernel/sun4d_smp.c Tue May 11 08:24:31 1999 +++ linux/arch/sparc/kernel/sun4d_smp.c Thu Jul 1 15:09:00 1999 @@ -473,7 +473,7 @@ if(current->pid) { update_one_process(current, 1, user, !user, cpu); - if(--current->counter < 0) { + if(--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.3.9/linux/arch/sparc/kernel/sun4m_smp.c Tue May 11 08:24:31 1999 +++ linux/arch/sparc/kernel/sun4m_smp.c Thu Jul 1 15:09:01 1999 @@ -454,7 +454,7 @@ if(current->pid) { update_one_process(current, 1, user, !user, cpu); - if(--current->counter < 0) { + if(--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c --- v2.3.9/linux/arch/sparc/kernel/sunos_ioctl.c Tue Oct 27 09:52:20 1998 +++ linux/arch/sparc/kernel/sunos_ioctl.c Tue Jul 6 10:11:40 1999 @@ -36,11 +36,10 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) { - struct file *filp; int ret = -EBADF; lock_kernel(); - if (fd >= SUNOS_NR_OPEN || !(filp = current->files->fd [fd])) + if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) goto out; /* First handle an easy compat. case for tty ldisc. */ diff -u --recursive --new-file v2.3.9/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.3.9/linux/arch/sparc/kernel/sys_sunos.c Wed Jun 30 13:38:19 1999 +++ linux/arch/sparc/kernel/sys_sunos.c Mon Jul 5 20:35:17 1999 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c --- v2.3.9/linux/arch/sparc/mm/asyncd.c Wed May 12 08:41:12 1999 +++ linux/arch/sparc/mm/asyncd.c Sun Jul 4 09:53:12 1999 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.13 1999/05/12 11:11:34 davem Exp $ +/* $Id: asyncd.c,v 1.15 1999/07/04 04:35:50 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.3.9/linux/arch/sparc/mm/fault.c Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/mm/fault.c Mon Jul 5 20:35:18 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.101 1999/01/04 06:24:52 jj Exp $ +/* $Id: fault.c,v 1.103 1999/07/04 04:35:51 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.3.9/linux/arch/sparc/mm/srmmu.c Wed Apr 28 10:58:10 1999 +++ linux/arch/sparc/mm/srmmu.c Mon Jul 5 11:44:55 1999 @@ -2076,6 +2076,7 @@ goto done; inode = file->f_dentry->d_inode; offset = (address & PAGE_MASK) - vma->vm_start; + spin_lock(&inode->i_shared_lock); vmaring = inode->i_mmap; do { /* Do not mistake ourselves as another mapping. */ @@ -2109,6 +2110,7 @@ } } } while ((vmaring = vmaring->vm_next_share) != NULL); + spin_unlock(&inode->i_shared_lock); if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) { pgdp = srmmu_pgd_offset(vma->vm_mm, address); diff -u --recursive --new-file v2.3.9/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.9/linux/arch/sparc/mm/sun4c.c Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/mm/sun4c.c Mon Jul 5 11:44:55 1999 @@ -2682,8 +2682,10 @@ inode = dentry->d_inode; if(inode) { unsigned long offset = (address & PAGE_MASK) - vma->vm_start; - struct vm_area_struct *vmaring = inode->i_mmap; + struct vm_area_struct *vmaring; int alias_found = 0; + spin_lock(&inode->i_shared_lock); + vmaring = inode->i_mmap; do { unsigned long vaddr = vmaring->vm_start + offset; unsigned long start; @@ -2712,6 +2714,7 @@ } } } while ((vmaring = vmaring->vm_next_share) != NULL); + spin_unlock(&inode->i_shared_lock); if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = sun4c_pgd_offset(vma->vm_mm, address); diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.9/linux/arch/sparc64/config.in Wed Jun 30 13:38:19 1999 +++ linux/arch/sparc64/config.in Tue Jul 6 19:05:48 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.66 1999/03/29 05:08:42 davem Exp $ +# $Id: config.in,v 1.67 1999/05/01 09:17:37 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -68,20 +68,8 @@ fi if [ "$CONFIG_PCI" = "y" ]; then - tristate 'Parallel port support' CONFIG_PARPORT - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_AX" = "m" ]; then - define_bool CONFIG_PARPORT_LOWLEVEL_MODULE y - fi - if [ "$CONFIG_PARPORT_AX" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi - dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT - if [ "$CONFIG_PRINTER" != "n" ]; then - bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK - fi - fi + source drivers/misc/Config.in + dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT tristate 'SUNW,envctrl support' CONFIG_ENVCTRL fi endmenu @@ -232,6 +220,16 @@ 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 + +mainmenu_option next_comment +comment 'Video For Linux' +tristate 'Video For Linux' CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV + fi fi endmenu diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.9/linux/arch/sparc64/defconfig Wed Jun 30 13:38:19 1999 +++ linux/arch/sparc64/defconfig Tue Jul 6 19:05:48 1999 @@ -93,11 +93,13 @@ CONFIG_BINFMT_MISC=m CONFIG_SOLARIS_EMUL=m CONFIG_PARPORT=m -CONFIG_PARPORT_AX=m -CONFIG_PARPORT_LOWLEVEL_MODULE=y +# CONFIG_PARPORT_PC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set # CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set CONFIG_PRINTER=m -CONFIG_PRINTER_READBACK=y CONFIG_ENVCTRL=m # @@ -260,6 +262,12 @@ # CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 + +# +# Video For Linux +# +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_BT848=y # # Filesystems diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.3.9/linux/arch/sparc64/kernel/binfmt_aout32.c Wed Jun 30 13:38:19 1999 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Thu Jul 1 17:33:12 1999 @@ -311,9 +311,10 @@ fd = open_dentry(bprm->dentry, O_RDONLY); if (fd < 0) return fd; - file = fcheck(fd); + file = fget(fd); if (!file->f_op || !file->f_op->mmap) { + fput(fd); sys_close(fd); do_brk(0, ex.a_text+ex.a_data); read_exec(bprm->dentry, fd_offset, @@ -327,6 +328,7 @@ fd_offset); if (error != N_TXTADDR(ex)) { + fput(file); sys_close(fd); send_sig(SIGKILL, current, 0); return error; @@ -336,6 +338,7 @@ PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); + fput(file); sys_close(fd); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.9/linux/arch/sparc64/kernel/ioctl32.c Wed Jun 9 14:44:25 1999 +++ linux/arch/sparc64/kernel/ioctl32.c Tue Jul 6 10:11:40 1999 @@ -1696,9 +1696,9 @@ int error = -EBADF; lock_kernel(); - filp = fcheck(fd); + filp = fget(fd); if(!filp) - goto out; + goto out2; if (!filp->f_op || !filp->f_op->ioctl) { error = sys_ioctl (fd, cmd, arg); @@ -2381,6 +2381,8 @@ break; } out: + fput(filp); +out2: unlock_kernel(); return error; } diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c --- v2.3.9/linux/arch/sparc64/kernel/psycho.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc64/kernel/psycho.c Mon Jul 5 20:35:18 1999 @@ -1,4 +1,4 @@ -/* $Id: psycho.c,v 1.85 1999/04/02 14:54:28 davem Exp $ +/* $Id: psycho.c,v 1.86 1999/07/01 10:39:43 davem Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -68,7 +68,6 @@ #include #include -#include #include #include #include @@ -757,13 +756,15 @@ unsigned short stmp; unsigned int itmp; +#if 0 for(pdev = pci_devices; pdev; pdev = pdev->next) { if(pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SABRE) { - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); break; } } +#endif for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { @@ -795,13 +796,14 @@ pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp); itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp); - +#if 0 /* Don't mess with the retry limit and PIO/DMA latency * timer settings. But do set primary and secondary * latency timers. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); - pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 128); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); +#endif } } } diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.3.9/linux/arch/sparc64/kernel/ptrace.c Thu Jun 17 01:08:50 1999 +++ linux/arch/sparc64/kernel/ptrace.c Mon Jul 5 11:30:11 1999 @@ -28,242 +28,6 @@ #define MAGIC_CONSTANT 0x80000000 -/* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - */ -static pte_t *ptrace_get_page(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr, int write) -{ - pgd_t * pgdir; - pmd_t * pgmiddle; - pte_t * pgtable; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - - /* Seems non-intuitive but the page copy/clear routines always - * check current's value. - */ - current->mm->segments = (void *) (addr & PAGE_SIZE); - - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, write); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace: bad page directory %016lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return 0; - } - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, write); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace: bad page middle %016lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return 0; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, write); - goto repeat; - } - if (write && !pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, write); - goto repeat; - } - return pgtable; -} - -/* We must bypass the L1-cache to avoid alias issues. -DaveM */ -static __inline__ unsigned long read_user_long(unsigned long kvaddr) -{ - unsigned long ret; - - __asm__ __volatile__("ldxa [%1] %2, %0" - : "=r" (ret) - : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); - return ret; -} - -static __inline__ unsigned int read_user_int(unsigned long kvaddr) -{ - unsigned int ret; - - __asm__ __volatile__("lduwa [%1] %2, %0" - : "=r" (ret) - : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); - return ret; -} - -static __inline__ void write_user_long(unsigned long kvaddr, unsigned long val) -{ - __asm__ __volatile__("stxa %0, [%1] %2" - : /* no outputs */ - : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); -} - -static __inline__ void write_user_int(unsigned long kvaddr, unsigned int val) -{ - __asm__ __volatile__("stwa %0, [%1] %2" - : /* no outputs */ - : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); -} - -static inline unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) -{ - pte_t * pgtable; - unsigned long page, retval; - - if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0; - page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) >= max_mapnr) - return 0; - page += addr & ~PAGE_MASK; - retval = read_user_long(page); - flush_page_to_ram(page); - return retval; -} - -static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long addr, unsigned long data) -{ - pte_t *pgtable; - unsigned long page; - - if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return; - page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ - flush_cache_page(vma, addr); - if (MAP_NR(page) < max_mapnr) { - unsigned long pgaddr; - - pgaddr = page + (addr & ~PAGE_MASK); - write_user_long(pgaddr, data); - - __asm__ __volatile__(" - membar #StoreStore - flush %0 -" : : "r" (pgaddr & ~7) : "memory"); - } -/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ -/* this should also re-instate whatever read-only mode there was before */ - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_page(vma, addr); -} - -static inline unsigned int get_int(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) -{ - pte_t * pgtable; - unsigned long page; - unsigned int retval; - - if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0; - page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) >= max_mapnr) - return 0; - page += addr & ~PAGE_MASK; - retval = read_user_int(page); - flush_page_to_ram(page); - return retval; -} - -static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long addr, unsigned int data) -{ - pte_t *pgtable; - unsigned long page; - - if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return; - page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ - flush_cache_page(vma, addr); - if (MAP_NR(page) < max_mapnr) { - unsigned long pgaddr; - - pgaddr = page + (addr & ~PAGE_MASK); - write_user_int(pgaddr, data); - - __asm__ __volatile__(" - membar #StoreStore - flush %0 -" : : "r" (pgaddr & ~7) : "memory"); - } -/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ -/* this should also re-instate whatever read-only mode there was before */ - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_page(vma, addr); -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ -static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - *result = get_long(tsk, vma, addr); - return 0; -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_int() to read a int. - */ -static int read_int(struct task_struct * tsk, unsigned long addr, - unsigned int * result) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - *result = get_int(tsk, vma, addr); - return 0; -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ -static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - put_long(tsk, vma, addr, data); - return 0; -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_int() to write a int. - */ -static int write_int(struct task_struct * tsk, unsigned long addr, - unsigned int data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk, addr); - - if (!vma) - return -EIO; - put_int(tsk, vma, addr, data); - return 0; -} - /* Returning from ptrace is a bit tricky because the syscall return * low level code assumes any value returned which is negative and * is a valid errno will mean setting the condition codes to indicate @@ -310,175 +74,6 @@ pt_succ_return_linux (regs, val, addr); } -#if 0 -/* XXX: Implement this some day */ -/* Fuck me gently with a chainsaw... */ -static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, - struct task_struct *tsk, long *addr) -{ - struct pt_regs *cregs = tsk->tss.kregs; - struct thread_struct *t = &tsk->tss; - int v; - - if(offset >= 1024) - offset -= 1024; /* whee... */ - if(offset & ((sizeof(unsigned int) - 1))) { - pt_error_return(regs, EIO); - return; - } - if(offset >= 16 && offset < 784) { - offset -= 16; offset >>= 2; - if (t->w_saved) - pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); - return; - } - if(offset >= 784 && offset < 832) { - offset -= 784; offset >>= 2; - if (t->w_saved) - pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); - return; - } - switch(offset) { - case 0: - v = t->ksp; - break; -#if 0 - case 4: - v = t->kpc; - break; -#endif - case 8: - v = t->kpsr; - break; - case 12: - v = t->uwinmask; - break; - case 832: - v = t->w_saved; - break; - case 896: - v = cregs->u_regs[UREG_I0]; - break; - case 900: - v = cregs->u_regs[UREG_I1]; - break; - case 904: - v = cregs->u_regs[UREG_I2]; - break; - case 908: - v = cregs->u_regs[UREG_I3]; - break; - case 912: - v = cregs->u_regs[UREG_I4]; - break; - case 916: - v = cregs->u_regs[UREG_I5]; - break; - case 920: - v = cregs->u_regs[UREG_I6]; - break; - case 924: - if(tsk->tss.flags & MAGIC_CONSTANT) - v = cregs->u_regs[UREG_G1]; - else - v = 0; - break; - case 940: - v = cregs->u_regs[UREG_I0]; - break; - case 944: - v = cregs->u_regs[UREG_I1]; - break; - - case 948: - /* Isn't binary compatibility _fun_??? */ - if(cregs->psr & PSR_C) - v = cregs->u_regs[UREG_I0] << 24; - else - v = 0; - break; - - /* Rest of them are completely unsupported. */ - default: - printk("%s [%d]: Wants to read user offset %ld\n", - current->comm, current->pid, offset); - pt_error_return(regs, EIO); - return; - } - pt_os_succ_return_linux (regs, v, addr); - return; -} - -static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, - struct task_struct *tsk) -{ - struct pt_regs *cregs = tsk->tss.kregs; - struct thread_struct *t = &tsk->tss; - unsigned int value = regs->u_regs[UREG_I3]; - - if(offset >= 1024) - offset -= 1024; /* whee... */ - if(offset & ((sizeof(unsigned long) - 1))) - goto failure; - if(offset >= 16 && offset < 784) { - offset -= 16; offset >>= 2; - if (t->w_saved) - *(((unsigned long *)(&t->reg_window[0]))+offset) = value; - goto success; - } - if(offset >= 784 && offset < 832) { - offset -= 784; offset >>= 2; - if (t->w_saved) - *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; - goto success; - } - switch(offset) { - case 896: - cregs->u_regs[UREG_I0] = value; - break; - case 900: - cregs->u_regs[UREG_I1] = value; - break; - case 904: - cregs->u_regs[UREG_I2] = value; - break; - case 908: - cregs->u_regs[UREG_I3] = value; - break; - case 912: - cregs->u_regs[UREG_I4] = value; - break; - case 916: - cregs->u_regs[UREG_I5] = value; - break; - case 920: - cregs->u_regs[UREG_I6] = value; - break; - case 924: - cregs->u_regs[UREG_I7] = value; - break; - case 940: - cregs->u_regs[UREG_I0] = value; - break; - case 944: - cregs->u_regs[UREG_I1] = value; - break; - - /* Rest of them are completely unsupported or "no-touch". */ - default: - printk("%s [%d]: Wants to write user offset %ld\n", - current->comm, current->pid, offset); - goto failure; - } -success: - pt_succ_return(regs, 0); - return; -failure: - pt_error_return(regs, EIO); - return; -} -#endif - /* #define ALLOW_INIT_TRACING */ /* #define DEBUG_PTRACE */ @@ -642,76 +237,54 @@ switch(request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { - unsigned long tmp; - int res; + unsigned long tmp64; + unsigned int tmp32; + int res, copied; - /* Non-word alignment _not_ allowed on Sparc. */ + res = -EIO; if (current->tss.flags & SPARC_FLAG_32BIT) { - unsigned int x; - if(addr & (sizeof(unsigned int) - 1)) { - pt_error_return(regs, EINVAL); - goto out; - } - down(&child->mm->mmap_sem); - res = read_int(child, addr, &x); - up(&child->mm->mmap_sem); - tmp = x; + copied = access_process_vm(child, addr, + &tmp32, sizeof(tmp32), 0); + tmp64 = (unsigned long) tmp32; + if (copied == sizeof(tmp32)) + res = 0; } else { - if(addr & (sizeof(unsigned long) - 1)) { - pt_error_return(regs, EINVAL); - goto out; - } - down(&child->mm->mmap_sem); - res = read_long(child, addr, &tmp); - up(&child->mm->mmap_sem); + copied = access_process_vm(child, addr, + &tmp64, sizeof(tmp64), 0); + if (copied == sizeof(tmp64)) + res = 0; } - if (res < 0) { + if (res < 0) pt_error_return(regs, -res); - goto out; - } - pt_os_succ_return(regs, tmp, (long *) data); - goto out; + else + pt_os_succ_return(regs, tmp64, (long *) data); + goto flush_and_out; } - case PTRACE_PEEKUSR: -#if 0 - read_sunos_user(regs, addr, child, (long *) data); -#endif - goto out; - - case PTRACE_POKEUSR: -#if 0 - write_sunos_user(regs, addr, child); -#endif - goto out; - case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: { - int res; + unsigned long tmp64; + unsigned int tmp32; + int copied, res = -EIO; - /* Non-word alignment _not_ allowed on Sparc. */ if (current->tss.flags & SPARC_FLAG_32BIT) { - if(addr & (sizeof(unsigned int) - 1)) { - pt_error_return(regs, EINVAL); - goto out; - } - down(&child->mm->mmap_sem); - res = write_int(child, addr, data); - up(&child->mm->mmap_sem); + tmp32 = data; + copied = access_process_vm(child, addr, + &tmp32, sizeof(tmp32), 1); + if (copied == sizeof(tmp32)) + res = 0; } else { - if(addr & (sizeof(unsigned long) - 1)) { - pt_error_return(regs, EINVAL); - goto out; - } - down(&child->mm->mmap_sem); - res = write_long(child, addr, data); - up(&child->mm->mmap_sem); + tmp64 = data; + copied = access_process_vm(child, addr, + &tmp64, sizeof(tmp64), 1); + if (copied == sizeof(tmp64)) + res = 0; } if(res < 0) pt_error_return(regs, -res); else pt_succ_return(regs, res); - goto out; + goto flush_and_out; } case PTRACE_GETREGS: { @@ -926,98 +499,31 @@ case PTRACE_READTEXT: case PTRACE_READDATA: { - unsigned char *dest = (unsigned char *) addr2; - unsigned long src = addr; - int len = data, curlen; - struct vm_area_struct *vma; - pte_t *pgtable; - unsigned long page; - - while(len) { - down(&child->mm->mmap_sem); - vma = find_extend_vma(child, src); - if (!vma) { - up(&child->mm->mmap_sem); - pt_error_return(regs, EIO); - goto flush_and_out; - } - pgtable = ptrace_get_page (child, vma, src, 0); - up(&child->mm->mmap_sem); - if (src & ~PAGE_MASK) { - curlen = PAGE_SIZE - (src & ~PAGE_MASK); - if (curlen > len) curlen = len; - } else if (len > PAGE_SIZE) - curlen = PAGE_SIZE; - else - curlen = len; - if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) { - if (copy_to_user (dest, ((char *)page) + (src & ~PAGE_MASK), curlen)) { - flush_page_to_ram(page); - pt_error_return(regs, EFAULT); - goto flush_and_out; - } - flush_page_to_ram(page); - } else { - if (clear_user (dest, curlen)) { - pt_error_return(regs, EFAULT); - goto flush_and_out; - } - } - src += curlen; - dest += curlen; - len -= curlen; + int res = ptrace_readdata(child, addr, + (void *)addr2, data); + if (res == data) { + pt_succ_return(regs, 0); + goto flush_and_out; } - pt_succ_return(regs, 0); + if (res >= 0) + res = -EIO; + pt_error_return(regs, -res); goto flush_and_out; } case PTRACE_WRITETEXT: case PTRACE_WRITEDATA: { - unsigned char *src = (unsigned char *) addr2; - unsigned long dest = addr; - int len = data, curlen; - struct vm_area_struct *vma; - pte_t *pgtable; - unsigned long page; - - while(len) { - down(&child->mm->mmap_sem); - vma = find_extend_vma(child, dest); - if (!vma) { - up(&child->mm->mmap_sem); - pt_error_return(regs, EIO); - goto flush_and_out; - } - pgtable = ptrace_get_page (child, vma, dest, 1); - up(&child->mm->mmap_sem); - if (dest & ~PAGE_MASK) { - curlen = PAGE_SIZE - (dest & ~PAGE_MASK); - if (curlen > len) curlen = len; - } else if (len > PAGE_SIZE) - curlen = PAGE_SIZE; - else - curlen = len; - if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) { - flush_cache_page(vma, dest); - if (copy_from_user (((char *)page) + (dest & ~PAGE_MASK), src, curlen)) { - flush_page_to_ram(page); - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_page(vma, dest); - pt_error_return(regs, EFAULT); - goto flush_and_out; - } - flush_page_to_ram(page); - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_page(vma, dest); - } - src += curlen; - dest += curlen; - len -= curlen; + int res = ptrace_writedata(child, (void *) addr2, + addr, data); + if (res == data) { + pt_succ_return(regs, 0); + goto flush_and_out; } - pt_succ_return(regs, 0); + if (res >= 0) + res = -EIO; + pt_error_return(regs, -res); goto flush_and_out; } - case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ addr = 1; @@ -1105,6 +611,14 @@ unsigned long va; for(va = 0; va < (PAGE_SIZE << 1); va += 32) spitfire_put_dcache_tag(va, 0x0); + if (request == PTRACE_PEEKTEXT || + request == PTRACE_POKETEXT || + request == PTRACE_READTEXT || + request == PTRACE_WRITETEXT) { + for(va = 0; va < (PAGE_SIZE << 1); va += 32) + spitfire_put_icache_tag(va, 0x0); + __asm__ __volatile__("flush %g6"); + } } out: unlock_kernel(); diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.3.9/linux/arch/sparc64/kernel/smp.c Thu May 27 09:55:21 1999 +++ linux/arch/sparc64/kernel/smp.c Thu Jul 1 15:09:01 1999 @@ -615,7 +615,7 @@ unsigned int *inc, *inc2; update_one_process(current, 1, user, !user, cpu); - if(--current->counter < 0) { + if(--current->counter <= 0) { current->counter = 0; current->need_resched = 1; } diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.3.9/linux/arch/sparc64/kernel/sparc64_ksyms.c Wed Jun 30 13:38:19 1999 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Jul 5 20:35:18 1999 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.59 1999/06/28 11:28:50 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.60 1999/07/03 22:11:12 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -45,7 +45,6 @@ #include #endif #include -#include struct poll { int fd; @@ -118,6 +117,12 @@ /* used by various drivers */ #ifdef __SMP__ +/* Out of line rw-locking implementation. */ +EXPORT_SYMBOL_PRIVATE(read_lock); +EXPORT_SYMBOL_PRIVATE(read_unlock); +EXPORT_SYMBOL_PRIVATE(write_lock); +EXPORT_SYMBOL_PRIVATE(write_unlock); + /* Kernel wide locking */ EXPORT_SYMBOL(kernel_flag); @@ -157,6 +162,10 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); #endif + +/* Atomic counter implementation. */ +EXPORT_SYMBOL_PRIVATE(atomic_add); +EXPORT_SYMBOL_PRIVATE(atomic_sub); EXPORT_SYMBOL(ivector_table); EXPORT_SYMBOL(enable_irq); diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.3.9/linux/arch/sparc64/kernel/sys_sparc32.c Wed Jun 30 13:38:19 1999 +++ linux/arch/sparc64/kernel/sys_sparc32.c Tue Jul 6 10:11:40 1999 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -32,18 +31,15 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include -#include #include #include @@ -2328,8 +2324,8 @@ break; } /* Bump the usage count and install the file. */ - atomic_inc(&fp[i]->f_count); - current->files->fd[new_fd] = fp[i]; + get_file(fp[i]); + fd_install(new_fd, fp[i]); } if (i > 0) { diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.3.9/linux/arch/sparc64/kernel/sys_sunos32.c Wed Jun 30 13:38:19 1999 +++ linux/arch/sparc64/kernel/sys_sunos32.c Tue Jul 6 10:11:40 1999 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -712,7 +711,7 @@ struct inode *inode; struct file *file; - file = current->files->fd [fd]; + file = fcheck(fd); if(!file) return 0; diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile --- v2.3.9/linux/arch/sparc64/lib/Makefile Tue Oct 27 09:52:20 1998 +++ linux/arch/sparc64/lib/Makefile Sun Jul 4 09:53:12 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $ +# $Id: Makefile,v 1.19 1999/07/03 22:11:08 davem Exp $ # Makefile for Sparc library files.. # @@ -6,7 +6,8 @@ OBJS = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ - VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o + VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o \ + atomic.o rwlock.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/lib/atomic.S linux/arch/sparc64/lib/atomic.S --- v2.3.9/linux/arch/sparc64/lib/atomic.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/lib/atomic.S Sun Jul 4 09:53:12 1999 @@ -0,0 +1,32 @@ +/* $Id: atomic.S,v 1.1 1999/07/03 22:11:04 davem Exp $ + * atomic.S: These things are too big to do inline. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include + + .text + .align 64 + + .globl __atomic_add +__atomic_add: + lduw [%g1], %g5 + add %g5, %g2, %g7 + cas [%g1], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __atomic_add + nop + jmpl %g3 + 8, %g0 + add %g7, %g2, %g2 + + .globl __atomic_sub +__atomic_sub: + lduw [%g1], %g5 + sub %g5, %g2, %g7 + cas [%g1], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __atomic_sub + nop + jmpl %g3 + 8, %g0 + sub %g7, %g2, %g2 diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/lib/rwlock.S linux/arch/sparc64/lib/rwlock.S --- v2.3.9/linux/arch/sparc64/lib/rwlock.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/lib/rwlock.S Sun Jul 4 09:53:12 1999 @@ -0,0 +1,81 @@ +/* $Id: rwlock.S,v 1.1 1999/07/03 22:11:06 davem Exp $ + * rwlocks.S: These things are too big to do inline. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + + .text + .align 64 + + /* The non-contention read lock usage is 2 cache lines. */ + + .globl __read_lock, __read_unlock + /* g1=lock, g3=retpc, g5/g7=scratch */ +__read_lock: + ldsw [%g1], %g5 + brlz,pn %g5, __read_wait_for_writer +4: add %g5, 1, %g7 + cas [%g1], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __read_lock + membar #StoreLoad | #StoreStore +99: jmpl %g3 + 8, %g0 + nop +__read_unlock: + lduw [%g1], %g5 + sub %g5, 1, %g7 + cas [%g1], %g5, %g7 + cmp %g5, %g7 + be,pt %xcc, 99b + membar #StoreLoad | #StoreStore + b,a,pt %xcc, __read_unlock + +__read_wait_for_writer: + ldsw [%g1], %g5 + brlz,pt %g5, __read_wait_for_writer + membar #LoadLoad + b,a,pt %xcc, 4b +__write_wait_for_writer: + ldsw [%g1], %g5 + brlz,pt %g5, __write_wait_for_writer + membar #LoadLoad + b,a,pt %xcc, 4f + + /* Similarly, 2 cache lines for non-contention write locks. */ + + .align 64 + .globl __write_unlock + /* g1=lock, g3=retpc, g2/g5/g7=scratch */ +__write_unlock: + sethi %hi(0x80000000), %g2 +1: lduw [%g1], %g5 + andn %g5, %g2, %g7 + cas [%g1], %g5, %g7 + cmp %g5, %g7 + be,pt %icc, 99b + membar #StoreLoad | #StoreStore + b,a,pt %xcc, 1b + + .globl __write_lock +__write_lock: + sethi %hi(0x80000000), %g2 +1: ldsw [%g1], %g5 +4: brnz,pn %g5, 5f + or %g5, %g2, %g7 + cas [%g1], %g5, %g7 + cmp %g5, %g7 + be,pt %icc, 99b + membar #StoreLoad | #StoreStore + + b,a,pt %xcc, 1b +5: brlz %g5, __write_wait_for_writer + or %g5, %g2, %g7 + cas [%g1], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, 5b +8: ldsw [%g1], %g5 + cmp %g5, %g2 + be,pn %icc, 99b + membar #LoadLoad + b,a,pt %xcc, 99b + diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c --- v2.3.9/linux/arch/sparc64/mm/asyncd.c Wed May 12 08:41:12 1999 +++ linux/arch/sparc64/mm/asyncd.c Sun Jul 4 09:53:12 1999 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.6 1999/05/12 11:11:48 davem Exp $ +/* $Id: asyncd.c,v 1.8 1999/07/04 04:35:55 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.3.9/linux/arch/sparc64/mm/fault.c Tue Mar 16 21:52:06 1999 +++ linux/arch/sparc64/mm/fault.c Sun Jul 4 09:53:12 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.34 1999/03/16 12:12:28 jj Exp $ +/* $Id: fault.c,v 1.36 1999/07/04 04:35:56 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/solaris/ioctl.c linux/arch/sparc64/solaris/ioctl.c --- v2.3.9/linux/arch/sparc64/solaris/ioctl.c Wed May 26 18:14:37 1999 +++ linux/arch/sparc64/solaris/ioctl.c Tue Jul 6 10:11:40 1999 @@ -367,15 +367,8 @@ static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg, int len, int *len_p) { - struct file *filp; struct inode *ino; int ret; - - filp = current->files->fd[fd]; - if (! filp || - ! (ino = filp->f_dentry->d_inode) || - ! ino->i_sock) - return TBADF; switch (cmd & 0xff) { case 141: /* TI_OPTMGMT */ @@ -459,7 +452,7 @@ return TNOTSUPPORT; } -static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg) +static inline int solaris_S(struct file *filp, unsigned int fd, unsigned int cmd, u32 arg) { char *p; int ret; @@ -470,9 +463,7 @@ struct sol_socket_struct *sock; struct module_info *mi; - filp = current->files->fd[fd]; - if (! filp || - ! (ino = filp->f_dentry->d_inode) || + if (! (ino = filp->f_dentry->d_inode) || ! ino->i_sock) return -EBADF; sock = filp->private_data; @@ -696,14 +687,14 @@ struct file *filp; int error = -EBADF; - lock_kernel(); - filp = fcheck(fd); + filp = fget(fd); if (!filp) goto out; + lock_kernel(); error = -EFAULT; switch ((cmd >> 8) & 0xff) { - case 'S': error = solaris_S(fd, cmd, arg); break; + case 'S': error = solaris_S(filp, fd, cmd, arg); break; case 'T': error = solaris_T(fd, cmd, arg); break; case 'i': error = solaris_i(fd, cmd, arg); break; case 'r': error = solaris_r(fd, cmd, arg); break; @@ -714,6 +705,8 @@ error = -ENOSYS; break; } + unlock_kernel(); + fput(filp); out: if (error == -ENOSYS) { unsigned char c = cmd>>8; @@ -723,6 +716,5 @@ (int)fd, (unsigned int)cmd, c, (unsigned int)arg); error = -EINVAL; } - unlock_kernel(); return error; } diff -u --recursive --new-file v2.3.9/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c --- v2.3.9/linux/arch/sparc64/solaris/socksys.c Sun Oct 4 10:22:43 1998 +++ linux/arch/sparc64/solaris/socksys.c Mon Jul 5 20:35:18 1999 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c --- v2.3.9/linux/drivers/acorn/char/keyb_arc.c Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/char/keyb_arc.c Mon Jul 5 20:35:18 1999 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/ap1000/bif.c linux/drivers/ap1000/bif.c --- v2.3.9/linux/drivers/ap1000/bif.c Fri May 8 00:47:24 1998 +++ linux/drivers/ap1000/bif.c Mon Jul 5 20:35:18 1999 @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/ap1000/ringbuf.c linux/drivers/ap1000/ringbuf.c --- v2.3.9/linux/drivers/ap1000/ringbuf.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/ap1000/ringbuf.c Sun Jul 4 10:02:30 1999 @@ -318,6 +318,7 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* get_block */ NULL, /* readpage */ NULL, /* writepage */ diff -u --recursive --new-file v2.3.9/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.9/linux/drivers/block/Config.in Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/Config.in Mon Jul 5 19:52:13 1999 @@ -41,30 +41,49 @@ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS + bool ' Generic ATA-66 support (DANGEROUS)' CONFIG_IDEDMA_ULTRA_66 + define_bool IDEDMA_PCI_EXPERIMENTAL y + else + define_bool IDEDMA_PCI_EXPERIMENTAL n + fi fi bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 + bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 + bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 + fi + bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then + bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA + fi + bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PIIX" = "y" ]; then + bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + fi + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 - bool ' Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX - if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then - bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 - bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 - bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 - bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 - bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 - bool ' PDC20246 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20246 - bool ' PDC20262 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20262 - if [ "$CONFIG_BLK_DEV_PDC20246" = "y" -o \ - "$CONFIG_BLK_DEV_PDC20262" = "y" ]; then - define_bool CONFIG_BLK_DEV_PDC202XX y - else - define_bool CONFIG_BLK_DEV_PDC202XX n - fi - bool ' HPT343 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT343 + fi + if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then + bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX + if [ "$CONFIG_EXPERIMENTAL" = "y" -a \ + "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then + bool ' Special UDMA Feature (EXPERIMENTAL)' PDC202XX_FORCE_BURST_BIT + bool ' Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE fi fi + if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 + bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + fi fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 @@ -106,13 +125,12 @@ bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B + if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \ + "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 + fi bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then - bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 - fi - fi fi if [ "$CONFIG_AMIGA" = "y" ]; then bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE @@ -145,6 +163,7 @@ dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI fi fi +tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA comment 'Additional Block Devices' @@ -182,13 +201,13 @@ source drivers/block/paride/Config.in fi - -if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ - "$CONFIG_IDE_CHIPSETS" = "y" -o \ - "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ - "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ +if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ + "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \ + "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ - "$CONFIG_BLK_DEV_HPT343" = "y" -o \ + "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ + "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ + "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y diff -u --recursive --new-file v2.3.9/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.9/linux/drivers/block/Makefile Wed May 26 09:30:31 1999 +++ linux/drivers/block/Makefile Mon Jul 5 19:52:13 1999 @@ -202,8 +202,8 @@ IDE_OBJS += aec6210.o endif -ifeq ($(CONFIG_BLK_DEV_HPT343),y) -IDE_OBJS += hpt343.o +ifeq ($(CONFIG_BLK_DEV_HPT34X),y) +IDE_OBJS += hpt34x.o endif ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored @@ -271,6 +271,14 @@ else ifeq ($(CONFIG_BLK_DEV_XD),m) M_OBJS += xd.o + endif +endif + +ifeq ($(CONFIG_BLK_CPQ_DA),y) +L_OBJS += cpqarray.o +else + ifeq ($(CONFIG_BLK_CPQ_DA),m) + M_OBJS += cpqarray.o endif endif diff -u --recursive --new-file v2.3.9/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c --- v2.3.9/linux/drivers/block/alim15x3.c Wed May 26 16:55:40 1999 +++ linux/drivers/block/alim15x3.c Thu Jul 1 10:25:38 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/alim15x3.c Version 0.04 Feb. 8, 1999 + * linux/drivers/block/alim15x3.c Version 0.05 Jun. 29, 1999 * * Copyright (C) 1998-99 Michel Aubry, Maintainer * Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer @@ -20,6 +20,8 @@ #include +#include "ide_modes.h" + #define DISPLAY_ALI_TIMINGS #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) @@ -59,6 +61,55 @@ }; #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ +static void ali15x3_tune_drive (ide_drive_t *drive, byte pio) +{ + ide_pio_data_t d; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int s_time, a_time, c_time; + byte s_clc, a_clc, r_clc; + unsigned long flags; + int bus_speed = ide_system_bus_speed(); + int port = hwif->index ? 0x5c : 0x58; + + pio = ide_get_best_pio_mode(drive, pio, 5, &d); + s_time = ide_pio_timings[pio].setup_time; + a_time = ide_pio_timings[pio].active_time; + if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) + s_clc = 0; + if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8) + a_clc = 0; + c_time = ide_pio_timings[pio].cycle_time; + +#if 0 + if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16) + r_clc = 0; +#endif + + if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) { + r_clc = 1; + } else { + if (r_clc >= 16) + r_clc = 0; + } + save_flags(flags); + cli(); + pci_write_config_byte(dev, port, s_clc); + pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); + restore_flags(flags); + + /* + * setup active rec + * { 70, 165, 365 }, PIO Mode 0 + * { 50, 125, 208 }, PIO Mode 1 + * { 30, 100, 110 }, PIO Mode 2 + * { 30, 80, 70 }, PIO Mode 3 with IORDY + * { 25, 70, 25 }, PIO Mode 4 with IORDY ns + * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) + */ + +} + __initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name)) { byte confreg0 = 0, confreg1 =0, progif = 0; @@ -146,19 +197,22 @@ __initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif)) { struct pci_dev *dev; - byte ideic, inmir; + byte ideic, inmir, iderev; byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; + + pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &iderev); + hwif->irq = hwif->channel ? 15 : 14; for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */ if (dev->vendor==PCI_VENDOR_ID_AL && - dev->device==PCI_DEVICE_ID_AL_M1533) + dev->device==PCI_DEVICE_ID_AL_M1533) break; if (dev) { pci_read_config_byte(dev, 0x58, &ideic); ideic = ideic & 0x03; if ((hwif->channel && ideic == 0x03) || - (!hwif->channel && !ideic)) { + (!hwif->channel && !ideic)) { pci_read_config_byte(dev, 0x44, &inmir); inmir = inmir & 0x0f; hwif->irq = irq_routing_table[inmir]; @@ -174,8 +228,15 @@ ali_display_info = &ali_get_info; #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - if (hwif->dma_base) + hwif->tuneproc = &ali15x3_tune_drive; + if ((hwif->dma_base) && (iderev >= 0xC1)) { + /* M1543C or newer for DMAing */ hwif->dmaproc = &ali15x3_dmaproc; + } else { + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } return; } diff -u --recursive --new-file v2.3.9/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.3.9/linux/drivers/block/amiflop.c Tue May 11 23:33:42 1999 +++ linux/drivers/block/amiflop.c Tue Jul 6 19:05:48 1999 @@ -1755,13 +1755,13 @@ NULL, /* revalidate */ }; -__initfunc(void amiga_floppy_setup (char *str, int *ints)) +void __init amiga_floppy_setup (char *str, int *ints) { printk (KERN_INFO "amiflop: Setting default df0 to %x\n", ints[1]); fd_def_df0 = ints[1]; } -__initfunc(static int fd_probe_drives(void)) +static int __init fd_probe_drives(void) { int drive,drives,nomem; @@ -1791,7 +1791,7 @@ return -ENOMEM; } -__initfunc(int amiga_floppy_init(void)) +int __init amiga_floppy_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c --- v2.3.9/linux/drivers/block/ataflop.c Sat May 15 23:43:04 1999 +++ linux/drivers/block/ataflop.c Tue Jul 6 19:05:48 1999 @@ -1771,7 +1771,7 @@ /* Initialize the 'unit' variable for drive 'drive' */ -__initfunc(static void fd_probe( int drive )) +static void __init fd_probe( int drive ) { UD.connected = 0; UDT = NULL; @@ -1814,7 +1814,7 @@ * declared absent. */ -__initfunc(static int fd_test_drive_present( int drive )) +static int __init fd_test_drive_present( int drive ) { unsigned long timeout; unsigned char status; @@ -1861,7 +1861,7 @@ * floppies, additionally start the disk-change and motor-off timers. */ -__initfunc(static void config_types( void )) +static void __init config_types( void ) { int drive, cnt = 0; @@ -2006,7 +2006,7 @@ floppy_revalidate, /* revalidate */ }; -__initfunc(int atari_floppy_init (void)) +int __init atari_floppy_init (void) { int i; @@ -2075,7 +2075,7 @@ } -__initfunc(void atari_floppy_setup( char *str, int *ints )) +void __init atari_floppy_setup( char *str, int *ints ) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/block/cmd646.c linux/drivers/block/cmd646.c --- v2.3.9/linux/drivers/block/cmd646.c Thu May 27 09:55:21 1999 +++ linux/drivers/block/cmd646.c Tue Jul 6 19:05:48 1999 @@ -1,4 +1,4 @@ -/* $Id: cmd646.c,v 1.13 1999/05/27 04:49:38 davem Exp $ +/* $Id: cmd646.c,v 1.14 1999/07/03 08:56:09 davem Exp $ * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because * there the "BIOS" has done all of the following already. @@ -94,6 +94,9 @@ static void cmd646_do_setfeature(ide_drive_t *drive, byte command) { +#if 0 + (void) ide_config_drive_speed(drive, command); +#else unsigned long flags; byte old_select; @@ -116,6 +119,7 @@ out: OUT_BYTE(old_select, IDE_SELECT_REG); restore_flags(flags); +#endif } static void cmd646_dma2_enable(ide_drive_t *drive, unsigned long dma_base) @@ -236,7 +240,7 @@ return cmd646_dmaproc(func, drive); } -__initfunc(void ide_init_cmd646 (ide_hwif_t *hwif)) +void __init ide_init_cmd646 (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; unsigned char mrdmode; diff -u --recursive --new-file v2.3.9/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.3.9/linux/drivers/block/cpqarray.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cpqarray.c Tue Jul 6 10:11:40 1999 @@ -0,0 +1,1730 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) + +#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.4)" +#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,4) +#define MAJOR_NR COMPAQ_SMART2_MAJOR +#include +#include +#include + +#include "cpqarray.h" +#include "ida_cmd.h" +#include "smart1,2.h" +#include "ida_ioctl.h" + +#define READ_AHEAD 128 +#define NR_CMDS 128 /* This could probably go as high as ~400 */ + +#define MAX_CTLR 8 +#define CTLR_SHIFT 8 + +static int nr_ctlr = 0; +static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static int eisa[8] = { 0, 0 ,0 ,0, 0, 0 ,0 ,0 }; + +#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) + +/* board_id = Subsystem Device ID & Vendor ID + * product = Marketing Name for the board + * access = Address of the struct of function pointers + */ +struct board_type products[] = { + { 0x0040110E, "IDA", &smart1_access }, + { 0x0140110E, "IDA-2", &smart1_access }, + { 0x1040110E, "IAES", &smart1_access }, + { 0x2040110E, "SMART", &smart1_access }, + { 0x3040110E, "SMART-2/E", &smart2e_access }, + { 0x40300E11, "SMART-2/P", &smart2_access }, + { 0x40310E11, "SMART-2SL", &smart2_access }, + { 0x40320E11, "Smart Array 3200", &smart2_access }, + { 0x40330E11, "Smart Array 3100ES", &smart2_access }, + { 0x40340E11, "Smart Array 221", &smart2_access }, + { 0x40400E11, "Integrated Array", &smart4_access }, + { 0x40500E11, "Smart Array 4200", &smart4_access }, + { 0x40510E11, "Smart Array 4250ES", &smart4_access }, +}; + +static struct hd_struct * ida; +static int * ida_sizes; +static int * ida_blocksizes; +static int * ida_hardsizes; +static struct gendisk ida_gendisk[MAX_CTLR]; + +struct proc_dir_entry *proc_array = NULL; + +/* Debug... */ +#define DBG(s) do { s } while(0) +/* Debug (general info)... */ +#define DBGINFO(s) do { } while(0) +/* Debug Paranoid... */ +#define DBGP(s) do { } while(0) +/* Debug Extra Paranoid... */ +#define DBGPX(s) do { } while(0) + +void cpqarray_init(void); +static int cpqarray_pci_detect(void); +static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn); +static ulong remap_pci_mem(ulong base, ulong size); +static int cpqarray_eisa_detect(void); +static int pollcomplete(int ctlr); +static void getgeometry(int ctlr); +static void start_fwbk(int ctlr); + +static cmdlist_t * cmd_alloc(ctlr_info_t *h); +static void cmd_free(ctlr_info_t *h, cmdlist_t *c); + +static int sendcmd( + __u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int blk, + unsigned int blkcnt, + unsigned int log_unit ); + +static int ida_open(struct inode *inode, struct file *filep); +static int ida_release(struct inode *inode, struct file *filep); +static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); +static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io); + +static void do_ida_request(int i); +/* + * This is a hack. This driver eats a major number for each controller, and + * sets blkdev[xxx].request_fn to each one of these so the real request + * function knows what controller its working with. + */ +#define DO_IDA_REQUEST(x) { do_ida_request(x); } + +static void do_ida_request0(void) DO_IDA_REQUEST(0); +static void do_ida_request1(void) DO_IDA_REQUEST(1); +static void do_ida_request2(void) DO_IDA_REQUEST(2); +static void do_ida_request3(void) DO_IDA_REQUEST(3); +static void do_ida_request4(void) DO_IDA_REQUEST(4); +static void do_ida_request5(void) DO_IDA_REQUEST(5); +static void do_ida_request6(void) DO_IDA_REQUEST(6); +static void do_ida_request7(void) DO_IDA_REQUEST(7); + +static void start_io(ctlr_info_t *h); + +static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c); +static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c); +static inline void complete_buffers(struct buffer_head *bh, int ok); +static inline void complete_command(cmdlist_t *cmd, int timeout); + +static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs); +static void ida_timer(unsigned long tdata); +static int frevalidate_logvol(kdev_t dev); +static int revalidate_logvol(kdev_t dev, int maxusage); +static int revalidate_allvol(kdev_t dev); + +static void ida_procinit(int i); +static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data); + +static void ida_geninit(struct gendisk *g) +{ + int ctlr = g-ida_gendisk; + int i,j; + drv_info_t *drv; + + for(i=0; idrv[i]; + if (!drv->nr_blks) + continue; + ida[(ctlr<nr_blks; + + for(j=0; j<16; j++) { + ida_blocksizes[(ctlr<blk_size; + } + ida_gendisk[ctlr].nr_real++; + } + +} + +struct file_operations ida_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + ida_ioctl, /* ioctl */ + NULL, /* mmap */ + ida_open, /* open code */ + NULL, + ida_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + NULL, /* Disk change */ + frevalidate_logvol, /* revalidate */ +}; + + +/* + * Get us a file in /proc/array that says something about each controller. + * Create /proc/array if it doesn't exist yet. + */ +static void ida_procinit(int i) +{ + struct proc_dir_entry *pd; + + if (proc_array == NULL) { + proc_array = create_proc_entry("array", S_IFDIR|S_IRUGO|S_IXUGO, + &proc_root); + if (!proc_array) return; + } + + pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_array); + if (!pd) return; + pd->read_proc = ida_proc_get_info; + pd->data = hba[i]; +} + +/* + * Report information about this controller. + */ +static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + off_t pos = 0; + off_t len = 0; + int size, i, ctlr; + ctlr_info_t *h = (ctlr_info_t*)data; + drv_info_t *drv; +#ifdef CPQ_PROC_PRINT_QUEUES + cmdlist_t *c; +#endif + + ctlr = h->ctlr; + size = sprintf(buffer, "%s: Compaq %s Controller\n" + " Board ID: %08lx\n" + " Firmware Revision: %c%c%c%c\n" + " Controller Sig: %08lx\n" + " Memory Address: %08lx\n" + " I/O Port: %04x\n" + " IRQ: %x\n" + " Logical drives: %d\n" + " Physical drives: %d\n\n" + " Current Q depth: %d\n" + " Max Q depth since init: %d\n\n", + h->devname, + h->product_name, + (unsigned long)h->board_id, + h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3], + (unsigned long)h->ctlr_sig, (unsigned long)h->vaddr, + (unsigned int) h->ioaddr, (unsigned int)h->intr, + h->log_drives, h->phys_drives, + h->Qdepth, h->maxQsinceinit); + + pos += size; len += size; + + size = sprintf(buffer+len, "Logical Drive Info:\n"); + pos += size; len += size; + + for(i=0; ilog_drives; i++) { + drv = &h->drv[i]; + size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n", + ctlr, i, drv->blk_size, drv->nr_blks); + pos += size; len += size; + } + +#ifdef CPQ_PROC_PRINT_QUEUES + size = sprintf(buffer+len, "\nCurrent Queues:\n"); + pos += size; len += size; + + c = h->reqQ; + size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size; + if (c) c=c->next; + while(c && c != h->reqQ) { + size = sprintf(buffer+len, "->%p", c); + pos += size; len += size; + c=c->next; + } + + c = h->cmpQ; + size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size; + if (c) c=c->next; + while(c && c != h->cmpQ) { + size = sprintf(buffer+len, "->%p", c); + pos += size; len += size; + c=c->next; + } + + size = sprintf(buffer+len, "\n"); pos += size; len += size; +#endif + size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n", + h->nr_allocs, h->nr_frees); + pos += size; len += size; + + *eof = 1; + *start = buffer+offset; + len -= offset; + if (len>length) + len = length; + return len; +} + +#ifdef MODULE + +MODULE_PARM(eisa, "1-8i"); +EXPORT_NO_SYMBOLS; + +/* This is a bit of a hack... */ +int init_module(void) +{ + int i, j; + cpqarray_init(); + if (nr_ctlr == 0) + return -EIO; + + for(i=0; iaccess.set_intr_mask(hba[i], 0); + free_irq(hba[i]->intr, hba[i]); + iounmap((void*)hba[i]->vaddr); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + del_timer(&hba[i]->timer); + remove_proc_entry(hba[i]->devname, proc_array); + kfree(hba[i]->cmd_pool); + kfree(hba[i]->cmd_pool_bits); + + if (gendisk_head == &ida_gendisk[i]) { + gendisk_head = ida_gendisk[i].next; + } else { + for(g=gendisk_head; g; g=g->next) { + if (g->next == &ida_gendisk[i]) { + g->next = ida_gendisk[i].next; + break; + } + } + } + } + remove_proc_entry("array", &proc_root); + kfree(ida); + kfree(ida_sizes); + kfree(ida_hardsizes); + kfree(ida_blocksizes); + + +} +#endif /* MODULE */ + +/* + * This is it. Find all the controllers and register them. I really hate + * stealing all these major device numbers. + */ +void cpqarray_init(void) +{ + void (*request_fns[MAX_CTLR])(void) = { + do_ida_request0, do_ida_request1, + do_ida_request2, do_ida_request3, + do_ida_request4, do_ida_request5, + do_ida_request6, do_ida_request7, + }; + int i; + + /* detect controllers */ + cpqarray_pci_detect(); + cpqarray_eisa_detect(); + + if (nr_ctlr == 0) + return; + + printk(DRIVER_NAME "\n"); + printk("Found %d controller(s)\n", nr_ctlr); + + /* allocate space for disk structs */ + ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL); + + if(ida==NULL) + goto bail; + ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + if(ida_sizes==NULL) + goto bail2; + ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + if(ida_blocksizes==NULL) + goto bail3; + ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + if(ida_hardsizes==NULL) + goto bail4; + + memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16); + memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16); + memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16); + memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16); + memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR); + + /* + * register block devices + * Find disks and fill in structs + * Get an interrupt, set the Q depth and get into /proc + */ + for(i=0; i< nr_ctlr; i++) { + hba[i]->access.set_intr_mask(hba[i], 0); + if (request_irq(hba[i]->intr, do_ida_intr, + SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) { + + printk("Unable to get irq %d for %s\n", + hba[i]->intr, hba[i]->devname); + continue; + } + if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) { + printk("Unable to get major number %d for ida\n", + MAJOR_NR+i); + continue; + } + + hba[i]->cmd_pool = (cmdlist_t *)kmalloc( + NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL); + hba[i]->cmd_pool_bits = (__u32*)kmalloc( + ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); + + if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) + { + int j; + if(hba[i]->cmd_pool_bits) + kfree(hba[i]->cmd_pool_bits); + if(hba[i]->cmd_pool) + kfree(hba[i]->cmd_pool); + for(j=0;iintr, hba[j]); + unregister_blkdev(MAJOR_NR+j, hba[j]->devname); + kfree(hba[j]->cmd_pool_bits); + kfree(hba[j]->cmd_pool); + } + free_irq(hba[i]->intr, hba[i]); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + goto bail5; + } + memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t)); + memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32)); + printk("Finding drives on %s", hba[i]->devname); + getgeometry(i); + start_fwbk(i); + + hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY); + + ida_procinit(i); + ida_gendisk[i].major = MAJOR_NR + i; + ida_gendisk[i].major_name = "ida"; + ida_gendisk[i].minor_shift = NWD_SHIFT; + ida_gendisk[i].max_p = 16; + ida_gendisk[i].max_nr = 16; + ida_gendisk[i].init = ida_geninit; + ida_gendisk[i].part = ida + (i*256); + ida_gendisk[i].sizes = ida_sizes + (i*256); + /* ida_gendisk[i].nr_real is handled by getgeometry */ + + blk_dev[MAJOR_NR+i].request_fn = request_fns[i]; + blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); + hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); + read_ahead[MAJOR_NR+i] = READ_AHEAD; + + /* Get on the disk list */ + ida_gendisk[i].next = gendisk_head; + gendisk_head = &ida_gendisk[i]; + + init_timer(&hba[i]->timer); + hba[i]->timer.expires = jiffies + IDA_TIMER; + hba[i]->timer.data = (unsigned long)hba[i]; + hba[i]->timer.function = ida_timer; + add_timer(&hba[i]->timer); + + } + /* done ! */ + return; +bail5: + kfree(ida_hardsizes); +bail4: + kfree(ida_blocksizes); +bail3: + kfree(ida_sizes); +bail2: + kfree(ida); +bail: + printk(KERN_ERR "cpqarray: out of memory.\n"); +} + +/* + * Find the controller and initialize it + * Cannot use the class code to search, because older array controllers use + * 0x018000 and new ones use 0x010400. So I might as well search for each + * each device IDs, being there are only going to be three of them. + */ +static int cpqarray_pci_detect(void) +{ + int index; + unchar bus=0, dev_fn=0; + + /* This seems dumb, surely we could use an array of types to match ?? */ + + for(index=0; ; index++) { + if (pcibios_find_device(PCI_VENDOR_ID_DEC, + PCI_DEVICE_ID_COMPAQ_42XX, index, &bus, &dev_fn)) + break; + printk(KERN_DEBUG "42XX Device has been found at %x %x\n", + bus, dev_fn); + if (index == 1000000) break; + if (nr_ctlr == 8) { + printk("This driver supports a maximum of " + "8 controllers.\n"); + break; + } + + hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); + if(hba[nr_ctlr]==NULL) + { + printk(KERN_ERR "cpqarray: out of memory.\n"); + continue; + } + memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); + if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) + continue; + sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); + hba[nr_ctlr]->ctlr = nr_ctlr; + nr_ctlr++; + } + + for(index=0; ; index++) { + unsigned short subvendor=0; + + if (pcibios_find_device(PCI_VENDOR_ID_NCR, + PCI_DEVICE_ID_NCR_53C1510, index, &bus, &dev_fn)) + break; + printk(KERN_DEBUG "Integrated RAID Chip has been found at %x %x\n", + bus, dev_fn); + if(pcibios_read_config_word(bus, dev_fn, + PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) + { + printk(KERN_DEBUG "cpqarray failed to read subvendor\n"); + break; + } + if(subvendor != PCI_VENDOR_ID_COMPAQ) + break; + printk(KERN_DEBUG "Its a compaq RAID Chip\n"); + if (index == 1000000) break; + if (nr_ctlr == 8) { + printk("This driver supports a maximum of " + "8 controllers.\n"); + break; + } + + hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); + if(hba[nr_ctlr]==NULL) + { + printk(KERN_ERR "cpqarray: out of memory.\n"); + continue; + } + memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); + /* DOESNT THIS LEAK MEMORY ?????? - AC */ + if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) + continue; + sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); + hba[nr_ctlr]->ctlr = nr_ctlr; + nr_ctlr++; + } + + for(index=0; ; index++) { + if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn)) + break; + + if (index == 1000000) break; + if (nr_ctlr == 8) { + printk("This driver supports a maximum of " + "8 controllers.\n"); + break; + } + + hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); + if(hba[nr_ctlr]==NULL) + { + printk(KERN_ERR "cpqarray: out of memory.\n"); + continue; + } + memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); + if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) + continue; + sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); + hba[nr_ctlr]->ctlr = nr_ctlr; + nr_ctlr++; + } + + return nr_ctlr; +} +/* + * Find the IO address of the controller, its IRQ and so forth. Fill + * in some basic stuff into the ctlr_info_t structure. + */ +static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) +{ + ushort vendor_id, device_id, command; + unchar cache_line_size, latency_timer; + unchar irq, revision; + uint addr[6]; + __u32 board_id; + struct pci_dev *pdev; + + int i; + + pdev = pci_find_slot(bus, device_fn); + vendor_id = pdev->vendor; + device_id = pdev->device; + irq = pdev->irq; + + for(i=0; i<6; i++) + addr[i] = pdev->base_address[i]; + + (void) pcibios_read_config_word(bus, device_fn, + PCI_COMMAND,&command); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_CLASS_REVISION,&revision); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_CACHE_LINE_SIZE, &cache_line_size); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_LATENCY_TIMER, &latency_timer); + + (void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id); + +DBGINFO( + printk("vendor_id = %x\n", vendor_id); + printk("device_id = %x\n", device_id); + printk("command = %x\n", command); + for(i=0; i<6; i++) + printk("addr[%d] = %x\n", i, addr[i]); + printk("revision = %x\n", revision); + printk("irq = %x\n", irq); + printk("cache_line_size = %x\n", cache_line_size); + printk("latency_timer = %x\n", latency_timer); + printk("board_id = %x\n", board_id); +); + + c->intr = irq; + c->ioaddr = addr[0] & ~0x1; + + /* + * Memory base addr is first addr with the first bit _not_ set + */ + for(i=0; i<6; i++) + if (!(addr[i] & 0x1)) { + c->paddr = addr[i]; + break; + } + c->vaddr = remap_pci_mem(c->paddr, 128); + c->board_id = board_id; + + for(i=0; iproduct_name = products[i].product_name; + c->access = *(products[i].access); + break; + } + } + if (i == NR_PRODUCTS) { + printk("Sorry, I don't know how to access the SMART Array" + " controller %08lx\n", (unsigned long)board_id); + return -1; + } + + return 0; +} + +/* + * Map (physical) PCI mem into (virtual) kernel space + */ +static ulong remap_pci_mem(ulong base, ulong size) +{ + ulong page_base = ((ulong) base) & PAGE_MASK; + ulong page_offs = ((ulong) base) - page_base; + ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + + return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); +} + +/* + * Copy the contents of the ints[] array passed to us by init. + */ +void cpqarray_setup(char *str, int *ints) +{ + int i; + for(i=0; iioaddr = eisa[i]; + + /* + * Read the config register to find our interrupt + */ + intr = inb(eisa[i]+0xCC0) >> 4; + if (intr & 1) intr = 11; + else if (intr & 2) intr = 10; + else if (intr & 4) intr = 14; + else if (intr & 8) intr = 15; + + hba[nr_ctlr]->intr = intr; + sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); + hba[nr_ctlr]->product_name = products[j].product_name; + hba[nr_ctlr]->access = *(products[j].access); + hba[nr_ctlr]->ctlr = nr_ctlr; + hba[nr_ctlr]->board_id = board_id; + +DBGINFO( + printk("i = %d, j = %d\n", i, j); + printk("irq = %x\n", intr); + printk("product name = %s\n", products[j].product_name); + printk("board_id = %x\n", board_id); +); + + nr_ctlr++; + i++; + } + + return nr_ctlr; +} + + +/* + * Open. Make sure the device is really there. + */ +static int ida_open(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + + DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); + if (ctlr > MAX_CTLR || hba[ctlr] == NULL) + return -ENXIO; + + if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) + + MINOR(inode->i_rdev)] == 0) + return -ENXIO; + + /* + * Root is allowed to open raw volume zero even if its not configured + * so array config can still work. I don't think I really like this, + * but I'm already using way to many device nodes to claim another one + * for "raw controller". + */ + if (suser() + && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 + && MINOR(inode->i_rdev) != 0) + return -ENXIO; + + hba[ctlr]->drv[dsk].usage_count++; + hba[ctlr]->usage_count++; + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Close. Sync first. + */ +static int ida_release(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + + DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); + fsync_dev(inode->i_rdev); + + hba[ctlr]->drv[dsk].usage_count--; + hba[ctlr]->usage_count--; + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Enqueuing and dequeuing functions for cmdlists. + */ +static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c) +{ + if (*Qptr == NULL) { + *Qptr = c; + c->next = c->prev = c; + } else { + c->prev = (*Qptr)->prev; + c->next = (*Qptr); + (*Qptr)->prev->next = c; + (*Qptr)->prev = c; + } +} + +static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c) +{ + if (c && c->next != c) { + if (*Qptr == c) *Qptr = c->next; + c->prev->next = c->next; + c->next->prev = c->prev; + } else { + *Qptr = NULL; + } + return c; +} + +/* + * Get a request and submit it to the controller. + * This routine needs to grab all the requests it possibly can from the + * req Q and submit them. Interrupts are off (and need to be off) when you + * are in here (either via the dummy do_ida_request functions or by being + * called from the interrupt handler + */ +static void do_ida_request(int ctlr) +{ + ctlr_info_t *h = hba[ctlr]; + cmdlist_t *c; + int seg, sect; + char *lastdataend; + struct buffer_head *bh; + struct request *creq; + + creq = blk_dev[MAJOR_NR+ctlr].current_request; + if (creq == NULL || creq->rq_status == RQ_INACTIVE) + goto doreq_done; + + if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || + ctlr > nr_ctlr || h == NULL) { + printk("doreq cmd for %d, %x at %p\n", + ctlr, creq->rq_dev, creq); + complete_buffers(creq->bh, 0); + goto doreq_done; + } + + if ((c = cmd_alloc(h)) == NULL) + goto doreq_done; + + bh = creq->bh; + + c->ctlr = ctlr; + c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT; + c->hdr.size = sizeof(rblk_t) >> 2; + c->size += sizeof(rblk_t); + + c->req.hdr.blk = ida[(ctlr<rq_dev)].start_sect + creq->sector; + c->bh = bh; +DBGPX( + if (bh == NULL) + panic("bh == NULL?"); + + printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors); +); + seg = 0; lastdataend = NULL; + sect = 0; + while(bh) { + sect += bh->b_size/512; +DBGPX( + if (bh->b_size % 512) { + printk("Oh damn. %d+%d, size = %d\n", creq->sector, sect, bh->b_size); + panic("b_size %% 512 != 0"); + } +); + if (bh->b_data == lastdataend) { + c->req.sg[seg-1].size += bh->b_size; + lastdataend += bh->b_size; + } else { + c->req.sg[seg].size = bh->b_size; + c->req.sg[seg].addr = (__u32)virt_to_bus(bh->b_data); + lastdataend = bh->b_data + bh->b_size; + if (++seg == SG_MAX) + break; + } + bh = bh->b_reqnext; + } +DBGPX( printk("Submitting %d sectors in %d segments\n", sect, seg); ); + c->req.hdr.sg_cnt = seg; + c->req.hdr.blk_cnt = sect; + + creq->sector += sect; + creq->nr_sectors -= sect; + + /* Ready the next request: + * Fix up creq if we still have more buffers in the buffer chain, or + * mark this request as done and ready the next one. + */ + if (creq->nr_sectors) { +DBGPX( + if (bh==NULL) { + printk("sector=%d, nr_sectors=%d, sect=%d, seg=%d\n", + creq->sector, creq->nr_sectors, sect, seg); + panic("mother..."); + } +); + creq->bh = bh->b_reqnext; + bh->b_reqnext = NULL; +DBGPX( printk("More to do on same request %p\n", creq); ); + } else { +DBGPX( printk("Done with %p, queueing %p\n", creq, creq->next); ); + creq->rq_status = RQ_INACTIVE; + blk_dev[MAJOR_NR+ctlr].current_request = creq->next; + wake_up(&wait_for_request); + } + + c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE; + c->type = CMD_RWREQ; + + /* Put the request on the tail of the request queue */ + addQ(&h->reqQ, c); + h->Qdepth++; + if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; + +doreq_done: + start_io(h); +} + +/* + * start_io submits everything on a controller's request queue + * and moves it to the completion queue. + * + * Interrupts had better be off if you're in here + */ +static void start_io(ctlr_info_t *h) +{ + cmdlist_t *c; + + while((c = h->reqQ) != NULL) { + /* Can't do anything if we're busy */ + if (h->access.fifo_full(h) == 0) + return; + + /* Get the first entry from the request Q */ + removeQ(&h->reqQ, c); + h->Qdepth--; + + /* Tell the controller to do our bidding */ + h->access.submit_command(h, c); + + /* Get onto the completion Q */ + addQ(&h->cmpQ, c); + } +} + +static inline void complete_buffers(struct buffer_head *bh, int ok) +{ + struct buffer_head *xbh; + while(bh) { + xbh = bh->b_reqnext; + bh->b_reqnext = NULL; + + bh->b_end_io(bh, ok); + + bh = xbh; + } +} +/* + * Mark all buffers that cmd was responsible for + */ +static inline void complete_command(cmdlist_t *cmd, int timeout) +{ + char buf[80]; + int ok=1; + + if (cmd->req.hdr.rcode & RCODE_NONFATAL && + (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) { + sprintf(buf, "Non Fatal error on ida/c%dd%d\n", + cmd->ctlr, cmd->hdr.unit); + console_print(buf); + hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN; + } + if (cmd->req.hdr.rcode & RCODE_FATAL) { + sprintf(buf, "Fatal error on ida/c%dd%d\n", + cmd->ctlr, cmd->hdr.unit); + console_print(buf); + ok = 0; + } + if (cmd->req.hdr.rcode & RCODE_INVREQ) { + sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n", + cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd, + cmd->req.hdr.blk, cmd->req.hdr.blk_cnt, + cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode); + console_print(buf); + ok = 0; + } + if (timeout) ok = 0; + complete_buffers(cmd->bh, ok); +} + +/* + * The controller will interrupt us upon completion of commands. + * Find the command on the completion queue, remove it, tell the OS and + * try to queue up more IO + */ +static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + ctlr_info_t *h = dev_id; + cmdlist_t *c; + unsigned long istat; + unsigned long flags; + __u32 a,a1; + + + istat = h->access.intr_pending(h); + /* Is this interrupt for us? */ + if (istat == 0) + return; + + /* + * If there are completed commands in the completion queue, + * we had better do something about it. + */ + spin_lock_irqsave(&io_request_lock, flags); + if (istat & FIFO_NOT_EMPTY) { + while((a = h->access.command_completed(h))) { + a1 = a; a &= ~3; + if ((c = h->cmpQ) == NULL) goto bad_completion; + while(c->busaddr != a) { + c = c->next; + if (c == h->cmpQ) break; + } + /* + * If we've found the command, take it off the + * completion Q and free it + */ + if (c->busaddr == a) { + removeQ(&h->cmpQ, c); + if (c->type == CMD_RWREQ) { + complete_command(c, 0); + cmd_free(h, c); + } else if (c->type == CMD_IOCTL_PEND) { + c->type = CMD_IOCTL_DONE; + } + continue; + } +bad_completion: + printk("Completion of %08lx ignored\n", (unsigned long)a1); + } + } + + /* + * See if we can queue up some more IO + */ + do_ida_request(h->ctlr); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +/* + * This timer was for timing out requests that haven't happened after + * IDA_TIMEOUT. That wasn't such a good idea. This timer is used to + * reset a flags structure so we don't flood the user with + * "Non-Fatal error" messages. + */ +static void ida_timer(unsigned long tdata) +{ + ctlr_info_t *h = (ctlr_info_t*)tdata; + + h->timer.expires = jiffies + IDA_TIMER; + add_timer(&h->timer); + h->misc_tflags = 0; +} + +/* + * ida_ioctl does some miscellaneous stuff like reporting drive geometry, + * setting readahead and submitting commands from userspace to the controller. + */ +static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int error; + int diskinfo[4]; + struct hd_geometry *geo = (struct hd_geometry *)arg; + ida_ioctl_t *io = (ida_ioctl_t*)arg; + ida_ioctl_t my_io; + + switch(cmd) { + case HDIO_GETGEO: + if (hba[ctlr]->drv[dsk].cylinders) { + diskinfo[0] = hba[ctlr]->drv[dsk].heads; + diskinfo[1] = hba[ctlr]->drv[dsk].sectors; + diskinfo[2] = hba[ctlr]->drv[dsk].cylinders; + } else { + diskinfo[0] = 0xff; + diskinfo[1] = 0x3f; + diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f); + } + put_user(diskinfo[0], &geo->heads); + put_user(diskinfo[1], &geo->sectors); + put_user(diskinfo[2], &geo->cylinders); + put_user(ida[(ctlr<i_rdev)].start_sect, &geo->start); + return 0; + case IDAGETDRVINFO: + return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t)); + case BLKGETSIZE: + if (!arg) return -EINVAL; + put_user(ida[(ctlr<i_rdev)].nr_sects, (long*)arg); + return 0; + case BLKRRPART: + return revalidate_logvol(inode->i_rdev, 1); + case IDAPASSTHRU: + if (!suser()) return -EPERM; + error = copy_from_user(&my_io, io, sizeof(my_io)); + if (error) return error; + error = ida_ctlr_ioctl(ctlr, dsk, &my_io); + if (error) return error; + error = copy_to_user(io, &my_io, sizeof(my_io)); + return error; + case IDAGETCTLRSIG: + if (!arg) return -EINVAL; + put_user(hba[ctlr]->ctlr_sig, (int*)arg); + return 0; + case IDAREVALIDATEVOLS: + return revalidate_allvol(inode->i_rdev); + case IDADRIVERVERSION: + if (!arg) return -EINVAL; + put_user(DRIVER_VERSION, (unsigned long*)arg); + return 0; + + case BLKFLSBUF: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + + default: + return -EBADRQC; + } + +} +/* + * ida_ctlr_ioctl is for passing commands to the controller from userspace. + * The command block (io) has already been copied to kernel space for us, + * however, any elements in the sglist need to be copied to kernel space + * or copied back to userspace. + * + * Only root may perform a controller passthru command, however I'm not doing + * any serious sanity checking on the arguments. Doing an IDA_WRITE_MEDIA and + * putting a 64M buffer in the sglist is probably a *bad* idea. + */ +static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io) +{ + ctlr_info_t *h = hba[ctlr]; + cmdlist_t *c; + void *p = NULL; + unsigned long flags; + int error; + + if ((c = cmd_alloc(NULL)) == NULL) + return -ENOMEM; + c->ctlr = ctlr; + c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk; + c->hdr.size = sizeof(rblk_t) >> 2; + c->size += sizeof(rblk_t); + + c->req.hdr.cmd = io->cmd; + c->req.hdr.blk = io->blk; + c->req.hdr.blk_cnt = io->blk_cnt; + c->type = CMD_IOCTL_PEND; + + /* Pre submit processing */ + switch(io->cmd) { + case PASSTHRU_A: + p = kmalloc(io->sg[0].size, GFP_KERNEL); + if (!p) { error = -ENOMEM; goto ioctl_err_exit; } + copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); + c->req.bp = virt_to_bus(&(io->c)); + c->req.sg[0].size = io->sg[0].size; + c->req.sg[0].addr = virt_to_bus(p); + c->req.hdr.sg_cnt = 1; + break; + case IDA_READ: + p = kmalloc(io->sg[0].size, GFP_KERNEL); + if (!p) { error = -ENOMEM; goto ioctl_err_exit; } + c->req.sg[0].size = io->sg[0].size; + c->req.sg[0].addr = virt_to_bus(p); + c->req.hdr.sg_cnt = 1; + break; + case IDA_WRITE: + case IDA_WRITE_MEDIA: + case DIAG_PASS_THRU: + p = kmalloc(io->sg[0].size, GFP_KERNEL); + if (!p) { error = -ENOMEM; goto ioctl_err_exit; } + copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); + c->req.sg[0].size = io->sg[0].size; + c->req.sg[0].addr = virt_to_bus(p); + c->req.hdr.sg_cnt = 1; + break; + default: + c->req.sg[0].size = sizeof(io->c); + c->req.sg[0].addr = virt_to_bus(&io->c); + c->req.hdr.sg_cnt = 1; + } + + /* Put the request on the tail of the request queue */ + spin_lock_irqsave(&io_request_lock, flags); + addQ(&h->reqQ, c); + h->Qdepth++; + start_io(h); + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Wait for completion */ + while(c->type != CMD_IOCTL_DONE) + schedule(); + + /* Post submit processing */ + switch(io->cmd) { + case PASSTHRU_A: + case IDA_READ: + case DIAG_PASS_THRU: + copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size); + /* fall through and free p */ + case IDA_WRITE: + case IDA_WRITE_MEDIA: + kfree(p); + break; + default: + /* Nothing to do */ + } + + io->rcode = c->req.hdr.rcode; + error = 0; +ioctl_err_exit: + cmd_free(NULL, c); + return error; +} + +/* + * Commands are pre-allocated in a large block. Here we use a simple bitmap + * scheme to suballocte them to the driver. Operations that are not time + * critical (and can wait for kmalloc and possibly sleep) can pass in NULL + * as the first argument to get a new command. + */ +static cmdlist_t * cmd_alloc(ctlr_info_t *h) +{ + cmdlist_t * c; + int i; + + if (h == NULL) { + c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL); + if(c==NULL) + return NULL; + } else { + do { + i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS); + if (i == NR_CMDS) + return NULL; + } while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0); + c = h->cmd_pool + i; + h->nr_allocs++; + } + + memset(c, 0, sizeof(cmdlist_t)); + c->busaddr = virt_to_bus(c); + return c; +} + +static void cmd_free(ctlr_info_t *h, cmdlist_t *c) +{ + int i; + + if (h == NULL) { + kfree(c); + } else { + i = c - h->cmd_pool; + clear_bit(i%32, h->cmd_pool_bits+(i/32)); + h->nr_frees++; + } +} + +/*********************************************************************** + name: sendcmd + Send a command to an IDA using the memory mapped FIFO interface + and wait for it to complete. + This routine should only be called at init time. +***********************************************************************/ +static int sendcmd( + __u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int blk, + unsigned int blkcnt, + unsigned int log_unit ) +{ + cmdlist_t *c; + int complete; + unsigned long temp; + unsigned long i; + ctlr_info_t *info_p = hba[ctlr]; + + c = cmd_alloc(info_p); + c->ctlr = ctlr; + c->hdr.unit = log_unit; + c->hdr.prio = 0; + c->hdr.size = sizeof(rblk_t) >> 2; + c->size += sizeof(rblk_t); + + /* The request information. */ + c->req.hdr.next = 0; + c->req.hdr.rcode = 0; + c->req.bp = 0; + c->req.hdr.sg_cnt = 1; + c->req.hdr.reserved = 0; + + if (size == 0) + c->req.sg[0].size = 512; + else + c->req.sg[0].size = size; + + c->req.hdr.blk = blk; + c->req.hdr.blk_cnt = blkcnt; + c->req.hdr.cmd = (unsigned char) cmd; + c->req.sg[0].addr = (__u32) virt_to_bus(buff); + /* + * Disable interrupt + */ + info_p->access.set_intr_mask(info_p, 0); + /* Make sure there is room in the command FIFO */ + /* Actually it should be completely empty at this time. */ + for (i = 200000; i > 0; i--) { + temp = info_p->access.fifo_full(info_p); + if (temp != 0) { + break; + } + udelay(10); +DBG( + printk("ida%d: idaSendPciCmd FIFO full, waiting!\n", + ctlr); +); + } + /* + * Send the cmd + */ + info_p->access.submit_command(info_p, c); + complete = pollcomplete(ctlr); + if (complete != 1) { + if (complete != c->busaddr) { + printk( + "ida%d: idaSendPciCmd " + "Invalid command list address returned! (%08lx)\n", + ctlr, (unsigned long)complete); + cmd_free(info_p, c); + return (IO_ERROR); + } + } else { + printk( + "ida%d: idaSendPciCmd Timeout out, " + "No command list address returned!\n", + ctlr); + cmd_free(info_p, c); + return (IO_ERROR); + } + + if (c->req.hdr.rcode & 0x00FE) { + if (!(c->req.hdr.rcode & BIG_PROBLEM)) { + printk( + "ida%d: idaSendPciCmd, error: Controller failed " + "at init time " + "cmd: 0x%x, return code = 0x%x\n", + ctlr, c->req.hdr.cmd, c->req.hdr.rcode); + + cmd_free(info_p, c); + return (IO_ERROR); + } + } + cmd_free(info_p, c); + return (IO_OK); +} + +static int frevalidate_logvol(kdev_t dev) +{ + return revalidate_logvol(dev, 0); +} + +/* + * revalidate_allvol is for online array config utilities. After a + * utility reconfigures the drives in the array, it can use this function + * (through an ioctl) to make the driver zap any previous disk structs for + * that controller and get new ones. + * + * Right now I'm using the getgeometry() function to do this, but this + * function should probably be finer grained and allow you to revalidate one + * particualar logical volume (instead of all of them on a particular + * controller). + */ +static int revalidate_allvol(kdev_t dev) +{ + int ctlr, i; + unsigned long flags; + + ctlr = MAJOR(dev) - MAJOR_NR; + if (MINOR(dev) != 0) + return -ENXIO; + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->usage_count > 1) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk("Device busy for volume revalidation (usage=%d)\n", + hba[ctlr]->usage_count); + return -EBUSY; + } + spin_unlock_irqrestore(&io_request_lock, flags); + hba[ctlr]->usage_count++; + + /* + * Set the partition and block size structures for all volumes + * on this controller to zero. We will reread all of this data + */ + memset(ida+(ctlr*256), 0, sizeof(struct hd_struct)*NWD*16); + memset(ida_sizes+(ctlr*256), 0, sizeof(int)*NWD*16); + memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16); + memset(ida_hardsizes+(ctlr*256), 0, sizeof(int)*NWD*16); + memset(hba[ctlr]->drv, 0, sizeof(drv_info_t)*NWD); + ida_gendisk[ctlr].nr_real = 0; + + /* + * Tell the array controller not to give us any interupts while + * we check the new geometry. Then turn interrupts back on when + * we're done. + */ + hba[ctlr]->access.set_intr_mask(hba[ctlr], 0); + getgeometry(ctlr); + hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY); + + ida_geninit(&ida_gendisk[ctlr]); + for(i=0; iusage_count--; + return 0; +} + +/* Borrowed and adapted from sd.c */ +static int revalidate_logvol(kdev_t dev, int maxusage) +{ + int ctlr, target; + struct gendisk *gdev; + unsigned long flags; + int max_p; + int start; + int i; + + target = DEVICE_NR(dev); + ctlr = MAJOR(dev) - MAJOR_NR; + gdev = &ida_gendisk[ctlr]; + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->drv[target].usage_count > maxusage) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk("Device busy for revalidation (usage=%d)\n", + hba[ctlr]->drv[target].usage_count); + return -EBUSY; + } + + hba[ctlr]->drv[target].usage_count++; + spin_unlock_irqrestore(&io_request_lock, flags); + + max_p = gdev->max_p; + start = target << gdev->minor_shift; + + for(i=max_p; i>=0; i--) { + int minor = start+i; + kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); + struct super_block *sb = get_super(devi); + sync_dev(devi); + if (sb) invalidate_inodes(sb); + invalidate_buffers(devi); + gdev->part[minor].start_sect = 0; + gdev->part[minor].nr_sects = 0; + + /* reset the blocksize so we can read the partition table */ + blksize_size[MAJOR_NR+ctlr][minor] = 1024; + } + + gdev->part[start].nr_sects = hba[ctlr]->drv[target].nr_blks; + resetup_one_dev(gdev, target); + hba[ctlr]->drv[target].usage_count--; + return 0; +} + + +/******************************************************************** + name: pollcomplete + Wait polling for a command to complete. + The memory mapped FIFO is polled for the completion. + Used only at init time, interrupts disabled. + ********************************************************************/ +static int pollcomplete(int ctlr) +{ + int done; + int i; + + /* Wait (up to 2 seconds) for a command to complete */ + + for (i = 200000; i > 0; i--) { + done = hba[ctlr]->access.command_completed(hba[ctlr]); + if (done == 0) { + udelay(10); /* a short fixed delay */ + } else + return (done); + } + /* Invalid address to tell caller we ran out of time */ + return 1; +} +/***************************************************************** + start_fwbk + Starts controller firmwares background processing. + Currently only the Integrated Raid controller needs this done. + If the PCI mem address registers are written to after this, + data corruption may occur +*****************************************************************/ +static void start_fwbk(int ctlr) +{ + id_ctlr_t *id_ctlr_buf; + int ret_code; + + if( hba[ctlr]->board_id != 0x40400E11) + /* Not a Integrated Raid, so there is nothing for us to do */ + return; + printk(KERN_DEBUG "Starting firmware's background processing\n"); + /* Command does not return anything, but idasend command needs a + buffer */ + id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); + if(id_ctlr_buf==NULL) + { + printk(KERN_WARNING "Out of memory. Unable to start background processing.\n"); + return; + } + ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr, + id_ctlr_buf, 0, 0, 0, 0); + if(ret_code != IO_OK) + printk(KERN_WARNING "Unable to start background processing\n"); + kfree(id_ctlr_buf); +} +/***************************************************************** + getgeometry + Get ida logical volume geometry from the controller + This is a large bit of code which once existed in two flavors, + It is used only at init time. +*****************************************************************/ +static void getgeometry(int ctlr) +{ + id_log_drv_t *id_ldrive; + id_ctlr_t *id_ctlr_buf; + sense_log_drv_stat_t *id_lstatus_buf; + config_t *sense_config_buf; + unsigned int log_unit, log_index; + int ret_code, size; + drv_info_t *drv; + ctlr_info_t *info_p = hba[ctlr]; + + info_p->log_drv_map = 0; + + id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL); + if(id_ldrive == NULL) + return; + id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); + if(id_ctlr_buf == NULL) + goto bail2; + id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL); + if(id_lstatus_buf == NULL) + goto bail3; + sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL); + if(sense_config_buf == NULL) + goto bail4; + memset(id_ldrive, 0, sizeof(id_log_drv_t)); + memset(id_ctlr_buf, 0, sizeof(id_ctlr_t)); + memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t)); + memset(sense_config_buf, 0, sizeof(config_t)); + + info_p->phys_drives = 0; + info_p->log_drv_map = 0; + info_p->drv_assign_map = 0; + info_p->drv_spare_map = 0; + info_p->mp_failed_drv_map = 0; /* only initialized here */ + /* Get controllers info for this logical drive */ + ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0); + if (ret_code == IO_ERROR) { + /* + * If can't get controller info, set the logical drive map to 0, + * so the idastubopen will fail on all logical drives + * on the controller. + */ + goto geo_ret; /* release the buf and return */ + } + info_p->log_drives = id_ctlr_buf->nr_drvs;; + *(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev); + info_p->ctlr_sig = id_ctlr_buf->cfg_sig; + + printk(" (%s)\n", info_p->product_name); + /* + * Initialize logical drive map to zero + */ + log_index = 0; + /* + * Get drive geometry for all logical drives + */ + if (id_ctlr_buf->nr_drvs > 16) + printk("ida%d: This driver supports 16 logical drives " + "per controller.\n. Additional drives will not be " + "detected\n", ctlr); + + for (log_unit = 0; + (log_index < id_ctlr_buf->nr_drvs) + && (log_unit < NWD); + log_unit++) { + + size = sizeof(sense_log_drv_stat_t); + + /* + Send "Identify logical drive status" cmd + */ + ret_code = sendcmd(SENSE_LOG_DRV_STAT, + ctlr, id_lstatus_buf, size, 0, 0, log_unit); + if (ret_code == IO_ERROR) { + /* + If can't get logical drive status, set + the logical drive map to 0, so the + idastubopen will fail for all logical drives + on the controller. + */ + info_p->log_drv_map = 0; + printk( + "ida%d: idaGetGeometry - Controller failed " + "to report status of logical drive %d\n" + "Access to this controller has been disabled\n", + ctlr, log_unit); + goto geo_ret; /* release the buf and return */ + + } + /* + Make sure the logical drive is configured + */ + if (id_lstatus_buf->status != LOG_NOT_CONF) { + ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive, + sizeof(id_log_drv_t), 0, 0, log_unit); + /* + If error, the bit for this + logical drive won't be set and + idastubopen will return error. + */ + if (ret_code != IO_ERROR) { + drv = &info_p->drv[log_unit]; + drv->blk_size = id_ldrive->blk_size; + drv->nr_blks = id_ldrive->nr_blks; + drv->cylinders = id_ldrive->drv.cyl; + drv->heads = id_ldrive->drv.heads; + drv->sectors = id_ldrive->drv.sect_per_track; + info_p->log_drv_map |= (1 << log_unit); + + printk("ida/c%dd%d: blksz=%d nr_blks=%d\n", + ctlr, log_unit, drv->blk_size, drv->nr_blks); + ret_code = sendcmd(SENSE_CONFIG, + ctlr, sense_config_buf, + sizeof(config_t), 0, 0, log_unit); + if (ret_code == IO_ERROR) { + info_p->log_drv_map = 0; + goto geo_ret; /* release the buf and return */ + } + info_p->phys_drives = + sense_config_buf->ctlr_phys_drv; + info_p->drv_assign_map + |= sense_config_buf->drv_asgn_map; + info_p->drv_assign_map + |= sense_config_buf->spare_asgn_map; + info_p->drv_spare_map + |= sense_config_buf->spare_asgn_map; + } /* end of if no error on id_ldrive */ + log_index = log_index + 1; + } /* end of if logical drive configured */ + } /* end of for log_unit */ +geo_ret: + kfree(sense_config_buf); +bail4: + kfree(id_ldrive); +bail3: + kfree(id_lstatus_buf); +bail2: + kfree(id_ctlr_buf); +} diff -u --recursive --new-file v2.3.9/linux/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h --- v2.3.9/linux/drivers/block/cpqarray.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cpqarray.h Tue Jul 6 10:11:40 1999 @@ -0,0 +1,120 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#ifndef CPQARRAY_H +#define CPQARRAY_H + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#endif + +#include "ida_cmd.h" + +#define IO_OK 0 +#define IO_ERROR 1 +#define NWD 16 +#define NWD_SHIFT 4 + +#define IDA_TIMER (5*HZ) +#define IDA_TIMEOUT (10*HZ) + +#define MISC_NONFATAL_WARN 0x01 + +typedef struct { + unsigned blk_size; + unsigned nr_blks; + unsigned cylinders; + unsigned heads; + unsigned sectors; + int usage_count; +} drv_info_t; + +#ifdef __KERNEL__ + +struct ctlr_info; +typedef struct ctlr_info ctlr_info_t; + +struct access_method { + void (*submit_command)(ctlr_info_t *h, cmdlist_t *c); + void (*set_intr_mask)(ctlr_info_t *h, unsigned long val); + unsigned long (*fifo_full)(ctlr_info_t *h); + unsigned long (*intr_pending)(ctlr_info_t *h); + unsigned long (*command_completed)(ctlr_info_t *h); +}; + +struct board_type { + __u32 board_id; + char *product_name; + struct access_method *access; +}; + +struct ctlr_info { + int ctlr; + char devname[8]; + __u32 log_drv_map; + __u32 drv_assign_map; + __u32 drv_spare_map; + __u32 mp_failed_drv_map; + + char firm_rev[4]; + int ctlr_sig; + + int log_drives; + int phys_drives; + + __u32 board_id; + char *product_name; + + __u32 vaddr; + __u32 paddr; + __u32 ioaddr; + int intr; + int usage_count; + drv_info_t drv[NWD]; + struct proc_dir_entry *proc; + + struct access_method access; + + cmdlist_t *reqQ; + cmdlist_t *cmpQ; + cmdlist_t *cmd_pool; + __u32 *cmd_pool_bits; + + unsigned int Qdepth; + unsigned int maxQsinceinit; + + unsigned int nr_requests; + unsigned int nr_allocs; + unsigned int nr_frees; + struct timer_list timer; + unsigned int misc_tflags; +}; +#endif + +#endif /* CPQARRAY_H */ diff -u --recursive --new-file v2.3.9/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.3.9/linux/drivers/block/floppy.c Wed Jun 9 16:42:58 1999 +++ linux/drivers/block/floppy.c Tue Jul 6 19:05:48 1999 @@ -3896,7 +3896,7 @@ /* Determine the floppy disk controller type */ /* This routine was written by David C. Niemi */ -__initfunc(static char get_fdc_version(void)) +static char __init get_fdc_version(void) { int r; @@ -3974,7 +3974,7 @@ /* lilo configuration */ -__initfunc(static void floppy_set_flags(int *ints,int param, int param2)) +static void __init floppy_set_flags(int *ints,int param, int param2) { int i; @@ -3987,7 +3987,7 @@ DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param); } -__initfunc(static void daring(int *ints,int param, int param2)) +static void __init daring(int *ints,int param, int param2) { int i; @@ -4003,7 +4003,7 @@ DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken"); } -__initfunc(static void set_cmos(int *ints, int dummy, int dummy2)) +static void __init set_cmos(int *ints, int dummy, int dummy2) { int current_drive=0; @@ -4063,7 +4063,7 @@ { "L40SX", 0, &print_unex, 0, 0 } }; #define FLOPPY_SETUP -__initfunc(void floppy_setup(char *str, int *ints)) +void __init floppy_setup(char *str, int *ints) { int i; int param; @@ -4101,7 +4101,7 @@ static int have_no_fdc= -EIO; -__initfunc(int floppy_init(void)) +int __init floppy_init(void) { int i,unit,drive; @@ -4362,7 +4362,7 @@ char *floppy=NULL; -__initfunc(static void parse_floppy_cfg_string(char *cfg)) +static void __init parse_floppy_cfg_string(char *cfg) { char *ptr; int ints[11]; @@ -4378,7 +4378,7 @@ } } -__initfunc(static void mod_setup(char *pattern, void (*setup)(char *, int *))) +static void __init mod_setup(char *pattern, void (*setup)(char *, int *)) { unsigned long i; char c; diff -u --recursive --new-file v2.3.9/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.3.9/linux/drivers/block/genhd.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/genhd.c Mon Jul 5 20:35:18 1999 @@ -30,6 +30,7 @@ #include #include +#include /* * Many architectures don't like unaligned accesses, which is @@ -60,6 +61,7 @@ extern int blk_dev_init(void); extern int scsi_dev_init(void); extern int net_dev_init(void); +extern int i2o_init(void); #ifdef CONFIG_PPC extern void note_bootable_part(kdev_t dev, int part); @@ -112,6 +114,16 @@ return buf; } } + if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) { + int ctlr = hd->major - COMPAQ_SMART2_MAJOR; + int disk = minor >> hd->minor_shift; + int part = minor & (( 1 << hd->minor_shift) - 1); + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, disk); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part); + return buf; + } if (part) sprintf(buf, "%s%c%d", maj, unit, part); else @@ -121,10 +133,13 @@ static void add_partition (struct gendisk *hd, int minor, int start, int size) { - char buf[32]; + char buf[40]; hd->part[minor].start_sect = start; hd->part[minor].nr_sects = size; - printk(" %s", disk_name(hd, minor, buf)); + if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) + printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); + else + printk(" %s", disk_name(hd, minor, buf)); } static inline int is_extended_partition(struct partition *p) @@ -222,7 +237,7 @@ if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) return; - if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC)) + if ((*(__u16 *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC)) goto done; p = (struct partition *) (0x1BE + bh->b_data); @@ -676,12 +691,10 @@ label = (struct disklabel *) (bh->b_data+64); partition = label->d_partitions; if (label->d_magic != DISKLABELMAGIC) { - printk("magic: %08x\n", label->d_magic); brelse(bh); return 0; } if (label->d_magic2 != DISKLABELMAGIC) { - printk("magic2: %08x\n", label->d_magic2); brelse(bh); return 0; } @@ -775,14 +788,11 @@ #endif /* CONFIG_SUN_PARTITION */ #ifdef CONFIG_SGI_PARTITION -#include static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) { - int i, csum; - unsigned int *ui; - unsigned int start, blocks, cs; - int magic; + int i, csum, magic; + unsigned int *ui, start, blocks, cs; struct buffer_head *bh; struct sgi_disklabel { int magic_mushroom; /* Big fat spliff... */ @@ -851,7 +861,6 @@ #endif #ifdef CONFIG_AMIGA_PARTITION -#include #include static __inline__ u32 @@ -919,13 +928,14 @@ blk = htonl(pb->pb_Next); if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block( (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) { - + /* Tell Kernel about it */ if (!(nr_sects = (htonl(pb->pb_Environment[10]) + 1 - htonl(pb->pb_Environment[9])) * htonl(pb->pb_Environment[3]) * htonl(pb->pb_Environment[5]))) { + brelse(bh); continue; } start_sect = htonl(pb->pb_Environment[9]) * @@ -938,8 +948,9 @@ brelse(bh); } printk("\n"); - break; } + else + brelse(bh); } rdb_done: @@ -1077,7 +1088,7 @@ #endif /* CONFIG_MAC_PARTITION */ #ifdef CONFIG_ATARI_PARTITION -#include +#include /* ++guenther: this should be settable by the user ("make config")?. */ @@ -1091,16 +1102,27 @@ struct rootsector *rs; struct partition_info *pi; ulong extensect; + unsigned int psum; + int i; #ifdef ICD_PARTS int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ #endif bh = bread (dev, 0, get_ptable_blocksize(dev)); - if (!bh) - { - printk (" unable to read block 0\n"); + if (!bh) { + printk (" unable to read block 0 (partition table)\n"); return -1; - } + } + + /* Verify this is an Atari rootsector: */ + psum=0; + for (i=0;i<256;i++) { + psum+=ntohs(((__u16 *) (bh->b_data))[i]); + } + if ((psum & 0xFFFF) != 0x1234) { + brelse(bh); + return 0; + } rs = (struct rootsector *) bh->b_data; pi = &rs->part[0]; @@ -1121,7 +1143,7 @@ part_fmt = 1; #endif printk(" XGM<"); - partsect = extensect = pi->st; + partsect = extensect = ntohl(pi->st); while (1) { xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev)); @@ -1142,8 +1164,8 @@ break; } - add_partition(hd, minor, partsect + xrs->part[0].st, - xrs->part[0].siz); + add_partition(hd, minor, partsect + ntohl(xrs->part[0].st), + ntohl(xrs->part[0].siz)); if (!(xrs->part[1].flg & 1)) { /* end of linked partition list */ @@ -1156,7 +1178,7 @@ break; } - partsect = xrs->part[1].st + extensect; + partsect = ntohl(xrs->part[1].st) + extensect; brelse (xbh); minor++; if (minor >= m_lim) { @@ -1169,7 +1191,7 @@ else { /* we don't care about other id's */ - add_partition (hd, minor, pi->st, pi->siz); + add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz)); } } } @@ -1196,7 +1218,7 @@ memcmp (pi->id, "RAW", 3) == 0) ) { part_fmt = 2; - add_partition (hd, minor, pi->st, pi->siz); + add_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz)); } } printk(" >"); @@ -1211,14 +1233,62 @@ } #endif /* CONFIG_ATARI_PARTITION */ +#ifdef CONFIG_ULTRIX_PARTITION + +static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) +{ + int i, minor = current_minor; + struct buffer_head *bh; + struct ultrix_disklabel { + s32 pt_magic; /* magic no. indicating part. info exits */ + s32 pt_valid; /* set by driver if pt is current */ + struct pt_info { + s32 pi_nblocks; /* no. of sectors */ + u32 pi_blkoff; /* block offset for start */ + } pt_part[8]; + } *label; + +#define PT_MAGIC 0x032957 /* Partition magic number */ +#define PT_VALID 1 /* Indicates if struct is valid */ + +#define SBLOCK ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \ + /get_ptable_blocksize(dev))) + + bh = bread (dev, SBLOCK, get_ptable_blocksize(dev)); + if (!bh) { + printk (" unable to read block 0x%lx\n", SBLOCK); + return -1; + } + + label = (struct ultrix_disklabel *)(bh->b_data + + get_ptable_blocksize(dev) + - sizeof(struct ultrix_disklabel)); + + if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) { + for (i=0; i<8; i++, minor++) + if (label->pt_part[i].pi_nblocks) + add_partition(hd, minor, + label->pt_part[i].pi_blkoff, + label->pt_part[i].pi_nblocks); + brelse(bh); + printk ("\n"); + return 1; + } else { + brelse(bh); + return 0; + } +} + +#endif /* CONFIG_ULTRIX_PARTITION */ + static void check_partition(struct gendisk *hd, kdev_t dev) { static int first_time = 1; unsigned long first_sector; - char buf[32]; + char buf[40]; if (first_time) - printk("Partition check:\n"); + printk(KERN_INFO "Partition check:\n"); first_time = 0; first_sector = hd->part[MINOR(dev)].start_sect; @@ -1231,7 +1301,7 @@ return; } - printk(" %s:", disk_name(hd, MINOR(dev), buf)); + printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); #ifdef CONFIG_MSDOS_PARTITION if (msdos_partition(hd, dev, first_sector)) return; @@ -1260,6 +1330,10 @@ if(sgi_partition(hd, dev, first_sector)) return; #endif +#ifdef CONFIG_ULTRIX_PARTITION + if(ultrix_partition(hd, dev, first_sector)) + return; +#endif printk(" unknown partition table\n"); } @@ -1309,9 +1383,10 @@ resetup_one_dev(dev, drive); } -__initfunc(void device_setup(void)) +void __init device_setup(void) { extern void console_map_init(void); + extern void cpqarray_init(void); #ifdef CONFIG_PARPORT extern int parport_init(void) __init; #endif @@ -1326,6 +1401,13 @@ #ifdef CONFIG_PARPORT parport_init(); #endif + /* + * I2O must come before block and char as the I2O layer may + * in future claim devices that block/char most not touch. + */ +#ifdef CONFIG_I2O + i2o_init(); +#endif chr_dev_init(); blk_dev_init(); sti(); @@ -1336,6 +1418,9 @@ #ifdef CONFIG_SCSI scsi_dev_init(); #endif +#ifdef CONFIG_BLK_CPQ_DA + cpqarray_init(); +#endif #ifdef CONFIG_INET net_dev_init(); #endif @@ -1362,7 +1447,7 @@ int get_partition_list(char * page) { struct gendisk *p; - char buf[32]; + char buf[40]; int n, len; len = sprintf(page, "major minor #blocks name\n\n"); diff -u --recursive --new-file v2.3.9/linux/drivers/block/hd.c linux/drivers/block/hd.c --- v2.3.9/linux/drivers/block/hd.c Sat May 15 23:43:04 1999 +++ linux/drivers/block/hd.c Tue Jul 6 19:05:48 1999 @@ -113,7 +113,7 @@ } #endif -__initfunc(void hd_setup(char *str, int *ints)) +void __init hd_setup(char *str, int *ints) { int hdind = 0; @@ -783,7 +783,7 @@ block_fsync /* fsync */ }; -__initfunc(int hd_init(void)) +int __init hd_init(void) { if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) { printk("hd: unable to get major %d for hard disk\n",MAJOR_NR); diff -u --recursive --new-file v2.3.9/linux/drivers/block/hpt343.c linux/drivers/block/hpt343.c --- v2.3.9/linux/drivers/block/hpt343.c Wed May 26 16:55:40 1999 +++ linux/drivers/block/hpt343.c Wed Dec 31 16:00:00 1969 @@ -1,392 +0,0 @@ -/* - * linux/drivers/block/hpt343.c Version 0.23 May 12, 1999 - * - * Copyright (C) 1998-99 Andre Hedrick - * (hedrick@astro.dyer.vanderbilt.edu) - * - * 00:12.0 Unknown mass storage controller: - * Triones Technologies, Inc. - * Unknown device 0003 (rev 01) - * - * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010) - * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030) - * hde: DMA 2 (0x0000 0x0002) (0x0000 0x0010) - * hdf: DMA 2 (0x0002 0x0012) (0x0010 0x0030) - * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) - * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) - * - * drive_number - * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "ide_modes.h" - -#ifndef SPLIT_BYTE -#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) -#endif - -#define HPT343_DEBUG_DRIVE_INFO 0 -#define HPT343_DISABLE_ALL_DMAING 0 -#define HPT343_DMA_DISK_ONLY 0 - -extern char *ide_xfer_verbose (byte xfer_rate); - -static void hpt343_clear_chipset (ide_drive_t *drive) -{ - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - unsigned int reg1 = 0, tmp1 = 0; - unsigned int reg2 = 0, tmp2 = 0; - - pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); - pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); - tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); - tmp2 = ((0x00 << drive_number) | reg2); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); -} - -static int hpt343_tune_chipset (ide_drive_t *drive, byte speed) -{ - int err; - byte hi_speed, lo_speed; - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - unsigned int reg1 = 0, tmp1 = 0; - unsigned int reg2 = 0, tmp2 = 0; - - SPLIT_BYTE(speed, hi_speed, lo_speed); - - if (hi_speed & 7) { - hi_speed = (hi_speed & 4) ? 0x01 : 0x10; - } else { - lo_speed <<= 5; - lo_speed >>= 5; - } - - pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); - pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); - tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); - tmp2 = ((hi_speed << drive_number) | reg2); - err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); - -#if HPT343_DEBUG_DRIVE_INFO - printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \ - " (0x%02x 0x%02x) 0x%04x\n", - drive->name, ide_xfer_verbose(speed), - drive_number, reg1, tmp1, reg2, tmp2, - hi_speed, lo_speed, err); -#endif /* HPT343_DEBUG_DRIVE_INFO */ - - return(err); -} - -/* - * This allows the configuration of ide_pci chipset registers - * for cards that learn about the drive's UDMA, DMA, PIO capabilities - * after the drive is reported by the OS. Initally for designed for - * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. - */ -static int config_chipset_for_dma (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - byte speed = 0x00; - -#if HPT343_DISABLE_ALL_DMAING - return ((int) ide_dma_off); -#elif HPT343_DMA_DISK_ONLY - if (drive->media != ide_disk) - return ((int) ide_dma_off_quietly); -#endif /* HPT343_DISABLE_ALL_DMAING */ - - if (id->dma_ultra & 0x0004) { - if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_ultra |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_ultra |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_ultra |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - if (!((id->dma_mword >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0404; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - if (!((id->dma_mword >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0202; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - if (!((id->dma_mword >> 8) & 1)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0101; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - if (!((id->dma_1word >> 8) & 4)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - } - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - if (!((id->dma_1word >> 8) & 2)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - } - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - if (!((id->dma_1word >> 8) & 1)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - } - speed = XFER_SW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); - } - - (void) hpt343_tune_chipset(drive, speed); - - return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); -} - -static void config_chipset_for_pio (ide_drive_t *drive) -{ - unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; - unsigned short xfer_pio = drive->id->eide_pio_modes; - - byte timing, speed, pio; - - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio> 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) { - for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; - xfer_pio--); - } else { - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; - } - - timing = (xfer_pio >= pio) ? xfer_pio : pio; - - switch(timing) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: - speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - break; - } - - (void) hpt343_tune_chipset(drive, speed); -} - -#if 0 -static void hpt343_tune_drive (ide_drive_t *drive, byte pio) -{ -} -#endif - -static int config_drive_xfer_rate (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - ide_dma_action_t dma_func = ide_dma_on; - - if (id && (id->capability & 1) && HWIF(drive)->autodma) { - /* Consult the list of known "bad" drives */ - if (ide_dmaproc(ide_dma_bad_drive, drive)) { - dma_func = ide_dma_off; - goto fast_ata_pio; - } - dma_func = ide_dma_off_quietly; - if (id->field_valid & 4) { - if (id->dma_ultra & 0x0007) { - /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive); - if ((id->field_valid & 2) && - (dma_func != ide_dma_on)) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x0007)) { - /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) - goto no_dma_set; - } - } else if (ide_dmaproc(ide_dma_good_drive, drive)) { - if (id->eide_dma_time > 150) { - goto no_dma_set; - } - /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive); - if (dma_func != ide_dma_on) - goto no_dma_set; - } else { - goto fast_ata_pio; - } - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - dma_func = ide_dma_off_quietly; -no_dma_set: - - config_chipset_for_pio(drive); - } - return HWIF(drive)->dmaproc(dma_func, drive); -} - -/* - * hpt343_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. - * - * This is specific to the HPT343 UDMA bios-less chipset - * and HPT345 UDMA bios chipset (stamped HPT363) - * by HighPoint|Triones Technologies, Inc. - */ - -int hpt343_dmaproc (ide_dma_action_t func, ide_drive_t *drive) -{ - switch (func) { - case ide_dma_check: - hpt343_clear_chipset(drive); - return config_drive_xfer_rate(drive); -#if 0 - case ide_dma_off: - case ide_dma_off_quietly: - case ide_dma_on: - case ide_dma_check: - return config_drive_xfer_rate(drive); - case ide_dma_read: - case ide_dma_write: - case ide_dma_begin: - case ide_dma_end: - case ide_dma_test_irq: -#endif - default: - break; - } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ -} - -/* - * If the BIOS does not set the IO base addaress to XX00, 343 will fail. - */ -#define HPT343_PCI_INIT_REG 0x80 - -__initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name)) -{ - int i; - unsigned short cmd; - unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; -#if 0 - unsigned char misc10 = inb(hpt343IoBase + 0x0010); - unsigned char misc11 = inb(hpt343IoBase + 0x0011); -#endif - - pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x00); - pci_read_config_word(dev, PCI_COMMAND, &cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); - - dev->base_address[0] = (hpt343IoBase + 0x20); - dev->base_address[1] = (hpt343IoBase + 0x34); - dev->base_address[2] = (hpt343IoBase + 0x28); - dev->base_address[3] = (hpt343IoBase + 0x3c); - - for(i=0; i<4; i++) - dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; - - /* - * Since 20-23 can be assigned and are R/W, we correct them. - */ - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]); - pci_write_config_word(dev, PCI_COMMAND, cmd); - -#if 0 - outb(misc10|0x78, (hpt343IoBase + 0x0010)); - outb(misc11, (hpt343IoBase + 0x0011)); -#endif - -#ifdef DEBUG - printk("%s: 0x%02x 0x%02x\n", - (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name, - inb(hpt343IoBase + 0x0010), - inb(hpt343IoBase + 0x0011)); -#endif - - if (cmd & PCI_COMMAND_MEMORY) { - if (dev->rom_address) { - pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address); - } - } else { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); - } - return dev->irq; -} - -__initfunc(void ide_init_hpt343 (ide_hwif_t *hwif)) -{ - if (hwif->dma_base) { - unsigned short pcicmd = 0; - - pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); - hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; - hwif->dmaproc = &hpt343_dmaproc; - } -} diff -u --recursive --new-file v2.3.9/linux/drivers/block/hpt34x.c linux/drivers/block/hpt34x.c --- v2.3.9/linux/drivers/block/hpt34x.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/hpt34x.c Mon Jul 5 20:13:59 1999 @@ -0,0 +1,408 @@ +/* + * linux/drivers/block/hpt34x.c Version 0.24 July 3, 1999 + * + * Copyright (C) 1998-99 Andre Hedrick + * (hedrick@astro.dyer.vanderbilt.edu) + * + * 00:12.0 Unknown mass storage controller: + * Triones Technologies, Inc. + * Unknown device 0003 (rev 01) + * + * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010) + * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030) + * hde: DMA 2 (0x0000 0x0002) (0x0000 0x0010) + * hdf: DMA 2 (0x0002 0x0012) (0x0010 0x0030) + * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) + * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) + * + * drive_number + * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +#ifndef SPLIT_BYTE +#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) +#endif + +#define HPT343_DEBUG_DRIVE_INFO 0 +#define HPT343_DISABLE_ALL_DMAING 0 +#define HPT343_DMA_DISK_ONLY 0 + +extern char *ide_xfer_verbose (byte xfer_rate); + +static void hpt34x_clear_chipset (ide_drive_t *drive) +{ + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + unsigned int reg1 = 0, tmp1 = 0; + unsigned int reg2 = 0, tmp2 = 0; + + pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); + pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); + tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); + tmp2 = ((0x00 << drive_number) | reg2); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); +} + +static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed) +{ + int err; + byte hi_speed, lo_speed; + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + unsigned int reg1 = 0, tmp1 = 0; + unsigned int reg2 = 0, tmp2 = 0; + + SPLIT_BYTE(speed, hi_speed, lo_speed); + + if (hi_speed & 7) { + hi_speed = (hi_speed & 4) ? 0x01 : 0x10; + } else { + lo_speed <<= 5; + lo_speed >>= 5; + } + + pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); + pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); + tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); + tmp2 = ((hi_speed << drive_number) | reg2); + err = ide_config_drive_speed(drive, speed); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); + pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); + +#if HPT343_DEBUG_DRIVE_INFO + printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \ + " (0x%02x 0x%02x) 0x%04x\n", + drive->name, ide_xfer_verbose(speed), + drive_number, reg1, tmp1, reg2, tmp2, + hi_speed, lo_speed, err); +#endif /* HPT343_DEBUG_DRIVE_INFO */ + + return(err); +} + +/* + * This allows the configuration of ide_pci chipset registers + * for cards that learn about the drive's UDMA, DMA, PIO capabilities + * after the drive is reported by the OS. Initally for designed for + * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. + */ +static int config_chipset_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte speed = 0x00; + +#if HPT343_DISABLE_ALL_DMAING + return ((int) ide_dma_off); +#elif HPT343_DMA_DISK_ONLY + if (drive->media != ide_disk) + return ((int) ide_dma_off_quietly); +#endif /* HPT343_DISABLE_ALL_DMAING */ + + if (id->dma_ultra & 0x0004) { + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_2; + } else if (id->dma_ultra & 0x0002) { + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_1; + } else if (id->dma_ultra & 0x0001) { + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0x0F00; + drive->id->dma_ultra |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + drive->id->dma_1word &= ~0x0F00; + } + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + drive->id->dma_mword &= ~0x0F00; + } + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + (void) hpt34x_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static void config_chipset_for_pio (ide_drive_t *drive) +{ + unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + + byte timing, speed, pio; + + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + xfer_pio = 0; + + if (drive->id->eide_pio_iordy > 0) { + for (xfer_pio = 5; + xfer_pio>0 && + drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; + xfer_pio--); + } else { + xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : + (drive->id->eide_pio_modes & 2) ? 0x04 : + (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; + } + + timing = (xfer_pio >= pio) ? xfer_pio : pio; + + switch(timing) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: + speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; + break; + } + (void) hpt34x_tune_chipset(drive, speed); +} + +static void hpt34x_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + + hpt34x_clear_chipset(drive); + switch(pio) { + case 4: speed = XFER_PIO_4;break; + case 3: speed = XFER_PIO_3;break; + case 2: speed = XFER_PIO_2;break; + case 1: speed = XFER_PIO_1;break; + default: speed = XFER_PIO_0;break; + } + (void) hpt34x_tune_chipset(drive, speed); +} + +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x0007) { + /* Force if Capable UltraDMA */ + dma_func = config_chipset_for_dma(drive); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x0007)) { + /* Force if Capable regular DMA modes */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + + config_chipset_for_pio(drive); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + +/* + * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + * + * This is specific to the HPT343 UDMA bios-less chipset + * and HPT345 UDMA bios chipset (stamped HPT363) + * by HighPoint|Triones Technologies, Inc. + */ + +int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + hpt34x_clear_chipset(drive); + return config_drive_xfer_rate(drive); +#if 0 + case ide_dma_off: + case ide_dma_off_quietly: + case ide_dma_on: + case ide_dma_check: + return config_drive_xfer_rate(drive); + case ide_dma_read: + case ide_dma_write: + case ide_dma_begin: + case ide_dma_end: + case ide_dma_test_irq: +#endif + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +/* + * If the BIOS does not set the IO base addaress to XX00, 343 will fail. + */ +#define HPT34X_PCI_INIT_REG 0x80 + +__initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name)) +{ + int i; + unsigned short cmd; + unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; +#if 0 + unsigned char misc10 = inb(hpt34xIoBase + 0x0010); + unsigned char misc11 = inb(hpt34xIoBase + 0x0011); +#endif + + pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); + + dev->base_address[0] = (hpt34xIoBase + 0x20); + dev->base_address[1] = (hpt34xIoBase + 0x34); + dev->base_address[2] = (hpt34xIoBase + 0x28); + dev->base_address[3] = (hpt34xIoBase + 0x3c); + + for(i=0; i<4; i++) + dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; + + /* + * Since 20-23 can be assigned and are R/W, we correct them. + */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]); + pci_write_config_word(dev, PCI_COMMAND, cmd); + +#if 0 + outb(misc10|0x78, (hpt34xIoBase + 0x0010)); + outb(misc11, (hpt34xIoBase + 0x0011)); +#endif + +#ifdef DEBUG + printk("%s: 0x%02x 0x%02x\n", + (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name, + inb(hpt34xIoBase + 0x0010), + inb(hpt34xIoBase + 0x0011)); +#endif + + if (cmd & PCI_COMMAND_MEMORY) { + if (dev->rom_address) { + pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); + printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address); + } + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); + } else { + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); + } + return dev->irq; +} + +__initfunc(void ide_init_hpt34x (ide_hwif_t *hwif)) +{ + hwif->tuneproc = &hpt34x_tune_drive; + if (hwif->dma_base) { + unsigned short pcicmd = 0; + + pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); +#ifdef CONFIG_BLK_DEV_HPT34X_DMA + hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; +#endif /* CONFIG_BLK_DEV_HPT34X_DMA */ + hwif->dmaproc = &hpt34x_dmaproc; + } else { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } +} diff -u --recursive --new-file v2.3.9/linux/drivers/block/icside.c linux/drivers/block/icside.c --- v2.3.9/linux/drivers/block/icside.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/icside.c Thu Jul 1 10:25:38 1999 @@ -299,6 +299,9 @@ drive->drive_data = 250; } +#if 1 + err = ide_config_drive_speed(drive, (byte) speed); +#else /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, @@ -313,6 +316,7 @@ err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); +#endif if (err == 0) { drive->id->dma_mword &= 0x00ff; diff -u --recursive --new-file v2.3.9/linux/drivers/block/ida_cmd.h linux/drivers/block/ida_cmd.h --- v2.3.9/linux/drivers/block/ida_cmd.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/ida_cmd.h Mon Jul 5 19:52:13 1999 @@ -0,0 +1,347 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#ifndef ARRAYCMD_H +#define ARRAYCMD_H + +#include +#if 0 +#include +#endif + +/* for the Smart Array 42XX cards */ +#define S42XX_REQUEST_PORT_OFFSET 0x40 +#define S42XX_REPLY_INTR_MASK_OFFSET 0x34 +#define S42XX_REPLY_PORT_OFFSET 0x44 +#define S42XX_INTR_STATUS 0x30 + +#define S42XX_INTR_OFF 0x08 +#define S42XX_INTR_PENDING 0x08 + +#define COMMAND_FIFO 0x04 +#define COMMAND_COMPLETE_FIFO 0x08 +#define INTR_MASK 0x0C +#define INTR_STATUS 0x10 +#define INTR_PENDING 0x14 + +#define FIFO_NOT_EMPTY 0x01 +#define FIFO_NOT_FULL 0x02 + +#define BIG_PROBLEM 0x40 +#define LOG_NOT_CONF 2 + +#pragma pack(1) +typedef struct { + __u32 size; + __u32 addr; +} sg_t; + +#define RCODE_NONFATAL 0x02 +#define RCODE_FATAL 0x04 +#define RCODE_INVREQ 0x10 +typedef struct { + __u16 next; + __u8 cmd; + __u8 rcode; + __u32 blk; + __u16 blk_cnt; + __u8 sg_cnt; + __u8 reserved; +} rhdr_t; + +#define SG_MAX 32 +typedef struct { + rhdr_t hdr; + sg_t sg[SG_MAX]; + __u32 bp; +} rblk_t; + +typedef struct { + __u8 unit; + __u8 prio; + __u16 size; +} chdr_t; + +#define CMD_RWREQ 0x00 +#define CMD_IOCTL_PEND 0x01 +#define CMD_IOCTL_DONE 0x02 + +typedef struct cmdlist { + chdr_t hdr; + rblk_t req; + __u32 size; + int retry_cnt; + __u32 busaddr; + int ctlr; + struct cmdlist *prev; + struct cmdlist *next; + struct buffer_head *bh; + int type; +} cmdlist_t; + +#define ID_CTLR 0x11 +typedef struct { + __u8 nr_drvs; + __u32 cfg_sig; + __u8 firm_rev[4]; + __u8 rom_rev[4]; + __u8 hw_rev; + __u32 bb_rev; + __u32 drv_present_map; + __u32 ext_drv_map; + __u32 board_id; + __u8 cfg_error; + __u32 non_disk_bits; + __u8 bad_ram_addr; + __u8 cpu_rev; + __u8 pdpi_rev; + __u8 epic_rev; + __u8 wcxc_rev; + __u8 marketing_rev; + __u8 ctlr_flags; + __u8 host_flags; + __u8 expand_dis; + __u8 scsi_chips; + __u32 max_req_blocks; + __u32 ctlr_clock; + __u8 drvs_per_bus; + __u16 big_drv_present_map[8]; + __u16 big_ext_drv_map[8]; + __u16 big_non_disk_map[8]; + __u16 task_flags; + __u8 icl_bus; + __u8 red_modes; + __u8 cur_red_mode; + __u8 red_ctlr_stat; + __u8 red_fail_reason; + __u8 reserved[403]; +} id_ctlr_t; + +typedef struct { + __u16 cyl; + __u8 heads; + __u8 xsig; + __u8 psectors; + __u16 wpre; + __u8 maxecc; + __u8 drv_ctrl; + __u16 pcyls; + __u8 pheads; + __u16 landz; + __u8 sect_per_track; + __u8 cksum; +} drv_param_t; + +#define ID_LOG_DRV 0x10 +typedef struct { + __u16 blk_size; + __u32 nr_blks; + drv_param_t drv; + __u8 fault_tol; + __u8 reserved; + __u8 bios_disable; +} id_log_drv_t; + +#define ID_LOG_DRV_EXT 0x18 +typedef struct { + __u32 log_drv_id; + __u8 log_drv_label[64]; + __u8 reserved[418]; +} id_log_drv_ext_t; + +#define SENSE_LOG_DRV_STAT 0x12 +typedef struct { + __u8 status; + __u32 fail_map; + __u16 read_err[32]; + __u16 write_err[32]; + __u8 drv_err_data[256]; + __u8 drq_timeout[32]; + __u32 blks_to_recover; + __u8 drv_recovering; + __u16 remap_cnt[32]; + __u32 replace_drv_map; + __u32 act_spare_map; + __u8 spare_stat; + __u8 spare_repl_map[32]; + __u32 repl_ok_map; + __u8 media_exch; + __u8 cache_fail; + __u8 expn_fail; + __u8 unit_flags; + __u16 big_fail_map[8]; + __u16 big_remap_map[8]; + __u16 big_repl_map[8]; + __u16 big_act_spare_map[8]; + __u8 big_spar_repl_map[128]; + __u16 big_repl_ok_map[8]; + __u8 big_drv_rebuild; + __u8 reserved[36]; +} sense_log_drv_stat_t; + +#define START_RECOVER 0x13 + +#define ID_PHYS_DRV 0x15 +typedef struct { + __u8 scsi_bus; + __u8 scsi_id; + __u16 blk_size; + __u32 nr_blks; + __u32 rsvd_blks; + __u8 drv_model[40]; + __u8 drv_sn[40]; + __u8 drv_fw[8]; + __u8 scsi_iq_bits; + __u8 compaq_drv_stmp; + __u8 last_fail; + __u8 phys_drv_flags; + __u8 phys_drv_flags1; + __u8 scsi_lun; + __u8 phys_drv_flags2; + __u8 reserved; + __u32 spi_speed_rules; + __u8 phys_connector[2]; + __u8 phys_box_on_bus; + __u8 phys_bay_in_box; +} id_phys_drv_t; + +#define BLINK_DRV_LEDS 0x16 +typedef struct { + __u32 blink_duration; + __u32 reserved; + __u8 blink[256]; + __u8 reserved1[248]; +} blink_drv_leds_t; + +#define SENSE_BLINK_LEDS 0x17 +typedef struct { + __u32 blink_duration; + __u32 btime_elap; + __u8 blink[256]; + __u8 reserved1[248]; +} sense_blink_leds_t; + +#define IDA_READ 0x20 +#define IDA_WRITE 0x30 +#define IDA_WRITE_MEDIA 0x31 +#define RESET_TO_DIAG 0x40 +#define DIAG_PASS_THRU 0x41 + +#define SENSE_CONFIG 0x50 +#define SET_CONFIG 0x51 +typedef struct { + __u32 cfg_sig; + __u16 compat_port; + __u8 data_dist_mode; + __u8 surf_an_ctrl; + __u16 ctlr_phys_drv; + __u16 log_unit_phys_drv; + __u16 fault_tol_mode; + __u8 phys_drv_param[16]; + drv_param_t drv; + __u32 drv_asgn_map; + __u16 dist_factor; + __u32 spare_asgn_map; + __u8 reserved[6]; + __u16 os; + __u8 ctlr_order; + __u8 extra_info; + __u32 data_offs; + __u8 parity_backedout_write_drvs; + __u8 parity_dist_mode; + __u8 parity_shift_fact; + __u8 bios_disable_flag; + __u32 blks_on_vol; + __u32 blks_per_drv; + __u8 scratch[16]; + __u16 big_drv_map[8]; + __u16 big_spare_map[8]; + __u8 ss_source_vol; + __u8 mix_drv_cap_range; + struct { + __u16 big_drv_map[8]; + __u32 blks_per_drv; + __u16 fault_tol_mode; + __u16 dist_factor; + } MDC_range[4]; + __u8 reserved1[248]; +} config_t; + +#define BYPASS_VOL_STATE 0x52 +#define SS_CREATE_VOL 0x53 +#define CHANGE_CONFIG 0x54 +#define SENSE_ORIG_CONF 0x55 +#define REORDER_LOG_DRV 0x56 +typedef struct { + __u8 old_units[32]; +} reorder_log_drv_t; + +#define LABEL_LOG_DRV 0x57 +typedef struct { + __u8 log_drv_label[64]; +} label_log_drv_t; + +#define SS_TO_VOL 0x58 + +#define SET_SURF_DELAY 0x60 +typedef struct { + __u16 delay; + __u8 reserved[510]; +} surf_delay_t; + +#define SET_OVERHEAT_DELAY 0x61 +typedef struct { + __u16 delay; +} overhead_delay_t; + +#define SET_MP_DELAY +typedef struct { + __u16 delay; + __u8 reserved[510]; +} mp_delay_t; + +#define PASSTHRU_A 0x91 +typedef struct { + __u8 target; + __u8 bus; + __u8 lun; + __u32 timeout; + __u32 flags; + __u8 status; + __u8 error; + __u8 cdb_len; + __u8 sense_error; + __u8 sense_key; + __u32 sense_info; + __u8 sense_code; + __u8 sense_qual; + __u8 residual; + __u8 reserved[4]; + __u8 cdb[12]; +} scsi_param_t; + +#define RESUME_BACKGROUND_ACTIVITY 0x99 +#pragma pack() + +#endif /* ARRAYCMD_H */ diff -u --recursive --new-file v2.3.9/linux/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h --- v2.3.9/linux/drivers/block/ida_ioctl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/ida_ioctl.h Mon Jul 5 19:52:13 1999 @@ -0,0 +1,83 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#ifndef IDA_IOCTL_H +#define IDA_IOCTL_H + +#include "ida_cmd.h" +#include "cpqarray.h" + +#define IDAGETDRVINFO 0x27272828 +#define IDAPASSTHRU 0x28282929 +#define IDAGETCTLRSIG 0x29293030 +#define IDAREVALIDATEVOLS 0x30303131 +#define IDADRIVERVERSION 0x31313232 + +/* + * Normally, the ioctl determines the logical unit for this command by + * the major,minor number of the fd passed to ioctl. If you need to send + * a command to a different/nonexistant unit (such as during config), you + * can override the normal behavior by setting the unit valid bit. (Normally, + * it should be zero) The controller the command is sent to is still + * determined by the major number of the open device. + */ + +#define UNITVALID 0x80 +typedef struct { + __u8 cmd; + __u8 rcode; + __u8 unit; + __u32 blk; + __u16 blk_cnt; + +/* currently, sg_cnt is assumed to be 1: only the 0th element of sg is used */ + struct { + void *addr; + size_t size; + } sg[SG_MAX]; + int sg_cnt; + + union ctlr_cmds { + drv_info_t drv; + unsigned char buf[512]; + + id_ctlr_t id_ctlr; + drv_param_t drv_param; + id_log_drv_t id_log_drv; + id_log_drv_ext_t id_log_drv_ext; + sense_log_drv_stat_t sense_log_drv_stat; + id_phys_drv_t id_phys_drv; + blink_drv_leds_t blink_drv_leds; + sense_blink_leds_t sense_blink_leds; + config_t config; + reorder_log_drv_t reorder_log_drv; + label_log_drv_t label_log_drv; + surf_delay_t surf_delay; + overhead_delay_t overhead_delay; + mp_delay_t mp_delay; + scsi_param_t scsi_param; + } c; +} ida_ioctl_t; + +#endif /* IDA_IOCTL_H */ diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.3.9/linux/drivers/block/ide-disk.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/ide-disk.c Mon Jul 5 20:13:59 1999 @@ -776,8 +776,9 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); if (drive->using_dma) { - if ((id->field_valid & 4) && (id->word93 & 0x2000) && - (id->dma_ultra & (id->dma_ultra >> 11) & 3)) { + if ((id->field_valid & 4) && (id->word93 & 0x2000) && + (HWIF(drive)->udma_four) && + (id->dma_ultra & (id->dma_ultra >> 11) & 3)) { printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ } else if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.3.9/linux/drivers/block/ide-dma.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/ide-dma.c Thu Jul 1 10:25:38 1999 @@ -91,9 +91,8 @@ #include #include -#define IDE_DMA_NEW_LISTINGS 0 +#ifdef IDEDMA_NEW_DRIVE_LISTINGS -#if IDE_DMA_NEW_LISTINGS struct drive_list_entry { char * id_model; char * id_firmware; @@ -130,7 +129,8 @@ return 1; return 0; } -#else /* !IDE_DMA_NEW_LISTINGS */ + +#else /* !IDEDMA_NEW_DRIVE_LISTINGS */ /* * good_dma_drives() lists the model names (from "hdparm -i") @@ -162,7 +162,7 @@ "WDC AC31600H", NULL}; -#endif /* IDE_DMA_NEW_LISTINGS */ +#endif /* IDEDMA_NEW_DRIVE_LISTINGS */ /* * Our Physical Region Descriptor (PRD) table should be large enough @@ -314,8 +314,7 @@ { struct hd_driveid *id = drive->id; -#if IDE_DMA_NEW_LISTINGS - +#ifdef IDEDMA_NEW_DRIVE_LISTINGS if (good_bad) { return in_drive_list(id, drive_whitelist); } else { @@ -324,8 +323,7 @@ printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); return(blacklist); } -#else /* !IDE_DMA_NEW_LISTINGS */ - +#else /* !IDEDMA_NEW_DRIVE_LISTINGS */ const char **list; if (good_bad) { @@ -346,7 +344,7 @@ } } } -#endif /* IDE_DMA_NEW_LISTINGS */ +#endif /* IDEDMA_NEW_DRIVE_LISTINGS */ return 0; } @@ -359,12 +357,12 @@ /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); -#if 0 +#ifdef CONFIG_IDEDMA_ULTRA_66 /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */ if ((id->field_valid & 4) && (id->word93 & 0x2000)) if ((id->dma_ultra & (id->dma_ultra >> 11) & 3)) return hwif->dmaproc(ide_dma_on, drive); -#endif +#endif /* CONFIG_IDEDMA_ULTRA_66 */ /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) @@ -527,7 +525,7 @@ } } if (dma_base) { - if (extra) /* PDC20246 & HPT343 */ + if (extra) /* PDC20246, PDC20262, & HPT343 */ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; @@ -538,13 +536,15 @@ * Lets attempt to use the same Ali tricks * to fix CMD643..... */ +#ifdef CONFIG_BLK_DEV_ALI15X3 case PCI_DEVICE_ID_AL_M5219: case PCI_DEVICE_ID_AL_M5229: - outb(inb(dma_base+2) & 0x60, dma_base+2); /* * Ali 15x3 chipsets know as ALI IV and V report * this as simplex, skip this test for them. */ +#endif /* CONFIG_BLK_DEV_ALI15X3 */ + outb(inb(dma_base+2) & 0x60, dma_base+2); if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA forced\n", name); } diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.3.9/linux/drivers/block/ide-pci.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/ide-pci.c Mon Jul 5 20:13:59 1999 @@ -51,7 +51,7 @@ #define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF}) -#define DEVID_HPT343 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) +#define DEVID_HPT34X ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) #define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) @@ -156,14 +156,14 @@ #define PCI_AEC6210 NULL #endif -#ifdef CONFIG_BLK_DEV_HPT343 -extern unsigned int pci_init_hpt343(struct pci_dev *, const char *); -extern void ide_init_hpt343(ide_hwif_t *); -#define PCI_HPT343 &pci_init_hpt343 -#define INIT_HPT343 &ide_init_hpt343 +#ifdef CONFIG_BLK_DEV_HPT34X +extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *); +extern void ide_init_hpt34x(ide_hwif_t *); +#define PCI_HPT34X &pci_init_hpt34x +#define INIT_HPT34X &ide_init_hpt34x #else -#define PCI_HPT343 NULL -#define INIT_HPT343 NULL +#define PCI_HPT34X NULL +#define INIT_HPT34X NULL #endif #define INIT_SAMURAI NULL @@ -212,7 +212,7 @@ {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HPT343, "HPT343", PCI_HPT343, INIT_HPT343, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, + {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0 }, {DEVID_CY82C693,"CY82C693", NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, @@ -231,19 +231,22 @@ { int i; unsigned short pcicmd = 0; - unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; + unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; pci_write_config_byte(dev, 0x80, 0x00); - dev->base_address[0] = (hpt343IoBase + 0x20); - dev->base_address[1] = (hpt343IoBase + 0x34); - dev->base_address[2] = (hpt343IoBase + 0x28); - dev->base_address[3] = (hpt343IoBase + 0x3c); + dev->base_address[0] = (hpt34xIoBase + 0x20); + dev->base_address[1] = (hpt34xIoBase + 0x34); + dev->base_address[2] = (hpt34xIoBase + 0x28); + dev->base_address[3] = (hpt34xIoBase + 0x3c); for(i=0; i<4; i++) dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - if (!(pcicmd & PCI_COMMAND_MEMORY)) + if (!(pcicmd & PCI_COMMAND_MEMORY)) { pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); + } else { + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); + } } case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: @@ -422,7 +425,7 @@ printk("%s: 100%% native mode on irq %d\n", d->name, pciirq); #endif } - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343)) { + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { /* * Since there are two cards that report almost identically, * the only discernable difference is the values @@ -483,16 +486,19 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513)) + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) autodma = 0; + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) + hwif->udma_four = 1; if (autodma) hwif->autodma = 1; if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || -#ifdef CONFIG_BLK_DEV_HPT343 - IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343) || -#endif +#ifdef CONFIG_BLK_DEV_HPT34X + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || +#endif /* CONFIG_BLK_DEV_HPT34X */ IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.3.9/linux/drivers/block/ide-probe.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/ide-probe.c Mon Jul 5 20:13:59 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-probe.c Version 1.04 March 10, 1999 + * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -18,8 +18,11 @@ * by Andrea Arcangeli * Version 1.03 fix for (hwif->chipset == ide_4drives) * Version 1.04 fixed buggy treatments of known flash memory cards - * fix for (hwif->chipset == ide_pdc4030) + * + * Version 1.05 fix for (hwif->chipset == ide_pdc4030) * added ide6/7 + * allowed for secondary flash card to be detectable + * with new flag : drive->ata_flash : 1; */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -141,8 +144,10 @@ */ if (drive_is_flashcard(drive)) { ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit]; - mate->present = 0; - mate->noprobe = 1; + if (!mate->ata_flash) { + mate->present = 0; + mate->noprobe = 1; + } } drive->media = ide_disk; printk("ATA DISK drive\n"); diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.3.9/linux/drivers/block/ide-tape.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/ide-tape.c Tue Jul 6 19:16:55 1999 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-tape.c Version 1.14 Dec 30, 1998 + * linux/drivers/block/ide-tape.c Version 1.15 Jul 4, 1999 * - * Copyright (C) 1995 - 1998 Gadi Oxman + * Copyright (C) 1995 - 1999 Gadi Oxman * * This driver was constructed as a student project in the software laboratory * of the faculty of electrical engineering in the Technion - Israel's @@ -214,6 +214,9 @@ * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB * Ver 1.14 Dec 30 98 Partial fixes for the Sony/AIWA tape drives. * Replace cli()/sti() with hwgroup spinlocks. + * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup + * spinlock with private per-tape spinlock. + * Fix use of freed memory. * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well: @@ -697,6 +700,7 @@ int excess_bh_size; /* Wasted space in each stage */ unsigned int flags; /* Status/Action flags */ + spinlock_t spinlock; /* protects the ide-tape queue */ } idetape_tape_t; /* @@ -1443,7 +1447,7 @@ #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_add_stage_tail\n"); #endif /* IDETAPE_DEBUG_LOG */ - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); stage->next=NULL; if (tape->last_stage != NULL) tape->last_stage->next=stage; @@ -1454,7 +1458,7 @@ tape->next_stage=tape->last_stage; tape->nr_stages++; tape->nr_pending_stages++; - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); } /* @@ -1556,7 +1560,9 @@ ide_drive_t *drive = hwgroup->drive; struct request *rq = hwgroup->rq; idetape_tape_t *tape = drive->driver_data; + unsigned long flags; int error; + int remove_stage = 0; #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_end_request\n"); @@ -1571,6 +1577,7 @@ if (error) tape->failed_pc = NULL; + spin_lock_irqsave(&tape->spinlock, flags); if (tape->active_data_request == rq) { /* The request was a pipelined data transfer request */ tape->active_stage = NULL; tape->active_data_request = NULL; @@ -1581,7 +1588,7 @@ if (error == IDETAPE_ERROR_EOD) idetape_abort_pipeline (drive); } - idetape_remove_stage_head (drive); + remove_stage = 1; } if (tape->next_stage != NULL) { idetape_active_next_stage (drive); @@ -1599,6 +1606,9 @@ idetape_increase_max_pipeline_stages (drive); } ide_end_drive_cmd (drive, 0, 0); + if (remove_stage) + idetape_remove_stage_head (drive); + spin_unlock_irqrestore(&tape->spinlock, flags); } /* @@ -2340,6 +2350,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) { DECLARE_MUTEX_LOCKED(sem); + idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_BUGS if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) { @@ -2348,9 +2359,9 @@ } #endif /* IDETAPE_DEBUG_BUGS */ rq->sem = &sem; - spin_unlock(&HWGROUP(drive)->spinlock); + spin_unlock(&tape->spinlock); down(&sem); - spin_lock_irq(&HWGROUP(drive)->spinlock); + spin_lock_irq(&tape->spinlock); } /* @@ -2424,10 +2435,10 @@ */ return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh)); } - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (tape->active_stage == tape->first_stage) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); rq_ptr = &tape->first_stage->rq; bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); @@ -2476,12 +2487,12 @@ * Pay special attention to possible race conditions. */ while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) { - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (idetape_pipeline_active (tape)) { idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); } else { - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); idetape_insert_pipeline_into_queue (drive); if (idetape_pipeline_active (tape)) continue; @@ -2538,11 +2549,11 @@ if (tape->first_stage == NULL) return; - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); tape->next_stage = NULL; if (idetape_pipeline_active (tape)) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); while (tape->first_stage != NULL) idetape_remove_stage_head (drive); @@ -2562,7 +2573,7 @@ if (!idetape_pipeline_active (tape)) idetape_insert_pipeline_into_queue (drive); - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (!idetape_pipeline_active (tape)) goto abort; #if IDETAPE_DEBUG_BUGS @@ -2572,7 +2583,7 @@ #endif /* IDETAPE_DEBUG_BUGS */ idetape_wait_for_request(drive, &tape->last_stage->rq); abort: - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); } static void idetape_pad_zeros (ide_drive_t *drive, int bcount) @@ -2817,10 +2828,10 @@ * Wait until the first read-ahead request * is serviced. */ - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (tape->active_stage == tape->first_stage) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK) count++; @@ -3564,6 +3575,8 @@ u16 speed; struct idetape_id_gcw gcw; + memset (tape, 0, sizeof (idetape_tape_t)); + spin_lock_init(&tape->spinlock); drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ #ifdef CONFIG_BLK_DEV_IDEPCI diff -u --recursive --new-file v2.3.9/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.3.9/linux/drivers/block/ide.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/ide.c Mon Jul 5 20:13:59 1999 @@ -297,7 +297,8 @@ if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */ || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ || !strncmp(id->model, "SunDisk SDCFB", 13) /* SunDisk */ - || !strncmp(id->model, "HAGIWARA HPC", 12)) /* Hagiwara */ + || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */ + || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */ { return 1; /* yes, it is a flash memory card */ } @@ -1353,7 +1354,7 @@ (void) hwgroup->hwif->dmaproc(ide_dma_end, drive); printk("%s: timeout waiting for DMA\n", drive->name); /* - * need something here for HX PIIX3 UDMA and HPT343.......AMH + * need something here for HPT34X.......AMH * irq timeout: status=0x58 { DriveReady SeekComplete DataRequest } */ } @@ -1898,6 +1899,7 @@ hwif->irq = old_hwif.irq; hwif->major = old_hwif.major; hwif->proc = old_hwif.proc; + hwif->udma_four = old_hwif.udma_four; hwif->chipset = old_hwif.chipset; hwif->pci_dev = old_hwif.pci_dev; hwif->pci_devid = old_hwif.pci_devid; @@ -2235,6 +2237,27 @@ while (0 < (signed long)(timeout - jiffies)); } +int ide_config_drive_speed (ide_drive_t *drive, byte speed) +{ + int err; + + /* + * Don't use ide_wait_cmd here - it will + * attempt to set_geometry and recalibrate, + * but for some reason these don't work at + * this point (lost interrupt). + */ + SELECT_DRIVE(HWIF(drive), drive); + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + OUT_BYTE(speed, IDE_NSECTOR_REG); + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + + err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); + + return(err); +} + static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2317,10 +2340,15 @@ } if ((((byte *)arg)[0] == WIN_SETFEATURES) && (((byte *)arg)[1] > 66) && - (((byte *)arg)[2] == 3) && - ((drive->id->word93 & 0x2000) == 0)) { - printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name); - goto abort; + (((byte *)arg)[2] == 3)) { + if (!HWIF(drive)->udma_four) { + printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name); + goto abort; + } + if ((drive->id->word93 & 0x2000) == 0) { + printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name); + goto abort; + } } err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); if (!err && @@ -2581,6 +2609,9 @@ * * "hdx=swapdata" : when the drive is a disk, byte swap all data * "hdx=bswap" : same as above.......... + * "hdx=flash" : allows for more than one ata_flash disk to be + * registered. In most cases, only one device + * will be present. * * "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz, * where "xx" is between 20 and 66 inclusive, @@ -2667,7 +2698,7 @@ if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", - "slow", "swapdata", "bswap", NULL}; + "slow", "swapdata", "bswap", "flash", NULL}; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; @@ -2708,6 +2739,9 @@ case -10: drive->bswap = 1; goto done; + case -11: + drive->ata_flash = 1; + goto done; case 3: /* cyl,head,sect */ drive->media = ide_disk; drive->cyl = drive->bios_cyl = vals[0]; @@ -3416,6 +3450,7 @@ EXPORT_SYMBOL(ide_cmd); EXPORT_SYMBOL(ide_wait_cmd); EXPORT_SYMBOL(ide_delay_50ms); +EXPORT_SYMBOL(ide_config_drive_speed); EXPORT_SYMBOL(ide_stall_queue); #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(ide_add_proc_entries); diff -u --recursive --new-file v2.3.9/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.9/linux/drivers/block/ll_rw_blk.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/block/ll_rw_blk.c Mon Jul 5 19:52:52 1999 @@ -347,6 +347,9 @@ /* for SCSI devices, call request_fn unconditionally */ if (scsi_blk_major(MAJOR(req->rq_dev))) queue_new_request = 1; + if (MAJOR(req->rq_dev) >= COMPAQ_SMART2_MAJOR+0 && + MAJOR(req->rq_dev) <= COMPAQ_SMART2_MAJOR+7) + queue_new_request = 1; out: if (queue_new_request) (dev->request_fn)(); @@ -506,6 +509,14 @@ case SCSI_DISK7_MAJOR: case SCSI_CDROM_MAJOR: case I2O_MAJOR: + case COMPAQ_SMART2_MAJOR+0: + case COMPAQ_SMART2_MAJOR+1: + case COMPAQ_SMART2_MAJOR+2: + case COMPAQ_SMART2_MAJOR+3: + case COMPAQ_SMART2_MAJOR+4: + case COMPAQ_SMART2_MAJOR+5: + case COMPAQ_SMART2_MAJOR+6: + case COMPAQ_SMART2_MAJOR+7: do { if (req->sem) @@ -717,7 +728,7 @@ wake_up(&wait_for_request); } -__initfunc(int blk_dev_init(void)) +int __init blk_dev_init(void) { struct request * req; struct blk_dev_struct *dev; diff -u --recursive --new-file v2.3.9/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.3.9/linux/drivers/block/loop.c Sun May 30 10:17:43 1999 +++ linux/drivers/block/loop.c Mon Jul 5 20:15:24 1999 @@ -27,7 +27,13 @@ * - Should use an own CAP_* category instead of CAP_SYS_ADMIN * - Should use the underlying filesystems/devices read function if possible * to support read ahead (and for write) - */ + * + * WARNING/FIXME: + * - The block number as IV passing to low level transfer functions is broken: + * it passes the underlying device's block number instead of the + * offset. This makes it change for a given block when the file is + * moved/restored/copied and also doesn't work over NFS. + */ #include @@ -107,7 +113,7 @@ static int xor_status(struct loop_device *lo, struct loop_info *info) { - if (info->lo_encrypt_key_size < 0) + if (info->lo_encrypt_key_size <= 0) return -EINVAL; return 0; } @@ -369,6 +375,10 @@ a file structure */ lo->lo_backing_file = NULL; } else if (S_ISREG(inode->i_mode)) { + if (!inode->i_op->bmap) { + printk(KERN_ERR "loop: device has no block access/not implemented\n"); + goto out_putf; + } /* Backed by a regular file - we need to hold onto a file structure for this file. We'll use it to @@ -391,6 +401,7 @@ lo->lo_backing_file->f_dentry = file->f_dentry; lo->lo_backing_file->f_op = file->f_op; lo->lo_backing_file->private_data = file->private_data; + file_moveto(lo->lo_backing_file, file); error = get_write_access(inode); if (error) { @@ -504,8 +515,6 @@ if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; type = info.lo_encrypt_type; - if (info.lo_encrypt_key_size == 0 && type == LO_CRYPT_XOR) - return -EINVAL; if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) return -EINVAL; err = loop_release_xfer(lo); diff -u --recursive --new-file v2.3.9/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.3.9/linux/drivers/block/nbd.c Wed May 12 08:41:12 1999 +++ linux/drivers/block/nbd.c Mon Jul 5 20:07:02 1999 @@ -401,7 +401,7 @@ return 0; case NBD_SET_SIZE_BLOCKS: nbd_sizes[dev] = arg; - nbd_bytesizes[dev] = arg << nbd_blksize_bits[dev]; + nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev]; return 0; case NBD_DO_IT: if (!lo->file) diff -u --recursive --new-file v2.3.9/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c --- v2.3.9/linux/drivers/block/pdc202xx.c Wed May 26 16:55:40 1999 +++ linux/drivers/block/pdc202xx.c Thu Jul 1 10:25:38 1999 @@ -90,8 +90,6 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 -#define PDC202XX_FORCE_BURST_BIT 0 -#define PDC202XX_FORCE_MASTER_MODE 0 extern char *ide_xfer_verbose (byte xfer_rate); @@ -225,16 +223,12 @@ switch(drive_number) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 1: drive_pci = 0x64; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, 0x60, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -242,16 +236,12 @@ break; case 2: drive_pci = 0x68; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 3: drive_pci = 0x6c; pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; pci_read_config_byte(dev, 0x68, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -415,7 +405,7 @@ return ide_dma_off_quietly; } - err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + err = ide_config_drive_speed(drive, speed); #if PDC202XX_DECODE_REGISTER_INFO pci_read_config_byte(dev, (drive_pci), &AP); @@ -436,8 +426,6 @@ printk("0x%08x\n", drive_conf); #endif /* PDC202XX_DEBUG_DRIVE_INFO */ -chipset_is_set: - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : @@ -533,7 +521,7 @@ (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" ); -#if PDC202XX_FORCE_BURST_BIT +#ifdef PDC202XX_FORCE_BURST_BIT if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); outb(udma_speed_flag|1, high_16 + 0x001f); @@ -541,7 +529,7 @@ } #endif /* PDC202XX_FORCE_BURST_BIT */ -#if PDC202XX_FORCE_MASTER_MODE +#ifdef PDC202XX_FORCE_MASTER_MODE if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); diff -u --recursive --new-file v2.3.9/linux/drivers/block/piix.c linux/drivers/block/piix.c --- v2.3.9/linux/drivers/block/piix.c Wed Jun 2 22:21:51 1999 +++ linux/drivers/block/piix.c Sat Jul 3 10:45:04 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/piix.c Version 0.23 May 29, 1999 + * linux/drivers/block/piix.c Version 0.24 June 28, 1999 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer @@ -44,8 +44,15 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); * + * #if 0 + * int err; + * err = ide_config_drive_speed(drive, speed); + * (void) ide_config_drive_speed(drive, speed); + * #else + * #endif */ +#include #include #include #include @@ -62,6 +69,7 @@ extern char *ide_xfer_verbose (byte xfer_rate); +#ifdef CONFIG_BLK_DEV_PIIX_TUNING /* * */ @@ -91,6 +99,7 @@ return 0; } } +#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ /* * Based on settings done by AMI BIOS @@ -111,11 +120,7 @@ { 2, 1 }, { 2, 3 }, }; -#if 1 pio = ide_get_best_pio_mode(drive, pio, 5, NULL); -#else - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); -#endif pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); if (is_slave) { master_data = master_data | 0x4000; @@ -142,6 +147,8 @@ restore_flags(flags); } +#ifdef CONFIG_BLK_DEV_PIIX_TUNING + static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra) { struct hd_driveid *id = drive->id; @@ -246,17 +253,13 @@ } speed = XFER_SW_DMA_2; } else { -#if 0 - speed = XFER_PIO_0; -#else speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); -#endif } restore_flags(flags); piix_tune_drive(drive, piix_dma_2_pio(speed)); - (void) ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL); + (void) ide_config_drive_speed(drive, speed); #if PIIX_DEBUG_DRIVE_INFO printk("%s: %s drive%d ", @@ -284,11 +287,19 @@ /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } +#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ void ide_init_piix (ide_hwif_t *hwif) { hwif->tuneproc = &piix_tune_drive; +#ifdef CONFIG_BLK_DEV_PIIX_TUNING if (hwif->dma_base) { hwif->dmaproc = &piix_dmaproc; + } else +#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ + { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; } + } diff -u --recursive --new-file v2.3.9/linux/drivers/block/smart1,2.h linux/drivers/block/smart1,2.h --- v2.3.9/linux/drivers/block/smart1,2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/smart1,2.h Mon Jul 5 19:52:52 1999 @@ -0,0 +1,274 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ + +/* + * This file contains the controller communication implementation for + * Compaq SMART-1 and SMART-2 controllers. To the best of my knowledge, + * this should support: + * + * PCI: + * SMART-2/P, SMART-2DH, SMART-2SL, SMART-221, SMART-3100ES, SMART-3200 + * Integerated SMART Array Controller, SMART-4200, SMART-4250ES + * + * EISA: + * SMART-2/E, SMART, IAES, IDA-2, IDA + */ + +/* + * Memory mapped FIFO interface (SMART 42xx cards) + */ +static void smart4_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + writel(c->busaddr, h->vaddr + S42XX_REQUEST_PORT_OFFSET); +} + +/* + * This card is the oposite of the other cards. + * 0 turns interrupts on... + * 0x08 turns them off... + */ +static void smart4_intr_mask(ctlr_info_t *h, unsigned long val) +{ + if (val) + { /* Turn interrupts on */ + writel(0, h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); + } else /* Turn them off */ + { + writel( S42XX_INTR_OFF, + h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); + } +} + +/* + * For this card fifo is full if reading this port returns 0! + * + */ +static unsigned long smart4_fifo_full(ctlr_info_t *h) +{ + + return (~readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET)); +} + +/* This type of controller returns -1 if the fifo is empty, + * Not 0 like the others. + * And we need to let it know we read a value out + */ +static unsigned long smart4_completed(ctlr_info_t *h) +{ + long register_value + = readl(h->vaddr + S42XX_REPLY_PORT_OFFSET); + + /* Fifo is empty */ + if( register_value == -1) + return 0; + + /* Need to let it know we got the reply */ + /* We do this by writing a 0 to the port we just read from */ + writel(0, h->vaddr + S42XX_REPLY_PORT_OFFSET); + + return ((unsigned long) register_value); +} + + /* + * This hardware returns interrupt pending at a different place and + * it does not tell us if the fifo is empty, we will have check + * that by getting a 0 back from the comamnd_completed call. + */ +static unsigned long smart4_intr_pending(ctlr_info_t *h) +{ + unsigned long register_value = + readl(h->vaddr + S42XX_INTR_STATUS); + + if( register_value & S42XX_INTR_PENDING) + return FIFO_NOT_EMPTY; + return 0 ; +} + +static struct access_method smart4_access = { + smart4_submit_command, + smart4_intr_mask, + smart4_fifo_full, + smart4_intr_pending, + smart4_completed, +}; + +/* + * Memory mapped FIFO interface (PCI SMART2 and SMART 3xxx cards) + */ +static void smart2_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + writel(c->busaddr, h->vaddr + COMMAND_FIFO); +} + +static void smart2_intr_mask(ctlr_info_t *h, unsigned long val) +{ + writel(val, h->vaddr + INTR_MASK); +} + +static unsigned long smart2_fifo_full(ctlr_info_t *h) +{ + return readl(h->vaddr + COMMAND_FIFO); +} + +static unsigned long smart2_completed(ctlr_info_t *h) +{ + return readl(h->vaddr + COMMAND_COMPLETE_FIFO); +} + +static unsigned long smart2_intr_pending(ctlr_info_t *h) +{ + return readl(h->vaddr + INTR_PENDING); +} + +static struct access_method smart2_access = { + smart2_submit_command, + smart2_intr_mask, + smart2_fifo_full, + smart2_intr_pending, + smart2_completed, +}; + +/* + * IO access for SMART-2/E cards + */ +static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + outl(c->busaddr, h->ioaddr + COMMAND_FIFO); +} + +static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val) +{ + outl(val, h->ioaddr + INTR_MASK); +} + +static unsigned long smart2e_fifo_full(ctlr_info_t *h) +{ + return inl(h->ioaddr + COMMAND_FIFO); +} + +static unsigned long smart2e_completed(ctlr_info_t *h) +{ + return inl(h->ioaddr + COMMAND_COMPLETE_FIFO); +} + +static unsigned long smart2e_intr_pending(ctlr_info_t *h) +{ + return inl(h->ioaddr + INTR_PENDING); +} + +static struct access_method smart2e_access = { + smart2e_submit_command, + smart2e_intr_mask, + smart2e_fifo_full, + smart2e_intr_pending, + smart2e_completed, +}; + +/* + * IO access for older SMART-1 type cards + */ +#define SMART1_SYSTEM_MASK 0xC8E +#define SMART1_SYSTEM_DOORBELL 0xC8F +#define SMART1_LOCAL_MASK 0xC8C +#define SMART1_LOCAL_DOORBELL 0xC8D +#define SMART1_INTR_MASK 0xC89 +#define SMART1_LISTADDR 0xC90 +#define SMART1_LISTLEN 0xC94 +#define SMART1_TAG 0xC97 +#define SMART1_COMPLETE_ADDR 0xC98 +#define SMART1_LISTSTATUS 0xC9E + +#define CHANNEL_BUSY 0x01 +#define CHANNEL_CLEAR 0x02 + +static void smart1_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + /* + * This __u16 is actually a bunch of control flags on SMART + * and below. We want them all to be zero. + */ + c->hdr.size = 0; + + outb(CHANNEL_CLEAR, h->ioaddr + SMART1_SYSTEM_DOORBELL); + + outl(c->busaddr, h->ioaddr + SMART1_LISTADDR); + outw(c->size, h->ioaddr + SMART1_LISTLEN); + + outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL); +} + +static void smart1_intr_mask(ctlr_info_t *h, unsigned long val) +{ + if (val == 1) { + outb(0xFD, h->ioaddr + SMART1_SYSTEM_DOORBELL); + outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL); + outb(0x01, h->ioaddr + SMART1_INTR_MASK); + outb(0x01, h->ioaddr + SMART1_SYSTEM_MASK); + } else { + outb(0, h->ioaddr + 0xC8E); + } +} + +static unsigned long smart1_fifo_full(ctlr_info_t *h) +{ + unsigned char chan; + chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR; + return chan; +} + +static unsigned long smart1_completed(ctlr_info_t *h) +{ + unsigned char status; + unsigned long cmd; + + if (inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) { + outb(CHANNEL_BUSY, h->ioaddr + SMART1_SYSTEM_DOORBELL); + + cmd = inl(h->ioaddr + SMART1_COMPLETE_ADDR); + status = inb(h->ioaddr + SMART1_LISTSTATUS); + + outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL); + + if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status; + } else { + cmd = 0; + } + return cmd; +} + +static unsigned long smart1_intr_pending(ctlr_info_t *h) +{ + unsigned char chan; + chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY; + return chan; +} + +static struct access_method smart1_access = { + smart1_submit_command, + smart1_intr_mask, + smart1_fifo_full, + smart1_intr_pending, + smart1_completed, +}; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v2.3.9/linux/drivers/cdrom/aztcd.c Wed May 12 13:27:37 1999 +++ linux/drivers/cdrom/aztcd.c Tue Jul 6 19:05:48 1999 @@ -1087,7 +1087,7 @@ #ifdef AZT_KERNEL_PRIOR_2_1 void aztcd_setup(char *str, int *ints) #else -__initfunc(void aztcd_setup(char *str, int *ints)) +void __init aztcd_setup(char *str, int *ints) #endif { if (ints[0] > 0) azt_port = ints[1]; @@ -1617,7 +1617,7 @@ #ifdef AZT_KERNEL_PRIOR_2_1 int aztcd_init(void) #else -__initfunc(int aztcd_init(void)) +int __init aztcd_init(void) #endif { long int count, max_count; unsigned char result[50]; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v2.3.9/linux/drivers/cdrom/cdu31a.c Wed May 12 13:27:37 1999 +++ linux/drivers/cdrom/cdu31a.c Tue Jul 6 19:05:48 1999 @@ -3251,10 +3251,10 @@ /* The different types of disc loading mechanisms supported */ static const char *load_mech[] __initdata = { "caddy", "tray", "pop-up", "unknown" }; -__initfunc(static void +static void __init get_drive_configuration(unsigned short base_io, unsigned char res_reg[], - unsigned int *res_size)) + unsigned int *res_size) { int retry_count; @@ -3318,9 +3318,9 @@ /* * Set up base I/O and interrupts, called from main.c. */ -__initfunc(void +void __init cdu31a_setup(char *strings, - int *ints)) + int *ints) { if (ints[0] > 0) { @@ -3349,8 +3349,8 @@ /* * Initialize the driver. */ -__initfunc(int -cdu31a_init(void)) +int __init +cdu31a_init(void) { struct s_sony_drive_config drive_config; unsigned int res_size; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v2.3.9/linux/drivers/cdrom/cm206.c Wed May 12 13:27:37 1999 +++ linux/drivers/cdrom/cm206.c Tue Jul 6 19:05:48 1999 @@ -1294,7 +1294,7 @@ check_region, 15 bits of one port and 6 of another make things likely enough to accept the region on the first hit... */ -__initfunc(int probe_base_port(int base)) +int __init probe_base_port(int base) { int b=0x300, e=0x370; /* this is the range of start addresses */ volatile int fool, i; @@ -1314,7 +1314,7 @@ #if !defined(MODULE) || defined(AUTO_PROBE_MODULE) /* Probe for irq# nr. If nr==0, probe for all possible irq's. */ -__initfunc(int probe_irq(int nr)) { +int __init probe_irq(int nr){ int irqs, irq; outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ sti(); @@ -1328,7 +1328,7 @@ } #endif -__initfunc(int cm206_init(void)) +int __init cm206_init(void) { uch e=0; long int size=sizeof(struct cm206_struct); @@ -1413,7 +1413,7 @@ static int cm206[2] = {0,0}; /* for compatible `insmod' parameter passing */ -__initfunc(void parse_options(void)) +void __init parse_options(void) { int i; for (i=0; i<2; i++) { @@ -1447,7 +1447,7 @@ /* This setup function accepts either `auto' or numbers in the range * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */ -__initfunc(void cm206_setup(char *s, int *p)) +void __init cm206_setup(char *s, int *p) { int i; if (!strcmp(s, "auto")) auto_probe=1; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c --- v2.3.9/linux/drivers/cdrom/gscd.c Sat May 15 15:05:36 1999 +++ linux/drivers/cdrom/gscd.c Tue Jul 6 19:05:48 1999 @@ -194,7 +194,7 @@ } -__initfunc(void gscd_setup (char *str, int *ints)) +void __init gscd_setup (char *str, int *ints) { if (ints[0] > 0) { @@ -851,7 +851,7 @@ return; } -__initfunc(int find_drives (void)) +int __init find_drives (void) { int *pdrv; int drvnum; @@ -902,7 +902,7 @@ return drvnum; } -__initfunc(void init_cd_drive ( int num )) +void __init init_cd_drive ( int num ) { char resp [50]; int i; @@ -994,7 +994,7 @@ /* Test for presence of drive and initialize it. Called only at boot time. */ -__initfunc(int gscd_init (void)) +int __init gscd_init (void) { return my_gscd_init (); } @@ -1002,7 +1002,7 @@ /* This is the common initialisation for the GoldStar drive. */ /* It is called at boot time AND for module init. */ -__initfunc(int my_gscd_init (void)) +int __init my_gscd_init (void) { int i; int result; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/isp16.c linux/drivers/cdrom/isp16.c --- v2.3.9/linux/drivers/cdrom/isp16.c Tue Dec 2 11:41:44 1997 +++ linux/drivers/cdrom/isp16.c Tue Jul 6 19:05:48 1999 @@ -77,8 +77,8 @@ #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) -__initfunc(void -isp16_setup(char *str, int *ints)) +void __init +isp16_setup(char *str, int *ints) { if ( ints[0] > 0 ) isp16_cdrom_base = ints[1]; @@ -94,8 +94,8 @@ * ISP16 initialisation. * */ -__initfunc(int -isp16_init(void)) +int __init +isp16_init(void) { u_char expected_drive; @@ -144,8 +144,8 @@ return(0); } -__initfunc(static short -isp16_detect(void)) +static short __init +isp16_detect(void) { if ( isp16_c929__detect() >= 0 ) @@ -154,8 +154,8 @@ return(isp16_c928__detect()); } -__initfunc(static short -isp16_c928__detect(void)) +static short __init +isp16_c928__detect(void) { u_char ctrl; u_char enable_cdrom; @@ -203,8 +203,8 @@ return(i); } -__initfunc(static short -isp16_c929__detect(void)) +static short __init +isp16_c929__detect(void) { u_char ctrl; u_char tmp; @@ -230,8 +230,8 @@ return(2); } -__initfunc(static short -isp16_cdi_config(int base, u_char drive_type, int irq, int dma)) +static short __init +isp16_cdi_config(int base, u_char drive_type, int irq, int dma) { u_char base_code; u_char irq_code; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.3.9/linux/drivers/cdrom/mcd.c Wed May 12 13:27:37 1999 +++ linux/drivers/cdrom/mcd.c Tue Jul 6 19:05:48 1999 @@ -230,8 +230,7 @@ }; - -__initfunc(void mcd_setup(char *str, int *ints)) +void __init mcd_setup(char *str, int *ints) { if (ints[0] > 0) mcd_port = ints[1]; @@ -1155,7 +1154,7 @@ * Test for presence of drive and initialize it. Called at boot time. */ -__initfunc(int mcd_init(void)) +int __init mcd_init(void) { int count; unsigned char result[3]; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c --- v2.3.9/linux/drivers/cdrom/mcdx.c Wed May 12 13:27:37 1999 +++ linux/drivers/cdrom/mcdx.c Tue Jul 6 19:05:48 1999 @@ -770,7 +770,7 @@ return 1; } -__initfunc(void mcdx_setup(char *str, int *pi)) +void __init mcdx_setup(char *str, int *pi) { if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1]; if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2]; @@ -1013,7 +1013,7 @@ /* Support functions ************************************************/ -__initfunc(int mcdx_init_drive(int drive)) +int __init mcdx_init_drive(int drive) { struct s_version version; struct s_drive_stuff* stuffp; @@ -1174,7 +1174,7 @@ return 0; } -__initfunc(int mcdx_init(void)) +int __init mcdx_init(void) { int drive; #ifdef MODULE diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c --- v2.3.9/linux/drivers/cdrom/optcd.c Wed May 12 13:27:37 1999 +++ linux/drivers/cdrom/optcd.c Tue Jul 6 19:05:48 1999 @@ -1966,7 +1966,7 @@ /* Returns 1 if a drive is detected with a version string starting with "DOLPHIN". Otherwise 0. */ -__initfunc(static int version_ok(void)) +static int __init version_ok(void) { char devname[100]; int count, i, ch, status; @@ -2022,7 +2022,7 @@ /* Get kernel parameter when used as a kernel driver */ -__initfunc(void optcd_setup(char *str, int *ints)) +void __init optcd_setup(char *str, int *ints) { if (ints[0] > 0) optcd_port = ints[1]; @@ -2030,7 +2030,7 @@ /* Test for presence of drive and initialize it. Called at boot time or during module initialisation. */ -__initfunc(int optcd_init(void)) +int __init optcd_init(void) { int status; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.3.9/linux/drivers/cdrom/sbpcd.c Sat May 15 15:05:36 1999 +++ linux/drivers/cdrom/sbpcd.c Tue Jul 6 19:05:48 1999 @@ -3215,7 +3215,7 @@ } #endif FUTURE /*==========================================================================*/ -__initfunc(static void check_datarate(void)) +static void __init check_datarate(void) { int i=0; @@ -3285,7 +3285,7 @@ } #endif /*==========================================================================*/ -__initfunc(static void ask_mail(void)) +static void __init ask_mail(void) { int i; @@ -3304,7 +3304,7 @@ msg(DBG_INF,"infobuf =%s\n", msgbuf); } /*==========================================================================*/ -__initfunc(static int check_version(void)) +static int __init check_version(void) { int i, j, l; int teac_possible=0; @@ -3602,7 +3602,7 @@ /* * probe for the presence of an interface card */ -__initfunc(static int check_card(int port)) +static int __init check_card(int port) { #undef N_RESPO #define N_RESPO 20 @@ -3706,7 +3706,7 @@ /* * probe for the presence of drives on the selected controller */ -__initfunc(static int check_drives(void)) +static int __init check_drives(void) { int i, j; @@ -5458,9 +5458,9 @@ * */ #if (SBPCD_ISSUE-1) -__initfunc(static void sbpcd_setup(const char *s, int *p)) +static void __init sbpcd_setup(const char *s, int *p) #else -__initfunc(void sbpcd_setup(const char *s, int *p)) +void __init sbpcd_setup(const char *s, int *p) #endif { setup_done++; @@ -5512,7 +5512,7 @@ * port 0x330, we have to use an offset of 8; so, the real CDROM port * address is 0x338. */ -__initfunc(static int config_spea(void)) +static int __init config_spea(void) { /* * base address offset between configuration port and CDROM port, @@ -5571,7 +5571,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int SBPCD_INIT(void)) +int __init SBPCD_INIT(void) #endif MODULE { int i=0, j=0; diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c --- v2.3.9/linux/drivers/cdrom/sjcd.c Wed May 12 13:27:37 1999 +++ linux/drivers/cdrom/sjcd.c Tue Jul 6 19:05:48 1999 @@ -163,7 +163,7 @@ * Set up device, i.e., use command line data to set * base address. */ -__initfunc(void sjcd_setup( char *str, int *ints )) +void __init sjcd_setup( char *str, int *ints ) { if (ints[0] > 0) sjcd_base = ints[1]; @@ -1457,7 +1457,7 @@ * Test for presence of drive and initialize it. Called at boot time. * Probe cdrom, find out version and status. */ -__initfunc(int sjcd_init( void )){ +int __init sjcd_init( void ){ int i; printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR, diff -u --recursive --new-file v2.3.9/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v2.3.9/linux/drivers/cdrom/sonycd535.c Wed May 26 09:31:44 1999 +++ linux/drivers/cdrom/sonycd535.c Tue Jul 6 19:05:48 1999 @@ -1486,8 +1486,8 @@ /* * Initialize the driver. */ -__initfunc(int -sony535_init(void)) +int __init +sony535_init(void) { struct s535_sony_drive_config drive_config; Byte cmd_buff[3]; @@ -1655,8 +1655,8 @@ * * the address value has to be the existing CDROM port address. */ -__initfunc(void -sonycd535_setup(char *strings, int *ints)) +void __init +sonycd535_setup(char *strings, int *ints) { /* if IRQ change and default io base desired, * then call with io base of 0 diff -u --recursive --new-file v2.3.9/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.9/linux/drivers/char/Config.in Wed Jun 30 13:38:19 1999 +++ linux/drivers/char/Config.in Tue Jul 6 19:16:55 1999 @@ -28,6 +28,9 @@ tristate 'Digiboard PC/Xx Support' CONFIG_DIGI fi tristate 'Cyclades async mux support' CONFIG_CYCLADES + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then + bool ' Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR + fi bool 'Stallion multiport serial support' CONFIG_STALDRV if [ "$CONFIG_STALDRV" = "y" ]; then tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION @@ -52,8 +55,9 @@ if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT if [ "$CONFIG_PRINTER" != "n" ]; then - bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK + bool ' Support for console on line printer' CONFIG_LP_CONSOLE fi + dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT fi bool 'Mouse Support (not serial mice)' CONFIG_MOUSE @@ -79,6 +83,9 @@ comment ' from the tpqic02-support package. It is available at' comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/' fi + dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV + dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN + dep_tristate ' Include support for LML33' CONFIG_VIDEO_LML33 $CONFIG_VIDEO_ZORAN fi bool 'Watchdog Timer Support' CONFIG_WATCHDOG @@ -111,6 +118,7 @@ tristate 'Video For Linux' CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV dep_tristate 'AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f @@ -123,11 +131,14 @@ if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 fi - dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV - dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c + fi + dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV + dep_tristate 'TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV + if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then + hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590 fi if [ "$CONFIG_PCI" != "n" ]; then dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV diff -u --recursive --new-file v2.3.9/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.9/linux/drivers/char/Makefile Sat May 22 15:02:48 1999 +++ linux/drivers/char/Makefile Tue Jul 6 19:16:55 1999 @@ -356,6 +356,30 @@ endif endif +ifeq ($(CONFIG_VIDEO_ZORAN),y) +L_OBJS += buz.o +else + ifeq ($(CONFIG_VIDEO_LML33),m) + M_OBJS += buz.o + endif +endif + +ifeq ($(CONFIG_VIDEO_LML33),y) +L_OBJS += bt856.o bt819.o +else + ifeq ($(CONFIG_VIDEO_LML33),m) + M_OBJS += bt856.o bt819.o + endif +endif + +ifeq ($(CONFIG_VIDEO_BUZ),y) +L_OBJS += saa7111.o saa7185.o +else + ifeq ($(CONFIG_VIDEO_BUZ),m) + M_OBJS += saa7111.o saa7185.o + endif +endif + ifeq ($(CONFIG_VIDEO_PMS),y) L_OBJS += pms.o else @@ -372,6 +396,14 @@ endif endif +ifeq ($(CONFIG_VIDEO_VINO),y) +L_OBJS += vino.o +else + ifeq ($(CONFIG_VIDEO_VINO),m) + M_OBJS += vino.o + endif +endif + ifeq ($(CONFIG_RADIO_AZTECH),y) L_OBJS += radio-aztech.o else @@ -444,6 +476,14 @@ endif endif +ifeq ($(CONFIG_RADIO_TERRATEC),y) +L_OBJS += radio-terratec.o +else + ifeq ($(CONFIG_RADIO_TERRATEC),m) + M_OBJS += radio-terratec.o + endif +endif + ifeq ($(CONFIG_QIC02_TAPE),y) L_OBJS += tpqic02.o else @@ -466,6 +506,14 @@ ifdef CONFIG_H8 LX_OBJS += h8.o +endif + +ifeq ($(CONFIG_PPDEV),y) +L_OBJS += ppdev.o +else + ifeq ($(CONFIG_PPDEV),m) + M_OBJS += ppdev.o + endif endif ifeq ($(L_I2C),y) diff -u --recursive --new-file v2.3.9/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.3.9/linux/drivers/char/acquirewdt.c Wed Jun 2 11:29:13 1999 +++ linux/drivers/char/acquirewdt.c Tue Jul 6 19:16:55 1999 @@ -212,7 +212,7 @@ #endif -__initfunc(int acq_init(void)) +int __init acq_init(void) { printk("WDT driver for Acquire single board computer initialising.\n"); diff -u --recursive --new-file v2.3.9/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c --- v2.3.9/linux/drivers/char/adbmouse.c Mon Jun 7 12:12:22 1999 +++ linux/drivers/char/adbmouse.c Tue Jul 6 19:16:55 1999 @@ -38,9 +38,7 @@ #ifdef __powerpc__ #include #endif -#ifdef __mc68000__ #include -#endif static struct mouse_status mouse; static unsigned char adb_mouse_buttons[16]; @@ -244,7 +242,7 @@ ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops }; -__initfunc(int adb_mouse_init(void)) +int __init adb_mouse_init(void) { mouse.active = 0; mouse.ready = 0; @@ -270,7 +268,7 @@ * option, which is about using ADB keyboard buttons to emulate * mouse buttons. -- paulus */ -__initfunc(void adb_mouse_setup(char *str, int *ints)) +void __init adb_mouse_setup(char *str, int *ints) { if (ints[0] >= 1) { adb_emulate_buttons = ints[1] > 0; @@ -282,7 +280,6 @@ } #ifdef MODULE -#include int init_module(void) { diff -u --recursive --new-file v2.3.9/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c --- v2.3.9/linux/drivers/char/amigamouse.c Mon Aug 24 13:02:43 1998 +++ linux/drivers/char/amigamouse.c Tue Jul 6 19:16:55 1999 @@ -309,7 +309,7 @@ AMIGAMOUSE_MINOR, "amigamouse", &amiga_mouse_fops }; -__initfunc(int amiga_mouse_init(void)) +int __init amiga_mouse_init(void) { if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) return -ENODEV; @@ -333,7 +333,6 @@ } #ifdef MODULE -#include int init_module(void) { diff -u --recursive --new-file v2.3.9/linux/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c --- v2.3.9/linux/drivers/char/amikeyb.c Mon Apr 26 13:25:54 1999 +++ linux/drivers/char/amikeyb.c Tue Jul 6 19:16:55 1999 @@ -295,7 +295,7 @@ } } -__initfunc(int amiga_keyb_init(void)) +int __init amiga_keyb_init(void) { if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) return -EIO; @@ -343,6 +343,6 @@ } /* for "kbd-reset" cmdline param */ -__initfunc(void amiga_kbd_reset_setup(char *str, int *ints)) +void __init amiga_kbd_reset_setup(char *str, int *ints) { } diff -u --recursive --new-file v2.3.9/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c --- v2.3.9/linux/drivers/char/atarimouse.c Mon Aug 24 13:02:43 1998 +++ linux/drivers/char/atarimouse.c Tue Jul 6 19:16:55 1999 @@ -159,7 +159,7 @@ ATARIMOUSE_MINOR, "atarimouse", &atari_mouse_fops }; -__initfunc(int atari_mouse_init(void)) +int __init atari_mouse_init(void) { int r; @@ -182,7 +182,7 @@ #define MIN_THRESHOLD 1 #define MAX_THRESHOLD 20 /* more seems not reasonable... */ -__initfunc(void atari_mouse_setup( char *str, int *ints )) +void __init atari_mouse_setup( char *str, int *ints ) { if (ints[0] < 1) { printk( "atari_mouse_setup: no arguments!\n" ); diff -u --recursive --new-file v2.3.9/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c --- v2.3.9/linux/drivers/char/atixlmouse.c Wed May 12 13:27:37 1999 +++ linux/drivers/char/atixlmouse.c Tue Jul 6 19:16:55 1999 @@ -202,7 +202,7 @@ }; -__initfunc(int atixl_busmouse_init(void)) +int __init atixl_busmouse_init(void) { unsigned char a,b,c; diff -u --recursive --new-file v2.3.9/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.9/linux/drivers/char/bttv.c Mon Jun 7 16:17:59 1999 +++ linux/drivers/char/bttv.c Mon Jul 5 20:35:18 1999 @@ -43,7 +43,6 @@ #include #include #include -#include #if LINUX_VERSION_CODE >= 0x020100 #include @@ -81,8 +80,8 @@ #include "bttv.h" #include "tuner.h" -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ #if LINUX_VERSION_CODE >= 0x020117 MODULE_PARM(vidmem,"i"); @@ -110,7 +109,7 @@ #define CARD_DEFAULT 0 #endif -static unsigned int remap[BTTV_MAX]; /* remap Bt848 */ +static unsigned long remap[BTTV_MAX]; /* remap Bt848 */ static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT, CARD_DEFAULT, CARD_DEFAULT }; @@ -129,51 +128,80 @@ #define EEPROM_WRITE_DELAY 20000 #define BURSTOFFSET 76 - - /*******************************/ /* Memory management functions */ /*******************************/ -/* convert virtual user memory address to physical address */ -/* (virt_to_phys only works for kmalloced kernel memory) */ +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ -static inline unsigned long uvirt_to_phys(unsigned long adr) +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) { - pgd_t *pgd; + unsigned long ret = 0UL; pmd_t *pmd; pte_t *ptep, pte; - pgd = pgd_offset(current->mm, adr); - if (pgd_none(*pgd)) - return 0; - pmd = pmd_offset(pgd, adr); - if (pmd_none(*pmd)) - return 0; - ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); - pte = *ptep; - if(pte_present(pte)) - return - virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); - return 0; + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = (pte_page(pte)|(adr&(PAGE_SIZE-1))); + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; } static inline unsigned long uvirt_to_bus(unsigned long adr) { - return virt_to_bus(phys_to_virt(uvirt_to_phys(adr))); -} + unsigned long kva, ret; -/* convert virtual kernel memory address to physical address */ -/* (virt_to_phys only works for kmalloced kernel memory) */ + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} -static inline unsigned long kvirt_to_phys(unsigned long adr) +static inline unsigned long kvirt_to_bus(unsigned long adr) { - return uvirt_to_phys(VMALLOC_VMADDR(adr)); + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; } -static inline unsigned long kvirt_to_bus(unsigned long adr) +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) { - return uvirt_to_bus(VMALLOC_VMADDR(adr)); + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; } static void * rvmalloc(unsigned long size) @@ -188,8 +216,8 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_phys(adr); - mem_map_reserve(MAP_NR(phys_to_virt(page))); + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -206,8 +234,8 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_phys(adr); - mem_map_unreserve(MAP_NR(phys_to_virt(page))); + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -541,13 +569,13 @@ /* Aimslab VHX */ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, /* Zoltrix TV-Max */ - { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, + { 3, 1, 0, 2, 0x00000f, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0x8}}, /* Pixelview PlayTV (bt878) */ { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }}, /* "Leadtek WinView 601", */ { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}}, /* AVEC Intercapture */ - { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, + { 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}}, }; #define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) @@ -823,30 +851,30 @@ unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; - DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd)); - DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even)); - DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); - DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); + DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd)); + DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even)); + DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po)); + DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); - *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0; + *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; for (i=0; i<16; i++) { - *(po++)=VBI_RISC; - *(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); + *(po++)=cpu_to_le32(VBI_RISC); + *(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); } - *(po++)=BT848_RISC_JUMP; - *(po++)=virt_to_bus(btv->risc_jmp+4); + *(po++)=cpu_to_le32(BT848_RISC_JUMP); + *(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); - *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0; + *(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0; for (i=16; i<32; i++) { - *(pe++)=VBI_RISC; - *(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); + *(pe++)=cpu_to_le32(VBI_RISC); + *(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); } - *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16); - *(pe++)=virt_to_bus(btv->risc_jmp+10); - DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); - DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); + *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); + *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po)); + DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); } int fmtbppx2[16] = { @@ -881,8 +909,8 @@ unsigned long bpl=1024; /* bytes per line */ unsigned long vadr=(unsigned long) vbuf; - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY is 2 and without separate VBI grabbing. @@ -890,17 +918,17 @@ for (line=0; line < 640; line++) { - *(ro++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL; - *(ro++)=kvirt_to_bus(vadr); - *(re++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL; - *(re++)=kvirt_to_bus(vadr+BTTV_MAX_FBUF/2); + *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); + *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2)); vadr+=bpl; } - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); return 0; } @@ -954,8 +982,8 @@ cradr=cbadr+csize; inter = (height>btv->win.cropheight/2) ? 1 : 0; - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { @@ -991,15 +1019,15 @@ todo-=bl; if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */ - *((*rp)++)=rcmd|bl; - *((*rp)++)=blcb|(blcr<<16); - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(rcmd|bl); + *((*rp)++)=cpu_to_le32(blcb|(blcr<<16)); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bl; if((rcmd&(15<<28))==BT848_RISC_WRITE123) { - *((*rp)++)=kvirt_to_bus(cbadr); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr)); cbadr+=blcb; - *((*rp)++)=kvirt_to_bus(cradr); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); cradr+=blcr; } @@ -1007,10 +1035,10 @@ } } - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); return 0; } @@ -1037,8 +1065,8 @@ inter = (height>btv->win.cropheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { @@ -1050,35 +1078,35 @@ bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); if (bpl<=bl) { - *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bpl; } else { todo=bpl; - *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bl; todo-=bl; while (todo>PAGE_SIZE) { - *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=PAGE_SIZE; todo-=PAGE_SIZE; } - *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo; - *((*rp)++)=kvirt_to_bus(vadr); + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=todo; } } - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); return 0; } @@ -1162,10 +1190,10 @@ adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ - *(ro++)=BT848_RISC_JUMP; - *(ro++)=btv->bus_vbi_even; - *(re++)=BT848_RISC_JUMP; - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); } if (ncr < 0) { /* bitmap was pased */ memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); @@ -1187,8 +1215,8 @@ if (btv->win.y<0) clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); - *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; - *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; /* translate bitmap to risc code */ for (line=outofmem=0; line < (height<bus_vbi_even; - *(re++)=BT848_RISC_JUMP; - *(re++)=btv->bus_vbi_odd; + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); } /* set geometry for even/odd frames @@ -1297,6 +1325,23 @@ set_pll(btv); btwrite(fmt, BT848_COLOR_FMT); +#ifdef __sparc__ + if(fmt == BT848_COLOR_FMT_RGB32 || + fmt == BT848_COLOR_FMT_RGB24) { + btwrite((BT848_COLOR_CTL_GAMMA | + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } else if(fmt == BT848_COLOR_FMT_RGB16 || + fmt == BT848_COLOR_FMT_RGB15) { + btwrite((BT848_COLOR_CTL_GAMMA | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } +#endif hactive=width; vtc=0; @@ -1474,7 +1519,7 @@ btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI); } - btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ; + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); @@ -2268,7 +2313,7 @@ pos=(unsigned long) btv->fbuffer; while (size > 0) { - page = kvirt_to_phys(pos); + page = kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start+=PAGE_SIZE; @@ -3110,44 +3155,44 @@ int flags=btv->cap; /* Sync to start of odd field */ - btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE; + btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE); btv->risc_jmp[1]=0; /* Jump to odd vbi sub */ - btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20); + btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0x5<<20)); if (flags&8) - btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); else - btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); /* Jump to odd sub */ - btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20); + btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0x6<<20)); if (flags&2) - btv->risc_jmp[5]=virt_to_bus(btv->risc_odd); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd)); else - btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); /* Sync to start of even field */ - btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO; + btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO); btv->risc_jmp[7]=0; /* Jump to even vbi sub */ - btv->risc_jmp[8]=BT848_RISC_JUMP; + btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); if (flags&4) - btv->risc_jmp[9]=virt_to_bus(btv->vbi_even); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); else - btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); /* Jump to even sub */ - btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20); + btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); if (flags&1) - btv->risc_jmp[11]=virt_to_bus(btv->risc_even); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even)); else - btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); - btv->risc_jmp[12]=BT848_RISC_JUMP; - btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp); + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); + btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable capturing */ btaor(flags, ~0x0f, BT848_CAP_CTL); @@ -3165,7 +3210,7 @@ /* reset the bt848 */ btwrite(0, BT848_SRESET); - DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem)); + DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem)); /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ @@ -3330,8 +3375,7 @@ if (!astat) return; btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat)); - IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat)); + IDEBUG(printk ("bttv%d: astat %08x stat %08x\n", btv->nr, astat, stat)); /* get device status bits */ dstat=btread(BT848_DSTATUS); @@ -3387,8 +3431,8 @@ btv->gro = btv->gro_next; btv->gre = btv->gre_next; btv->grf = btv->grf_next; - btv->risc_jmp[5]=btv->gro; - btv->risc_jmp[11]=btv->gre; + btv->risc_jmp[5]=cpu_to_le32(btv->gro); + btv->risc_jmp[11]=cpu_to_le32(btv->gre); bt848_set_geo(btv, btv->gwidth, btv->gheight, btv->gfmt); @@ -3405,9 +3449,9 @@ } if (stat&(8<<28)) { - btv->risc_jmp[5]=btv->gro; - btv->risc_jmp[11]=btv->gre; - btv->risc_jmp[12]=BT848_RISC_JUMP; + btv->risc_jmp[5]=cpu_to_le32(btv->gro); + btv->risc_jmp[11]=cpu_to_le32(btv->gre); + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); bt848_set_geo(btv, btv->gwidth, btv->gheight, btv->gfmt); } @@ -3502,14 +3546,16 @@ if (remap[bttv_num]) { + unsigned int dw = btv->bt848_adr; + if (remap[bttv_num] < 0x1000) remap[bttv_num]<<=20; remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK; - printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n", + printk(KERN_INFO "bttv%d: remapping to : 0x%lx.\n", bttv_num,remap[bttv_num]); remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK); pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dw); btv->dev->base_address[0] = btv->bt848_adr; } btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; @@ -3518,7 +3564,7 @@ bttv_num,btv->id, btv->revision); printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn); printk("irq: %d, ",btv->irq); - printk("memory: 0x%08x.\n", btv->bt848_adr); + printk("memory: 0x%lx.\n", btv->bt848_adr); btv->pll.pll_crystal = 0; btv->pll.pll_ifreq = 0; @@ -3542,7 +3588,11 @@ } } +#ifdef __sparc__ + btv->bt848_mem=(unsigned char *)btv->bt848_adr; +#else btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); +#endif /* clear interrupt mask */ btwrite(0, BT848_INT_MASK); @@ -3817,17 +3867,17 @@ if (btv->risc_even) kfree((void *) btv->risc_even); - DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%08x.\n", btv->risc_jmp)); + DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); if (btv->risc_jmp) kfree((void *) btv->risc_jmp); - DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf)); + DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf)); if (btv->vbibuf) vfree((void *) btv->vbibuf); free_irq(btv->irq,btv); - DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem)); + DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem)); if (btv->bt848_mem) iounmap(btv->bt848_mem); diff -u --recursive --new-file v2.3.9/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.3.9/linux/drivers/char/bttv.h Mon Jun 7 16:17:59 1999 +++ linux/drivers/char/bttv.h Mon Jul 5 20:07:02 1999 @@ -102,9 +102,9 @@ #else struct pci_dev *dev; #endif - unsigned char irq; /* IRQ used by Bt848 card */ + unsigned int irq; /* IRQ used by Bt848 card */ unsigned char revision; - unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char *bt848_mem; /* pointer to mapped IO memory */ unsigned long busriscmem; u32 *riscmem; @@ -274,7 +274,7 @@ #define TEA6320_S 0x07 /* switch register */ /* values for those registers: */ #define TEA6320_S_SA 0x01 /* stereo A input */ -#define TEA6320_S_SB 0x02 /* stereo B */ +#define TEA6320_S_SB 0x07 /* stereo B -- databook wrong? this works */ #define TEA6320_S_SC 0x04 /* stereo C */ #define TEA6320_S_GMU 0x80 /* general mute */ diff -u --recursive --new-file v2.3.9/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.3.9/linux/drivers/char/busmouse.c Wed May 12 13:27:37 1999 +++ linux/drivers/char/busmouse.c Tue Jul 6 19:16:55 1999 @@ -60,7 +60,7 @@ MODULE_PARM(mouse_irq, "i"); #endif -__initfunc(void bmouse_setup(char *str, int *ints)) +void __init bmouse_setup(char *str, int *ints) { if (ints[0] > 0) mouse_irq=ints[1]; @@ -252,7 +252,7 @@ LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops }; -__initfunc(int bus_mouse_init(void)) +int __init bus_mouse_init(void) { if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) { mouse.present = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/char/buz.c linux/drivers/char/buz.c --- v2.3.9/linux/drivers/char/buz.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/buz.c Tue Jul 6 10:11:40 1999 @@ -0,0 +1,3478 @@ +#define MAX_KMALLOC_MEM (512*1024) +/* + buz - Iomega Buz driver version 1.0 + + Copyright (C) 1999 Rainer Johanni + + based on + + buz.0.0.3 Copyright (C) 1998 Dave Perks + + and + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include "buz.h" +#include +#include + +#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) +#define GPIO_MASK 0xdf + +/* + + BUZ + + GPIO0 = 1, take board out of reset + GPIO1 = 1, take JPEG codec out of sleep mode + GPIO3 = 1, deassert FRAME# to 36060 + + + GIRQ0 signals a vertical sync of the video signal + GIRQ1 signals that ZR36060's DATERR# line is asserted. + + SAA7111A + + In their infinite wisdom, the Iomega engineers decided to + use the same input line for composite and S-Video Color, + although there are two entries not connected at all! + Through this ingenious strike, it is not possible to + keep two running video sources connected at the same time + to Composite and S-VHS input! + + mode 0 - N/C + mode 1 - S-Video Y + mode 2 - noise or something I don't know + mode 3 - Composite and S-Video C + mode 4 - N/C + mode 5 - S-Video (gain C independently selectable of gain Y) + mode 6 - N/C + mode 7 - S-Video (gain C adapted to gain Y) + */ + +#define MAJOR_VERSION 1 /* driver major version */ +#define MINOR_VERSION 0 /* driver minor version */ + +#define BUZ_NAME "Iomega BUZ V-1.0" /* name of the driver */ + +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ +#define IOCTL_DEBUG(x) + + +/* The parameters for this driver */ + +/* + The video mem address of the video card. + The driver has a little database for some videocards + to determine it from there. If your video card is not in there + you have either to give it to the driver as a parameter + or set in in a VIDIOCSFBUF ioctl + */ + +static unsigned long vidmem = 0; /* Video memory base address */ + +/* Special purposes only: */ + +static int triton = 0; /* 0=no, 1=yes */ +static int natoma = 0; /* 0=no, 1=yes */ + +/* + Number and size of grab buffers for Video 4 Linux + The vast majority of applications should not need more than 2, + the very popular BTTV driver actually does ONLY have 2. + Time sensitive applications might need more, the maximum + is VIDEO_MAX_FRAME (defined in ). + + The size is set so that the maximum possible request + can be satisfied. Decrease it, if bigphys_area alloc'd + memory is low. If you don't have the bigphys_area patch, + set it to 128 KB. Will you allow only to grab small + images with V4L, but that's better than nothing. + + v4l_bufsize has to be given in KB ! + + */ + +static int v4l_nbufs = 2; +static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ + +/* + Default input and video norm at startup of the driver. + */ + +static int default_input = 0; /* 0=Composite, 1=S-VHS */ +static int default_norm = 0; /* 0=PAL, 1=NTSC */ + +MODULE_PARM(vidmem, "i"); +MODULE_PARM(triton, "i"); +MODULE_PARM(natoma, "i"); +MODULE_PARM(v4l_nbufs, "i"); +MODULE_PARM(v4l_bufsize, "i"); +MODULE_PARM(default_input, "i"); +MODULE_PARM(default_norm, "i"); + +/* Anybody who uses more than four? */ +#define BUZ_MAX 4 + +static int zoran_num; /* number of Buzs in use */ +static struct zoran zoran[BUZ_MAX]; + +/* forward references */ + +static void v4l_fbuffer_free(struct zoran *zr); +static void jpg_fbuffer_free(struct zoran *zr); +static void zoran_feed_stat_com(struct zoran *zr); + + + +/* + * Allocate the V4L grab buffers + * + * These have to be pysically contiguous. + * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc + */ + +static int v4l_fbuffer_alloc(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (zr->v4l_gbuf[i].fbuffer) + printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i); + + if (v4l_bufsize <= MAX_KMALLOC_MEM) { + /* Use kmalloc */ + + mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name); + v4l_fbuffer_free(zr); + return -ENOBUFS; + } + zr->v4l_gbuf[i].fbuffer = mem; + zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); + zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem))); + } else { + return -ENOBUFS; + } + } + + return 0; +} + +/* free the V4L grab buffers */ +static void v4l_fbuffer_free(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (!zr->v4l_gbuf[i].fbuffer) + continue; + + mem = zr->v4l_gbuf[i].fbuffer; + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_unreserve(MAP_NR(mem + off)); + kfree((void *) zr->v4l_gbuf[i].fbuffer); + zr->v4l_gbuf[i].fbuffer = NULL; + } +} + +/* + * Allocate the MJPEG grab buffers. + * + * If the requested buffer size is smaller than MAX_KMALLOC_MEM, + * kmalloc is used to request a physically contiguous area, + * else we allocate the memory in framgents with get_free_page. + * + * If a Natoma chipset is present and this is a revision 1 zr36057, + * each MJPEG buffer needs to be physically contiguous. + * (RJ: This statement is from Dave Perks' original driver, + * I could never check it because I have a zr36067) + * The driver cares about this because it reduces the buffer + * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). + * + * RJ: The contents grab buffers needs never be accessed in the driver. + * Therefore there is no need to allocate them with vmalloc in order + * to get a contiguous virtual memory space. + * I don't understand why many other drivers first allocate them with + * vmalloc (which uses internally also get_free_page, but delivers you + * virtual addresses) and then again have to make a lot of efforts + * to get the physical address. + * + */ + +static int jpg_fbuffer_alloc(struct zoran *zr) +{ + int i, j, off, alloc_contig; + unsigned long mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (zr->jpg_gbuf[i].frag_tab) + printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i); + + /* Allocate fragment table for this buffer */ + + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + memset((void *) mem, 0, PAGE_SIZE); + zr->jpg_gbuf[i].frag_tab = (u32 *) mem; + zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); + + if (alloc_contig) { + mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); + if (mem == 0) { + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1; + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + } else { + /* jpg_bufsize is alreay page aligned */ + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1; + mem_map_reserve(MAP_NR(mem)); + } + + zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; + } + } + + DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n", + (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); + zr->jpg_buffers_allocated = 1; + return 0; +} + +/* free the MJPEG grab buffers */ +static void jpg_fbuffer_free(struct zoran *zr) +{ + int i, j, off, alloc_contig; + unsigned char *mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (!zr->jpg_gbuf[i].frag_tab) + continue; + + if (alloc_contig) { + if (zr->jpg_gbuf[i].frag_tab[0]) { + mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]); + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_unreserve(MAP_NR(mem + off)); + kfree((void *) mem); + zr->jpg_gbuf[i].frag_tab[0] = 0; + zr->jpg_gbuf[i].frag_tab[1] = 0; + } + } else { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + if (!zr->jpg_gbuf[i].frag_tab[2 * j]) + break; + mem_map_unreserve(MAP_NR(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]))); + free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])); + zr->jpg_gbuf[i].frag_tab[2 * j] = 0; + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; + } + } + + free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); + zr->jpg_gbuf[i].frag_tab = NULL; + } + zr->jpg_buffers_allocated = 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* I2C functions */ + +#define I2C_DELAY 10 + + +/* software I2C functions */ + +static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) +{ + struct zoran *zr = (struct zoran *) bus->data; + btwrite((data << 1) | ctrl, ZR36057_I2CBR); + btread(ZR36057_I2CBR); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *zr = (struct zoran *) bus->data; + return (btread(ZR36057_I2CBR) >> 1) & 1; +} + +void attach_inform(struct i2c_bus *bus, int id) +{ + DEBUG(struct zoran *zr = (struct zoran *) bus->data); + DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id)); +} + +void detach_inform(struct i2c_bus *bus, int id) +{ + DEBUG(struct zoran *zr = (struct zoran *) bus->data); + DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id)); +} + +static struct i2c_bus zoran_i2c_bus_template = +{ + "zr36057", + I2C_BUSID_BT848, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL, +}; + + +/* ----------------------------------------------------------------------- */ + +static void GPIO(struct zoran *zr, unsigned bit, unsigned value) +{ + u32 reg; + u32 mask; + + mask = 1 << (24 + bit); + reg = btread(ZR36057_GPPGCR1) & ~mask; + if (value) { + reg |= mask; + } + btwrite(reg, ZR36057_GPPGCR1); + /* Stop any PCI posting on the GPIO bus */ + btread(ZR36057_I2CBR); +} + + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the ZR36057 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.zoran.com - nicely done those folks. + */ + +struct tvnorm { + u16 Wt, Wa, Ht, Ha, HStart, VStart; +}; + +static struct tvnorm tvnorms[] = +{ + /* PAL-BDGHI */ + {864, 720, 625, 576, 31, 16}, + /* NTSC */ + {858, 720, 525, 480, 21, 8}, +}; +#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm)) + +static int format2bpp(int format) +{ + int bpp; + + /* Determine the number of bytes per pixel for the video format requested */ + + switch (format) { + + case VIDEO_PALETTE_YUV422: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB555: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB565: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB24: + bpp = 3; + break; + + case VIDEO_PALETTE_RGB32: + bpp = 4; + break; + + default: + bpp = 0; + } + + return bpp; +} + +/* + * set geometry + */ +static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, + unsigned int video_format) +{ + struct tvnorm *tvn; + unsigned HStart, HEnd, VStart, VEnd; + unsigned DispMode; + unsigned VidWinWid, VidWinHt; + unsigned hcrop1, hcrop2, vcrop1, vcrop2; + unsigned Wa, We, Ha, He; + unsigned X, Y, HorDcm, VerDcm; + u32 reg; + unsigned mask_line_size; + + if (zr->params.norm < 0 || zr->params.norm > 1) { + printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name, zr->params.norm); + return; + } + if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) { + printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height); + return; + } + tvn = &tvnorms[zr->params.norm]; + + Wa = tvn->Wa; + Ha = tvn->Ha; + + /* if window has more than half of active height, + switch on interlacing - we want the full information */ + + zr->video_interlace = (video_height > Ha / 2); + +/**** zr36057 ****/ + + /* horizontal */ + VidWinWid = video_width; + X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; + We = (VidWinWid * 64) / X; + HorDcm = 64 - X; + hcrop1 = 2 * ((tvn->Wa - We) / 4); + hcrop2 = tvn->Wa - We - hcrop1; + HStart = tvn->HStart | 1; + HEnd = HStart + tvn->Wa - 1; + HStart += hcrop1; + HEnd -= hcrop2; + reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) + | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); + reg |= ZR36057_VFEHCR_HSPol; + btwrite(reg, ZR36057_VFEHCR); + + /* Vertical */ + DispMode = !zr->video_interlace; + VidWinHt = DispMode ? video_height : video_height / 2; + Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; + He = (VidWinHt * 64) / Y; + VerDcm = 64 - Y; + vcrop1 = (tvn->Ha / 2 - He) / 2; + vcrop2 = tvn->Ha / 2 - He - vcrop1; + VStart = tvn->VStart; + VEnd = VStart + tvn->Ha / 2 - 1; + VStart += vcrop1; + VEnd -= vcrop2; + reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) + | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); + reg |= ZR36057_VFEVCR_VSPol; + btwrite(reg, ZR36057_VFEVCR); + + /* scaler and pixel format */ + reg = 0 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */ + | (HorDcm << ZR36057_VFESPFR_HorDcm) + | (VerDcm << ZR36057_VFESPFR_VerDcm) + | (DispMode << ZR36057_VFESPFR_DispMode) + | ZR36057_VFESPFR_LittleEndian; + /* RJ: I don't know, why the following has to be the opposite + of the corresponding ZR36060 setting, but only this way + we get the correct colors when uncompressing to the screen */ + reg |= ZR36057_VFESPFR_VCLKPol; + /* RJ: Don't know if that is needed for NTSC also */ + reg |= ZR36057_VFESPFR_TopField; + switch (video_format) { + + case VIDEO_PALETTE_YUV422: + reg |= ZR36057_VFESPFR_YUV422; + break; + + case VIDEO_PALETTE_RGB555: + reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB565: + reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB24: + reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; + break; + + case VIDEO_PALETTE_RGB32: + reg |= ZR36057_VFESPFR_RGB888; + break; + + default: + printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format); + return; + + } + if (HorDcm >= 48) { + reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ + } else if (HorDcm >= 32) { + reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ + } else if (HorDcm >= 16) { + reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ + } + btwrite(reg, ZR36057_VFESPFR); + + /* display configuration */ + + reg = (16 << ZR36057_VDCR_MinPix) + | (VidWinHt << ZR36057_VDCR_VidWinHt) + | (VidWinWid << ZR36057_VDCR_VidWinWid); + if (triton) + reg &= ~ZR36057_VDCR_Triton; + else + reg |= ZR36057_VDCR_Triton; + btwrite(reg, ZR36057_VDCR); + + /* Write overlay clipping mask data, but don't enable overlay clipping */ + /* RJ: since this makes only sense on the screen, we use + zr->window.width instead of video_width */ + + mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + reg = virt_to_bus(zr->overlay_mask); + btwrite(reg, ZR36057_MMTR); + reg = virt_to_bus(zr->overlay_mask + mask_line_size); + btwrite(reg, ZR36057_MMBR); + reg = mask_line_size - (zr->window.width + 31) / 32; + if (DispMode == 0) + reg += mask_line_size; + reg <<= ZR36057_OCR_MaskStride; + btwrite(reg, ZR36057_OCR); + +} + +/* + * Switch overlay on or off + */ + +static void zr36057_overlay(struct zoran *zr, int on) +{ + int fmt, bpp; + u32 reg; + + if (on) { + /* do the necessary settings ... */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ + + switch (zr->buffer.depth) { + case 15: + fmt = VIDEO_PALETTE_RGB555; + bpp = 2; + break; + case 16: + fmt = VIDEO_PALETTE_RGB565; + bpp = 2; + break; + case 24: + fmt = VIDEO_PALETTE_RGB24; + bpp = 3; + break; + case 32: + fmt = VIDEO_PALETTE_RGB32; + bpp = 4; + break; + default: + fmt = 0; + bpp = 0; + } + + zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt); + + /* Start and length of each line MUST be 4-byte aligned. + This should be allready checked before the call to this routine. + All error messages are internal driver checking only! */ + + /* video display top and bottom registers */ + + reg = (u32) zr->buffer.base + + zr->window.x * bpp + + zr->window.y * zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDTR); + if (reg & 3) + printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name); + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + + reg = zr->buffer.bytesperline - zr->window.width * bpp; + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + if (reg & 3) + printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name); + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ + btwrite(reg, ZR36057_VSSFGR); + + /* Set overlay clipping */ + + if (zr->window.clipcount) + btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); + + /* ... and switch it on */ + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } else { + /* Switch it off */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + } +} + +/* + * The overlay mask has one bit for each pixel on a scan line, + * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. + */ +static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count) +{ + unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + u32 *mask; + int x, y, width, height; + unsigned i, j, k; + u32 reg; + + /* fill mask with one bits */ + memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); + reg = 0; + + for (i = 0; i < count; ++i) { + /* pick up local copy of clip */ + x = vp[i].x; + y = vp[i].y; + width = vp[i].width; + height = vp[i].height; + + /* trim clips that extend beyond the window */ + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > zr->window.width) { + width = zr->window.width - x; + } + if (y + height > zr->window.height) { + height = zr->window.height - y; + } + /* ignore degenerate clips */ + if (height <= 0) { + continue; + } + if (width <= 0) { + continue; + } + /* apply clip for each scan line */ + for (j = 0; j < height; ++j) { + /* reset bit for each pixel */ + /* this can be optimized later if need be */ + mask = zr->overlay_mask + (y + j) * mask_line_size; + for (k = 0; k < width; ++k) { + mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32); + } + } + } +} + +/* Enable/Disable uncompressed memory grabbing of the 36057 */ + +static void zr36057_set_memgrab(struct zoran *zr, int mode) +{ + if (mode) { + if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) + printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name); + + /* switch on VSync interrupts */ + + btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts + + btor(ZR36057_ICR_GIRQ0, ZR36057_ICR); + + /* enable SnapShot */ + + btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + + /* Set zr36057 video front end and enable video */ + +#ifdef XAWTV_HACK + zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat); +#else + zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); +#endif + + zr->v4l_memgrab_active = 1; + } else { + zr->v4l_memgrab_active = 0; + + /* switch off VSync interrupts */ + + btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR); + + /* reenable grabbing to screen if it was running */ + + if (zr->v4l_overlay_active) { + zr36057_overlay(zr, 1); + } else { + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + } + } +} + +static int wait_grab_pending(struct zoran *zr) +{ + unsigned long flags; + + /* wait until all pending grabs are finished */ + + if (!zr->v4l_memgrab_active) + return 0; + + while (zr->v4l_pend_tail != zr->v4l_pend_head) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + zr36057_set_memgrab(zr, 0); + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* + * V4L Buffer grabbing + */ + +static int v4l_grab(struct zoran *zr, struct video_mmap *mp) +{ + unsigned long flags; + int res, bpp; + + /* + * There is a long list of limitations to what is allowed to be grabbed + * We don't output error messages her, since some programs (e.g. xawtv) + * just try several settings to find out what is valid or not. + */ + + /* No grabbing outside the buffer range! */ + + if (mp->frame >= v4l_nbufs || mp->frame < 0) + return -EINVAL; + + /* Check size and format of the grab wanted */ + + if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH) + return -EINVAL; + if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) + return -EINVAL; + + bpp = format2bpp(mp->format); + if (bpp == 0) + return -EINVAL; + + /* Check against available buffer size */ + + if (mp->height * mp->width * bpp > v4l_bufsize) + return -EINVAL; + + /* The video front end needs 4-byte alinged line sizes */ + + if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) + return -EINVAL; + + /* + * To minimize the time spent in the IRQ routine, we avoid setting up + * the video front end there. + * If this grab has different parameters from a running streaming capture + * we stop the streaming capture and start it over again. + */ + + if (zr->v4l_memgrab_active && + (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) { + res = wait_grab_pending(zr); + if (res) + return res; + } + zr->gwidth = mp->width; + zr->gheight = mp->height; + zr->gformat = mp->format; + zr->gbpl = bpp * zr->gwidth; + + + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->v4l_gbuf[mp->frame].state) { + + default: + case BUZ_STATE_PEND: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + case BUZ_STATE_DONE: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame; + zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; + res = 0; + break; + + } + + /* put the 36057 into frame grabbing mode */ + + if (!res && !zr->v4l_memgrab_active) + zr36057_set_memgrab(zr, 1); + + spin_unlock_irqrestore(&zr->lock, flags); + + return res; +} + +/* + * Sync on a V4L buffer + */ + +static int v4l_sync(struct zoran *zr, int frame) +{ + unsigned long flags; + + + /* check passed-in frame number */ + if (frame >= v4l_nbufs || frame < 0) { + printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame); + return -EINVAL; + } + /* Check if is buffer was queued at all */ + + if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { +// printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name); + return -EINVAL; + } + /* wait on this buffer to get ready */ + + while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name); + + /* Check if streaming capture has finished */ + + spin_lock_irqsave(&zr->lock, flags); + + if (zr->v4l_pend_tail == zr->v4l_pend_head) + zr36057_set_memgrab(zr, 0); + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} +/***************************************************************************** + * * + * Set up the Buz-specific MJPEG part * + * * + *****************************************************************************/ + +/* + * Wait til post office is no longer busy + */ + +static int post_office_wait(struct zoran *zr) +{ + u32 por; + u32 ct=0; + + while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { + ct++; + if(ct>100000) + { + printk(KERN_ERR "%s: timeout on post office.\n", zr->name); + return -1; + } + /* wait for something to happen */ + } + if ((por & ZR36057_POR_POPen) != 0) { + printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por); + return -1; + } + if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) { + printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); + return -1; + } + return 0; +} + +static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value) +{ + u32 por; + + post_office_wait(zr); + por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF); + btwrite(por, ZR36057_POR); + return post_office_wait(zr); +} + +static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) +{ + u32 por; + + post_office_wait(zr); + por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); + btwrite(por, ZR36057_POR); + if (post_office_wait(zr) < 0) { + return -1; + } + return btread(ZR36057_POR) & 0xFF; +} + +static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_write(zr, 0, 3, val); +} + +static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 8)) { + return -1; + } + return zr36060_write_8(zr, reg + 1, val >> 0); +} + +static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 1, val >> 0); +} + +static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_16(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 2, val >> 0); +} + +static u32 zr36060_read_8(struct zoran *zr, unsigned reg) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_read(zr, 0, 3) & 0xFF; +} + +static int zr36060_reset(struct zoran *zr) +{ + return post_office_write(zr, 3, 0, 0); +} + +static void zr36060_sleep(struct zoran *zr, int sleep) +{ + GPIO(zr, 1, !sleep); +} + + +static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int size; + + reg = (1 << 0) /* CodeMstr */ + |(0 << 2) /* CFIS=0 */ + |(0 << 6) /* Endian=0 */ + |(0 << 7); /* Code16=0 */ + zr36060_write_8(zr, 0x002, reg); + + switch (mode) { + + case BUZ_MODE_MOTION_DECOMPRESS: + case BUZ_MODE_STILL_DECOMPRESS: + reg = 0x00; /* Codec mode = decompression */ + break; + + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_STILL_COMPRESS: + default: + reg = 0xa4; /* Codec mode = compression with variable scale factor */ + break; + + } + zr36060_write_8(zr, 0x003, reg); + + reg = 0x00; /* reserved, mbz */ + zr36060_write_8(zr, 0x004, reg); + + reg = 0xff; /* 510 bits/block */ + zr36060_write_8(zr, 0x005, reg); + + /* JPEG markers */ + reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ + if (zr->params.COM_len) + reg |= JPEG_MARKER_COM; + if (zr->params.APP_len) + reg |= JPEG_MARKER_APP; + zr36060_write_8(zr, 0x006, reg); + + reg = (0 << 3) /* DATERR=0 */ + |(0 << 2) /* END=0 */ + |(0 << 1) /* EOI=0 */ + |(0 << 0); /* EOAV=0 */ + zr36060_write_8(zr, 0x007, reg); + + /* code volume */ + + /* Target field size in pixels: */ + tvn = &tvnorms[zr->params.norm]; + size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm); + + /* Target compressed field size in bits: */ + size = size * 16; /* uncompressed size in bits */ + size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ + + /* Lower limit (arbitrary, 1 KB) */ + if (size < 8192) + size = 8192; + + /* Upper limit: 7/8 of the code buffers */ + if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7) + size = zr->jpg_bufsize * 7 / zr->params.field_per_buff; + + reg = size; + zr36060_write_32(zr, 0x009, reg); + + /* how do we set initial SF as a function of quality parameter? */ + reg = 0x0100; /* SF=1.0 */ + zr36060_write_16(zr, 0x011, reg); + + reg = 0x00ffffff; /* AF=max */ + zr36060_write_24(zr, 0x013, reg); + + reg = 0x0000; /* test */ + zr36060_write_16(zr, 0x024, reg); +} + +static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + + reg = (0 << 7) /* Video8=0 */ + |(0 << 6) /* Range=0 */ + |(0 << 3) /* FlDet=0 */ + |(1 << 2) /* FlVedge=1 */ + |(0 << 1) /* FlExt=0 */ + |(0 << 0); /* SyncMstr=0 */ + + /* According to ZR36067 documentation, FlDet should correspond + to the odd_even flag of the ZR36067 */ + if (zr->params.odd_even) + reg |= (1 << 3); + + if (mode != BUZ_MODE_STILL_DECOMPRESS) { + /* limit pixels to range 16..235 as per CCIR-601 */ + reg |= (1 << 6); /* Range=1 */ + } + zr36060_write_8(zr, 0x030, reg); + + reg = (0 << 7) /* VCLKPol=0 */ + |(0 << 6) /* PValPol=0 */ + |(1 << 5) /* PoePol=1 */ + |(0 << 4) /* SImgPol=0 */ + |(0 << 3) /* BLPol=0 */ + |(0 << 2) /* FlPol=0 */ + |(0 << 1) /* HSPol=0, sync on falling edge */ + |(1 << 0); /* VSPol=1 */ + zr36060_write_8(zr, 0x031, reg); + + switch (zr->params.HorDcm) { + default: + case 1: + reg = (0 << 0); + break; /* HScale = 0 */ + + case 2: + reg = (1 << 0); + break; /* HScale = 1 */ + + case 4: + reg = (2 << 0); + break; /* HScale = 2 */ + } + if (zr->params.VerDcm == 2) + reg |= (1 << 2); + zr36060_write_8(zr, 0x032, reg); + + reg = 0x80; /* BackY */ + zr36060_write_8(zr, 0x033, reg); + + reg = 0xe0; /* BackU */ + zr36060_write_8(zr, 0x034, reg); + + reg = 0xe0; /* BackV */ + zr36060_write_8(zr, 0x035, reg); + + /* sync generator */ + + tvn = &tvnorms[zr->params.norm]; + + reg = tvn->Ht - 1; /* Vtotal */ + zr36060_write_16(zr, 0x036, reg); + + reg = tvn->Wt - 1; /* Htotal */ + zr36060_write_16(zr, 0x038, reg); + + reg = 6 - 1; /* VsyncSize */ + zr36060_write_8(zr, 0x03a, reg); + + reg = 100 - 1; /* HsyncSize */ + zr36060_write_8(zr, 0x03b, reg); + + reg = tvn->VStart - 1; /* BVstart */ + zr36060_write_8(zr, 0x03c, reg); + + reg += tvn->Ha / 2; /* BVend */ + zr36060_write_16(zr, 0x03e, reg); + + reg = tvn->HStart - 1; /* BHstart */ + zr36060_write_8(zr, 0x03d, reg); + + reg += tvn->Wa; /* BHend */ + zr36060_write_16(zr, 0x040, reg); + + /* active area */ + reg = zr->params.img_y + tvn->VStart; /* Vstart */ + zr36060_write_16(zr, 0x042, reg); + + reg += zr->params.img_height; /* Vend */ + zr36060_write_16(zr, 0x044, reg); + + reg = zr->params.img_x + tvn->HStart; /* Hstart */ + zr36060_write_16(zr, 0x046, reg); + + reg += zr->params.img_width; /* Hend */ + zr36060_write_16(zr, 0x048, reg); + + /* subimage area */ + reg = zr->params.img_y + tvn->VStart; /* SVstart */ + zr36060_write_16(zr, 0x04a, reg); + + reg += zr->params.img_height; /* SVend */ + zr36060_write_16(zr, 0x04c, reg); + + reg = zr->params.img_x + tvn->HStart; /* SHstart */ + zr36060_write_16(zr, 0x04e, reg); + + reg += zr->params.img_width; /* SHend */ + zr36060_write_16(zr, 0x050, reg); +} + +static void zr36060_set_jpg_SOF(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffc0; /* SOF marker */ + zr36060_write_16(zr, 0x060, reg); + + reg = 17; /* SOF length */ + zr36060_write_16(zr, 0x062, reg); + + reg = 8; /* precision 8 bits */ + zr36060_write_8(zr, 0x064, reg); + + reg = zr->params.img_height / zr->params.VerDcm; /* image height */ + zr36060_write_16(zr, 0x065, reg); + + reg = zr->params.img_width / zr->params.HorDcm; /* image width */ + zr36060_write_16(zr, 0x067, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x069, reg); + + reg = 0x002100; /* Y component */ + zr36060_write_24(zr, 0x06a, reg); + + reg = 0x011101; /* U component */ + zr36060_write_24(zr, 0x06d, reg); + + reg = 0x021101; /* V component */ + zr36060_write_24(zr, 0x070, reg); +} + +static void zr36060_set_jpg_SOS(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffda; /* SOS marker */ + zr36060_write_16(zr, 0x07a, reg); + + reg = 12; /* SOS length */ + zr36060_write_16(zr, 0x07c, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x07e, reg); + + reg = 0x0000; /* Y component */ + zr36060_write_16(zr, 0x07f, reg); + + reg = 0x0111; /* U component */ + zr36060_write_16(zr, 0x081, reg); + + reg = 0x0211; /* V component */ + zr36060_write_16(zr, 0x083, reg); + + reg = 0x003f00; /* Start, end spectral scans */ + zr36060_write_24(zr, 0x085, reg); +} + +static void zr36060_set_jpg_DRI(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffdd; /* DRI marker */ + zr36060_write_16(zr, 0x0c0, reg); + + reg = 4; /* DRI length */ + zr36060_write_16(zr, 0x0c2, reg); + + reg = 8; /* length in MCUs */ + zr36060_write_16(zr, 0x0c4, reg); +} + +static void zr36060_set_jpg_DQT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dqt[] = + { + 0xff, 0xdb, /* DHT marker */ + 0x00, 0x84, /* DHT length */ + 0x00, /* table ID 0 */ + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0x01, /* table ID 1 */ + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 + }; + + /* write fixed quantitization tables */ + adr = 0x0cc; + for (i = 0; i < sizeof(dqt); ++i) { + zr36060_write_8(zr, adr++, dqt[i]); + } +} + +static void zr36060_set_jpg_DHT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dht[] = + { + 0xff, 0xc4, /* DHT marker */ + 0x01, 0xa2, /* DHT length */ + 0x00, /* table class 0, ID 0 */ + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ + 0x00, /* values for codes of length 2 */ + 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ + 0x06, /* values for codes of length 4 */ + 0x07, /* values for codes of length 5 */ + 0x08, /* values for codes of length 6 */ + 0x09, /* values for codes of length 7 */ + 0x0a, /* values for codes of length 8 */ + 0x0b, /* values for codes of length 9 */ + 0x01, /* table class 0, ID 1 */ + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ + 0x00, 0x01, 0x02, /* values for codes of length 2 */ + 0x03, /* values for codes of length 3 */ + 0x04, /* values for codes of length 4 */ + 0x05, /* values for codes of length 5 */ + 0x06, /* values for codes of length 6 */ + 0x07, /* values for codes of length 7 */ + 0x08, /* values for codes of length 8 */ + 0x09, /* values for codes of length 9 */ + 0x0a, /* values for codes of length 10 */ + 0x0b, /* values for codes of length 11 */ + 0x10, + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, + 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, + 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, + 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, + 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, + 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, + 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, + 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, + 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa + }; + + /* write fixed Huffman tables */ + adr = 0x1d4; + for (i = 0; i < sizeof(dht); ++i) { + zr36060_write_8(zr, adr++, dht[i]); + } +} + +static void zr36060_set_jpg_APP(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.APP_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + i = zr->params.APPn; + if (i < 0) + i = 0; + if (i > 15) + i = 15; + + reg = 0xffe0 + i; /* APPn marker */ + zr36060_write_16(zr, 0x380, reg); + + reg = len + 2; /* APPn len */ + zr36060_write_16(zr, 0x382, reg); + + /* write APPn data */ + adr = 0x384; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0)); + } +} + +static void zr36060_set_jpg_COM(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.COM_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + reg = 0xfffe; /* COM marker */ + zr36060_write_16(zr, 0x3c0, reg); + + reg = len + 2; /* COM len */ + zr36060_write_16(zr, 0x3c2, reg); + + /* write COM data */ + adr = 0x3c4; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0)); + } +} + +static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) +{ + unsigned i; + u32 reg; + + zr36060_reset(zr); + mdelay(10); + + reg = (0 << 7) /* Load=0 */ + |(1 << 0); /* SynRst=1 */ + zr36060_write_8(zr, 0x000, reg); + + zr36060_set_jpg(zr, mode); + zr36060_set_video(zr, mode); + zr36060_set_jpg_SOF(zr); + zr36060_set_jpg_SOS(zr); + zr36060_set_jpg_DRI(zr); + zr36060_set_jpg_DQT(zr); + zr36060_set_jpg_DHT(zr); + zr36060_set_jpg_APP(zr); + zr36060_set_jpg_COM(zr); + + reg = (1 << 7) /* Load=1 */ + |(0 << 0); /* SynRst=0 */ + zr36060_write_8(zr, 0x000, reg); + + /* wait for codec to unbusy */ + for (i = 0; i < 1000; ++i) { + reg = zr36060_read_8(zr, 0x001); + if ((reg & (1 << 7)) == 0) { + DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i)); + return; + } + udelay(1000); + } + printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg); +} + +static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int i; + + tvn = &tvnorms[zr->params.norm]; + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + /* re-initialize DMA ring stuff */ + zr->jpg_que_head = 0; + zr->jpg_dma_head = 0; + zr->jpg_dma_tail = 0; + zr->jpg_que_tail = 0; + zr->jpg_seq_num = 0; + for (i = 0; i < BUZ_NUM_STAT_COM; ++i) { + zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ + } + for (i = 0; i < zr->jpg_nbufs; i++) { + zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* MJPEG compression mode */ + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + default: + reg = ZR36057_JMC_MJPGCmpMode; + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + reg = ZR36057_JMC_MJPGExpMode; + reg |= ZR36057_JMC_SyncMstr; + /* RJ: The following is experimental - improves the output to screen */ + if (zr->params.VFIFO_FB) + reg |= ZR36057_JMC_VFIFO_FB; + break; + + case BUZ_MODE_STILL_COMPRESS: + reg = ZR36057_JMC_JPGCmpMode; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + reg = ZR36057_JMC_JPGExpMode; + break; + + } + reg |= ZR36057_JMC_JPG; + if (zr->params.field_per_buff == 1) + reg |= ZR36057_JMC_Fld_per_buff; + btwrite(reg, ZR36057_JMC); + + /* vertical */ + btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); + reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); + btwrite(reg, ZR36057_VSP); + reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) + | (zr->params.img_height << ZR36057_FVAP_PAY); + btwrite(reg, ZR36057_FVAP); + + /* horizontal */ + btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); + reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot); + btwrite(reg, ZR36057_HSP); + reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX) + | (zr->params.img_width << ZR36057_FHAP_PAX); + btwrite(reg, ZR36057_FHAP); + + /* field process parameters */ + if (zr->params.odd_even) + reg = ZR36057_FPP_Odd_Even; + else + reg = 0; + btwrite(reg, ZR36057_FPP); + + /* Set proper VCLK Polarity, else colors will be wrong during playback */ + btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); + + /* code base address and FIFO threshold */ + reg = virt_to_bus(zr->stat_com); + btwrite(reg, ZR36057_JCBA); + reg = 0x50; + btwrite(reg, ZR36057_JCFT); + + /* JPEG codec guest ID */ + reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg); + btwrite(reg, ZR36057_JCGI); + + /* Code transfer guest ID */ + reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg); + reg |= ZR36057_MCTCR_CFlush; + btwrite(reg, ZR36057_MCTCR); + + /* deassert P_Reset */ + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); +} + +static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + static int zero = 0; + static int one = 1; + + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + zr36060_set_cap(zr, mode); + zr36057_set_jpg(zr, mode); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); + + /* deassert P_Reset, assert Code transfer enable */ + btwrite(IRQ_MASK, ZR36057_ISR); + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one); + zr36060_set_cap(zr, mode); + zr36057_set_jpg(zr, mode); + + /* deassert P_Reset, assert Code transfer enable */ + btwrite(IRQ_MASK, ZR36057_ISR); + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + break; + + case BUZ_MODE_IDLE: + default: + /* shut down processing */ + btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); + btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); + btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + btwrite(0, ZR36057_ISR); + zr36060_reset(zr); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); + break; + + } + zr->codec_mode = mode; +} + +/* + * Queue a MJPEG buffer for capture/playback + */ + +static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode) +{ + unsigned long flags; + int res; + + /* Check if buffers are allocated */ + + if (!zr->jpg_buffers_allocated) { + printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name); + return -ENOMEM; + } + /* Does the user want to stop streaming? */ + + if (frame < 0) { + if (zr->codec_mode == mode) { + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + return 0; + } else { + printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name); + return -EINVAL; + } + } + /* No grabbing outside the buffer range! */ + + if (frame >= zr->jpg_nbufs) { + printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame); + return -EINVAL; + } + /* what is the codec mode right now? */ + + if (zr->codec_mode == BUZ_MODE_IDLE) { + /* Ok load up the zr36060 and go */ + zr36057_enable_jpg(zr, mode); + } else if (zr->codec_mode != mode) { + /* wrong codec mode active - invalid */ + printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name); + return -EINVAL; + } + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->jpg_gbuf[frame].state) { + + default: + case BUZ_STATE_DMA: + case BUZ_STATE_PEND: + case BUZ_STATE_DONE: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; + zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; + zoran_feed_stat_com(zr); + res = 0; + break; + + } + + spin_unlock_irqrestore(&zr->lock, flags); + + /* Start the zr36060 when the first frame is queued */ + if (zr->jpg_que_head == 1) { + btor(ZR36057_JMC_Go_en, ZR36057_JMC); + btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC); + } + return res; +} + +/* + * Sync on a MJPEG buffer + */ + +static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) +{ + unsigned long flags; + int frame; + + if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && + zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { + return -EINVAL; + } + while (zr->jpg_que_tail == zr->jpg_dma_tail) { + interruptible_sleep_on(&zr->jpg_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + + frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name); + + *bs = zr->jpg_gbuf[frame].bs; + zr->jpg_gbuf[frame].state = BUZ_STATE_USER; + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* when this is called the spinlock must be held */ +static void zoran_feed_stat_com(struct zoran *zr) +{ + /* move frames from pending queue to DMA */ + + int frame, i, max_stat_com; + + max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); + + while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com + && zr->jpg_dma_head != zr->jpg_que_head) { + + frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; + if (zr->params.TmpDcm == 1) { + /* fill 1 stat_com entry */ + i = zr->jpg_dma_head & BUZ_MASK_STAT_COM; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + } else { + /* fill 2 stat_com entries */ + i = (zr->jpg_dma_head & 1) * 2; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus; + } + zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; + zr->jpg_dma_head++; + + } +} + +/* when this is called the spinlock must be held */ +static void zoran_reap_stat_com(struct zoran *zr) +{ + /* move frames from DMA queue to done queue */ + + int i; + u32 stat_com; + unsigned int seq; + unsigned int dif; + int frame; + struct zoran_gbuffer *gbuf; + + /* In motion decompress we don't have a hardware frame counter, + we just count the interrupts here */ + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_seq_num++; + + while (zr->jpg_dma_tail != zr->jpg_dma_head) { + if (zr->params.TmpDcm == 1) + i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM; + else + i = (zr->jpg_dma_tail & 1) * 2 + 1; + + stat_com = zr->stat_com[i]; + + if ((stat_com & 1) == 0) { + return; + } + frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; + gbuf = &zr->jpg_gbuf[frame]; + get_fast_time(&gbuf->bs.timestamp); + + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { + gbuf->bs.length = (stat_com & 0x7fffff) >> 1; + + /* update sequence number with the help of the counter in stat_com */ + + seq = stat_com >> 24; + dif = (seq - zr->jpg_seq_num) & 0xff; + zr->jpg_seq_num += dif; + } else { + gbuf->bs.length = 0; + } + gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; + gbuf->state = BUZ_STATE_DONE; + + zr->jpg_dma_tail++; + } +} + +static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat, astat; + int count; + struct zoran *zr; + unsigned long flags; + + zr = (struct zoran *) dev_id; + count = 0; + + spin_lock_irqsave(&zr->lock, flags); + while (1) { + /* get/clear interrupt status bits */ + stat = btread(ZR36057_ISR); + astat = stat & IRQ_MASK; + if (!astat) { + break; + } + btwrite(astat, ZR36057_ISR); + IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat)); + +#if (IRQ_MASK & ZR36057_ISR_GIRQ0) + if (astat & ZR36057_ISR_GIRQ0) { + + /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. + We simply ignore them */ + + if (zr->v4l_memgrab_active) { + +/* A lot more checks should be here ... */ + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) + printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name); + + if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { + /* There is a grab on a frame going on, check if it has finished */ + + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { + /* it is finished, notify the user */ + + zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE; + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq++; + zr->v4l_pend_tail++; + } + } + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) + wake_up_interruptible(&zr->v4l_capq); + + /* Check if there is another grab queued */ + + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && + zr->v4l_pend_tail != zr->v4l_pend_head) { + + int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; + u32 reg; + + zr->v4l_grab_frame = frame; + + /* Set zr36057 video front end and enable video */ + + /* Buffer address */ + + reg = zr->v4l_gbuf[frame].fbuffer_bus; + btwrite(reg, ZR36057_VDTR); + if (zr->video_interlace) + reg += zr->gbpl; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + +#ifdef XAWTV_HACK + reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0; +#else + reg = 0; +#endif + if (zr->video_interlace) + reg += zr->gbpl; + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; + reg |= ZR36057_VSSFGR_SnapShot; + reg |= ZR36057_VSSFGR_FrameGrab; + btwrite(reg, ZR36057_VSSFGR); + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } + } + } +#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ0) */ + +#if (IRQ_MASK & ZR36057_ISR_GIRQ1) + if (astat & ZR36057_ISR_GIRQ1) { + unsigned csr = zr36060_read_8(zr, 0x001); + unsigned isr = zr36060_read_8(zr, 0x008); + + IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n", + zr->name, csr, isr)); + + btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + } +#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ1) */ + +#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) + if (astat & ZR36057_ISR_CodRepIRQ) { + IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name)); + btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); + } +#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ + +#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) + if ((astat & ZR36057_ISR_JPEGRepIRQ) && + (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || + zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + } +#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ + + count++; + if (count > 10) { + printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count); + if (count > 20) { + btwrite(0, ZR36057_ICR); + printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n", zr->name); + break; + } + } + } + spin_unlock_irqrestore(&zr->lock, flags); +} + +/* Check a zoran_params struct for correctness, insert default params */ + +static int zoran_check_params(struct zoran *zr, struct zoran_params *params) +{ + int err = 0, err0 = 0; + + /* insert constant params */ + + params->major_version = MAJOR_VERSION; + params->minor_version = MINOR_VERSION; + + /* Check input and norm */ + + if (params->input != 0 && params->input != 1) { + err++; + } + if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) { + err++; + } + /* Check decimation, set default values for decimation = 1, 2, 4 */ + + switch (params->decimation) { + case 1: + + params->HorDcm = 1; + params->VerDcm = 1; + params->TmpDcm = 1; + params->field_per_buff = 2; + + params->img_x = 0; + params->img_y = 0; + params->img_width = 720; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 2: + + params->HorDcm = 2; + params->VerDcm = 1; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = 704; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 4: + + params->HorDcm = 4; + params->VerDcm = 2; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = 704; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 0: + + /* We have to check the data the user has set */ + + if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4) + err0++; + if (params->VerDcm != 1 && params->VerDcm != 2) + err0++; + if (params->TmpDcm != 1 && params->TmpDcm != 2) + err0++; + if (params->field_per_buff != 1 && params->field_per_buff != 2) + err0++; + + if (params->img_x < 0) + err0++; + if (params->img_y < 0) + err0++; + if (params->img_width < 0) + err0++; + if (params->img_height < 0) + err0++; + if (params->img_x + params->img_width > 720) + err0++; + if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2) + err0++; + if (params->img_width % (16 * params->HorDcm) != 0) + err0++; + if (params->img_height % (8 * params->VerDcm) != 0) + err0++; + + if (err0) { + err++; + } + break; + + default: + err++; + break; + } + + if (params->quality > 100) + params->quality = 100; + if (params->quality < 5) + params->quality = 5; + + if (params->APPn < 0) + params->APPn = 0; + if (params->APPn > 15) + params->APPn = 15; + if (params->APP_len < 0) + params->APP_len = 0; + if (params->APP_len > 60) + params->APP_len = 60; + if (params->COM_len < 0) + params->COM_len = 0; + if (params->COM_len > 60) + params->COM_len = 60; + + if (err) + return -EINVAL; + + return 0; + +} +static void zoran_open_init_params(struct zoran *zr) +{ + int i; + + /* Per default, map the V4L Buffers */ + + zr->map_mjpeg_buffers = 0; + + /* User must explicitly set a window */ + + zr->window_set = 0; + + zr->window.x = 0; + zr->window.y = 0; + zr->window.width = 0; + zr->window.height = 0; + zr->window.chromakey = 0; + zr->window.flags = 0; + zr->window.clips = NULL; + zr->window.clipcount = 0; + + zr->video_interlace = 0; + + zr->v4l_memgrab_active = 0; + zr->v4l_overlay_active = 0; + + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq = 0; + + zr->gwidth = 0; + zr->gheight = 0; + zr->gformat = 0; + zr->gbpl = 0; + + /* DMA ring stuff for V4L */ + + zr->v4l_pend_tail = 0; + zr->v4l_pend_head = 0; + for (i = 0; i < v4l_nbufs; i++) { + zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* Set necessary params and call zoran_check_params to set the defaults */ + + zr->params.decimation = 1; + + zr->params.quality = 50; /* default compression factor 8 */ + zr->params.odd_even = 1; + + zr->params.APPn = 0; + zr->params.APP_len = 0; /* No APPn marker */ + for (i = 0; i < 60; i++) + zr->params.APP_data[i] = 0; + + zr->params.COM_len = 0; /* No COM marker */ + for (i = 0; i < 60; i++) + zr->params.COM_data[i] = 0; + + zr->params.VFIFO_FB = 0; + + memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); + + zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; + + i = zoran_check_params(zr, &zr->params); + if (i) + printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name); +} + +/* + * Open a buz card. Right now the flags stuff is just playing + */ + +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *zr = (struct zoran *) dev; + + DEBUG(printk(KERN_INFO ": zoran_open\n")); + + switch (flags) { + + case 0: + if (zr->user) + return -EBUSY; + zr->user++; + + if (v4l_fbuffer_alloc(zr) < 0) { + zr->user--; + return -ENOMEM; + } + /* default setup */ + + zoran_open_init_params(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + + btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts + + btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); + + break; + + default: + return -EBUSY; + + } + MOD_INC_USE_COUNT; + return 0; +} + +static void zoran_close(struct video_device *dev) +{ + struct zoran *zr = (struct zoran *) dev; + + DEBUG(printk(KERN_INFO ": zoran_close\n")); + + /* disable interrupts */ + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + + /* wake up sleeping beauties */ + wake_up_interruptible(&zr->v4l_capq); + wake_up_interruptible(&zr->jpg_capq); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + zr36057_set_memgrab(zr, 0); + if (zr->v4l_overlay_active) + zr36057_overlay(zr, 0); + + zr->user--; + + v4l_fbuffer_free(zr); + jpg_fbuffer_free(zr); + zr->jpg_nbufs = 0; + + MOD_DEC_USE_COUNT; + DEBUG(printk(KERN_INFO ": zoran_close done\n")); +} + + +static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +/* + * ioctl routine + */ + + +static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zoran *zr = (struct zoran *) dev; + + switch (cmd) { + + case VIDIOCGCAP: + { + struct video_capability b; + IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n")); + strncpy(b.name, zr->video_dev.name, sizeof(b.name)); + b.type = VID_TYPE_CAPTURE | + VID_TYPE_OVERLAY | + VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | + VID_TYPE_SCALES; + /* theoretically we could also flag VID_TYPE_SUBCAPTURE + but this is not even implemented in the BTTV driver */ + + b.channels = 2; /* composite, svhs */ + b.audios = 0; + b.maxwidth = BUZ_MAX_WIDTH; + b.maxheight = BUZ_MAX_HEIGHT; + b.minwidth = BUZ_MIN_WIDTH; + b.minheight = BUZ_MIN_HEIGHT; + if (copy_to_user(arg, &b, sizeof(b))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel)); + switch (v.channel) { + case 0: + strcpy(v.name, "Composite"); + break; + case 1: + strcpy(v.name, "SVHS"); + break; + default: + return -EINVAL; + } + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = zr->params.norm; + if (copy_to_user(arg, &v, sizeof(v))) { + return -EFAULT; + } + return 0; + } + + /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: + + * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." + * ^^^^^^^ + * The famos BTTV driver has it implemented with a struct video_channel argument + * and we follow it for compatibility reasons + * + * BTW: this is the only way the user can set the norm! + */ + + case VIDIOCSCHAN: + { + struct video_channel v; + int input; + int on, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm)); + switch (v.channel) { + case 0: + input = 3; + break; + case 1: + input = 7; + break; + default: + return -EINVAL; + } + + if (v.norm != VIDEO_MODE_PAL + && v.norm != VIDEO_MODE_NTSC) { + return -EINVAL; + } + zr->params.norm = v.norm; + zr->params.input = v.channel; + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + if (on) + zr36057_overlay(zr, 1); + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + + case VIDIOCGTUNER: + case VIDIOCSTUNER: + return -EINVAL; + + case VIDIOCGPICT: + { + struct video_picture p = zr->picture; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n")); + p.depth = zr->buffer.depth; + switch (zr->buffer.depth) { + case 15: + p.palette = VIDEO_PALETTE_RGB555; + break; + + case 16: + p.palette = VIDEO_PALETTE_RGB565; + break; + + case 24: + p.palette = VIDEO_PALETTE_RGB24; + break; + + case 32: + p.palette = VIDEO_PALETTE_RGB32; + break; + } + + if (copy_to_user(arg, &p, sizeof(p))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) { + return -EFAULT; + } + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); + IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", + p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette)); + /* The depth and palette values have no meaning to us, + should we return -EINVAL if they don't fit ? */ + zr->picture = p; + return 0; + } + + case VIDIOCCAPTURE: + { + int v, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v)); + /* If there is nothing to do, return immediatly */ + + if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active)) + return 0; + + if (v == 0) { + zr->v4l_overlay_active = 0; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 0); + /* When a grab is running, the video simply won't be switched on any more */ + } else { + if (!zr->buffer_set || !zr->window_set) { + return -EINVAL; + } + zr->v4l_overlay_active = 1; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 1); + /* When a grab is running, the video will be switched on when grab is finished */ + } + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + return 0; + } + + case VIDIOCGWIN: + { + IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n")); + if (copy_to_user(arg, &zr->window, sizeof(zr->window))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSWIN: + { + struct video_clip *vcp; + struct video_window vw; + int on, end, res; + + if (copy_from_user(&vw, arg, sizeof(vw))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount)); + if (!zr->buffer_set) { + return -EINVAL; + } + /* + * The video front end needs 4-byte alinged line sizes, we correct that + * silently here if necessary + */ + + if (zr->buffer.depth == 15 || zr->buffer.depth == 16) { + end = (vw.x + vw.width) & ~1; /* round down */ + vw.x = (vw.x + 1) & ~1; /* round up */ + vw.width = end - vw.x; + } + if (zr->buffer.depth == 24) { + end = (vw.x + vw.width) & ~3; /* round down */ + vw.x = (vw.x + 3) & ~3; /* round up */ + vw.width = end - vw.x; + } +#if 0 + // At least xawtv seems to care about the following - just leave it away + /* + * Also corrected silently (as long as window fits at all): + * video not fitting the screen + */ +#if 0 + if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width || + vw.y + vw.height > zr->buffer.height) { + printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n", + vw.width, vw.height, vw.x, vw.y); + return -EINVAL; + } +#else + if (vw.x < 0) + vw.x = 0; + if (vw.y < 0) + vw.y = 0; + if (vw.x + vw.width > zr->buffer.width) + vw.width = zr->buffer.width - vw.x; + if (vw.y + vw.height > zr->buffer.height) + vw.height = zr->buffer.height - vw.y; +#endif +#endif + + /* Check for vaild parameters */ + if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT || + vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) { + return -EINVAL; + } +#ifdef XAWTV_HACK + if (vw.width > 720) + vw.width = 720; +#endif + + zr->window.x = vw.x; + zr->window.y = vw.y; + zr->window.width = vw.width; + zr->window.height = vw.height; + zr->window.chromakey = 0; + zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? + + zr->window.clips = NULL; + zr->window.clipcount = vw.clipcount; + + /* + * If an overlay is running, we have to switch it off + * and switch it on again in order to get the new settings in effect. + * + * We also want to avoid that the overlay mask is written + * when an overlay is running. + */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + /* + * Write the overlay mask if clips are wanted. + */ + if (vw.clipcount) { + vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4)); + if (vcp == NULL) { + return -ENOMEM; + } + if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + write_overlay_mask(zr, vcp, vw.clipcount); + vfree(vcp); + } + if (on) + zr36057_overlay(zr, 1); + zr->window_set = 1; + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + + case VIDIOCGFBUF: + { + IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n")); + if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSFBUF: + { + struct video_buffer v; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline)); + if (zr->v4l_overlay_active) { + /* Has the user gotten crazy ... ? */ + return -EINVAL; + } + if (v.depth != 15 + && v.depth != 16 + && v.depth != 24 + && v.depth != 32) { + return -EINVAL; + } + if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) { + return -EINVAL; + } + if (v.bytesperline & 3) { + return -EINVAL; + } + if (v.base) { + zr->buffer.base = (void *) ((unsigned long) v.base & ~3); + } + zr->buffer.height = v.height; + zr->buffer.width = v.width; + zr->buffer.depth = v.depth; + zr->buffer.bytesperline = v.bytesperline; + + if (zr->buffer.base) + zr->buffer_set = 1; + zr->window_set = 0; /* The user should set new window parameters */ + return 0; + } + + /* RJ: what is VIDIOCKEY intended to do ??? */ + + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + + case VIDIOCSYNC: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v)); + return v4l_sync(zr, v); + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", + vm.frame, vm.height, vm.width, vm.format)); + return v4l_grab(zr, &vm); + } + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n")); + + vm.size = v4l_nbufs * v4l_bufsize; + vm.frames = v4l_nbufs; + for (i = 0; i < v4l_nbufs; i++) { + vm.offsets[i] = i * v4l_bufsize; + } + + /* The next mmap will map the V4L buffers */ + zr->map_mjpeg_buffers = 0; + + if (copy_to_user(arg, &vm, sizeof(vm))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n")); + vu.video = zr->video_dev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if (copy_to_user(arg, &vu, sizeof(vu))) + return -EFAULT; + return 0; + } + + /* + * RJ: In principal we could support subcaptures for V4L grabbing. + * Not even the famous BTTV driver has them, however. + * If there should be a strong demand, one could consider + * to implement them. + */ + case VIDIOCGCAPTURE: + case VIDIOCSCAPTURE: + return -EINVAL; + + case BUZIOC_G_PARAMS: + { + IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n")); + if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) + return -EFAULT; + return 0; + } + + case BUZIOC_S_PARAMS: + { + struct zoran_params bp; + int input, on; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + return -EINVAL; + } + if (copy_from_user(&bp, arg, sizeof(bp))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n")); + + /* Check the params first before overwriting our internal values */ + + if (zoran_check_params(zr, &bp)) + return -EINVAL; + + zr->params = bp; + + /* Make changes of input and norm go into effect immediatly */ + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + input = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + if (on) + zr36057_overlay(zr, 1); + + if (copy_to_user(arg, &bp, sizeof(bp))) { + return -EFAULT; + } + return 0; + } + + case BUZIOC_REQBUFS: + { + struct zoran_requestbuffers br; + + if (zr->jpg_buffers_allocated) { + return -EINVAL; + } + if (copy_from_user(&br, arg, sizeof(br))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", + br.count, br.size)); + /* Enforce reasonable lower and upper limits */ + if (br.count < 4) + br.count = 4; /* Could be choosen smaller */ + if (br.count > BUZ_MAX_FRAME) + br.count = BUZ_MAX_FRAME; + br.size = PAGE_ALIGN(br.size); + if (br.size < 8192) + br.size = 8192; /* Arbitrary */ + /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ + if (br.size > (512 * 1024)) + br.size = (512 * 1024); /* 512 K should be enough */ + if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM) + br.size = MAX_KMALLOC_MEM; + + zr->jpg_nbufs = br.count; + zr->jpg_bufsize = br.size; + + if (jpg_fbuffer_alloc(zr)) + return -ENOMEM; + + /* The next mmap will map the MJPEG buffers */ + zr->map_mjpeg_buffers = 1; + + if (copy_to_user(arg, &br, sizeof(br))) { + return -EFAULT; + } + return 0; + } + + case BUZIOC_QBUF_CAPT: + { + int nb; + + if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); + } + + case BUZIOC_QBUF_PLAY: + { + int nb; + + if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS); + } + + case BUZIOC_SYNC: + { + struct zoran_sync bs; + int res; + + IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n")); + res = jpg_sync(zr, &bs); + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return res; + } + + case BUZIOC_G_STATUS: + { + struct zoran_status bs; + int norm, input, status; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + return -EINVAL; + } + if (copy_from_user(&bs, arg, sizeof(bs))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n")); + switch (bs.input) { + case 0: + input = 3; + break; + case 1: + input = 7; + break; + default: + return -EINVAL; + } + + /* Set video norm to VIDEO_MODE_AUTO */ + + norm = VIDEO_MODE_AUTO; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + + /* sleep 1 second */ + + schedule_timeout(HZ); + + /* Get status of video decoder */ + + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status); + bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; + bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; + + /* restore previous input and norm */ + input = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return 0; + } + + default: + return -ENOIOCTLCMD; + + } + return 0; +} + + +/* + * This maps the buffers to user space. + * + * Depending on the state of zr->map_mjpeg_buffers + * the V4L or the MJPEG buffers are mapped + * + */ + +static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct zoran *zr = (struct zoran *) dev; + unsigned long start = (unsigned long) adr; + unsigned long page, pos, todo, fraglen; + int i, j; + + if (zr->map_mjpeg_buffers) { + /* Map the MJPEG buffers */ + + if (!zr->jpg_buffers_allocated) { + return -ENOMEM; + } + if (size > zr->jpg_nbufs * zr->jpg_bufsize) { + return -EINVAL; + } + + for (i = 0; i < zr->jpg_nbufs; i++) { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1; + todo = size; + if (todo > fraglen) + todo = fraglen; + pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j]; + page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ + if (remap_page_range(start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1) + break; /* was last fragment */ + } + if (size == 0) + break; + } + } else { + /* Map the V4L buffers */ + + if (size > v4l_nbufs * v4l_bufsize) { + return -EINVAL; + } + + for (i = 0; i < v4l_nbufs; i++) { + todo = size; + if (todo > v4l_bufsize) + todo = v4l_bufsize; + page = zr->v4l_gbuf[i].fbuffer_phys; + DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start)); + if (remap_page_range(start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + } + } + return 0; +} + +static int zoran_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device zoran_template = +{ + BUZ_NAME, + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | + VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, + VID_HARDWARE_BT848, /* Not true, but the buz is not yet in the list */ + zoran_open, + zoran_close, + zoran_read, + zoran_write, + NULL, + zoran_ioctl, + zoran_mmap, + zoran_init_done, + NULL, + 0, + 0 +}; + +static int zr36057_init(int i) +{ + struct zoran *zr = &zoran[i]; + unsigned long mem; + unsigned mem_needed; + int j; + int rev; + + /* reset zr36057 */ + btwrite(0, ZR36057_SPGPPCR); + mdelay(10); + + /* default setup of all parameters which will persist beetween opens */ + + zr->user = 0; + + init_waitqueue_head(&zr->v4l_capq); + init_waitqueue_head(&zr->jpg_capq); + + zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ + + zr->jpg_nbufs = 0; + zr->jpg_bufsize = 0; + zr->jpg_buffers_allocated = 0; + + zr->buffer_set = 0; /* Flag if frame buffer has been set */ + zr->buffer.base = (void *) vidmem; + zr->buffer.width = 0; + zr->buffer.height = 0; + zr->buffer.depth = 0; + zr->buffer.bytesperline = 0; + + zr->params.norm = default_norm ? 1 : 0; /* Avoid nonsense settings from user */ + zr->params.input = default_input ? 1 : 0; /* Avoid nonsense settings from user */ + zr->video_interlace = 0; + + /* Should the following be reset at every open ? */ + + zr->picture.colour = 32768; + zr->picture.brightness = 32768; + zr->picture.hue = 32768; + zr->picture.contrast = 32768; + zr->picture.whiteness = 0; + zr->picture.depth = 0; + zr->picture.palette = 0; + + for (j = 0; j < VIDEO_MAX_FRAME; j++) { + zr->v4l_gbuf[i].fbuffer = 0; + zr->v4l_gbuf[i].fbuffer_phys = 0; + zr->v4l_gbuf[i].fbuffer_bus = 0; + } + + zr->stat_com = 0; + + /* default setup (will be repeated at every open) */ + + zoran_open_init_params(zr); + + /* allocate memory *before* doing anything to the hardware in case allocation fails */ + + /* STAT_COM table and overlay mask */ + + mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; + mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); + if (!mem) { + return -ENOMEM; + } + memset((void *) mem, 0, mem_needed); + + zr->stat_com = (u32 *) mem; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ + } + zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); + + /* Initialize zr->jpg_gbuf */ + + for (j = 0; j < BUZ_MAX_FRAME; j++) { + zr->jpg_gbuf[j].frag_tab = 0; + zr->jpg_gbuf[j].frag_tab_bus = 0; + zr->jpg_gbuf[j].state = BUZ_STATE_USER; + zr->jpg_gbuf[j].bs.frame = j; + } + + /* take zr36057 out of reset now */ + btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); + mdelay(10); + + /* stop all DMA processes */ + btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + switch(zr->board) + { + case BOARD_BUZ: + + /* set up GPIO direction */ + btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); + + /* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */ + btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1); + mdelay(10); + + /* reset video decoder */ + + GPIO(zr, 0, 0); + mdelay(10); + GPIO(zr, 0, 1); + mdelay(10); + + /* reset JPEG codec */ + zr36060_sleep(zr, 0); + mdelay(10); + zr36060_reset(zr); + mdelay(10); + zr36060_sleep(zr, 1); + mdelay(10); + + /* display codec revision */ + if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev); + kfree((void *) zr->stat_com); + return -1; + } + break; + + case BOARD_LML33: +// btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); +// udelay(100); +// btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); +// udelay(1000); + + /* + * Set up the GPIO direction + */ + btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR); + /* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */ + btwrite(0xFF00F888, ZR36057_GPPGCR1); + mdelay(10); + GPIO(zr, 5, 0); /* Analog video bypass */ + udelay(3000); + GPIO(zr, 0, 0); /* Reset 819 */ + udelay(3000); + GPIO(zr, 0, 1); /* 819 back */ + udelay(3000); + /* reset JPEG codec */ + zr36060_sleep(zr, 0); + udelay(3000); + zr36060_reset(zr); + udelay(3000); + zr36060_sleep(zr, 1); + udelay(3000); + + /* display codec revision */ + if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); +// kfree((void *) zr->stat_com); +// return -1; + } + break; + } + /* i2c */ + memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus)); + sprintf(zr->i2c.name, "zoran%u%u", zr->id); + zr->i2c.data = zr; + if (i2c_register_bus(&zr->i2c) < 0) { + kfree((void *) zr->stat_com); + return -1; + } + /* + * Now add the template and register the device unit. + */ + memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); + sprintf(zr->video_dev.name, "zoran%u", zr->id); + if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) { + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + /* toggle JPEG codec sleep to sync PLL */ + zr36060_sleep(zr, 1); + mdelay(10); + zr36060_sleep(zr, 0); + mdelay(10); + + /* Enable bus-mastering */ + pci_set_master(zr->pci_dev); + + j = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + /* set individual interrupt enables (without GIRQ0) + but don't global enable until zoran_open() */ + + btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR); + + if(request_irq(zr->pci_dev->irq, zoran_irq, + SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0) + { + printk(KERN_ERR "%s: Can't assign irq.\n", zr->name); + video_unregister_device(&zr->video_dev); + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + zr->initialized = 1; + return 0; +} + + + +static void release_zoran(void) +{ + u8 command; + int i; + struct zoran *zr; + + for (i = 0; i < zoran_num; i++) { + zr = &zoran[i]; + + if (!zr->initialized) + continue; + + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + + /* disable PCI bus-mastering */ + pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); + + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + + free_irq(zr->pci_dev->irq, zr); + + /* unmap and free memory */ + + kfree((void *) zr->stat_com); + + iounmap(zr->zr36057_mem); + + video_unregister_device(&zr->video_dev); + } +} + +/* + * Scan for a Buz card (actually for the PCI controller ZR36057), + * request the irq and map the io memory + */ + +static int find_zr36057(void) +{ + unsigned char latency; + struct zoran *zr; + struct pci_dev *dev = NULL; + + zoran_num = 0; + + while (zoran_num < BUZ_MAX + && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { + zr = &zoran[zoran_num]; + zr->pci_dev = dev; + zr->zr36057_mem = NULL; + zr->id = zoran_num; + sprintf(zr->name, "zoran%u", zr->id); + + spin_lock_init(&zr->lock); + + zr->zr36057_adr = zr->pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; + pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); + if (zr->revision < 2) { + printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", + zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); + } else { + unsigned short ss_vendor_id, ss_id; + + pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor_id); + pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_ID, &ss_id); + printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", + zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); + printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n", + zr->name, ss_vendor_id, ss_id); + if(ss_vendor_id==0xFF10 && ss_id == 0xDE41) + { + zr->board = BOARD_LML33; + printk(KERN_INFO "%s: LML33 detected.\n", zr->name); + } + } + + zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000); + + /* set PCI latency timer */ + pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); + if (latency != 48) { + printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency); + latency = 48; + pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency); + } + zoran_num++; + } + if (zoran_num == 0) + printk(KERN_INFO "zoran: no cards found.\n"); + + return zoran_num; +} + +#include "chipsets.h" + +static void handle_chipset(void) +{ + int index; + struct pci_dev *dev = NULL; + + for (index = 0; index < sizeof(black) / sizeof(black[0]); index++) { + if ((dev = pci_find_device(black[index].vendor, black[index].device, dev)) != NULL) { + printk(KERN_INFO ": Host bridge: %s, ", black[index].name); + switch (black[index].action) { + + case TRITON: + printk("enabling Triton support.\n"); + triton = 1; + break; + + case NATOMA: + printk("enabling Natoma workaround.\n"); + natoma = 1; + break; + } + } + } +} + +#ifdef MODULE +int init_module(void) +#else +int init_zoran_cards(struct video_init *unused) +#endif +{ + int i; + + + printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n"); + + /* Look for Buz cards */ + + if (find_zr36057() <= 0) { + return -EIO; + } + printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num); + + if (zoran_num == 0) + return -ENXIO; + + + /* check the parameters we have been given, adjust if necessary */ + + if (v4l_nbufs < 0) + v4l_nbufs = 0; + if (v4l_nbufs > VIDEO_MAX_FRAME) + v4l_nbufs = VIDEO_MAX_FRAME; + /* The user specfies the in KB, we want them in byte (and page aligned) */ + v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); + if (v4l_bufsize < 32768) + v4l_bufsize = 32768; + /* 2 MB is arbitrary but sufficient for the maximum possible images */ + if (v4l_bufsize > 2048 * 1024) + v4l_bufsize = 2048 * 1024; + + printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10); + + /* Use parameter for vidmem or try to find a video card */ + + if (vidmem) { + printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem); + } + + /* check if we have a Triton or Natome chipset */ + + handle_chipset(); + + /* take care of Natoma chipset and a revision 1 zr36057 */ + + for (i = 0; i < zoran_num; i++) { + if (natoma && zoran[i].revision <= 1) { + zoran[i].need_contiguous = 1; + printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name); + } else { + zoran[i].need_contiguous = 0; + } + } + + /* initialize the Buzs */ + + /* We have to know which ones must be released if an error occurs */ + for (i = 0; i < zoran_num; i++) + zoran[i].initialized = 0; + + for (i = 0; i < zoran_num; i++) { + if (zr36057_init(i) < 0) { + release_zoran(); + return -EIO; + } + } + + return 0; +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + release_zoran(); +} + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/buz.h linux/drivers/char/buz.h --- v2.3.9/linux/drivers/char/buz.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/buz.h Mon Jul 5 20:07:02 1999 @@ -0,0 +1,319 @@ +/* + buz - Iomega Buz driver + + Copyright (C) 1999 Rainer Johanni + + based on + + buz.0.0.3 Copyright (C) 1998 Dave Perks + + and + + bttv - Bt848 frame grabber driver + Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _BUZ_H_ +#define _BUZ_H_ + +/* The Buz only supports a maximum width of 720, but some V4L + applications (e.g. xawtv are more happy with 768). + If XAWTV_HACK is defined, we try to fake a device with bigger width */ + +#define XAWTV_HACK + +#ifdef XAWTV_HACK +#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ +#else +#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ +#endif +#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ +#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ +#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ + +struct zoran_requestbuffers { + unsigned long count; /* Number of buffers for MJPEG grabbing */ + unsigned long size; /* Size PER BUFFER in bytes */ +}; + +struct zoran_sync { + unsigned long frame; /* number of buffer that has been free'd */ + unsigned long length; /* number of code bytes in buffer (capture only) */ + unsigned long seq; /* frame sequence number */ + struct timeval timestamp; /* timestamp */ +}; + +struct zoran_status { + int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ + int signal; /* Returned: 1 if valid video signal detected */ + int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int color; /* Returned: 1 if color signal detected */ +}; + +struct zoran_params { + + /* The following parameters can only be queried */ + + int major_version; /* Major version number of driver */ + int minor_version; /* Minor version number of driver */ + + /* Main control parameters */ + + int input; /* Input channel: 0 = Composite, 1 = S-VHS */ + int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int decimation; /* decimation of captured video, + enlargement of video played back. + Valid values are 1, 2, 4 or 0. + 0 is a special value where the user + has full control over video scaling */ + + /* The following parameters only have to be set if decimation==0, + for other values of decimation they provide the data how the image is captured */ + + int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ + int VerDcm; /* Vertical decimation: 1 or 2 */ + int TmpDcm; /* Temporal decimation: 1 or 2, + if TmpDcm==2 in capture every second frame is dropped, + in playback every frame is played twice */ + int field_per_buff; /* Number of fields per buffer: 1 or 2 */ + int img_x; /* start of image in x direction */ + int img_y; /* start of image in y direction */ + int img_width; /* image width BEFORE decimation, + must be a multiple of HorDcm*16 */ + int img_height; /* image height BEFORE decimation, + must be a multiple of VerDcm*8 */ + + /* --- End of parameters for decimation==0 only --- */ + + /* JPEG control parameters */ + + int quality; /* Measure for quality of compressed images. + Scales linearly with the size of the compressed images. + Must be beetween 0 and 100, 100 is a compression + ratio of 1:4 */ + + int odd_even; /* Which field should come first ??? */ + + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + unsigned long jpeg_markers; /* Which markers should go into the JPEG output. + Unless you exactly know what you do, leave them untouched. + Inluding less markers will make the resulting code + smaller, but there will be fewer aplications + which can read it. + The presence of the APP and COM marker is + influenced by APP0_len and COM_len ONLY! */ +#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ + + int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. + If this flag is turned on and JPEG decompressing + is going to the screen, the decompress process + is stopped every time the Video Fifo is full. + This enables a smooth decompress to the screen + but the video output signal will get scrambled */ + + /* Misc */ + + char reserved[312]; /* Makes 512 bytes for this structure */ +}; + +/* + Private IOCTL to set up for displaying MJPEG + */ +#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) +#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) +#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) +#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) +#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) +#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) +#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) + + +#ifdef __KERNEL__ + +#define BUZ_NUM_STAT_COM 4 +#define BUZ_MASK_STAT_COM 3 + +#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ +#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ + +#if VIDEO_MAX_FRAME <= 32 +#define V4L_MAX_FRAME 32 +#elif VIDEO_MAX_FRAME <= 64 +#define V4L_MAX_FRAME 64 +#else +#error "Too many video frame buffers to handle" +#endif +#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) + + +#include "zr36057.h" + +enum zoran_codec_mode { + BUZ_MODE_IDLE, /* nothing going on */ + BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ + BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ + BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ + BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ +}; + +enum zoran_buffer_state { + BUZ_STATE_USER, /* buffer is owned by application */ + BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ + BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ + BUZ_STATE_DONE /* buffer is ready to return to application */ +}; + +struct zoran_gbuffer { + u32 *frag_tab; /* addresses of frag table */ + u32 frag_tab_bus; /* same value cached to save time in ISR */ + enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ + struct zoran_sync bs; /* DONE: info to return to application */ +}; + +struct v4l_gbuffer { + char *fbuffer; /* virtual address of frame buffer */ + unsigned long fbuffer_phys; /* physical address of frame buffer */ + unsigned long fbuffer_bus; /* bus address of frame buffer */ + enum zoran_buffer_state state; /* state: unused/pending/done */ +}; + +struct zoran { + struct video_device video_dev; + struct i2c_bus i2c; + + int initialized; /* flag if zoran has been correctly initalized */ + int user; /* number of current users (0 or 1) */ + + unsigned short id; /* number of this device */ + char name[32]; /* name of this device */ + struct pci_dev *pci_dev; /* PCI device */ + unsigned char revision; /* revision of zr36057 */ + int board; /* Board type */ +#define BOARD_BUZ 0 +#define BOARD_LML33 1 + unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *zr36057_mem; /* pointer to mapped IO memory */ + + int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ + + spinlock_t lock; /* Spinlock */ + + /* Video for Linux parameters */ + + struct video_picture picture; /* Current picture params */ + struct video_buffer buffer; /* Current buffer params */ + struct video_window window; /* Current window params */ + int buffer_set, window_set; /* Flags if the above structures are set */ + int video_interlace; /* Image on screen is interlaced */ + + u32 *overlay_mask; + + wait_queue_head_t v4l_capq; /* wait here for grab to finish */ + + int v4l_overlay_active; /* Overlay grab is activated */ + int v4l_memgrab_active; /* Memory grab is activated */ + + int v4l_grab_frame; /* Frame number being currently grabbed */ +#define NO_GRAB_ACTIVE (-1) + int v4l_grab_seq; /* Number of frames grabbed */ + int gwidth; /* Width of current memory capture */ + int gheight; /* Height of current memory capture */ + int gformat; /* Format of ... */ + int gbpl; /* byte per line of ... */ + + /* V4L grab queue of frames pending */ + + unsigned v4l_pend_head; + unsigned v4l_pend_tail; + int v4l_pend[V4L_MAX_FRAME]; + + struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ + + /* Buz MJPEG parameters */ + + unsigned long jpg_nbufs; /* Number of buffers */ + unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ + int jpg_buffers_allocated; /* Flag if buffers are allocated */ + int need_contiguous; /* Flag if contiguous buffers are needed */ + + enum zoran_codec_mode codec_mode; /* status of codec */ + struct zoran_params params; /* structure with a lot of things to play with */ + + wait_queue_head_t jpg_capq; /* wait here for grab to finish */ + + /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ + /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ + /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ + unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ + unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ + unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ + unsigned long jpg_que_tail; /* Index of last buffer in queue */ + unsigned long jpg_seq_num; /* count of frames since grab/play started */ + + /* zr36057's code buffer table */ + u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + + /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ + int jpg_pend[BUZ_MAX_FRAME]; + + /* array indexed by frame number */ + struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ +}; + +#endif + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BUZ in the Makefile. */ + +#ifdef _ALPHA_BUZ +#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) +#define btread(adr) readl(zr->zr36057_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) +#define btread(adr) readl(zr->zr36057_mem+(adr)) +#endif + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_SAA7111 0x48 +#define I2C_SAA7185 0x88 + +#define TDA9850_CON1 0x04 +#define TDA9850_CON2 0x05 +#define TDA9850_CON3 0x06 +#define TDA9850_CON4 0x07 +#define TDA9850_ALI1 0x08 +#define TDA9850_ALI2 0x09 +#define TDA9850_ALI3 0x0a + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.3.9/linux/drivers/char/bw-qcam.c Fri Mar 26 13:57:41 1999 +++ linux/drivers/char/bw-qcam.c Mon Jul 5 20:07:02 1999 @@ -159,6 +159,8 @@ struct qcam_device *q; q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + if(q==NULL) + return NULL; q->pport = port; q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, @@ -1045,7 +1047,7 @@ close_bwqcam(qcams[i]); } #else -__initfunc(int init_bw_qcams(struct video_init *unused)) +int __init init_bw_qcams(struct video_init *unused) { struct parport *port; diff -u --recursive --new-file v2.3.9/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.3.9/linux/drivers/char/c-qcam.c Wed Dec 16 12:53:13 1998 +++ linux/drivers/char/c-qcam.c Mon Jul 5 20:07:02 1999 @@ -1,6 +1,6 @@ /* * Video4Linux Colour QuickCam driver - * Copyright 1997-1998 Philip Blundell + * Copyright 1997-1999 Philip Blundell * */ @@ -294,7 +294,7 @@ if (is_bi_dir) { /* Turn the port around */ - parport_frob_control(q->pport, 0x20, 0x20); + parport_data_reverse(q->pport); mdelay(3); qcam_set_ack(q, 0); if (qcam_await_ready1(q, 1)) { @@ -336,7 +336,7 @@ { printk("qcam: short read.\n"); if (is_bi_dir) - parport_frob_control(q->pport, 0x20, 0); + parport_data_forward(q->pport); qc_setup(q); return len; } @@ -355,11 +355,11 @@ if (qcam_await_ready1(q, 1)) { printk("qcam: no ack after EOF\n"); - parport_frob_control(q->pport, 0x20, 0); + parport_data_forward(q->pport); qc_setup(q); return len; } - parport_frob_control(q->pport, 0x20, 0); + parport_data_forward(q->pport); mdelay(3); qcam_set_ack(q, 1); if (qcam_await_ready1(q, 0)) @@ -641,12 +641,14 @@ struct qcam_device *q; q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + if(q==NULL) + return NULL; q->pport = port; q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, NULL, 0, NULL); - q->bidirectional = (q->pport->modes & PARPORT_MODE_PCPS2)?1:0; + q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0; if (q->pdev == NULL) { @@ -678,10 +680,7 @@ struct qcam_device *qcam; if (num_cams == MAX_CAMS) - { - printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); return -ENOSPC; - } qcam = qcam_init(port); if (qcam==NULL) @@ -725,19 +724,40 @@ kfree(qcam); } -#define BANNER "Connectix Colour Quickcam driver v0.02\n" +#define BANNER "Connectix Colour Quickcam driver v0.03" -#ifdef MODULE -int init_module(void) +static void cq_attach(struct parport *port) +{ + init_cqcam(port); +} + +static void cq_detach(struct parport *port) +{ + /* Write this some day. */ +} + +static struct parport_driver cqcam_driver = { + "cqcam", + cq_attach, + cq_detach, + NULL +}; + +static void cqcam_init(void) { - struct parport *port; + printk(BANNER "\n"); + parport_register_driver(&cqcam_driver); +} - printk(BANNER); +#ifdef MODULE - for (port = parport_enumerate(); port; port=port->next) - init_cqcam(port); +MODULE_AUTHOR("Philip Blundell "); +MODULE_DESCRIPTION(BANNER); - return (num_cams)?0:-ENODEV; +int init_module(void) +{ + cqcam_init(); + return 0; } void cleanup_module(void) @@ -747,14 +767,9 @@ close_cqcam(qcams[i]); } #else -__initfunc(int init_colour_qcams(struct video_init *unused)) +int __init init_colour_qcams(struct video_init *unused) { - struct parport *port; - - printk(BANNER); - - for (port = parport_enumerate(); port; port=port->next) - init_cqcam(port); + cqcam_init(); return 0; } #endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/chipsets.h linux/drivers/char/chipsets.h --- v2.3.9/linux/drivers/char/chipsets.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/chipsets.h Mon Jul 5 20:07:02 1999 @@ -0,0 +1,41 @@ +static const struct { + unsigned short vendor; + unsigned short device; + enum { + TRITON, + NATOMA + } action; + const char *name; +} black[] = { + + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, TRITON, "82437" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, TRITON, "82437VX Triton II" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, TRITON, "82439HX Triton II" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, TRITON, "82439TX" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, NATOMA, "82441FX Natoma" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, NATOMA, "440LX - 82443LX PAC Host" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, NATOMA, "440LX - 82443LX PAC AGP" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, NATOMA, "440BX - 82443BX Host" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, NATOMA, "440BX - 82443BX AGP" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, NATOMA, "440BX - 82443BX Host (no AGP)" + }, +}; diff -u --recursive --new-file v2.3.9/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.3.9/linux/drivers/char/console.c Tue May 11 14:37:40 1999 +++ linux/drivers/char/console.c Tue Jul 6 19:16:55 1999 @@ -2282,7 +2282,7 @@ struct tty_driver console_driver; static int console_refcount; -__initfunc(unsigned long con_init(unsigned long kmem_start)) +unsigned long __init con_init(unsigned long kmem_start) { const char *display_desc = NULL; unsigned int currcons = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c --- v2.3.9/linux/drivers/char/consolemap.c Tue Dec 29 14:28:37 1998 +++ linux/drivers/char/consolemap.c Tue Jul 6 19:16:55 1999 @@ -671,8 +671,8 @@ * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) * from this function, hence the call from sys_setup. */ -__initfunc(void -console_map_init(void)) +void __init +console_map_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.3.9/linux/drivers/char/cyclades.c Mon May 24 22:38:07 1999 +++ linux/drivers/char/cyclades.c Tue Jul 6 19:05:48 1999 @@ -1,7 +1,7 @@ #define BLOCKMOVE #define Z_WAKE static char rcsid[] = -"$Revision: 2.2.2.2 $$Date: 1999/05/21 17:18:15 $"; +"$Revision: 2.2.2.3 $$Date: 1999/06/28 11:13:29 $"; /* * linux/drivers/char/cyclades.c @@ -31,6 +31,16 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.2.2.3 1999/06/28 11:13:29 ivan + * Added support for interrupt mode operation for the Z cards; + * Removed the driver inactivity control for the Z; + * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when + * the Z firmware is not loaded yet; + * Replaced the "manual" Z Tx flush buffer by a call to a FW command of + * same functionality; + * Implemented workaround for IRQ setting loss on the PCI configuration + * registers after a PCI bridge EEPROM reload (affects PLX9060 only); + * * Revision 2.2.2.2 1999/05/14 17:18:15 ivan * /proc entry location changed to /proc/tty/driver/cyclades; * Added support to shared IRQ's (only for PCI boards); @@ -528,7 +538,7 @@ constant in the definition below. No other change is necessary to support more boards/ports. */ -#define NR_PORTS 128 +#define NR_PORTS 256 #define ZE_V1_NPORTS 64 #define ZO_V1 0 @@ -810,13 +820,15 @@ #ifndef CONFIG_COBALT_27 static void cy_probe(int, void *, struct pt_regs *); #endif /* CONFIG_COBALT_27 */ -static void cyz_poll(unsigned long); #ifdef CYCLOM_SHOW_STATUS static void show_status(int); #endif static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *); +#ifndef CONFIG_CYZ_INTR +static void cyz_poll(unsigned long); + /* The Cyclades-Z polling cycle is defined by this variable */ static long cyz_polling_cycle = CZ_DEF_POLL; @@ -825,6 +837,7 @@ cyz_timerlist = { NULL, NULL, 0, 0, cyz_poll }; +#endif /* CONFIG_CYZ_INTR */ /************************************************** error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long)); @@ -1197,7 +1210,7 @@ if((cinfo = (struct cyclades_card *)dev_id) == 0){ #ifdef CY_DEBUG_INTERRUPTS - printk("cy_interrupt: spurious interrupt %d\n\r", irq); + printk("cyy_interrupt: spurious interrupt %d\n\r", irq); #endif return; /* spurious interrupt */ } @@ -1229,7 +1242,7 @@ } if (status & CySRReceive) { /* reception interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); + printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); #endif /* determine the channel & change to that context */ save_xir = (u_char) cy_readb(base_addr+(CyRIR<base_addr + ID_ADDRESS); + if (!ISZLOADED(*cinfo)) { +#ifdef CY_DEBUG_INTERRUPTS + printk("cyz_interrupt: board not yet loaded (INT %d).\n\r", irq); +#endif + return; + } + + zfw_ctrl = (struct ZFW_CTRL *) + (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr)); + board_ctrl = &(zfw_ctrl->board_ctrl); + fw_ver = cy_readl(&board_ctrl->fw_version); + hw_ver = cy_readl(&((struct RUNTIME_9060 *) + (cinfo->ctl_addr))->mail_box_0); + + while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { + special_count = 0; + info = &cy_port[channel + cinfo->first_line]; + if((tty = info->tty) == 0) continue; + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); + buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); + + switch(cmd){ + case C_CM_PR_ERROR: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + *tty->flip.char_buf_ptr++ = 0; + special_count++; + break; + case C_CM_FR_ERROR: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + *tty->flip.char_buf_ptr++ = 0; + special_count++; + break; + case C_CM_RXBRK: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + *tty->flip.char_buf_ptr++ = 0; + special_count++; + break; + case C_CM_MDCD: + if (info->flags & ASYNC_CHECK_CD){ + if ((fw_ver > 241 ? + ((u_long)param) : + cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) { + /* SP("Open Wakeup\n"); */ + cy_sched_event(info, + Cy_EVENT_OPEN_WAKEUP); + }else if(!((info->flags + & ASYNC_CALLOUT_ACTIVE) + &&(info->flags + & ASYNC_CALLOUT_NOHUP))){ + /* SP("Hangup\n"); */ + cy_sched_event(info, + Cy_EVENT_HANGUP); + } + } + break; + case C_CM_MCTS: + if (info->flags & ASYNC_CTS_FLOW) { + if(info->tty->hw_stopped){ + if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){ + /* cy_start isn't used because... + HW flow is handled by the board */ + /* SP("Write Wakeup\n"); */ + cy_sched_event(info, + Cy_EVENT_WRITE_WAKEUP); + } + }else{ + if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){ + /* cy_stop isn't used because + HW flow is handled by the board */ + /* SP("Write stop\n"); */ + } + } + } + break; + case C_CM_MRI: + break; + case C_CM_MDSR: + break; +#ifdef Z_WAKE + case C_CM_IOCTLW: + cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP); + break; +#endif + case C_CM_RXHIWM: + case C_CM_RXNNDT: + /* Reception Interrupt */ +#ifdef CY_DEBUG_INTERRUPTS + printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r", + info->card, channel); +#endif + + rx_get = cy_readl(&buf_ctrl->rx_get); + rx_put = cy_readl(&buf_ctrl->rx_put); + rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize); + if (rx_put >= rx_get) + char_count = rx_put - rx_get; + else + char_count = rx_put - rx_get + rx_bufsize; + + if ( char_count ){ + +#ifdef CY_ENABLE_MONITORING + info->mon.int_count++; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; +#endif + info->idle_stats.recv_bytes += char_count; + info->idle_stats.recv_idle = jiffies; + if( tty == 0){ + /* flush received characters */ + rx_get = (rx_get + char_count) & (rx_bufsize - 1); + /* SP("-"); */ + info->rflush_count++; + }else{ +#ifdef BLOCKMOVE + /* we'd like to use memcpy(t, f, n) and memset(s, c, count) + for performance, but because of buffer boundaries, there + may be several steps to the operation */ + while(0 < (small_count + = cy_min((rx_bufsize - rx_get), + cy_min((TTY_FLIPBUF_SIZE - tty->flip.count), + char_count)))){ + + memcpy_fromio(tty->flip.char_buf_ptr, + (char *)(cinfo->base_addr + + cy_readl(&buf_ctrl->rx_bufaddr) + + rx_get), + small_count); + + tty->flip.char_buf_ptr += small_count; + memset(tty->flip.flag_buf_ptr, + TTY_NORMAL, + small_count); + tty->flip.flag_buf_ptr += small_count; + rx_get = (rx_get + small_count) & (rx_bufsize - 1); + char_count -= small_count; + tty->flip.count += small_count; + } +#else + while(char_count--){ + if (tty->flip.count >= TTY_FLIPBUF_SIZE){ + break; + } + data = cy_readb(cinfo->base_addr + + cy_readl(&buf_ctrl->rx_bufaddr) + rx_get); + rx_get = (rx_get + 1) & (rx_bufsize - 1); + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = data; + } +#endif + queue_task(&tty->flip.tqueue, &tq_timer); + } + /* Update rx_get */ + cy_writel(&buf_ctrl->rx_get, rx_get); + } + break; + case C_CM_TXBEMPTY: + case C_CM_TXLOWWM: + case C_CM_INTBACK: + /* Transmission Interrupt */ +#ifdef CY_DEBUG_INTERRUPTS + printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r", + info->card, channel); +#endif + + tx_get = cy_readl(&buf_ctrl->tx_get); + tx_put = cy_readl(&buf_ctrl->tx_put); + tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); + if (tx_put >= tx_get) + char_count = tx_get - tx_put - 1 + tx_bufsize; + else + char_count = tx_get - tx_put - 1; + + if ( char_count ){ + + if( tty == 0 ){ + goto ztxdone; + } + + if(info->x_char) { /* send special char */ + data = info->x_char; + + cy_writeb((cinfo->base_addr + + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data); + tx_put = (tx_put + 1) & (tx_bufsize - 1); + info->x_char = 0; + char_count--; + } +#ifdef BLOCKMOVE + while(0 < (small_count + = cy_min((tx_bufsize - tx_put), + cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail), + cy_min(info->xmit_cnt, char_count))))){ + + memcpy_toio((char *)(cinfo->base_addr + + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), + &info->xmit_buf[info->xmit_tail], + small_count); + + tx_put = (tx_put + small_count) & (tx_bufsize - 1); + char_count -= small_count; + info->xmit_cnt -= small_count; + info->xmit_tail = + (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1); + } +#else + while (info->xmit_cnt && char_count){ + data = info->xmit_buf[info->xmit_tail]; + info->xmit_cnt--; + info->xmit_tail = + (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); + + cy_writeb(cinfo->base_addr + + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put, + data); + tx_put = (tx_put + 1) & (tx_bufsize - 1); + char_count--; + } + +#endif + ztxdone: + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + /* Update tx_put */ + cy_writel(&buf_ctrl->tx_put, tx_put); + } + break; + case C_CM_FATAL: + /* should do something with this !!! */ + break; + } + if(special_count){ + queue_task(&tty->flip.tqueue, &tq_timer); + } + } + + return; } /* cyz_interrupt */ +#else /* CONFIG_CYZ_INTR */ static void cyz_poll(unsigned long arg) @@ -1675,7 +1961,6 @@ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); if (!ISZLOADED(*cinfo)) { - cinfo->inact_ctrl = 0; continue; } @@ -1686,12 +1971,6 @@ hw_ver = cy_readl(&((struct RUNTIME_9060 *) (cinfo->ctl_addr))->mail_box_0); - /* Enables the firmware inactivity control */ - if ((fw_ver > 0x00000310L) && (!cinfo->inact_ctrl)) { - param = cyz_issue_cmd( &cy_card[card], 0L, C_CM_TINACT, 0L); - cinfo->inact_ctrl = 1; - } - while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1){ char_count = 0; info = &cy_port[ channel + cinfo->first_line ]; @@ -1922,17 +2201,13 @@ } /* poll every 40 ms */ cyz_timerlist.expires = jiffies + cyz_polling_cycle; - - /* refresh inactivity counter */ - if (cinfo->inact_ctrl) { - cy_writel(&board_ctrl->inactivity, (uclong) ZF_TINACT); - } } add_timer(&cyz_timerlist); return; } /* cyz_poll */ +#endif /* CONFIG_CYZ_INTR */ /********** End of block of Cyclades-Z specific code *********/ /***********************************************************/ @@ -2053,12 +2328,27 @@ cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE); #ifdef Z_WAKE +#ifdef CONFIG_CYZ_INTR cy_writel(&ch_ctrl[channel].intr_enable, - C_IN_MDCD|C_IN_MCTS|C_IN_IOCTLW); + C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT| + C_IN_IOCTLW| + C_IN_MDCD|C_IN_MCTS); #else cy_writel(&ch_ctrl[channel].intr_enable, + C_IN_IOCTLW| C_IN_MDCD|C_IN_MCTS); -#endif +#endif /* CONFIG_CYZ_INTR */ +#else +#ifdef CONFIG_CYZ_INTR + cy_writel(&ch_ctrl[channel].intr_enable, + C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT| + C_IN_MDCD|C_IN_MCTS); +#else + cy_writel(&ch_ctrl[channel].intr_enable, + C_IN_MDCD|C_IN_MCTS); +#endif /* CONFIG_CYZ_INTR */ +#endif /* Z_WAKE */ + retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L); /* was C_CM_RESET */ if (retval != 0){ @@ -2126,11 +2416,21 @@ cy_readb(base_addr+(CySRER<card].intr_enabled) { + retval = cyz_issue_cmd(&cy_card[info->card], + 0, C_CM_IRQ_ENBL, 0L); + if (retval != 0){ + printk("cyc:IRQ enable retval was %x\n", retval); + } + cy_card[info->card].intr_enabled = 1; + } + } +#endif /* CONFIG_CYZ_INTR */ } #ifdef CY_DEBUG_OTHER printk("cyc:cy_open ttyC%d\n", info->line); /* */ @@ -2640,7 +2956,6 @@ printk("Not clean (jiff=%lu)...", jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -2653,7 +2968,6 @@ } /* Run one more char cycle */ current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time * 5); current->state = TASK_RUNNING; #ifdef CY_DEBUG_WAIT_UNTIL_SENT @@ -3798,14 +4112,14 @@ if (break_state == -1) { if (!info->breakon) { info->breakon = 1; - if (!info->xmit_cnt ) { + if (!info->xmit_cnt) { start_xmit(info); } } } else { if (!info->breakoff) { info->breakoff = 1; - if (!info->xmit_cnt ) { + if (!info->xmit_cnt) { start_xmit(info); } } @@ -4053,6 +4367,7 @@ case CYGETCD1400VER: ret_val = info->chip_rev; break; +#ifndef CONFIG_CYZ_INTR case CYZSETPOLLCYCLE: cyz_polling_cycle = (arg * HZ) / 1000; ret_val = 0; @@ -4060,6 +4375,7 @@ case CYZGETPOLLCYCLE: ret_val = (cyz_polling_cycle * 1000) / HZ; break; +#endif /* CONFIG_CYZ_INTR */ case CYSETWAIT: info->closing_wait = (unsigned short)arg * HZ/100; ret_val = 0; @@ -4333,7 +4649,7 @@ cy_flush_buffer(struct tty_struct *tty) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel; + int card, channel, retval; unsigned long flags; #ifdef CY_DEBUG_IO @@ -4351,19 +4667,10 @@ if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board buffers as well */ - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; - - firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr + - cy_readl(&firm_id->zfwctrl_addr)); - ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); - buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); - - while (cy_readl(&buf_ctrl->tx_get) != cy_readl(&buf_ctrl->tx_put)) - cy_writel(&buf_ctrl->tx_put, cy_readl(&buf_ctrl->tx_get)); + retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L); + if (retval != 0) { + printk("cyc: flush_buffer retval was %x\n", retval); + } } wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) @@ -4410,8 +4717,8 @@ /* initialize chips on Cyclom-Y card -- return number of valid chips (which is number of ports/4) */ -__initfunc(static unsigned short -cyy_init_card(volatile ucchar *true_base_addr,int index)) +static unsigned short __init +cyy_init_card(volatile ucchar *true_base_addr,int index) { unsigned int chip_number; volatile ucchar* base_addr; @@ -4496,8 +4803,7 @@ * sets global variables and return the number of ISA boards found. * --------------------------------------------------------------------- */ -__initfunc(static int -cy_detect_isa(void)) +static int __init cy_detect_isa(void) { unsigned short cy_isa_irq,nboard; volatile ucchar *cy_isa_address; @@ -4604,8 +4910,8 @@ * sets global variables and return the number of PCI boards found. * --------------------------------------------------------------------- */ -__initfunc(static int -cy_detect_pci(void)) +static int __init +cy_detect_pci(void) { #ifdef CONFIG_PCI @@ -4872,10 +5178,11 @@ return(i); } +#ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ - if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { - if(request_irq(cy_pci_irq,cyz_interrupt, - SA_SHIRQ,"Cyclades-Z",&cy_card[j])) + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { + if(request_irq(cy_pci_irq, cyz_interrupt, + SA_SHIRQ, "Cyclades-Z", &cy_card[j])) { printk("Could not allocate IRQ%d ", cy_pci_irq); @@ -4884,6 +5191,7 @@ return(i); } } +#endif /* CONFIG_CYZ_INTR */ /* set cy_card */ @@ -4896,7 +5204,7 @@ /* print message */ /* don't report IRQ if board is no IRQ */ - if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) { + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", j+1,(ulong)cy_pci_addr2, (ulong)(cy_pci_addr2 + CyPCI_Zwin - 1), @@ -4908,6 +5216,11 @@ } printk("%d channels starting from port %d.\n", cy_pci_nchan,cy_next_channel); +#ifdef CONFIG_CYZ_INTR + /* Enable interrupts on the PLX chip */ + cy_writew(cy_pci_addr0+0x68, + cy_readw(cy_pci_addr0+0x68)|0x0900); +#endif /* CONFIG_CYZ_INTR */ cy_next_channel += cy_pci_nchan; } } @@ -4927,10 +5240,6 @@ (ulong)cy_pci_addr2, (ulong)cy_pci_addr0); printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n"); #endif - /* The following clears the firmware id word. This ensures - that the driver will not attempt to talk to the board - until it has been properly initialized. - */ PAUSE /* This must be the new Cyclades-Ze/PCI. */ cy_pci_nchan = ZE_V1_NPORTS; @@ -4955,10 +5264,11 @@ return(i); } +#ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ - if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { - if(request_irq(cy_pci_irq,cyz_interrupt, - SA_SHIRQ,"Cyclades-Z",&cy_card[j])) + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { + if(request_irq(cy_pci_irq, cyz_interrupt, + SA_SHIRQ, "Cyclades-Z", &cy_card[j])) { printk("Could not allocate IRQ%d ", cy_pci_irq); @@ -4967,6 +5277,7 @@ return(i); } } +#endif /* CONFIG_CYZ_INTR */ /* set cy_card */ cy_card[j].base_addr = cy_pci_addr2; @@ -4978,7 +5289,7 @@ /* print message */ /* don't report IRQ if board is no IRQ */ - if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) { + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", j+1,(ulong)cy_pci_addr2, (ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1), @@ -4990,6 +5301,11 @@ } printk("%d channels starting from port %d.\n", cy_pci_nchan,cy_next_channel); +#ifdef CONFIG_CYZ_INTR + /* Enable interrupts on the PLX chip */ + cy_writew(cy_pci_addr0+0x68, + cy_readw(cy_pci_addr0+0x68)|0x0900); +#endif /* CONFIG_CYZ_INTR */ cy_next_channel += cy_pci_nchan; } if (ZeIndex != 0) { @@ -5098,8 +5414,8 @@ extra ports are ignored. */ -__initfunc(int -cy_init(void)) +int __init +cy_init(void) { struct cyclades_port *info; struct cyclades_card *cinfo; @@ -5219,6 +5535,7 @@ mailbox = cy_readl(&((struct RUNTIME_9060 *) cy_card[board].ctl_addr)->mail_box_0); nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; + cinfo->intr_enabled = 0; for (port = cinfo->first_line ; port < cinfo->first_line + nports; port++) @@ -5342,15 +5659,17 @@ } } } - - if ( number_z_boards && !cyz_timeron){ - cyz_timeron++; + +#ifndef CONFIG_CYZ_INTR + if (number_z_boards && !cyz_timeron){ + cyz_timeron++; cyz_timerlist.expires = jiffies + 1; add_timer(&cyz_timerlist); #ifdef CY_PCI_DEBUG printk("Cyclades-Z polling initialized\n"); #endif } +#endif /* CONFIG_CYZ_INTR */ #ifdef CY_PROC ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0); @@ -5377,10 +5696,12 @@ int e1, e2; unsigned long flags; +#ifndef CONFIG_CYZ_INTR if (cyz_timeron){ cyz_timeron = 0; del_timer(&cyz_timerlist); } +#endif /* CONFIG_CYZ_INTR */ save_flags(flags); cli(); remove_bh(CYCLADES_BH); @@ -5396,6 +5717,9 @@ for (i = 0; i < NR_CARDS; i++) { if (cy_card[i].base_addr != 0 +#ifndef CONFIG_CYZ_INTR + && cy_card[i].num_chips != -1 /* not a Z card */ +#endif /* CONFIG_CYZ_INTR */ && cy_card[i].irq) { free_irq(cy_card[i].irq, &cy_card[i]); diff -u --recursive --new-file v2.3.9/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c --- v2.3.9/linux/drivers/char/dn_keyb.c Sat May 15 15:05:36 1999 +++ linux/drivers/char/dn_keyb.c Tue Jul 6 19:16:55 1999 @@ -570,7 +570,7 @@ APOLLO_MOUSE_MINOR, "apollomouse", &apollo_mouse_fops }; -__initfunc(int dn_keyb_init(void)) { +int __init dn_keyb_init(void){ /* printk("dn_keyb_init\n"); */ diff -u --recursive --new-file v2.3.9/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.3.9/linux/drivers/char/dsp56k.c Sat Oct 31 11:05:37 1998 +++ linux/drivers/char/dsp56k.c Tue Jul 6 19:16:55 1999 @@ -519,8 +519,7 @@ /****** Init and module functions ******/ - -__initfunc(int dsp56k_init(void)) +int __init dsp56k_init(void) { if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) { printk("DSP56k driver: Hardware not present\n"); diff -u --recursive --new-file v2.3.9/linux/drivers/char/dz.c linux/drivers/char/dz.c --- v2.3.9/linux/drivers/char/dz.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/char/dz.c Mon Jul 5 20:35:18 1999 @@ -16,6 +16,8 @@ * field from "current" - somewhere between 2.1.121 and 2.1.131 */ +#define DEBUG_DZ 1 + #ifdef MODULE #include #include @@ -41,8 +43,10 @@ /* for definition of struct console */ #ifdef CONFIG_SERIAL_CONSOLE #define CONSOLE_LINE (3) -#include #endif /* ifdef CONFIG_SERIAL_CONSOLE */ +#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) +#include +#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */ #include #include @@ -54,13 +58,8 @@ #include #include -#define DEBUG_DZ 1 #ifdef DEBUG_DZ -#include -#include #include -#include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.3.9/linux/drivers/char/esp.c Wed May 12 13:27:37 1999 +++ linux/drivers/char/esp.c Tue Jul 6 19:16:55 1999 @@ -2180,7 +2180,6 @@ while ((serial_in(info, UART_ESI_STAT1) != 0x03) || (serial_in(info, UART_ESI_STAT2) != 0xff)) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; schedule_timeout(char_time); if (signal_pending(current)) @@ -2526,7 +2525,7 @@ /* * The serial driver boot-time initialization code! */ -__initfunc(int espserial_init(void)) +int __init espserial_init(void) { int i, offset; int region_start; diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-init.c linux/drivers/char/ftape/lowlevel/ftape-init.c --- v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-init.c Tue Dec 2 09:33:16 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-init.c Tue Jul 6 19:16:55 1999 @@ -64,7 +64,7 @@ /* Called by modules package when installing the driver * or by kernel during the initialization phase */ -__initfunc(int ftape_init(void)) +int __init ftape_init(void) { TRACE_FUN(ft_t_flow); diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-proc.c linux/drivers/char/ftape/lowlevel/ftape-proc.c --- v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-proc.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/char/ftape/lowlevel/ftape-proc.c Tue Jul 6 19:16:55 1999 @@ -112,6 +112,7 @@ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* get_block */ NULL, /* readpage */ NULL, /* writepage */ @@ -420,7 +421,7 @@ return len; } -__initfunc(int ftape_proc_init(void)) +int __init ftape_proc_init(void) { return FT_PROC_REGISTER(&proc_root, &proc_ftape); } diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-setup.c linux/drivers/char/ftape/lowlevel/ftape-setup.c --- v2.3.9/linux/drivers/char/ftape/lowlevel/ftape-setup.c Tue Nov 25 14:45:27 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-setup.c Tue Jul 6 19:16:55 1999 @@ -60,7 +60,7 @@ { "mach2", &ft_mach2, CONFIG_FT_MACH2, 0, 1} }; -__initfunc(void ftape_setup(char *str, int *ints)) +void __init ftape_setup(char *str, int *ints) { int i; int param; diff -u --recursive --new-file v2.3.9/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c --- v2.3.9/linux/drivers/char/ftape/zftape/zftape-init.c Sun Mar 7 10:42:26 1999 +++ linux/drivers/char/ftape/zftape/zftape-init.c Tue Jul 6 19:16:55 1999 @@ -414,7 +414,7 @@ /* Called by modules package when installing the driver or by kernel * during the initialization phase */ -__initfunc(int zft_init(void)) +int __init zft_init(void) { TRACE_FUN(ft_t_flow); diff -u --recursive --new-file v2.3.9/linux/drivers/char/hfmodem/main.c linux/drivers/char/hfmodem/main.c --- v2.3.9/linux/drivers/char/hfmodem/main.c Wed May 12 13:27:37 1999 +++ linux/drivers/char/hfmodem/main.c Tue Jul 6 19:16:55 1999 @@ -62,7 +62,6 @@ #if LINUX_VERSION_CODE >= 0x20100 #include #else -#include #include #undef put_user @@ -160,7 +159,7 @@ } /* --------------------------------------------------------------------- */ -__initfunc(static int check_lpt(struct hfmodem_state *dev, unsigned int iobase)) +static int __init check_lpt(struct hfmodem_state *dev, unsigned int iobase) { struct parport *pp = parport_enumerate(); @@ -179,7 +178,7 @@ enum uart { c_uart_unknown, c_uart_8250, c_uart_16450, c_uart_16550, c_uart_16550A }; static const char *uart_str[] __initdata = { "unknown", "8250", "16450", "16550", "16550A" }; -__initfunc(static enum uart check_uart(unsigned int iobase)) +static enum uart __init check_uart(unsigned int iobase) { unsigned char b1,b2,b3; enum uart u; @@ -215,7 +214,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(static int check_midi(unsigned int iobase)) +static int __init check_midi(unsigned int iobase) { unsigned long timeout; unsigned long flags; @@ -263,7 +262,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(static void output_check(struct hfmodem_state *dev)) +static void __init output_check(struct hfmodem_state *dev) { enum uart u = c_uart_unknown; @@ -625,7 +624,7 @@ #endif -__initfunc(int init_module(void)) +int __init init_module(void) { int i; @@ -678,7 +677,7 @@ static int hw = 0; -__initfunc(void hfmodem_setup(char *str, int *ints)) +void __init hfmodem_setup(char *str, int *ints) { if (ints[0] < 7) { printk(KERN_WARNING "%s: setup: too few parameters\n", hfmodem_drvname); @@ -699,7 +698,7 @@ hfmodem_refclock_setscale(ints[ints[0]-2], ints[ints[0]-1], ints[ints[0]]); } -__initfunc(void hfmodem_init(void)) +void __init hfmodem_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/char/hfmodem/refclock.c linux/drivers/char/hfmodem/refclock.c --- v2.3.9/linux/drivers/char/hfmodem/refclock.c Sat Jul 18 11:47:49 1998 +++ linux/drivers/char/hfmodem/refclock.c Tue Jul 6 19:16:55 1999 @@ -66,7 +66,7 @@ /* --------------------------------------------------------------------- */ #ifdef __i386__ -__initfunc(static void i386_capability(void)) +static void __init i386_capability(void) { if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) rdtsc_ok = 1; @@ -77,7 +77,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(void hfmodem_refclock_probe(void)) +void __init hfmodem_refclock_probe(void) { #ifdef __i386__ if (rdtsc_ok) { diff -u --recursive --new-file v2.3.9/linux/drivers/char/i2c-parport.c linux/drivers/char/i2c-parport.c --- v2.3.9/linux/drivers/char/i2c-parport.c Sat May 22 15:02:48 1999 +++ linux/drivers/char/i2c-parport.c Thu Jul 1 14:22:56 1999 @@ -36,9 +36,7 @@ static struct parport_i2c_bus *bus_list; -#ifdef __SMP__ static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED; -#endif /* software I2C functions */ diff -u --recursive --new-file v2.3.9/linux/drivers/char/i2c.c linux/drivers/char/i2c.c --- v2.3.9/linux/drivers/char/i2c.c Thu Jan 14 22:53:02 1999 +++ linux/drivers/char/i2c.c Mon Jul 5 20:07:02 1999 @@ -40,6 +40,14 @@ extern int i2c_tuner_init(void); extern int msp3400c_init(void); #endif +#ifdef CONFIG_VIDEO_BUZ +extern int saa7111_init(void); +extern int saa7185_init(void); +#endif +#ifdef CONFIG_VIDEO_LML33 +extern int bt819_init(void); +extern int bt856_init(void); +#endif int i2c_init(void) { @@ -50,6 +58,14 @@ i2c_tuner_init(); msp3400c_init(); #endif +#ifdef CONFIG_VIDEO_BUZ + saa7111_init(); + saa7185_init(); +#endif +#ifdef CONFIG_VIDEO_LML33 + bt819_init(); + bt856_init(); +#endif return 0; } diff -u --recursive --new-file v2.3.9/linux/drivers/char/joystick/joy-db9.c linux/drivers/char/joystick/joy-db9.c --- v2.3.9/linux/drivers/char/joystick/joy-db9.c Tue Dec 1 19:05:05 1998 +++ linux/drivers/char/joystick/joy-db9.c Thu Jul 1 14:22:57 1999 @@ -337,7 +337,7 @@ return port; } - if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2))) { + if (!(pp->modes & PARPORT_MODE_TRISTATE)) { printk(KERN_ERR "js-db9: specified parport is not bidirectional\n"); return port; } diff -u --recursive --new-file v2.3.9/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.3.9/linux/drivers/char/lp.c Wed May 12 08:41:12 1999 +++ linux/drivers/char/lp.c Thu Jul 1 14:22:57 1999 @@ -27,6 +27,9 @@ * Obsoleted the CAREFUL flag since a printer that doesn' t work with * CAREFUL will block a bit after in lp_check_status(). * Andrea Arcangeli, 15 Oct 1998 + * Obsoleted and removed all the lowlevel stuff implemented in the last + * month to use the IEEE1284 functions (that handle the _new_ compatibilty + * mode fine). */ /* This driver should, in theory, work with any parallel port that has an @@ -58,74 +61,6 @@ * # insmod lp.o reset=1 */ -/* - * LP OPTIMIZATIONS - * - * - TRUST_IRQ flag - * - * Epson Stylus Color, HP and many other new printers want the TRUST_IRQ flag - * set when printing with interrupts. This is a long story. Such printers - * use a broken handshake (see the timing graph below) when printing with - * interrupts. The lp driver as default is just able to handle such bogus - * handshake, but setting such flag cause lp to go faster and probably do - * what such printers want (even if not documented). - * - * NOTE that setting the TRUST_IRQ flag in some printer can cause the irq - * printing to fail completly. You must try, to know if your printer - * will handle it. I suggest a graphics printing to force a major flow of - * characters to the printer for do the test. NOTE also that the TRUST_IRQ - * flag _should_ be fine everywhere but there is a lot of buggy hardware out - * there, so I am forced to implement it as a not-default thing. - * WARNING: before to do the test, be sure to have not played with the - * `-w' parameter of tunelp! - * - * Note also that lp automagically warn you (with a KERN_WARNING) if it - * detects that you could _try_ to set the TRUST_IRQ flag to speed up the - * printing and decrease the CPU load. - * - * To set the TRUST_IRQ flag you can use this command: - * - * tunelp /dev/lp? -T on - * - * If you have an old tunelp executable you can (hack and) use this simple - * C lazy proggy to set the flag in the lp driver: - --------------------------- cut here ------------------------------------- -#include -#include - -#define LPTRUSTIRQ 0x060f - -int main(int argc, char **argv) -{ - int fd = open("/dev/lp0", O_RDONLY); - ioctl(fd, LPTRUSTIRQ, argc - 1); - if (argc - 1) - printf("trusting the irq\n"); - else - printf("untrusting the irq\n"); - return 0; -} --------------------------- cut here ------------------------------------- - - * - LP_WAIT time - * - * You can use this setting if your printer is fast enough and/or your - * machine is slow enough ;-). - * - * tunelp /dev/lp? -w 0 - * - * - LP_CHAR tries - * - * If you print with irqs probably you can decrease the CPU load a lot using - * this setting. This is not the default because the printing is reported to - * be jerky somewhere... - * - * tunelp /dev/lp? -c 1 - * - * 11 Nov 1998, Andrea Arcangeli - */ - /* COMPATIBILITY WITH OLD KERNELS * * Under Linux 2.0 and previous versions, lp devices were bound to ports at @@ -162,6 +97,15 @@ * this case fine too. * * 15 Oct 1998, Andrea Arcangeli + * + * The so called `buggy' handshake is really the well documented + * compatibility mode IEEE1284 handshake. They changed the well known + * Centronics handshake acking in the middle of busy expecting to not + * break drivers or legacy application, while they broken linux lp + * until I fixed it reverse engineering the protocol by hand some + * month ago... + * + * 14 Dec 1998, Andrea Arcangeli */ #include @@ -175,6 +119,8 @@ #include #include #include +#include +#include #include #undef LP_STATS @@ -189,6 +135,8 @@ struct lp_struct lp_table[LP_NO]; +static unsigned int lp_count = 0; + /* Test if printer is ready */ #define LP_READY(status) ((status) & LP_PBUSY) /* Test if the printer is not acking the strobe */ @@ -197,7 +145,9 @@ #define LP_NO_ERROR(status) ((status) & LP_PERRORP) #undef LP_DEBUG -#undef LP_READ_DEBUG + +/* If you want to see if you can get lp_poll working, define this. */ +#undef SUPPORT_POLL /* --- parport support ----------------------------------------- */ @@ -205,15 +155,62 @@ { struct lp_struct *lps = (struct lp_struct *)handle; - if (waitqueue_active (&lps->wait_q)) - wake_up_interruptible(&lps->wait_q); + if (!(lps->flags & LP_PORT_BUSY)) { + /* Let the port go. */ + clear_bit (LP_HAVE_PORT_BIT, &lps->flags); + return 0; + } + + if (!(lps->flags & LP_PORT_BUSY)) { + /* Let the port go. */ + clear_bit (LP_HAVE_PORT_BIT, &lps->flags); + return 0; + } /* Don't actually release the port now */ return 1; } -#define lp_parport_release(x) do { parport_release(lp_table[(x)].dev); } while (0); -#define lp_parport_claim(x) do { parport_claim_or_block(lp_table[(x)].dev); } while (0); +static void lp_check_data (struct lp_struct *lp) +{ +#if !defined(CONFIG_PARPORT_1284) || !defined (SUPPORT_POLL) + return; +#else + struct pardevice *dev = lp->dev; + if (!(lp->flags & LP_NO_REVERSE)) { + int err = parport_negotiate (dev->port, IEEE1284_MODE_NIBBLE); + if (err) + lp->flags |= LP_NO_REVERSE; + else { + unsigned char s = parport_read_status (dev->port); + if (s & PARPORT_STATUS_ERROR) + lp->flags &= ~LP_DATA_AVAIL; + else { + lp->flags |= LP_DATA_AVAIL; + if (waitqueue_active (&lp->dataq)) + wake_up_interruptible (&lp->dataq); + } + } + } +#endif /* IEEE 1284 support */ +} + +static void lp_parport_release (int minor) +{ + lp_check_data (&lp_table[minor]); + if (test_and_clear_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags)) + parport_release (lp_table[minor].dev); + + lp_table[minor].flags &= ~LP_PORT_BUSY; +} + +static void lp_parport_claim (int minor) +{ + if (!test_and_set_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags)) + parport_claim_or_block (lp_table[minor].dev); + + lp_table[minor].flags |= LP_PORT_BUSY; +} /* --- low-level port access ----------------------------------- */ @@ -222,29 +219,6 @@ #define w_ctr(x,y) do { parport_write_control(lp_table[(x)].dev->port, (y)); } while (0) #define w_dtr(x,y) do { parport_write_data(lp_table[(x)].dev->port, (y)); } while (0) -static __inline__ void lp_yield (int minor) -{ - if (!parport_yield_blocking (lp_table[minor].dev)) - { - if (current->need_resched) - schedule (); - } else - lp_table[minor].irq_missed = 1; -} - -static __inline__ void lp_schedule(int minor, long timeout) -{ - struct pardevice *dev = lp_table[minor].dev; - register unsigned long int timeslip = (jiffies - dev->time); - if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) { - lp_parport_release(minor); - lp_table[minor].irq_missed = 1; - schedule_timeout(timeout); - lp_parport_claim(minor); - } else - schedule_timeout(timeout); -} - static int lp_reset(int minor) { int retval; @@ -257,161 +231,51 @@ return retval; } -#define lp_wait(minor) udelay(LP_WAIT(minor)) - -static inline int lp_char(char lpchar, int minor) +static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - unsigned long count = 0; -#ifdef LP_STATS - struct lp_stats *stats; -#endif - - if (signal_pending(current)) - return 0; - - for (;;) - { - unsigned char status; - int irq_ok = 0; - - /* - * Give a chance to other pardevice to run in the meantime. - */ - lp_yield(minor); - - status = r_str(minor); - if (LP_NO_ERROR(status)) - { - if (LP_READY(status)) - break; - - /* - * This is a crude hack that should be well known - * at least by Epson device driver developers. -arca - */ - irq_ok = (!LP_POLLED(minor) && - LP_NO_ACKING(status) && - lp_table[minor].irq_detected); - if ((LP_F(minor) & LP_TRUST_IRQ) && irq_ok) - break; - } - /* - * NOTE: if you run with irqs you _must_ use - * `tunelp /dev/lp? -c 1' to be rasonable efficient! - */ - 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); - -#ifdef LP_STATS - stats = &LP_STAT(minor); - stats->chars++; -#endif + struct lp_struct *lp_dev = (struct lp_struct *) dev_id; + if (!(lp_dev->flags & LP_PORT_BUSY)) + /* We must have the port since we got an interrupt. */ + lp_check_data (lp_dev); + if (waitqueue_active (&lp_dev->waitq)) + wake_up_interruptible (&lp_dev->waitq); +} - /* must wait before taking strobe high, and after taking strobe - low, according spec. Some printers need it, others don't. */ - lp_wait(minor); +static void lp_wakeup (void *handle) +{ + struct lp_struct *lp_dev = handle; - /* control port takes strobe high */ - if (LP_POLLED(minor)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE); - lp_wait(minor); - w_ctr(minor, LP_PSELECP | LP_PINITP); - } else { - /* - * Epson Stylus Color generate the IRQ on the rising edge of - * strobe so clean the irq's information before playing with - * the strobe. -arca - */ - lp_table[minor].irq_detected = 0; - lp_table[minor].irq_missed = 0; - /* - * Be sure that the CPU doesn' t reorder instructions. -arca - */ - mb(); - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE | LP_PINTEN); - lp_wait(minor); - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); - } - - /* - * Give to the printer a chance to put BUSY low. Really we could - * remove this because we could _guess_ that we are slower to reach - * again lp_char() than the printer to put BUSY low, but I' d like - * to remove this variable from the function I go solve - * when I read bug reports ;-). -arca - */ - lp_wait(minor); + if (lp_dev->flags & LP_PORT_BUSY) + return; -#ifdef LP_STATS - /* update waittime statistics */ - if (count > stats->maxwait) { -#ifdef LP_DEBUG - printk(KERN_DEBUG "lp%d success after %d counts.\n", - minor, count); -#endif - stats->maxwait = count; + /* Grab the port if it can help (i.e. reverse mode is possible). */ + if (!(lp_dev->flags & LP_NO_REVERSE)) { + parport_claim (lp_dev->dev); + set_bit (LP_HAVE_PORT_BIT, &lp_dev->flags); + lp_check_data (lp_dev); + if (waitqueue_active (&lp_dev->waitq)) + wake_up_interruptible (&lp_dev->waitq); } - count *= 256; - wait = (count > stats->meanwait) ? count - stats->meanwait : - stats->meanwait - count; - stats->meanwait = (255 * stats->meanwait + count + 128) / 256; - stats->mdev = ((127 * stats->mdev) + wait + 64) / 128; -#endif - - return 1; } -static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void lp_error (int minor) { - struct lp_struct *lp_dev = (struct lp_struct *) dev_id; + int polling; - if (waitqueue_active (&lp_dev->wait_q)) - wake_up_interruptible(&lp_dev->wait_q); - - lp_dev->irq_detected = 1; - lp_dev->irq_missed = 0; -} + if (LP_F(minor) & LP_ABORT) + return; -static void lp_error(int minor) -{ - if (LP_POLLED(minor) || LP_PREEMPTED(minor)) { - current->state = TASK_INTERRUPTIBLE; - lp_parport_release(minor); - schedule_timeout(LP_TIMEOUT_POLLED); - lp_parport_claim(minor); - lp_table[minor].irq_missed = 1; - } + polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE; + if (polling) lp_parport_release (minor); + interruptible_sleep_on_timeout (&lp_table[minor].waitq, + LP_TIMEOUT_POLLED); + if (polling) lp_parport_claim (minor); + else parport_yield_blocking (lp_table[minor].dev); } static int lp_check_status(int minor) { + int error = 0; unsigned int last = lp_table[minor].last_error; unsigned char status = r_str(minor); if (status & LP_PERRORP) @@ -422,155 +286,112 @@ last = LP_POUTPA; printk(KERN_INFO "lp%d out of paper\n", minor); } + error = -ENOSPC; } else if (!(status & LP_PSELECD)) { if (last != LP_PSELECD) { last = LP_PSELECD; printk(KERN_INFO "lp%d off-line\n", minor); } + error = -EIO; } else { if (last != LP_PERRORP) { last = LP_PERRORP; printk(KERN_INFO "lp%d on fire\n", minor); } + error = -EIO; } lp_table[minor].last_error = last; - if (last != 0) { - if (LP_F(minor) & LP_ABORT) - return 1; + if (last != 0) lp_error(minor); - } - return 0; + return error; } -static int lp_write_buf(unsigned int minor, const char *buf, int count) +static ssize_t lp_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) { - unsigned long copy_size; - unsigned long total_bytes_written = 0; - unsigned long bytes_written; - struct lp_struct *lp = &lp_table[minor]; - - if (minor >= LP_NO) - return -ENXIO; - if (lp->dev == NULL) - return -ENXIO; - - lp_table[minor].last_error = 0; - lp_table[minor].irq_detected = 0; - lp_table[minor].irq_missed = 1; - - if (LP_POLLED(minor)) - w_ctr(minor, LP_PSELECP | LP_PINITP); - else - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); - - do { - bytes_written = 0; - copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); - - if (copy_from_user(lp->lp_buffer, buf, copy_size)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP); - return -EFAULT; - } + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct parport *port = lp_table[minor].dev->port; + char *kbuf = lp_table[minor].lp_buffer; + ssize_t retv = 0; + ssize_t written; + size_t copy_size = count; - while (copy_size) { - if (lp_char(lp->lp_buffer[bytes_written], minor)) { - --copy_size; - ++bytes_written; #ifdef LP_STATS - lp->runchars++; -#endif - } else { - int rc = total_bytes_written + bytes_written; + if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) + lp_table[minor].runchars = 0; -#ifdef LP_STATS - if (lp->runchars > LP_STAT(minor).maxrun) - LP_STAT(minor).maxrun = lp->runchars; - LP_STAT(minor).sleeps++; + lp_table[minor].lastcall = jiffies; #endif - if (signal_pending(current)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP); - if (total_bytes_written + bytes_written) - return total_bytes_written + bytes_written; - else - return -EINTR; - } + /* Need to copy the data from user-space. */ + if (copy_size > LP_BUFFER_SIZE) + copy_size = LP_BUFFER_SIZE; -#ifdef LP_STATS - lp->runchars = 0; -#endif + if (copy_from_user (kbuf, buf, copy_size)) + return -EFAULT; - if (lp_check_status(minor)) - { - w_ctr(minor, LP_PSELECP | LP_PINITP); - return rc ? rc : -EIO; - } + /* Claim Parport or sleep until it becomes available + */ + lp_parport_claim (minor); - if (LP_POLLED(minor) || - lp_table[minor].irq_missed) - { - lp_polling: -#if defined(LP_DEBUG) && defined(LP_STATS) - printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor)); -#endif - current->state = TASK_INTERRUPTIBLE; - lp_schedule(minor, LP_TIME(minor)); - } else { - cli(); - if (LP_PREEMPTED(minor)) - { - /* - * We can' t sleep on the interrupt - * since another pardevice need the port. - * We must check this in a cli() protected - * envinroment to avoid parport sharing - * starvation. - */ - sti(); - goto lp_polling; - } - if (!lp_table[minor].irq_detected) - interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT); - sti(); - } - } - } + /* Go to compatibility mode. */ + parport_negotiate (port, IEEE1284_MODE_COMPAT); - total_bytes_written += bytes_written; - buf += bytes_written; - count -= bytes_written; + do { + /* Wait until lp_read has finished. */ + if (down_interruptible (&lp_table[minor].port_mutex)) + break; - } while (count > 0); + /* Write the data. */ + written = parport_write (port, kbuf, copy_size); + if (written >= 0) { + copy_size -= written; + count -= written; + buf += written; + retv += written; + } - w_ctr(minor, LP_PSELECP | LP_PINITP); - return total_bytes_written; -} + up (&lp_table[minor].port_mutex); -static ssize_t lp_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); - ssize_t retv; + if (signal_pending (current)) { + if (retv == 0) + retv = -EINTR; -#ifdef LP_STATS - if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) - lp_table[minor].runchars = 0; + break; + } - lp_table[minor].lastcall = jiffies; -#endif + if (copy_size > 0) { + /* incomplete write -> check error ! */ + int error = lp_check_status (minor); - /* Claim Parport or sleep until it becomes available - */ - lp_parport_claim (minor); + if (LP_F(minor) & LP_ABORT) { + if (retv == 0) + retv = error; + break; + } - retv = lp_write_buf(minor, buf, count); + parport_yield_blocking (lp_table[minor].dev); + } else if (current->need_resched) + schedule (); + + if (count) { + copy_size = count; + if (copy_size > LP_BUFFER_SIZE) + copy_size = LP_BUFFER_SIZE; + + if (copy_from_user(kbuf, buf, copy_size)) { + if (retv == 0) + retv = -EFAULT; + break; + } + } + } while (count > 0); lp_parport_release (minor); + return retv; } @@ -579,109 +400,54 @@ return -ESPIPE; } -#ifdef CONFIG_PRINTER_READBACK +#ifdef CONFIG_PARPORT_1284 -static int lp_read_nibble(int minor) -{ - unsigned char i; - i = r_str(minor)>>3; - i &= ~8; - if ((i & 0x10) == 0) i |= 8; - return (i & 0x0f); -} - -static void lp_read_terminate(struct parport *port) { - parport_write_control(port, (parport_read_control(port) & ~2) | 8); - /* SelectIN high, AutoFeed low */ - if (parport_wait_peripheral(port, 0x80, 0)) - /* timeout, SelectIN high, Autofeed low */ - return; - parport_write_control(port, parport_read_control(port) | 2); - /* AutoFeed high */ - parport_wait_peripheral(port, 0x80, 0x80); - /* no timeout possible, Autofeed low, SelectIN high */ - parport_write_control(port, (parport_read_control(port) & ~2) | 8); -} - -/* Status readback confirming to ieee1284 */ +/* Status readback conforming to ieee1284 */ static ssize_t lp_read(struct file * file, char * buf, - size_t length, loff_t *ppos) + size_t count, loff_t *ppos) { - int i; unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev); - char *temp = buf; - ssize_t count = 0; - unsigned char z = 0; - unsigned char Byte = 0; struct parport *port = lp_table[minor].dev->port; + ssize_t retval = 0; + char *kbuf = lp_table[minor].lp_buffer; + + if (count > LP_BUFFER_SIZE) + count = LP_BUFFER_SIZE; lp_parport_claim (minor); - switch (parport_ieee1284_nibble_mode_ok(port, 0)) - { - case 0: - /* Handshake failed. */ - lp_read_terminate(port); - lp_parport_release (minor); - return -EIO; - case 1: - /* No data. */ - lp_read_terminate(port); - lp_parport_release (minor); - return 0; - default: - /* Data available. */ + if (!down_interruptible (&lp_table[minor].port_mutex)) { + for (;;) { + retval = parport_read (port, kbuf, count); - /* Hack: Wait 10ms (between events 6 and 7) */ - schedule_timeout((HZ+99)/100); - break; - } + if (retval) + break; - for (i=0; ; i++) { - parport_frob_control(port, 2, 2); /* AutoFeed high */ - if (parport_wait_peripheral(port, 0x40, 0)) { -#ifdef LP_READ_DEBUG - /* Some peripherals just time out when they've sent - all their data. */ - printk("%s: read1 timeout.\n", port->name); -#endif - parport_frob_control(port, 2, 0); /* AutoFeed low */ - break; - } - z = lp_read_nibble(minor); - parport_frob_control(port, 2, 0); /* AutoFeed low */ - if (parport_wait_peripheral(port, 0x40, 0x40)) { - printk("%s: read2 timeout.\n", port->name); - break; - } - if ((i & 1) != 0) { - Byte |= (z<<4); - if (__put_user (Byte, temp)) - { - count = -EFAULT; + if (file->f_flags & O_NONBLOCK) break; - } else { - temp++; - if (++count == length) - break; - } - /* Does the error line indicate end of data? */ - if ((parport_read_status(port) & LP_PERRORP) == - LP_PERRORP) + /* Wait for an interrupt. */ + interruptible_sleep_on_timeout (&lp_table[minor].waitq, + LP_TIMEOUT_POLLED); + + if (signal_pending (current)) { + retval = -EINTR; break; - } else - Byte=z; - } + } + } - lp_read_terminate(port); + up (&lp_table[minor].port_mutex); + } lp_parport_release (minor); - return count; + if (retval > 0 && copy_to_user (buf, kbuf, retval)) + retval = -EFAULT; + + return retval; } -#endif +#endif /* IEEE 1284 support */ static int lp_open(struct inode * inode, struct file * file) { @@ -729,7 +495,6 @@ LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } - init_waitqueue_head(&(lp_table[minor].wait_q)); return 0; } @@ -752,7 +517,7 @@ int retval = 0; #ifdef LP_DEBUG - printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg); + printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg); #endif if (minor >= LP_NO) return -ENODEV; @@ -785,12 +550,6 @@ LP_F(minor) &= ~LP_CAREFUL; break; #endif - case LPTRUSTIRQ: - if (arg) - LP_F(minor) |= LP_TRUST_IRQ; - else - LP_F(minor) &= ~LP_TRUST_IRQ; - break; case LPWAIT: LP_WAIT(minor) = arg; break; @@ -834,16 +593,35 @@ return retval; } +#ifdef CONFIG_PARPORT_1284 +static unsigned int lp_poll (struct file *filp, struct poll_table_struct *wait) +{ + unsigned int minor = MINOR (filp->f_dentry->d_inode->i_rdev); + unsigned int mask = POLLOUT | POLLWRNORM; /* always writable */ + + poll_wait (filp, &lp_table[minor].dataq, wait); + + if (lp_table[minor].flags & LP_DATA_AVAIL) + mask |= POLLIN | POLLRDNORM; + + return mask; +} +#endif /* IEEE 1284 support */ + static struct file_operations lp_fops = { lp_lseek, -#ifdef CONFIG_PRINTER_READBACK +#ifdef CONFIG_PARPORT_1284 lp_read, #else NULL, #endif lp_write, NULL, /* lp_readdir */ - NULL, /* lp_poll */ +#ifdef CONFIG_PARPORT_1284 + lp_poll, +#else + NULL, +#endif lp_ioctl, NULL, /* lp_mmap */ lp_open, @@ -851,6 +629,70 @@ lp_release }; +/* --- support for console on the line printer ----------------- */ + +#ifdef CONFIG_LP_CONSOLE + +#define CONSOLE_LP 0 + +/* If the printer is out of paper, we can either lose the messages or + * stall until the printer is happy again. Define CONSOLE_LP_STRICT + * non-zero to get the latter behaviour. */ +#define CONSOLE_LP_STRICT 1 + +static void lp_console_write (struct console *co, const char *s, + unsigned count) +{ + struct pardevice *dev = lp_table[CONSOLE_LP].dev; + struct parport *port = dev->port; + ssize_t written; + signed long old_to; + + if (!(lp_table[CONSOLE_LP].flags & (1< 0) { + s += written; + count -= written; + } + } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); + + parport_set_timeout (dev, old_to); +} + +static kdev_t lp_console_device (struct console *c) +{ + return MKDEV(LP_MAJOR, CONSOLE_LP); +} + +static struct console lpcons = { + "lp", + lp_console_write, + NULL, + lp_console_device, + NULL, + NULL, + NULL, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +#endif /* console on line printer */ + /* --- initialisation code ------------------------------------- */ #ifdef MODULE @@ -864,8 +706,8 @@ #else -static int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; -static int reset __initdata = 0; +static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; +static int reset = 0; static int parport_ptr = 0; @@ -896,10 +738,10 @@ #endif -int lp_register(int nr, struct parport *port) +static int lp_register(int nr, struct parport *port) { lp_table[nr].dev = parport_register_device(port, "lp", - lp_preempt, NULL, + lp_preempt, lp_wakeup, lp_interrupt, 0, (void *) &lp_table[nr]); @@ -916,13 +758,56 @@ return 0; } -int lp_init(void) +static void lp_attach (struct parport *port) { - unsigned int count = 0; unsigned int i; - struct parport *port; - for(i = 0; i < LP_NO; i++) { + switch (parport_nr[0]) + { + case LP_PARPORT_UNSPEC: + case LP_PARPORT_AUTO: + if (parport_nr[0] == LP_PARPORT_AUTO && + port->probe_info[0].class != PARPORT_CLASS_PRINTER) + return; + + if (!lp_register(lp_count, port)) + if (++lp_count == LP_NO) + break; + + break; + + default: + for (i = 0; i < LP_NO; i++) { + if (port->number == parport_nr[i]) { + if (!lp_register(i, port)) + lp_count++; + break; + } + } + break; + } +} + +static void lp_detach (struct parport *port) +{ + /* Write this some day. */ +} + +static struct parport_driver lp_driver = { + "lp", + lp_attach, + lp_detach, + NULL +}; + +int __init lp_init (void) +{ + int i; + + if (parport_nr[0] == LP_PARPORT_OFF) + return 0; + + for (i = 0; i < LP_NO; i++) { lp_table[i].dev = NULL; lp_table[i].flags = 0; lp_table[i].chars = LP_INIT_CHAR; @@ -932,55 +817,37 @@ #ifdef LP_STATS lp_table[i].lastcall = 0; lp_table[i].runchars = 0; - memset(&lp_table[i].stats, 0, sizeof(struct lp_stats)); + memset (&lp_table[i].stats, 0, sizeof (struct lp_stats)); #endif - init_waitqueue_head(&lp_table[i].wait_q); lp_table[i].last_error = 0; - lp_table[i].irq_detected = 0; - lp_table[i].irq_missed = 0; + init_waitqueue_head (&lp_table[i].waitq); + init_waitqueue_head (&lp_table[i].dataq); + init_MUTEX (&lp_table[i].port_mutex); } - switch (parport_nr[0]) - { - case LP_PARPORT_OFF: - return 0; - - case LP_PARPORT_UNSPEC: - case LP_PARPORT_AUTO: - for (port = parport_enumerate(); port; port = port->next) { - - if (parport_nr[0] == LP_PARPORT_AUTO && - port->probe_info.class != PARPORT_CLASS_PRINTER) - continue; - - if (!lp_register(count, port)) - if (++count == LP_NO) - break; - } - break; + if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) { + printk ("lp: unable to get major %d\n", LP_MAJOR); + return -EIO; + } - default: - for (i = 0; i < LP_NO; i++) { - for (port = parport_enumerate(); port; - port = port->next) { - if (port->number == parport_nr[i]) { - if (!lp_register(i, port)) - count++; - break; - } - } - } - break; + if (parport_register_driver (&lp_driver)) { + printk ("lp: unable to register with parport\n"); + return -EIO; } - if (count) { - if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) { - printk("lp: unable to get major %d\n", LP_MAJOR); - return -EIO; - } - } else { - printk(KERN_INFO "lp: driver loaded but no devices found\n"); + if (!lp_count) { + printk (KERN_INFO "lp: driver loaded but no devices found\n"); +#ifndef CONFIG_PARPORT_12843 + if (parport_nr[0] == LP_PARPORT_AUTO) + printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n"); +#endif + } +#ifdef CONFIG_LP_CONSOLE + else { + register_console (&lpcons); + printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP); } +#endif return 0; } @@ -1018,10 +885,18 @@ { unsigned int offset; + parport_unregister_driver (&lp_driver); + +#ifdef CONFIG_LP_CONSOLE + unregister_console (&lpcons); +#endif + unregister_chrdev(LP_MAJOR, "lp"); for (offset = 0; offset < LP_NO; offset++) { if (lp_table[offset].dev == NULL) continue; + if (lp_table[offset].flags & (1< -#include #include #include #endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c --- v2.3.9/linux/drivers/char/n_hdlc.c Wed Jun 16 19:26:27 1999 +++ linux/drivers/char/n_hdlc.c Mon Jul 5 20:35:18 1999 @@ -100,7 +100,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ #include diff -u --recursive --new-file v2.3.9/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.3.9/linux/drivers/char/pc_keyb.c Tue May 11 14:37:40 1999 +++ linux/drivers/char/pc_keyb.c Mon Jul 5 20:35:18 1999 @@ -38,7 +38,6 @@ #include #include #include -#include /* Some configuration switches are present in the include file... */ diff -u --recursive --new-file v2.3.9/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.3.9/linux/drivers/char/pcwd.c Mon Aug 24 13:14:10 1998 +++ linux/drivers/char/pcwd.c Tue Jul 6 19:05:48 1999 @@ -34,6 +34,9 @@ * 971222 Changed open/close for temperature handling * Michael Meskes . * 980112 Used minor numbers from include/linux/miscdevice.h + * 990605 Made changes to code to support Firmware 1.22a, added + * fairly useless proc entry. + * 990610 removed said useless proc code for the merge */ #include @@ -55,6 +58,7 @@ #include #include #include +#include #include #include @@ -67,7 +71,7 @@ */ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; -#define WD_VER "1.0 (11/18/96)" +#define WD_VER "1.10 (06/05/99)" /* * It should be noted that PCWD_REVISION_B was removed because A and B @@ -99,7 +103,7 @@ * This routine checks the "current_readport" to see if the card lies there. * If it does, it returns accordingly. */ -__initfunc(static int pcwd_checkcard(void)) +static int __init pcwd_checkcard(void) { int card_dat, prev_card_dat, found = 0, count = 0, done = 0; @@ -228,10 +232,9 @@ int i, cdat, rv; static struct watchdog_info ident= { - /* FIXME: should set A/C here */ WDIOF_OVERHEAT|WDIOF_CARDRESET, 1, - "PCWD." + "PCWD" }; switch(cmd) { @@ -408,8 +411,11 @@ switch(MINOR(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: - /* c is in celsius, we need fahrenheit */ - cp = (c*9/5)+32; + /* + * Convert metric to Fahrenheit, since this was + * the decided 'standard' for this return value. + */ + cp = (c * 9 / 5) + 32; if(copy_to_user(buf, &cp, 1)) return -EFAULT; return 1; @@ -450,7 +456,7 @@ return(PCWD_REVISION_C); } -__initfunc(static int send_command(int cmd)) +static int __init send_command(int cmd) { int i; @@ -506,6 +512,38 @@ mode_debug = 0; } +static int pcwd_proc_get_info(char *buffer, char **start, off_t offset, + int length, int inout) +{ + int len; + off_t begin = 0; + + revision = get_revision(); + len = sprintf(buffer, "Version = " WD_VER "\n"); + + if (revision == PCWD_REVISION_A) + len += sprintf(buffer + len, "Revision = A\n"); + else + len += sprintf(buffer + len, "Revision = C\n"); + + if (supports_temp) { + unsigned short c = inb(current_readport); + + len += sprintf(buffer + len, "Temp = Yes\n" + "Current temp = %d (Celsius)\n", + c); + } else + len += sprintf(buffer + len, "Temp = No\n"); + + *start = buffer + (offset); + len -= offset; + + if (len > length) + len = length; + + return len; +} + static struct file_operations pcwd_fops = { NULL, /* Seek */ pcwd_read, /* Read */ @@ -539,14 +577,14 @@ #ifdef MODULE int init_module(void) #else -__initfunc(int pcwatchdog_init(void)) +int __init pcwatchdog_init(void) #endif { int i, found = 0; revision = PCWD_REVISION_A; - printk("pcwd: v%s Ken Hollis (khollis@nurk.org)\n", WD_VER); + printk("pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); /* Initial variables */ is_open = 0; @@ -588,6 +626,9 @@ printk("pcwd: Unable to get revision.\n"); return -1; } + + if (supports_temp) + printk("pcwd: Temperature Option Detected.\n"); debug_off(); diff -u --recursive --new-file v2.3.9/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.3.9/linux/drivers/char/ppdev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ppdev.c Mon Jul 5 20:31:26 1999 @@ -0,0 +1,548 @@ +/* + * linux/drivers/char/ppdev.c + * + * This is the code behind /dev/parport* -- it allows a user-space + * application to use the parport subsystem. + * + * Copyright (C) 1998-9 Tim Waugh + * + * 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. + * + * A /dev/parportxy device node represents an arbitrary device ('y') + * on port 'x'. The following operations are possible: + * + * open do nothing, set up default IEEE 1284 protocol to be COMPAT + * close release port and unregister device (if necessary) + * ioctl + * EXCL register device exclusively (may fail) + * CLAIM (register device first time) parport_claim_or_block + * RELEASE parport_release + * SETMODE set the IEEE 1284 protocol to use for read/write + * DATADIR data_forward / data_reverse + * WDATA write_data + * RDATA read_data + * WCONTROL write_control + * RCONTROL read_control + * FCONTROL frob_control + * RSTATUS read_status + * NEGOT parport_negotiate + * YIELD parport_yield_blocking + * read/write read or write in current IEEE 1284 protocol + * select wait for interrupt (in readfds) + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ppdev.h" + +#define PP_VERSION "ppdev: user-space parallel port driver" +#define CHRDEV "ppdev" + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* The device minor encodes the parport number and (arbitrary) + * pardevice number as (port << 4) | dev. */ +#define PP_PORT(minor) ((minor >> 4) & 0xf) +#define PP_DEV(minor) ((minor) & 0xf) + +struct pp_struct { + struct pardevice * pdev; + wait_queue_head_t irq_wait; + int mode; + unsigned int flags; +}; + +/* pp_struct.flags bitfields */ +#define PP_CLAIMED (1<<0) +#define PP_EXCL (1<<1) + +/* Other constants */ +#define PP_INTERRUPT_TIMEOUT (10 * HZ) /* 10s */ +#define PP_BUFFER_SIZE 256 +#define PARDEVICE_MAX 8 + +static struct pp_struct pp_table[PARPORT_MAX][PARDEVICE_MAX]; + +static loff_t pp_lseek (struct file * file, long long offset, int origin) +{ + return -ESPIPE; +} + +/* This looks a bit like parport_read. The difference is that we don't + * determine the mode to use from the port data, but rather from the + * mode the driver told us to use. */ +static ssize_t do_read (struct pp_struct *pp, void *buf, size_t len) +{ + size_t (*fn) (struct parport *, void *, size_t, int); + struct parport *port = pp->pdev->port; + + switch (pp->mode) { + case IEEE1284_MODE_COMPAT: + /* This is a write-only mode. */ + return -EIO; + + case IEEE1284_MODE_NIBBLE: + fn = port->ops->nibble_read_data; + break; + + case IEEE1284_MODE_BYTE: + fn = port->ops->byte_read_data; + break; + + case IEEE1284_MODE_EPP: + fn = port->ops->epp_read_data; + break; + + case IEEE1284_MODE_ECP: + case IEEE1284_MODE_ECPRLE: + fn = port->ops->ecp_read_data; + break; + + case IEEE1284_MODE_ECPSWE: + fn = parport_ieee1284_ecp_read_data; + break; + + default: + printk (KERN_DEBUG "%s: unknown mode 0x%02x\n", + pp->pdev->name, pp->mode); + return -EINVAL; + } + + return (*fn) (port, buf, len, 0); +} + +/* This looks a bit like parport_write. The difference is that we don't + * determine the mode to use from the port data, but rather from the + * mode the driver told us to use. */ +static ssize_t do_write (struct pp_struct *pp, const void *buf, size_t len) +{ + size_t (*fn) (struct parport *, const void *, size_t, int); + struct parport *port = pp->pdev->port; + + switch (pp->mode) { + case IEEE1284_MODE_NIBBLE: + case IEEE1284_MODE_BYTE: + /* Read-only modes. */ + return -EIO; + + case IEEE1284_MODE_COMPAT: + fn = port->ops->compat_write_data; + break; + + case IEEE1284_MODE_EPP: + fn = port->ops->epp_write_data; + break; + + case IEEE1284_MODE_ECP: + case IEEE1284_MODE_ECPRLE: + fn = port->ops->ecp_write_data; + break; + + case IEEE1284_MODE_ECPSWE: + fn = parport_ieee1284_ecp_write_data; + break; + + default: + printk (KERN_DEBUG "%s: unknown mode 0x%02x\n", + pp->pdev->name, pp->mode); + return -EINVAL; + } + + return (*fn) (port, buf, len, 0); +} + +static ssize_t pp_read (struct file * file, char * buf, size_t count, + loff_t * ppos) +{ + unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev); + unsigned int portnum = PP_PORT (minor); + unsigned int dev = PP_DEV (minor); + char * kbuffer; + ssize_t bytes_read = 0; + ssize_t got = 0; + + if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) { + /* Don't have the port claimed */ + printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n", + minor); + return -EPERM; + } + + kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL); + if (!kbuffer) + return -ENOMEM; + + while (bytes_read < count) { + ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE); + + got = do_read (&pp_table[portnum][dev], kbuffer, need); + + if (got < 0) { + if (!bytes_read) + bytes_read = got; + + break; + } + + if (copy_to_user (kbuffer, buf + bytes_read, got)) { + bytes_read = -EFAULT; + break; + } + + bytes_read += got; + + if (signal_pending (current)) { + if (!bytes_read) + bytes_read = -EINTR; + break; + } + + if (current->need_resched) + schedule (); + } + + kfree (kbuffer); + return bytes_read; +} + +static ssize_t pp_write (struct file * file, const char * buf, size_t count, + loff_t * ppos) +{ + unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev); + unsigned int portnum = PP_PORT (minor); + unsigned int dev = PP_DEV (minor); + char * kbuffer; + ssize_t bytes_written = 0; + ssize_t wrote; + + if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) { + /* Don't have the port claimed */ + printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n", + minor); + return -EPERM; + } + + kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL); + if (!kbuffer) + return -ENOMEM; + + while (bytes_written < count) { + ssize_t n = min(count - bytes_written, PP_BUFFER_SIZE); + + if (copy_from_user (kbuffer, buf + bytes_written, n)) { + bytes_written = -EFAULT; + break; + } + + wrote = do_write (&pp_table[portnum][dev], kbuffer, n); + + if (wrote < 0) { + if (!bytes_written) + bytes_written = wrote; + break; + } + + bytes_written += wrote; + + if (signal_pending (current)) { + if (!bytes_written) + bytes_written = -EINTR; + break; + } + + if (current->need_resched) + schedule (); + } + + kfree (kbuffer); + return bytes_written; +} + +static void pp_irq (int irq, void * private, struct pt_regs * unused) +{ + struct pp_struct * pp = (struct pp_struct *) private; + wake_up_interruptible (&pp->irq_wait); +} + +static int register_device (int minor) +{ + unsigned int portnum = PP_PORT (minor); + unsigned int dev = PP_DEV (minor); + struct parport * port; + struct pardevice * pdev = NULL; + char *name; + int fl; + + name = kmalloc (strlen (CHRDEV) + 3, GFP_KERNEL); + if (name == NULL) + return -ENOMEM; + + sprintf (name, CHRDEV "%02x", minor); + port = parport_enumerate (); /* FIXME: use attach/detach */ + + while (port && port->number != portnum) + port = port->next; + + if (!port) { + printk (KERN_WARNING "%s: no associated port!\n", name); + kfree (name); + return -ENXIO; + } + + fl = (pp_table[portnum][dev].flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; + pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl, + &pp_table[portnum][dev]); + + if (!pdev) { + printk (KERN_WARNING "%s: failed to register device!\n", name); + kfree (name); + return -ENXIO; + } + + pp_table[portnum][dev].pdev = pdev; + printk (KERN_DEBUG "%s: registered pardevice\n", name); + return 0; +} + +static int pp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor = MINOR(inode->i_rdev); + unsigned int portnum = PP_PORT (minor); + unsigned int dev = PP_DEV (minor); + struct parport * port; + + /* First handle the cases that don't take arguments. */ + if (cmd == PPCLAIM) { + if (pp_table[portnum][dev].flags & PP_CLAIMED) { + printk (KERN_DEBUG CHRDEV + "%02x: you've already got it!\n", minor); + return -EINVAL; + } + + /* Deferred device registration. */ + if (!pp_table[portnum][dev].pdev) { + int err = register_device (minor); + if (err) + return err; + } + + parport_claim_or_block (pp_table[portnum][dev].pdev); + pp_table[portnum][dev].flags |= PP_CLAIMED; + return 0; + } + + port = pp_table[portnum][dev].pdev->port; + if (cmd == PPEXCL) { + if (pp_table[portnum][dev].pdev) { + printk (KERN_DEBUG CHRDEV "%02x: too late for PPEXCL; " + "already registered\n", minor); + if (pp_table[portnum][dev].flags & PP_EXCL) + /* But it's not really an error. */ + return 0; + /* There's no chance of making the driver happy. */ + return -EINVAL; + } + + /* Just remember to register the device exclusively + * when we finally do the registration. */ + pp_table[portnum][dev].flags |= PP_EXCL; + return 0; + } + + /* Everything else requires the port to be claimed, so check + * that now. */ + if ((pp_table[portnum][dev].flags & PP_CLAIMED) == 0) { + printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n", + minor); + return -EPERM; + } + + switch (cmd) { + unsigned char reg; + unsigned char mask; + int mode; + + case PPRSTATUS: + reg = parport_read_status (port); + return copy_to_user ((unsigned char *) arg, ®, + sizeof (reg)); + + case PPRDATA: + reg = parport_read_data (port); + return copy_to_user ((unsigned char *) arg, ®, + sizeof (reg)); + + case PPRCONTROL: + reg = parport_read_control (port); + return copy_to_user ((unsigned char *) arg, ®, + sizeof (reg)); + + case PPYIELD: + parport_yield_blocking (pp_table[portnum][dev].pdev); + return 0; + + case PPRELEASE: + parport_release (pp_table[portnum][dev].pdev); + pp_table[portnum][dev].flags &= ~PP_CLAIMED; + return 0; + + case PPSETMODE: + if (copy_from_user (&mode, (int *) arg, sizeof (mode))) + return -EFAULT; + /* FIXME: validate mode */ + pp_table[portnum][dev].mode = mode; + return 0; + + case PPWCONTROL: + if (copy_from_user (®, (unsigned char *) arg, sizeof (reg))) + return -EFAULT; + parport_write_control (port, reg); + return 0; + + case PPWDATA: + if (copy_from_user (®, (unsigned char *) arg, sizeof (reg))) + return -EFAULT; + parport_write_data (port, reg); + return 0; + + case PPFCONTROL: + if (copy_from_user (&mask, (unsigned char *) arg, + sizeof (mask))) + return -EFAULT; + if (copy_from_user (®, 1 + (unsigned char *) arg, + sizeof (reg))) + return -EFAULT; + parport_frob_control (port, mask, reg); + return 0; + + case PPDATADIR: + if (copy_from_user (&mode, (int *) arg, sizeof (mode))) + return -EFAULT; + if (mode) + port->ops->data_reverse (port); + else + port->ops->data_forward (port); + return 0; + + case PPNEGOT: + if (copy_from_user (&mode, (int *) arg, sizeof (mode))) + return -EFAULT; + /* FIXME: validate mode */ + return parport_negotiate (port, mode); + + default: + printk (KERN_DEBUG CHRDEV "%02x: What? (cmd=0x%x\n", minor, + cmd); + return -EINVAL; + } + + /* Keep the compiler happy */ + return 0; +} + +static int pp_open (struct inode * inode, struct file * file) +{ + unsigned int minor = MINOR (inode->i_rdev); + unsigned int portnum = PP_PORT (minor); + unsigned int dev = PP_DEV (minor); + + if (portnum >= PARPORT_MAX) + return -ENXIO; + + if (pp_table[portnum][dev].pdev) + return -EBUSY; + + pp_table[portnum][dev].mode = IEEE1284_MODE_COMPAT; + pp_table[portnum][dev].flags = 0; + init_waitqueue_head (&pp_table[portnum][dev].irq_wait); + + /* Defer the actual device registration until the first claim. + * That way, we know whether or not the driver wants to have + * exclusive access to the port (PPEXCL). + */ + pp_table[portnum][dev].pdev = NULL; + + MOD_INC_USE_COUNT; + return 0; +} + +static int pp_release (struct inode * inode, struct file * file) +{ + unsigned int minor = MINOR (inode->i_rdev); + unsigned int portnum = PP_PORT (minor); + unsigned int dev = PP_DEV (minor); + + if (pp_table[portnum][dev].flags & PP_CLAIMED) { + parport_release (pp_table[portnum][dev].pdev); + printk (KERN_DEBUG CHRDEV "%02x: released pardevice because " + "user-space forgot\n", minor); + } + + if (pp_table[portnum][dev].pdev) { + kfree (pp_table[portnum][dev].pdev->name); + parport_unregister_device (pp_table[portnum][dev].pdev); + pp_table[portnum][dev].pdev = NULL; + printk (KERN_DEBUG CHRDEV "%02x: unregistered pardevice\n", + minor); + } + + MOD_DEC_USE_COUNT; + return 0; +} + +#if 0 +static unsigned int pp_poll (struct file * file, poll_table * wait) +{ + unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev); + poll_wait (file, &pp_table[minor].irq_wait, wait); + return 0; /* FIXME! Return value is wrong here */ +} +#endif + +static struct file_operations pp_fops = { + pp_lseek, + pp_read, + pp_write, + NULL, /* pp_readdir */ + NULL, /* pp_poll */ + pp_ioctl, + NULL, /* pp_mmap */ + pp_open, + NULL, /* pp_flush */ + pp_release +}; + +#ifdef MODULE +#define pp_init init_module +#endif + +int pp_init (void) +{ + if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { + printk (KERN_WARNING CHRDEV ": unable to get major %d\n", + PP_MAJOR); + return -EIO; + } + + printk (KERN_INFO PP_VERSION "\n"); + return 0; +} + +#ifdef MODULE +void cleanup_module (void) +{ + /* Clean up all parport stuff */ + unregister_chrdev (PP_MAJOR, CHRDEV); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.3.9/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h --- v2.3.9/linux/drivers/char/ppdev.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ppdev.h Mon Jul 5 20:31:26 1999 @@ -0,0 +1,65 @@ +/* + * linux/drivers/char/ppdev.h + * + * User-space parallel port device driver (header file). + * + * Copyright (C) 1998-9 Tim Waugh + * + * 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. + * + */ + +#define PP_MAJOR 99 + +#define PP_IOCTL 'p' + +/* Set mode for read/write (e.g. IEEE1284_MODE_EPP) */ +#define PPSETMODE _IOW(PP_IOCTL, 0x80, int) + +/* Read status */ +#define PPRSTATUS _IOR(PP_IOCTL, 0x81, unsigned char) +#define PPWSTATUS OBSOLETE__IOW(PP_IOCTL, 0x82, unsigned char) + +/* Read/write control */ +#define PPRCONTROL _IOR(PP_IOCTL, 0x83, unsigned char) +#define PPWCONTROL _IOW(PP_IOCTL, 0x84, unsigned char) + +struct ppdev_frob_struct { + unsigned char mask; + unsigned char val; +}; +#define PPFCONTROL _IOW(PP_IOCTL, 0x8e, struct ppdev_frob_struct) + +/* Read/write data */ +#define PPRDATA _IOR(PP_IOCTL, 0x85, unsigned char) +#define PPWDATA _IOW(PP_IOCTL, 0x86, unsigned char) + +/* Read/write econtrol (not used) */ +#define PPRECONTROL OBSOLETE__IOR(PP_IOCTL, 0x87, unsigned char) +#define PPWECONTROL OBSOLETE__IOW(PP_IOCTL, 0x88, unsigned char) + +/* Read/write FIFO (not used) */ +#define PPRFIFO OBSOLETE__IOR(PP_IOCTL, 0x89, unsigned char) +#define PPWFIFO OBSOLETE__IOW(PP_IOCTL, 0x8a, unsigned char) + +/* Claim the port to start using it */ +#define PPCLAIM _IO(PP_IOCTL, 0x8b) + +/* Release the port when you aren't using it */ +#define PPRELEASE _IO(PP_IOCTL, 0x8c) + +/* Yield the port (release it if another driver is waiting, + * then reclaim) */ +#define PPYIELD _IO(PP_IOCTL, 0x8d) + +/* Register device exclusively (must be before PPCLAIM). */ +#define PPEXCL _IO(PP_IOCTL, 0x8f) + +/* Data line direction: non-zero for input mode. */ +#define PPDATADIR _IOW(PP_IOCTL, 0x90, int) + +/* Negotiate a particular IEEE 1284 mode. */ +#define PPNEGOT _IOW(PP_IOCTL, 0x91, int) diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-aimslab.c linux/drivers/char/radio-aimslab.c --- v2.3.9/linux/drivers/char/radio-aimslab.c Thu Apr 15 05:42:40 1999 +++ linux/drivers/char/radio-aimslab.c Mon Jul 5 20:07:02 1999 @@ -324,7 +324,7 @@ NULL }; -__initfunc(int rtrack_init(struct video_init *v)) +int __init rtrack_init(struct video_init *v) { if (check_region(io, 2)) { diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-aztech.c linux/drivers/char/radio-aztech.c --- v2.3.9/linux/drivers/char/radio-aztech.c Thu Apr 15 05:42:40 1999 +++ linux/drivers/char/radio-aztech.c Mon Jul 5 20:07:02 1999 @@ -279,7 +279,7 @@ NULL }; -__initfunc(int aztech_init(struct video_init *v)) +int __init aztech_init(struct video_init *v) { if (check_region(io, 2)) { diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c --- v2.3.9/linux/drivers/char/radio-cadet.c Mon Jun 7 16:17:59 1999 +++ linux/drivers/char/radio-cadet.c Mon Jul 5 20:07:02 1999 @@ -1,7 +1,7 @@ -/* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card +/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card * * by Fred Gleason - * Version 0.3.2 + * Version 0.3.3 * * (Loosely) based on code for the Aztech radio card by * @@ -346,17 +346,13 @@ static long cadet_read(struct video_device *v,char *buf,unsigned long count, int nonblock) { - int i=0,c; + int i=0; unsigned char readbuf[RDS_BUFFER]; if(rdsstat==0) { cadet_lock++; rdsstat=1; outb(0x80,io); /* Select RDS fifo */ - c=3*(inb(io)&0x03); - for(i=0;i /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_TERRATEC_PORT */ + +#ifndef CONFIG_RADIO_TERRATEC_PORT +#define CONFIG_RADIO_TERRATEC_PORT 0x590 +#endif + +/**************** this ones are for the terratec *******************/ +#define BASEPORT 0x590 +#define VOLPORT 0x591 +#define WRT_DIS 0x00 +#define CLK_OFF 0x00 +#define IIC_DATA 0x01 +#define IIC_CLK 0x02 +#define DATA 0x04 +#define CLK_ON 0x08 +#define WRT_EN 0x10 +/*******************************************************************/ + +static int io = CONFIG_RADIO_TERRATEC_PORT; +static int users = 0; + +struct tt_device +{ + int port; + int curvol; + unsigned long curfreq; + int muted; +}; + + +/* local things */ + +static void cardWriteVol(int volume) +{ + int i; + volume = volume+(volume * 32); // change both channels + for (i=0;i<8;i++) + { + if (volume & (0x80>>i)) + outb(0x80, VOLPORT); + else outb(0x00, VOLPORT); + } +} + + + +static void tt_mute(struct tt_device *dev) +{ + dev->muted = 1; + cardWriteVol(0); +} + +static int tt_setvol(struct tt_device *dev, int vol) +{ + +// printk(KERN_ERR "setvol called, vol = %d\n", vol); + + if(vol == dev->curvol) { /* requested volume = current */ + if (dev->muted) { /* user is unmuting the card */ + dev->muted = 0; + cardWriteVol(vol); /* enable card */ + } + + return 0; + } + + if(vol == 0) { /* volume = 0 means mute the card */ + cardWriteVol(0); /* "turn off card" by setting vol to 0 */ + dev->curvol = vol; /* track the volume state! */ + return 0; + } + + dev->muted = 0; + + cardWriteVol(vol); + + dev->curvol = vol; + + return 0; + +} + + +/* this is the worst part in this driver */ +/* many more or less strange things are going on here, but hey, it works :) */ + +static int tt_setfreq(struct tt_device *dev, unsigned long freq1) +{ + int freq; + int i; + int p; + int temp; + long rest; + + unsigned char buffer[25]; /* we have to bit shift 25 registers */ + freq = freq1/160; /* convert the freq. to a nice to handel value */ + for(i=24;i>-1;i--) + buffer[i]=0; + + rest = freq*10+10700; /* i once had understood what is going on here */ + /* maybe some wise guy (friedhelm?) can comment this stuff */ + i=13; + p=10; + temp=102400; + while (rest!=0) + { + if (rest%temp == rest) + buffer[i] = 0; + else + { + buffer[i] = 1; + rest = rest-temp; + } + i--; + p--; + temp = temp/2; + } + + for (i=24;i>-1;i--) /* bit shift the values to the radiocard */ + { + if (buffer[i]==1) + { + outb(WRT_EN|DATA, BASEPORT); + outb(WRT_EN|DATA|CLK_ON , BASEPORT); + outb(WRT_EN|DATA, BASEPORT); + } + else + { + outb(WRT_EN|0x00, BASEPORT); + outb(WRT_EN|0x00|CLK_ON , BASEPORT); + } + } + outb(0x00, BASEPORT); + + return 0; +} + +int tt_getsigstr(struct tt_device *dev) /* TODO */ +{ + if (inb(io) & 2) /* bit set = no signal present */ + return 0; + return 1; /* signal present */ +} + + +/* implement the video4linux api */ + +static int tt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct tt_device *tt=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + strcpy(v.name, "ActiveRadio"); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; + v.mode=VIDEO_MODE_AUTO; + strcpy(v.name, "FM"); + v.signal=0xFFFF*tt_getsigstr(tt); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &tt->curfreq, sizeof(tt->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&tt->curfreq, arg,sizeof(tt->curfreq))) + return -EFAULT; + tt_setfreq(tt, tt->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; + v.volume=tt->curvol * 6554; + v.step=6554; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + + if(v.flags&VIDEO_AUDIO_MUTE) + tt_mute(tt); + else + tt_setvol(tt,v.volume/6554); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int tt_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void tt_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct tt_device terratec_unit; + +static struct video_device terratec_radio= +{ + "TerraTec ActiveRadio", + VID_TYPE_TUNER, + VID_HARDWARE_TERRATEC, + tt_open, + tt_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* No poll */ + tt_ioctl, + NULL, + NULL +}; + +__initfunc(int terratec_init(struct video_init *v)) +{ + if (check_region(io, 2)) + { + printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io); + return -EBUSY; + } + + terratec_radio.priv=&terratec_unit; + + if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 2, "terratec"); + printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n"); + + /* mute card - prevents noisy bootups */ + + /* this ensures that the volume is all the way down */ + cardWriteVol(0); + terratec_unit.curvol = 0; + + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("R.OFFERMANNS & others"); +MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); + +EXPORT_NO_SYMBOLS; + +int init_module(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + return terratec_init(NULL); +} + +void cleanup_module(void) +{ + video_unregister_device(&terratec_radio); + release_region(io,2); + printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n"); +} + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/radio-zoltrix.c linux/drivers/char/radio-zoltrix.c --- v2.3.9/linux/drivers/char/radio-zoltrix.c Mon May 10 13:00:10 1999 +++ linux/drivers/char/radio-zoltrix.c Mon Jul 5 20:07:02 1999 @@ -333,7 +333,7 @@ NULL }; -__initfunc(int zoltrix_init(struct video_init *v)) +int __init zoltrix_init(struct video_init *v) { if (check_region(io, 2)) { printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io); diff -u --recursive --new-file v2.3.9/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.3.9/linux/drivers/char/rocket.c Wed May 12 13:27:37 1999 +++ linux/drivers/char/rocket.c Mon Jul 5 20:35:18 1999 @@ -57,14 +57,13 @@ #ifdef MODVERSIONS #include #endif -#include #else /* !NEW_MODULES */ #ifdef MODVERSIONS #define MODULE #endif -#include #endif /* NEW_MODULES */ +#include #include #include #include @@ -154,7 +153,6 @@ /* * NB. we must include the kernel idenfication string in to install the module. */ -#include /*static*/ char kernel_version[] = UTS_RELEASE; #endif @@ -1664,7 +1662,6 @@ jiffies, check_time); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(check_time); if (signal_pending(current)) break; diff -u --recursive --new-file v2.3.9/linux/drivers/char/saa7111.c linux/drivers/char/saa7111.c --- v2.3.9/linux/drivers/char/saa7111.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/saa7111.c Mon Jul 5 20:07:02 1999 @@ -0,0 +1,421 @@ +/* + saa7111 - Philips SAA7111A video decoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEBUG(x) /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct saa7111 { + struct i2c_bus *bus; + int addr; + unsigned char reg[32]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_SAA7111 0x48 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + unsigned long flags; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) +{ + int ack; + unsigned subaddr; + unsigned long flags; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +static int saa7111_read(struct saa7111 *dev, unsigned char subaddr) +{ + int data; + unsigned long flags; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); + data = i2c_readbyte(dev->bus, 1); + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return data; +} + +/* ----------------------------------------------------------------------- */ + +static int saa7111_attach(struct i2c_device *device) +{ + int i; + struct saa7111 *decoder; + + static const unsigned char init[] = + { + 0x00, 0x00, /* 00 - ID byte */ + 0x01, 0x00, /* 01 - reserved */ + + /*front end */ + 0x02, 0xd0, /* 02 - FUSE=3, GUDL=2, MODE=0 */ + 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */ + 0x04, 0x00, /* 04 - GAI1=256 */ + 0x05, 0x00, /* 05 - GAI2=256 */ + + /* decoder */ + 0x06, 0xf6, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ + 0x07, 0xdd, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ + 0x08, 0xc8, /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */ + 0x09, 0x01, /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */ + 0x0a, 0x80, /* 0a - BRIG=128 */ + 0x0b, 0x47, /* 0b - CONT=1.109 */ + 0x0c, 0x40, /* 0c - SATN=1.0 */ + 0x0d, 0x00, /* 0d - HUE=0 */ + 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */ + 0x0f, 0x00, /* 0f - reserved */ + 0x10, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ + 0x11, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */ + 0x12, 0x00, /* 12 - output control 2 */ + 0x13, 0x00, /* 13 - output control 3 */ + 0x14, 0x00, /* 14 - reserved */ + 0x15, 0x00, /* 15 - VBI */ + 0x16, 0x00, /* 16 - VBI */ + 0x17, 0x00, /* 17 - VBI */ + }; + + device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL); + if (decoder == NULL) { + return -ENOMEM; + } + MOD_INC_USE_COUNT; + + memset(decoder, 0, sizeof(struct saa7111)); + strcpy(device->name, "saa7111"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_NTSC; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + + i = saa7111_write_block(decoder, init, sizeof(init)); + if (i < 0) { + printk(KERN_ERR "%s_attach: init status %d\n", device->name, i); + } else { + printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00)); + } + return 0; +} + + +static int saa7111_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7111 *decoder = device->data; + + switch (cmd) { + +#if defined(DECODER_DUMP) + case DECODER_DUMP: + { + int i; + + for (i = 0; i < 32; i += 16) { + int j; + + printk("KERN_DEBUG %s: %03x", device->name, i); + for (j = 0; j < 16; ++j) { + printk(" %02x", saa7111_read(decoder, i + j)); + } + printk("\n"); + } + } + break; +#endif /* defined(DECODER_DUMP) */ + + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *cap = arg; + + cap->flags + = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC + | VIDEO_DECODER_AUTO + | VIDEO_DECODER_CCIR; + cap->inputs = 8; + cap->outputs = 1; + } + break; + + case DECODER_GET_STATUS: + { + int *iarg = arg; + int status; + int res; + + status = saa7111_read(decoder, 0x1f); + res = 0; + if ((status & (1 << 6)) == 0) { + res |= DECODER_STATUS_GOOD; + } + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + default: + case VIDEO_MODE_AUTO: + if ((status & (1 << 5)) != 0) { + res |= DECODER_STATUS_NTSC; + } else { + res |= DECODER_STATUS_PAL; + } + break; + } + if ((status & (1 << 0)) != 0) { + res |= DECODER_STATUS_COLOR; + } + *iarg = res; + } + break; + + case DECODER_SET_NORM: + { + int *iarg = arg; + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40); + break; + + case VIDEO_MODE_PAL: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00); + break; + + case VIDEO_MODE_AUTO: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80); + break; + + default: + return -EINVAL; + + } + decoder->norm = *iarg; + } + break; + + case DECODER_SET_INPUT: + { + int *iarg = arg; + + if (*iarg < 0 || *iarg > 7) { + return -EINVAL; + } + if (decoder->input != *iarg) { + decoder->input = *iarg; + /* select mode */ + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + /* bypass chrominance trap for modes 4..7 */ + saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); + } + } + break; + + case DECODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case DECODER_ENABLE_OUTPUT: + { + int *iarg = arg; + int enable = (*iarg != 0); + + if (decoder->enable != enable) { + decoder->enable = enable; + +// RJ: If output should be disabled (for playing videos), we also need a open PLL. + // The input is set to 0 (where no input source is connected), although this + // is not necessary. + // + // If output should be enabled, we have to reverse the above. + + if (decoder->enable) { + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb)); + saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c); + } else { + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8)); + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04); + saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3)); + } + } + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + if (decoder->bright != pic->brightness) { + /* We want 0 to 255 we get 0-65535 */ + decoder->bright = pic->brightness; + saa7111_write(decoder, 0x0a, decoder->bright >> 8); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 we get 0-65535 */ + decoder->contrast = pic->contrast; + saa7111_write(decoder, 0x0b, decoder->contrast >> 9); + } + if (decoder->sat != pic->colour) { + /* We want 0 to 127 we get 0-65535 */ + decoder->sat = pic->colour; + saa7111_write(decoder, 0x0c, decoder->sat >> 9); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8); + } + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7111 = +{ + "saa7111", /* name */ + I2C_DRIVERID_VIDEODECODER, /* ID */ + I2C_SAA7111, I2C_SAA7111 + 1, + + saa7111_attach, + saa7111_detach, + saa7111_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7111_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7111); +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7111); +} + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/saa7185.c linux/drivers/char/saa7185.c --- v2.3.9/linux/drivers/char/saa7185.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/saa7185.c Mon Jul 5 20:07:02 1999 @@ -0,0 +1,379 @@ +/* + saa7185 - Philips SAA7185B video encoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEBUG(x) x /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct saa7185 { + struct i2c_bus *bus; + int addr; + unsigned char reg[128]; + + int norm; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_SAA7185 0x88 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + unsigned long flags; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) +{ + int ack; + unsigned subaddr; + unsigned long flags; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +/* ----------------------------------------------------------------------- */ + +static const unsigned char init_common[] = +{ + 0x3a, 0x0f, /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */ + + 0x42, 0x6b, /* OVLY0=107 */ + 0x43, 0x00, /* OVLU0=0 white */ + 0x44, 0x00, /* OVLV0=0 */ + 0x45, 0x22, /* OVLY1=34 */ + 0x46, 0xac, /* OVLU1=172 yellow */ + 0x47, 0x0e, /* OVLV1=14 */ + 0x48, 0x03, /* OVLY2=3 */ + 0x49, 0x1d, /* OVLU2=29 cyan */ + 0x4a, 0xac, /* OVLV2=172 */ + 0x4b, 0xf0, /* OVLY3=240 */ + 0x4c, 0xc8, /* OVLU3=200 green */ + 0x4d, 0xb9, /* OVLV3=185 */ + 0x4e, 0xd4, /* OVLY4=212 */ + 0x4f, 0x38, /* OVLU4=56 magenta */ + 0x50, 0x47, /* OVLV4=71 */ + 0x51, 0xc1, /* OVLY5=193 */ + 0x52, 0xe3, /* OVLU5=227 red */ + 0x53, 0x54, /* OVLV5=84 */ + 0x54, 0xa3, /* OVLY6=163 */ + 0x55, 0x54, /* OVLU6=84 blue */ + 0x56, 0xf2, /* OVLV6=242 */ + 0x57, 0x90, /* OVLY7=144 */ + 0x58, 0x00, /* OVLU7=0 black */ + 0x59, 0x00, /* OVLV7=0 */ + + 0x5a, 0x00, /* CHPS=0 */ + 0x5b, 0x76, /* GAINU=118 */ + 0x5c, 0xa5, /* GAINV=165 */ + 0x5d, 0x3c, /* BLCKL=60 */ + 0x5e, 0x3a, /* BLNNL=58 */ + 0x5f, 0x3a, /* CCRS=0, BLNVB=58 */ + 0x60, 0x00, /* NULL */ + +/* 0x61 - 0x66 set according to norm */ + + 0x67, 0x00, /* 0 : caption 1st byte odd field */ + 0x68, 0x00, /* 0 : caption 2nd byte odd field */ + 0x69, 0x00, /* 0 : caption 1st byte even field */ + 0x6a, 0x00, /* 0 : caption 2nd byte even field */ + + 0x6b, 0x91, /* MODIN=2, PCREF=0, SCCLN=17 */ + 0x6c, 0x20, /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */ + 0x6d, 0x00, /* SRCM1=0, CCEN=0 */ + + 0x6e, 0x0e, /* HTRIG=0x00e, approx. centered, at least for PAL */ + 0x6f, 0x00, /* HTRIG upper bits */ + 0x70, 0x20, /* PHRES=0, SBLN=1, VTRIG=0 */ + +/* The following should not be needed */ + + 0x71, 0x15, /* BMRQ=0x115 */ + 0x72, 0x90, /* EMRQ=0x690 */ + 0x73, 0x61, /* EMRQ=0x690, BMRQ=0x115 */ + 0x74, 0x00, /* NULL */ + 0x75, 0x00, /* NULL */ + 0x76, 0x00, /* NULL */ + 0x77, 0x15, /* BRCV=0x115 */ + 0x78, 0x90, /* ERCV=0x690 */ + 0x79, 0x61, /* ERCV=0x690, BRCV=0x115 */ + +/* Field length controls */ + + 0x7a, 0x70, /* FLC=0 */ + +/* The following should not be needed if SBLN = 1 */ + + 0x7b, 0x16, /* FAL=22 */ + 0x7c, 0x35, /* LAL=244 */ + 0x7d, 0x20, /* LAL=244, FAL=22 */ +}; + +static const unsigned char init_pal[] = +{ + 0x61, 0x1e, /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ + 0x62, 0xc8, /* DECTYP=1, BSTA=72 */ + 0x63, 0xcb, /* FSC0 */ + 0x64, 0x8a, /* FSC1 */ + 0x65, 0x09, /* FSC2 */ + 0x66, 0x2a, /* FSC3 */ +}; + +static const unsigned char init_ntsc[] = +{ + 0x61, 0x1d, /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ + 0x62, 0xe6, /* DECTYP=1, BSTA=102 */ + 0x63, 0x1f, /* FSC0 */ + 0x64, 0x7c, /* FSC1 */ + 0x65, 0xf0, /* FSC2 */ + 0x66, 0x21, /* FSC3 */ +}; + +static int saa7185_attach(struct i2c_device *device) +{ + int i; + struct saa7185 *encoder; + + device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL); + if (encoder == NULL) { + return -ENOMEM; + } + MOD_INC_USE_COUNT; + + memset(encoder, 0, sizeof(struct saa7185)); + strcpy(device->name, "saa7185"); + encoder->bus = device->bus; + encoder->addr = device->addr; + encoder->norm = VIDEO_MODE_NTSC; + encoder->enable = 1; + + i = saa7185_write_block(encoder, init_common, sizeof(init_common)); + if (i >= 0) { + i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + } + if (i < 0) { + printk(KERN_ERR "%s_attach: init error %d\n", device->name, i); + } + return 0; +} + + +static int saa7185_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7185 *encoder = device->data; + + switch (cmd) { + + case ENCODER_GET_CAPABILITIES: + { + struct video_encoder_capability *cap = arg; + + cap->flags + = VIDEO_ENCODER_PAL + | VIDEO_ENCODER_NTSC + | VIDEO_ENCODER_SECAM + | VIDEO_ENCODER_CCIR; + cap->inputs = 1; + cap->outputs = 1; + } + break; + + case ENCODER_SET_NORM: + { + int *iarg = arg; + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + break; + + case VIDEO_MODE_PAL: + saa7185_write_block(encoder, init_pal, sizeof(init_pal)); + break; + + case VIDEO_MODE_SECAM: + default: + return -EINVAL; + + } + encoder->norm = *iarg; + } + break; + + case ENCODER_SET_INPUT: + { + int *iarg = arg; + +#if 0 + /* not much choice of inputs */ + if (*iarg != 0) { + return -EINVAL; + } +#else + /* RJ: *iarg = 0: input is from SA7111 + *iarg = 1: input is from ZR36060 */ + + switch (*iarg) { + + case 0: + /* Switch RTCE to 1 */ + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); + break; + + case 1: + /* Switch RTCE to 0 */ + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); + break; + + default: + return -EINVAL; + + } +#endif + } + break; + + case ENCODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case ENCODER_ENABLE_OUTPUT: + { + int *iarg = arg; + + encoder->enable = !!*iarg; + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40)); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7185 = +{ + "saa7185", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_SAA7185, I2C_SAA7185 + 1, + + saa7185_attach, + saa7185_detach, + saa7185_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7185_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7185); +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7185); +} + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.3.9/linux/drivers/char/serial.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/char/serial.c Thu Jul 1 15:09:01 1999 @@ -2380,7 +2380,6 @@ printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; diff -u --recursive --new-file v2.3.9/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c --- v2.3.9/linux/drivers/char/sysrq.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/char/sysrq.c Sat Jul 3 10:42:21 1999 @@ -150,15 +150,6 @@ /* Aux routines for the syncer */ -static void all_files_read_only(void) /* Kill write permissions of all files */ -{ - struct file *file; - - for (file = inuse_filps; file; file = file->f_next) - if (file->f_dentry && atomic_read(&file->f_count) && S_ISREG(file->f_dentry->d_inode->i_mode)) - file->f_mode &= ~2; -} - static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */ { unsigned int major = MAJOR(dev); @@ -192,6 +183,7 @@ struct super_block *sb = get_super(dev); struct vfsmount *vfsmnt; int ret, flags; + struct list_head *p; if (!sb) { printk("Superblock not found\n"); @@ -201,6 +193,15 @@ printk("R/O\n"); return; } + + file_list_lock(); + for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + struct file *file = list_entry(p, struct file, f_list); + if (file->f_dentry && file_count(file) + && S_ISREG(file->f_dentry->d_inode->i_mode)) + file->f_mode &= ~2; + } + file_list_unlock(); DQUOT_OFF(dev); fsync_dev(dev); flags = MS_RDONLY; @@ -239,9 +240,6 @@ lock_kernel(); remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT); emergency_sync_scheduled = 0; - - if (remount_flag) - all_files_read_only(); for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) if (is_local_disk(mnt->mnt_dev)) diff -u --recursive --new-file v2.3.9/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.3.9/linux/drivers/char/tpqic02.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/char/tpqic02.c Tue Jul 6 10:11:40 1999 @@ -127,7 +127,7 @@ static volatile int ctlbits = 0; /* control reg bits for tape interface */ -static wait_queue_t qic02_tape_transfer; /* sync rw with interrupts */ +static wait_queue_head_t qic02_tape_transfer; /* sync rw with interrupts */ static volatile struct mtget ioctl_status; /* current generic status */ @@ -2216,7 +2216,7 @@ } /* Only one at a time from here on... */ - if (atomic_read(&filp->f_count)>1) /* filp->f_count==1 for the first open() */ + if (file_count(filp)>1) /* filp->f_count==1 for the first open() */ { return -EBUSY; } @@ -2889,7 +2889,7 @@ return 0; } /* qic02_get_resources */ -__initfunc(int qic02_tape_init(void)) +int __init qic02_tape_init(void) { if (TPSTATSIZE != 6) { diff -u --recursive --new-file v2.3.9/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.9/linux/drivers/char/tty_io.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/char/tty_io.c Sun Jul 4 10:18:52 1999 @@ -173,13 +173,15 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) { #ifdef CHECK_TTY_COUNT - struct file *f; + struct list_head *p; int count = 0; - for(f = inuse_filps; f; f = f->f_next) { - if(f->private_data == tty) + file_list_lock(); + for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) { + if(list_entry(p, struct file, f_list)->private_data == tty) count++; } + file_list_unlock(); if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) @@ -383,9 +385,9 @@ void do_tty_hangup(void *data) { struct tty_struct *tty = (struct tty_struct *) data; - struct file * filp; struct file * cons_filp = NULL; struct task_struct *p; + struct list_head *l; int closecount = 0, n; if (!tty) @@ -395,13 +397,11 @@ lock_kernel(); check_tty_count(tty, "do_tty_hangup"); - for (filp = inuse_filps; filp; filp = filp->f_next) { - if (filp->private_data != tty) - continue; + file_list_lock(); + for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) { + struct file * filp = list_entry(l, struct file, f_list); if (!filp->f_dentry) continue; - if (!filp->f_dentry->d_inode) - continue; if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV || filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) { cons_filp = filp; @@ -410,9 +410,10 @@ if (filp->f_op != &tty_fops) continue; closecount++; - tty_fasync(-1, filp, 0); + tty_fasync(-1, filp, 0); /* can't block */ filp->f_op = &hung_up_tty_fops; } + file_list_unlock(); /* FIXME! What are the locking issues here? This may me overdoing things.. */ { @@ -1307,6 +1308,7 @@ init_dev_done: #endif filp->private_data = tty; + file_move(filp, &tty->tty_files); check_tty_count(tty, "tty_open"); if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_MASTER) @@ -1788,6 +1790,10 @@ * have to coordinate with the init process, since all processes associated * with the current tty must be dead before the new getty is allowed * to spawn. + * + * Now, if it would be correct ;-/ The current code has a nasty hole - + * it doesn't catch files in flight. We may send the descriptor to ourselves + * via AF_UNIX socket, close it and later fetch from socket. FIXME. */ void do_SAK( struct tty_struct *tty) { @@ -1812,6 +1818,7 @@ ((session > 0) && (p->session == session))) send_sig(SIGKILL, p, 1); else if (p->files) { + read_lock(&p->files->file_lock); for (i=0; i < p->files->max_fds; i++) { filp = fcheck_task(p, i); if (filp && (filp->f_op == &tty_fops) && @@ -1820,6 +1827,7 @@ break; } } + read_unlock(&p->files->file_lock); } } read_unlock(&tasklist_lock); @@ -1937,6 +1945,7 @@ tty->tq_hangup.routine = do_tty_hangup; tty->tq_hangup.data = tty; sema_init(&tty->atomic_read, 1); + INIT_LIST_HEAD(&tty->tty_files); } /* diff -u --recursive --new-file v2.3.9/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.3.9/linux/drivers/char/videodev.c Wed Jun 2 11:29:13 1999 +++ linux/drivers/char/videodev.c Mon Jul 5 20:09:40 1999 @@ -63,6 +63,9 @@ #ifdef CONFIG_RADIO_RTRACK extern int rtrack_init(struct video_init *); #endif +#ifdef CONFIG_RADIO_RTRACK2 +extern int rtrack2_init(struct video_init *); +#endif #ifdef CONFIG_RADIO_SF16FMI extern int fmi_init(struct video_init *); #endif @@ -78,9 +81,15 @@ #ifdef CONFIG_RADIO_CADET extern int cadet_init(struct video_init *); #endif +#ifdef CONFIG_RADIO_TERRATEC +extern int terratec_init(struct video_init *); +#endif #ifdef CONFIG_VIDEO_PMS extern int init_pms_cards(struct video_init *); #endif +#ifdef CONFIG_VIDEO_ZORAN +extern int init_zoran_cards(struct video_init *); +#endif static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_BT848 @@ -108,6 +117,9 @@ #ifdef CONFIG_RADIO_RTRACK {"RTrack", rtrack_init}, #endif +#ifdef CONFIG_RADIO_RTRACK2 + {"RTrack2", rtrack2_init}, +#endif #ifdef CONFIG_RADIO_SF16FMI {"SF16FMI", fmi_init}, #endif @@ -123,6 +135,12 @@ #ifdef CONFIG_RADIO_TYPHOON {"radio-typhoon", typhoon_init}, #endif +#ifdef CONFIG_RADIO_TERRATEC + {"radio-terratec", terratec_init}, +#endif +#ifdef CONFIG_VIDEO_ZORAN + {"zoran", init_zoran_cards}, +#endif {"end", NULL} }; diff -u --recursive --new-file v2.3.9/linux/drivers/char/zr36057.h linux/drivers/char/zr36057.h --- v2.3.9/linux/drivers/char/zr36057.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/zr36057.h Mon Jul 5 20:09:40 1999 @@ -0,0 +1,168 @@ +/* + zr36057.h - zr36057 register offsets + + Copyright (C) 1998 Dave Perks + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ZR36057_H_ +#define _ZR36057_H_ + + +/* Zoran ZR36057 registers */ + +#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ +#define ZR36057_VFEHCR_HSPol (1<<30) +#define ZR36057_VFEHCR_HStart 10 +#define ZR36057_VFEHCR_HEnd 0 +#define ZR36057_VFEHCR_Hmask 0x3ff + +#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ +#define ZR36057_VFEVCR_VSPol (1<<30) +#define ZR36057_VFEVCR_VStart 10 +#define ZR36057_VFEVCR_VEnd 0 +#define ZR36057_VFEVCR_Vmask 0x3ff + +#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ +#define ZR36057_VFESPFR_ExtFl (1<<26) +#define ZR36057_VFESPFR_TopField (1<<25) +#define ZR36057_VFESPFR_VCLKPol (1<<24) +#define ZR36057_VFESPFR_HFilter 21 +#define ZR36057_VFESPFR_HorDcm 14 +#define ZR36057_VFESPFR_VerDcm 8 +#define ZR36057_VFESPFR_DispMode 6 +#define ZR36057_VFESPFR_YUV422 (0<<3) +#define ZR36057_VFESPFR_RGB888 (1<<3) +#define ZR36057_VFESPFR_RGB565 (2<<3) +#define ZR36057_VFESPFR_RGB555 (3<<3) +#define ZR36057_VFESPFR_ErrDif (1<<2) +#define ZR36057_VFESPFR_Pack24 (1<<1) +#define ZR36057_VFESPFR_LittleEndian (1<<0) + +#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ + +#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ + +#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ +#define ZR36057_VSSFGR_DispStride 16 +#define ZR36057_VSSFGR_VidOvf (1<<8) +#define ZR36057_VSSFGR_SnapShot (1<<1) +#define ZR36057_VSSFGR_FrameGrab (1<<0) + +#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ +#define ZR36057_VDCR_VidEn (1<<31) +#define ZR36057_VDCR_MinPix 24 +#define ZR36057_VDCR_Triton (1<<24) +#define ZR36057_VDCR_VidWinHt 12 +#define ZR36057_VDCR_VidWinWid 0 + +#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ + +#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ + +#define ZR36057_OCR 0x024 /* Overlay Control Register */ +#define ZR36057_OCR_OvlEnable (1 << 15) +#define ZR36057_OCR_MaskStride 0 + +#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ +#define ZR36057_SPGPPCR_SoftReset (1<<24) + +#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ + +#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ + +#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ +#define ZR36057_MCTCR_CodTime (1 << 30) +#define ZR36057_MCTCR_CEmpty (1 << 29) +#define ZR36057_MCTCR_CFlush (1 << 28) +#define ZR36057_MCTCR_CodGuestID 20 +#define ZR36057_MCTCR_CodGuestReg 16 + +#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ + +#define ZR36057_ISR 0x03c /* Interrupt Status Register */ +#define ZR36057_ISR_GIRQ1 (1<<30) +#define ZR36057_ISR_GIRQ0 (1<<29) +#define ZR36057_ISR_CodRepIRQ (1<<28) +#define ZR36057_ISR_JPEGRepIRQ (1<<27) + +#define ZR36057_ICR 0x040 /* Interrupt Control Register */ +#define ZR36057_ICR_GIRQ1 (1<<30) +#define ZR36057_ICR_GIRQ0 (1<<29) +#define ZR36057_ICR_CodRepIRQ (1<<28) +#define ZR36057_ICR_JPEGRepIRQ (1<<27) +#define ZR36057_ICR_IntPinEn (1<<24) + +#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ +#define ZR36057_I2CBR_SDA (1<<1) +#define ZR36057_I2CBR_SCL (1<<0) + +#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ +#define ZR36057_JMC_JPG (1 << 31) +#define ZR36057_JMC_JPGExpMode (0 << 29) +#define ZR36057_JMC_JPGCmpMode (1 << 29) +#define ZR36057_JMC_MJPGExpMode (2 << 29) +#define ZR36057_JMC_MJPGCmpMode (3 << 29) +#define ZR36057_JMC_RTBUSY_FB (1 << 6) +#define ZR36057_JMC_Go_en (1 << 5) +#define ZR36057_JMC_SyncMstr (1 << 4) +#define ZR36057_JMC_Fld_per_buff (1 << 3) +#define ZR36057_JMC_VFIFO_FB (1 << 2) +#define ZR36057_JMC_CFIFO_FB (1 << 1) +#define ZR36057_JMC_Stll_LitEndian (1 << 0) + +#define ZR36057_JPC 0x104 /* JPEG Process Control */ +#define ZR36057_JPC_P_Reset (1 << 7) +#define ZR36057_JPC_CodTrnsEn (1 << 5) +#define ZR36057_JPC_Active (1 << 0) + +#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ +#define ZR36057_VSP_VsyncSize 16 +#define ZR36057_VSP_FrmTot 0 + +#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ +#define ZR36057_HSP_HsyncStart 16 +#define ZR36057_HSP_LineTot 0 + +#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ +#define ZR36057_FHAP_NAX 16 +#define ZR36057_FHAP_PAX 0 + +#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ +#define ZR36057_FVAP_NAY 16 +#define ZR36057_FVAP_PAY 0 + +#define ZR36057_FPP 0x118 /* Field Process Parameters */ +#define ZR36057_FPP_Odd_Even (1 << 0) + +#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ + +#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ + +#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ +#define ZR36057_JCGI_JPEGuestID 4 +#define ZR36057_JCGI_JPEGuestReg 0 + +#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ + +#define ZR36057_POR 0x200 /* Post Office Register */ +#define ZR36057_POR_POPen (1<<25) +#define ZR36057_POR_POTime (1<<24) +#define ZR36057_POR_PODir (1<<23) + +#define ZR36057_STR 0x300 /* "Still" Transfer Register */ + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/char/zr36060.h linux/drivers/char/zr36060.h --- v2.3.9/linux/drivers/char/zr36060.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/zr36060.h Mon Jul 5 20:09:40 1999 @@ -0,0 +1,35 @@ +/* + zr36060.h - zr36060 register offsets + + Copyright (C) 1998 Dave Perks + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ZR36060_H_ +#define _ZR36060_H_ + + +/* Zoran ZR36060 registers */ + +#define ZR36060_LoadParameters 0x000 +#define ZR36060_Load (1<<7) +#define ZR36060_SyncRst (1<<0) + +#define ZR36060_CodeFifoStatus 0x001 +#define ZR36060_Load (1<<7) +#define ZR36060_SyncRst (1<<0) + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/fc4/socal.c linux/drivers/fc4/socal.c --- v2.3.9/linux/drivers/fc4/socal.c Sun Mar 28 09:07:47 1999 +++ linux/drivers/fc4/socal.c Mon Jul 5 20:35:18 1999 @@ -37,7 +37,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/README linux/drivers/i2o/README --- v2.3.9/linux/drivers/i2o/README Wed Jun 2 14:40:22 1999 +++ linux/drivers/i2o/README Mon Jul 5 20:09:40 1999 @@ -22,8 +22,15 @@ Philip Rumpf Fixed assorted dumb SMP locking bugs -Juha Sievanen, University Of Helsinki Finland +Juha Sievanen, University of Helsinki Finland LAN OSM + /proc interface to LAN class + Bug fixes + Core code extensions + +Auvo Häkkinen, University of Helsinki Finland + LAN OSM + /Proc interface to LAN class Bug fixes Core code extensions @@ -41,13 +48,16 @@ BoxHill Corporation Loan of initial FibreChannel disk array used for development work. +European Comission + Funding the work done by the University of Helsinki + STATUS: o The core setup works within limits. o The scsi layer seems to almost work. I'm still chasing down the hang bug. o The block OSM is fairly minimal but does seem to work. - +o LAN OSM works with FDDI cards. TO DO: @@ -69,10 +79,8 @@ SCSI: o Find the right way to associate drives/luns/busses -Net: -o Port the existing RCPCI work to the frame work or write a new - driver. This one is with the Finns +Lan: Batch mode sends + Fix the "killing interrupt handler" in i2o_set_multicast_list Tape: o Anyone seen anything implementing this ? - diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/README.lan linux/drivers/i2o/README.lan --- v2.3.9/linux/drivers/i2o/README.lan Wed Jun 2 14:40:22 1999 +++ linux/drivers/i2o/README.lan Mon Jul 5 20:09:40 1999 @@ -1,5 +1,6 @@ Linux I2O LAN OSM + (c) University of Helsinki, Department of Computer Science This program is free software; you can redistribute it and/or @@ -8,14 +9,14 @@ 2 of the License, or (at your option) any later version. AUTHORS -Auvo Häkkinen, Auvo.Hakkinen@cs.Helsinki.FI -Juha Sievänen, Juha.Sievanen@cs.Helsinki.FI + Auvo Häkkinen, Auvo.Hakkinen@cs.Helsinki.FI + Juha Sievänen, Juha.Sievanen@cs.Helsinki.FI CREDITS This work was made possible by -European Committee +European Commission Funding for the project SysKonnect @@ -32,7 +33,6 @@ LAN: o Add support for bactches -o Find why big packets flow from I2O box out, but don't want to come in o Find the bug in i2o_set_multicast_list(), which kills interrupt handler in i2o_wait_reply() o Add support for Ethernet, Token Ring, AnyLAN, Fibre Channel diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.3.9/linux/drivers/i2o/i2o_block.c Wed Jun 2 14:40:22 1999 +++ linux/drivers/i2o/i2o_block.c Mon Jul 5 20:09:40 1999 @@ -10,13 +10,17 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * This is an initial test release. Most of the good code was taken + * This is a beta test release. Most of the good code was taken * from the nbd driver by Pavel Machek, who in turn took some of it * from loop.c. Isn't free software great for reusability 8) * * Fixes: * Steve Ralston: Multiple device handling error fixes, * Added a queue depth. + * + * Todo: + * 64bit cleanness. + * Remove the queue walk. We can do that better. */ #include @@ -31,6 +35,7 @@ #include #include #include +#include #include #include @@ -47,7 +52,7 @@ #define MAX_I2OB 16 -#define MAX_I2OB_DEPTH 4 +#define MAX_I2OB_DEPTH 8 /* * Some of these can be made smaller later @@ -61,9 +66,7 @@ static int i2ob_context; -#ifdef __SMP__ static spinlock_t i2ob_lock = SPIN_LOCK_UNLOCKED; -#endif struct i2ob_device { @@ -175,15 +178,10 @@ msg[5] -= count; } -// printk("Send for %p\n", req); - i2o_post_message(c,m); atomic_inc(&queue_depth); if(atomic_read(&queue_depth)>old_qd) - { old_qd=atomic_read(&queue_depth); - printk("Depth now %d.\n", old_qd); - } return 0; } @@ -825,7 +823,7 @@ */ if(i2ob_claim_device(dev, 1)==0) { - printk(KERN_INFO "Claimed Dev %x Tid %d Unit %d\n",dev,dev->tid,unit); + printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit); i2ob_install_device(c,d,unit); unit+=16; @@ -836,7 +834,7 @@ * the block or scsi driver. */ if (i2ob_claim_device(dev, 0)<0) - printk(KERN_INFO "Could not unclaim Dev %x Tid %d\n",dev,dev->tid); + printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid); } else @@ -966,14 +964,14 @@ */ #ifdef MODULE -#define i2ob_init init_module +#define i2o_block_init init_module #endif -int i2ob_init(void) +int i2o_block_init(void) { int i; - printk("I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n"); + printk(KERN_INFO "I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n"); /* * Register the block device interfaces diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c --- v2.3.9/linux/drivers/i2o/i2o_config.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/i2o/i2o_config.c Mon Jul 5 20:35:18 1999 @@ -5,8 +5,10 @@ * * Written by Alan Cox, Building Number Three Ltd * - * Modified 04/20/199 by Deepak Saxena + * Modified 04/20/1999 by Deepak Saxena * - Added basic ioctl() support + * Modified 06/07/1999 by Deepak Saxena + * - Added software download ioctl (still testing) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,7 +24,6 @@ #include #include #include -#include #include #include @@ -210,7 +211,10 @@ workspace = kmalloc(8192, GFP_KERNEL); hrt = (pi2o_hrt)workspace; if(workspace==NULL) + { + i2o_unlock_controller(c); return -ENOMEM; + } memset(workspace, 0, 8192); @@ -271,7 +275,10 @@ workspace = kmalloc(8192, GFP_KERNEL); lct = (pi2o_lct)workspace; if(workspace==NULL) + { + i2o_unlock_controller(c); return -ENOMEM; + } memset(workspace, 0, 8192); @@ -337,10 +344,14 @@ ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL); if(!ops) + { + i2o_unlock_controller(c); return -ENOMEM; + } if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) { + i2o_unlock_controller(c); kfree(ops); return -EFAULT; } @@ -352,6 +363,7 @@ res = (u8*)kmalloc(65536, GFP_KERNEL); if(!res) { + i2o_unlock_controller(c); kfree(ops); return -ENOMEM; } @@ -374,11 +386,12 @@ token = i2o_post_wait(c, kcmd.tid, msg, 9*4, &i2o_cfg_token,10); if(token == I2O_POST_WAIT_TIMEOUT) { + i2o_unlock_controller(c); kfree(ops); kfree(res); return -ETIMEDOUT; } - + i2o_unlock_controller(c); kfree(ops); /* @@ -448,9 +461,13 @@ { query = kmalloc(kcmd.qlen, GFP_KERNEL); if(!query) + { + i2o_unlock_controller(c); return -ENOMEM; + } if(copy_from_user(query, kcmd.qbuf, kcmd.qlen)) { + i2o_unlock_controller(c); printk(KERN_INFO "i2o_config: could not get query\n"); kfree(query); return -EFAULT; @@ -459,7 +476,10 @@ res = kmalloc(4096, GFP_KERNEL); if(!res) + { + i2o_unlock_controller(c); return -ENOMEM; + } msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid; msg[2] = i2o_cfg_context; @@ -480,11 +500,13 @@ token = i2o_post_wait(c, cmd->tid, msg, 9*4, &i2o_cfg_token, 10); if(token == I2O_POST_WAIT_TIMEOUT) { + i2o_unlock_controller(c); kfree(res); if(kcmd.qlen) kfree(query); return -ETIMEDOUT; } + i2o_unlock_controller(c); len = strnlen(res, 8192); put_user(len, kcmd.reslen); @@ -500,10 +522,123 @@ return ret; } -/* To be written */ int ioctl_swdl(unsigned long arg) { - return -ENOSYS; + struct i2o_sw_xfer kxfer; + struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg; + unsigned char maxfrag = 0, curfrag = 0; + unsigned char buffer[8192]; + u32 msg[MSG_FRAME_SIZE/4]; + unsigned int token = 0, diff = 0, swlen = 0, swxfer = 0; + struct i2o_controller *c; + int foo = 0; + + printk("*** foo%d ***\n", foo++); + if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) + { + printk( "i2o_config: can't copy i2o_sw cmd @ %p\n", pxfer); + return -EFAULT; + } + printk("*** foo%d ***\n", foo++); + + printk("Attempting to copy swlen from %p\n", kxfer.swlen); + if(get_user(swlen, kxfer.swlen) < 0) + { + printk( "i2o_config: can't copy swlen\n"); + return -EFAULT; + } + printk("*** foo%d ***\n", foo++); + + maxfrag = swlen >> 13; // Transfer in 8k fragments + + printk("Attempting to write maxfrag @ %p\n", kxfer.maxfrag); + if(put_user(maxfrag, kxfer.maxfrag) < 0) + { + printk( "i2o_config: can't write maxfrag\n"); + return -EFAULT; + } + printk("*** foo%d ***\n", foo++); + + printk("Attempting to write curfrag @ %p\n", kxfer.curfrag); + if(put_user(curfrag, kxfer.curfrag) < 0) + { + printk( "i2o_config: can't write curfrag\n"); + return -EFAULT; + } + printk("*** foo%d ***\n", foo++); + + if(!kxfer.buf) + { + printk( "i2o_config: NULL software buffer\n"); + return -EFAULT; + } + printk("*** foo%d ***\n", foo++); + + // access_ok doesn't check for NULL... + if(!access_ok(VERIFY_READ, kxfer.buf, swlen)) + { + printk( "i2o_config: Cannot read sw buffer\n"); + return -EFAULT; + } + printk("*** foo%d ***\n", foo++); + + c = i2o_find_controller(kxfer.iop); + if(!c) + return -ENXIO; + printk("*** foo%d ***\n", foo++); + + msg[0]= EIGHT_WORD_MSG_SIZE| SGL_OFFSET_7; + msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= (u32)cfg_handler.context; + msg[3]= 0; + msg[4]= ((u32)kxfer.dl_flags)<<24|((u32)kxfer.sw_type)<<16|((u32)maxfrag)<<8|((u32)curfrag); + msg[5]= swlen; + msg[6]= kxfer.sw_id; + msg[7]= (0xD0000000 | 8192); + msg[8]= virt_to_phys(buffer); + + printk("*** foo%d ***\n", foo++); + + // + // Loop through all fragments but last and transfer them... + // We already checked memory, so from now we assume it's all good + // + for(curfrag = 0; curfrag < maxfrag-1; curfrag++) + { + printk("Transfering fragment %d\n", curfrag); + + msg[4] |= (u32)curfrag; + + __copy_from_user(buffer, kxfer.buf, 8192); + swxfer += 8129; + + // Yes...that's one minute, but the spec states that + // transfers take a long time, and I've seen just how + // long they can take. + token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,60); + if( token == I2O_POST_WAIT_TIMEOUT ) // Something very wrong + { + printk("Timeout downloading software"); + return -ETIMEDOUT; + } + + __put_user(curfrag, kxfer.curfrag); + } + + // Last frag is special case since it's not exactly 8K + diff = swlen - swxfer; + msg[4] |= (u32)maxfrag; + msg[7] = (0xD0000000 | diff); + __copy_from_user(buffer, kxfer.buf, 8192); + token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,60); + if( token == I2O_POST_WAIT_TIMEOUT ) // Something very wrong + { + printk("Timeout downloading software"); + return -ETIMEDOUT; + } + __put_user(curfrag, kxfer.curfrag); + + return 0; } /* To be written */ @@ -557,7 +692,7 @@ #ifdef MODULE int init_module(void) #else -int i2o_config_init(void) +__init int i2o_config_init(void) #endif { printk(KERN_INFO "i2o configuration manager v 0.02\n"); diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.3.9/linux/drivers/i2o/i2o_core.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/i2o/i2o_core.c Tue Jul 6 10:11:40 1999 @@ -13,12 +13,12 @@ * A lot of the I2O message side code from this is taken from the * Red Creek RCPCI45 adapter driver by Red Creek Communications * - * Some fixes and cleanup by Philipp Rumpf - * - * Additional fixes by Juha Sievänen - * + * Fixes by Philipp Rumpf + * Juha Sievänen + * Auvo Häkkinen */ +#include #include #include #include @@ -32,26 +32,69 @@ #include "i2o_lan.h" + /* * Size of the I2O module table */ - static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES]; static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS]; int i2o_num_controllers = 0; - +static int core_context = 0; +static int reply_flag = 0; extern int i2o_online_controller(struct i2o_controller *c); +static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, + struct i2o_message *); + +/* Message handler */ +static struct i2o_handler i2o_core_handler = +{ + (void *)i2o_core_reply, + "I2O core layer", + 0 +}; /* * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */ -#ifdef __SMP__ static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; + +void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, + struct i2o_message *m) +{ + u32 *msg=(u32 *)m; + u32 *flag = (u32 *)msg[3]; + +#if 0 + i2o_report_status(KERN_INFO, "i2o_core", msg); #endif + + if (msg[0] & (1<<13)) // Fail bit is set + { + printk(KERN_ERR "IOP failed to process the msg:\n"); + printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n", + (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & + 0xFFF); + printk(KERN_ERR " FailureCode = 0x%02X\n Severity = 0x%02X\n" + "LowestVersion = 0x%02X\n HighestVersion = 0x%02X\n", + msg[4] >> 24, (msg[4] >> 16) & 0xFF, + (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); + printk(KERN_ERR " FailingHostUnit = 0x%04X\n FailingIOP = 0x%03X\n", + msg[5] >> 16, msg[5] & 0xFFF); + return; + } + + if (msg[4] >> 24) + { + i2o_report_status(KERN_WARNING, "i2o_core", msg); + *flag = -(msg[4] & 0xFFFF); + } + else + *flag = I2O_POST_WAIT_OK; +} /* * Install an I2O handler - these handle the asynchronous messaging @@ -179,10 +222,11 @@ int i2o_delete_controller(struct i2o_controller *c) { struct i2o_controller **p; - + spin_lock(&i2o_configuration_lock); if(atomic_read(&c->users)) { + printk("Someones using controller iop%d\n", c->unit); spin_unlock(&i2o_configuration_lock); return -EBUSY; } @@ -195,21 +239,41 @@ return -EBUSY; } } - c->destructor(c); - +// c->destructor(c); /* We dont want to free the IRQ yet */ + p=&i2o_controller_chain; - + + /* Send first SysQuiesce to other IOPs */ + while(*p) + { + if(*p!=c) + if(i2o_quiesce_controller(*p)<0) + printk(KERN_INFO "Unable to quiesce iop%d\n", + (*p)->unit); + p=&((*p)->next); + } + + p=&i2o_controller_chain; + while(*p) { if(*p==c) { - /* Prepare for restart */ -// i2o_clear_controller(c); + /* Ask the IOP to switch to HOLD state */ + if (i2o_clear_controller(c) < 0) + printk("Unable to clear iop%d\n", c->unit); + + /* Release IRQ */ + c->destructor(c); *p=c->next; spin_unlock(&i2o_configuration_lock); if(c->page_frame); kfree(c->page_frame); + if(c->hrt) + kfree(c->hrt); + if(c->lct) + kfree(c->lct); i2o_controllers[c->unit]=NULL; kfree(c); i2o_num_controllers--; @@ -317,7 +381,7 @@ "Device Driver Module", "Block Device", "Tape Device", - "LAN Inteface", + "LAN Interface", "WAN Interface", "Fibre Channel Port", "Fibre Channel Device", @@ -384,7 +448,7 @@ { if((jiffies-time)>=5*HZ) { - printk(KERN_ERR "%s: Timeout waiting for message to send %s.\n", + printk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n", c->name, why); return 0xFFFFFFFF; } @@ -396,7 +460,7 @@ /* - * Wait up to 5 seconds for a reply to be available. + * Wait up to timeout seconds for a reply to be available. */ u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout) @@ -418,173 +482,6 @@ } - -/* Quiesce and clear IOP */ -int i2o_quiesce_controller(struct i2o_controller *c) -{ - u32 m; - u32 *msg; - - /* now we stop receiving messages to this IOP */ - m=i2o_wait_message(c, "Quiesce IOP"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - - msg=(u32 *)(c->mem_offset+m); - - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=0; - msg[3]=0; - - printk(KERN_DEBUG "Sending SysQuiesce to %s\n", c->name); - i2o_post_message(c,m); - - m=i2o_wait_reply(c, "System Quiesce", 20); - - if (m==0xFFFFFFFF) - return -ETIMEDOUT; - /* Someday we should check return status... */ - - return 0; -} - -int i2o_clear_controller(struct i2o_controller *c) -{ - u32 m; - u32 *msg; - - m=i2o_wait_message(c, "IOP Clear"); - if (m==0xFFFFFFFF) - return -ETIMEDOUT; - - msg=(u32 *)(c->mem_offset+m); - - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=0; - msg[3]=0; - - printk(KERN_DEBUG "Sending IOPClear to %s\n", c->name); - i2o_post_message(c, m); - - m=i2o_wait_reply(c, "IOP Clear timeout", 5); - - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - - return 0; -} - - -/* - * i2o table walking. We just provide a single element retrieve. You can - * all sorts of fancy lookups in I2O but we have no performance critical - * lookups so why write all the code for it. - */ - -#if 0 -static int i2o_query_table_polled(struct i2o_controller *c, int tid, void *buf, int buflen, - int group, int field, u32 *key, int keylen) -{ - u32 m; - u32 *msg; - u16 op[64]; - u32 *p; - int i; - u32 *rbuf; - - op[0]=1; /* One Operation */ - op[1]=0; /* PAD */ - op[2]=2; /* LIST_GET */ - op[3]=group; /* group number */ - op[4]=1; /* 1 field */ - op[5]=field; /* Field number */ - op[6]=1; /* Key count */ - memcpy(op+7, key, keylen); /* Key */ - - m=i2o_wait_message(c, "I2O query table."); - if(m==0xFFFFFFFF) - { - return -ETIMEDOUT; - } - - msg=(u32 *)(c->mem_offset+m); - - rbuf=kmalloc(buflen+32, GFP_KERNEL); - if(rbuf==NULL) - { - printk(KERN_ERR "No free memory for table read.\n"); - return -ENOMEM; - } - msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; - msg[2]=0; /* Context */ - msg[3]=0; - msg[4]=0; - msg[5]=0x54000000|(14); - msg[6]=virt_to_bus(op); - msg[7]=0xD0000000|(32+buflen); - msg[8]=virt_to_bus(rbuf); - - i2o_post_message(c,m); - barrier(); - - /* - * Now wait for a reply - */ - - - m=i2o_wait_reply(c, "Table read timeout", 5); - - if(m==0xFFFFFFFF) - { - kfree(rbuf); - return -ETIMEDOUT; - } - - msg = (u32 *)bus_to_virt(m); - - if(msg[4]>>24) - { - i2o_report_status(KERN_WARNING, "i2o_core", - (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, - msg[4]&0xFFFF); - } - - p=rbuf; - - /* Ok 'p' is the reply block - lets see what happened */ - /* p0->p2 are the header */ - - /* FIXME: endians - turn p3 to little endian */ - - i=(p[0]&0xFFFF)<<2; /* Message size */ - if(iname); - kfree(rbuf); - return -EBADR; - } - - /* p[1] holds the more flag and row count - we dont care */ - - /* Ok it worked p[2]-> hold the data */ - memcpy(buf, p+2, buflen); - - kfree(rbuf); - - /* Finally return the message */ - I2O_REPLY_WRITE32(c,m); - return buflen; -} -#endif - static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen, int group, int field) { @@ -602,7 +499,7 @@ op[4]=1; /* 1 field */ op[5]=field; /* Field number */ - m=i2o_wait_message(c, "I2O query scalar."); + m=i2o_wait_message(c, "ParamsGet"); if(m==0xFFFFFFFF) { return -ETIMEDOUT; @@ -634,8 +531,7 @@ * Now wait for a reply */ - - m=i2o_wait_reply(c, "Scalar read timeout", 5); + m=i2o_wait_reply(c, "ParamsGet", 5); if(m==0xFFFFFFFF) { @@ -646,9 +542,7 @@ msg = (u32 *)bus_to_virt(m); if(msg[4]>>24) { - i2o_report_status(KERN_WARNING, "i2o_core", - (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, - msg[4]&0xFFFF); + i2o_report_status(KERN_WARNING, "i2o_core", msg); } p=rbuf; @@ -729,9 +623,10 @@ * This is full of endianisms! */ -static int i2o_parse_hrt(struct i2o_controller *c, u8 *p) +static int i2o_parse_hrt(struct i2o_controller *c) { - u32 *rows=(u32 *)p; + u32 *rows=c->hrt; + u8 *p=(u8 *)c->hrt; u8 *d; int count; int length; @@ -818,7 +713,7 @@ * on the board. Most of the stuff isn't interesting to us. */ -static int i2o_parse_lct(struct i2o_controller *c, u32 *lct) +static int i2o_parse_lct(struct i2o_controller *c) { int i; int max; @@ -826,11 +721,18 @@ u32 *p; struct i2o_device *d; char str[22]; + u32 *lct=(u32 *)c->lct; max=lct[0]&0xFFFF; max-=3; max/=9; + + if(max==0) + { + printk(KERN_ERR "LCT is empty????\n"); + return -1; + } printk(KERN_INFO "LCT has %d entries.\n", max); @@ -891,37 +793,61 @@ return 0; } -#if 0 -/* Reset the IOP to sane state */ -/* I think we need handler for core (or executive class in I2O terms) */ -static int i2o_reset_adapter(struct i2o_controller *c) +/* Quiesce IOP */ +int i2o_quiesce_controller(struct i2o_controller *c) { - u32 m; - u8 *work8; - u32 *msg; - long time; + u32 msg[4]; - /* First stop extral operations */ - m=i2o_wait_message(c, "quiesce IOP"); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - - msg=(u32 *)(c->mem_offset+m); - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=0; - msg[3]=0; + msg[2]=core_context; + msg[3]=(u32)&reply_flag; - i2o_post_message(c,m); + return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10); +} - m=i2o_wait_reply(c, "System Quiesce timeout", 5); - if(m==0xFFFFFFFF) - return -ETIMEDOUT; +int i2o_clear_controller(struct i2o_controller *c) +{ + u32 msg[4]; + + /* First stop external operations for this IOP */ + if(i2o_quiesce_controller(c)<0) + printk(KERN_INFO "Unable to quiesce iop%d\n", c->unit); + else + printk(KERN_INFO "Iop%d quiesced\n", c->unit); + + /* Then clear the IOP */ + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=core_context; + msg[3]=(u32)&reply_flag; + + return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10); +} + + +/* Reset the IOP to sane state */ +static int i2o_reset_controller(struct i2o_controller *c) +{ + u32 m; + u8 *work8; + u32 *msg; + long time; + struct i2o_controller *iop; + + /* First stop external operations */ + for(iop=i2o_controller_chain; iop != NULL; iop=iop->next) + { + if(i2o_quiesce_controller(iop)<0) + printk(KERN_INFO "Unable to quiesce iop%d\n", + iop->unit); + else + printk(KERN_DEBUG "%s quiesced\n", iop->name); + } /* Then reset the IOP */ - m=i2o_wait_message(c, "reset IOP"); + m=i2o_wait_message(c, "AdapterReset"); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -937,8 +863,8 @@ msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=0; - msg[3]=0; + msg[2]=core_context; + msg[3]=(u32)&reply_flag; msg[4]=0; msg[5]=0; msg[6]=virt_to_phys(work8); @@ -949,8 +875,10 @@ /* Wait for a reply */ time=jiffies; - while(work8[0]==0x01) { - if((jiffies-time)>=5*HZ) { + while(work8[0]==0x01) + { + if((jiffies-time)>=5*HZ) + { printk(KERN_ERR "IOP reset timeout.\n"); kfree(work8); return -ETIMEDOUT; @@ -964,113 +892,186 @@ return 0; } -#endif -/* - * Bring an I2O controller into HOLD state. See the 1.5 - * spec. Basically we go - * - * Wait for the message queue to initialise. - * If it didnt -> controller is dead - * - * Send a get status using the message queue - * Poll for a reply block 88 bytes long - * - * Send an initialise outbound queue - * Poll for a reply - * - * Post our blank messages to the queue FIFO - * - * Send GetHRT, Parse it - */ -int i2o_activate_controller(struct i2o_controller *c) +int i2o_status_get(struct i2o_controller *c) { long time; u32 m; - u8 *workspace; u32 *msg; - int i; - - printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n", (u32)c->mem_phys); + u8 *status_block; - /* First reset the IOP to sane state */ -// i2o_reset_adapter(c) - - m=i2o_wait_message(c, "initialise"); + status_block=(void *)kmalloc(88, GFP_KERNEL); + if(status_block==NULL) + { + printk(KERN_ERR "StatusGet failed - no free memory.\n"); + return -ENOMEM; + } + + m=i2o_wait_message(c, "StatusGet"); if(m==0xFFFFFFFF) return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); - - workspace = (void *)kmalloc(88, GFP_KERNEL); - if(workspace==NULL) - { - printk(KERN_ERR "IOP initialisation failed - no free memory.\n"); - return -ENOMEM; - } - - memset(workspace, 0, 88); - + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=0; + msg[2]=core_context; msg[3]=0; msg[4]=0; msg[5]=0; - msg[6]=virt_to_phys(workspace); + msg[6]=virt_to_phys(status_block); msg[7]=0; /* 64bit host FIXME */ msg[8]=88; i2o_post_message(c,m); - /* - * Wait for a reply - */ - + /* Wait for a reply */ time=jiffies; - while(workspace[87]!=0xFF) + while(status_block[87]!=0xFF) { if((jiffies-time)>=5*HZ) { printk(KERN_ERR "IOP get status timeout.\n"); - kfree(workspace); return -ETIMEDOUT; } schedule(); barrier(); } - /* - * Ok the reply has arrived. Fill in the important stuff - */ - - c->status = workspace[10]; - c->i2oversion = (workspace[9]>>4)&0xFF; - c->inbound_size = (workspace[12]|(workspace[13]<<8))*4; /* 32bit words */ - + /* Ok the reply has arrived. Fill in the important stuff */ + c->status = status_block[10]; + c->i2oversion = (status_block[9]>>4)&0xFF; + c->inbound_size = (status_block[12]|(status_block[13]<<8))*4; + + return 0; +} + + +int i2o_hrt_get(struct i2o_controller *c) +{ + u32 m; + u32 *msg; + + c->hrt=kmalloc(2048, GFP_KERNEL); + if(c->hrt==NULL) + { + printk(KERN_ERR "IOP init failed; no memory.\n"); + return -ENOMEM; + } + + m=i2o_wait_message(c, "HRTGet"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; + msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= core_context; + msg[3]= 0x0; /* Transaction context */ + msg[4]= (0xD0000000 | 2048); /* Simple transaction , 2K */ + msg[5]= virt_to_phys(c->hrt); /* Dump it here */ + + i2o_post_message(c,m); + + barrier(); + + /* Now wait for a reply */ + m=i2o_wait_reply(c, "HRTGet", 5); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + i2o_report_status(KERN_WARNING, "i2o_core", msg); + + I2O_REPLY_WRITE32(c,m); + + return 0; +} + + +/* + * Bring an I2O controller into HOLD state. See the 1.5 + * spec. Basically we go + * + * Wait for the message queue to initialise. + * If it didnt -> controller is dead + * + * Send a get status using the message queue + * Poll for a reply block 88 bytes long + * + * Send an initialise outbound queue + * Poll for a reply + * + * Post our blank messages to the queue FIFO + * + * Send GetHRT, Parse it + */ + +int i2o_activate_controller(struct i2o_controller *c) +{ + long time; + u32 m; + u8 *workspace; + u32 *msg; + int i; + int ret; + + printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n", + (u32)c->mem_phys); + + if((ret=i2o_status_get(c))) + return ret; + + if(c->status == ADAPTER_STATE_FAULTED) /* not likely to be seen */ + { + printk(KERN_CRIT "i2o: iop%d has hardware fault\n", + c->unit); + return -1; + } + /* * If the board is running, reset it - we have no idea * what kind of a mess the previous owner left it in. */ - -// if(c->status == ADAPTER_STATE_OPERATIONAL) -// i2o_reset_device(c); + if(c->status == ADAPTER_STATE_HOLD || + c->status == ADAPTER_STATE_READY || + c->status == ADAPTER_STATE_OPERATIONAL || + c->status == ADAPTER_STATE_FAILED) + { + if((ret=i2o_reset_controller(c))) + return ret; - - m=i2o_wait_message(c, "initqueue"); + if((ret=i2o_status_get(c))) + return ret; + } + + workspace = (void *)kmalloc(88, GFP_KERNEL); + if(workspace==NULL) + { + printk(KERN_ERR "IOP initialisation failed - no free memory.\n"); + return -ENOMEM; + } + + memset(workspace, 0, 88); + + m=i2o_wait_message(c, "OutboundInit"); if(m==0xFFFFFFFF) { kfree(workspace); return -ETIMEDOUT; } - + msg=(u32 *)(c->mem_offset+m); msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= 0; + msg[2]= core_context; msg[3]= 0x0106; /* Transaction context */ msg[4]= 4096; /* Host page frame size */ msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ @@ -1099,9 +1100,11 @@ schedule(); barrier(); } - + kfree(workspace); + /* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */ + c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); if(c->page_frame==NULL) { @@ -1124,64 +1127,71 @@ * Now we need the Hardware Resource Table. We must ask for * this next we can't issue random messages yet. */ + ret=i2o_hrt_get(c); + if(ret) + return ret; + + ret=i2o_parse_hrt(c); + if(ret) + return ret; + + return i2o_online_controller(c); +// i2o_report_controller_unit(c, ADAPTER_TID); +} - workspace=kmalloc(2048, GFP_KERNEL); - if(workspace==NULL) +int i2o_lct_get(struct i2o_controller *c) +{ + u32 m; + u32 *msg; + + m=i2o_wait_message(c, "LCTNotify"); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + c->lct = kmalloc(8192, GFP_KERNEL); + if(c->lct==NULL) { - printk(KERN_ERR "IOP init failed; no memory.\n"); + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]= HOST_TID<<12|ADAPTER_TID; /* NOP */ + i2o_post_message(c,m); + printk(KERN_ERR "No free memory for i2o controller buffer.\n"); return -ENOMEM; } - m=i2o_wait_message(c, "I2O HRT timeout."); - if(m==0xFFFFFFFF) - { - kfree(workspace); - return -ETIMEDOUT; - } + memset(c->lct, 0, 8192); - msg=(u32 *)(c->mem_offset+m); + msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = 0; /* Context not needed */ + msg[3] = 0; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = 0x00000000; /* Report now */ + msg[6] = 0xD0000000|8192; + msg[7] = virt_to_bus(c->lct); - msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; - msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= 0x0; - msg[3]= 0x0; /* Transaction context */ - msg[4]= (0xD0000000 | 2048); /* Simple transaction , 2K */ - msg[5]= virt_to_phys(workspace); /* Dump it here */ - *((u32 *)workspace)=0xFFFFFFFF; - i2o_post_message(c,m); - + barrier(); - - /* - * Now wait for a reply - */ - - m=i2o_wait_reply(c, "HRT table", 5); - + + /* Now wait for a reply */ + m=i2o_wait_reply(c, "LCTNotify", 5); + if(m==0xFFFFFFFF) - { - kfree(workspace); return -ETIMEDOUT; - } - + msg=(u32 *)bus_to_virt(m); - + + /* TODO: Check TableSize for big LCTs and send new ExecLctNotify + * with bigger workspace */ + if(msg[4]>>24) - { - i2o_report_status(KERN_WARNING, "i2o_core", - (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, - msg[4]&0xFFFF); - } - I2O_REPLY_WRITE32(c,m); - - i2o_parse_hrt(c, workspace); - - kfree(workspace); - - return i2o_online_controller(c); -// i2o_report_controller_unit(c, ADAPTER_TID); + i2o_report_status(KERN_ERR, "i2o_core", msg); + + return 0; } @@ -1196,7 +1206,7 @@ u32 systab[32]; u32 privmem[2]; u32 privio[2]; - u32 *workspace; + int ret; systab[0]=1; systab[1]=0; @@ -1216,7 +1226,7 @@ privio[0]=c->priv_io; /* Private I/O address */ privio[1]=c->priv_io_size; - m=i2o_wait_message(c, "SetSysTab"); + m=i2o_wait_message(c, "SysTabSet"); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -1249,7 +1259,7 @@ */ - m=i2o_wait_reply(c, "Systab read", 5); + m=i2o_wait_reply(c, "SysTabSet", 5); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -1258,9 +1268,7 @@ if(msg[4]>>24) { - i2o_report_status(KERN_ERR, "i2o_core", - (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, - msg[4]&0xFFFF); + i2o_report_status(KERN_ERR, "i2o_core", msg); } I2O_REPLY_WRITE32(c,m); @@ -1268,7 +1276,7 @@ * Finally we go online */ - m=i2o_wait_message(c, "No message for SysEnable"); + m=i2o_wait_message(c, "SysEnable"); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -1289,7 +1297,7 @@ */ - m=i2o_wait_reply(c, "Enable", 240); + m=i2o_wait_reply(c, "SysEnable", 240); if(m==0xFFFFFFFF) return -ETIMEDOUT; @@ -1298,73 +1306,25 @@ if(msg[4]>>24) { - i2o_report_status(KERN_ERR, "i2o_core", - (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, - msg[4]&0xFFFF); + i2o_report_status(KERN_ERR, "i2o_core", msg); } I2O_REPLY_WRITE32(c,m); /* * Grab the LCT, see what is attached */ - - m=i2o_wait_message(c, "No message for LCT"); - - if(m==0xFFFFFFFF) - return -ETIMEDOUT; - - msg=(u32 *)(c->mem_offset+m); - - - workspace = kmalloc(8192, GFP_KERNEL); - if(workspace==NULL) - { - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]= HOST_TID<<12|ADAPTER_TID; /* NOP */ - i2o_post_message(c,m); - printk(KERN_ERR "No free memory for i2o controller buffer.\n"); - return -ENOMEM; - } - - memset(workspace, 0, 8192); - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = 0; /* Context not needed */ - msg[3] = 0; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = 0x00000000; /* Report now */ - msg[6] = 0xD0000000|8192; - msg[7] = virt_to_bus(workspace); - - i2o_post_message(c,m); - - barrier(); - /* - * Now wait for a reply - */ - - m=i2o_wait_reply(c, "LCT", 5); - - if(m==0xFFFFFFFF) + ret=i2o_lct_get(c); + if(ret) { - kfree(workspace); - return -ETIMEDOUT; + /* Maybe we should do also sthg else */ + return ret; } - - msg=(u32 *)bus_to_virt(m); - - if(msg[4]>>24) - { - i2o_report_status(KERN_ERR, "i2o_core", - (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, - msg[4]&0xFFFF); - } - - i2o_parse_lct(c, workspace); - kfree(workspace); - + + ret=i2o_parse_lct(c); + if(ret) + return ret; + I2O_REPLY_WRITE32(c,m); return 0; @@ -1417,16 +1377,21 @@ *flag = 0; if(i2o_post_this(c, tid, data, len)) - return -1; + return I2O_POST_WAIT_TIMEOUT; while(!*flag && (jiffies-t)>24, (res[1]>>16)&0xFF, res[1]&0xFFFF); + return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ + } + + res_count = res[0] & 0xFFFF; /* # of resultblocks */ + bytes = 4; + res += 4; + while (res_count--) + { + blk_size = (res[0] & 0xFFFF) << 2; + bytes += blk_size; + res += blk_size; + } + + return bytes; /* total sizeof Result List in bytes */ +} + +/* + * Query one scalar group value or a whole scalar group. + */ +int i2o_query_scalar(struct i2o_controller *iop, int tid, int context, + int group, int field, void *buf, int buflen, int *flag) +{ + u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; + u8 resblk[8+buflen]; /* 8 bytes for header */ + int size; + + if (field == -1) /* whole group */ + opblk[4] = -1; + + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, context, + opblk, sizeof(opblk), resblk, sizeof(resblk), flag); + + if (size < 0) + return size; + + memcpy(buf, resblk+8, buflen); /* cut off header */ + return buflen; +} + /* - * Query a scalar value + * Set a scalar group value or a whole group. */ - -int i2o_query_scalar(struct i2o_controller *c, int tid, int context, - int group, int field, void *buf, int buflen, int *flag) +int i2o_set_scalar(struct i2o_controller *iop, int tid, int context, + int group, int field, void *buf, int buflen, int *flag) { - u16 *op; - u32 *bl; - u32 msg[9]; - - bl=kmalloc(buflen+64, GFP_KERNEL); /* Enough space for error replys */ - if(bl==NULL) - { - printk(KERN_ERR "i2o: no memory for query buffer.\n"); - return -ENOMEM; - } - - op = (u16*)bl; - op[0]=1; /* One Operation */ - op[1]=0; /* PAD */ - op[2]=1; /* FIELD_GET */ - op[3]=group; /* group number */ - op[4]=1; /* field count, default = 1 */ - op[5]=field; /* field index */ + u16 *opblk; + u8 resblk[8+buflen]; /* 8 bytes for header */ + int size; + + opblk = kmalloc(buflen+64, GFP_KERNEL); + if (opblk == NULL) + { + printk(KERN_ERR "i2o: no memory for operation buffer.\n"); + return -ENOMEM; + } + + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = I2O_PARAMS_FIELD_SET; + opblk[3] = group; + + if(field == -1) { /* whole group */ + opblk[4] = -1; + memcpy(opblk+5, buf, buflen); + } + else /* single field */ + { + opblk[4] = 1; + opblk[5] = field; + memcpy(opblk+6, buf, buflen); + } - if(field == -1) - /* Single value or the whole group? */ - { - op[4]=-1; - op[5]=0; - } + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, + opblk, 12+buflen, resblk, sizeof(resblk), flag); - msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; - msg[2]=context|0x80000000; /* So we can pick it out */ - msg[3]=(u32)flag; - msg[4]=0; - msg[5]=0x54000000|12; - msg[6]=virt_to_bus(bl); - /* - * There are 8 bytes of "overhead" required to pull in - * a Params ResultsList; 2 bytes for ResultCount - * (which should have value=1), plus 2 bytes for pad, - * plus 2 bytes for BlockSize, plus 1 byte BlockStatus, - * plus 1 byte ErrorInfoSize (8 bytes total overhead). - * This is followed finally by actual result value(s). - * - * Tell the IOP to return 8 + buflen bytes. - */ - msg[7]=0xD0000000|(8+buflen); - msg[8]=virt_to_bus(bl+3); - - bl[3]=0xFCFCFCFC; // Pad,ResultCount - bl[4]=0xFAFAFCFC; // ErrorInfoSize,BlockStatus,BlockSize - - /* - * Post the message and await a reply - */ - - if (i2o_post_wait(c, tid, msg, sizeof(msg), flag,2) < 0) - { - kfree(bl); - return -1; - } - - if(bl[4]&0x00FF00000) /* BlockStatus != SUCCESS */ - { - printk(KERN_WARNING "i2o_query_scalar - Error\n" - "ErrorInfoSize = 0x%02x, BlockStatus = 0x%02x, " - "BlockSize = 0x%04x\n", - bl[4]>>24, (bl[4]>>16)&0xFF, bl[4]&0xFFFF); - kfree(bl); - return -1; - } - if((bl[3] & 0xFFFF) != 1) - { - printk(KERN_ERR "i2o: query ResultCount = 0x%04x\n", bl[3]&0xFFFF); - } - - memcpy(buf, bl+5, buflen); - kfree(bl); - return 0; + kfree(opblk); + return size; } - -#if 0 /* - * Query a table field - * FIXME: NOT TESTED! + * if oper == I2O_PARAMS_TABLE_GET: + * Get all table group fields from all rows or + * get specific table group fields from all rows. + * + * if fieldcount == -1 we query all fields from all rows + * ibuf is NULL and ibuflen is 0 + * else we query specific fields from all rows + * ibuf contains fieldindexes + * + * if oper == I2O_PARAMS_LIST_GET: + * Get all table group fields from specified rows or + * get specific table group fields from specified rows. + * + * if fieldcount == -1 we query all fields from specified rows + * ibuf contains rowcount, keyvalues + * else we query specific fields from specified rows + * ibuf contains fieldindexes, rowcount, keyvalues + * + * You could also use directly function i2o_issue_params(). */ -int i2o_query_table(struct i2o_controller *c, int tid, int context, - void *buf, int buflen, - int table, - int *field, int fieldlen, - u32 *key, int keylen, - int *flag) +int i2o_query_table(int oper, + struct i2o_controller *iop, int tid, int context, int group, + int fieldcount, void *ibuf, int ibuflen, + void *resblk, int reslen, int *flag) { - static u16 op[32]; - u32 *bl; - u32 msg[9]; - int i; + u16 *opblk; + int size; - bl=kmalloc(buflen+64, GFP_KERNEL); - if(bl==NULL) + opblk = kmalloc(10 + ibuflen, GFP_KERNEL); + if (opblk == NULL) { printk(KERN_ERR "i2o: no memory for query buffer.\n"); return -ENOMEM; } - op[0]=1; /* Operation count */ - op[1]=0; /* Reserved */ - op[2]=I2O_PARAMS_LIST_GET; /* Operation */ - op[3]=table; /* Group */ - /* Specific fields or the whole group? */ - if(*field != -1) - { /* FIXME: Fields can be variable size */ - op[4]=fieldlen; - for (i=0; i < fieldlen; i++) - op[4+i]=field[i]; - } - else - { - op[4]=-1; - op[5]=0; - } - - memcpy(bl, op, 12); - - msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; - msg[2]=context|0x80000000; /* So we can pick it out */ - msg[3]=(u32)flag; - msg[4]=0; - msg[5]=0x54000000|12; - msg[6]=virt_to_bus(bl); + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = oper; + opblk[3] = group; + opblk[4] = fieldcount; + memcpy(opblk+5, ibuf, ibuflen); /* other params */ - msg[7]=0xD0000000|(buflen+48); - msg[8]=virt_to_bus(bl+4); + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, context, + opblk, 10+ibuflen, resblk, reslen, flag); - /* - * Post the message and await a reply - */ + kfree(opblk); + return size; +} - if(i2o_post_wait(c, tid, msg, sizeof(msg), flag,2)<0) - return -1; - - if(bl[5]&0x00FF00000) /* BlockStatus != SUCCESS */ - { - printk(KERN_WARNING "i2o_query_table - Error\n" - "ErrorInfoSize = 0x%02x, BlockStatus = 0x%02x, " - "BlockSize = 0x%04x\n", - bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF); - kfree(bl); - return -1; - } +/* + * Clear table group, i.e. delete all rows. + */ - if((bl[4]&0xFFFF)!=1) - printk(KERN_ERR "i2o: query ResultCount = %0#4x\n", - bl[4]&0xFFFF); +int i2o_clear_table(struct i2o_controller *iop, int tid, int context, + int group, int *flag) +{ + u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group }; + u8 resblk[32]; /* min 8 bytes for result header */ - memcpy(buf, bl+6, buflen); - kfree(bl); - return 0; + return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, + opblk, sizeof(opblk), resblk, sizeof(resblk), flag); } -#endif /* - * Set (for now) scalar value + * Add a new row into a table group. * - * TODO: Add support for table groups - */ + * if fieldcount==-1 then we add whole rows + * buf contains rowcount, keyvalues + * else just specific fields are given, rest use defaults + * buf contains fieldindexes, rowcount, keyvalues + */ -int i2o_params_set(struct i2o_controller *c, int tid, int context, int table, - int field, void *buf, int buflen, int *flag) +int i2o_row_add_table(struct i2o_controller *iop, int tid, int context, + int group, int fieldcount, void *buf, int buflen, + int *flag) { - static u16 opdata[]={1,0,6,0,1,4,0}; - u32 *bl; - u32 msg[9]; + u16 *opblk; + u8 resblk[32]; /* min 8 bytes for header */ + int size; - bl=kmalloc(buflen+64, GFP_KERNEL); - if(bl==NULL) + opblk = kmalloc(buflen+64, GFP_KERNEL); + if (opblk == NULL) { - printk(KERN_ERR "i2o: no memory for set buffer.\n"); + printk(KERN_ERR "i2o: no memory for operation buffer.\n"); return -ENOMEM; } - opdata[3]=table; - /* Single value or the whole group? */ - if(field != -1) { - opdata[4]=1; - opdata[5]=field; - opdata[6]=*(u16 *)buf; - } - else { - opdata[4]=-1; - opdata[5]=0; - } + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = I2O_PARAMS_ROW_ADD; + opblk[3] = group; + opblk[4] = fieldcount; + memcpy(opblk+5, buf, buflen); - memcpy(bl, opdata, 14); + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, + opblk, 10+buflen, resblk, sizeof(resblk), flag); - msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; - msg[1]=I2O_CMD_UTIL_PARAMS_SET<<24|HOST_TID<<12|tid; - msg[2]=context|0x80000000; /* So we can pick it out */ - msg[3]=(u32)flag; - msg[4]=0; - msg[5]=0x54000000|14; - msg[6]=virt_to_bus(bl); - msg[7]=0xD0000000|(buflen+48); - msg[8]=virt_to_bus(bl+4); - - /* Post the message and wait for a reply */ - if(i2o_post_wait(c, tid, msg, 36, flag, 5)<0) - { - kfree(bl); - return -1; - } + kfree(opblk); + return size; +} - /* Perhaps we should check errors, eh? */ - if(bl[5]&0x00FF00000) /* BlockStatus != SUCCESS */ - { - printk(KERN_WARNING "i2o_params_set - Error\n" - "ErrorInfoSize = %0#2x, BlockStatus = %0#2x, " - "BlockSize = %0#4x\n", - bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF); - kfree(bl); - return -1; - } +/* + * Delete rows from a table group. + */ + +int i2o_row_delete_table(struct i2o_controller *iop, int tid, int context, + int group, int keycount, void *keys, int keyslen, + int *flag) +{ + u16 *opblk; + u8 resblk[32]; /* min 8 bytes for header */ + int size; - if((bl[4] & 0xFFFF) != 1) + opblk = kmalloc(keyslen+64, GFP_KERNEL); + if (opblk == NULL) { - printk(KERN_ERR "i2o: params set ResultCount = %0#4x\n", - bl[4]&0xFFFF); + printk(KERN_ERR "i2o: no memory for operation buffer.\n"); + return -ENOMEM; } - kfree(bl); - return 0; -} + opblk[0] = 1; /* operation count */ + opblk[1] = 0; /* pad */ + opblk[2] = I2O_PARAMS_ROW_DELETE; + opblk[3] = group; + opblk[4] = keycount; + memcpy(opblk+5, keys, keyslen); + size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, context, + opblk, 10+keyslen, resblk, sizeof(resblk), flag); + + kfree(opblk); + return size; +} -void report_common_status(u8 req_status) +void i2o_report_common_status(u8 req_status) { /* the following reply status strings are common to all classes */ @@ -1719,7 +1699,7 @@ return; } -static void report_common_dsc(u16 detailed_status) +static void i2o_report_common_dsc(u16 detailed_status) { /* The following detailed statuscodes are valid - for executive class, utility class, DDM class and @@ -1766,7 +1746,7 @@ return; } -void report_lan_dsc(u16 detailed_status) +static void i2o_report_lan_dsc(u16 detailed_status) { static char *LAN_DSC[] = { // Lan detailed status code strings "SUCCESS", @@ -1786,10 +1766,11 @@ "DEST_ADDRESS_DETECTED", "DEST_ADDRESS_OMITTED", "PARTIAL_PACKET_RETURNED", - "TEMP_SUSPENDED_STATE" + "TEMP_SUSPENDED_STATE", // last Lan detailed status code + "INVALID_REQUEST" // general detailed status code }; - if (detailed_status > I2O_LAN_DSC_TEMP_SUSPENDED_STATE) + if (detailed_status > I2O_DSC_INVALID_REQUEST) printk("%0#4x.\n", detailed_status); else printk("%s.\n", LAN_DSC[detailed_status]); @@ -1797,7 +1778,7 @@ return; } -static void report_util_cmd(u8 cmd) +static void i2o_report_util_cmd(u8 cmd) { switch (cmd) { case I2O_CMD_UTIL_NOP: @@ -1850,7 +1831,7 @@ } -static void report_exec_cmd(u8 cmd) +static void i2o_report_exec_cmd(u8 cmd) { switch (cmd) { case I2O_CMD_ADAPTER_ASSIGN: @@ -1959,7 +1940,7 @@ return; } -static void report_lan_cmd(u8 cmd) +static void i2o_report_lan_cmd(u8 cmd) { switch (cmd) { case LAN_PACKET_SEND: @@ -1985,30 +1966,32 @@ } /* TODO: Add support for other classes */ -void i2o_report_status(const char *severity, const char *module, u8 cmd, - u8 req_status, u16 detailed_status) +void i2o_report_status(const char *severity, const char *module, u32 *msg) { - printk("%s", severity); - printk("%s: ", module); + u8 cmd = (msg[1]>>24)&0xFF; + u8 req_status = (msg[4]>>24)&0xFF; + u16 detailed_status = msg[4]&0xFFFF; + + printk("%s%s: ", severity, module); if (cmd < 0x1F) { // Utility Class - report_util_cmd(cmd); - report_common_status(req_status); - report_common_dsc(detailed_status); + i2o_report_util_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_common_dsc(detailed_status); return; } if (cmd >= 0x30 && cmd <= 0x3F) { // LAN class - report_lan_cmd(cmd); - report_common_status(req_status); - report_lan_dsc(detailed_status); + i2o_report_lan_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_lan_dsc(detailed_status); return; } if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive class - report_exec_cmd(cmd); - report_common_status(req_status); - report_common_dsc(detailed_status); + i2o_report_exec_cmd(cmd); + i2o_report_common_status(req_status); + i2o_report_common_dsc(detailed_status); return; } @@ -2017,6 +2000,8 @@ } +#ifdef CONFIG_MODULE + EXPORT_SYMBOL(i2o_install_handler); EXPORT_SYMBOL(i2o_remove_handler); EXPORT_SYMBOL(i2o_install_device); @@ -2037,16 +2022,75 @@ EXPORT_SYMBOL(i2o_get_class_name); EXPORT_SYMBOL(i2o_query_scalar); -EXPORT_SYMBOL(i2o_params_set); +EXPORT_SYMBOL(i2o_set_scalar); +EXPORT_SYMBOL(i2o_query_table); +EXPORT_SYMBOL(i2o_clear_table); +EXPORT_SYMBOL(i2o_row_add_table); +EXPORT_SYMBOL(i2o_row_delete_table); + EXPORT_SYMBOL(i2o_post_this); EXPORT_SYMBOL(i2o_post_wait); EXPORT_SYMBOL(i2o_issue_claim); EXPORT_SYMBOL(i2o_report_status); -EXPORT_SYMBOL(report_common_status); -EXPORT_SYMBOL(report_lan_dsc); - -EXPORT_SYMBOL(i2o_wait_message); MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Core"); + + +int init_module(void) +{ + if (i2o_install_handler(&i2o_core_handler) < 0) + { + printk(KERN_ERR "i2o_core: Unable to install core handler.\n"); + return 0; + } + + core_context = i2o_core_handler.context; + + return 0; +} + +void cleanup_module(void) +{ + i2o_remove_handler(&i2o_core_handler); +} + +#else + +extern int i2o_block_init(void); +extern int i2o_config_init(void); +extern int i2o_lan_init(void); +extern int i2o_pci_init(void); +extern int i2o_proc_init(void); +extern int i2o_scsi_init(void); + +__init int i2o_init(void) +{ + if (i2o_install_handler(&i2o_core_handler) < 0) + { + printk(KERN_ERR "i2o_core: Unable to install core handler.\n"); + return 0; + } + + core_context = i2o_core_handler.context; +#ifdef CONFIG_I2O_PCI + i2o_pci_init(); +#endif + i2o_config_init(); +#ifdef CONFIG_I2O_BLOCK + i2o_block_init(); +#endif +#ifdef CONFIG_I2O_SCSI + i2o_scsi_init(); +#endif +#ifdef CONFIG_I2O_LAN + i2o_lan_init(); +#endif +#ifdef CONFIG_I2O_PROC + i2o_proc_init(); +#endif + return 0; +} + +#endif \ No newline at end of file diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c --- v2.3.9/linux/drivers/i2o/i2o_lan.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/i2o/i2o_lan.c Mon Jul 5 20:09:40 1999 @@ -1,7 +1,7 @@ /* * linux/drivers/i2o/i2o_lan.c * - * I2O LAN CLASS OSM Prototyping, May 7th 1999 + * I2O LAN CLASS OSM Prototyping, June 4th 1999 * * (C) Copyright 1999 University of Helsinki, * Department of Computer Science @@ -13,16 +13,19 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Author: Auvo Häkkinen + * Authors: Auvo Häkkinen + * Juha Sievänen * * Tested: in FDDI environment (using SysKonnect's DDM) - * in ETH environment (using Intel 82558 DDM proto) + * in Ethernet environment (using Intel 82558 DDM proto) * * TODO: batch mode networking - * - this one assumes that we always get one packet in a bucket - * - we've not been able to test batch replies and batch receives - * error checking / timeouts - * - code/test for other LAN classes + * - this one assumes that we always get one packet + * in a bucket + * - we've not been able to test batch replies and + * batch receives + * - error checking / timeouts + * - code / test for other LAN classes */ #include @@ -35,6 +38,7 @@ #include #include #include +#include #include #include @@ -56,9 +60,9 @@ struct i2o_lan_local { u8 unit; struct i2o_device *i2o_dev; - int reply_flag; // needed by scalar/table queries - struct fddi_statistics stats; -/* first fields are same as in struct net_device_stats stats; */ + int reply_flag; /* needed by scalar/table queries */ + u32 packet_tresh; /* treshold for incoming skb's */ + struct fddi_statistics stats; /* see also struct net_device_stats */ unsigned short (*type_trans)(struct sk_buff *, struct device *); }; @@ -66,6 +70,11 @@ static int i2o_lan_receive_post(struct device *dev); static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m); +/* + * Module params + */ +static u32 bucketpost = 64; +static u32 bucketthresh = 8; static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m) @@ -74,17 +83,25 @@ u8 unit = (u8)(msg[2]>>16); // InitiatorContext struct device *dev = i2o_landevs[unit]; -#ifdef DRIVERDEBUG - i2o_report_status(KERN_INFO, "i2o_lan", msg[1]>>24, msg[4]>>24, - msg[4]&0xFFFF); -#endif if (msg[0] & (1<<13)) // Fail bit is set { - printk(KERN_INFO "IOP failed to process the msg\n"); - printk("From tid=%d to tid=%d",(msg[1]>>12)&0xFFF,msg[1]&0xFFF); + printk(KERN_ERR "IOP failed to process the msg:\n"); + printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid = %d\n", + (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); + printk(KERN_ERR " FailureCode = 0x%02X\n Severity = 0x%02X\n " + "LowestVersion = 0x%02X\n HighestVersion = 0x%02X\n", + msg[4] >> 24, (msg[4] >> 16) & 0xFF, + (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); + printk(KERN_ERR " FailingHostUnit = 0x%04X\n FailingIOP = 0x%03X\n", + msg[5] >> 16, msg[5] & 0xFFF); return; } +#ifdef DRIVERDEBUG +// if (msg[4] >> 24) /* ReqStatus != SUCCESS */ + i2o_report_status(KERN_INFO, "i2o_lan", msg); +#endif + switch (msg[1] >> 24) { case LAN_RECEIVE_POST: if (dev->start) @@ -94,11 +111,9 @@ u8 trl_count = msg[3] & 0x000000FF; struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6]; - struct sk_buff *skb; do { - dprintk("Releasing unused bucket\n"); - skb = (struct sk_buff *)bucket->context; - dev_kfree_skb(skb); + dprintk("%s: Releasing unused bucket\n",dev->name); + dev_kfree_skb((struct sk_buff *)bucket->context); bucket++; } while (--trl_count); } @@ -110,30 +125,30 @@ u8 trl_count = msg[3] & 0x000000FF; if (msg[4] >> 24) // ReqStatus != SUCCESS - { - printk(KERN_WARNING "%s: ",dev->name); - report_common_status(msg[4]>>24); - report_lan_dsc(msg[4]&0xFFFF); - } + i2o_report_status(KERN_WARNING, dev->name, msg); - do { // The HDM has handled the outgoing packet + do { // The HDM has handled the outgoing packet dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]); dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", dev->name,trl_count); } while (--trl_count); - dev->tbusy = 0; - mark_bh(NET_BH); /* inform upper layers */ + dev->tbusy = 0; + mark_bh(NET_BH); /* inform upper layers */ } break; default: - if (msg[2] & 0x80000000) // reply to a util get/set - { // flag for the i2o_post_wait - int *flag = (int *)msg[3]; - // ReqStatus != I2O_REPLY_STATUS_SUCCESS - *flag = (msg[4] >> 24) ? I2O_POST_WAIT_TIMEOUT - : I2O_POST_WAIT_OK ; + if (msg[2] & 0x80000000) // reply to a UtilParamsGet/Set + { + int *flag = (int *)msg[3]; // flag for i2o_post_wait + if (msg[4] >> 24) // ReqStatus != SUCCESS + { + i2o_report_status(KERN_WARNING, dev->name, msg); + *flag = -(msg[4] & 0xFFFF); // DetailedStatus + } + else + *flag = I2O_POST_WAIT_OK; } } } @@ -155,40 +170,54 @@ struct i2o_packet_info *packet; u8 trl_count = msg[3] & 0x000000FF; - struct sk_buff *skb; + struct sk_buff *skb, *newskb; -#ifdef 0 +#if 0 dprintk(KERN_INFO "TrlFlags = 0x%02X, TrlElementSize = %d, TrlCount = %d\n" "msgsize = %d, buckets_remaining = %d\n", msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]); #endif + dprintk(KERN_INFO "Buckets_remaining = %d\n",msg[5]); -/* - * NOTE: here we assume that also in batch mode we will get only - * one packet per bucket. This can be ensured by setting the - * PacketOrphanLimit to MaxPacketSize, as well as the bucket size. - */ do { - /* packet is not at all needed here */ + skb = (struct sk_buff *)(bucket->context); packet = (struct i2o_packet_info *)bucket->packet_info; -#ifdef 0 +#if 0 dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n", packet->flags, packet->offset, packet->status, packet->len); #endif - skb = (struct sk_buff *)(bucket->context); - skb_put(skb,packet->len); - skb->dev = dev; - skb->protocol = priv->type_trans(skb, dev); - netif_rx(skb); + if (packet->len < priv->packet_tresh) { + newskb = (struct sk_buff *) + dev_alloc_skb(packet->len+2); + if (newskb) { + skb_reserve(newskb,2); + memcpy(skb_put(newskb,packet->len), + skb->data, packet->len); + newskb->dev = dev; + newskb->protocol = priv->type_trans(newskb, dev); + netif_rx(newskb); + dev_kfree_skb(skb); // FIXME: reuse this skb? + } + else { + printk("Can't allocate skb.\n"); + return -ENOMEM; + } + } else { + skb_put(skb,packet->len); + skb->dev = dev; + skb->protocol = priv->type_trans(skb, dev); + + netif_rx(skb); + } dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered " "to upper level.\n",dev->name,packet->len); - - bucket++; // to next Packet Descriptor Block + bucket++; // to next Packet Descriptor Block } while (--trl_count); - if (msg[5] <= I2O_BUCKET_THRESH) // BucketsRemaining + + if (msg[5] <= bucketthresh) // BucketsRemaining i2o_lan_receive_post(dev); return 0; @@ -198,6 +227,7 @@ * Interface to i2o: functions to send lan class request */ + /* * i2o_lan_receive_post(): Post buckets to receive packets. */ @@ -211,25 +241,22 @@ u32 bucket_len = (dev->mtu + dev->hard_header_len); u32 bucket_count; - int n_elems = (iop->inbound_size - 16 ) / 12; // msg header + SGLs + int n_elems = (iop->inbound_size - 16 ) / 12; /* msg header + SGLs */ u32 total = 0; int i; - dprintk(KERN_INFO "%s: Allocating %d buckets (size %d).\n", - dev->name, I2O_BUCKET_COUNT, bucket_len); - - while (total < I2O_BUCKET_COUNT) + while (total < bucketpost) { m = I2O_POST_READ32(iop); if (m == 0xFFFFFFFF) return -ETIMEDOUT; msg = bus_to_virt(iop->mem_offset + m); - bucket_count = (total + n_elems < I2O_BUCKET_COUNT) + bucket_count = (total + n_elems < bucketpost) ? n_elems - : I2O_BUCKET_COUNT - total; - - msg[0] = I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | 1<<12 | SGL_OFFSET_4; + : bucketpost - total; + + msg[0] = I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4; msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->id; msg[2] = priv->unit << 16 | lan_context; // InitiatorContext msg[3] = bucket_count; // BucketCount @@ -248,7 +275,7 @@ i2o_post_message(iop,m); dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n", - dev->name,bucket_count,bucket_len); + dev->name, bucket_count, bucket_len); total += bucket_count; } @@ -264,12 +291,7 @@ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - u32 m; u32 *msg; - - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) - return -ETIMEDOUT; - msg = bus_to_virt(iop->mem_offset + m); + u32 msg[5]; msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->id; @@ -277,7 +299,8 @@ msg[3] = 0; // TransactionContext msg[4] = 1 << 16; // return posted buckets - i2o_post_message(iop,m); + if (i2o_post_this(iop, i2o_dev->id, msg, sizeof(msg)) < 0) + return -ETIMEDOUT; return 0; } @@ -292,12 +315,7 @@ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - u32 m; u32 *msg; - - m = I2O_POST_READ32(iop); - if (m == 0xFFFFFFFF) - return -ETIMEDOUT; - msg = bus_to_virt(iop->mem_offset + m); + u32 msg[5]; msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->id; @@ -305,7 +323,8 @@ msg[3] = 0; // TransactionContext msg[4] = 1 << 16; // return posted buckets - i2o_post_message(iop,m); + if (i2o_post_this(iop, i2o_dev->id, msg, sizeof(msg)) < 0) + return -ETIMEDOUT; return 0; } @@ -330,12 +349,13 @@ // enable batch mode, toggle automatically val = 0x00000000; - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 0, +// val = 0x00000001; // turn off batch mode + if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0003, 0, &val, 4, &priv->reply_flag) <0) printk(KERN_WARNING "Unable to enter I2O LAN batch mode.\n"); else dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name); - +// dprintk(KERN_INFO "%s: I2O LAN batch mode disabled.\n",dev->name); /* * When PacketOrphanlimit is same as the maximum packet length, * the packets will never be split into two separate buckets @@ -344,46 +364,12 @@ /* set LAN_OPERATION attributes */ val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0004, 2, + if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0004, 2, &val, 4, &priv->reply_flag) < 0) printk(KERN_WARNING "i2o_lan: Unable to set PacketOrphanLimit.\n"); else - dprintk(KERN_INFO "PacketOrphanLimit set to %d\n",val); - -#ifdef 0 -/* - * I2O spec 2.0: there should be proper default values for other attributes - * used in batch mode. - */ - - /* set LAN_RECEIVE_INFO attributes */ - - val = 10; // RxMaxBucketsReply - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 3, - &val, 4, &priv->reply_flag) < 0) - printk(KERN_WARNING "%s: Unable to set RxMaxBucketsReply.\n", - dev->name); - - val = 10; // RxMaxPacketsBuckets - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 4, - &val, 4, &priv->reply_flag) < 0) - printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n", - dev->name); - - /* set LAN_BATCH_CONTROL attributes */ - - val = 10; // MaxRxBatchCount - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 5, - &val, 4, &priv->reply_flag) < 0) - printk(KERN_WARNING "%s: Unable to set MaxRxBatchCount.\n", - dev->name); - - val = 10; // MaxTxBatchCount - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 8, - &val, 4, &priv->reply_flag) < 0) - printk(KERN_WARNING "%s Unable to set MaxTxBatchCount.\n", - dev->name); -#endif + dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d\n", + dev->name,val); return; } @@ -398,24 +384,26 @@ struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - i2o_lan_reset(dev); - if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 1, - &priv->reply_flag) < 0) + &priv->reply_flag) < 0) { printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name); return -EAGAIN; } dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", dev->name, i2o_dev->id); + i2o_lan_reset(dev); + dev->tbusy = 0; dev->start = 1; + priv->packet_tresh = dev->mtu - (dev->mtu >> 3); + i2o_set_batch_mode(dev); i2o_lan_receive_post(dev); MOD_INC_USE_COUNT; - + return 0; } @@ -431,15 +419,16 @@ dev->tbusy = 1; dev->start = 0; - if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, - &priv->reply_flag) < 0) - { - printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device (tid=%d)\n", - dev->name, i2o_dev->id); - } +// This is the right place for LanSuspend, but it seems to cause +// a kernel crash when we are using 82558 HDM proto i2o_lan_suspend(dev); + if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, + &priv->reply_flag) < 0) + printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device " + "(tid=%d)\n", dev->name, i2o_dev->id); + MOD_DEC_USE_COUNT; return 0; @@ -452,7 +441,7 @@ */ static int i2o_lan_sdu_send(struct sk_buff *skb, struct device *dev) { -#ifdef 0 +#if 0 /* not yet tested */ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; @@ -461,13 +450,13 @@ dprintk(KERN_INFO "LanSDUSend called, skb->len = %d\n", skb->len); - m = *iop->post_port; - if (m == 0xFFFFFFFF) + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) { - dev_kfree_skb(skb); - return -1; - } - msg = bus_to_virt(iop->mem_offset + m); + dev_kfree_skb(skb); + return -ETIMEDOUT; + } + msg = bus_to_virt(iop->mem_offset + m); msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_4; msg[1] = LAN_SDU_SEND<<24 | HOST_TID<<12 | i2o_dev->id; @@ -483,7 +472,7 @@ msg[7] &= 0x0000FFFF; // followed by two bytes zeros msg[8] = virt_to_bus(skb->data); dev->trans_start = jiffies; - i2o_post_message(iop,m); + i2o_post_message(iop,m); dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n", dev->name,skb->len); @@ -502,16 +491,15 @@ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - u32 m; u32 *msg; + u32 m; u32 *msg; - m = *iop->post_port; + m = I2O_POST_READ32(iop); if (m == 0xFFFFFFFF) { dev_kfree_skb(skb); - return -1; - } - + return -ETIMEDOUT; + } msg = bus_to_virt(iop->mem_offset + m); - + msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4; msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->id; msg[2] = priv->unit << 16 | lan_context; // IntiatorContext @@ -524,37 +512,130 @@ msg[5] = (u32)skb; // TransactionContext msg[6] = virt_to_bus(skb->data); - i2o_post_message(iop,m); - + i2o_post_message(iop,m); + dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n", dev->name, skb->len); return 0; } -/* - * net_device_stats(): Return statistical information. - */ static struct net_device_stats *i2o_lan_get_stats(struct device *dev) { struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; - u64 val[16]; + u64 val64[16]; + u64 supported_group[4] = { 0, 0, 0, 0 }; - /* query LAN_HISTORICAL_STATS scalar parameter group 0x0100 */ + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, + val64, sizeof(val64), &priv->reply_flag) < 0) + dprintk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name); + else { + dprintk("%s: LAN_HISTORICAL_STATS queried.\n",dev->name); + priv->stats.tx_packets = val64[0]; + priv->stats.tx_bytes = val64[1]; + priv->stats.rx_packets = val64[2]; + priv->stats.rx_bytes = val64[3]; + priv->stats.tx_errors = val64[4]; + priv->stats.rx_errors = val64[5]; + priv->stats.rx_dropped = val64[6]; + } - i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, - &val, 16*8, &priv->reply_flag); - priv->stats.tx_packets = val[0]; - priv->stats.tx_bytes = val[1]; - priv->stats.rx_packets = val[2]; - priv->stats.rx_bytes = val[3]; - priv->stats.tx_errors = val[4]; - priv->stats.rx_errors = val[5]; - priv->stats.rx_dropped = val[6]; + i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0180, -1, + &supported_group, sizeof(supported_group), &priv->reply_flag); - // other net_device_stats and FDDI class specific fields follow ... + if (supported_group[2]) { + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0183, -1, + val64, sizeof(val64), &priv->reply_flag) < 0) + dprintk("%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n",dev->name); + else { + dprintk("%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n",dev->name); + priv->stats.multicast = val64[4]; + priv->stats.rx_length_errors = val64[10]; + priv->stats.rx_crc_errors = val64[0]; + } + } + + if (i2o_dev->subclass == I2O_LAN_ETHERNET) + { + u64 supported_stats = 0; + + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0200, -1, + val64, sizeof(val64), &priv->reply_flag) < 0) + dprintk("%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n",dev->name); + else { + dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name); + priv->stats.transmit_collision = val64[1] + val64[2]; + priv->stats.rx_frame_errors = val64[0]; + priv->stats.tx_carrier_errors = val64[6]; + } + + i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0280, -1, + &supported_stats, 8, &priv->reply_flag); + + if (supported_stats != 0) { + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0281, -1, + val64, sizeof(val64), &priv->reply_flag) < 0) + dprintk("%s: Unable to query LAN_OPTIONLA_802_3_HISTORICAL_STATS.\n",dev->name); + else { + dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name); + if (supported_stats & 0x1) + priv->stats.rx_over_errors = val64[0]; + if (supported_stats & 0x4) + priv->stats.tx_heartbeat_errors = val64[2]; + } + } + } + +#ifdef CONFIG_TR + if (i2o_dev->subclass == I2O_LAN_TR) + { + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0300, -1, + val64, sizeof(val64), &priv->reply_flag) < 0) + dprintk("%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n",dev->name); + else { + struct tr_statistics *stats = + (struct tr_statistics *)&priv->stats; + dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name); + + stats->line_errors = val64[0]; + stats->internal_errors = val64[7]; + stats->burst_errors = val64[4]; + stats->A_C_errors = val64[2]; + stats->abort_delimiters = val64[3]; + stats->lost_frames = val64[1]; + /* stats->recv_congest_count = ?; FIXME ??*/ + stats->frame_copied_errors = val64[5]; + stats->frequency_errors = val64[6]; + stats->token_errors = val64[9]; + } + /* Token Ring optional stats not yet defined */ + } +#endif + +#ifdef CONFIG_FDDI + if (i2o_dev->subclass == I2O_LAN_FDDI) + { + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0400, -1, + val64, sizeof(val64), &priv->reply_flag) < 0) + dprintk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name); + else { + dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name); + priv->stats.smt_cf_state = val64[0]; + memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN); + memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN); + priv->stats.mac_error_cts = val64[3]; + priv->stats.mac_lost_cts = val64[4]; + priv->stats.mac_rmt_state = val64[5]; + memcpy(priv->stats.port_lct_fail_cts, &val64[6], 8); + memcpy(priv->stats.port_lem_reject_cts, &val64[7], 8); + memcpy(priv->stats.port_lem_cts, &val64[8], 8); + memcpy(priv->stats.port_pcm_state, &val64[9], 8); + } + /* FDDI optional stats not yet defined */ + } +#endif return (struct net_device_stats *)&priv->stats; } @@ -569,75 +650,78 @@ struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; u32 filter_mask; + u32 work32[64]; - dprintk(KERN_INFO "Entered i2o_lan_set_multicast_list().\n"); + dprintk(KERN_INFO "%s: Entered i2o_lan_set_multicast_list().\n", dev->name); return; -/* - * FIXME: For some reason this kills interrupt handler in i2o_post_wait :-( - * +/* FIXME: Why does the next call kill the interrupt handler? + * The same works fine in function lan_open(), and in i2o_proc.c + * + * *because its trying to sleep in an irq - this must be async - Alan */ - dprintk(KERN_INFO "dev->flags = 0x%08X, dev->mc_count = 0x%08X\n", - dev->flags,dev->mc_count); - if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3, - &filter_mask, 4, &priv->reply_flag) < 0 ) - printk(KERN_WARNING "i2o_lan: Unable to query filter mask.\n"); + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, -1, + &work32, sizeof(work32), &priv->reply_flag) < 0 ) + { + printk(KERN_WARNING "i2o_lan: Unable to query " + " LAN_MAC_ADDRESS table.\n"); + return; + } + printk(KERN_INFO "capab mask = 0x%08X, filter mask = 0x%08X\n", + work32[7], work32[6]); - dprintk(KERN_INFO "filter_mask = 0x%08X\n",filter_mask); + filter_mask = work32[6]; if (dev->flags & IFF_PROMISC) { - // Enable promiscuous mode - filter_mask |= 0x00000002; - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, - &filter_mask, 4, &priv->reply_flag) <0) - printk(KERN_WARNING "i2o_lan: Unable to enable promiscuous multicast mode.\n"); - else - dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n"); - - return; + dprintk(KERN_INFO "i2o_lan: Enabling promiscuous mode...\n"); } -// if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) -// { -// // Disable promiscuous mode, use normal mode. -// hardware_set_filter(NULL); -// -// dprintk(KERN_INFO "i2o_lan: Disabled promiscuous mode, uses normal mode\n"); -// -// filter_mask = 0x00000000; -// i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, -// &filter_mask, 4, &priv->reply_flag); -// -// return; -// } + else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > work32[5]) + { + filter_mask |= 0x00000000; + dprintk(KERN_INFO "i2o_lan: Enabling all multicast mode...\n"); + } - if (dev->mc_count) - { - // Walk the address list, and load the filter -// hardware_set_filter(dev->mc_list); + else if (dev->mc_count) + { + struct dev_mc_list *mclist; + int i; + u8 *work8 = (u8 *)work32; + dprintk(KERN_INFO "i2o_lan: Enabling multicast mode...\n"); filter_mask = 0x00000004; - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, - &filter_mask, 4, &priv->reply_flag) <0) - printk(KERN_WARNING "i2o_lan: Unable to enable Promiscuous multicast mode.\n"); - else - dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n"); - - return; - } - - // Unicast - - filter_mask |= 0x00000300; // Broadcast, Multicast disabled - if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, + + /* Fill the multicast addresses */ + mclist = dev->mc_list; + + for (i = 0; i < dev->mc_count; i++) + { + memcpy(work8, mclist->dmi_addr, mclist->dmi_addrlen); + work8 += 8; + mclist = mclist->next; + } + + if (i2o_clear_table(iop, i2o_dev->id, lan_context, 0x0002, + &priv->reply_flag) < 0 ) + dprintk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name); + + if (i2o_row_add_table(iop, i2o_dev->id, lan_context, 0x0002, -1, + work32, dev->mc_count*8, &priv->reply_flag) < 0) + dprintk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name); + } + + else { + filter_mask |= 0x00000300; // Broadcast, Multicast disabled + dprintk(KERN_INFO "i2o_lan: Enabling unicast mode...\n"); + } + + if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3, &filter_mask, 4, &priv->reply_flag) <0) - printk(KERN_WARNING "i2o_lan: Unable to enable unicast mode.\n"); - else - dprintk(KERN_INFO "i2o_lan: Unicast mode enabled.\n"); + printk(KERN_WARNING "i2o_lan: Unable to set MAC FilterMask.\n"); return; } @@ -648,34 +732,31 @@ struct i2o_lan_local *priv = NULL; u8 hw_addr[8]; unsigned short (*type_trans)(struct sk_buff *, struct device *); + void (*unregister_dev)(struct device *dev); switch (i2o_dev->subclass) { case I2O_LAN_ETHERNET: - /* Note: init_etherdev calls - ether_setup() and register_netdevice() - and allocates the priv structure */ - dev = init_etherdev(NULL, sizeof(struct i2o_lan_local)); if (dev == NULL) return NULL; type_trans = eth_type_trans; + unregister_dev = unregister_netdev; break; -/* #ifdef CONFIG_ANYLAN case I2O_LAN_100VG: - printk(KERN_WARNING "i2o_lan: 100base VG not yet supported\n"); + printk(KERN_ERR "i2o_lan: 100base VG not yet supported\n"); break; #endif -*/ #ifdef CONFIG_TR case I2O_LAN_TR: dev = init_trdev(NULL, sizeof(struct i2o_lan_local)); - if(dev==NULL) + if (dev==NULL) return NULL; type_trans = tr_type_trans; + unregister_dev = unregister_trdev; break; #endif @@ -697,23 +778,23 @@ return NULL; } type_trans = fddi_type_trans; - + unregister_dev = (void *)unregister_netdevice; + fddi_setup(dev); register_netdev(dev); } break; #endif -/* #ifdef CONFIG_FIBRE_CHANNEL case I2O_LAN_FIBRE_CHANNEL: - printk(KERN_WARNING "i2o_lan: Fibre Channel not yet supported\n"); + printk(KERN_INFO "i2o_lan: Fibre Channel not yet supported\n"); break; #endif -*/ + case I2O_LAN_UNKNOWN: default: - printk(KERN_WARNING "i2o_lan: LAN type 0x%08X not supported\n", + printk(KERN_ERR "i2o_lan: LAN type 0x%08X not supported\n", i2o_dev->subclass); return NULL; } @@ -721,16 +802,17 @@ priv = (struct i2o_lan_local *)dev->priv; priv->i2o_dev = i2o_dev; priv->type_trans = type_trans; - + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, lan_context, 0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0) { - printk("%s: Unable to query hardware address.\n", - dev->name); + printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); + unregister_dev(dev); + kfree(dev); return NULL; } - - dprintk("%s hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + + dprintk("%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name,hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], hw_addr[4], hw_addr[5]); @@ -747,8 +829,10 @@ } #ifdef MODULE +#define i2o_lan_init init_module +#endif -int init_module(void) +__init int i2o_lan_init(void) { struct device *dev; struct i2o_lan_local *priv; @@ -772,13 +856,12 @@ for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) { - int class = i2o_dev->class; - - if (class != 0x020) /* not I2O_CLASS_LAN device*/ + if (i2o_dev->class != I2O_CLASS_LAN) continue; if (unit == MAX_LAN_CARDS) { + i2o_unlock_controller(iop); printk(KERN_WARNING "Too many I2O LAN devices.\n"); return -EINVAL; } @@ -786,7 +869,7 @@ dev = i2o_lan_register_device(i2o_dev); if (dev == NULL) { - printk(KERN_WARNING "Unable to register I2O LAN device\n"); + printk(KERN_ERR "Unable to register I2O LAN device\n"); continue; // try next one } priv = (struct i2o_lan_local *)dev->priv; @@ -800,6 +883,7 @@ dev->name, i2o_dev->id, i2o_dev->subclass, priv->unit); } + i2o_unlock_controller(iop); } dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1); @@ -807,6 +891,8 @@ return 0; } +#ifdef MODULE + void cleanup_module(void) { int i; @@ -831,7 +917,7 @@ #endif #ifdef CONFIG_TR case I2O_LAN_TR: - unregister_netdev(dev); + unregister_trdev(dev); kfree(dev); break; #endif @@ -848,7 +934,11 @@ } EXPORT_NO_SYMBOLS; + MODULE_AUTHOR("Univ of Helsinki, CS Department"); MODULE_DESCRIPTION("I2O Lan OSM"); + +MODULE_PARM(bucketpost, "i"); // Number of buckets to post +MODULE_PARM(bucketthresh, "i"); // Bucket post threshold #endif diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h --- v2.3.9/linux/drivers/i2o/i2o_lan.h Wed Jun 2 14:40:22 1999 +++ linux/drivers/i2o/i2o_lan.h Mon Jul 5 20:09:40 1999 @@ -1,7 +1,7 @@ /* * i2o_lan.h LAN Class specific definitions * - * I2O LAN CLASS OSM Prototyping, May 7th 1999 + * I2O LAN CLASS OSM Prototyping, May 17th 1999 * * (C) Copyright 1999 University of Helsinki, * Department of Computer Science @@ -9,16 +9,16 @@ * This code is still under development / test. * * Author: Auvo Häkkinen - * + * Juha Sievänen */ -#ifndef I2O_LAN_H -#define I2O_LAN_H +#ifndef _I2O_LAN_H +#define _I2O_LAN_H /* Tunable parameters first */ -#define I2O_BUCKET_COUNT 64 -#define I2O_BUCKET_THRESH 5 +#define I2O_BUCKET_COUNT 16 +#define I2O_BUCKET_THRESH 0 /* LAN types */ #define I2O_LAN_ETHERNET 0x0030 @@ -75,7 +75,7 @@ #define LAN_SDU_SEND 0x3D #define LAN_RECEIVE_POST 0x3E #define LAN_RESET 0x35 -#define LAN_SUSPEND 0x37 +#define LAN_SUSPEND 0x37 /* LAN DetailedStatusCode defines */ #define I2O_LAN_DSC_SUCCESS 0x00 @@ -109,4 +109,4 @@ struct i2o_packet_info packet_info[1]; }; -#endif /* I2O_LAN_H */ +#endif /* _I2O_LAN_H */ diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c --- v2.3.9/linux/drivers/i2o/i2o_pci.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/i2o/i2o_pci.c Mon Jul 5 20:09:40 1999 @@ -10,6 +10,9 @@ * 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. + * + * TODO: + * Support polled I2O PCI controllers. */ #include @@ -187,9 +190,9 @@ c=i2o_find_controller(i); if(c==NULL) continue; + i2o_unlock_controller(c); if(c->type == I2O_TYPE_PCI) i2o_delete_controller(c); - i2o_unlock_controller(c); } } @@ -209,7 +212,6 @@ { printk("I2O: Failed to initialize iop%d\n", c->unit); i2o_unlock_controller(c); - free_irq(c->bus.pci.irq, c); i2o_delete_controller(c); continue; } @@ -239,4 +241,13 @@ i2o_pci_unload(); } +#else +__init void i2o_pci_init(void) +{ + if(i2o_pci_scan()>=0) + { + printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n"); + i2o_pci_activate(); + } +} #endif diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c --- v2.3.9/linux/drivers/i2o/i2o_proc.c Wed Jun 30 13:38:19 1999 +++ linux/drivers/i2o/i2o_proc.c Mon Jul 5 20:09:40 1999 @@ -17,9 +17,9 @@ * DISCLAIMER: This code is still under development/test and may cause * your system to behave unpredictably. Use at your own discretion. * - * LAN entries by Juha Sievänen(Juha.Sievanen@cs.Helsinki.FI), + * LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI), + * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI) * University of Helsinki, Department of Computer Science - * */ /* @@ -61,8 +61,8 @@ */ typedef struct _i2o_proc_entry_t { - char *name; /* entry name */ - mode_t mode; /* mode */ + char *name; /* entry name */ + mode_t mode; /* mode */ read_proc_t *read_proc; /* read func */ write_proc_t *write_proc; /* write func */ } i2o_proc_entry; @@ -74,66 +74,66 @@ static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_stat(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_dst(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_ds(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_dev(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_ddm(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *); static int print_serial_number(char *, int, u8 *, int); static int i2o_proc_create_entries(void *, - i2o_proc_entry *p, struct proc_dir_entry *); -static void i2o_proc_remove_entries(i2o_proc_entry *p, - struct proc_dir_entry *); + i2o_proc_entry *, struct proc_dir_entry *); +static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *); static int i2o_proc_add_controller(struct i2o_controller *, - struct proc_dir_entry * ); + struct proc_dir_entry * ); static void i2o_proc_remove_controller(struct i2o_controller *, - struct proc_dir_entry * ); + struct proc_dir_entry * ); static int create_i2o_procfs(void); static int destroy_i2o_procfs(void); static void i2o_proc_reply(struct i2o_handler *, struct i2o_controller *, - struct i2o_message *); + struct i2o_message *); static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *, void *); -static int i2o_proc_read_lan_curr_addr(char *, char **, off_t, int, int *, - void *); -#if 0 static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *, void *); -#endif static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int, int *, void *); -#if 0 static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *, void *); -#endif static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_lan_supp_opt_stats(char *, char **, off_t, int, int *, + void *); static int i2o_proc_read_lan_opt_tx_hist_stats(char *, char **, off_t, int, int *, void *); static int i2o_proc_read_lan_opt_rx_hist_stats(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int, + int *, void *); +static int i2o_proc_read_lan_supp_eth_stats(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_opt_eth_stats(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *, + void *); static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *, void *); -#if 0 -/* Do we really need this??? */ - -static loff_t i2o_proc_lseek(struct file *file, loff_t off, int whence) -{ - return 0; -} -#endif - static struct proc_dir_entry *i2o_proc_dir_root; /* @@ -156,6 +156,9 @@ {"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL}, {"stat", S_IFREG|S_IRUGO, i2o_proc_read_stat, NULL}, {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL}, + {"dst", S_IFREG|S_IRUGO, i2o_proc_read_dst, NULL}, + {"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL}, + {"ds", S_IFREG|S_IRUGO, i2o_proc_read_ds, NULL}, {NULL, 0, NULL, NULL} }; @@ -164,8 +167,11 @@ */ static i2o_proc_entry generic_dev_entries[] = { + {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL}, + {"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL}, {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev, NULL}, {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm, NULL}, + {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL}, {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL}, {NULL, 0, NULL, NULL} }; @@ -200,7 +206,7 @@ /* private */ /* - * LAN specific entries + * Generic LAN specific entries * * Should groups with r/w entries have their own subdirectory? * @@ -210,34 +216,79 @@ /* LAN param groups 0000h-0008h */ {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL}, {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL}, -#if 0 {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR, i2o_proc_read_lan_mcast_addr, NULL}, -#endif {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR, i2o_proc_read_lan_batch_control, NULL}, {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL}, {"lan_media_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_media_operation, NULL}, -#if 0 {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL}, -#endif {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL}, {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL}, + /* LAN param groups 0100h, 0180h, 0182h, 0183h */ {"lan_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL}, + {"lan_supp_opt_stats", S_IFREG|S_IRUGO, + i2o_proc_read_lan_supp_opt_stats, NULL}, {"lan_opt_tx_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_opt_tx_hist_stats, NULL}, {"lan_opt_rx_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_opt_rx_hist_stats, NULL}, - {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL}, - /* some useful r/w entries, no write yet */ - {"lan_curr_addr", S_IFREG|S_IRUGO|S_IWUSR, - i2o_proc_read_lan_curr_addr, NULL}, + /* TODO: LAN param group 0184h */ + {NULL, 0, NULL, NULL} +}; + +/* + * Ethernet specific LAN entries + * + */ +static i2o_proc_entry lan_eth_entries[] = +{ + /* LAN param groups 0200h, 0280h, 0281h */ + {"lan_eth_stat", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL}, + {"lan_supp_eth_stats", S_IFREG|S_IRUGO, + i2o_proc_read_lan_supp_eth_stats, NULL}, + {"lan_opt_eth_stats", S_IFREG|S_IRUGO, + i2o_proc_read_lan_opt_eth_stats, NULL}, + {NULL, 0, NULL, NULL} +}; + +/* + * Token Ring specific LAN entries + * + */ +static i2o_proc_entry lan_tr_entries[] = +{ + /* LAN param group 0300h */ + {"lan_tr_stats", S_IFREG|S_IRUGO, + i2o_proc_read_lan_tr_stats, NULL}, + /* TODO: LAN param group 0380h, 0381h */ + {NULL, 0, NULL, NULL} +}; + +/* + * FDDI specific LAN entries + * + */ +static i2o_proc_entry lan_fddi_entries[] = +{ + /* LAN param group 0400h */ + {"lan_fddi_stats", S_IFREG|S_IRUGO, + i2o_proc_read_lan_fddi_stats, NULL}, + /* TODO: LAN param group 0480h, 0481h */ {NULL, 0, NULL, NULL} }; + static u32 i2o_proc_token = 0; +static char *chtostr(u8 *chars, int n) +{ + char tmp[256]; + tmp[0] = 0; + return strncat(tmp, (char *)chars, n); +} + static char* bus_strings[] = { "Local Bus", @@ -253,13 +304,13 @@ static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; void i2o_proc_reply(struct i2o_handler *phdlr, struct i2o_controller *pctrl, - struct i2o_message *pmsg) + struct i2o_message *pmsg) { i2o_proc_token = I2O_POST_WAIT_OK; } int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, - int *eof, void *data) + int *eof, void *data) { struct i2o_controller *c = (struct i2o_controller *)data; pi2o_hrt hrt; @@ -303,8 +354,10 @@ if(hrt->hrt_version) { + kfree(workspace); len += sprintf(buf+len, - "HRT table for controller is too new a version.\n"); + "HRT table for controller is too new a version.\n"); + spin_unlock(&i2o_proc_lock); return len; } @@ -312,6 +365,7 @@ if((count * hrt->entry_len + 8) > 2048) { printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n"); + kfree(workspace); len += sprintf(buf+len, "HRT table too big to fit in buffer.\n"); spin_unlock(&i2o_proc_lock); @@ -490,7 +544,8 @@ break; default: - len += sprintf(buf+len, ": Unknown"); + len += sprintf(buf+len, ": Unknown (0x%02x)", + lct->lct_entry[i].sub_class); break; } break; @@ -519,7 +574,8 @@ break; default: - len += sprintf(buf+len, ": Unknown Sub-Class"); + len += sprintf(buf+len, ": Unknown Sub-Class (0x%02x)", + lct->lct_entry[i].sub_class & 0xFF); break; } break; @@ -642,6 +698,8 @@ len += sprintf(buf+len, "Lowest I2O version supported: "); switch(workspace[2]) { case 0x00: + len += sprintf(buf+len, "1.0\n"); + break; case 0x01: len += sprintf(buf+len, "1.5\n"); break; @@ -653,6 +711,8 @@ len += sprintf(buf+len, "Highest I2O version supported: "); switch(workspace[3]) { case 0x00: + len += sprintf(buf+len, "1.0\n"); + break; case 0x01: len += sprintf(buf+len, "1.5\n"); break; @@ -666,10 +726,12 @@ len += sprintf(buf+len, "Host Unit ID: %0#6x\n", work16[3]); len += sprintf(buf+len, "Segment Number: %0#5x\n", work16[4]&0XFFF); - len += sprintf(buf+len, "I2O Version: "); + len += sprintf(buf+len, "I2O version: "); switch(version) { case 0x00: + len += sprintf(buf+len, "1.0\n"); + break; case 0x01: len += sprintf(buf+len, "1.5\n"); break; @@ -722,7 +784,7 @@ switch (workspace[11]) { case 0x00: - len += sprintf(buf+len, "Memory Mapped\n"); + len += sprintf(buf+len, "Memory mapped\n"); break; case 0x01: len += sprintf(buf+len, "Memory mapped only\n"); @@ -749,26 +811,27 @@ len += sprintf(buf+len, "LCT Size: %d\n", work32[13]); - len += sprintf(buf+len, "Desired Private Memory Space: %d kB\n", + len += sprintf(buf+len, "Desired private memory space: %d kB\n", work32[15]>>10); - len += sprintf(buf+len, "Allocated Private Memory Space: %d kB\n", + len += sprintf(buf+len, "Allocated private memory space: %d kB\n", work32[16]>>10); - len += sprintf(buf+len, "Private Memory Base Address: %0#10x\n", + len += sprintf(buf+len, "Private memory base address: %0#10x\n", work32[17]); - len += sprintf(buf+len, "Desired Private I/O Space: %d kB\n", + len += sprintf(buf+len, "Desired private I/O space: %d kB\n", work32[18]>>10); - len += sprintf(buf+len, "Allocated Private I/O Space: %d kB\n", + len += sprintf(buf+len, "Allocated private I/O space: %d kB\n", work32[19]>>10); - len += sprintf(buf+len, "Private I/O Base Address: %0#10x\n", + len += sprintf(buf+len, "Private I/O base address: %0#10x\n", work32[20]); + kfree(workspace); spin_unlock(&i2o_proc_lock); return len; } int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, - int *eof, void *data) + int *eof, void *data) { struct i2o_controller *c = (struct i2o_controller*)data; static u32 work32[5]; @@ -779,14 +842,14 @@ static char *cpu_table[] = { - "Intel 80960 Series", - "AMD2900 Series", - "Motorola 68000 Series", - "ARM Series", - "MIPS Series", - "Sparc Series", - "PowerPC Series", - "Intel x86 Series" + "Intel 80960 series", + "AMD2900 series", + "Motorola 68000 series", + "ARM series", + "MIPS series", + "Sparc series", + "PowerPC series", + "Intel x86 series" }; spin_lock(&i2o_proc_lock); @@ -807,15 +870,15 @@ return len; } - len += sprintf(buf, "IOP Hardware Information Table\n"); + len += sprintf(buf, "IOP Hardware Information Table (group = 0x0000)\n"); - len += sprintf(buf+len, "I2O Vendor ID: %0#6x\n", work16[0]); - len += sprintf(buf+len, "Product ID: %0#6x\n", work16[1]); - len += sprintf(buf+len, "RAM: %dkB\n", work32[1]>>10); - len += sprintf(buf+len, "Non-Volatile Storage: %dkB\n", work32[2]>>10); + len += sprintf(buf+len, "I2O Vendor ID : %0#6x\n", work16[0]); + len += sprintf(buf+len, "Product ID : %0#6x\n", work16[1]); + len += sprintf(buf+len, "RAM : %dkB\n", work32[1]>>10); + len += sprintf(buf+len, "Non-Volatile Storage : %dkB\n", work32[2]>>10); hwcap = work32[3]; - len += sprintf(buf+len, "Capabilities:\n"); + len += sprintf(buf+len, "Capabilities :\n"); if(hwcap&0x00000001) len += sprintf(buf+len, " Self-booting\n"); if(hwcap&0x00000002) @@ -827,7 +890,7 @@ if(hwcap&0x00000010) len += sprintf(buf+len, " Battery-backed RAM\n"); - len += sprintf(buf+len, "CPU: "); + len += sprintf(buf+len, "CPU : "); if(work8[16] > 8) len += sprintf(buf+len, "Unknown\n"); else @@ -839,14 +902,407 @@ return len; } + +/* Executive group 0003h - Executing DDM List (table) */ +int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + int token; + int i; + + typedef struct _i2o_exec_execute_ddm_table { + u16 ddm_tid; + u8 module_type; + u8 reserved; + u16 i2o_vendor_id; + u16 module_id; + u8 module_name[24]; + u8 module_version[4]; + u32 data_size; + u32 code_size; + } i2o_exec_execute_ddm_table, *pi2o_exec_execute_ddm_table; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + i2o_exec_execute_ddm_table ddm_table[MAX_I2O_MODULES]; + } result; + + i2o_exec_execute_ddm_table ddm_table; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + c, ADAPTER_TID, proc_context, + 0x0003, -1, + NULL, 0, + &result, sizeof(result), &i2o_proc_token); + + if (token<0) + switch (token) + { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + len += sprintf(buf, "Error reading group. BlockStatus %d\n", + token); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Tid Type Vendor Id Name Vrs Data_size Code_size\n"); + ddm_table=result.ddm_table[0]; + + for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i]) + { + len += sprintf(buf+len, "0x%03x ", ddm_table.ddm_tid & 0xFFF); + + switch(ddm_table.module_type) + { + case 0x01: + len += sprintf(buf+len, "Downloaded DDM "); + break; + case 0x22: + len += sprintf(buf+len, "Embedded DDM "); + break; + default: + len += sprintf(buf+len, " "); + } + + len += sprintf(buf+len, "%-0#7x", ddm_table.i2o_vendor_id); + len += sprintf(buf+len, "%-0#7x", ddm_table.module_id); + len += sprintf(buf+len, "%-25s", chtostr(ddm_table.module_name, 24)); + len += sprintf(buf+len, "%-6s", chtostr(ddm_table.module_version,4)); + len += sprintf(buf+len, "%8d ", ddm_table.data_size); + len += sprintf(buf+len, "%8d", ddm_table.code_size); + + len += sprintf(buf+len, "\n"); + } + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Executive group 0004h - Driver Store (scalar) */ +int i2o_proc_read_ds(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + u32 work32[8]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(c, ADAPTER_TID, proc_context, 0x0004, -1, + &work32, sizeof(work32), &i2o_proc_token); + + if (token<0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "Module limit : %d\n" + "Module count : %d\n" + "Current space : %d kB\n" + "Free space : %d kB\n", + work32[0], work32[1], work32[2]>>10, work32[3]>>10); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Executive group 0005h - Driver Store Table (table) */ +int i2o_proc_read_dst(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + typedef struct _i2o_driver_store { + u16 stored_ddm_index; + u8 module_type; + u8 reserved; + u16 i2o_vendor_id; + u16 module_id; + u8 module_name_version[28]; + u8 date[8]; + u32 module_size; + u32 mpb_size; + u32 module_flags; + } i2o_driver_store_table; + + struct i2o_controller *c = (struct i2o_controller*)data; + int token; + int i; + + struct + { + u16 result_count; + u16 pad; + u16 block_size; + u8 block_status; + u8 error_info_size; + u16 row_count; + u16 more_flag; + i2o_driver_store_table dst[MAX_I2O_MODULES]; + } result; + + i2o_driver_store_table dst; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + c, ADAPTER_TID, proc_context, + 0x0005, -1, + NULL, 0, + &result, sizeof(result), &i2o_proc_token); + + if (token<0) + switch (token) + { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + len += sprintf(buf, "Error reading group. " + "BlockStatus %d\n",token); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "# Type Vendor Id Name Vrs Date Mod_size Par_size Flags\n"); + + for(i=0, dst=result.dst[0]; i < result.row_count; dst=result.dst[++i]) + { + len += sprintf(buf+len, "%-3d", dst.stored_ddm_index); + switch(dst.module_type) + { + case 0x01: + len += sprintf(buf+len, "Downloaded DDM "); + break; + case 0x22: + len += sprintf(buf+len, "Embedded DDM "); + break; + default: + len += sprintf(buf+len, " "); + } + +#if 0 + if(c->i2oversion == 0x02) + len += sprintf(buf+len, "%-d", dst.module_state); +#endif + + len += sprintf(buf+len, "%-0#7x", dst.i2o_vendor_id); + len += sprintf(buf+len, "%-0#8x", dst.module_id); + len += sprintf(buf+len, "%-29s", chtostr(dst.module_name_version,28)); + len += sprintf(buf+len, "%-9s", chtostr(dst.date,8)); + len += sprintf(buf+len, "%8d ", dst.module_size); + len += sprintf(buf+len, "%8d ", dst.mpb_size); + len += sprintf(buf+len, "0x%04x", dst.module_flags); +#if 0 + if(c->i2oversion == 0x02) + len += sprintf(buf+len, "%d", + dst.notification_level); +#endif + len += sprintf(buf+len, "\n"); + } + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Generic group F000h - Params Descriptor (table) */ +int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + int token; + int i; + int rows; + u16 work16[2048]; + u16 *group=work16; + int more; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + c, ADAPTER_TID, proc_context, + 0xF000, -1, + NULL, 0, + &work16, sizeof(work16), &i2o_proc_token); + + if (token<0) + switch (token) + { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + len += sprintf(buf, "Error reading table. BlockStatus %d\n", + token); + spin_unlock(&i2o_proc_lock); + return len; + } + + rows=work16[4]; + more=work16[5]; + + len += sprintf(buf+len, "\nPARAMS DESCRIPTOR TABLE:\n\n"); + len += sprintf(buf+len, "# Group FieldCount RowCount Type Add Del Clear\n"); + + group+=64; + + for(i=0; i < rows; i++, group+=16) + { + len += sprintf(buf+len, "%-3d", i); + + len += sprintf(buf+len, "%-0#6x ", group[0]); + len += sprintf(buf+len, "%10d ", group[1]); + len += sprintf(buf+len, "%8d ", group[2]); + + if(group[3]&0x1) + len += sprintf(buf+len, "Table "); + else + len += sprintf(buf+len, "Scalar "); + if(group[3]&0x2) + len += sprintf(buf+len, "x "); + else + len += sprintf(buf+len, " "); + if(group[3]&0x4) + len += sprintf(buf+len, "x "); + else + len += sprintf(buf+len, " "); + if(group[3]&0x8) + len += sprintf(buf+len, "x "); + else + len += sprintf(buf+len, " "); + + len += sprintf(buf+len, "\n"); + } + + if(more) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +/* Generic group F005h - Private message extensions (table) */ +int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + int token; + int i; + int rows; + int more; + u16 work16[1024]; + u16 *field=work16; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + c, ADAPTER_TID, proc_context, + 0xF000, -1, + NULL, 0, + &work16, sizeof(work16), &i2o_proc_token); + + if (token<0) + switch (token) + { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + len += sprintf(buf, "Error reading field. BlockStatus %d\n", + token); + spin_unlock(&i2o_proc_lock); + return len; + } + + rows=work16[4]; + more=work16[5]; + + len += sprintf(buf+len, "Instance# OrgId FunctionCode\n"); + + field+=64; + for(i=0; i < rows; i++, field+=16) + { + len += sprintf(buf+len, "%0#9x ", field[0]); + len += sprintf(buf+len, "%0#6x ", work16[1]); + len += sprintf(buf+len, "%0#6x", work16[2]); + + len += sprintf(buf+len, "\n"); + } + + if(more) + len += sprintf(buf+len, "There is more...\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + int i2o_proc_read_dev(char *buf, char **start, off_t offset, int len, - int *eof, void *data) + int *eof, void *data) { struct i2o_device *d = (struct i2o_device*)data; static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number // == (allow) 512d bytes (max) static u16 *work16 = (u16*)work32; - char sz[17]; int token; spin_lock(&i2o_proc_lock); @@ -866,34 +1322,21 @@ spin_unlock(&i2o_proc_lock); return len; } + + len += sprintf(buf, "Device Class : %s\n", i2o_get_class_name(work16[0])); + len += sprintf(buf+len, "Owner TID : %0#5x\n", work16[2]); + len += sprintf(buf+len, "Parent TID : %0#5x\n", work16[3]); + len += sprintf(buf+len, "Vendor info : %s\n", chtostr((u8 *)(work32+2), 16)); + len += sprintf(buf+len, "Product info : %s\n", chtostr((u8 *)(work32+6), 16)); + len += sprintf(buf+len, "Description : %s\n", chtostr((u8 *)(work32+10), 16)); + len += sprintf(buf+len, "Product rev. : %s\n", chtostr((u8 *)(work32+14), 8)); - len += sprintf(buf, "Device Class: %s\n", i2o_get_class_name(work16[0])); - - len += sprintf(buf+len, "Owner TID: %0#5x\n", work16[2]); - len += sprintf(buf+len, "Parent TID: %0#5x\n", work16[3]); - - memcpy(sz, work32+2, 16); - sz[16] = '\0'; - len += sprintf(buf+len, "Vendor Info: %s\n", sz); - - memcpy(sz, work32+6, 16); - sz[16] = '\0'; - len += sprintf(buf+len, "Product Info: %s\n", sz); - - memcpy(sz, work32+10, 16); - sz[16] = '\0'; - len += sprintf(buf+len, "Description: %s\n", sz); - - memcpy(sz, work32+14, 8); - sz[8] = '\0'; - len += sprintf(buf+len, "Product Revision: %s\n", sz); - - len += sprintf(buf+len, "Serial Number: "); + len += sprintf(buf+len, "Serial number : "); len = print_serial_number(buf, len, (u8*)(work32+16), - /* allow for SNLen plus - * possible trailing '\0' - */ + /* allow for SNLen plus + * possible trailing '\0' + */ sizeof(work32)-(16*sizeof(u32))-2 ); len += sprintf(buf+len, "\n"); @@ -920,13 +1363,12 @@ int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len, - int *eof, void *data) + int *eof, void *data) { struct i2o_device *d = (struct i2o_device*)data; static u32 work32[128]; static u16 *work16 = (u16*)work32; int token; - char mod[25]; spin_lock(&i2o_proc_lock); @@ -946,22 +1388,16 @@ return len; } - len += sprintf(buf, "Registering DDM TID: 0x%03x\n", work16[0]&0xFFF); - - memcpy(mod, (char*)(work16+1), 24); - mod[24] = '\0'; - len += sprintf(buf+len, "Module Name: %s\n", mod); - - memcpy(mod, (char*)(work16+13), 8); - mod[8] = '\0'; - len += sprintf(buf+len, "Module Rev: %s\n", mod); + len += sprintf(buf, "Registering DDM TID : 0x%03x\n", work16[0]&0xFFF); + len += sprintf(buf+len, "Module name : %s\n", chtostr((u8 *)(work16+1), 24)); + len += sprintf(buf+len, "Module revision : %s\n", chtostr((u8 *)(work16+13), 8)); - len += sprintf(buf+len, "Serial Number: "); + len += sprintf(buf+len, "Serial number : "); len = print_serial_number(buf, len, (u8*)(work16+17), - /* allow for SNLen plus - * possible trailing '\0' - */ + /* allow for SNLen plus + * possible trailing '\0' + */ sizeof(work32)-(17*sizeof(u16))-2 ); len += sprintf(buf+len, "\n"); @@ -972,13 +1408,12 @@ } int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, - int *eof, void *data) + int *eof, void *data) { struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[128]; + static u32 work32[256]; int token; - char sz[65]; - + spin_lock(&i2o_proc_lock); len = 0; @@ -997,27 +1432,73 @@ return len; } - memcpy(sz, (char*)work32, 64); - sz[64] = '\0'; - len += sprintf(buf, "Device Name: %s\n", sz); - - memcpy(sz, (char*)(work32+16), 64); - sz[64] = '\0'; - len += sprintf(buf+len, "Service Name: %s\n", sz); - - memcpy(sz, (char*)(work32+32), 64); - sz[64] = '\0'; - len += sprintf(buf+len, "Physical Name: %s\n", sz); - - memcpy(sz, (char*)(work32+48), 4); - sz[4] = '\0'; - len += sprintf(buf+len, "Instance Number: %s\n", sz); + len += sprintf(buf, "Device name : %s\n", chtostr((u8 *)work32, 64)); + len += sprintf(buf+len, "Service name : %s\n", chtostr((u8 *)(work32+16), 64)); + len += sprintf(buf+len, "Physical name : %s\n", chtostr((u8 *)(work32+32), 64)); + len += sprintf(buf+len, "Instance number : %s\n", chtostr((u8 *)(work32+48), 4)); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[12]; + static u16 *work16 = (u16 *)work32; + static u8 *work8 = (u8 *)work32; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0xF103, // ParamGroup F103h (SGL Operating Limits) + -1, // all fields + &work32, + sizeof(work32), + &i2o_proc_token); + + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "SGL chain size : %d\n", work32[0]); + len += sprintf(buf+len, "Max SGL chain size : %d\n", work32[1]); + len += sprintf(buf+len, "SGL chain size target : %d\n", work32[2]); + len += sprintf(buf+len, "SGL frag count : %d\n", work16[6]); + len += sprintf(buf+len, "Max SGL frag count : %d\n", work16[7]); + len += sprintf(buf+len, "SGL frag count target : %d\n", work16[8]); + + if (d->i2oversion == 0x02) + { + len += sprintf(buf+len, "SGL data alignment : %d\n", work16[8]); + len += sprintf(buf+len, "SGL addr limit : %d\n", work8[20]); + len += sprintf(buf+len, "SGL addr sizes supported : "); + if (work8[21] & 0x01) + len += sprintf(buf+len, "32 bit "); + if (work8[21] & 0x02) + len += sprintf(buf+len, "64 bit "); + if (work8[21] & 0x04) + len += sprintf(buf+len, "96 bit "); + if (work8[21] & 0x08) + len += sprintf(buf+len, "128 bit "); + len += sprintf(buf+len, "\n"); + } spin_unlock(&i2o_proc_lock); return len; } + static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len) { int i; @@ -1068,22 +1549,22 @@ case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ pos += sprintf(buff+pos, - "LAN-48 MAC Address @ %02X:%02X:%02X:%02X:%02X:%02X", + "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", serialno[2], serialno[3], serialno[4], serialno[5], serialno[6], serialno[7]); + break; case I2O_SNFORMAT_WAN: /* WAN MAC Address */ /* FIXME: Figure out what a WAN access address looks like?? */ pos += sprintf(buff+pos, "WAN Access Address"); break; - /* plus new in v2.0 */ case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ /* FIXME: Figure out what a LAN-64 address really looks like?? */ pos += sprintf(buff+pos, - "LAN-64 MAC Address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", + "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", serialno[8], serialno[9], serialno[2], serialno[3], serialno[4], serialno[5], @@ -1114,13 +1595,222 @@ case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ default: - pos += sprintf(buff+pos, "Unknown Data Format"); + pos += sprintf(buff+pos, "Unknown data format (0x%02x)", + serialno[0]); break; } return pos; } +const char * i2o_get_connector_type(int conn) +{ + int idx = 16; + static char *i2o_connector_type[] = { + "OTHER", + "UNKNOWN", + "AUI", + "UTP", + "BNC", + "RJ45", + "STP DB9", + "FIBER MIC", + "APPLE AUI", + "MII", + "DB9", + "HSSDC", + "DUPLEX SC FIBER", + "DUPLEX ST FIBER", + "TNC/BNC", + "HW DEFAULT" + }; + + switch(conn) + { + case 0x00000000: + idx = 0; + break; + case 0x00000001: + idx = 1; + break; + case 0x00000002: + idx = 2; + break; + case 0x00000003: + idx = 3; + break; + case 0x00000004: + idx = 4; + break; + case 0x00000005: + idx = 5; + break; + case 0x00000006: + idx = 6; + break; + case 0x00000007: + idx = 7; + break; + case 0x00000008: + idx = 8; + break; + case 0x00000009: + idx = 9; + break; + case 0x0000000A: + idx = 10; + break; + case 0x0000000B: + idx = 11; + break; + case 0x0000000C: + idx = 12; + break; + case 0x0000000D: + idx = 13; + break; + case 0x0000000E: + idx = 14; + break; + case 0xFFFFFFFF: + idx = 15; + break; + } + + return i2o_connector_type[idx]; +} + + +const char * i2o_get_connection_type(int conn) +{ + int idx = 0; + static char *i2o_connection_type[] = { + "Unknown", + "AUI", + "10BASE5", + "FIORL", + "10BASE2", + "10BROAD36", + "10BASE-T", + "10BASE-FP", + "10BASE-FB", + "10BASE-FL", + "100BASE-TX", + "100BASE-FX", + "100BASE-T4", + "1000BASE-SX", + "1000BASE-LX", + "1000BASE-CX", + "1000BASE-T", + "100VG-ETHERNET", + "100VG-TOKEN RING", + "4MBIT TOKEN RING", + "16 Mb Token Ring", + "125 MBAUD FDDI", + "Point-to-point", + "Arbitrated loop", + "Public loop", + "Fabric", + "Emulation", + "Other", + "HW default" + }; + + switch(conn) + { + case I2O_LAN_UNKNOWN: + idx = 0; + break; + case I2O_LAN_AUI: + idx = 1; + break; + case I2O_LAN_10BASE5: + idx = 2; + break; + case I2O_LAN_FIORL: + idx = 3; + break; + case I2O_LAN_10BASE2: + idx = 4; + break; + case I2O_LAN_10BROAD36: + idx = 5; + break; + case I2O_LAN_10BASE_T: + idx = 6; + break; + case I2O_LAN_10BASE_FP: + idx = 7; + break; + case I2O_LAN_10BASE_FB: + idx = 8; + break; + case I2O_LAN_10BASE_FL: + idx = 9; + break; + case I2O_LAN_100BASE_TX: + idx = 10; + break; + case I2O_LAN_100BASE_FX: + idx = 11; + break; + case I2O_LAN_100BASE_T4: + idx = 12; + break; + case I2O_LAN_1000BASE_SX: + idx = 13; + break; + case I2O_LAN_1000BASE_LX: + idx = 14; + break; + case I2O_LAN_1000BASE_CX: + idx = 15; + break; + case I2O_LAN_1000BASE_T: + idx = 16; + break; + case I2O_LAN_100VG_ETHERNET: + idx = 17; + break; + case I2O_LAN_100VG_TR: + idx = 18; + break; + case I2O_LAN_4MBIT: + idx = 19; + break; + case I2O_LAN_16MBIT: + idx = 20; + break; + case I2O_LAN_125MBAUD: + idx = 21; + break; + case I2O_LAN_POINT_POINT: + idx = 22; + break; + case I2O_LAN_ARB_LOOP: + idx = 23; + break; + case I2O_LAN_PUBLIC_LOOP: + idx = 24; + break; + case I2O_LAN_FABRIC: + idx = 25; + break; + case I2O_LAN_EMULATION: + idx = 26; + break; + case I2O_LAN_OTHER: + idx = 27; + break; + case I2O_LAN_DEFAULT: + idx = 28; + break; + } + + return i2o_connection_type[idx]; +} + + /* LAN group 0000h - Device info (scalar) */ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, int *eof, void *data) @@ -1145,7 +1835,7 @@ return len; } - len += sprintf(buf, "LAN Type ........... "); + len += sprintf(buf, "LAN Type : "); switch (work16[0]) { case 0x0030: @@ -1164,7 +1854,7 @@ len += sprintf(buf+len, "Fibre Channel, "); break; default: - len += sprintf(buf+len, "Unknown type, "); + len += sprintf(buf+len, "Unknown type (0x%04x), ", work16[0]); break; } @@ -1178,7 +1868,7 @@ else len += sprintf(buf+len, "simplex\n"); - len += sprintf(buf+len, "Address format: "); + len += sprintf(buf+len, "Address format : "); switch(work8[4]) { case 0x00: len += sprintf(buf+len, "IEEE 48bit\n"); @@ -1187,11 +1877,11 @@ len += sprintf(buf+len, "FC IEEE\n"); break; default: - len += sprintf(buf+len, "Unknown\n"); + len += sprintf(buf+len, "Unknown (0x%02x)\n", work8[4]); break; } - len += sprintf(buf+len, "State: "); + len += sprintf(buf+len, "State : "); switch(work8[5]) { case 0x00: @@ -1210,7 +1900,14 @@ len += sprintf(buf+len, "Resetting\n"); break; case 0x05: - len += sprintf(buf+len, "Error\n"); + len += sprintf(buf+len, "ERROR: "); + if(work16[3]&0x0001) + len += sprintf(buf+len, "TxCU inoperative "); + if(work16[3]&0x0002) + len += sprintf(buf+len, "RxCU inoperative "); + if(work16[3]&0x0004) + len += sprintf(buf+len, "Local mem alloc "); + len += sprintf(buf+len, "\n"); break; case 0x06: len += sprintf(buf+len, "Operational no Rx\n"); @@ -1223,27 +1920,18 @@ break; } - len += sprintf(buf+len, "Error status: "); - if(work16[3]&0x0001) - len += sprintf(buf+len, "Transmit Control Unit Inoperative "); - if(work16[3]&0x0002) - len += sprintf(buf+len, "Receive Control Unit Inoperative\n"); - if(work16[3]&0x0004) - len += sprintf(buf+len, "Local memory Allocation Error\n"); - len += sprintf(buf+len, "\n"); - - len += sprintf(buf+len, "Min Packet size: %d\n", work32[2]); - len += sprintf(buf+len, "Max Packet size: %d\n", work32[3]); - len += sprintf(buf+len, "HW Address: " + len += sprintf(buf+len, "Min packet size : %d\n", work32[2]); + len += sprintf(buf+len, "Max packet size : %d\n", work32[3]); + len += sprintf(buf+len, "HW address : " "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", work8[16],work8[17],work8[18],work8[19], work8[20],work8[21],work8[22],work8[23]); - len += sprintf(buf+len, "Max Tx Wire Speed: " FMT_U64_HEX " bps\n", U64_VAL(&work64[3])); - len += sprintf(buf+len, "Max Rx Wire Speed: " FMT_U64_HEX " bps\n", U64_VAL(&work64[4])); + len += sprintf(buf+len, "Max Tx wire speed : %d bps\n", work64[3]); + len += sprintf(buf+len, "Max Rx wire speed : %d bps\n", work64[4]); - len += sprintf(buf+len, "Min SDU packet size: 0x%08x\n", work32[10]); - len += sprintf(buf+len, "Max SDU packet size: 0x%08x\n", work32[11]); + len += sprintf(buf+len, "Min SDU packet size : 0x%08x\n", work32[10]); + len += sprintf(buf+len, "Max SDU packet size : 0x%08x\n", work32[11]); spin_unlock(&i2o_proc_lock); return len; @@ -1270,60 +1958,65 @@ return len; } - len += sprintf(buf, "Active address: " + len += sprintf(buf, "Active address : " "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", work8[0],work8[1],work8[2],work8[3], work8[4],work8[5],work8[6],work8[7]); - len += sprintf(buf+len, "Current address: " + len += sprintf(buf+len, "Current address : " "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", work8[8],work8[9],work8[10],work8[11], work8[12],work8[13],work8[14],work8[15]); - len += sprintf(buf+len, "Functional address mask: " + len += sprintf(buf+len, "Functional address mask : " "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", work8[16],work8[17],work8[18],work8[19], work8[20],work8[21],work8[22],work8[23]); - len += sprintf(buf+len, "Filter mask: 0x%08x\n", work32[6]); - len += sprintf(buf+len, "HW/DDM capabilities: 0x%08x\n", work32[7]); - len += sprintf(buf+len, " Unicast packets %ssupported (%sabled)\n", - (work32[7]&0x00000001)?"":"not ", - (work32[6]&0x00000001)?"en":"dis"); - len += sprintf(buf+len, " Promiscuous mode %ssupported (%sabled)\n", - (work32[7]&0x00000002)?"":"not", - (work32[6]&0x00000002)?"en":"dis"); - len += sprintf(buf+len, - " Multicast promiscuous mode %ssupported (%sabled)\n", - (work32[7]&0x00000004)?"":"not ", - (work32[6]&0x00000004)?"en":"dis"); - len += sprintf(buf+len, - " Broadcast Reception disabling %ssupported (%sabled)\n", - (work32[7]&0x00000100)?"":"not ", - (work32[6]&0x00000100)?"en":"dis"); - len += sprintf(buf+len, - " Multicast Reception disabling %ssupported (%sabled)\n", - (work32[7]&0x00000200)?"":"not ", - (work32[6]&0x00000200)?"en":"dis"); - len += sprintf(buf+len, - " Functional address disabling %ssupported (%sabled)\n", - (work32[7]&0x00000400)?"":"not ", - (work32[6]&0x00000400)?"en":"dis"); + len += sprintf(buf+len, "HW/DDM capabilities : 0x%08x\n", work32[7]); + len += sprintf(buf+len, " Unicast packets %ssupported\n", + (work32[7]&0x00000001)?"":"not "); + len += sprintf(buf+len, " Promiscuous mode %ssupported\n", + (work32[7]&0x00000002)?"":"not"); + len += sprintf(buf+len, " Promiscuous multicast mode %ssupported\n", + (work32[7]&0x00000004)?"":"not "); + len += sprintf(buf+len," Broadcast reception disabling %ssupported\n", + (work32[7]&0x00000100)?"":"not "); + len += sprintf(buf+len," Multicast reception disabling %ssupported\n", + (work32[7]&0x00000200)?"":"not "); + len += sprintf(buf+len," Functional address disabling %ssupported\n", + (work32[7]&0x00000400)?"":"not "); len += sprintf(buf+len, " MAC reporting %ssupported\n", - (work32[7]&0x00000800)?"":"not "); - - len += sprintf(buf+len, " MAC Reporting mode: "); - if (work32[6]&0x00000800) - len += sprintf(buf+len, "Pass only priority MAC packets\n"); - else if (work32[6]&0x00001000) - len += sprintf(buf+len, "Pass all MAC packets\n"); - else if (work32[6]&0x00001800) - len += sprintf(buf+len, "Pass all MAC packets (promiscuous)\n"); - else - len += sprintf(buf+len, "Do not pass MAC packets\n"); + (work32[7]&0x00000800)?"":"not "); - len += sprintf(buf+len, "Number of multicast addesses: %d\n", work32[8]); - len += sprintf(buf+len, "Perfect filtering for max %d multicast addesses\n", + len += sprintf(buf+len, "Filter mask : 0x%08x\n", work32[6]); + len += sprintf(buf+len, " Unicast packets %s\n", + (work32[6]&0x00000001)?"rejected":"enabled"); + len += sprintf(buf+len, " Promiscuous mode %s\n", + (work32[6]&0x00000002)?"enabled":"disabled"); + len += sprintf(buf+len, " Promiscuous multicast mode %s\n", + (work32[6]&0x00000004)?"enabled":"disabled"); + len += sprintf(buf+len, " Broadcast packets %s\n", + (work32[6]&0x00000100)?"rejected":"enabled"); + len += sprintf(buf+len, " Multicast packets %s\n", + (work32[6]&0x00000200)?"rejected":"enabled"); + len += sprintf(buf+len, " Functional address %s\n", + (work32[6]&0x00000400)?"ignored":"enabled"); + + if (work32[7]&0x00000800) + { + len += sprintf(buf+len, " MAC reporting mode : "); + if (work32[6]&0x00000800) + len += sprintf(buf+len, "Pass only priority MAC packets to user\n"); + else if (work32[6]&0x00001000) + len += sprintf(buf+len, "Pass all MAC packets to user\n"); + else if (work32[6]&0x00001800) + len += sprintf(buf+len, "Pass all MAC packets (promiscuous) to user\n"); + else + len += sprintf(buf+len, "Do not pass MAC packets to user\n"); + } + len += sprintf(buf+len, "Number of multicast addresses : %d\n", work32[8]); + len += sprintf(buf+len, "Perfect filtering for max %d multicast addresses\n", work32[9]); - len += sprintf(buf+len, "Imperfect filtering for max %d multicast addesses\n", + len += sprintf(buf+len, "Imperfect filtering for max %d multicast addresses\n", work32[10]); spin_unlock(&i2o_proc_lock); @@ -1331,97 +2024,76 @@ return len; } -/* LAN group 0001h, field 1 - Current MAC (scalar) */ -int i2o_proc_read_lan_curr_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) -{ - struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[2]; - static u8 *work8 = (u8*)work32; - int token; - - spin_lock(&i2o_proc_lock); - len = 0; - - token = i2o_query_scalar(d->controller, d->id, proc_context, - 0x0001, 2, &work32, 8, &i2o_proc_token); - if(token < 0) - { - len += sprintf(buf, "Timeout waiting for reply from IOP\n"); - spin_unlock(&i2o_proc_lock); - return len; - } - - len += sprintf(buf, "Current address: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - work8[0],work8[1],work8[2],work8[3], - work8[4],work8[5],work8[6],work8[7]); - - spin_unlock(&i2o_proc_lock); - return len; -} - - -#if 0 /* LAN group 0002h - Multicast MAC address table (table) */ -int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, + int len, int *eof, void *data) { struct i2o_device *d = (struct i2o_device*)data; - static u8 work8[32]; - static u32 field32[8]; + static u32 field32[64]; static u8 *field8 = (u8 *)field32; + static u16 *field16 = (u16 *)field32; int token; + int i; spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_table_polled(d->controller, d->id, &work8, 32, - 0x0002, 0, field32, 8); + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->id, proc_context, 0x0002, -1, + NULL, 0, &field32, sizeof(field32), + &i2o_proc_token); + + if (token<0) + switch (token) { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + len += sprintf(buf, "Error reading field. BlockStatus %d\n", + token); + spin_unlock(&i2o_proc_lock); + return len; + } - switch (token) { - case -ETIMEDOUT: - len += sprintf(buf, "Timeout reading table.\n"); - spin_unlock(&i2o_proc_lock); - return len; - break; - case -ENOMEM: - len += sprintf(buf, "No free memory to read the table.\n"); - spin_unlock(&i2o_proc_lock); - return len; - break; - case -EBADR: - len += sprintf(buf, "Error reading field.\n"); - spin_unlock(&i2o_proc_lock); - return len; - break; - default: - break; - } + len += sprintf(buf, "RowCount=%d, MoreFlag=%d\n", + field16[0], field16[1]); - len += sprintf(buf, "Multicast MAC address: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - field8[0],field8[1],field8[2],field8[3], - field8[4],field8[5],field8[6],field8[7]); + field8=(u8 *)&field16[2]; + + for(i=0; icontroller, d->id, proc_context, - 0x0003, -1, &work32, 72, &i2o_proc_token); + 0x0003, -1, &work32, 9*4, &i2o_proc_token); if(token < 0) { len += sprintf(buf, "Timeout waiting for reply from IOP\n"); @@ -1443,26 +2115,26 @@ len += sprintf(buf+len, "\n"); if(d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */ - len += sprintf(buf+len, "Rising Load Delay: %d ms\n", + len += sprintf(buf+len, "Rising load delay : %d ms\n", work32[1]/10); - len += sprintf(buf+len, "Rising Load Threshold: %d ms\n", + len += sprintf(buf+len, "Rising load threshold : %d ms\n", work32[2]/10); - len += sprintf(buf+len, "Falling Load Delay: %d ms\n", + len += sprintf(buf+len, "Falling load delay : %d ms\n", work32[3]/10); - len += sprintf(buf+len, "Falling Load Threshold: %d ms\n", + len += sprintf(buf+len, "Falling load threshold : %d ms\n", work32[4]/10); } - len += sprintf(buf+len, "Max Rx Batch Count: %d\n", work32[5]); - len += sprintf(buf+len, "Max Rx Batch Delay: %d\n", work32[6]); + len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]); + len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]); if(d->i2oversion == 0x00) { len += sprintf(buf+len, - "Transmission Completion Reporting Delay: %d ms\n", + "Transmission completion reporting delay : %d ms\n", work32[7]); } else { - len += sprintf(buf+len, "Max Tx Batch Delay: %d\n", work32[7]); - len += sprintf(buf+len, "Max Tx Batch Count: %d\n", work32[8]); + len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]); + len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]); } spin_unlock(&i2o_proc_lock); @@ -1489,14 +2161,14 @@ return len; } - len += sprintf(buf, "Packet prepadding (32b words): %d\n", work32[0]); - len += sprintf(buf+len, "Transmission error reporting: %s\n", + len += sprintf(buf, "Packet prepadding (32b words) : %d\n", work32[0]); + len += sprintf(buf+len, "Transmission error reporting : %s\n", (work32[1]&1)?"on":"off"); - len += sprintf(buf+len, "Bad packet handling: %s\n", + len += sprintf(buf+len, "Bad packet handling : %s\n", (work32[1]&0x2)?"by host":"by DDM"); - len += sprintf(buf+len, "Packet orphan limit: %d\n", work32[2]); + len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); - len += sprintf(buf+len, "Tx modes:\n"); + len += sprintf(buf+len, "Tx modes :\n"); if (work32[3]&0x00000004) len += sprintf(buf+len, " HW CRC supressed\n"); else @@ -1514,7 +2186,7 @@ if (work32[3]&0x00002000) len += sprintf(buf+len, " Loopback packet not delivered\n"); - len += sprintf(buf+len, "Rx modes:\n"); + len += sprintf(buf+len, "Rx modes :\n"); if (work32[4]&0x00000004) len += sprintf(buf+len, " FCS in payload\n"); if (work32[4]&0x00000100) @@ -1554,402 +2226,127 @@ return len; } - len += sprintf(buf, "Connector type: "); - switch(work32[0]) - { - case 0x00000000: - len += sprintf(buf+len, "OTHER\n"); - break; - case 0x00000001: - len += sprintf(buf+len, "UNKNOWN\n"); - break; - case 0x00000002: - len += sprintf(buf+len, "AUI\n"); - break; - case 0x00000003: - len += sprintf(buf+len, "UTP\n"); - break; - case 0x00000004: - len += sprintf(buf+len, "BNC\n"); - break; - case 0x00000005: - len += sprintf(buf+len, "RJ45\n"); - break; - case 0x00000006: - len += sprintf(buf+len, "STP DB9\n"); - break; - case 0x00000007: - len += sprintf(buf+len, "FIBER MIC\n"); - break; - case 0x00000008: - len += sprintf(buf+len, "APPLE AUI\n"); - break; - case 0x00000009: - len += sprintf(buf+len, "MII\n"); - break; - case 0x0000000A: - len += sprintf(buf+len, "DB9\n"); - break; - case 0x0000000B: - len += sprintf(buf+len, "HSSDC\n"); - break; - case 0x0000000C: - len += sprintf(buf+len, "DUPLEX SC FIBER\n"); - break; - case 0x0000000D: - len += sprintf(buf+len, "DUPLEX ST FIBER\n"); - break; - case 0x0000000E: - len += sprintf(buf+len, "TNC/BNC\n"); - break; - case 0xFFFFFFFF: - len += sprintf(buf+len, "HW DEFAULT\n"); - break; - } - - len += sprintf(buf+len, "Connection type: "); - switch(work32[1]) - { - case I2O_LAN_UNKNOWN: - len += sprintf(buf+len, "UNKNOWN\n"); - break; - case I2O_LAN_AUI: - len += sprintf(buf+len, "AUI\n"); - break; - case I2O_LAN_10BASE5: - len += sprintf(buf+len, "10BASE5\n"); - break; - case I2O_LAN_FIORL: - len += sprintf(buf+len, "FIORL\n"); - break; - case I2O_LAN_10BASE2: - len += sprintf(buf+len, "10BASE2\n"); - break; - case I2O_LAN_10BROAD36: - len += sprintf(buf+len, "10BROAD36\n"); - break; - case I2O_LAN_10BASE_T: - len += sprintf(buf+len, "10BASE-T\n"); - break; - case I2O_LAN_10BASE_FP: - len += sprintf(buf+len, "10BASE-FP\n"); - break; - case I2O_LAN_10BASE_FB: - len += sprintf(buf+len, "10BASE-FB\n"); - break; - case I2O_LAN_10BASE_FL: - len += sprintf(buf+len, "10BASE-FL\n"); - break; - case I2O_LAN_100BASE_TX: - len += sprintf(buf+len, "100BASE-TX\n"); - break; - case I2O_LAN_100BASE_FX: - len += sprintf(buf+len, "100BASE-FX\n"); - break; - case I2O_LAN_100BASE_T4: - len += sprintf(buf+len, "100BASE-T4\n"); - break; - case I2O_LAN_1000BASE_SX: - len += sprintf(buf+len, "1000BASE-SX\n"); - break; - case I2O_LAN_1000BASE_LX: - len += sprintf(buf+len, "1000BASE-LX\n"); - break; - case I2O_LAN_1000BASE_CX: - len += sprintf(buf+len, "1000BASE-CX\n"); - break; - case I2O_LAN_1000BASE_T: - len += sprintf(buf+len, "1000BASE-T\n"); - break; - case I2O_LAN_100VG_ETHERNET: - len += sprintf(buf+len, "100VG-ETHERNET\n"); - break; - case I2O_LAN_100VG_TR: - len += sprintf(buf+len, "100VG-TOKEN RING\n"); - break; - case I2O_LAN_4MBIT: - len += sprintf(buf+len, "4MBIT TOKEN RING\n"); - break; - case I2O_LAN_16MBIT: - len += sprintf(buf+len, "16 Mb Token Ring\n"); - break; - case I2O_LAN_125MBAUD: - len += sprintf(buf+len, "125 MBAUD FDDI\n"); - break; - case I2O_LAN_POINT_POINT: - len += sprintf(buf+len, "Point-to-point\n"); - break; - case I2O_LAN_ARB_LOOP: - len += sprintf(buf+len, "Arbitrated loop\n"); - break; - case I2O_LAN_PUBLIC_LOOP: - len += sprintf(buf+len, "Public loop\n"); - break; - case I2O_LAN_FABRIC: - len += sprintf(buf+len, "Fabric\n"); - break; - case I2O_LAN_EMULATION: - len += sprintf(buf+len, "Emulation\n"); - break; - case I2O_LAN_OTHER: - len += sprintf(buf+len, "Other\n"); - break; - case I2O_LAN_DEFAULT: - len += sprintf(buf+len, "HW default\n"); - break; - } - - len += sprintf(buf+len, "Current Tx Wire Speed: " FMT_U64_HEX " bps\n", - U64_VAL(&work64[1])); - len += sprintf(buf+len, "Current Rx Wire Speed: " FMT_U64_HEX " bps\n", - U64_VAL(&work64[2])); - - len += sprintf(buf+len, "%s duplex\n", (work8[24]&1)?"Full":"Half"); - - len += sprintf(buf+len, "Link status: "); - if(work8[25] == 0x00) - len += sprintf(buf+len, "Unknown\n"); - else if(work8[25] == 0x01) - len += sprintf(buf+len, "Normal\n"); - else if(work8[25] == 0x02) - len += sprintf(buf+len, "Failure\n"); - else if(work8[25] == 0x03) - len += sprintf(buf+len, "Reset\n"); - else - len += sprintf(buf+len, "Unspecified\n"); + len += sprintf(buf, "Connector type : %s\n", + i2o_get_connector_type(work32[0])); + len += sprintf(buf+len, "Connection type : %s\n", + i2o_get_connection_type(work32[1])); + + len += sprintf(buf+len, "Current Tx wire speed : %d bps\n", work64[1]); + len += sprintf(buf+len, "Current Rx wire speed : %d bps\n", work64[2]); + + len += sprintf(buf+len, "Duplex mode : %s duplex\n", + (work8[24]&1)?"Full":"Half"); + len += sprintf(buf+len, "Link status : "); + if(work8[25] == 0x00) + len += sprintf(buf+len, "Unknown\n"); + else if(work8[25] == 0x01) + len += sprintf(buf+len, "Normal\n"); + else if(work8[25] == 0x02) + len += sprintf(buf+len, "Failure\n"); + else if(work8[25] == 0x03) + len += sprintf(buf+len, "Reset\n"); + else + len += sprintf(buf+len, "Unspecified\n"); if (d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */ - len += sprintf(buf+len, "Bad packets handled by: %s\n", + len += sprintf(buf+len, "Bad packets handled by : %s\n", (work8[26] == 0xFF)?"host":"DDM"); } if (d->i2oversion != 0x00) { - len += sprintf(buf+len, "Duplex mode target: "); + len += sprintf(buf+len, "Duplex mode target : "); switch (work8[27]) { case 0: - len += sprintf(buf+len, "Half Duplex\n"); + len += sprintf(buf+len, "Half duplex\n"); break; case 1: - len += sprintf(buf+len, "Full Duplex\n"); - break; - default: - len += sprintf(buf+len, "\n"); - break; - } - - len += sprintf(buf+len, "Connector type target: "); - switch(work32[7]) - { - case 0x00000000: - len += sprintf(buf+len, "OTHER\n"); - break; - case 0x00000001: - len += sprintf(buf+len, "UNKNOWN\n"); - break; - case 0x00000002: - len += sprintf(buf+len, "AUI\n"); - break; - case 0x00000003: - len += sprintf(buf+len, "UTP\n"); - break; - case 0x00000004: - len += sprintf(buf+len, "BNC\n"); - break; - case 0x00000005: - len += sprintf(buf+len, "RJ45\n"); - break; - case 0x00000006: - len += sprintf(buf+len, "STP DB9\n"); - break; - case 0x00000007: - len += sprintf(buf+len, "FIBER MIC\n"); - break; - case 0x00000008: - len += sprintf(buf+len, "APPLE AUI\n"); - break; - case 0x00000009: - len += sprintf(buf+len, "MII\n"); - break; - case 0x0000000A: - len += sprintf(buf+len, "DB9\n"); - break; - case 0x0000000B: - len += sprintf(buf+len, "HSSDC\n"); - break; - case 0x0000000C: - len += sprintf(buf+len, "DUPLEX SC FIBER\n"); - break; - case 0x0000000D: - len += sprintf(buf+len, "DUPLEX ST FIBER\n"); - break; - case 0x0000000E: - len += sprintf(buf+len, "TNC/BNC\n"); - break; - case 0xFFFFFFFF: - len += sprintf(buf+len, "HW DEFAULT\n"); + len += sprintf(buf+len, "Full duplex\n"); break; default: len += sprintf(buf+len, "\n"); break; } - len += sprintf(buf+len, "Connection type target: "); - switch(work32[8]) - { - case I2O_LAN_UNKNOWN: - len += sprintf(buf+len, "UNKNOWN\n"); - break; - case I2O_LAN_AUI: - len += sprintf(buf+len, "AUI\n"); - break; - case I2O_LAN_10BASE5: - len += sprintf(buf+len, "10BASE5\n"); - break; - case I2O_LAN_FIORL: - len += sprintf(buf+len, "FIORL\n"); - break; - case I2O_LAN_10BASE2: - len += sprintf(buf+len, "10BASE2\n"); - break; - case I2O_LAN_10BROAD36: - len += sprintf(buf+len, "10BROAD36\n"); - break; - case I2O_LAN_10BASE_T: - len += sprintf(buf+len, "10BASE-T\n"); - break; - case I2O_LAN_10BASE_FP: - len += sprintf(buf+len, "10BASE-FP\n"); - break; - case I2O_LAN_10BASE_FB: - len += sprintf(buf+len, "10BASE-FB\n"); - break; - case I2O_LAN_10BASE_FL: - len += sprintf(buf+len, "10BASE-FL\n"); - break; - case I2O_LAN_100BASE_TX: - len += sprintf(buf+len, "100BASE-TX\n"); - break; - case I2O_LAN_100BASE_FX: - len += sprintf(buf+len, "100BASE-FX\n"); - break; - case I2O_LAN_100BASE_T4: - len += sprintf(buf+len, "100BASE-T4\n"); - break; - case I2O_LAN_1000BASE_SX: - len += sprintf(buf+len, "1000BASE-SX\n"); - break; - case I2O_LAN_1000BASE_LX: - len += sprintf(buf+len, "1000BASE-LX\n"); - break; - case I2O_LAN_1000BASE_CX: - len += sprintf(buf+len, "1000BASE-CX\n"); - break; - case I2O_LAN_1000BASE_T: - len += sprintf(buf+len, "1000BASE-T\n"); - break; - case I2O_LAN_100VG_ETHERNET: - len += sprintf(buf+len, "100VG-ETHERNET\n"); - break; - case I2O_LAN_100VG_TR: - len += sprintf(buf+len, "100VG-TOKEN RING\n"); - break; - case I2O_LAN_4MBIT: - len += sprintf(buf+len, "4MBIT TOKEN RING\n"); - break; - case I2O_LAN_16MBIT: - len += sprintf(buf+len, "16 Mb Token Ring\n"); - break; - case I2O_LAN_125MBAUD: - len += sprintf(buf+len, "125 MBAUD FDDI\n"); - break; - case I2O_LAN_POINT_POINT: - len += sprintf(buf+len, "Point-to-point\n"); - break; - case I2O_LAN_ARB_LOOP: - len += sprintf(buf+len, "Arbitrated loop\n"); - break; - case I2O_LAN_PUBLIC_LOOP: - len += sprintf(buf+len, "Public loop\n"); - break; - case I2O_LAN_FABRIC: - len += sprintf(buf+len, "Fabric\n"); - break; - case I2O_LAN_EMULATION: - len += sprintf(buf+len, "Emulation\n"); - break; - case I2O_LAN_OTHER: - len += sprintf(buf+len, "Other\n"); - break; - case I2O_LAN_DEFAULT: - len += sprintf(buf+len, "HW default\n"); - break; - default: - len += sprintf(buf+len, "\n"); - break; - } + len += sprintf(buf+len, "Connector type target : %s\n", + i2o_get_connector_type(work32[7])); + len += sprintf(buf+len, "Connection type target : %s\n", + i2o_get_connection_type(work32[8])); } + spin_unlock(&i2o_proc_lock); return len; } -#if 0 /* LAN group 0006h - Alternate address (table) */ int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len, int *eof, void *data) { struct i2o_device *d = (struct i2o_device*)data; - static u8 work8[32]; - static u32 field32[2]; + static u32 field32[64]; static u8 *field8 = (u8 *)field32; + static u16 *field16 = (u16 *)field32; int token; + int i; spin_lock(&i2o_proc_lock); len = 0; - token = i2o_query_table_polled(d->controller, d->id, &work8, 32, - 0x0006, 0, field32, 8); - switch (token) { - case -ETIMEDOUT: - len += sprintf(buf, "Timeout reading table.\n"); - spin_unlock(&i2o_proc_lock); - return len; - break; - case -ENOMEM: - len += sprintf(buf, "No free memory to read the table.\n"); - spin_unlock(&i2o_proc_lock); - return len; - break; - case -EBADR: - len += sprintf(buf, "Error reading field.\n"); - spin_unlock(&i2o_proc_lock); - return len; - break; - default: - break; - } + token = i2o_query_table(I2O_PARAMS_TABLE_GET, + d->controller, d->id, proc_context, 0x0006, -1, + NULL, 0, &field32, sizeof(field32), + &i2o_proc_token); + + if (token<0) + switch (token) { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + len += sprintf(buf, "Error reading field. BlockStatus %d\n", + token); + spin_unlock(&i2o_proc_lock); + return len; + } - len += sprintf(buf, "Alternate Address: " - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - field8[0],field8[1],field8[2],field8[3], - field8[4],field8[5],field8[6],field8[7]); + len += sprintf(buf,"RowCount=%d, MoreFlag=%d\n", field16[0], + field16[1]); + + field8=(u8 *)&field16[2]; + + for(i=0; icontroller, d->id, proc_context, - 0x0007, -1, &work32, 8, &i2o_proc_token); + 0x0007, -1, &work32, 8*4, &i2o_proc_token); if(token < 0) { len += sprintf(buf, "Timeout waiting for reply from IOP\n"); @@ -1957,12 +2354,12 @@ return len; } - len += sprintf(buf, "Max SG Elements per packet: %d\n", work32[0]); - len += sprintf(buf+len, "Max SG Elements per chain: %d\n", work32[1]); - len += sprintf(buf+len, "Max outstanding packets: %d\n", work32[2]); - len += sprintf(buf+len, "Max packets per request: %d\n", work32[3]); + len += sprintf(buf, "Max SG Elements per packet : %d\n", work32[0]); + len += sprintf(buf+len, "Max SG Elements per chain : %d\n", work32[1]); + len += sprintf(buf+len, "Max outstanding packets : %d\n", work32[2]); + len += sprintf(buf+len, "Max packets per request : %d\n", work32[3]); - len += sprintf(buf+len, "Tx modes:\n"); + len += sprintf(buf+len, "Tx modes :\n"); if(work32[4]&0x00000002) len += sprintf(buf+len, " No DA in SGL\n"); if(work32[4]&0x00000004) @@ -1974,25 +2371,25 @@ if(work32[4]&0x00000020) len += sprintf(buf+len, " RIF insertion\n"); if(work32[4]&0x00000100) - len += sprintf(buf+len, " IPv4 Checksum\n"); + len += sprintf(buf+len, " IPv4 checksum\n"); if(work32[4]&0x00000200) - len += sprintf(buf+len, " TCP Checksum\n"); + len += sprintf(buf+len, " TCP checksum\n"); if(work32[4]&0x00000400) - len += sprintf(buf+len, " UDP Checksum\n"); + len += sprintf(buf+len, " UDP checksum\n"); if(work32[4]&0x00000800) - len += sprintf(buf+len, " RSVP Checksum\n"); + len += sprintf(buf+len, " RSVP checksum\n"); if(work32[4]&0x00001000) - len += sprintf(buf+len, " ICMP Checksum\n"); + len += sprintf(buf+len, " ICMP checksum\n"); if (d->i2oversion == 0x00) { if(work32[4]&0x00008000) - len += sprintf(buf+len, " Loopback Enabled\n"); + len += sprintf(buf+len, " Loopback enabled\n"); if(work32[4]&0x00010000) - len += sprintf(buf+len, " Loopback Suppression Enabled\n"); + len += sprintf(buf+len, " Loopback suppression enabled\n"); } else { if(work32[4]&0x00010000) - len += sprintf(buf+len, " Loopback Enabled\n"); + len += sprintf(buf+len, " Loopback enabled\n"); if(work32[4]&0x00020000) - len += sprintf(buf+len, " Loopback Suppression Enabled\n"); + len += sprintf(buf+len, " Loopback suppression enabled\n"); } spin_unlock(&i2o_proc_lock); @@ -2001,17 +2398,17 @@ /* LAN group 0008h - Receive info (scalar) */ int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, - int *eof, void *data) + int *eof, void *data) { struct i2o_device *d = (struct i2o_device*)data; - static u32 work32[10]; + static u32 work32[8]; int token; spin_lock(&i2o_proc_lock); len = 0; token = i2o_query_scalar(d->controller, d->id, proc_context, - 0x0008, -1, &work32, 8, &i2o_proc_token); + 0x0008, -1, &work32, 8*4, &i2o_proc_token); if(token < 0) { len += sprintf(buf, "Timeout waiting for reply from IOP\n"); @@ -2019,14 +2416,14 @@ return len; } - len += sprintf(buf, "Max size of chain element: %d\n", work32[0]); - len += sprintf(buf+len, "Max number of buckets: %d\n", work32[1]); + len += sprintf(buf,"Max size of chain element : %d\n", work32[0]); + len += sprintf(buf+len, "Max number of buckets : %d\n", work32[1]); if (d->i2oversion > 0x00) { /* not in 1.5 */ - len += sprintf(buf+len, "Rx modes: %d\n", work32[2]); - len += sprintf(buf+len, "RxMaxBucketsReply: %d\n", work32[3]); - len += sprintf(buf+len, "RxMaxPacketsPerBuckets: %d\n", work32[4]); - len += sprintf(buf+len, "RxMaxPostBuckets: %d\n", work32[5]); + len += sprintf(buf+len, "RxModes : %d\n", work32[2]); + len += sprintf(buf+len, "RxMaxBucketsReply : %d\n", work32[3]); + len += sprintf(buf+len, "RxMaxPacketsPerBuckets : %d\n", work32[4]); + len += sprintf(buf+len, "RxMaxPostBuckets : %d\n", work32[5]); } spin_unlock(&i2o_proc_lock); @@ -2054,15 +2451,63 @@ return len; } - len += sprintf(buf, "Tx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[0])); - len += sprintf(buf+len, "Tx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); - len += sprintf(buf+len, "Rx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); - len += sprintf(buf+len, "Rx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); - len += sprintf(buf+len, "Tx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); - len += sprintf(buf+len, "Rx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[5])); - len += sprintf(buf+len, "Rx dropped: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); - len += sprintf(buf+len, "Adapter resets: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); - len += sprintf(buf+len, "Adapter suspends: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); + len += sprintf(buf, "Tx packets : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + len += sprintf(buf+len, "Tx bytes : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "Rx packets : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "Rx bytes : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "Tx errors : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "Rx errors : " FMT_U64_HEX "\n", + U64_VAL(&work64[5])); + len += sprintf(buf+len, "Rx dropped : " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "Adapter resets : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n", + U64_VAL(&work64[8])); + + spin_unlock(&i2o_proc_lock); + return len; +} + + +/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */ +int i2o_proc_read_lan_supp_opt_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[4]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0180, -1, &work64, 4*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + if (d->i2oversion == 0x00) + len += sprintf(buf, "Supported stats : " FMT_U64_HEX " \n", + U64_VAL(&work64[0])); + else + { + len += sprintf(buf, "Supported stats (0182h) : " FMT_U64_HEX " \n", + U64_VAL(&work64[1])); + len += sprintf(buf, "Supported stats (0183h) : " FMT_U64_HEX " \n", + U64_VAL(&work64[2])); + len += sprintf(buf, "Supported stats (0184h) : " FMT_U64_HEX " \n", + U64_VAL(&work64[3])); + } spin_unlock(&i2o_proc_lock); return len; @@ -2091,15 +2536,24 @@ return len; } - len += sprintf(buf, "TxRetryCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0])); - len += sprintf(buf+len, "DirectedBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); - len += sprintf(buf+len, "DirectedPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); - len += sprintf(buf+len, "MulticastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); - len += sprintf(buf+len, "MulticastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); - len += sprintf(buf+len, "BroadcastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[5])); - len += sprintf(buf+len, "BroadcastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); - len += sprintf(buf+len, "TotalGroupAddrTxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); - len += sprintf(buf+len, "TotalTxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); + len += sprintf(buf, "TxRetryCount : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + len += sprintf(buf+len, "DirectedBytesTx : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "DirectedPacketsTx : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "MulticastBytesTx : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "MulticastPacketsTx : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "BroadcastBytesTx : " FMT_U64_HEX "\n", + U64_VAL(&work64[5])); + len += sprintf(buf+len, "BroadcastPacketsTx : " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "TotalGroupAddrTxCount : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + len += sprintf(buf+len, "TotalTxPacketsTooShort : " FMT_U64_HEX "\n", + U64_VAL(&work64[8])); spin_unlock(&i2o_proc_lock); return len; @@ -2127,22 +2581,206 @@ return len; } - len += sprintf(buf, "ReceiveCRCErrorCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0])); - len += sprintf(buf+len, "DirectedBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); - len += sprintf(buf+len, "DirectedPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); - len += sprintf(buf+len, "MulticastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); - len += sprintf(buf+len, "MulticastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); - len += sprintf(buf+len, "BroadcastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[5])); - len += sprintf(buf+len, "BroadcastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); - len += sprintf(buf+len, "TotalGroupAddrRxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); - len += sprintf(buf+len, "TotalRxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); - len += sprintf(buf+len, "TotalRxPacketsTooLong: " FMT_U64_HEX "\n", U64_VAL(&work64[9])); - len += sprintf(buf+len, "TotalRuntPacketsReceived: " FMT_U64_HEX "\n", U64_VAL(&work64[10])); + len += sprintf(buf, "ReceiveCRCErrorCount : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + len += sprintf(buf+len, "DirectedBytesRx : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "DirectedPacketsRx : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "MulticastBytesRx : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "MulticastPacketsRx : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "BroadcastBytesRx : " FMT_U64_HEX "\n", + U64_VAL(&work64[5])); + len += sprintf(buf+len, "BroadcastPacketsRx : " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "TotalGroupAddrRxCount : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + len += sprintf(buf+len, "TotalRxPacketsTooShort : " FMT_U64_HEX "\n", + U64_VAL(&work64[8])); + len += sprintf(buf+len, "TotalRxPacketsTooLong : " FMT_U64_HEX "\n", + U64_VAL(&work64[9])); + len += sprintf(buf+len, "TotalRuntPacketsReceived : " FMT_U64_HEX "\n", + U64_VAL(&work64[10])); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0200h - Required Ethernet Statistics (scalar) */ +int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[8]; + int token; + + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0200, -1, &work64, 8*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Rx alignment errors : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + len += sprintf(buf+len, "Tx one collisions : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "Tx multicollisions : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "Tx deferred : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "Tx late collisions : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "Tx max collisions : " FMT_U64_HEX "\n", + U64_VAL(&work64[5])); + len += sprintf(buf+len, "Tx carrier lost : " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0280h - Supported Ethernet Historical Statistics (scalar) */ +int i2o_proc_read_lan_supp_eth_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[1]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0280, -1, &work64, 8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Supported stats : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */ +int i2o_proc_read_lan_opt_eth_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[3]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0281, -1, &work64, 3*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Rx overrun : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + len += sprintf(buf, "Tx underrun : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf, "Tx heartbeat failure : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); spin_unlock(&i2o_proc_lock); return len; } +/* LAN group 0300h - Required Token Ring Statistics (scalar) */ +int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[13]; + int token; + + static char *ring_status[] = + { + "", + "", + "", + "", + "", + "Ring Recovery", + "Single Station", + "Counter Overflow", + "Remove Received", + "", + "Auto-Removal Error 1", + "Lobe Wire Fault", + "Transmit Beacon", + "Soft Error", + "Hard Error", + "Signal Loss" + }; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0300, -1, &work64, 13*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "LineErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[0])); + len += sprintf(buf+len, "LostFrames : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "ACError : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "TxAbortDelimiter : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "BursErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "FrameCopiedErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[5])); + len += sprintf(buf+len, "FrequencyErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "InternalErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + len += sprintf(buf+len, "LastRingStatus : %s\n", ring_status[work64[8]]); + len += sprintf(buf+len, "TokenError : " FMT_U64_HEX "\n", + U64_VAL(&work64[9])); + len += sprintf(buf+len, "UpstreamNodeAddress : " FMT_U64_HEX "\n", + U64_VAL(&work64[10])); + len += sprintf(buf+len, "LastRingID : " FMT_U64_HEX "\n", + U64_VAL(&work64[11])); + len += sprintf(buf+len, "LastBeaconType : " FMT_U64_HEX "\n", + U64_VAL(&work64[12])); + + spin_unlock(&i2o_proc_lock); + return len; +} /* LAN group 0400h - Required FDDI Statistics (scalar) */ int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset, @@ -2208,23 +2846,31 @@ return len; } - len += sprintf(buf, "ConfigurationState: %s\n", conf_state[work64[0]]); - len += sprintf(buf+len, "UpstreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); - len += sprintf(buf+len, "DownStreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); - len += sprintf(buf+len, "FrameErrors: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); - len += sprintf(buf+len, "FramesLost: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); - len += sprintf(buf+len, "RingMgmtState: %s\n", ring_state[work64[5]]); - len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); - len += sprintf(buf+len, "LEMRejects: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); - len += sprintf(buf+len, "LEMCount: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); - len += sprintf(buf+len, "LConnectionState: %s\n", link_state[work64[9]]); + len += sprintf(buf, "ConfigurationState : %s\n", conf_state[work64[0]]); + len += sprintf(buf+len, "UpstreamNode : " FMT_U64_HEX "\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "DownStreamNode : " FMT_U64_HEX "\n", + U64_VAL(&work64[2])); + len += sprintf(buf+len, "FrameErrors : " FMT_U64_HEX "\n", + U64_VAL(&work64[3])); + len += sprintf(buf+len, "FramesLost : " FMT_U64_HEX "\n", + U64_VAL(&work64[4])); + len += sprintf(buf+len, "RingMgmtState : %s\n", ring_state[work64[5]]); + len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n", + U64_VAL(&work64[6])); + len += sprintf(buf+len, "LEMRejects : " FMT_U64_HEX "\n", + U64_VAL(&work64[7])); + len += sprintf(buf+len, "LEMCount : " FMT_U64_HEX "\n", + U64_VAL(&work64[8])); + len += sprintf(buf+len, "LConnectionState : %s\n", + link_state[work64[9]]); spin_unlock(&i2o_proc_lock); return len; } -static int i2o_proc_create_entries(void *data, - i2o_proc_entry *pentry, struct proc_dir_entry *parent) +static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry, + struct proc_dir_entry *parent) { struct proc_dir_entry *ent; @@ -2245,7 +2891,7 @@ } static void i2o_proc_remove_entries(i2o_proc_entry *pentry, - struct proc_dir_entry *parent) + struct proc_dir_entry *parent) { while(pentry->name != NULL) { @@ -2255,7 +2901,7 @@ } static int i2o_proc_add_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *root ) + struct proc_dir_entry *root ) { struct proc_dir_entry *dir, *dir1; struct i2o_device *dev; @@ -2291,6 +2937,23 @@ break; case I2O_CLASS_LAN: i2o_proc_create_entries(dev, lan_entries, dir1); + switch(dev->subclass) + { + case I2O_LAN_ETHERNET: + i2o_proc_create_entries(dev, lan_eth_entries, + dir1); + break; + case I2O_LAN_FDDI: + i2o_proc_create_entries(dev, lan_fddi_entries, + dir1); + break; + case I2O_LAN_TR: + i2o_proc_create_entries(dev, lan_tr_entries, + dir1); + break; + default: + break; + } break; default: break; @@ -2301,17 +2964,58 @@ } static void i2o_proc_remove_controller(struct i2o_controller *pctrl, - struct proc_dir_entry *parent) + struct proc_dir_entry *parent) { char buff[10]; + char dev_id[10]; + struct proc_dir_entry *de; + struct i2o_device *dev; - sprintf(buff, "iop%d", pctrl->unit); + /* Remove unused device entries */ + for(dev=pctrl->devices; dev; dev=dev->next) + { + de=dev->proc_entry; + sprintf(dev_id, "%0#5x", dev->id); - i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); + /* Would it be safe to remove _files_ even if they are in use? */ + if((de) && (!de->count)) + { + i2o_proc_remove_entries(generic_dev_entries, de); - remove_proc_entry(buff, parent); + switch(dev->class) + { + case I2O_CLASS_SCSI_PERIPHERAL: + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + i2o_proc_remove_entries(rbs_dev_entries, de); + break; + case I2O_CLASS_LAN: + i2o_proc_remove_entries(lan_entries, de); + switch(dev->subclass) + { + case I2O_LAN_ETHERNET: + i2o_proc_remove_entries(lan_eth_entries, de); + break; + case I2O_LAN_FDDI: + i2o_proc_remove_entries(lan_fddi_entries, de); + break; + case I2O_LAN_TR: + i2o_proc_remove_entries(lan_tr_entries, de); + break; + } + } + remove_proc_entry(dev_id, parent); + } + } - pctrl->proc_entry = NULL; + if(!pctrl->proc_entry->count) + { + sprintf(buff, "iop%d", pctrl->unit); + + i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); + + remove_proc_entry(buff, parent); + pctrl->proc_entry = NULL; + } } static int create_i2o_procfs(void) @@ -2327,7 +3031,10 @@ { pctrl = i2o_find_controller(i); if(pctrl) + { i2o_proc_add_controller(pctrl, i2o_proc_dir_root); + i2o_unlock_controller(pctrl); + } }; return 0; @@ -2345,19 +3052,25 @@ { pctrl = i2o_find_controller(i); if(pctrl) + { i2o_proc_remove_controller(pctrl, i2o_proc_dir_root); + i2o_unlock_controller(pctrl); + } }; - remove_proc_entry("i2o", 0); + if(!i2o_proc_dir_root->count) + remove_proc_entry("i2o", 0); + else + return -1; + return 0; } #ifdef MODULE +#define i2o_proc_init init_module +#endif -MODULE_AUTHOR("Intel Corporation"); -MODULE_DESCRIPTION("I2O procfs Handler"); - -int init_module(void) +__init int i2o_proc_init(void) { if(create_i2o_procfs()) return -EBUSY; @@ -2372,6 +3085,12 @@ return 0; } + +#ifdef MODULE + + +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("I2O procfs Handler"); void cleanup_module(void) { diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_proc.h linux/drivers/i2o/i2o_proc.h --- v2.3.9/linux/drivers/i2o/i2o_proc.h Wed Jun 2 14:40:22 1999 +++ linux/drivers/i2o/i2o_proc.h Mon Jul 5 20:09:40 1999 @@ -32,110 +32,5 @@ u8 reserved; u8 req_status; } i2o_mult_reply_msg, *pi2o_mult_reply_msg; - -/************************************************************************** - * HRT related constants and structures - **************************************************************************/ -#define I2O_BUS_LOCAL 0 -#define I2O_BUS_ISA 1 -#define I2O_BUS_EISA 2 -#define I2O_BUS_MCA 3 -#define I2O_BUS_PCI 4 -#define I2O_BUS_PCMCIA 5 -#define I2O_BUS_NUBUS 6 -#define I2O_BUS_CARDBUS 7 -#define I2O_BUS_UNKNOWN 0x80 - -typedef struct _i2o_pci_bus { - u8 PciFunctionNumber; - u8 PciDeviceNumber; - u8 PciBusNumber; - u8 reserved; - u16 PciVendorID; - u16 PciDeviceID; -} i2o_pci_bus, *pi2o_pci_bus; - -typedef struct _i2o_local_bus { - u16 LbBaseIOPort; - u16 reserved; - u32 LbBaseMemoryAddress; -} i2o_local_bus, *pi2o_local_bus; - -typedef struct _i2o_isa_bus { - u16 IsaBaseIOPort; - u8 CSN; - u8 reserved; - u32 IsaBaseMemoryAddress; -} i2o_isa_bus, *pi2o_isa_bus; - -/* I2O_EISA_BUS_INFO */ -typedef struct _i2o_eisa_bus_info { - u16 EisaBaseIOPort; - u8 reserved; - u8 EisaSlotNumber; - u32 EisaBaseMemoryAddress; -} i2o_eisa_bus, *pi2o_eisa_bus; - -typedef struct _i2o_mca_bus { - u16 McaBaseIOPort; - u8 reserved; - u8 McaSlotNumber; - u32 McaBaseMemoryAddress; -} i2o_mca_bus, *pi2o_mca_bus; - -typedef struct _i2o_other_bus { - u16 BaseIOPort; - u16 reserved; - u32 BaseMemoryAddress; -} i2o_other_bus, *pi2o_other_bus; - - -typedef struct _i2o_hrt_entry { - u32 adapter_id; - u32 parent_tid:12; - u32 state:4; - u32 bus_num:8; - u32 bus_type:8; - union { - i2o_pci_bus pci_bus; - i2o_local_bus local_bus; - i2o_isa_bus isa_bus; - i2o_eisa_bus eisa_bus; - i2o_mca_bus mca_bus; - i2o_other_bus other_bus; - } bus; -} i2o_hrt_entry, *pi2o_hrt_entry; - -typedef struct _i2o_hrt { - u16 num_entries; - u8 entry_len; - u8 hrt_version; - u32 change_ind; - i2o_hrt_entry hrt_entry[1]; -} i2o_hrt, *pi2o_hrt; - -typedef struct _i2o_lct_entry { - u32 entry_size:16; - u32 tid:12; - u32 reserved:4; - u32 change_ind; - u32 device_flags; - u32 class_id; - u32 sub_class; - u32 user_tid:12; - u32 parent_tid:12; - u32 bios_info:8; - u8 identity_tag[8]; - u32 event_capabilities; -} i2o_lct_entry, *pi2o_lct_entry; - -typedef struct _i2o_lct { - u32 table_size:16; - u32 boot_tid:12; - u32 lct_ver:4; - u32 iop_flags; - u32 current_change_ind; - i2o_lct_entry lct_entry[1]; -} i2o_lct, *pi2o_lct; - + #endif /* i2oproc_h */ diff -u --recursive --new-file v2.3.9/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c --- v2.3.9/linux/drivers/i2o/i2o_scsi.c Wed Jun 2 14:40:22 1999 +++ linux/drivers/i2o/i2o_scsi.c Mon Jul 5 20:35:18 1999 @@ -26,6 +26,9 @@ * Fixes: * Steve Ralston : Scatter gather now works * + * To Do + * 64bit cleanups + * Fix the resource management problems. */ #include @@ -37,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -83,6 +85,7 @@ /* * SG Chain buffer support... */ + #define SG_MAX_FRAGS 64 /* @@ -204,9 +207,12 @@ } - /* Low byte is the adapter status, next is the device */ - as=(u8)m[4]; - ds=(u8)(m[4]>>8); + /* + * Low byte is device status, next is adapter status, + * (then one byte reserved), then request status. + */ + ds=(u8)m[4]; + as=(u8)(m[4]>>8); st=(u8)(m[4]>>24); dprintk(("i2o got a scsi reply %08X: ", m[0])); @@ -264,10 +270,10 @@ dprintk((KERN_DEBUG "SCSI error %08X", m[4])); - if (ds == 0x0E) + if (as == 0x0E) /* SCSI Reset */ current_command->result = DID_RESET << 16; - else if (ds == 0x0F) + else if (as == 0x0F) current_command->result = DID_PARITY << 16; else current_command->result = DID_ERROR << 16; @@ -433,7 +439,6 @@ ) continue; -// printk("Found a controller.\n"); shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); save_flags(flags); cli(); @@ -443,7 +448,6 @@ shpnt->irq = 0; shpnt->this_id = /* Good question */15; restore_flags(flags); -// printk("Scanning I2O port %d.\n", d->id); i2o_scsi_init(c, d, shpnt); count++; } @@ -534,25 +538,12 @@ int direction; int scsidir; u32 len; + u32 reqlen; + u32 tag; static int max_qd = 1; /* - * The scsi layer should be handling this stuff - */ - - if(is_dir_out(SCpnt)) - { - direction=0x04000000; - scsidir=0x80000000; - } - else - { - scsidir=0x40000000; - direction=0x00000000; - } - - /* * Do the incoming paperwork */ @@ -604,13 +595,45 @@ * Put together a scsi execscb message */ + len = SCpnt->request_bufflen; + direction = 0x00000000; // SGL IN (osm<--iop) + + /* + * The scsi layer should be handling this stuff + */ + + scsidir = 0x00000000; // DATA NO XFER + if(len) + { + if(is_dir_out(SCpnt)) + { + direction=0x04000000; // SGL OUT (osm-->iop) + scsidir =0x80000000; // DATA OUT (iop-->dev) + } + else + { + scsidir =0x40000000; // DATA IN (iop<--dev) + } + } + msg[1] = I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid; msg[2] = scsi_context; /* So the I2O layer passes to us */ /* Sorry 64bit folks. FIXME */ msg[3] = (u32)SCpnt; /* We want the SCSI control block back */ - /* Direction, disconnect ok, no tagging (yet) */ - msg[4] = scsidir|(1<<29)|SCpnt->cmd_len; + /* LSI_920_PCI_QUIRK + * + * Intermittant observations of msg frame word data corruption + * observed on msg[4] after: + * WRITE, READ-MODIFY-WRITE + * operations. 19990606 -sralston + * + * (Hence we build this word via tag. Its good practice anyway + * we don't want fetches over PCI needlessly) + */ + + tag=0; + /* * Attach tags to the devices */ @@ -623,25 +646,24 @@ */ if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ)) { - msg[4]|=(1<<23)|(1<<24); + tag=0x01800000; /* ORDERED! */ hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies; } - else switch(SCpnt->tag) + else { - case SIMPLE_QUEUE_TAG: - msg[4]|=(1<<23); - break; - case HEAD_OF_QUEUE_TAG: - msg[4]|=(1<<24); - break; - case ORDERED_QUEUE_TAG: - msg[4]|=(1<<23)|(1<<24); - break; - default: - msg[4]|=(1<<23); + /* Hmmm... I always see value of 0 here, + * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston + */ + if(SCpnt->tag == HEAD_OF_QUEUE_TAG) + tag=0x01000000; + else if(SCpnt->tag == ORDERED_QUEUE_TAG) + tag=0x01800000; } } + /* Direction, disconnect ok, tag, CDBLen */ + msg[4] = scsidir|0x20000000|SCpnt->cmd_len|tag; + mptr=msg+5; /* @@ -652,7 +674,7 @@ mptr+=4; lenptr=mptr++; /* Remember me - fill in when we know */ - + reqlen = 12; // SINGLE SGE /* * Now fill in the SGList and command * @@ -664,21 +686,22 @@ if(SCpnt->use_sg) { struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; + int chain = 0; if((sg_max_frags > 11) && (SCpnt->use_sg > 11)) { + chain = 1; /* * Need to chain! */ - SCpnt->host_scribble = (void*)(sg_chain_pool + sg_chain_tag); *mptr++=direction|0xB0000000|(SCpnt->use_sg*2*4); - *mptr=virt_to_bus(SCpnt->host_scribble); - mptr = (u32*)SCpnt->host_scribble; + *mptr=virt_to_bus(sg_chain_pool + sg_chain_tag); + mptr = (u32*)(sg_chain_pool + sg_chain_tag); if (SCpnt->use_sg > max_sg_len) { max_sg_len = SCpnt->use_sg; printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n", - SCpnt, SCpnt->use_sg, (chain_buf*)SCpnt->host_scribble-sg_chain_pool); + SCpnt, SCpnt->use_sg, sg_chain_tag); } if ( ++sg_chain_tag == SG_MAX_BUFS ) sg_chain_tag = 0; @@ -693,7 +716,15 @@ *mptr++=virt_to_bus(sg->address); sg++; } - mptr[-2]|=0xC0000000; /* End of List and block */ + + /* Make this an end of list. Again evade the 920 bug and + unwanted PCI read traffic */ + + mptr[-2]=direction|0xD0000000|(sg-1)->length; + + if(!chain) + reqlen = mptr - msg; + *lenptr=len; if(len != SCpnt->underflow) printk("Cmd len %08X Cmd underflow %08X\n", @@ -703,19 +734,23 @@ { dprintk(("non sg for %p, %d\n", SCpnt->request_buffer, SCpnt->request_bufflen)); - *mptr++=0xD0000000|direction|SCpnt->request_bufflen; - *mptr++=virt_to_bus(SCpnt->request_buffer); *lenptr = len = SCpnt->request_bufflen; - /* No transfer ? - fix up the request */ if(len == 0) - msg[4]&=~0xC0000000; + { + reqlen = 9; + } + else + { + *mptr++=0xD0000000|direction|SCpnt->request_bufflen; + *mptr++=virt_to_bus(SCpnt->request_buffer); + } } /* * Stick the headers on */ - msg[0] = (mptr-msg)<<16 | SGL_OFFSET_10; + msg[0] = reqlen<<16 | SGL_OFFSET_10; /* Queue the message */ i2o_post_message(c,m); @@ -757,7 +792,7 @@ u32 m; int tid; - printk("i2o_scsi_abort\n"); + printk("i2o_scsi: Aborting command block.\n"); host = SCpnt->host; hostdata = (struct i2o_scsi_host *)host->hostdata; @@ -790,8 +825,6 @@ wmb(); i2o_post_message(c,m); wmb(); -// SCpnt->result = DID_RESET << 16; -// SCpnt->scsi_done(SCpnt); return SCSI_ABORT_PENDING; } @@ -804,12 +837,12 @@ u32 m; u32 *msg; - printk("i2o_scsi_reset\n"); - /* * Find the TID for the bus */ + printk("i2o_scsi: Attempting to reset the bus.\n"); + host = SCpnt->host; hostdata = (struct i2o_scsi_host *)host->hostdata; tid = hostdata->bus_task; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.3.9/linux/drivers/isdn/avmb1/capidrv.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/avmb1/capidrv.c Mon Jul 5 20:09:40 1999 @@ -1386,13 +1386,14 @@ handle_data(&s_cmsg, skb); continue; } - kfree_skb(skb); if ((s_cmsg.adr.adrController & 0xffffff00) == 0) handle_controller(&s_cmsg); else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0) handle_plci(&s_cmsg); else handle_ncci(&s_cmsg); + + kfree_skb(skb); } } diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c --- v2.3.9/linux/drivers/isdn/hisax/amd7930.c Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/hisax/amd7930.c Tue Jul 6 19:05:48 1999 @@ -747,8 +747,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c --- v2.3.9/linux/drivers/isdn/hisax/asuscom.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/asuscom.c Tue Jul 6 19:05:48 1999 @@ -334,8 +334,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.3.9/linux/drivers/isdn/hisax/avm_a1.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/avm_a1.c Tue Jul 6 19:05:48 1999 @@ -234,8 +234,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.3.9/linux/drivers/isdn/hisax/config.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/config.c Tue Jul 6 19:05:48 1999 @@ -442,8 +442,8 @@ #ifdef MODULE #define HiSax_init init_module #else -__initfunc(void -HiSax_setup(char *str, int *ints)) +void __init +HiSax_setup(char *str, int *ints) { int i, j, argc; @@ -1236,8 +1236,8 @@ } -__initfunc(int -HiSax_init(void)) +int __init +HiSax_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.3.9/linux/drivers/isdn/hisax/diva.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/diva.c Tue Jul 6 19:05:48 1999 @@ -459,8 +459,8 @@ static struct pci_dev *dev_diva __initdata = NULL; static struct pci_dev *dev_diva_u __initdata = NULL; -__initfunc(int -setup_diva(struct IsdnCard *card)) +int __init +setup_diva(struct IsdnCard *card) { int bytecnt; u_char val; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/foreign.c linux/drivers/isdn/hisax/foreign.c --- v2.3.9/linux/drivers/isdn/hisax/foreign.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/isdn/hisax/foreign.c Tue Jul 6 19:05:48 1999 @@ -744,8 +744,8 @@ extern struct foreign_interface dbri_foreign_interface; #endif -__initfunc(int -setup_foreign(struct IsdnCard *card)) +int __init +setup_foreign(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c --- v2.3.9/linux/drivers/isdn/hisax/hfc_2bds0.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/hfc_2bds0.c Tue Jul 6 19:05:48 1999 @@ -1166,8 +1166,8 @@ #endif } -__initfunc(unsigned int -*init_send_hfcd(int cnt)) +unsigned int __init +*init_send_hfcd(int cnt) { int i, *send; @@ -1181,8 +1181,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c --- v2.3.9/linux/drivers/isdn/hisax/hfc_2bs0.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/hfc_2bs0.c Tue Jul 6 19:05:48 1999 @@ -555,8 +555,8 @@ return (0); } -__initfunc(void -init_send(struct BCState *bcs)) +void __init +init_send(struct BCState *bcs) { int i; @@ -569,8 +569,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c --- v2.3.9/linux/drivers/isdn/hisax/ix1_micro.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/ix1_micro.c Tue Jul 6 19:05:48 1999 @@ -289,8 +289,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c --- v2.3.9/linux/drivers/isdn/hisax/mic.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/mic.c Tue Jul 6 19:05:48 1999 @@ -231,8 +231,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.3.9/linux/drivers/isdn/hisax/netjet.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/netjet.c Tue Jul 6 19:05:48 1999 @@ -858,8 +858,8 @@ } -__initfunc(void -inittiger(struct IsdnCardState *cs)) +void __init +inittiger(struct IsdnCardState *cs) { if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int), GFP_KERNEL | GFP_DMA))) { @@ -1050,8 +1050,8 @@ static struct pci_dev *dev_netjet __initdata = NULL; -__initfunc(int -setup_netjet(struct IsdnCard *card)) +int __init +setup_netjet(struct IsdnCard *card) { int bytecnt; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.3.9/linux/drivers/isdn/hisax/niccy.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/niccy.c Tue Jul 6 19:05:48 1999 @@ -263,8 +263,8 @@ 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]; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.3.9/linux/drivers/isdn/hisax/sedlbauer.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/sedlbauer.c Tue Jul 6 19:05:48 1999 @@ -533,8 +533,8 @@ static int pci_index __initdata = 0; #endif -__initfunc(int -setup_sedlbauer(struct IsdnCard *card)) +int __init +setup_sedlbauer(struct IsdnCard *card) { int bytecnt, ver, val; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c --- v2.3.9/linux/drivers/isdn/hisax/sportster.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/sportster.c Tue Jul 6 19:05:48 1999 @@ -204,8 +204,8 @@ return(0); } -__initfunc(int -get_io_range(struct IsdnCardState *cs)) +int __init +get_io_range(struct IsdnCardState *cs) { int i, j, adr; @@ -230,8 +230,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c --- v2.3.9/linux/drivers/isdn/hisax/teleint.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/teleint.c Tue Jul 6 19:05:49 1999 @@ -289,8 +289,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.3.9/linux/drivers/isdn/hisax/teles0.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/teles0.c Tue Jul 6 19:05:49 1999 @@ -302,8 +302,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 --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.3.9/linux/drivers/isdn/hisax/teles3.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/teles3.c Tue Jul 6 19:05:49 1999 @@ -321,8 +321,8 @@ return(0); } -__initfunc(int -setup_teles3(struct IsdnCard *card)) +int __init +setup_teles3(struct IsdnCard *card) { u_char val; struct IsdnCardState *cs = card->cs; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/hisax/teles3c.c linux/drivers/isdn/hisax/teles3c.c --- v2.3.9/linux/drivers/isdn/hisax/teles3c.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/teles3c.c Tue Jul 6 19:05:49 1999 @@ -140,8 +140,8 @@ return(0); } -__initfunc(int -setup_t163c(struct IsdnCard *card)) +int __init +setup_t163c(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; char tmp[64]; diff -u --recursive --new-file v2.3.9/linux/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c --- v2.3.9/linux/drivers/isdn/isdn_bsdcomp.c Sun May 23 10:03:42 1999 +++ linux/drivers/isdn/isdn_bsdcomp.c Mon Jul 5 20:35:18 1999 @@ -64,7 +64,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ diff -u --recursive --new-file v2.3.9/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.3.9/linux/drivers/macintosh/macserial.c Mon Jun 7 12:12:32 1999 +++ linux/drivers/macintosh/macserial.c Thu Jul 1 15:09:01 1999 @@ -1558,7 +1558,6 @@ char_time = MIN(char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; diff -u --recursive --new-file v2.3.9/linux/drivers/misc/Config.in linux/drivers/misc/Config.in --- v2.3.9/linux/drivers/misc/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/misc/Config.in Thu Jul 1 14:22:57 1999 @@ -0,0 +1,37 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +# Parport configuration. +# + +tristate 'Parallel port support' CONFIG_PARPORT +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_PC" != "n" ]; then + bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO + fi + if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT + if [ "$CONFIG_ZORRO" != "n" ]; then + dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT + fi + else + define_bool CONFIG_PARPORT_AMIGA n + define_bool CONFIG_PARPORT_MFC3 n + fi + if [ "$CONFIG_ATARI" = "y" ]; then + dep_tristate ' Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT + else + define_bool CONFIG_PARPORT_ATARI n + fi + + # If exactly one hardware type is selected then parport will optimise away + # support for loading any others. Defeat this if the user is keen. + bool ' Support foreign hardware' CONFIG_PARPORT_OTHER + + bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 +fi diff -u --recursive --new-file v2.3.9/linux/drivers/misc/Makefile linux/drivers/misc/Makefile --- v2.3.9/linux/drivers/misc/Makefile Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/Makefile Thu Jul 1 14:22:57 1999 @@ -23,7 +23,13 @@ MIX_OBJS := ifeq ($(CONFIG_PARPORT),y) - L_OBJS += parport_share.o parport_ieee1284.o parport_procfs.o + L_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o \ + parport_procfs.o + + ifeq ($(CONFIG_PARPORT_1284),y) + L_OBJS += parport_daisy.o parport_probe.o + endif + ifeq ($(CONFIG_PARPORT_PC),y) LX_OBJS += parport_pc.o else @@ -62,7 +68,10 @@ LX_OBJS += parport_init.o else ifeq ($(CONFIG_PARPORT),m) - MI_OBJS += parport_share.o parport_ieee1284.o + MI_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o + ifeq ($(CONFIG_PARPORT_1284),y) + MI_OBJS += parport_daisy.o parport_probe.o + endif ifneq ($(CONFIG_PROC_FS),n) MI_OBJS += parport_procfs.o endif diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c --- v2.3.9/linux/drivers/misc/parport_arc.c Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/parport_arc.c Thu Jul 1 14:22:57 1999 @@ -98,41 +98,36 @@ arc_read_control, arc_frob_control, - NULL, /* write_econtrol */ - NULL, /* read_econtrol */ - NULL, /* frob_econtrol */ - - arc_write_status, arc_read_status, - NULL, /* write_fifo */ - NULL, /* read_fifo */ - - NULL, /* change_mode */ - - NULL, /* epp_write_data */ - NULL, /* epp_read_data */ - NULL, /* epp_write_addr */ - NULL, /* epp_read_addr */ - NULL, /* epp_check_timeout */ + arc_enable_irq, + arc_disable_irq, - NULL, /* epp_write_block */ - NULL, /* epp_read_block */ + arc_data_forward, + arc_data_reverse, + + arc_interrupt, - NULL, /* ecp_write_block */ - NULL, /* epp_write_block */ - arc_init_state, arc_save_state, arc_restore_state, - arc_enable_irq, - arc_disable_irq, - arc_interrupt, - arc_inc_use_count, arc_dec_use_count, - arc_fill_inode + arc_fill_inode, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, }; /* --- Initialisation code -------------------------------- */ @@ -142,11 +137,11 @@ /* Archimedes hardware provides only one port, at a fixed address */ struct parport *p; - if (check_region(PORT_BASE, 4)) + if (check_region(PORT_BASE, 1)) return 0; - - p = parport_register_port(base, IRQ_PRINTERACK, - PARPORT_DMA_NONE, &parport_arc_ops); + + p = parport_register_port (PORT_BASE, IRQ_PRINTERACK, + PARPORT_DMA_NONE, &parport_arc_ops); if (!p) return 0; @@ -157,9 +152,6 @@ printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n", p->irq); parport_proc_register(p); - - if (parport_probe_hook) - (*parport_probe_hook)(p); /* Tell the high-level drivers about the port. */ parport_announce_port (p); diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_atari.c linux/drivers/misc/parport_atari.c --- v2.3.9/linux/drivers/misc/parport_atari.c Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/parport_atari.c Thu Jul 1 14:22:57 1999 @@ -221,9 +221,6 @@ printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name); parport_proc_register(p); - if (parport_probe_hook) - (*parport_probe_hook)(p); - parport_announce_port (p); return 1; diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.3.9/linux/drivers/misc/parport_ax.c Wed Jun 9 14:44:25 1999 +++ linux/drivers/misc/parport_ax.c Sun Jul 4 09:53:12 1999 @@ -1,4 +1,4 @@ -/* $Id: parport_ax.c,v 1.19 1999/06/09 08:24:40 davem Exp $ +/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $ * Parallel-port routines for Sun Ultra/AX architecture * * Author: Eddie C. Dost @@ -164,6 +164,7 @@ void parport_ax_change_mode(struct parport *p, int m) { + /* FIXME */ parport_ax_frob_econtrol(p, 0xe0, m << 5); } @@ -201,58 +202,40 @@ writel(dcsr, (unsigned long)&dma->dcsr); } -int -parport_ax_claim_resources(struct parport *p) -{ -} - void -parport_ax_init_state(struct parport_state *s) +parport_ax_init_state(struct pardevice *dev, struct parport_state *s) { - s->u.pc.ctr = 0xc; - s->u.pc.ecr = 0x0; + struct linux_ebus_dma *dma = dev->port->private_data; + + s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); + s->u.ax.ecr = 0x0; + + if (dev->irq_func) + s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr) + | EBUS_DCSR_INT_EN); + else + s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr) + & ~EBUS_DCSR_INT_EN); } void parport_ax_save_state(struct parport *p, struct parport_state *s) { - s->u.pc.ctr = parport_ax_read_control(p); - s->u.pc.ecr = parport_ax_read_econtrol(p); + struct linux_ebus_dma *dma = p->private_data; + + s->u.ax.ctr = parport_ax_read_control(p); + s->u.ax.ecr = parport_ax_read_econtrol(p); + s->u.ax.dcsr = readl((unsigned long)&dma->dcsr); } void parport_ax_restore_state(struct parport *p, struct parport_state *s) { - parport_ax_write_control(p, s->u.pc.ctr); - parport_ax_write_econtrol(p, s->u.pc.ecr); -} - -size_t -parport_ax_epp_read_block(struct parport *p, void *buf, size_t length) -{ - return 0; /* FIXME */ -} - -size_t -parport_ax_epp_write_block(struct parport *p, void *buf, size_t length) -{ - return 0; /* FIXME */ -} - -int -parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length, - void (*fn)(struct parport *, void *, size_t), - void *handle) -{ - return 0; /* FIXME */ -} + struct linux_ebus_dma *dma = p->private_data; -int -parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length, - void (*fn)(struct parport *, void *, size_t), - void *handle) -{ - return 0; /* FIXME */ + parport_ax_write_control(p, s->u.ax.ctr); + parport_ax_write_econtrol(p, s->u.ax.ecr); + writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr); } void @@ -290,41 +273,36 @@ parport_ax_read_control, parport_ax_frob_control, - parport_ax_write_econtrol, - parport_ax_read_econtrol, - parport_ax_frob_econtrol, - - parport_ax_write_status, parport_ax_read_status, - parport_ax_write_fifo, - parport_ax_read_fifo, - - parport_ax_change_mode, - - parport_ax_write_epp, - parport_ax_read_epp, - parport_ax_write_epp_addr, - parport_ax_read_epp_addr, - parport_ax_check_epp_timeout, + parport_ax_enable_irq, + parport_ax_disable_irq, - parport_ax_epp_write_block, - parport_ax_epp_read_block, + parport_ax_data_forward, + parport_ax_data_reverse, + + parport_ax_interrupt, - parport_ax_ecp_write_block, - parport_ax_ecp_read_block, - parport_ax_init_state, parport_ax_save_state, parport_ax_restore_state, - parport_ax_enable_irq, - parport_ax_disable_irq, - parport_ax_interrupt, - parport_ax_inc_use_count, parport_ax_dec_use_count, - parport_ax_fill_inode + parport_ax_fill_inode, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, }; @@ -539,20 +517,6 @@ if (p->dma == PARPORT_DMA_AUTO) p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE; - if (p->irq != PARPORT_IRQ_NONE) { - int err; - if ((err = request_irq(p->irq, parport_ax_interrupt, - 0, p->name, p)) != 0) - return err; - else - parport_ax_enable_irq(p); - } - request_region(p->base, p->size, p->name); - if (p->modes & PARPORT_MODE_PCECR) - request_region(p->base+0x400, 3, p->name); - request_region((unsigned long)p->private_data, - sizeof(struct linux_ebus_dma), p->name); - printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); if (p->irq != PARPORT_IRQ_NONE) printk(", irq %s", __irq_itoa(p->irq)); @@ -569,12 +533,21 @@ printk("]\n"); parport_proc_register(p); + if (p->irq != PARPORT_IRQ_NONE) + if ((err = request_irq(p->irq, parport_ax_interrupt, + 0, p->name, p)) != 0) + return 0; /* @@@ FIXME */ + + request_region(p->base, p->size, p->name); + if (p->modes & PARPORT_MODE_PCECR) + request_region(p->base+0x400, 3, p->name); + request_region((unsigned long)p->private_data, + sizeof(struct linux_ebus_dma), p->name); + p->ops->write_control(p, 0x0c); p->ops->write_data(p, 0); - if (parport_probe_hook) - (*parport_probe_hook)(p); - + /* Tell the high-level drivers about the port. */ parport_announce_port (p); return 1; diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_daisy.c linux/drivers/misc/parport_daisy.c --- v2.3.9/linux/drivers/misc/parport_daisy.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/misc/parport_daisy.c Sat Jul 3 10:45:04 1999 @@ -0,0 +1,473 @@ +/* + * IEEE 1284.3 Parallel port daisy chain and multiplexor code + * + * Copyright (C) 1999 Tim Waugh + * + * 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. + * + * ??-12-1998: Initial implementation. + * 31-01-1999: Make port-cloning transparent. + * 13-02-1999: Move DeviceID technique from parport_probe. + * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too. + * + */ + +#include +#include +#include + +#define DEBUG /* undef me for production */ + +#ifdef DEBUG +#define DPRINTK(stuff...) printk (stuff) +#else +#define DPRINTK(stuff...) +#endif + +static struct daisydev { + struct daisydev *next; + struct parport *port; + int daisy; + int devnum; +} *topology = NULL; + +static int numdevs = 0; + +/* Forward-declaration of lower-level functions. */ +static int mux_present (struct parport *port); +static int num_mux_ports (struct parport *port); +static int select_port (struct parport *port); +static int assign_addrs (struct parport *port); + +/* Add a device to the discovered topology. */ +static void add_dev (int devnum, struct parport *port, int daisy) +{ + struct daisydev *newdev; + newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev)); + if (newdev) { + newdev->port = port; + newdev->daisy = daisy; + newdev->devnum = devnum; + newdev->next = topology; + if (!topology || topology->devnum >= devnum) + topology = newdev; + else { + struct daisydev *prev = topology; + while (prev->next && prev->next->devnum < devnum) + prev = prev->next; + newdev->next = prev->next; + prev->next = newdev; + } + } +} + +/* Clone a parport (actually, make an alias). */ +static struct parport *clone_parport (struct parport *real, int muxport) +{ + struct parport *extra = parport_register_port (real->base, + real->irq, + real->dma, + real->ops); + if (extra) { + extra->portnum = real->portnum; + extra->physport = real; + extra->muxport = muxport; + } + + return extra; +} + +/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */ +int parport_daisy_init (struct parport *port) +{ + char *deviceid; + static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" }; + int num_ports; + int i; + + /* Because this is called before any other devices exist, + * we don't have to claim exclusive access. */ + + /* If mux present on normal port, need to create new + * parports for each extra port. */ + if (port->muxport < 0 && mux_present (port) && + /* don't be fooled: a mux must have 2 or 4 ports. */ + ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) { + /* Leave original as port zero. */ + port->muxport = 0; + printk (KERN_INFO + "%s: 1st (default) port of %d-way multiplexor\n", + port->name, num_ports); + for (i = 1; i < num_ports; i++) { + /* Clone the port. */ + struct parport *extra = clone_parport (port, i); + if (!extra) { + if (signal_pending (current)) + break; + + schedule (); + continue; + } + + printk (KERN_INFO + "%s: %d%s port of %d-way multiplexor on %s\n", + extra->name, i + 1, th[i + 1], num_ports, + port->name); + + /* Analyse that port too. We won't recurse + forever because of the 'port->muxport < 0' + test above. */ + parport_announce_port (extra); + } + } + + if (port->muxport >= 0) + select_port (port); + + parport_daisy_deselect_all (port); + assign_addrs (port); + + /* Count the potential legacy device at the end. */ + add_dev (numdevs++, port, -1); + + /* Find out the legacy device's IEEE 1284 device ID. */ + deviceid = kmalloc (1000, GFP_KERNEL); + if (deviceid) { + parport_device_id (numdevs - 1, deviceid, 1000); + kfree (deviceid); + } + + return 0; +} + +/* Forget about devices on a physical port. */ +void parport_daisy_fini (struct parport *port) +{ + struct daisydev *dev, *prev = topology; + while (prev && prev->port == port) + prev = topology = topology->next; + + while (prev) { + dev = prev->next; + if (dev && dev->port == port) + prev->next = dev->next; + + prev = prev->next; + } + + /* Gaps in the numbering could be handled better. How should + someone enumerate through all IEEE1284.3 devices in the + topology?. */ + if (!topology) numdevs = 0; + return; } + +/* Find a device by canonical device number. */ +struct pardevice *parport_open (int devnum, const char *name, + int (*pf) (void *), void (*kf) (void *), + void (*irqf) (int, void *, struct pt_regs *), + int flags, void *handle) +{ + struct parport *port = parport_enumerate (); + struct pardevice *dev; + int portnum; + int muxnum; + int daisynum; + + if (parport_device_coords (devnum, &portnum, &muxnum, &daisynum)) + return NULL; + + while (port && ((port->portnum != portnum) || + (port->muxport != muxnum))) + port = port->next; + + if (!port) + /* No corresponding parport. */ + return NULL; + + dev = parport_register_device (port, name, pf, kf, + irqf, flags, handle); + if (dev) + dev->daisy = daisynum; + + /* Check that there really is a device to select. */ + if (daisynum >= 0) { + int selected; + parport_claim_or_block (dev); + selected = port->daisy; + parport_release (dev); + + if (selected != port->daisy) { + /* No corresponding device. */ + parport_unregister_device (dev); + return NULL; + } + } + + return dev; +} + +/* The converse of parport_open. */ +void parport_close (struct pardevice *dev) +{ + parport_unregister_device (dev); +} + +/* Convert device coordinates into a canonical device number. */ +int parport_device_num (int parport, int mux, int daisy) +{ + struct daisydev *dev = topology; + + while (dev && dev->port->portnum != parport && + dev->port->muxport != mux && dev->daisy != daisy) + dev = dev->next; + + if (!dev) + return -ENXIO; + + return dev->devnum; +} + +/* Convert a canonical device number into device coordinates. */ +int parport_device_coords (int devnum, int *parport, int *mux, int *daisy) +{ + struct daisydev *dev = topology; + + while (dev && dev->devnum != devnum) + dev = dev->next; + + if (!dev) + return -ENXIO; + + if (parport) *parport = dev->port->portnum; + if (mux) *mux = dev->port->muxport; + if (daisy) *daisy = dev->daisy; + return 0; +} + +/* Send a daisy-chain-style CPP command packet. */ +static int cpp_daisy (struct parport *port, int cmd) +{ + unsigned char s; + + parport_write_data (port, 0xaa); udelay (2); + parport_write_data (port, 0x55); udelay (2); + parport_write_data (port, 0x00); udelay (2); + parport_write_data (port, 0xff); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x87); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x78); udelay (2); + parport_write_data (port, cmd); udelay (2); + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + udelay (1); + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + udelay (1); + s = parport_read_status (port); + parport_write_data (port, 0xff); udelay (2); + + return s; +} + +/* Send a mux-style CPP command packet. */ +static int cpp_mux (struct parport *port, int cmd) +{ + unsigned char s; + int rc; + + parport_write_data (port, 0xaa); udelay (2); + parport_write_data (port, 0x55); udelay (2); + parport_write_data (port, 0xf0); udelay (2); + parport_write_data (port, 0x0f); udelay (2); + parport_write_data (port, 0x52); udelay (2); + parport_write_data (port, 0xad); udelay (2); + parport_write_data (port, cmd); udelay (2); + + s = parport_read_status (port); + if (!(s & PARPORT_STATUS_ACK)) { + DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n", + port->name, cmd, s); + return -EIO; + } + + rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) | + ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) | + ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) | + ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3)); + + return rc; +} + +void parport_daisy_deselect_all (struct parport *port) +{ + cpp_daisy (port, 0x30); +} + +int parport_daisy_select (struct parport *port, int daisy, int mode) +{ + /* mode is currently ignored. FIXME? */ + return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR; +} + +static int mux_present (struct parport *port) +{ + return cpp_mux (port, 0x51) == 3; +} + +static int num_mux_ports (struct parport *port) +{ + return cpp_mux (port, 0x58); +} + +static int select_port (struct parport *port) +{ + int muxport = port->muxport; + return cpp_mux (port, 0x60 + muxport) == muxport; +} + +static int assign_addrs (struct parport *port) +{ + unsigned char s, last_dev; + unsigned char daisy; + int thisdev = numdevs; + char *deviceid; + + parport_write_data (port, 0xaa); udelay (2); + parport_write_data (port, 0x55); udelay (2); + parport_write_data (port, 0x00); udelay (2); + parport_write_data (port, 0xff); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x87); udelay (2); + s = parport_read_status (port) & (PARPORT_STATUS_BUSY + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_ERROR); + if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { + DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n", + port->name, s); + return -ENXIO; + } + + parport_write_data (port, 0x78); udelay (2); + last_dev = 0; /* We've just been speaking to a device, so we + know there must be at least _one_ out there. */ + + for (daisy = 0; daisy < 4; daisy++) { + parport_write_data (port, daisy); + udelay (2); + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + udelay (1); + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + udelay (1); + + if (last_dev) + /* No more devices. */ + break; + + last_dev = !(parport_read_status (port) + & PARPORT_STATUS_BUSY); + + add_dev (numdevs++, port, daisy); + } + + parport_write_data (port, 0xff); udelay (2); + DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name, + numdevs - thisdev); + + /* Ask the new devices to introduce themselves. */ + deviceid = kmalloc (1000, GFP_KERNEL); + if (!deviceid) return 0; + + for (daisy = 0; thisdev < numdevs; thisdev++, daisy++) + parport_device_id (thisdev, deviceid, 1000); + + kfree (deviceid); + return 0; +} + +/* Find a device with a particular manufacturer and model string, + starting from a given device number. Like the PCI equivalent, + 'from' itself is skipped. */ +int parport_find_device (const char *mfg, const char *mdl, int from) +{ + struct daisydev *d = topology; /* sorted by devnum */ + + /* Find where to start. */ + while (d && d->devnum <= from) + d = d->next; + + /* Search. */ + while (d) { + struct parport_device_info *info; + info = &d->port->probe_info[1 + d->daisy]; + if ((!mfg || !strcmp (mfg, info->mfr)) && + (!mdl || !strcmp (mdl, info->model))) + break; + + d = d->next; + } + + if (d) + return d->devnum; + + return -1; +} + +/* Find a device in a particular class. Like the PCI equivalent, + 'from' itself is skipped. */ +int parport_find_class (parport_device_class cls, int from) +{ + struct daisydev *d = topology; /* sorted by devnum */ + + /* Find where to start. */ + while (d && d->devnum <= from) + d = d->next; + + /* Search. */ + while (d && d->port->probe_info[1 + d->daisy].class != cls) + d = d->next; + + if (d) + return d->devnum; + + return -1; +} diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c --- v2.3.9/linux/drivers/misc/parport_ieee1284.c Mon May 10 10:26:31 1999 +++ linux/drivers/misc/parport_ieee1284.c Wed Jul 7 12:55:47 1999 @@ -4,12 +4,73 @@ * Authors: Phil Blundell * Carsten Gross * Jose Renau + * Tim Waugh (largely rewritten) + * + * This file is responsible for IEEE 1284 negotiation, and for handing + * read/write requests to low-level drivers. */ +#include #include #include #include #include +#include + +#undef DEBUG /* undef me for production */ + +#ifdef CONFIG_LP_CONSOLE +#undef DEBUG /* Don't want a garbled console */ +#endif + +#ifdef DEBUG +#define DPRINTK(stuff...) printk (stuff) +#else +#define DPRINTK(stuff...) +#endif + +/* Make parport_wait_peripheral wake up. + * It will be useful to call this from an interrupt handler. */ +void parport_ieee1284_wakeup (struct parport *port) +{ + up (&port->physport->ieee1284.irq); +} + +static struct parport *port_from_cookie[PARPORT_MAX]; +static void timeout_waiting_on_port (unsigned long cookie) +{ + parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]); +} + +/* Wait for a parport_ieee1284_wakeup. + * 0: success + * <0: error (exit as soon as possible) + * >0: timed out + */ +int parport_wait_event (struct parport *port, signed long timeout) +{ + int ret; + struct timer_list timer; + + if (!port->physport->cad->timeout) + /* Zero timeout is special, and we can't down() the + semaphore. */ + return 1; + + init_timer (&timer); + timer.expires = jiffies + timeout; + timer.function = timeout_waiting_on_port; + port_from_cookie[port->number % PARPORT_MAX] = port; + timer.data = port->number; + + add_timer (&timer); + ret = down_interruptible (&port->physport->ieee1284.irq); + if (!del_timer (&timer) && !ret) + /* Timed out. */ + ret = 1; + + return ret; +} /* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to * 25 for this. After this time we can create a timeout because the @@ -19,53 +80,446 @@ * are able to eat the time up to 40ms. */ -int parport_wait_peripheral(struct parport *port, unsigned char mask, - unsigned char result) +int parport_wait_peripheral(struct parport *port, + unsigned char mask, + unsigned char result) { int counter; - unsigned char status; - - for (counter = 0; counter < 20; counter++) { - status = parport_read_status(port); + long deadline; + unsigned char status; + + counter = port->physport->spintime; /* usecs of fast polling */ + if (!port->physport->cad->timeout) + /* A zero timeout is "special": busy wait for the + entire 35ms. */ + counter = 35000; + + /* Fast polling. + * + * This should be adjustable. + * How about making a note (in the device structure) of how long + * it takes, so we know for next time? + */ + for (counter /= 5; counter > 0; counter--) { + status = parport_read_status (port); if ((status & mask) == result) return 0; - udelay(25); + if (signal_pending (current)) + return -EINTR; if (current->need_resched) - schedule(); + break; + udelay(5); } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); /* wait for 40ms */ - status = parport_read_status(port); - return ((status & mask) == result)?0:1; + + if (!port->physport->cad->timeout) + /* We may be in an interrupt handler, so we can't poll + * slowly anyway. */ + return 1; + + /* 40ms of slow polling. */ + deadline = jiffies + (HZ + 24) / 25; + while (time_before (jiffies, deadline)) { + int ret; + + if (signal_pending (current)) + return -EINTR; + + /* Wait for 10ms (or until an interrupt occurs if + * the handler is set) */ + if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0) + return ret; + + status = parport_read_status (port); + if ((status & mask) == result) + return 0; + + if (!ret) { + /* parport_wait_event didn't time out, but the + * peripheral wasn't actually ready either. + * Wait for another 10ms. */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout ((HZ+ 99) / 100); + } + } + + return 1; +} + +#ifdef CONFIG_PARPORT_1284 +/* Terminate a negotiated mode. */ +static void parport_ieee1284_terminate (struct parport *port) +{ + port = port->physport; + + port->ieee1284.phase = IEEE1284_PH_TERMINATE; + + /* EPP terminates differently. */ + switch (port->ieee1284.mode) { + case IEEE1284_MODE_EPP: + case IEEE1284_MODE_EPPSL: + case IEEE1284_MODE_EPPSWE: + /* Terminate from EPP mode. */ + + /* Event 68: Set nInit low */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + udelay (50); + + /* Event 69: Set nInit high, nSelectIn low */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); + break; + + default: + /* Terminate from all other modes. */ + + /* Event 22: Set nSelectIn low, nAutoFd high */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_SELECT); + + /* Event 24: nAck goes low */ + parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); + + /* Event 25: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 27: nAck goes high */ + parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK); + + /* Event 29: Set nAutoFd high */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + } + + port->ieee1284.mode = IEEE1284_MODE_COMPAT; + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n", + port->name); } +#endif /* IEEE1284 support */ -/* Test if the peripheral is IEEE 1284 compliant. +/* Negotiate an IEEE 1284 mode. * return values are: - * 0 - handshake failed; peripheral is not compliant (or none present) - * 1 - handshake OK; IEEE1284 peripheral present but no data available - * 2 - handshake OK; IEEE1284 peripheral and data available + * 0 - handshake OK; IEEE1284 peripheral and mode available + * -1 - handshake failed; peripheral is not compliant (or none present) + * 1 - handshake OK; IEEE1284 peripheral present but mode not available */ -int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) +int parport_negotiate (struct parport *port, int mode) { - /* make sure it's a valid state, set nStrobe & nAutoFeed high */ - parport_frob_control (port, (1|2), 0); - udelay(1); - parport_write_data(port, mode); - udelay(400); - /* nSelectIn high, nAutoFd low */ - parport_frob_control(port, (2|8), 2); - if (parport_wait_peripheral(port, 0x78, 0x38)) { - parport_frob_control(port, (2|8), 8); +#ifndef CONFIG_PARPORT_1284 + if (mode == IEEE1284_MODE_COMPAT) + return 0; + printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n"); + return -1; +#else + int m = mode; + unsigned char xflag; + + port = port->physport; + + /* Is there anything to do? */ + if (port->ieee1284.mode == mode) + return 0; + + /* Go to compability forward idle mode */ + if (port->ieee1284.mode != IEEE1284_MODE_COMPAT) + parport_ieee1284_terminate (port); + + if (mode == IEEE1284_MODE_COMPAT) + /* Compatibility mode: no negotiation. */ return 0; + + switch (mode) { + case IEEE1284_MODE_ECPSWE: + m = IEEE1284_MODE_ECP; + break; + case IEEE1284_MODE_EPPSL: + case IEEE1284_MODE_EPPSWE: + m = IEEE1284_MODE_EPP; + break; + case IEEE1284_MODE_BECP: + return -ENOSYS; /* FIXME (implement BECP) */ } - /* nStrobe low */ - parport_frob_control (port, 1, 1); - udelay(1); /* Strobe wait */ - /* nStrobe high, nAutoFeed low, last step before transferring - * reverse data */ - parport_frob_control (port, (1|2), 0); + + port->ieee1284.phase = IEEE1284_PH_NEGOTIATION; + + /* Start off with nStrobe and nAutoFd high, and nSelectIn low */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE + | PARPORT_CONTROL_AUTOFD + | PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); udelay(1); - /* Data available? */ - parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); - return (parport_read_status(port) & PARPORT_STATUS_ERROR)?1:2; + + /* Event 0: Set data */ + parport_write_data (port, m); + udelay (400); /* Shouldn't need to wait this long. */ + + /* Event 1: Set nSelectIn high, nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 2: PError, Select, nFault go high, nAck goes low */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ERROR + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_PAPEROUT + | PARPORT_STATUS_ACK, + PARPORT_STATUS_ERROR + | PARPORT_STATUS_SELECT + | PARPORT_STATUS_PAPEROUT)) { + /* Timeout */ + parport_frob_control (port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_SELECT); + DPRINTK (KERN_DEBUG + "%s: Peripheral not IEEE1284 compliant (0x%02X)\n", + port->name, parport_read_status (port)); + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + return -1; /* Not IEEE1284 compliant */ + } + + /* Event 3: Set nStrobe low */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Event 4: Set nStrobe and nAutoFd high */ + udelay (5); + parport_frob_control (port, + PARPORT_CONTROL_STROBE + | PARPORT_CONTROL_AUTOFD, + 0); + + /* Event 6: nAck goes high */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK + | PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_ACK)) { + if (parport_read_status (port) & PARPORT_STATUS_ACK) + printk (KERN_DEBUG + "%s: working around buggy peripheral: tell " + "Tim what make it is\n", port->name); + DPRINTK (KERN_DEBUG + "%s: Mode 0x%02x not supported? (0x%02x)\n", + port->name, mode, port->ops->read_status (port)); + parport_ieee1284_terminate (port); + return 1; + } + + xflag = parport_read_status (port) & PARPORT_STATUS_SELECT; + + /* xflag should be high for all modes other than nibble (0). */ + if (mode && !xflag) { + /* Mode not supported. */ + DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n", + port->name, mode); + parport_ieee1284_terminate (port); + return 1; + } + + /* Mode is supported */ + DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode); + port->ieee1284.mode = mode; + + /* But ECP is special */ + if (mode & IEEE1284_MODE_ECP) { + port->ieee1284.phase = IEEE1284_PH_ECP_SETUP; + + /* Event 30: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 31: PError goes high. */ + parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + /* (Should check that this works..) */ + + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", + port->name); + } else switch (mode) { + case IEEE1284_MODE_NIBBLE: + case IEEE1284_MODE_BYTE: + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; + break; + default: + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + } + + + return 0; +#endif /* IEEE1284 support */ +} + +/* Acknowledge that the peripheral has data available. + * Events 18-20, in order to get from Reverse Idle phase + * to Host Busy Data Available. + * This will most likely be called from an interrupt. + * Returns zero if data was available. + */ +#ifdef CONFIG_PARPORT_1284 +static int parport_ieee1284_ack_data_avail (struct parport *port) +{ + if (parport_read_status (port) & PARPORT_STATUS_ERROR) + /* Event 18 didn't happen. */ + return -1; + + /* Event 20: nAutoFd goes high. */ + port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; + return 0; +} +#endif /* IEEE1284 support */ + +/* Handle an interrupt. */ +void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs) +{ + struct parport *port = handle; + parport_ieee1284_wakeup (port); + +#ifdef CONFIG_PARPORT_1284 + if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) { + /* An interrupt in this phase means that data + * is now available. */ + DPRINTK (KERN_DEBUG "%s: Data available\n", port->name); + parport_ieee1284_ack_data_avail (port); + } +#endif /* IEEE1284 support */ +} + +/* Write a block of data. */ +ssize_t parport_write (struct parport *port, const void *buffer, size_t len) +{ +#ifndef CONFIG_PARPORT_1284 + return port->ops->compat_write_data (port, buffer, len, 0); +#else + ssize_t retval; + int mode = port->ieee1284.mode; + size_t (*fn) (struct parport *, const void *, size_t, int); + + /* Ignore the device-ID-request bit. */ + mode &= ~IEEE1284_DEVICEID; + + /* Use the mode we're in. */ + switch (mode) { + case IEEE1284_MODE_NIBBLE: + parport_negotiate (port, IEEE1284_MODE_COMPAT); + case IEEE1284_MODE_COMPAT: + DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n", + port->name); + fn = port->ops->compat_write_data; + break; + + case IEEE1284_MODE_EPP: + DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); + fn = port->ops->epp_write_data; + break; + + case IEEE1284_MODE_ECP: + case IEEE1284_MODE_ECPRLE: + DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); + fn = port->ops->ecp_write_data; + break; + + case IEEE1284_MODE_ECPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n", + port->name); + /* The caller has specified that it must be emulated, + * even if we have ECP hardware! */ + fn = parport_ieee1284_ecp_write_data; + break; + + default: + DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name, + port->ieee1284.mode); + return -ENOSYS; + } + + retval = (*fn) (port, buffer, len, 0); + DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval, + len); + return retval; +#endif /* IEEE1284 support */ +} + +/* Read a block of data. */ +ssize_t parport_read (struct parport *port, void *buffer, size_t len) +{ +#ifndef CONFIG_PARPORT_1284 + printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n"); + return -ENODEV; +#else + int mode = port->physport->ieee1284.mode; + size_t (*fn) (struct parport *, void *, size_t, int); + + /* Ignore the device-ID-request bit. */ + mode &= ~IEEE1284_DEVICEID; + + /* Use the mode we're in. */ + switch (mode) { + case IEEE1284_MODE_COMPAT: + if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) + return -EIO; + case IEEE1284_MODE_NIBBLE: + DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name); + fn = port->ops->nibble_read_data; + break; + + case IEEE1284_MODE_BYTE: + DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name); + fn = port->ops->byte_read_data; + break; + + case IEEE1284_MODE_EPP: + DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); + fn = port->ops->epp_read_data; + break; + + case IEEE1284_MODE_ECP: + case IEEE1284_MODE_ECPRLE: + DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); + fn = port->ops->ecp_read_data; + break; + + case IEEE1284_MODE_ECPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n", + port->name); + fn = parport_ieee1284_ecp_read_data; + break; + + default: + DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name, + port->physport->ieee1284.mode); + return -ENOSYS; + } + + return (*fn) (port, buffer, len, 0); +#endif /* IEEE1284 support */ +} + +/* Set the amount of time we wait while nothing's happening. */ +long parport_set_timeout (struct pardevice *dev, long inactivity) +{ + long int old = dev->timeout; + + dev->timeout = inactivity; + + if (dev->port->physport->cad == dev) + parport_ieee1284_wakeup (dev->port); + + return old; } diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_ieee1284_ops.c linux/drivers/misc/parport_ieee1284_ops.c --- v2.3.9/linux/drivers/misc/parport_ieee1284_ops.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/misc/parport_ieee1284_ops.c Tue Jul 6 19:08:33 1999 @@ -0,0 +1,848 @@ +/* IEEE-1284 operations for parport. + * + * This file is for generic IEEE 1284 operations. The idea is that + * they are used by the low-level drivers. If they have a special way + * of doing something, they can provide their own routines (and put + * the function pointers in port->ops); if not, they can just use these + * as a fallback. + * + * Note: Make no assumptions about hardware or architecture in this file! + * + * Author: Tim Waugh + */ + +#include +#include +#include +#include + +#define DEBUG /* undef me for production */ + +#ifdef CONFIG_LP_CONSOLE +#undef DEBUG /* Don't want a garbled console */ +#endif + +#ifdef DEBUG +#define DPRINTK(stuff...) printk (stuff) +#else +#define DPRINTK(stuff...) +#endif + +/*** * + * One-way data transfer functions. * + * ***/ + +static inline +int polling (struct pardevice *dev) +{ + return dev->port->irq == PARPORT_IRQ_NONE; +} + +/* Compatibility mode. */ +size_t parport_ieee1284_write_compat (struct parport *port, + const void *buffer, size_t len, + int flags) +{ + ssize_t count = 0; + const unsigned char *addr = buffer; + unsigned char byte; + struct pardevice *dev = port->physport->cad; + unsigned char ctl = (PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); + + if (port->irq != PARPORT_IRQ_NONE) + parport_enable_irq (port); + + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + while (count < len) { + long expire = jiffies + dev->timeout; + long wait = (HZ + 99) / 100; + unsigned char mask = (PARPORT_STATUS_ERROR + | PARPORT_STATUS_BUSY); + unsigned char val = (PARPORT_STATUS_ERROR + | PARPORT_STATUS_BUSY); + int i; + + /* Write the character to the data lines. */ + byte = *addr++; + parport_write_data (port, byte); + udelay (1); + + /* Wait until the peripheral's ready */ + do { + /* Is the peripheral ready yet? */ + if (!parport_wait_peripheral (port, mask, val)) + /* Skip the loop */ + goto ready; + + /* Is the peripheral upset? */ + if ((parport_read_status (port) & + (PARPORT_STATUS_PAPEROUT | + PARPORT_STATUS_SELECT | + PARPORT_STATUS_ERROR)) + != (PARPORT_STATUS_SELECT | + PARPORT_STATUS_ERROR)) + /* If nFault is asserted (i.e. no + * error) and PAPEROUT and SELECT are + * just red herrings, give the driver + * a chance to check it's happy with + * that before continuing. */ + goto stop; + + /* Have we run out of time? */ + if (!time_before (jiffies, expire)) + break; + + /* Yield the port for a while. If this is the + first time around the loop, don't let go of + the port. This way, we find out if we have + our interrupt handler called. */ + if (count && polling (dev)) { + parport_release (dev); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout (wait); + parport_claim_or_block (dev); + } + else + /* We must have the device claimed here */ + parport_wait_event (port, wait); + + /* Is there a signal pending? */ + if (signal_pending (current)) + goto stop; + + /* Wait longer next time. */ + wait *= 2; + } while (time_before (jiffies, expire)); + + DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name); + break; + + ready: + /* Clear out previous irqs. */ + while (!down_trylock (&port->physport->ieee1284.irq)); + + /* Pulse strobe. */ + parport_write_control (port, ctl | PARPORT_CONTROL_STROBE); + udelay (1); /* strobe */ + + parport_write_control (port, ctl); + udelay (1); /* hold */ + + /* Wait until it's received (up to 20us). */ + for (i = 0; i < 20; i++) { + if (!down_trylock (&port->physport->ieee1284.irq) || + !(parport_read_status (port) & PARPORT_STATUS_ACK)) + break; + udelay (1); + } + + count++; + + /* Let another process run if it needs to. */ + if (time_before (jiffies, expire)) + if (!parport_yield_blocking (dev) + && current->need_resched) + schedule (); + } + stop: + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return count; +} + +/* Nibble mode. */ +size_t parport_ieee1284_read_nibble (struct parport *port, + void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + unsigned char *buf = buffer; + int i; + unsigned char byte = 0; + + len *= 2; /* in nibbles */ + for (i=0; i < len; i++) { + unsigned char nibble; + + /* Does the error line indicate end of data? */ + if (((i & 1) == 0) && + (parport_read_status(port) & PARPORT_STATUS_ERROR)) { + port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + DPRINTK (KERN_DEBUG + "%s: No more nibble data (%d bytes)\n", + port->name, i/2); + + /* Go to reverse idle phase. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE; + break; + } + + /* Event 7: Set nAutoFd low. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 9: nAck goes low. */ + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, 0)) { + /* Timeout -- no more data? */ + DPRINTK (KERN_DEBUG + "%s: Nibble timeout at event 9 (%d bytes)\n", + port->name, i/2); + break; + } + + + /* Read a nibble. */ + nibble = parport_read_status (port) >> 3; + nibble &= ~8; + if ((nibble & 0x10) == 0) + nibble |= 8; + nibble &= 0xf; + + /* Event 10: Set nAutoFd high. */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 11: nAck goes high. */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK)) { + /* Timeout -- no more data? */ + DPRINTK (KERN_DEBUG + "%s: Nibble timeout at event 11\n", + port->name); + break; + } + + if (i & 1) { + /* Second nibble */ + byte |= nibble << 4; + *buf++ = byte; + } else + byte = nibble; + } + + i /= 2; /* i is now in bytes */ + + if (i == len) { + /* Read the last nibble without checking data avail. */ + port = port->physport; + if (parport_read_status (port) & PARPORT_STATUS_ERROR) + port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + else + port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; + } + + return i; +#endif /* IEEE1284 support */ +} + +/* Byte mode. */ +size_t parport_ieee1284_read_byte (struct parport *port, + void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + unsigned char *buf = buffer; + ssize_t count = 0; + + for (count = 0; count < len; count++) { + unsigned char byte; + + /* Data available? */ + if (parport_read_status (port) & PARPORT_STATUS_ERROR) { + port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + DPRINTK (KERN_DEBUG + "%s: No more byte data (%d bytes)\n", + port->name, count); + + /* Go to reverse idle phase. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE; + break; + } + + /* Event 7: Set nAutoFd low. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* Event 9: nAck goes low. */ + port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA; + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + 0)) { + /* Timeout -- no more data? */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + 0); + DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n", + port->name); + break; + } + + byte = parport_read_data (port); + *buf++ = byte; + + /* Event 10: Set nAutoFd high */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 11: nAck goes high. */ + if (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK)) { + /* Timeout -- no more data? */ + DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n", + port->name); + break; + } + + /* Event 16: Set nStrobe low. */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + udelay (5); + + /* Event 17: Set nStrobe high. */ + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + } + + if (count == len) { + /* Read the last byte without checking data avail. */ + port = port->physport; + if (parport_read_status (port) & PARPORT_STATUS_ERROR) + port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; + else + port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; + } + + return count; +#endif /* IEEE1284 support */ +} + +/*** * + * ECP Functions. * + * ***/ + +#ifdef CONFIG_PARPORT_1284 + +static inline +int ecp_forward_to_reverse (struct parport *port) +{ + int retval; + + /* Event 38: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + parport_data_reverse (port); + udelay (5); + + /* Event 39: Set nInit low to initiate bus reversal */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + + /* Event 40: PError goes low */ + retval = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, 0); + + if (!retval) { + DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n", + port->name); + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; + } + + return retval; +} + +static inline +int ecp_reverse_to_forward (struct parport *port) +{ + int retval; + + /* Event 47: Set nInit high */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + parport_data_reverse (port); + + /* Event 49: PError goes high */ + retval = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + + if (!retval) { + parport_data_forward (port); + DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", + port->name); + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + } + + return retval; +} + +#endif /* IEEE1284 support */ + +/* ECP mode, forward channel, data. */ +size_t parport_ieee1284_ecp_write_data (struct parport *port, + const void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + const unsigned char *buf = buffer; + size_t written; + int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD; + int retry; + + port = port->physport; + + if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) + if (ecp_reverse_to_forward (port)) + return 0; + + port->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* HostAck high (data, not command) */ + parport_write_control (port, ctl); + for (written = 0; written < len; written++, buf++) { + long expire = jiffies + port->cad->timeout; + unsigned char byte; + + byte = *buf; + try_again: + parport_write_data (port, byte); + parport_write_control (port, ctl | PARPORT_CONTROL_STROBE); + udelay (5); + for (retry = 0; retry < 100; retry++) { + if (!parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, 0)) + goto success; + + if (signal_pending (current)) { + parport_write_control (port, ctl); + break; + } + } + + /* Time for Host Transfer Recovery (page 41 of IEEE1284) */ + DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name); + + parport_write_control (port, ctl | PARPORT_CONTROL_INIT); + udelay (50); + if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) { + /* It's buggered. */ + parport_write_control (port, ctl); + break; + } + + parport_write_control (port, ctl); + udelay (50); + if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT)) + break; + + DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n", + port->name); + + if (time_after_eq (jiffies, expire)) break; + goto try_again; + success: + parport_write_control (port, ctl); + udelay (5); + if (parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + /* Peripheral hasn't accepted the data. */ + break; + } + + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +#endif /* IEEE1284 support */ +} + +/* ECP mode, reverse channel, data. */ +size_t parport_ieee1284_ecp_read_data (struct parport *port, + void *buffer, size_t len, int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + struct pardevice *dev = port->cad; + unsigned char *buf = buffer; + int rle_count = 0; /* shut gcc up */ + int rle = 0; + ssize_t count = 0; + + port = port->physport; + + if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) + if (ecp_forward_to_reverse (port)) + return 0; + + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + + /* Set HostAck low to start accepting data. */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + while (count < len) { + long expire = jiffies + dev->timeout; + unsigned char byte; + int command; + + /* Event 43: Peripheral sets nAck low. It can take as + long as it wants. */ + while (parport_wait_peripheral (port, + PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK)) { + /* The peripheral hasn't given us data in + 35ms. If we have data to give back to the + caller, do it now. */ + if (count) + goto out; + + /* If we've used up all the time we were allowed, + give up altogether. */ + if (!time_before (jiffies, expire)) + goto out; + + /* Yield the port for a while. */ + if (count && polling (dev)) { + parport_release (dev); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout ((HZ + 99) / 25); + parport_claim_or_block (dev); + } + else + /* We must have the device claimed here. */ + parport_wait_event (port, (HZ + 99) / 25); + + /* Is there a signal pending? */ + if (signal_pending (current)) + goto out; + } + + /* Is this a command? */ + if (rle) + /* The last byte was a run-length count, so + this can't be as well. */ + command = 0; + else + command = (parport_read_status (port) & + PARPORT_STATUS_BUSY) ? 1 : 0; + + /* Read the data. */ + byte = parport_read_data (port); + + /* If this is a channel command, rather than an RLE + command or a normal data byte, don't accept it. */ + if (command) { + if (byte & 0x80) { + DPRINTK (KERN_DEBUG "%s: stopping short at " + "channel command (%02x)\n", + port->name, byte); + goto out; + } + else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE) + DPRINTK (KERN_DEBUG "%s: device illegally " + "using RLE; accepting anyway\n", + port->name); + + rle_count = byte + 1; + + /* Are we allowed to read that many bytes? */ + if (rle_count > (len - count)) { + DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes " + "for next time\n", port->name, + rle_count); + break; + } + + rle = 1; + } + + /* Event 44: Set HostAck high, acknowledging handshake. */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 45: The peripheral has 35ms to set nAck high. */ + if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { + /* It's gone wrong. Return what data we have + to the caller. */ + DPRINTK (KERN_DEBUG "ECP read timed out at 45\n"); + + if (command) + printk (KERN_WARNING + "%s: command ignored (%02x)\n", + port->name, byte); + + break; + } + + /* Event 46: Set HostAck low and accept the data. */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + /* If we just read a run-length count, fetch the data. */ + if (command) + continue; + + /* If this is the byte after a run-length count, decompress. */ + if (rle) { + rle = 0; + memset (buf, byte, rle_count); + buf += rle_count; + count += rle_count; + DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n", + port->name, rle_count); + } + else + /* Normal data byte. */ + *buf++ = byte, count++; + } + + out: + return count; +#endif /* IEEE1284 support */ +} + +/* ECP mode, forward channel, commands. */ +size_t parport_ieee1284_ecp_write_addr (struct parport *port, + const void *buffer, size_t len, + int flags) +{ +#ifndef CONFIG_PARPORT_1284 + return 0; +#else + const unsigned char *buf = buffer; + size_t written; + int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD; + int retry; + + port = port->physport; + + if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) + if (ecp_reverse_to_forward (port)) + return 0; + + port->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* HostAck low (command, not data) */ + parport_write_control (port, ctl); + for (written = 0; written < len; written++, buf++) { + long expire = jiffies + port->cad->timeout; + unsigned char byte; + + byte = *buf; + try_again: + parport_write_data (port, byte); + parport_write_control (port, ctl | PARPORT_CONTROL_STROBE); + udelay (5); + for (retry = 0; retry < 100; retry++) { + if (!parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, 0)) + goto success; + + if (signal_pending (current)) { + parport_write_control (port, ctl); + break; + } + } + + /* Time for Host Transfer Recovery (page 41 of IEEE1284) */ + DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name); + + parport_write_control (port, ctl | PARPORT_CONTROL_INIT); + udelay (50); + if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) { + /* It's buggered. */ + parport_write_control (port, ctl); + break; + } + + parport_write_control (port, ctl); + udelay (50); + if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT)) + break; + + DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n", + port->name); + + if (time_after_eq (jiffies, expire)) break; + goto try_again; + success: + parport_write_control (port, ctl); + udelay (5); + if (parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + /* Peripheral hasn't accepted the data. */ + break; + } + + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +#endif /* IEEE1284 support */ +} + +/*** * + * EPP functions. * + * ***/ + +/* EPP mode, forward channel, data. */ +size_t parport_ieee1284_epp_write_data (struct parport *port, + const void *buffer, size_t len, + int flags) +{ + /* This is untested */ + unsigned char *bp = (unsigned char *) buffer; + size_t ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT); + port->ops->data_forward (port); + for (; len > 0; len--, bp++) { + parport_write_data (port, *bp); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + /* Strobe data */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + ret++; + } + + return ret; +} + +/* EPP mode, reverse channel, data. */ +size_t parport_ieee1284_epp_read_data (struct parport *port, + void *buffer, size_t len, + int flags) +{ + /* This is untested. */ + unsigned char *bp = (unsigned char *) buffer; + unsigned ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT, 0); + port->ops->data_reverse (port); + for (; len > 0; len--, bp++) { + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + *bp = parport_read_data (port); + + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + ret++; + } + port->ops->data_forward (port); + + return ret; +} + +/* EPP mode, forward channel, addresses. */ +size_t parport_ieee1284_epp_write_addr (struct parport *port, + const void *buffer, size_t len, + int flags) +{ + /* This is untested */ + unsigned char *bp = (unsigned char *) buffer; + size_t ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT); + port->ops->data_forward (port); + for (; len > 0; len--, bp++) { + parport_write_data (port, *bp); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + /* Strobe data */ + parport_frob_control (port, PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + ret++; + } + + return ret; +} + +/* EPP mode, reverse channel, addresses. */ +size_t parport_ieee1284_epp_read_addr (struct parport *port, + void *buffer, size_t len, + int flags) +{ + /* This is untested. */ + unsigned char *bp = (unsigned char *) buffer; + unsigned ret = 0; + + parport_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_AUTOFD, 0); + port->ops->data_reverse (port); + for (; len > 0; len--, bp++) { + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY)) + break; + + parport_frob_control (port, PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); + + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + break; + + *bp = parport_read_data (port); + + parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + ret++; + } + port->ops->data_forward (port); + + return ret; +} diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c --- v2.3.9/linux/drivers/misc/parport_init.c Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/parport_init.c Sun Jul 4 10:14:13 1999 @@ -22,7 +22,7 @@ static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY }; -static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_AUTO }; +static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE }; extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma); extern int parport_ax_init(void); @@ -119,10 +119,7 @@ if (io[0] == PARPORT_DISABLE) return 1; -#ifdef CONFIG_PNP_PARPORT - parport_probe_hook = &parport_probe_one; -#endif -#ifdef CONFIG_SYSCTL +#ifdef CONFIG_SYSCTL parport_default_proc_register (); #endif @@ -161,13 +158,42 @@ EXPORT_SYMBOL(parport_register_device); EXPORT_SYMBOL(parport_unregister_device); EXPORT_SYMBOL(parport_enumerate); -EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok); +EXPORT_SYMBOL(parport_negotiate); +EXPORT_SYMBOL(parport_write); +EXPORT_SYMBOL(parport_read); +EXPORT_SYMBOL(parport_ieee1284_wakeup); EXPORT_SYMBOL(parport_wait_peripheral); +EXPORT_SYMBOL(parport_wait_event); +EXPORT_SYMBOL(parport_set_timeout); +EXPORT_SYMBOL(parport_ieee1284_interrupt); +EXPORT_SYMBOL(parport_ieee1284_ecp_write_data); +EXPORT_SYMBOL(parport_ieee1284_ecp_read_data); +EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr); +EXPORT_SYMBOL(parport_ieee1284_write_compat); +EXPORT_SYMBOL(parport_ieee1284_read_nibble); +EXPORT_SYMBOL(parport_ieee1284_read_byte); +EXPORT_SYMBOL(parport_ieee1284_epp_write_data); +EXPORT_SYMBOL(parport_ieee1284_epp_read_data); +EXPORT_SYMBOL(parport_ieee1284_epp_write_addr); +EXPORT_SYMBOL(parport_ieee1284_epp_read_addr); EXPORT_SYMBOL(parport_proc_register); EXPORT_SYMBOL(parport_proc_unregister); -EXPORT_SYMBOL(parport_probe_hook); +EXPORT_SYMBOL(parport_device_proc_register); +EXPORT_SYMBOL(parport_device_proc_unregister); +EXPORT_SYMBOL(parport_default_proc_register); +EXPORT_SYMBOL(parport_default_proc_unregister); EXPORT_SYMBOL(parport_parse_irqs); EXPORT_SYMBOL(parport_parse_dmas); +#ifdef CONFIG_PARPORT_1284 +EXPORT_SYMBOL(parport_open); +EXPORT_SYMBOL(parport_close); +EXPORT_SYMBOL(parport_device_id); +EXPORT_SYMBOL(parport_device_num); +EXPORT_SYMBOL(parport_device_coords); +EXPORT_SYMBOL(parport_daisy_deselect_all); +EXPORT_SYMBOL(parport_daisy_select); +EXPORT_SYMBOL(parport_daisy_init); +#endif void inc_parport_count(void) { diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.3.9/linux/drivers/misc/parport_pc.c Mon Jun 7 13:25:18 1999 +++ linux/drivers/misc/parport_pc.c Wed Jul 7 12:55:47 1999 @@ -9,6 +9,7 @@ * based on work by Grant Guenther and Phil Blundell. * * Cleaned up include files - Russell King + * DMA support - Bert De Jonghe * Better EPP probing - Carlos Henrique Bauer */ @@ -46,9 +47,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -57,12 +60,138 @@ than PARPORT_MAX (in ). */ #define PARPORT_PC_MAX_PORTS 8 +/* ECR modes */ +#define ECR_SPP 00 +#define ECR_PS2 01 +#define ECR_PPF 02 +#define ECR_ECP 03 +#define ECR_EPP 04 +#define ECR_VND 05 +#define ECR_TST 06 +#define ECR_CNF 07 + static int user_specified __initdata = 0; +/* frob_control, but for ECR */ +static void frob_econtrol (struct parport *pb, unsigned char m, + unsigned char v) +{ + outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb)); +} + +#ifdef CONFIG_PARPORT_1284 +/* Safely change the mode bits in the ECR */ +static int change_mode(struct parport *p, int m) +{ + const struct parport_pc_private *priv = p->physport->private_data; + int ecr = ECONTROL(p); + unsigned char oecr; + int mode; + + if (!priv->ecr) { + printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); + return 0; + } + + /* Bits <7:5> contain the mode. */ + oecr = inb (ecr); + mode = (oecr >> 5) & 0x7; + if (mode == m) return 0; + if (mode && m) + /* We have to go through mode 000 */ + change_mode (p, ECR_SPP); + + if (m < 2 && !(parport_read_control (p) & 0x20)) { + /* This mode resets the FIFO, so we may + * have to wait for it to drain first. */ + long expire = jiffies + p->physport->cad->timeout; + int counter; + switch (mode) { + case ECR_PPF: /* Parallel Port FIFO mode */ + case ECR_ECP: /* ECP Parallel Port mode */ + /* Busy wait for 200us */ + for (counter = 0; counter < 40; counter++) { + if (inb (ECONTROL (p)) & 0x01) + break; + if (signal_pending (current)) break; + udelay (5); + } + + /* Poll slowly. */ + while (!(inb (ECONTROL (p)) & 0x01)) { + if (time_after_eq (jiffies, expire)) + /* The FIFO is stuck. */ + return -EBUSY; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout ((HZ + 99) / 100); + if (signal_pending (current)) + break; + } + } + } + + /* Set the mode. */ + oecr &= ~(7 << 5); + oecr |= m << 5; + outb (oecr, ecr); + return 0; +} + +/* Find FIFO lossage; FIFO is reset */ +static int get_fifo_residue (struct parport *p) +{ + int residue; + int cnfga; + const struct parport_pc_private *priv = p->physport->private_data; + + /* Prevent further data transfer. */ + parport_frob_control (p, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Adjust for the contents of the FIFO. */ + for (residue = priv->fifo_depth; ; residue--) { + if (inb (ECONTROL (p)) & 0x2) + /* Full up. */ + break; + + outb (0, FIFO (p)); + } + + printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name, + residue); + + /* Reset the FIFO. */ + frob_econtrol (p, 0xe0, 0x20); + parport_frob_control (p, PARPORT_CONTROL_STROBE, 0); + + /* Now change to config mode and clean up. FIXME */ + frob_econtrol (p, 0xe0, 0xe0); + cnfga = inb (CONFIGA (p)); + printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); + + if (!(cnfga & (1<<2))) { + printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name); + residue++; + } + + /* Don't care about partial PWords until support is added for + * PWord != 1 byte. */ + + /* Back to PS2 mode. */ + frob_econtrol (p, 0xe0, 0x20); + + return residue; +} + +#endif /* IEEE 1284 support */ + /* * Clear TIMEOUT BIT in EPP MODE + * + * This is also used in SPP detection. */ -int parport_pc_epp_clear_timeout(struct parport *pb) +static int clear_epp_timeout(struct parport *pb) { unsigned char r; @@ -72,187 +201,719 @@ /* To clear timeout some chips require double read */ parport_pc_read_status(pb); r = parport_pc_read_status(pb); - parport_pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */ - parport_pc_write_status(pb, r & 0xfe); /* Others by writing 0 */ + outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */ + outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */ r = parport_pc_read_status(pb); return !(r & 0x01); } +/* + * Access functions. + * + * These aren't static because they may be used by the parport_xxx_yyy + * macros. extern __inline__ versions of several of these are in + * parport_pc.h. + */ + static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { parport_generic_irq(irq, (struct parport *) dev_id, regs); } -void parport_pc_write_epp(struct parport *p, unsigned char d) +void parport_pc_write_data(struct parport *p, unsigned char d) { - outb(d, EPPDATA(p)); + outb (d, DATA (p)); } -unsigned char parport_pc_read_epp(struct parport *p) +unsigned char parport_pc_read_data(struct parport *p) { - return inb(EPPDATA(p)); + return inb (DATA (p)); } -void parport_pc_write_epp_addr(struct parport *p, unsigned char d) +unsigned char __frob_control (struct parport *p, unsigned char mask, + unsigned char val) { - outb(d, EPPADDR(p)); + struct parport_pc_private *priv = p->physport->private_data; + unsigned char ctr = priv->ctr; + ctr = (ctr & ~mask) ^ val; + ctr &= priv->ctr_writable; /* only write writable bits. */ + outb (ctr, CONTROL (p)); + return priv->ctr = ctr; /* update soft copy */ } -unsigned char parport_pc_read_epp_addr(struct parport *p) +void parport_pc_write_control(struct parport *p, unsigned char d) { - return inb(EPPADDR(p)); -} + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); + + /* Take this out when drivers have adapted to the newer interface. */ + if (d & 0x20) { + printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", + p->name, p->cad->name); + parport_pc_data_reverse (p); + } -int parport_pc_check_epp_timeout(struct parport *p) -{ - if (!(inb(STATUS(p)) & 1)) - return 0; - parport_pc_epp_clear_timeout(p); - return 1; + __frob_control (p, wm, d & wm); } -unsigned char parport_pc_read_configb(struct parport *p) +unsigned char parport_pc_read_control(struct parport *p) { - return inb(CONFIGB(p)); + const struct parport_pc_private *priv = p->physport->private_data; + return priv->ctr; /* Use soft copy */ } -void parport_pc_write_data(struct parport *p, unsigned char d) +unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, + unsigned char val) { - outb(d, DATA(p)); -} + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); + + /* Take this out when drivers have adapted to the newer interface. */ + if (mask & 0x20) { + printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", + p->name, p->cad->name); + parport_pc_data_reverse (p); + } -unsigned char parport_pc_read_data(struct parport *p) -{ - return inb(DATA(p)); + /* Restrict mask and val to control lines. */ + mask &= wm; + val &= wm; + + return __frob_control (p, mask, val); } -void parport_pc_write_control(struct parport *p, unsigned char d) +unsigned char parport_pc_read_status(struct parport *p) { - struct parport_pc_private *priv = p->private_data; - priv->ctr = d;/* update soft copy */ - outb(d, CONTROL(p)); + return inb (STATUS (p)); } -unsigned char parport_pc_read_control(struct parport *p) +void parport_pc_disable_irq(struct parport *p) { - struct parport_pc_private *priv = p->private_data; - return priv->ctr; + __frob_control (p, 0x10, 0); } -unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val) +void parport_pc_enable_irq(struct parport *p) { - struct parport_pc_private *priv = p->private_data; - unsigned char ctr = priv->ctr; - ctr = (ctr & ~mask) ^ val; - outb (ctr, CONTROL(p)); - return priv->ctr = ctr; /* update soft copy */ + __frob_control (p, 0x10, 0x10); } -void parport_pc_write_status(struct parport *p, unsigned char d) +void parport_pc_data_forward (struct parport *p) { - outb(d, STATUS(p)); + __frob_control (p, 0x20, 0); } -unsigned char parport_pc_read_status(struct parport *p) +void parport_pc_data_reverse (struct parport *p) { - return inb(STATUS(p)); + __frob_control (p, 0x20, 0x20); } -void parport_pc_write_econtrol(struct parport *p, unsigned char d) +void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) { - outb(d, ECONTROL(p)); + struct parport_pc_private *priv = dev->port->physport->private_data; + priv->ctr = s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); + s->u.pc.ecr = 0x24; } -unsigned char parport_pc_read_econtrol(struct parport *p) +void parport_pc_save_state(struct parport *p, struct parport_state *s) { - return inb(ECONTROL(p)); + const struct parport_pc_private *priv = p->physport->private_data; + s->u.pc.ctr = inb (CONTROL (p)); + if (priv->ecr) + s->u.pc.ecr = inb (ECONTROL (p)); } -unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) +void parport_pc_restore_state(struct parport *p, struct parport_state *s) { - unsigned char old = inb(ECONTROL(p)); - outb(((old & ~mask) ^ val), ECONTROL(p)); - return old; + const struct parport_pc_private *priv = p->physport->private_data; + outb (s->u.pc.ctr, CONTROL (p)); + if (priv->ecr) + outb (s->u.pc.ecr, ECONTROL (p)); } -void parport_pc_change_mode(struct parport *p, int m) +#ifdef CONFIG_PARPORT_1284 +static size_t parport_pc_epp_read_data (struct parport *port, void *buf, + size_t length, int flags) { - /* FIXME */ + size_t got = 0; + for (; got < length; got++) { + *((char*)buf)++ = inb (EPPDATA(port)); + if (inb (STATUS(port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return got; } -void parport_pc_write_fifo(struct parport *p, unsigned char v) +static size_t parport_pc_epp_write_data (struct parport *port, const void *buf, + size_t length, int flags) { - outb (v, CONFIGA(p)); + size_t written = 0; + for (; written < length; written++) { + outb (*((char*)buf)++, EPPDATA(port)); + if (inb (STATUS(port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return written; } -unsigned char parport_pc_read_fifo(struct parport *p) +static size_t parport_pc_epp_read_addr (struct parport *port, void *buf, + size_t length, int flags) { - return inb (CONFIGA(p)); + size_t got = 0; + for (; got < length; got++) { + *((char*)buf)++ = inb (EPPADDR (port)); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return got; } -void parport_pc_disable_irq(struct parport *p) +static size_t parport_pc_epp_write_addr (struct parport *port, + const void *buf, size_t length, + int flags) { - parport_pc_frob_control(p, 0x10, 0); + size_t written = 0; + for (; written < length; written++) { + outb (*((char*)buf)++, EPPADDR (port)); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return written; } -void parport_pc_enable_irq(struct parport *p) +static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf, + size_t length, int flags) { - parport_pc_frob_control(p, 0x10, 0x10); + size_t got; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + got = parport_pc_epp_read_data (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return got; } -void parport_pc_init_state(struct parport_state *s) -{ - s->u.pc.ctr = 0xc; - s->u.pc.ecr = 0x0; +static size_t parport_pc_ecpepp_write_data (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + written = parport_pc_epp_write_data (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return written; } -void parport_pc_save_state(struct parport *p, struct parport_state *s) +static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf, + size_t length, int flags) { - s->u.pc.ctr = parport_pc_read_control(p); - if (p->modes & PARPORT_MODE_PCECR) - s->u.pc.ecr = parport_pc_read_econtrol(p); + size_t got; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + got = parport_pc_epp_read_addr (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return got; } -void parport_pc_restore_state(struct parport *p, struct parport_state *s) -{ - parport_pc_write_control(p, s->u.pc.ctr); - if (p->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(p, s->u.pc.ecr); +static size_t parport_pc_ecpepp_write_addr (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + + frob_econtrol (port, 0xe0, ECR_EPP << 5); + written = parport_pc_epp_write_addr (port, buf, length, flags); + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + return written; } +#endif /* IEEE 1284 support */ -size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length) -{ - size_t got = 0; - for (; got < length; got++) { - *((char*)buf)++ = inb (EPPDATA(p)); - if (inb (STATUS(p)) & 0x01) +#ifdef CONFIG_PARPORT_PC_FIFO +static size_t parport_pc_fifo_write_block_pio (struct parport *port, + const void *buf, size_t length) +{ + int ret = 0; + const unsigned char *bufp = buf; + size_t left = length; + long expire = jiffies + port->physport->cad->timeout; + const int fifo = FIFO (port); + int poll_for = 8; /* 80 usecs */ + const struct parport_pc_private *priv = port->physport->private_data; + const int fifo_depth = priv->fifo_depth; + + port = port->physport; + + /* We don't want to be interrupted every character. */ + parport_pc_disable_irq (port); + frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ + + /* Forward mode. */ + parport_pc_data_forward (port); + + while (left) { + unsigned char byte; + unsigned char ecrval = inb (ECONTROL (port)); + int i = 0; + + if (current->need_resched && time_before (jiffies, expire)) + /* Can't yield the port. */ + schedule (); + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG "Somebody wants the port\n"); break; - } - return got; + } + + if (ecrval & 0x02) { + /* FIFO is full. Wait for interrupt. */ + + /* Clear serviceIntr */ + outb (ecrval & ~(1<<2), ECONTROL (port)); + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "Timed out\n"); + break; + } + ecrval = inb (ECONTROL (port)); + if (!(ecrval & (1<<2))) { + if (current->need_resched && + time_before (jiffies, expire)) + schedule (); + + goto false_alarm; + } + + continue; + } + + /* Can't fail now. */ + expire = jiffies + port->cad->timeout; + + poll: + if (signal_pending (current)) + break; + + if (ecrval & 0x01) { + /* FIFO is empty. Blast it full. */ + const int n = left < fifo_depth ? left : fifo_depth; + outsb (fifo, bufp, n); + bufp += n; + left -= n; + + /* Adjust the poll time. */ + if (i < (poll_for - 2)) poll_for--; + continue; + } else if (i++ < poll_for) { + udelay (10); + ecrval = inb (ECONTROL (port)); + goto poll; + } + + /* Half-full (call me an optimist) */ + byte = *bufp++; + outb (byte, fifo); + left--; + } + + return length - left; } -size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length) +static size_t parport_pc_fifo_write_block_dma (struct parport *port, + const void *buf, size_t length) { - size_t written = 0; - for (; written < length; written++) { - outb (*((char*)buf)++, EPPDATA(p)); - if (inb (STATUS(p)) & 0x01) + int ret = 0; + unsigned long dmaflag; + size_t left = length; + const struct parport_pc_private *priv = port->physport->private_data; + + port = port->physport; + + /* We don't want to be interrupted every character. */ + parport_pc_disable_irq (port); + frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ + + /* Forward mode. */ + parport_pc_data_forward (port); + + while (left) { + long expire = jiffies + port->physport->cad->timeout; + + size_t count = left; + + if (count > PAGE_SIZE) + count = PAGE_SIZE; + + memcpy(priv->dma_buf, buf, count); + + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + set_dma_mode(port->dma, DMA_MODE_WRITE); + set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf)); + set_dma_count(port->dma, count); + + /* Set DMA mode */ + frob_econtrol (port, 1<<3, 1<<3); + + /* Clear serviceIntr */ + frob_econtrol (port, 1<<2, 0); + + enable_dma(port->dma); + release_dma_lock(dmaflag); + + /* assume DMA will be successful */ + left -= count; + buf += count; + + /* Wait for interrupt. */ + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "Timed out\n"); + break; + } + /* Is serviceIntr set? */ + if (!(inb (ECONTROL (port)) & (1<<2))) { + if (current->need_resched) + schedule (); + + goto false_alarm; + } + + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + count = get_dma_residue(port->dma); + release_dma_lock(dmaflag); + + if (current->need_resched) + /* Can't yield the port. */ + schedule (); + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG "Somebody wants the port\n"); break; + } + + /* update for possible DMA residue ! */ + buf -= count; + left += count; } + + /* Maybe got here through break, so adjust for DMA residue! */ + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + left += get_dma_residue(port->dma); + release_dma_lock(dmaflag); + + /* Turn off DMA mode */ + frob_econtrol (port, 1<<3, 0); + + return length - left; +} + +/* Parallel Port FIFO mode (ECP chipsets) */ +size_t parport_pc_compat_write_block_pio (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + + /* Special case: a timeout of zero means we cannot call schedule(). */ + if (!port->physport->cad->timeout) + return parport_ieee1284_write_compat (port, buf, + length, flags); + + /* Set up parallel port FIFO mode.*/ + change_mode (port, ECR_PPF); /* Parallel port FIFO */ + parport_pc_data_forward (port); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Write the data to the FIFO. */ + if (port->dma != PARPORT_DMA_NONE) + written = parport_pc_fifo_write_block_dma (port, buf, length); + else + written = parport_pc_fifo_write_block_pio (port, buf, length); + + /* Finish up. */ + if (change_mode (port, ECR_PS2) == -EBUSY) { + const struct parport_pc_private *priv = + port->physport->private_data; + + printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + + /* Prevent further data transfer. */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Adjust for the contents of the FIFO. */ + for (written -= priv->fifo_depth; ; written++) { + if (inb (ECONTROL (port)) & 0x2) + /* Full up. */ + break; + + outb (0, FIFO (port)); + } + + /* Reset the FIFO. */ + frob_econtrol (port, 0xe0, 0); + + /* De-assert strobe. */ + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + } + + parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + return written; } -int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) -{ - return -ENOSYS; /* FIXME */ +/* ECP */ +#ifdef CONFIG_PARPORT_1284 +size_t parport_pc_ecp_write_block_pio (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + + /* Special case: a timeout of zero means we cannot call schedule(). */ + if (!port->physport->cad->timeout) + return parport_ieee1284_ecp_write_data (port, buf, + length, flags); + + /* Switch to forward mode if necessary. */ + if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { + /* Event 47: Set nInit high. */ + parport_frob_control (port, PARPORT_CONTROL_INIT, 0); + + /* Event 40: PError goes high. */ + parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + } + + /* Set up ECP parallel port mode.*/ + change_mode (port, ECR_ECP); /* ECP FIFO */ + parport_pc_data_forward (port); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Write the data to the FIFO. */ + if (port->dma != PARPORT_DMA_NONE) + written = parport_pc_fifo_write_block_dma (port, buf, length); + else + written = parport_pc_fifo_write_block_pio (port, buf, length); + + /* Finish up. */ + if (change_mode (port, ECR_PS2) == -EBUSY) { + const struct parport_pc_private *priv = + port->physport->private_data; + + printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + + /* Prevent further data transfer. */ + parport_frob_control (port, + PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_STROBE); + + /* Adjust for the contents of the FIFO. */ + for (written -= priv->fifo_depth; ; written++) { + if (inb (ECONTROL (port)) & 0x2) + /* Full up. */ + break; + + outb (0, FIFO (port)); + } + + /* Reset the FIFO. */ + frob_econtrol (port, 0xe0, 0); + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + + /* Host transfer recovery. */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + parport_pc_data_reverse (port); + parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + parport_frob_control (port, PARPORT_CONTROL_INIT, 0); + parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + } + + parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; } -int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) +size_t parport_pc_ecp_read_block_pio (struct parport *port, + void *buf, size_t length, int flags) { - return -ENOSYS; /* FIXME */ + size_t left = length; + size_t fifofull; + const int fifo = FIFO(port); + const struct parport_pc_private *priv = port->physport->private_data; + const int fifo_depth = priv->fifo_depth; + char *bufp = buf; + + port = port->physport; + + /* Special case: a timeout of zero means we cannot call schedule(). */ + if (!port->cad->timeout) + return parport_ieee1284_ecp_read_data (port, buf, + length, flags); + + fifofull = fifo_depth; + if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) + /* If the peripheral is allowed to send RLE compressed + * data, it is possible for a byte to expand to 128 + * bytes in the FIFO. */ + fifofull = 128; + + /* If the caller wants less than a full FIFO's worth of data, + * go through software emulation. Otherwise we may have to through + * away data. */ + if (length < fifofull) + return parport_ieee1284_ecp_read_data (port, buf, + length, flags); + + /* Switch to reverse mode if necessary. */ + if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { + /* Event 38: Set nAutoFd low */ + parport_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + parport_pc_data_reverse (port); + udelay (5); + + /* Event 39: Set nInit low to initiate bus reversal */ + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + + /* Event 40: PError goes low */ + parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + } + + /* Set up ECP parallel port mode.*/ + change_mode (port, ECR_ECP); /* ECP FIFO */ + parport_pc_data_reverse (port); + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + + /* Do the transfer. */ + while (left > fifofull) { + int ret; + long int expire = jiffies + port->cad->timeout; + unsigned char ecrval = inb (ECONTROL (port)); + + if (current->need_resched && time_before (jiffies, expire)) + /* Can't yield the port. */ + schedule (); + + /* At this point, the FIFO may already be full. + * Ideally, we'd be able to tell the port to hold on + * for a second while we empty the FIFO, and we'd be + * able to ensure that no data is lost. I'm not sure + * that's the case. :-( It might be that you can play + * games with STB, as in the forward case; someone should + * look at a datasheet. */ + + if (ecrval & 0x01) { + /* FIFO is empty. Wait for interrupt. */ + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG + "Somebody wants the port\n"); + break; + } + + /* Clear serviceIntr */ + outb (ecrval & ~(1<<2), ECONTROL (port)); + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "Timed out\n"); + break; + } + ecrval = inb (ECONTROL (port)); + if (!(ecrval & (1<<2))) { + if (current->need_resched && + time_before (jiffies, expire)) + schedule (); + + goto false_alarm; + } + + continue; + } + + if (ecrval & 0x02) { + /* FIFO is full. */ + insb (fifo, bufp, fifo_depth); + bufp += fifo_depth; + left -= fifo_depth; + continue; + } + + *bufp++ = inb (fifo); + left--; + } + + /* Finish up. */ + if (change_mode (port, ECR_PS2) == -EBUSY) { + int lost = get_fifo_residue (port); + printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name, + lost); + } + + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; + + return length - left; } +#endif /* IEEE 1284 support */ + +#endif /* Allowed to use FIFO/DMA */ + void parport_pc_inc_use_count(void) { #ifdef MODULE @@ -269,6 +930,7 @@ static void parport_pc_fill_inode(struct inode *inode, int fill) { + /* Is this still needed? -tim */ #ifdef MODULE if (fill) MOD_INC_USE_COUNT; @@ -286,46 +948,39 @@ parport_pc_read_control, parport_pc_frob_control, - parport_pc_write_econtrol, - parport_pc_read_econtrol, - parport_pc_frob_econtrol, - - parport_pc_write_status, parport_pc_read_status, - parport_pc_write_fifo, - parport_pc_read_fifo, - - parport_pc_change_mode, - - parport_pc_write_epp, - parport_pc_read_epp, - parport_pc_write_epp_addr, - parport_pc_read_epp_addr, - parport_pc_check_epp_timeout, + parport_pc_enable_irq, + parport_pc_disable_irq, - parport_pc_epp_write_block, - parport_pc_epp_read_block, + parport_pc_data_forward, + parport_pc_data_reverse, - parport_pc_ecp_write_block, - parport_pc_ecp_read_block, - + parport_pc_interrupt, parport_pc_init_state, parport_pc_save_state, parport_pc_restore_state, - parport_pc_enable_irq, - parport_pc_disable_irq, - parport_pc_interrupt, - parport_pc_inc_use_count, parport_pc_dec_use_count, - parport_pc_fill_inode + parport_pc_fill_inode, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, }; /* --- Mode detection ------------------------------------- */ - /* * Checks for port existence, all ports support SPP MODE */ @@ -339,22 +994,23 @@ * that does not even respond to SPP cycles if an EPP * timeout is pending */ - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); /* Do a simple read-write test to make sure the port exists. */ w = 0xc; - parport_pc_write_control(pb, w); + outb (w, CONTROL (pb)); - /* Can we read from the control register? Some ports don't - * allow reads, so read_control just returns a software - * copy. Some ports _do_ allow reads, so bypass the software - * copy here. In addition, some bits aren't writable. */ + /* Is there a control register that we can read from? Some + * ports don't allow reads, so read_control just returns a + * software copy. Some ports _do_ allow reads, so bypass the + * software copy here. In addition, some bits aren't + * writable. */ r = inb (CONTROL (pb)); if ((r & 0xf) == w) { w = 0xe; - parport_pc_write_control (pb, w); - r = inb (CONTROL(pb)); - parport_pc_write_control (pb, 0xc); + outb (w, CONTROL (pb)); + r = inb (CONTROL (pb)); + outb (0xc, CONTROL (pb)); if ((r & 0xf) == w) return PARPORT_MODE_PCSPP; } @@ -379,20 +1035,20 @@ } if (user_specified) - /* Didn't work with 0xaa, but the user is convinced - * this is the place. */ + /* Didn't work, but the user is convinced this is the + * place. */ printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n", pb->base, w, r); /* It's possible that we can't read the control register or - the data register. In that case just believe the user. */ + * the data register. In that case just believe the user. */ if (user_specified) return PARPORT_MODE_PCSPP; return 0; } -/* Check for ECP +/* Check for ECR * * Old style XT ports alias io ports every 0x400, hence accessing ECR * on these cards actually accesses the CTR. @@ -401,82 +1057,225 @@ * regardless of what is written here if the card does NOT support * ECP. * - * We will write 0x2c to ECR and 0xcc to CTR since both of these - * values are "safe" on the CTR since bits 6-7 of CTR are unused. + * We first check to see if ECR is the same as CTR. If not, the low + * two bits of ECR aren't writable, so we check by writing ECR and + * reading it back to see if it's what we expect. */ static int __init parport_ECR_present(struct parport *pb) { - unsigned char r; + struct parport_pc_private *priv = pb->private_data; + unsigned char r = 0xc; - parport_pc_write_control (pb, 0xc); - r = parport_pc_read_control(pb); - if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) { - parport_pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */ + priv->ecr = 0; + outb (r, CONTROL (pb)); + if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) { + outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */ - r = parport_pc_read_control(pb); - if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2)) + r = inb (CONTROL (pb)); + if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2)) goto no_reg; /* Sure that no ECR register exists */ } - if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1) + if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1) goto no_reg; - parport_pc_write_econtrol(pb, 0x34); - if (parport_pc_read_econtrol(pb) != 0x35) + outb (0x34, ECONTROL (pb)); + if (inb (ECONTROL (pb)) != 0x35) goto no_reg; - parport_pc_write_control(pb, 0xc); - - /* Go to mode 000; SPP, reset FIFO */ - parport_pc_frob_econtrol (pb, 0xe0, 0x00); + priv->ecr = 1; + outb (0xc, CONTROL (pb)); - return PARPORT_MODE_PCECR; + /* Go to mode 000 */ + frob_econtrol (pb, 0xe0, ECR_SPP << 5); + + return 1; no_reg: - parport_pc_write_control (pb, 0xc); - return 0; + outb (0xc, CONTROL (pb)); + return 0; +} + +#ifdef CONFIG_PARPORT_1284 +/* Detect PS/2 support. + * + * Bit 5 (0x20) sets the PS/2 data direction; setting this high + * allows us to read data from the data lines. In theory we would get back + * 0xff but any peripheral attached to the port may drag some or all of the + * lines down to zero. So if we get back anything that isn't the contents + * of the data register we deem PS/2 support to be present. + * + * Some SPP ports have "half PS/2" ability - you can't turn off the line + * drivers, but an external peripheral with sufficiently beefy drivers of + * its own can overpower them and assert its own levels onto the bus, from + * where they can then be read back as normal. Ports with this property + * and the right type of device attached are likely to fail the SPP test, + * (as they will appear to have stuck bits) and so the fact that they might + * be misdetected here is rather academic. + */ + +static int __init parport_PS2_supported(struct parport *pb) +{ + int ok = 0; + + clear_epp_timeout(pb); + + /* try to tri-state the buffer */ + parport_pc_data_reverse (pb); + + parport_pc_write_data(pb, 0x55); + if (parport_pc_read_data(pb) != 0x55) ok++; + + parport_pc_write_data(pb, 0xaa); + if (parport_pc_read_data(pb) != 0xaa) ok++; + + /* cancel input mode */ + parport_pc_data_forward (pb); + + if (ok) + pb->modes |= PARPORT_MODE_TRISTATE; + else { + struct parport_pc_private *priv = pb->private_data; + priv->ctr_writable &= ~0x20; + } + + return ok; } static int __init parport_ECP_supported(struct parport *pb) { int i; - unsigned char oecr; - + int config; + int pword; + struct parport_pc_private *priv = pb->private_data; + /* If there is no ECR, we have no hope of supporting ECP. */ - if (!(pb->modes & PARPORT_MODE_PCECR)) + if (!priv->ecr) return 0; - oecr = parport_pc_read_econtrol(pb); + /* Find out FIFO depth */ + outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ + outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */ + for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++) + outb (0xaa, FIFO (pb)); + /* * Using LGS chipset it uses ECR register, but * it doesn't support ECP or FIFO MODE */ + if (i == 1024) { + outb (ECR_SPP << 5, ECONTROL (pb)); + return 0; + } + + priv->fifo_depth = i; + printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i); + + /* Find out writeIntrThreshold */ + frob_econtrol (pb, 1<<2, 1<<2); + frob_econtrol (pb, 1<<2, 0); + for (i = 1; i <= priv->fifo_depth; i++) { + inb (FIFO (pb)); + udelay (50); + if (inb (ECONTROL (pb)) & (1<<2)) + break; + } + + if (i <= priv->fifo_depth) + printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n", + pb->base, i); + else + /* Number of bytes we know we can write if we get an + interrupt. */ + i = 0; + + priv->writeIntrThreshold = i; + + /* Find out readIntrThreshold */ + frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */ + parport_pc_data_reverse (pb); + frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */ + frob_econtrol (pb, 1<<2, 1<<2); + frob_econtrol (pb, 1<<2, 0); + for (i = 1; i <= priv->fifo_depth; i++) { + outb (0xaa, FIFO (pb)); + if (inb (ECONTROL (pb)) & (1<<2)) + break; + } + + if (i <= priv->fifo_depth) + printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n", + pb->base, i); + else + /* Number of bytes we can read if we get an interrupt. */ + i = 0; + + priv->readIntrThreshold = i; + + outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ + outb (0xf4, ECONTROL (pb)); /* Configuration mode */ + config = inb (FIFO (pb)); + pword = (config >> 4) & 0x7; + switch (pword) { + case 0: + pword = 2; + printk (KERN_WARNING "0x%lx: Unsupported pword size!\n", + pb->base); + break; + case 2: + pword = 4; + printk (KERN_WARNING "0x%lx: Unsupported pword size!\n", + pb->base); + break; + default: + printk (KERN_WARNING "0x%lx: Unknown implementation ID\n", + pb->base); + /* Assume 1 */ + case 1: + pword = 1; + } + priv->pword = pword; + printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword); + + config = inb (CONFIGB (pb)); + printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base, + config & 0x80 ? "Level" : "Pulses"); + + if (!(config & 0x40)) { + printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base); + pb->irq = PARPORT_IRQ_NONE; + } + + /* Go back to mode 000 */ + frob_econtrol (pb, 0xe0, ECR_SPP << 5); + pb->modes |= PARPORT_MODE_ECP; + + return 1; +} + +static int __init parport_ECPPS2_supported(struct parport *pb) +{ + const struct parport_pc_private *priv = pb->private_data; + int result; + unsigned char oecr; + + if (!priv->ecr) + return 0; + + oecr = inb (ECONTROL (pb)); + outb (ECR_PS2 << 5, ECONTROL (pb)); - parport_pc_write_econtrol(pb, 0xc0); /* TEST FIFO */ - for (i=0; i < 1024 && (parport_pc_read_econtrol(pb) & 0x01); i++) - parport_pc_write_fifo(pb, 0xaa); - - parport_pc_write_econtrol(pb, oecr); - return (i==1024)?0:PARPORT_MODE_PCECP; + result = parport_PS2_supported(pb); + + outb (oecr, ECONTROL (pb)); + return result; } -/* EPP mode detection - * Theory: - * Bit 0 of STR is the EPP timeout bit, this bit is 0 - * when EPP is possible and is set high when an EPP timeout - * occurs (EPP uses the HALT line to stop the CPU while it does - * the byte transfer, an EPP timeout occurs if the attached - * device fails to respond after 10 micro seconds). - * - * This bit is cleared by either reading it (National Semi) - * or writing a 1 to the bit (SMC, UMC, WinBond), others ??? - * This bit is always high in non EPP modes. - */ +/* EPP mode detection */ + static int __init parport_EPP_supported(struct parport *pb) { - /* If EPP timeout bit clear then EPP available */ - if (!parport_pc_epp_clear_timeout(pb)) - return 0; /* No way to clear timeout */ + const struct parport_pc_private *priv = pb->private_data; /* * Theory: @@ -491,132 +1290,70 @@ * This bit is always high in non EPP modes. */ - parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20); - parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10); - parport_pc_epp_clear_timeout(pb); - - parport_pc_read_epp(pb); - udelay(30); /* Wait for possible EPP timeout */ - - if (parport_pc_read_status(pb) & 0x01) { - parport_pc_epp_clear_timeout(pb); - return PARPORT_MODE_PCEPP; - } - - /* - * Theory: - * Write two values to the EPP address register and - * read them back. When the transfer times out, the state of - * the EPP register is undefined in some cases (EPP 1.9?) but - * in others (EPP 1.7, ECPEPP?) it is possible to read back - * its value. - */ - parport_pc_epp_clear_timeout(pb); - udelay(30); /* Wait for possible EPP timeout */ - - /* Previous test left outputs disabled. */ - outb (0x55, EPPADDR (pb)); - - parport_pc_epp_clear_timeout(pb); - udelay(30); /* Wait for possible EPP timeout */ - - /* We must enable the outputs to be able to read the address - register. */ - parport_pc_frob_control (pb, 0x20, 0x00); - - if (inb (EPPADDR (pb)) == 0x55) { - - /* wash ... */ - parport_pc_frob_control (pb, 0x20, 0x20); - outb (0xaa, EPPADDR (pb)); - - parport_pc_epp_clear_timeout(pb); - udelay(30); /* Wait for possible EPP timeout */ - - /* ... and repeat */ - parport_pc_frob_control (pb, 0x20, 0x00); + /* If EPP timeout bit clear then EPP available */ + if (!clear_epp_timeout(pb)) + return 0; /* No way to clear timeout */ - if (inb (EPPADDR (pb)) == 0xaa) { - parport_pc_epp_clear_timeout (pb); - return PARPORT_MODE_PCEPP; + /* Check for Intel bug. */ + if (priv->ecr) { + unsigned char i; + for (i = 0x00; i < 0x80; i += 0x20) { + outb (i, ECONTROL (pb)); + if (clear_epp_timeout (pb)) + /* Phony EPP in ECP. */ + return 0; } } - return 0; + pb->modes |= PARPORT_MODE_EPP; + + /* Set up access functions to use EPP hardware. */ + parport_pc_ops.epp_read_data = parport_pc_epp_read_data; + parport_pc_ops.epp_write_data = parport_pc_epp_write_data; + parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr; + parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr; + + return 1; } static int __init parport_ECPEPP_supported(struct parport *pb) { - int mode; + struct parport_pc_private *priv = pb->private_data; + int result; unsigned char oecr; - if (!(pb->modes & PARPORT_MODE_PCECR)) + if (!priv->ecr) return 0; - oecr = parport_pc_read_econtrol(pb); + oecr = inb (ECONTROL (pb)); /* Search for SMC style EPP+ECP mode */ - parport_pc_write_econtrol(pb, 0x80); + outb (0x80, ECONTROL (pb)); - mode = parport_EPP_supported(pb); + result = parport_EPP_supported(pb); - parport_pc_write_econtrol(pb, oecr); - - return mode?PARPORT_MODE_PCECPEPP:0; -} - -/* Detect PS/2 support. - * - * Bit 5 (0x20) sets the PS/2 data direction; setting this high - * allows us to read data from the data lines. In theory we would get back - * 0xff but any peripheral attached to the port may drag some or all of the - * lines down to zero. So if we get back anything that isn't the contents - * of the data register we deem PS/2 support to be present. - * - * Some SPP ports have "half PS/2" ability - you can't turn off the line - * drivers, but an external peripheral with sufficiently beefy drivers of - * its own can overpower them and assert its own levels onto the bus, from - * where they can then be read back as normal. Ports with this property - * and the right type of device attached are likely to fail the SPP test, - * (as they will appear to have stuck bits) and so the fact that they might - * be misdetected here is rather academic. - */ + outb (oecr, ECONTROL (pb)); -static int __init parport_PS2_supported(struct parport *pb) -{ - int ok = 0; - unsigned char octr = parport_pc_read_control(pb); - - parport_pc_epp_clear_timeout(pb); - - parport_pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */ - - parport_pc_write_data(pb, 0x55); - if (parport_pc_read_data(pb) != 0x55) ok++; - - parport_pc_write_data(pb, 0xaa); - if (parport_pc_read_data(pb) != 0xaa) ok++; - - parport_pc_write_control(pb, octr); /* cancel input mode */ + if (result) { + /* Set up access functions to use ECP+EPP hardware. */ + parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data; + parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data; + parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr; + parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr; + } - return ok?PARPORT_MODE_PCPS2:0; + return result; } -static int __init parport_ECPPS2_supported(struct parport *pb) -{ - int mode; - unsigned char oecr; - - if (!(pb->modes & PARPORT_MODE_PCECR)) - return 0; +#else /* No IEEE 1284 support */ - oecr = parport_pc_read_econtrol(pb); - parport_pc_write_econtrol(pb, 0x20); - - mode = parport_PS2_supported(pb); +/* Don't bother probing for modes we know we won't use. */ +static int __init parport_PS2_supported(struct parport *pb) { return 0; } +static int __init parport_ECP_supported(struct parport *pb) { return 0; } +static int __init parport_EPP_supported(struct parport *pb) { return 0; } +static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; } +static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; } - parport_pc_write_econtrol(pb, oecr); - return mode?PARPORT_MODE_PCECPPS2:0; -} +#endif /* No IEEE 1284 support */ /* --- IRQ detection -------------------------------------- */ @@ -624,17 +1361,17 @@ static int __init programmable_irq_support(struct parport *pb) { int irq, intrLine; - unsigned char oecr = parport_pc_read_econtrol(pb); + unsigned char oecr = inb (ECONTROL (pb)); static const int lookup[8] = { PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 }; - parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */ - - intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07; + outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */ + + intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07; irq = lookup[intrLine]; - parport_pc_write_econtrol(pb, oecr); + outb (oecr, ECONTROL (pb)); return irq; } @@ -645,15 +1382,16 @@ sti(); irqs = probe_irq_on(); - parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */ - parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */ - - /* If Full FIFO sure that WriteIntrThresold is generated */ - for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) - parport_pc_write_fifo(pb, 0xaa); + outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ + outb ((ECR_TST << 5) | 0x04, ECONTROL (pb)); + outb (ECR_TST << 5, ECONTROL (pb)); + + /* If Full FIFO sure that writeIntrThreshold is generated */ + for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) + outb (0xaa, FIFO (pb)); pb->irq = probe_irq_off(irqs); - parport_pc_write_econtrol(pb, 0x00); + outb (ECR_SPP << 5, ECONTROL (pb)); if (pb->irq <= 0) pb->irq = PARPORT_IRQ_NONE; @@ -671,22 +1409,21 @@ return PARPORT_IRQ_NONE; #else int irqs; - unsigned char octr = parport_pc_read_control(pb); unsigned char oecr; if (pb->modes & PARPORT_MODE_PCECR) - oecr = parport_pc_read_econtrol(pb); + oecr = inb (ECONTROL (pb)); sti(); irqs = probe_irq_on(); if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_frob_econtrol (pb, 0x10, 0x10); + frob_econtrol (pb, 0x10, 0x10); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); parport_pc_frob_control (pb, 0x20, 0x20); parport_pc_frob_control (pb, 0x10, 0x10); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); /* Device isn't expecting an EPP read * and generates an IRQ. @@ -696,56 +1433,20 @@ pb->irq = probe_irq_off (irqs); if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(pb, oecr); - parport_pc_write_control(pb, octr); + outb (oecr, ECONTROL (pb)); + parport_pc_write_control(pb, 0xc); if (pb->irq <= 0) pb->irq = PARPORT_IRQ_NONE; return pb->irq; -#endif /* Advanced detection. */ +#endif /* Advanced detection */ } static int __init irq_probe_SPP(struct parport *pb) { -#ifndef ADVANCED_DETECT /* Don't even try to do this. */ return PARPORT_IRQ_NONE; -#else - int irqs; - unsigned char octr = parport_pc_read_control(pb); - unsigned char oecr; - - if (pb->modes & PARPORT_MODE_PCECR) - oecr = parport_pc_read_econtrol(pb); - probe_irq_off(probe_irq_on()); /* Clear any interrupts */ - irqs = probe_irq_on(); - - if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(pb, 0x10); - - parport_pc_write_data(pb,0x00); - parport_pc_write_control(pb,0x00); - parport_pc_write_control(pb,0x0c); - udelay(5); - parport_pc_write_control(pb,0x0d); - udelay(5); - parport_pc_write_control(pb,0x0c); - udelay(25); - parport_pc_write_control(pb,0x08); - udelay(25); - parport_pc_write_control(pb,0x0c); - udelay(50); - - pb->irq = probe_irq_off(irqs); - if (pb->irq <= 0) - pb->irq = PARPORT_IRQ_NONE; /* No interrupt detected */ - - if (pb->modes & PARPORT_MODE_PCECR) - parport_pc_write_econtrol(pb, oecr); - parport_pc_write_control(pb, octr); - return pb->irq; -#endif /* Advanced detection. */ } /* We will attempt to share interrupt requests since other devices @@ -757,25 +1458,27 @@ */ static int __init parport_irq_probe(struct parport *pb) { - if (pb->modes & PARPORT_MODE_PCECR) { + const struct parport_pc_private *priv = pb->private_data; + + if (priv->ecr) { pb->irq = programmable_irq_support(pb); if (pb->irq != PARPORT_IRQ_NONE) goto out; } - if (pb->modes & PARPORT_MODE_PCECP) + if (pb->modes & PARPORT_MODE_ECP) pb->irq = irq_probe_ECP(pb); - if (pb->irq == PARPORT_IRQ_NONE && - (pb->modes & PARPORT_MODE_PCECPEPP)) + if (pb->irq == PARPORT_IRQ_NONE && priv->ecr && + (pb->modes & PARPORT_MODE_EPP)) pb->irq = irq_probe_EPP(pb); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); - if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP)) + if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP)) pb->irq = irq_probe_EPP(pb); - parport_pc_epp_clear_timeout(pb); + clear_epp_timeout(pb); if (pb->irq == PARPORT_IRQ_NONE) pb->irq = irq_probe_SPP(pb); @@ -784,6 +1487,33 @@ return pb->irq; } +/* --- DMA detection -------------------------------------- */ + +/* Only if supports ECP mode */ +static int __init programmable_dma_support (struct parport *p) +{ + unsigned char oecr = inb (ECONTROL (p)); + int dma; + + frob_econtrol (p, 0xe0, ECR_CNF << 5); + + dma = inb (CONFIGB(p)) & 0x03; + if (!dma) + dma = PARPORT_DMA_NONE; + + outb (oecr, ECONTROL (p)); + return dma; +} + +static int __init parport_dma_probe (struct parport *p) +{ + const struct parport_pc_private *priv = p->private_data; + if (priv->ecr) + p->dma = programmable_dma_support(p); + + return p->dma; +} + /* --- Initialisation code -------------------------------- */ static int __init probe_one_port(unsigned long int base, @@ -801,6 +1531,10 @@ return 0; } priv->ctr = 0xc; + priv->ctr_writable = 0xff; + priv->ecr = 0; + priv->fifo_depth = 0; + priv->dma_buf = 0; p->base = base; p->base_hi = base_hi; p->irq = irq; @@ -808,39 +1542,41 @@ p->modes = PARPORT_MODE_PCSPP; p->ops = &parport_pc_ops; p->private_data = priv; - if (base_hi && !check_region (base_hi, 3)) { - p->modes |= parport_ECR_present (p); - p->modes |= parport_ECP_supported (p); - p->modes |= parport_ECPPS2_supported (p); + p->physport = p; + if (base_hi && !check_region(base_hi,3)) { + parport_ECR_present(p); + parport_ECP_supported(p); + parport_ECPPS2_supported(p); } - if (p->base != 0x3bc) { + if (base != 0x3bc) { if (!check_region(base+0x3, 5)) { - p->modes |= parport_EPP_supported (p); - p->modes |= parport_ECPEPP_supported (p); + parport_EPP_supported(p); + if (!(p->modes & PARPORT_MODE_EPP)) + parport_ECPEPP_supported(p); } } - if (!parport_SPP_supported(p)) { + if (!parport_SPP_supported (p)) { /* No port. */ kfree (priv); return 0; } - p->modes |= parport_PS2_supported(p); + parport_PS2_supported (p); - if (!(p = parport_register_port (base, PARPORT_IRQ_NONE, - PARPORT_DMA_NONE, &parport_pc_ops))) { + if (!(p = parport_register_port(base, PARPORT_IRQ_NONE, + PARPORT_DMA_NONE, &parport_pc_ops))) { kfree (priv); return 0; } p->base_hi = base_hi; p->modes = tmp.modes; - p->size = (p->modes & PARPORT_MODE_PCEPP) ? 8 : 3; + p->size = (p->modes & PARPORT_MODE_EPP)?8:3; p->private_data = priv; printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); - if (p->base_hi && (p->modes & PARPORT_MODE_PCECR)) - printk (" (0x%lx)", p->base_hi); + if (p->base_hi && (p->modes & PARPORT_MODE_ECP)) + printk(" (0x%lx)", p->base_hi); p->irq = irq; p->dma = dma; if (p->irq == PARPORT_IRQ_AUTO) { @@ -852,33 +1588,54 @@ probedirq = p->irq; p->irq = PARPORT_IRQ_NONE; } - if (p->irq != PARPORT_IRQ_NONE) + if (p->irq != PARPORT_IRQ_NONE) { printk(", irq %d", p->irq); + + if (p->dma == PARPORT_DMA_AUTO) { + p->dma = PARPORT_DMA_NONE; + parport_dma_probe(p); + } + } if (p->dma == PARPORT_DMA_AUTO) p->dma = PARPORT_DMA_NONE; - if (p->dma != PARPORT_DMA_NONE) + if (p->dma != PARPORT_DMA_NONE) printk(", dma %d", p->dma); + +#ifdef CONFIG_PARPORT_PC_FIFO + if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) { + parport_pc_ops.compat_write_data = + parport_pc_compat_write_block_pio; +#ifdef CONFIG_PARPORT_1284 + parport_pc_ops.ecp_write_data = + parport_pc_ecp_write_block_pio; +#endif /* IEEE 1284 support */ + if (p->dma != PARPORT_DMA_NONE) + p->modes |= PARPORT_MODE_DMA; + printk(", using FIFO"); + } +#endif /* Allowed to use FIFO/DMA */ + printk(" ["); -#define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}} +#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}} { int f = 0; - printmode(SPP); - printmode(PS2); + printmode(PCSPP); + printmode(TRISTATE); + printmode(COMPAT) printmode(EPP); printmode(ECP); - printmode(ECPEPP); - printmode(ECPPS2); + printmode(DMA); } #undef printmode printk("]\n"); -#ifdef CONFIG_PROC_FS if (probedirq != PARPORT_IRQ_NONE) - printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq); -#endif + printk("%s: irq %d detected\n", p->name, probedirq); parport_proc_register(p); - request_region (p->base, p->size, p->name); - if (p->modes & PARPORT_MODE_PCECR) + request_region (p->base, 3, p->name); + if (p->size > 3) + request_region (p->base + 3, p->size - 3, p->name); + if (p->modes & PARPORT_MODE_ECP) request_region (p->base_hi, 3, p->name); if (p->irq != PARPORT_IRQ_NONE) { @@ -897,25 +1654,38 @@ "resorting to PIO operation\n", p->name, p->dma); p->dma = PARPORT_DMA_NONE; + } else { + priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1); + if (! priv->dma_buf) { + printk (KERN_WARNING "%s: " + "cannot get buffer for DMA, " + "resorting to PIO operation\n", + p->name); + free_dma(p->dma); + p->dma = PARPORT_DMA_NONE; + } } } } - /* Done probing. Now put the port into a sensible start-up state. */ - if (p->modes & PARPORT_MODE_PCECR) + /* Done probing. Now put the port into a sensible start-up state. + * SELECT | INIT also puts IEEE1284-compliant devices into + * compatibility mode. */ + if (p->modes & PARPORT_MODE_ECP) /* * Put the ECP detected port in PS2 mode. */ - parport_pc_write_econtrol(p, 0x24); + outb (0x24, ECONTROL (p)); + parport_pc_write_data(p, 0); - parport_pc_write_control(p, 0x8); + parport_pc_data_forward (p); + parport_pc_write_control(p, PARPORT_CONTROL_SELECT); udelay (50); - parport_pc_write_control(p, 0xc); + parport_pc_write_control(p, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); udelay (50); - if (parport_probe_hook) - (*parport_probe_hook)(p); - /* Now that we've told the sharing engine about the port, and found out its characteristics, let the high-level drivers know about it. */ @@ -953,11 +1723,8 @@ #define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8001 /* The Lava Dual Parallel is */ #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8002 /* two PCI devices on a card */ -#endif /* IDs not defined */ +#endif - int count = 0; -#ifdef CONFIG_PCI - int i; struct { unsigned int vendor; unsigned int device; @@ -1014,6 +1781,9 @@ { 0, } }; + int count = 0; + int i; + if (!pci_present ()) return 0; @@ -1036,7 +1806,6 @@ } } } -#endif /* CONFIG_PCI */ return count; } @@ -1070,17 +1839,9 @@ static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, }; - -MODULE_PARM_DESC(io, "base address"); MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); - -MODULE_PARM_DESC(io_hi, "base address for ECR"); MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); - -MODULE_PARM_DESC(irq, "irq line to use (or 'auto' or 'none')"); MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); - -MODULE_PARM_DESC(dma, "dma channel to use (or 'auto' or 'none')"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); int init_module(void) @@ -1120,15 +1881,20 @@ struct parport *p = parport_enumerate(), *tmp; while (p) { tmp = p->next; - if (p->modes & PARPORT_MODE_PCSPP) { + if (p->modes & PARPORT_MODE_PCSPP) { + struct parport_pc_private *priv = p->private_data; if (p->dma != PARPORT_DMA_NONE) - free_dma (p->dma); + free_dma(p->dma); if (p->irq != PARPORT_IRQ_NONE) - free_irq (p->irq, p); - release_region (p->base, p->size); - if (p->modes & PARPORT_MODE_PCECP) - release_region (p->base_hi, 3); + free_irq(p->irq, p); + release_region(p->base, 3); + if (p->size > 3); + release_region(p->base + 3, p->size - 3); + if (p->modes & PARPORT_MODE_ECP) + release_region(p->base_hi, 3); parport_proc_unregister(p); + if (priv->dma_buf) + free_page((unsigned long) priv->dma_buf); kfree (p->private_data); parport_unregister_port(p); } diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_probe.c linux/drivers/misc/parport_probe.c --- v2.3.9/linux/drivers/misc/parport_probe.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/misc/parport_probe.c Sun Jul 4 09:53:12 1999 @@ -0,0 +1,212 @@ +/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $ + * Parallel port device probing code + * + * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de + * Philip Blundell + */ + +#include +#include +#include + +static struct { + char *token; + char *descr; +} classes[] = { + { "", "Legacy device" }, + { "PRINTER", "Printer" }, + { "MODEM", "Modem" }, + { "NET", "Network device" }, + { "HDC", "Hard disk" }, + { "PCMCIA", "PCMCIA" }, + { "MEDIA", "Multimedia device" }, + { "FDC", "Floppy disk" }, + { "PORTS", "Ports" }, + { "SCANNER", "Scanner" }, + { "DIGICAM", "Digital camera" }, + { "", "Unknown device" }, + { "", "Unspecified" }, + { "SCSIADAPTER", "SCSI adapter" }, + { NULL, NULL } +}; + +static void pretty_print(struct parport *port, int device) +{ + struct parport_device_info *info = &port->probe_info[device + 1]; + + printk(KERN_INFO "%s", port->name); + + if (device >= 0) + printk (" (addr %d)", device); + + printk (": %s", classes[info->class].descr); + if (info->class) + printk(", %s %s", info->mfr, info->model); + + printk("\n"); +} + +static char *strdup(char *str) +{ + int n = strlen(str)+1; + char *s = kmalloc(n, GFP_KERNEL); + if (!s) return NULL; + return strcpy(s, str); +} + +static void parse_data(struct parport *port, int device, char *str) +{ + char *txt = kmalloc(strlen(str)+1, GFP_KERNEL); + char *p = txt, *q; + int guessed_class = PARPORT_CLASS_UNSPEC; + struct parport_device_info *info = &port->probe_info[device + 1]; + + if (!txt) { + printk("%s probe: memory squeeze\n", port->name); + return; + } + strcpy(txt, str); + while (p) { + char *sep; + q = strchr(p, ';'); + if (q) *q = 0; + sep = strchr(p, ':'); + if (sep) { + char *u = p; + *(sep++) = 0; + while (*u) { + *u = toupper(*u); + u++; + } + if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) { + if (info->mfr) + kfree (info->mfr); + info->mfr = strdup(sep); + } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) { + if (info->model) + kfree (info->model); + info->model = strdup(sep); + } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) { + int i; + if (info->class_name) + kfree (info->class_name); + info->class_name = strdup(sep); + for (u = sep; *u; u++) + *u = toupper(*u); + for (i = 0; classes[i].token; i++) { + if (!strcmp(classes[i].token, sep)) { + info->class = i; + goto rock_on; + } + } + printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep); + info->class = PARPORT_CLASS_OTHER; + } else if (!strcmp(p, "CMD") || + !strcmp(p, "COMMAND SET")) { + if (info->cmdset) + kfree (info->cmdset); + info->cmdset = strdup(sep); + /* if it speaks printer language, it's + probably a printer */ + if (strstr(sep, "PJL") || strstr(sep, "PCL")) + guessed_class = PARPORT_CLASS_PRINTER; + } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) { + if (info->description) + kfree (info->description); + info->description = strdup(sep); + } + } + rock_on: + if (q) p = q+1; else p=NULL; + } + + /* If the device didn't tell us its class, maybe we have managed to + guess one from the things it did say. */ + if (info->class == PARPORT_CLASS_UNSPEC) + info->class = guessed_class; + + pretty_print (port, device); + + kfree(txt); +} + +/* Get Std 1284 Device ID. */ +ssize_t parport_device_id (int devnum, char *buffer, size_t len) +{ + ssize_t retval = -ENXIO; + struct pardevice *dev = parport_open (devnum, "Device ID probe", + NULL, NULL, NULL, 0, NULL); + if (!dev) + return -ENXIO; + + parport_claim_or_block (dev); + + /* Negotiate to compatibility mode, and then to device ID mode. + * (This is in case we are already in device ID mode.) */ + parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); + retval = parport_negotiate (dev->port, + IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID); + + if (!retval) { + int idlen; + unsigned char length[2]; + mm_segment_t oldfs = get_fs (); + set_fs (get_ds ()); + + /* First two bytes are MSB,LSB of inclusive length. */ + retval = parport_read (dev->port, length, 2); + + if (retval != 2) goto restore_fs; + + idlen = (length[0] << 8) + length[1] - 2; + if (idlen < len) + len = idlen; + retval = parport_read (dev->port, buffer, len); + + if (retval != len) { + printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n", + dev->port->name, retval, len); + goto restore_fs; + } + + /* Some printer manufacturers mistakenly believe that + the length field is supposed to be _exclusive_. */ + /* In addition, there are broken devices out there + that don't even finish off with a semi-colon. */ + if (idlen == len && buffer[len - 1] != ';') { + ssize_t diff; + diff = parport_read (dev->port, buffer + len, 2); + retval += diff; + + if (diff) + printk (KERN_DEBUG + "%s: device reported incorrect " + "length field (%d, should be %d)\n", + dev->port->name, idlen, retval); + else { + /* One semi-colon short of a device ID. */ + buffer[len++] = ';'; + buffer[len] = '\0'; + printk (KERN_DEBUG "%s: faking semi-colon\n", + dev->port->name); + + /* If we get here, I don't think we + need to worry about the possible + standard violation of having read + more than we were told to. The + device is non-compliant anyhow. */ + } + } + + restore_fs: + set_fs (oldfs); + parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); + } + parport_release (dev); + + if (retval > 0) + parse_data (dev->port, dev->daisy, buffer); + + parport_close (dev); + return retval; +} diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.3.9/linux/drivers/misc/parport_procfs.c Thu Jun 3 16:21:47 1999 +++ linux/drivers/misc/parport_procfs.c Thu Jul 1 14:22:57 1999 @@ -62,7 +62,7 @@ return copy_to_user(result, buffer, len) ? -EFAULT : 0; } -#if 0 && defined (CONFIG_PARPORT_1284) +#ifdef CONFIG_PARPORT_1284 static int do_autoprobe(ctl_table *table, int write, struct file *filp, void *result, size_t *lenp) { @@ -146,9 +146,11 @@ #define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}} int f = 0; printmode(PCSPP); - printmode(PCPS2); - printmode(PCEPP); - printmode(PCECP); + printmode(TRISTATE); + printmode(COMPAT); + printmode(EPP); + printmode(ECP); + printmode(DMA); #undef printmode } buffer[len++] = '\n'; @@ -190,7 +192,7 @@ NULL, 0, 0444, NULL, &do_hardware }, PARPORT_DEVICES_ROOT_DIR, -#if 0 && defined(CONFIG_PARPORT_1284) +#ifdef CONFIG_PARPORT_1284 { DEV_PARPORT_AUTOPROBE, "autoprobe", NULL, 0, 0444, NULL, &do_autoprobe }, @@ -292,17 +294,11 @@ for (i = 0; i < 8; i++) t->vars[i].extra1 = port; -#if 0 /* Wait for IEEE 1284 support */ t->vars[0].data = &port->spintime; -#endif t->vars[2].child = t->device_dir; for (i = 0; i < 5; i++) -#if 0 t->vars[3 + i].extra2 = &port->probe_info[i]; -#else - t->vars[3 + i].extra2 = &port->probe_info; -#endif t->port_dir[0].procname = port->name; t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */ @@ -348,7 +344,7 @@ t->port_dir[0].child = t->devices_root_dir; t->devices_root_dir[0].child = t->device_dir; -#if 0 && defined(CONFIG_PARPORT_1284) +#ifdef CONFIG_PARPORT_1284 t->device_dir[0].ctl_name = parport_device_num(port->number, port->muxport, diff -u --recursive --new-file v2.3.9/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c --- v2.3.9/linux/drivers/misc/parport_share.c Mon Jun 7 14:49:23 1999 +++ linux/drivers/misc/parport_share.c Sun Jul 4 10:14:13 1999 @@ -14,11 +14,8 @@ #undef PARPORT_DEBUG_SHARING /* undef for production */ #include - #include - #include - #include #include #include @@ -31,18 +28,12 @@ #include #include -#ifdef CONFIG_KMOD -#include -#endif - #undef PARPORT_PARANOID #define PARPORT_DEFAULT_TIMESLICE (HZ/5) unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE; - -/* This doesn't do anything yet. */ -int parport_default_spintime; +int parport_default_spintime = DEFAULT_SPIN_TIME; static struct parport *portlist = NULL, *portlist_tail = NULL; spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED; @@ -50,7 +41,7 @@ static struct parport_driver *driver_chain = NULL; spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED; -static void call_driver_chain (int attach, struct parport *port) +static void call_driver_chain(int attach, struct parport *port) { struct parport_driver *drv; @@ -96,19 +87,9 @@ } } -void (*parport_probe_hook)(struct parport *port) = NULL; - /* Return a list of all the ports we know about. */ struct parport *parport_enumerate(void) { -#ifdef CONFIG_KMOD - if (portlist == NULL) { - request_module("parport_lowlevel"); -#ifdef CONFIG_PNP_PARPORT_MODULE - request_module("parport_probe"); -#endif /* CONFIG_PNP_PARPORT_MODULE */ - } -#endif /* CONFIG_KMOD */ return portlist; } @@ -117,16 +98,9 @@ { struct parport *tmp; int portnum; + int device; char *name; - /* Check for a previously registered port. - NOTE: we will ignore irq and dma if we find a previously - registered device. */ - for (tmp = portlist; tmp; tmp = tmp->next) { - if (tmp->base == base) - return tmp; - } - tmp = kmalloc(sizeof(struct parport), GFP_KERNEL); if (!tmp) { printk(KERN_WARNING "parport: memory squeeze\n"); @@ -154,16 +128,22 @@ tmp->base = base; tmp->irq = irq; tmp->dma = dma; + tmp->muxport = tmp->daisy = tmp->muxsel = -1; tmp->modes = 0; tmp->next = NULL; tmp->devices = tmp->cad = NULL; tmp->flags = 0; tmp->ops = ops; - tmp->number = portnum; - memset (&tmp->probe_info, 0, sizeof (struct parport_device_info)); + tmp->portnum = tmp->number = portnum; + tmp->physport = tmp; + memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info)); tmp->cad_lock = RW_LOCK_UNLOCKED; spin_lock_init(&tmp->waitlist_lock); spin_lock_init(&tmp->pardevice_lock); + tmp->ieee1284.mode = IEEE1284_MODE_COMPAT; + tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */ + tmp->spintime = parport_default_spintime; name = kmalloc(15, GFP_KERNEL); if (!name) { @@ -188,7 +168,10 @@ portlist = tmp; spin_unlock(&parportlist_lock); - tmp->probe_info.class = PARPORT_CLASS_LEGACY; /* assume the worst */ + for (device = 0; device < 5; device++) + /* assume the worst */ + tmp->probe_info[device].class = PARPORT_CLASS_LEGACY; + tmp->waithead = tmp->waittail = NULL; return tmp; @@ -196,6 +179,11 @@ void parport_announce_port (struct parport *port) { +#ifdef CONFIG_PARPORT_1284 + /* Analyse the IEEE1284.3 topology of the port. */ + parport_daisy_init (port); +#endif + /* Let drivers know that a new port has arrived. */ call_driver_chain (1, port); } @@ -203,10 +191,16 @@ void parport_unregister_port(struct parport *port) { struct parport *p; + int d; /* Spread the word. */ call_driver_chain (0, port); +#ifdef CONFIG_PARPORT_1284 + /* Forget the IEEE1284.3 topology of the port. */ + parport_daisy_fini (port); +#endif + spin_lock(&parportlist_lock); if (portlist == port) { if ((portlist = port->next) == NULL) @@ -222,16 +216,20 @@ "%s not found in port list!\n", port->name); } spin_unlock(&parportlist_lock); - if (port->probe_info.class_name) - kfree (port->probe_info.class_name); - if (port->probe_info.mfr) - kfree (port->probe_info.mfr); - if (port->probe_info.model) - kfree (port->probe_info.model); - if (port->probe_info.cmdset) - kfree (port->probe_info.cmdset); - if (port->probe_info.description) - kfree (port->probe_info.description); + + for (d = 0; d < 5; d++) { + if (port->probe_info[d].class_name) + kfree (port->probe_info[d].class_name); + if (port->probe_info[d].mfr) + kfree (port->probe_info[d].mfr); + if (port->probe_info[d].model) + kfree (port->probe_info[d].model); + if (port->probe_info[d].cmdset) + kfree (port->probe_info[d].cmdset); + if (port->probe_info[d].description) + kfree (port->probe_info[d].description); + } + kfree(port->name); kfree(port); } @@ -243,7 +241,7 @@ { struct pardevice *tmp; - if (port->flags & PARPORT_FLAG_EXCL) { + if (port->physport->flags & PARPORT_FLAG_EXCL) { /* An exclusive device is registered. */ printk (KERN_DEBUG "%s: no more devices allowed\n", port->name); @@ -272,13 +270,14 @@ tmp->name = name; tmp->port = port; + tmp->daisy = -1; tmp->preempt = pf; tmp->wakeup = kf; tmp->private = handle; tmp->flags = flags; tmp->irq_func = irq_func; - port->ops->init_state(tmp->state); tmp->waiting = 0; + tmp->timeout = 5 * HZ; /* Chain this onto the list */ tmp->prev = NULL; @@ -286,11 +285,11 @@ * This function must not run from an irq handler so we don' t need * to clear irq on the local CPU. -arca */ - spin_lock(&port->pardevice_lock); + spin_lock(&port->physport->pardevice_lock); if (flags & PARPORT_DEV_EXCL) { - if (port->devices) { - spin_unlock (&port->pardevice_lock); + if (port->physport->devices) { + spin_unlock (&port->physport->pardevice_lock); kfree (tmp->state); kfree (tmp); printk (KERN_DEBUG @@ -301,11 +300,11 @@ port->flags |= PARPORT_FLAG_EXCL; } - tmp->next = port->devices; - if (port->devices) - port->devices->prev = tmp; - port->devices = tmp; - spin_unlock(&port->pardevice_lock); + tmp->next = port->physport->devices; + if (port->physport->devices) + port->physport->devices->prev = tmp; + port->physport->devices = tmp; + spin_unlock(&port->physport->pardevice_lock); inc_parport_count(); port->ops->inc_use_count(); @@ -314,6 +313,12 @@ tmp->timeslice = parport_default_timeslice; tmp->waitnext = tmp->waitprev = NULL; + /* + * This has to be run as last thing since init_state may need other + * pardevice fields. -arca + */ + port->ops->init_state(tmp, tmp->state); + parport_device_proc_register(tmp); return tmp; } @@ -328,7 +333,9 @@ } #endif - port = dev->port; + parport_device_proc_unregister(dev); + + port = dev->port->physport; if (port->cad == dev) { printk(KERN_DEBUG "%s: %s forgot to release port\n", @@ -354,19 +361,17 @@ dec_parport_count(); port->ops->dec_use_count(); - - return; } int parport_claim(struct pardevice *dev) { struct pardevice *oldcad; - struct parport *port = dev->port; + struct parport *port = dev->port->physport; unsigned long flags; if (port->cad == dev) { printk(KERN_INFO "%s: %s already owner\n", - dev->port->name,dev->name); + dev->port->name,dev->name); return 0; } @@ -407,24 +412,27 @@ dev->waitprev = dev->waitnext = NULL; } - if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func) - /* - * If there was an irq pending it should hopefully happen - * before return from enable_irq(). -arca - */ - enable_irq(port->irq); - - /* - * Avoid running irq handlers if the pardevice doesn' t use it. -arca - */ - if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func) - disable_irq(port->irq); - /* Now we do the change of devices */ write_lock_irqsave(&port->cad_lock, flags); port->cad = dev; write_unlock_irqrestore(&port->cad_lock, flags); +#ifdef CONFIG_PARPORT_1284 + /* If it's a mux port, select it. */ + if (dev->port->muxport >= 0) { + /* FIXME */ + port->muxsel = dev->port->muxport; + } + + /* If it's a daisy chain device, select it. */ + if (dev->daisy >= 0) { + /* This could be lazier. */ + if (!parport_daisy_select (port, dev->daisy, + IEEE1284_MODE_COMPAT)) + port->daisy = dev->daisy; + } +#endif /* IEEE1284.3 support */ + /* Restore control registers */ port->ops->restore_state(port, dev->state); dev->time = jiffies; @@ -487,8 +495,11 @@ } restore_flags(flags); #ifdef PARPORT_DEBUG_SHARING - if (dev->port->cad != dev) - printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n", dev->name, dev->port->cad?dev->port->cad->name:"nobody"); + if (dev->port->physport->cad != dev) + printk(KERN_DEBUG "%s: exiting parport_claim_or_block " + "but %s owns port!\n", dev->name, + dev->port->physport->cad ? + dev->port->physport->cad->name:"nobody"); #endif } dev->waiting = 0; @@ -497,7 +508,7 @@ void parport_release(struct pardevice *dev) { - struct parport *port = dev->port; + struct parport *port = dev->port->physport; struct pardevice *pd; unsigned long flags; @@ -507,16 +518,24 @@ "when not owner\n", port->name, dev->name); return; } + +#ifdef CONFIG_PARPORT_1284 + /* If this is on a mux port, deselect it. */ + if (dev->port->muxport >= 0) { + /* FIXME */ + port->muxsel = -1; + } + + /* If this is a daisy device, deselect it. */ + if (dev->daisy >= 0) { + parport_daisy_deselect_all (port); + port->daisy = -1; + } +#endif + write_lock_irqsave(&port->cad_lock, flags); port->cad = NULL; write_unlock_irqrestore(&port->cad_lock, flags); - - /* - * Reenable irq and so discard the eventually pending irq while - * cad is NULL. -arca - */ - if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func) - enable_irq(port->irq); /* Save control registers */ port->ops->save_state(port, dev->state); diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v2.3.9/linux/drivers/net/3c501.c Thu Dec 31 12:03:49 1998 +++ linux/drivers/net/3c501.c Tue Jul 6 19:05:49 1999 @@ -210,7 +210,7 @@ struct netdev_entry el1_drv = {"3c501", el1_probe1, EL1_IO_EXTENT, netcard_portlist}; #else -__initfunc(int el1_probe(struct device *dev)) +int __init el1_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -237,7 +237,7 @@ * The actual probe. */ -__initfunc(static int el1_probe1(struct device *dev, int ioaddr)) +static int __init el1_probe1(struct device *dev, int ioaddr) { struct net_local *lp; const char *mname; /* Vendor name */ diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.3.9/linux/drivers/net/3c503.c Wed Dec 16 13:35:49 1998 +++ linux/drivers/net/3c503.c Tue Jul 6 19:05:49 1999 @@ -90,8 +90,8 @@ If the ethercard isn't found there is an optional probe for ethercard jumpered to programmed-I/O mode. */ -__initfunc(int -el2_probe(struct device *dev)) +int __init +el2_probe(struct device *dev) { int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0}; int base_addr = dev->base_addr; @@ -125,8 +125,8 @@ #ifndef HAVE_DEVLIST /* Try all of the locations that aren't obviously empty. This touches a lot of locations, and is much riskier than the code above. */ -__initfunc(int -el2_pio_probe(struct device *dev)) +int __init +el2_pio_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -151,8 +151,8 @@ /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ -__initfunc(int -el2_probe1(struct device *dev, int ioaddr)) +int __init +el2_probe1(struct device *dev, int ioaddr) { int i, iobase_reg, membase_reg, saved_406, wordlength; static unsigned version_printed = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.3.9/linux/drivers/net/3c505.c Thu Dec 17 09:03:57 1998 +++ linux/drivers/net/3c505.c Tue Jul 6 19:05:49 1999 @@ -1339,7 +1339,7 @@ * Called only by elp_autodetect ************************************************************/ -__initfunc(static int elp_sense(struct device *dev)) +static int __init elp_sense(struct device *dev) { int timeout; int addr = dev->base_addr; @@ -1406,7 +1406,7 @@ * Called only by eplus_probe *************************************************************/ -__initfunc(static int elp_autodetect(struct device *dev)) +static int __init elp_autodetect(struct device *dev) { int idx = 0; @@ -1450,7 +1450,7 @@ * work at all if it was in a weird state). */ -__initfunc(int elplus_probe(struct device *dev)) +int __init elplus_probe(struct device *dev) { elp_device *adapter; int i, tries, tries1, timeout, okay; diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.3.9/linux/drivers/net/3c507.c Thu May 6 23:14:36 1999 +++ linux/drivers/net/3c507.c Tue Jul 6 19:05:49 1999 @@ -305,7 +305,7 @@ device and return success. */ -__initfunc(int el16_probe(struct device *dev)) +int __init el16_probe(struct device *dev) { int base_addr = dev ? dev->base_addr : 0; int i; @@ -326,7 +326,7 @@ return ENODEV; } -__initfunc(int el16_probe1(struct device *dev, int ioaddr)) +int __init el16_probe1(struct device *dev, int ioaddr) { static unsigned char init_ID_done = 0, version_printed = 0; int i, irq, irqval; diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.3.9/linux/drivers/net/3c523.c Sat Apr 24 17:49:37 1999 +++ linux/drivers/net/3c523.c Tue Jul 6 19:05:49 1999 @@ -319,7 +319,7 @@ * Check to see if there's an 82586 out there. */ -__initfunc(static int check586(struct device *dev, unsigned long where, unsigned size)) +static int __init check586(struct device *dev, unsigned long where, unsigned size) { struct priv *p = (struct priv *) dev->priv; char *iscp_addrs[2]; @@ -422,7 +422,7 @@ /*****************************************************************/ -__initfunc(int elmc_probe(struct device *dev)) +int __init elmc_probe(struct device *dev) { static int slot = 0; int base_addr = dev ? dev->base_addr : 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/3c527.c linux/drivers/net/3c527.c --- v2.3.9/linux/drivers/net/3c527.c Wed May 12 13:27:37 1999 +++ linux/drivers/net/3c527.c Tue Jul 6 19:05:49 1999 @@ -147,7 +147,7 @@ * (detachable devices only). */ -__initfunc(int mc32_probe(struct device *dev)) +int __init mc32_probe(struct device *dev) { static int current_mca_slot = -1; int i; @@ -183,7 +183,7 @@ * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ -__initfunc(static int mc32_probe1(struct device *dev, int slot)) +static int __init mc32_probe1(struct device *dev, int slot) { static unsigned version_printed = 0; int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/82596.c linux/drivers/net/82596.c --- v2.3.9/linux/drivers/net/82596.c Thu Jan 7 08:46:59 1999 +++ linux/drivers/net/82596.c Tue Jul 6 19:05:49 1999 @@ -878,7 +878,7 @@ printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); } -__initfunc(int i82596_probe(struct device *dev)) +int __init i82596_probe(struct device *dev) { int i; struct i596_private *lp; diff -u --recursive --new-file v2.3.9/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.9/linux/drivers/net/Config.in Wed Jun 30 13:38:20 1999 +++ linux/drivers/net/Config.in Wed Jul 7 09:14:26 1999 @@ -2,6 +2,9 @@ # Network device configuration # +mainmenu_option next_comment +comment 'ARCnet devices' + tristate 'ARCnet support' CONFIG_ARCNET if [ "$CONFIG_ARCNET" != "n" ]; then bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH @@ -12,6 +15,8 @@ dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET fi +endmenu + tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -22,6 +27,10 @@ # # Ethernet # + +mainmenu_option next_comment +comment 'Ethernet (10 or 100Mbit)' + bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_ARM" = "y" ]; then @@ -82,18 +91,15 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then - tristate 'AT1700/1720 support' CONFIG_AT1700 + tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 tristate 'Cabletron E21xx support' CONFIG_E2100 tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 tristate 'EtherExpress 16 support' CONFIG_EEXPRESS - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO - fi + tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN @@ -103,7 +109,7 @@ fi tristate 'NE2000/NE1000 support' CONFIG_NE2000 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 + tristate 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 fi bool 'SK_G16 support' CONFIG_SK_G16 fi @@ -115,6 +121,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -145,6 +152,8 @@ fi fi +endmenu + bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX @@ -153,25 +162,20 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI if [ "$CONFIG_HIPPI" = "y" ]; then - bool 'CERN HIPPI PCI adapter support' CONFIG_CERN_HIPPI - bool 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER + tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER if [ "$CONFIG_ROADRUNNER" != "n" ]; then bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS fi fi fi -tristate 'Frame relay DLCI support' CONFIG_DLCI -if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then - int ' Max open DLCI' CONFIG_DLCI_COUNT 24 - int ' Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI -fi - # # AppleTalk # + if [ "$CONFIG_ATALK" != "n" ]; then + mainmenu_option next_comment + comment 'Appletalk devices' dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK if [ "$CONFIG_COPS" != "n" ]; then @@ -183,6 +187,7 @@ bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP fi + endmenu fi if [ ! "$CONFIG_PARPORT" = "n" ]; then @@ -203,23 +208,38 @@ bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP + dep_tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN + tristate 'Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN + fi +mainmenu_option next_comment +comment 'Token ring devices' + bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" = "y" ]; then tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR # tristate 'IBM Lanstreamer PCI adaptor support' CONFIG_IBMLS + tristate 'IBM Olympic chipset PCI adapter support' CONFIG_IBMOL tristate 'SysKonnect adapter support' CONFIG_SKTR fi +endmenu + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER fi + # # WAN drivers support # + +mainmenu_option next_comment +comment 'Wan interfaces' + + # There is no way to detect a comtrol sv11 - force it modular for now. # dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m @@ -227,8 +247,22 @@ # The COSA/SRP driver has not been tested as non-modular yet. # dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m -tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI # +# There is no way to detect a Sealevel board. Force it modular +# +dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + +tristate 'Frame relay DLCI support' CONFIG_DLCI +if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI +fi + +# +# Wan router core. +# + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then @@ -247,6 +281,9 @@ fi fi fi + +endmenu + # # X.25 network drivers # diff -u --recursive --new-file v2.3.9/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.9/linux/drivers/net/Makefile Wed Jun 30 13:38:20 1999 +++ linux/drivers/net/Makefile Tue Jul 6 19:16:55 1999 @@ -67,6 +67,14 @@ endif endif +ifeq ($(CONFIG_IBMOL),y) +L_OBJS += olympic.o +else + ifeq ($(CONFIG_IBMOL),m) + M_OBJS += olympic.o + endif +endif + ifeq ($(CONFIG_SKTR),y) L_OBJS += sktr.o else @@ -422,6 +430,14 @@ endif endif +ifeq ($(CONFIG_SUNBMAC),y) +L_OBJS += sunbmac.o +else + ifeq ($(CONFIG_SUNBMAC),m) + M_OBJS += sunbmac.o + endif +endif + ifeq ($(CONFIG_MYRI_SBUS),y) L_OBJS += myri_sbus.o else @@ -566,6 +582,14 @@ endif endif +ifeq ($(CONFIG_ARLAN),y) +LX_OBJS += arlan.o arlan-proc.o +else + ifeq ($(CONFIG_ARLAN),m) + MX_OBJS += arlan.o arlan-proc.o + endif +endif + ifeq ($(CONFIG_TLAN),y) L_OBJS += tlan.o else @@ -764,6 +788,19 @@ endif endif +ifeq ($(CONFIG_SEALEVEL_4021),y) +L_OBJS += sealevel.o +CONFIG_85230_BUILTIN = y +CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_SEALEVEL_4021),m) + CONFIG_85230_MODULE = y + CONFIG_SYNCPPP_MODULE = y + M_OBJS += sealevel.o + endif +endif + + ifeq ($(CONFIG_COSA),y) L_OBJS += cosa.o CONFIG_SYNCPPP_BUILTIN = y @@ -1061,15 +1098,6 @@ L_OBJS += cycx_main.o ifeq ($(CONFIG_CYCLOMX_X25),y) L_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),m) - MX_OBJS += cycx_drv.o - M_OBJS += cyclomx.o - CYCLOMX_OBJS = cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - CYCLOMX_OBJS += cycx_x25.o endif endif diff -u --recursive --new-file v2.3.9/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.9/linux/drivers/net/Space.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/net/Space.c Tue Jul 6 19:05:49 1999 @@ -67,6 +67,7 @@ extern int de4x5_probe(struct device *); extern int el1_probe(struct device *); extern int wavelan_probe(struct device *); +extern int arlan_probe(struct device *); extern int el16_probe(struct device *); extern int elmc_probe(struct device *); extern int skmca_probe(struct device *); @@ -147,7 +148,7 @@ * autoprobe (i.e. a probe that fails to find a card when autoprobing * will not be asked to autoprobe again). It exits when a card is found. */ -__initfunc(static int probe_list(struct device *dev, struct devprobe *plist)) +static int __init probe_list(struct device *dev, struct devprobe *plist) { struct devprobe *p = plist; unsigned long base_addr = dev->base_addr; @@ -359,6 +360,9 @@ #ifdef CONFIG_WAVELAN /* WaveLAN */ {wavelan_probe, 0}, #endif +#ifdef CONFIG_ARLAN /* Aironet */ + {arlan_probe, 0}, +#endif #ifdef CONFIG_EL16 /* 3c507 */ {el16_probe, 0}, #endif @@ -474,7 +478,7 @@ * Unified ethernet device probe, segmented per architecture and * per bus interface. */ -__initfunc(static int ethif_probe(struct device *dev)) +static int __init ethif_probe(struct device *dev) { unsigned long base_addr = dev->base_addr; @@ -522,7 +526,7 @@ } #ifdef CONFIG_FDDI -__initfunc(static int fddiif_probe(struct device *dev)) +static int __init fddiif_probe(struct device *dev) { unsigned long base_addr = dev->base_addr; @@ -719,6 +723,7 @@ #ifdef CONFIG_TR /* Token-ring device probe */ extern int ibmtr_probe(struct device *); +extern int olympic_probe(struct device *); static int trif_probe(struct device *dev) @@ -726,6 +731,9 @@ if (1 #ifdef CONFIG_IBMTR && ibmtr_probe(dev) +#endif +#ifdef CONFIG_IBMOL + && olympic_probe(dev) #endif #ifdef CONFIG_SKTR && sktr_probe(dev) diff -u --recursive --new-file v2.3.9/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.3.9/linux/drivers/net/a2065.c Sun Mar 21 07:22:00 1999 +++ linux/drivers/net/a2065.c Tue Jul 6 19:05:49 1999 @@ -739,8 +739,7 @@ mark_bh(NET_BH); } - -__initfunc(int a2065_probe(struct device *dev)) +int __init a2065_probe(struct device *dev) { unsigned int key, is_cbm; const struct ConfigDev *cd; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c --- v2.3.9/linux/drivers/net/ac3200.c Thu Dec 17 09:03:57 1998 +++ linux/drivers/net/ac3200.c Tue Jul 6 19:05:49 1999 @@ -95,7 +95,7 @@ or the unique value in the station address PROM. */ -__initfunc(int ac3200_probe(struct device *dev)) +int __init ac3200_probe(struct device *dev) { unsigned short ioaddr = dev->base_addr; @@ -117,7 +117,7 @@ return ENODEV; } -__initfunc(static int ac_probe1(int ioaddr, struct device *dev)) +static int __init ac_probe1(int ioaddr, struct device *dev) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.3.9/linux/drivers/net/acenic.c Mon Mar 22 08:08:12 1999 +++ linux/drivers/net/acenic.c Tue Jul 6 19:05:49 1999 @@ -177,7 +177,7 @@ static int probed __initdata = 0; -__initfunc(int acenic_probe (struct device *dev)) +int __init acenic_probe (struct device *dev) { int boards_found = 0; int version_disp; @@ -423,7 +423,7 @@ } -__initfunc(static int ace_init(struct device *dev, int board_idx)) +static int __init ace_init(struct device *dev, int board_idx) { struct ace_private *ap; struct ace_regs *regs; @@ -1574,7 +1574,7 @@ } -__initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)) +void __init ace_copy(struct ace_regs *regs, void *src, u32 dest, int size) { unsigned long tdest; u32 *wsrc; @@ -1609,7 +1609,7 @@ } -__initfunc(void ace_clear(struct ace_regs *regs, u32 dest, int size)) +void __init ace_clear(struct ace_regs *regs, u32 dest, int size) { unsigned long tdest; short tsize = 0, i; @@ -1642,7 +1642,7 @@ * This operation requires the NIC to be halted and is performed with * interrupts disabled and with the spinlock hold. */ -__initfunc(int ace_load_firmware(struct device *dev)) +int __init ace_load_firmware(struct device *dev) { struct ace_private *ap; struct ace_regs *regs; diff -u --recursive --new-file v2.3.9/linux/drivers/net/apne.c linux/drivers/net/apne.c --- v2.3.9/linux/drivers/net/apne.c Thu Dec 17 09:07:46 1998 +++ linux/drivers/net/apne.c Tue Jul 6 19:05:49 1999 @@ -121,7 +121,7 @@ static int apne_owned = 0; /* signal if card already owned */ -__initfunc(int apne_probe(struct device *dev)) +int __init apne_probe(struct device *dev) { #ifndef MANUAL_CONFIG char tuple[8]; @@ -161,8 +161,7 @@ } - -__initfunc(static int apne_probe1(struct device *dev, int ioaddr)) +static int __init apne_probe1(struct device *dev, int ioaddr) { int i; unsigned char SA_prom[32]; diff -u --recursive --new-file v2.3.9/linux/drivers/net/arc-rimi.c linux/drivers/net/arc-rimi.c --- v2.3.9/linux/drivers/net/arc-rimi.c Mon Sep 14 11:32:22 1998 +++ linux/drivers/net/arc-rimi.c Tue Jul 6 19:05:49 1999 @@ -100,7 +100,7 @@ MODULE_PARM(device, "s"); MODULE_PARM (node, "i"); #else -__initfunc(void arcrimi_setup (char *str, int *ints)); +void __init arcrimi_setup (char *str, int *ints); extern struct device arcnet_devs[]; extern char arcnet_dev_names[][10]; extern int arcnet_num_devs; @@ -140,7 +140,7 @@ * them. In fact, we can't even get their node ID automatically. So, we * need to be passed a specific shmem address, IRQ, and node ID. */ -__initfunc(int arcrimi_probe(struct device *dev)) +int __init arcrimi_probe(struct device *dev) { BUGLVL(D_NORMAL) printk(version); BUGMSG(D_NORMAL,"Given: node %02Xh, shmem %lXh, irq %d\n", @@ -167,7 +167,7 @@ /* Set up the struct device associated with this card. Called after * probing succeeds. */ -__initfunc(int arcrimi_found(struct device *dev,int node,int airq, u_long shmem)) +int __init arcrimi_found(struct device *dev,int node,int airq, u_long shmem) { struct arcnet_local *lp; u_long first_mirror,last_mirror; @@ -797,7 +797,7 @@ #else -__initfunc(void arcrimi_setup (char *str, int *ints)) +void __init arcrimi_setup (char *str, int *ints) { struct device *dev; diff -u --recursive --new-file v2.3.9/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.3.9/linux/drivers/net/arcnet.c Tue May 25 13:06:34 1999 +++ linux/drivers/net/arcnet.c Tue Jul 6 19:05:49 1999 @@ -471,9 +471,16 @@ #ifdef CONFIG_ARCNET_1051 /* Initialize the RFC1051-encap protocol driver */ - lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL); + lp->sdev=(struct device *)kmalloc(sizeof(struct device)+10,GFP_KERNEL); + if(lp->sdev = NULL) + { + if(lp->edev) + kfree(lp->edev); + lp->edev=NULL; + return -ENOMEM; + } memcpy(lp->sdev,dev,sizeof(struct device)); - lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL); + lp->sdev->name=(char *)(lp+1); sprintf(lp->sdev->name,"%ss",dev->name); lp->sdev->init=arcnetS_init; register_netdevice(lp->sdev); @@ -562,7 +569,6 @@ /* free the RFC1051-encap protocol device */ lp->sdev->priv=NULL; unregister_netdevice(lp->sdev); - kfree(lp->sdev->name); kfree(lp->sdev); lp->sdev=NULL; #endif @@ -1991,7 +1997,7 @@ int arcnet_num_devs=0; char arcnet_dev_names[MAX_ARCNET_DEVS][10]; -__initfunc(void arcnet_init(void)) +void __init arcnet_init(void) { int c; @@ -2041,7 +2047,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(static int init_module(void)) +static int __init init_module(void) #endif { #ifdef ALPHA_WARNING diff -u --recursive --new-file v2.3.9/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.3.9/linux/drivers/net/ariadne.c Thu Feb 25 10:02:13 1999 +++ linux/drivers/net/ariadne.c Tue Jul 6 19:05:49 1999 @@ -146,7 +146,7 @@ } -__initfunc(int ariadne_probe(struct device *dev)) +int __init ariadne_probe(struct device *dev) { unsigned int key; const struct ConfigDev *cd; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c --- v2.3.9/linux/drivers/net/ariadne2.c Thu Jan 7 08:41:54 1999 +++ linux/drivers/net/ariadne2.c Tue Jul 6 19:05:49 1999 @@ -81,8 +81,7 @@ const unsigned char *buf, const int start_page); - -__initfunc(int ariadne2_probe(struct device *dev)) +int __init ariadne2_probe(struct device *dev) { unsigned int key; const struct ConfigDev *cd; @@ -101,8 +100,8 @@ return -ENODEV; } -__initfunc(static int ariadne2_init(struct device *dev, unsigned int key, - unsigned long board)) +static int __init ariadne2_init(struct device *dev, unsigned int key, + unsigned long board) { int i; unsigned char SA_prom[32]; diff -u --recursive --new-file v2.3.9/linux/drivers/net/arlan-proc.c linux/drivers/net/arlan-proc.c --- v2.3.9/linux/drivers/net/arlan-proc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arlan-proc.c Tue Jul 6 10:11:40 1999 @@ -0,0 +1,1059 @@ +#include +#include "arlan.h" + +#ifdef CONFIG_PROC_FS + + +#include +#include + +/* void enableReceive(struct device* dev); +*/ + +static int arlan_command(struct device * dev, int command); + + +#define ARLAN_STR_SIZE 0x2ff0 +#define DEV_ARLAN_INFO 1 +#define DEV_ARLAN 1 +#define SARLG(type,var) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var)); \ + } + +#define SARLBN(type,var,nn) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + pos += sprintf(arlan_drive_info+pos, "\n"); \ + } + +#define SARLBNpln(type,var,nn) {\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + } + +#define SARLSTR(var,nn) {\ + char tmpStr[400];\ + int tmpLn = nn;\ + if (nn > 399 ) tmpLn = 399; \ + memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\ + tmpStr[tmpLn] = 0; \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\ + } + +#define SARLUC(var) SARLG(u_char, var) +#define SARLUCN(var,nn) SARLBN(u_char,var, nn) +#define SARLUS(var) SARLG(u_short, var) +#define SARLUSN(var,nn) SARLBN(u_short,var, nn) +#define SARLUI(var) SARLG(u_int, var) + +#define SARLUSA(var) {\ + u_short tmpVar;\ + memcpy(&tmpVar, (short *) priva->conf->var,2); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + +#define SARLUIA(var) {\ + u_int tmpVar;\ + memcpy(&tmpVar, (int* )priva->conf->var,4); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + + +const char *arlan_diagnostic_info_string(struct device *dev) +{ + + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + u_char diagnosticInfo; + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + + switch (diagnosticInfo) + { + case 0xFF: + return "Diagnostic info is OK"; + case 0xFE: + return "ERROR EPROM Checksum error "; + case 0xFD: + return "ERROR Local Ram Test Failed "; + case 0xFC: + return "ERROR SCC failure "; + case 0xFB: + return "ERROR BackBone failure "; + case 0xFA: + return "ERROR tranceiver not found "; + case 0xF9: + return "ERROR no more address space "; + case 0xF8: + return "ERROR Checksum error "; + case 0xF7: + return "ERROR Missing SS Code"; + case 0xF6: + return "ERROR Invalid config format"; + case 0xF5: + return "ERROR Reserved errorcode F5"; + case 0xF4: + return "ERROR Invalid spreading code/channel number"; + case 0xF3: + return "ERROR Load Code Error"; + case 0xF2: + return "ERROR Reserver errorcode F2 "; + case 0xF1: + return "ERROR Invalid command receivec by LAN card "; + case 0xF0: + return "ERROR Invalid parameter found in command "; + case 0xEF: + return "ERROR On-chip timer failure "; + case 0xEE: + return "ERROR T410 timer failure "; + case 0xED: + return "ERROR Too Many TxEnable commands "; + case 0xEC: + return "ERROR EEPROM error on radio module "; + default: + return "ERROR unknown Diagnostic info reply code "; + } +}; + +static const char *arlan_hardware_type_string(struct device *dev) +{ + u_char hardwareType; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + READSHM(hardwareType, arlan->hardwareType, u_char); + switch (hardwareType) + { + case 0x00: + return "type A450"; + case 0x01: + return "type A650 "; + case 0x04: + return "type TMA coproc"; + case 0x0D: + return "type A650E "; + case 0x18: + return "type TMA coproc Australian"; + case 0x19: + return "type A650A "; + case 0x26: + return "type TMA coproc European"; + case 0x2E: + return "type A655 "; + case 0x2F: + return "type A655A "; + case 0x30: + return "type A655E "; + case 0x0B: + return "type A670 "; + case 0x0C: + return "type A670E "; + case 0x2D: + return "type A670A "; + case 0x0F: + return "type A411T"; + case 0x16: + return "type A411TA"; + case 0x1B: + return "type A440T"; + case 0x1C: + return "type A412T"; + case 0x1E: + return "type A412TA"; + case 0x22: + return "type A411TE"; + case 0x24: + return "type A412TE"; + case 0x27: + return "type A671T "; + case 0x29: + return "type A671TA "; + case 0x2B: + return "type A671TE "; + case 0x31: + return "type A415T "; + case 0x33: + return "type A415TA "; + case 0x35: + return "type A415TE "; + case 0x37: + return "type A672"; + case 0x39: + return "type A672A "; + case 0x3B: + return "type A672T"; + case 0x6B: + return "type IC2200"; + default: + return "type A672T"; + } +} + +static void arlan_print_diagnostic_info(struct device *dev) +{ + int i; + u_char diagnosticInfo; + u_short diagnosticOffset; + u_char hardwareType; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + // ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info"); + + if (READSHMB(arlan->configuredStatusFlag) == 0) + printk("Arlan: Card NOT configured\n"); + else + printk("Arlan: Card is configured\n"); + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short); + + printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev)); + + if (diagnosticInfo != 0xff) + printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset); + + printk("arlan: LAN CODE ID = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char); + printk("\n"); + + printk("arlan: Arlan BroadCast address = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char); + printk("\n"); + + READSHM(hardwareType, arlan->hardwareType, u_char); + printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev)); + + + DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char); + DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char); + DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char); + DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short); + DEBUGSHM(1, "arlan: SID =%d\n", arlan->SID, u_short); + DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short); + + DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char); + + printk("arlan: name= "); + IFDEBUG(1) + + for (i = 0; i < 16; i++) + { + char c; + READSHM(c, arlan->name[i], char); + if (c) + printk("%c", c); + } + printk("\n"); + +// ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info"); + +} + + +/****************************** TEST MEMORY **************/ + +static int arlan_hw_test_memory(struct device *dev) +{ + u_char *ptr; + int i; + int memlen = sizeof(struct arlan_shmem) - 0xF; /* avoid control register */ + volatile char *arlan_mem = (char *) (dev->mem_start); + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + char pattern; + + ptr = NULL; + + /* hold card in reset state */ + setHardwareReset(dev); + + /* test memory */ + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != pattern++) + { + printk(KERN_ERR "Arlan driver memory test 1 failed \n"); + return -1; + } + } + + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ~(pattern++), char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != ~(pattern++)) + { + printk(KERN_ERR "Arlan driver memory test 2 failed \n"); + return -1; + } + } + + /* zero memory */ + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], 0x00, char); + + IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n"); + + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + + clearChannelAttention(dev); + clearHardwareReset(dev); + + /* wait for reset flag to become zero, we'll wait for two seconds */ + if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW)) + { + printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name); + return -1; + } + return 0; +} + + +static int arlan_setup_card_by_book(struct device *dev) +{ + u_char irqLevel, configuredStatusFlag; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + +// ARLAN_DEBUG_ENTRY("arlan_setup_card"); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + + IFDEBUG(10) + if (configuredStatusFlag != 0) + IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n"); + else + IFDEBUG(10) printk("arlan: card is NOT configured\n"); + + if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff)) + if (arlan_hw_test_memory(dev)) + return -1; + + DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); + DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); + + /* issue nop command - no interupt */ + arlan_command(dev, ARLAN_COMMAND_NOOP); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + IFDEBUG(50) printk("1st Noop successfully executed !!\n"); + + /* try to turn on the arlan interrupts */ + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + + /* issue nop command - with interrupt */ + + arlan_command(dev, ARLAN_COMMAND_NOOPINT); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + + IFDEBUG(50) printk("2nd Noop successfully executed !!\n"); + + READSHM(irqLevel, arlan->irqLevel, u_char) + + if (irqLevel != dev->irq) + { + IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel); + printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq); + dev->irq = irqLevel; + } + else + IFDEBUG(2) printk("irq level is OK\n"); + + + IFDEBUG(3) arlan_print_diagnostic_info(dev); + + arlan_command(dev, ARLAN_COMMAND_CONF); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + if (configuredStatusFlag == 0) + { + printk(KERN_WARNING "arlan configure failed\n"); + return -1; + } + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + arlan_command(dev, ARLAN_COMMAND_RX); + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + printk(KERN_NOTICE "%s: arlan driver version %s loaded\n", + dev->name, arlan_version); + +// ARLAN_DEBUG_EXIT("arlan_setup_card"); + + return 0; /* no errors */ +} + + +#ifdef ARLAN_PROC_INTERFACE +#ifdef ARLAN_PROC_SHM_DUMP + +static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0"; + +static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + struct device *dev; + pos = 0; + if (write) + { + printk("wrirte: "); + for (i = 0; i < 100; i++) + printk("adi %x \n", arlan_drive_info[i]); + } + if (ctl->procname == NULL || arlan_drive_info == NULL) + { + printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n "); + return -1; + } + devnum = ctl->procname[5] - '0'; + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] == NULL) + { + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname); + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + dev = arlan_device[devnum]; + + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + + pos = sprintf(arlan_drive_info, "Arlan info \n"); + /* Header Signature */ + SARLSTR(textRegion, 48); + SARLUC(resetFlag); + pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev)); + SARLUC(diagnosticInfo); + SARLUS(diagnosticOffset); + SARLUCN(_1, 12); + SARLUCN(lanCardNodeId, 6); + SARLUCN(broadcastAddress, 6); + pos += sprintf(arlan_drive_info + pos, "hardwareType =\t %s \n", arlan_hardware_type_string(dev)); + SARLUC(hardwareType); + SARLUC(majorHardwareVersion); + SARLUC(minorHardwareVersion); + SARLUC(radioModule); + SARLUC(defaultChannelSet); + SARLUCN(_2, 47); + + /* Control/Status Block - 0x0080 */ + SARLUC(interruptInProgress); + SARLUC(cntrlRegImage); + + SARLUCN(_3, 14); + SARLUC(commandByte); + SARLUCN(commandParameter, 15); + + /* Receive Status - 0x00a0 */ + SARLUC(rxStatus); + SARLUC(rxFrmType); + SARLUS(rxOffset); + SARLUS(rxLength); + SARLUCN(rxSrc, 6); + SARLUC(rxBroadcastFlag); + SARLUC(rxQuality); + SARLUC(scrambled); + SARLUCN(_4, 1); + + /* Transmit Status - 0x00b0 */ + SARLUC(txStatus); + SARLUC(txAckQuality); + SARLUC(numRetries); + SARLUCN(_5, 14); + SARLUCN(registeredRouter, 6); + SARLUCN(backboneRouter, 6); + SARLUC(registrationStatus); + SARLUC(configuredStatusFlag); + SARLUCN(_6, 1); + SARLUCN(ultimateDestAddress, 6); + SARLUCN(immedDestAddress, 6); + SARLUCN(immedSrcAddress, 6); + SARLUS(rxSequenceNumber); + SARLUC(assignedLocaltalkAddress); + SARLUCN(_7, 27); + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + SARLUS(txTimeout); + SARLUS(transportTime); + SARLUCN(_8, 4); + + /* - Configuration Parameters */ + SARLUC(irqLevel); + SARLUC(spreadingCode); + SARLUC(channelSet); + SARLUC(channelNumber); + SARLUS(radioNodeId); + SARLUCN(_9, 2); + SARLUC(scramblingDisable); + SARLUC(radioType); + SARLUS(routerId); + SARLUCN(_10, 9); + SARLUC(txAttenuation); + SARLUIA(systemId); + SARLUS(globalChecksum); + SARLUCN(_11, 4); + SARLUS(maxDatagramSize); + SARLUS(maxFrameSize); + SARLUC(maxRetries); + SARLUC(receiveMode); + SARLUC(priority); + SARLUC(rootOrRepeater); + SARLUCN(specifiedRouter, 6); + SARLUS(fastPollPeriod); + SARLUC(pollDecay); + SARLUSA(fastPollDelay); + SARLUC(arlThreshold); + SARLUC(arlDecay); + SARLUCN(_12, 1); + SARLUS(specRouterTimeout); + SARLUCN(_13, 5); + + /* Scrambled Area */ + SARLUIA(SID); + SARLUCN(encryptionKey, 12); + SARLUIA(_14); + SARLUSA(waitTime); + SARLUSA(lParameter); + SARLUCN(_15, 3); + SARLUS(headerSize); + SARLUS(sectionChecksum); + + SARLUC(registrationMode); + SARLUC(registrationFill); + SARLUS(pollPeriod); + SARLUS(refreshPeriod); + SARLSTR(name, 16); + SARLUCN(NID, 6); + SARLUC(localTalkAddress); + SARLUC(codeFormat); + SARLUC(numChannels); + SARLUC(channel1); + SARLUC(channel2); + SARLUC(channel3); + SARLUC(channel4); + SARLUCN(SSCode, 59); + +/* SARLUCN( _16, 0x140); + */ + /* Statistics Block - 0x0300 */ + SARLUC(hostcpuLock); + SARLUC(lancpuLock); + SARLUCN(resetTime, 18); + SARLUIA(numDatagramsTransmitted); + SARLUIA(numReTransmissions); + SARLUIA(numFramesDiscarded); + SARLUIA(numDatagramsReceived); + SARLUIA(numDuplicateReceivedFrames); + SARLUIA(numDatagramsDiscarded); + SARLUS(maxNumReTransmitDatagram); + SARLUS(maxNumReTransmitFrames); + SARLUS(maxNumConsecutiveDuplicateFrames); + /* misaligned here so we have to go to characters */ + SARLUIA(numBytesTransmitted); + SARLUIA(numBytesReceived); + SARLUIA(numCRCErrors); + SARLUIA(numLengthErrors); + SARLUIA(numAbortErrors); + SARLUIA(numTXUnderruns); + SARLUIA(numRXOverruns); + SARLUIA(numHoldOffs); + SARLUIA(numFramesTransmitted); + SARLUIA(numFramesReceived); + SARLUIA(numReceiveFramesLost); + SARLUIA(numRXBufferOverflows); + SARLUIA(numFramesDiscardedAddrMismatch); + SARLUIA(numFramesDiscardedSIDMismatch); + SARLUIA(numPollsTransmistted); + SARLUIA(numPollAcknowledges); + SARLUIA(numStatusTimeouts); + SARLUIA(numNACKReceived); + SARLUS(auxCmd); + SARLUCN(dumpPtr, 4); + SARLUC(dumpVal); + SARLUC(wireTest); + + /* next 4 seems too long for procfs, over single page ? + SARLUCN( _17, 0x86); + SARLUCN( txBuffer, 0x800); + SARLUCN( rxBuffer, 0x800); + SARLUCN( _18, 0x0bff); + */ + + pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x"); + for (i = 0; i < 0x50; i++) + pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]); + pos += sprintf(arlan_drive_info + pos, "\n"); + + SARLUC(configStatus); + SARLUC(_22); + SARLUC(progIOCtrl); + SARLUC(shareMBase); + SARLUC(controlRegister); + + pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos); + if (ctl) + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname); +final: + *lenp = pos; + + if (!write) + retv = proc_dostring(ctl, write, filp, buffer, lenp); + else + { + *lenp = 0; + return -1; + } + return retv; +} + + +static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLUCN(_16, 0xC0); + SARLUCN(_17, 0x6A); + SARLUCN(_18, 14); + SARLUCN(_19, 0x86); + SARLUCN(_21, 0x3fd); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, txBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, rxBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, _18, 0x800); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + + +#endif /* #ifdef ARLAN_PROC_SHM_DUMP */ + + +static char conf_reset_result[200]; + +static int arlan_configure(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int pos = 0; + int devnum = ctl->procname[6] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = arlan_device[devnum]->priv; + + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); + } + else + return -1; + + *lenp = pos; + return proc_dostring(ctl, write, filp, buffer, lenp); +} + +int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int pos = 0; + int devnum = ctl->procname[5] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = arlan_device[devnum]->priv; + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); + + } else + return -1; + *lenp = pos + 3; + return proc_dostring(ctl, write, filp, buffer, lenp); +} + + +/* Place files in /proc/sys/dev/arlan */ +#define CTBLN(num,card,nam) \ + {num , #nam, &(arlan_conf[card].nam), \ + sizeof(int), 0600, NULL, &proc_dointvec} + + +#define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\ + CTBLN(1,cardNo,spreadingCode),\ + CTBLN(2,cardNo, channelNumber),\ + CTBLN(3,cardNo, scramblingDisable),\ + CTBLN(4,cardNo, txAttenuation),\ + CTBLN(5,cardNo, systemId), \ + CTBLN(6,cardNo, maxDatagramSize),\ + CTBLN(7,cardNo, maxFrameSize),\ + CTBLN(8,cardNo, maxRetries),\ + CTBLN(9,cardNo, receiveMode),\ + CTBLN(10,cardNo, priority),\ + CTBLN(11,cardNo, rootOrRepeater),\ + CTBLN(12,cardNo, SID),\ + CTBLN(13,cardNo, registrationMode),\ + CTBLN(14,cardNo, registrationFill),\ + CTBLN(15,cardNo, localTalkAddress),\ + CTBLN(16,cardNo, codeFormat),\ + CTBLN(17,cardNo, numChannels),\ + CTBLN(18,cardNo, channel1),\ + CTBLN(19,cardNo, channel2),\ + CTBLN(20,cardNo, channel3),\ + CTBLN(21,cardNo, channel4),\ + CTBLN(22,cardNo, txClear),\ + CTBLN(23,cardNo, txRetries),\ + CTBLN(24,cardNo, txRouting),\ + CTBLN(25,cardNo, txScrambled),\ + CTBLN(26,cardNo, rxParameter),\ + CTBLN(27,cardNo, txTimeoutMs),\ + CTBLN(28,cardNo, waitCardTimeout),\ + CTBLN(29,cardNo, channelSet), \ + {30, "name", arlan_conf[cardNo].siteName, \ + 16, 0600, NULL, &proc_dostring},\ + CTBLN(31,cardNo,waitTime),\ + CTBLN(32,cardNo,lParameter),\ + CTBLN(33,cardNo,_15),\ + CTBLN(34,cardNo,headerSize),\ + CTBLN(35,cardNo,async),\ + CTBLN(36,cardNo,tx_delay_ms),\ + CTBLN(37,cardNo,retries),\ + CTBLN(38,cardNo,ReTransmitPacketMaxSize),\ + CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\ + CTBLN(40,cardNo,fastReTransCount),\ + CTBLN(41,cardNo,driverRetransmissions),\ + CTBLN(42,cardNo,txAckTimeoutMs),\ + CTBLN(43,cardNo,registrationInterrupts),\ + CTBLN(44,cardNo,hardwareType),\ + CTBLN(45,cardNo,radioType),\ + CTBLN(46,cardNo,writeEEPROM),\ + CTBLN(47,cardNo,writeRadioType),\ + {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec},\ + {49, "debug", &arlan_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec},\ + CTBLN(50,cardNo,in_speed),\ + CTBLN(51,cardNo,out_speed),\ + CTBLN(52,cardNo,in_speed10),\ + CTBLN(53,cardNo,out_speed10),\ + CTBLN(54,cardNo,in_speed_max),\ + CTBLN(55,cardNo,out_speed_max),\ + CTBLN(56,cardNo,measure_rate),\ + CTBLN(57,cardNo,pre_Command_Wait),\ + CTBLN(58,cardNo,rx_tweak1),\ + CTBLN(59,cardNo,rx_tweak2),\ + CTBLN(60,cardNo,tx_queue_len),\ + + + +static ctl_table arlan_conf_table0[] = +{ + ARLAN_SYSCTL_TABLE_TOTAL(0) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan0-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan0-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan0-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan0-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan0-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config0", &conf_reset_result, \ + 100, 0400, NULL, &arlan_configure}, \ + {156, "reset0", &conf_reset_result, \ + 100, 0400, NULL, &arlan_sysctl_reset}, \ + {0} +}; + +static ctl_table arlan_conf_table1[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(1) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan1-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan1-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan1-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan1-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan1-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config1", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset1", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + +static ctl_table arlan_conf_table2[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(2) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan2-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan2-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan2-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan2-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan2-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config2", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset2", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + +static ctl_table arlan_conf_table3[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(3) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan3-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan3-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan3-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan3-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan3-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config3", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset3", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + + + +static ctl_table arlan_table[] = +{ + {0, "arlan0", NULL, 0, 0600, arlan_conf_table0}, + {0, "arlan1", NULL, 0, 0600, arlan_conf_table1}, + {0, "arlan2", NULL, 0, 0600, arlan_conf_table2}, + {0, "arlan3", NULL, 0, 0600, arlan_conf_table3}, + {0} +}; + +#else + +static ctl_table arlan_table[MAX_ARLANS + 1] = +{ + {0} +}; +#endif +#endif + +static int mmtu = 1234; + +static ctl_table arlan_root_table[] = +{ + {254, "arlan", NULL, 0, 0555, arlan_table}, + {0} +}; + +/* Make sure that /proc/sys/dev is there */ +static ctl_table arlan_device_root_table[] = +{ + {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, + {0} +}; + + + +static struct ctl_table_header *arlan_device_sysctl_header = NULL; + +int init_arlan_proc(void) +{ + + int i = 0; + if (arlan_device_sysctl_header) + return 0; + for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++) + arlan_table[i].ctl_name = i + 1; + arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0); + if (!arlan_device_sysctl_header) + return -1; + + return 0; + +}; + + + +#ifdef MODULE + +int init_module(void) +{ + + return init_arlan_proc(); +}; + +void cleanup_module(void) +{ + unregister_sysctl_table(arlan_device_sysctl_header); + arlan_device_sysctl_header = NULL; + + return; +}; + +#endif // MODULE diff -u --recursive --new-file v2.3.9/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.3.9/linux/drivers/net/arlan.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arlan.c Tue Jul 6 10:11:40 1999 @@ -0,0 +1,2079 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * Gnu Public License applies + * This module provides support for the Arlan 655 card made by Aironet + */ + +#include +#include "arlan.h" + +static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; + +struct device *arlan_device[MAX_ARLANS]; +int last_arlan = 0; + +static int SID = SIDUNKNOWN; +static int radioNodeId = radioNodeIdUNKNOWN; +static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; +static char *siteName = siteNameUNKNOWN; +static int irq = irqUNKNOWN; +static int mem = memUNKNOWN; +static int arlan_debug = debugUNKNOWN; +static int probe = probeUNKNOWN; +static int numDevices = numDevicesUNKNOWN; +static int testMemory = testMemoryUNKNOWN; +static int spreadingCode = spreadingCodeUNKNOWN; +static int channelNumber = channelNumberUNKNOWN; +static int channelSet = channelSetUNKNOWN; +static int systemId = systemIdUNKNOWN; +static int registrationMode = registrationModeUNKNOWN; +static int txScrambled = 1; +static int keyStart = 0; +static int mdebug = 0; +static int tx_delay_ms = 0; +static int retries = 5; +static int async = 1; +static int tx_queue_len = 1; +static int arlan_entry_debug = 0; +static int arlan_exit_debug = 0; +static int arlan_entry_and_exit_debug = 0; +static int arlan_EEPROM_bad = 0; + +#if LINUX_VERSION_CODE > 0x20100 +MODULE_PARM(irq, "i"); +MODULE_PARM(mem, "i"); +MODULE_PARM(probe, "i"); +MODULE_PARM(arlan_debug, "i"); +MODULE_PARM(numDevices, "i"); +MODULE_PARM(testMemory, "i"); +MODULE_PARM(spreadingCode, "i"); +MODULE_PARM(channelNumber, "i"); +MODULE_PARM(channelSet, "i"); +MODULE_PARM(systemId, "i"); +MODULE_PARM(registrationMode, "i"); +MODULE_PARM(radioNodeId, "i"); +MODULE_PARM(SID, "i"); +MODULE_PARM(txScrambled, "i"); +MODULE_PARM(keyStart, "i"); +MODULE_PARM(mdebug, "i"); +MODULE_PARM(tx_delay_ms, "i"); +MODULE_PARM(retries, "i"); +MODULE_PARM(async, "i"); +MODULE_PARM(tx_queue_len, "i"); +MODULE_PARM(arlan_entry_debug, "i"); +MODULE_PARM(arlan_exit_debug, "i"); +MODULE_PARM(arlan_entry_and_exit_debug, "i"); +MODULE_PARM(arlan_EEPROM_bad, "i"); + +EXPORT_SYMBOL(arlan_device); +EXPORT_SYMBOL(last_arlan); + + +// #warning kernel 2.1.110 tested +#define myATOMIC_INIT(a,b) atomic_set(&(a),b) +#define __initfunctio(a) __initfunc(a) + +#else +#define test_and_set_bit set_bit +#define __initfunctio(a) a +#if LINUX_VERSION_CODE != 0x20024 + // #warning kernel 2.0.36 tested +#endif +#define myATOMIC_INIT(a,b) a = b; + +#endif + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; +int arlans_found = 0; + +static int arlan_probe_here(struct device *dev, int ioaddr); +static int arlan_open(struct device *dev); +static int arlan_tx(struct sk_buff *skb, struct device *dev); +static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int arlan_close(struct device *dev); +static struct enet_statistics * + arlan_statistics (struct device *dev); +static void arlan_set_multicast (struct device *dev); +static int arlan_hw_tx (struct device* dev, char *buf, int length ); +static int arlan_hw_config (struct device * dev); +static void arlan_tx_done_interrupt (struct device * dev, int status); +static void arlan_rx_interrupt (struct device * dev, u_char rxStatus, u_short, u_short); +static void arlan_process_interrupt (struct device * dev); +static int arlan_command(struct device * dev, int command); + +EXPORT_SYMBOL(arlan_command); + +extern inline long long arlan_time(void) +{ + struct timeval timev; + do_gettimeofday(&timev); + return ((long long) timev.tv_sec * 1000000 + timev.tv_usec); +}; + +#ifdef ARLAN_ENTRY_EXIT_DEBUGING +#define ARLAN_DEBUG_ENTRY(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_entry_debug || arlan_entry_and_exit_debug)\ + printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\ + } +#define ARLAN_DEBUG_EXIT(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_exit_debug || arlan_entry_and_exit_debug)\ + printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\ + } +#else +#define ARLAN_DEBUG_ENTRY(name) +#define ARLAN_DEBUG_EXIT(name) +#endif + + +#define arlan_interrupt_ack(dev)\ + clearClearInterrupt(dev);\ + setClearInterrupt(dev); + + +#define ARLAN_COMMAND_LOCK(dev) \ + if (atomic_dec_and_test(&((struct arlan_private * )dev->priv)->card_users))\ + arlan_wait_command_complete_short(dev,__LINE__); +#define ARLAN_COMMAND_UNLOCK(dev) \ + atomic_inc(&((struct arlan_private * )dev->priv)->card_users); + + +#define ARLAN_COMMAND_INC(dev) \ + {((struct arlan_private *) dev->priv)->under_command++;} +#define ARLAN_COMMAND_ZERO(dev) \ + {((struct arlan_private *) dev->priv)->under_command =0;} +#define ARLAN_UNDER_COMMAND(dev)\ + (((struct arlan_private *) dev->priv)->under_command) + +#define ARLAN_COMMAND_START(dev) ARLAN_COMMAND_INC(dev) +#define ARLAN_COMMAND_END(dev) ARLAN_COMMAND_ZERO(dev) +#define ARLAN_TOGGLE_START(dev)\ + {((struct arlan_private *) dev->priv)->under_toggle++;} +#define ARLAN_TOGGLE_END(dev)\ + {((struct arlan_private *) dev->priv)->under_toggle=0;} +#define ARLAN_UNDER_TOGGLE(dev)\ + (((struct arlan_private *) dev->priv)->under_toggle) + + + +extern inline int arlan_drop_tx(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + priv->stats.tx_errors++; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; + } + else + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + TXHEAD(dev).offset = 0; + TXTAIL(dev).offset = 0; + priv->txLast = 0; + priv->txOffset = 0; + priv->bad = 0; + if (!priv->under_reset && !priv->under_config) + { + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + return 1; +}; + + +static int arlan_command(struct device *dev, int command_p) +{ + + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + int udelayed = 0; + int i = 0; + long long time_mks = arlan_time(); + + ARLAN_DEBUG_ENTRY("arlan_command"); + + if (priv->card_polling_interval) + priv->card_polling_interval = 1; + + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_DEBUG "arlan_command, %lx lock %x commandByte %x waiting %x incoming %x \n", + jiffies, priv->command_lock, READSHMB(arlan->commandByte), + priv->waiting_command_mask, command_p); + + priv->waiting_command_mask |= command_p; + + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + if (jiffies - priv->lastReset < 5 * HZ) + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK) + { + arlan_interrupt_ack(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK; + } + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE; + } + + /* Card access serializing lock */ + + if (test_and_set_bit(0, (void *) &priv->command_lock)) + { + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_DEBUG "arlan_command: entered when command locked \n"); + goto command_busy_end; + } + /* Check cards status and waiting */ + + if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + if (READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) /* || + (readControlRegister(dev) & ARLAN_ACCESS)) + */ + udelay(40); + else + priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW); + + udelayed++; + + if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW) + { + if (udelayed * 40 > 1000000) + { + printk(KERN_ERR "%s long wait too long \n", dev->name); + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + break; + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW) + { + if (udelayed * 40 > 1000) + { + printk(KERN_ERR "%s short wait too long \n", dev->name); + goto bad_end; + } + } + } + } + else + { + i = 0; + while ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + conf->pre_Command_Wait > (i++) * 10) + udelay(10); + + + if ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + !(priv->waiting_command_mask & ARLAN_COMMAND_RESET)) + { + goto card_busy_end; + } + } + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + { + priv->under_reset = 1; + dev->start = 0; + } + if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + { + priv->under_config = 1; + dev->start = 0; + } + + /* Issuing command */ + arlan_lock_card_access(dev); + if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP) + { + // if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER)) + setPowerOn(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP; + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT) + { + if (priv->rx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT); + arlan_interrupt_lancpu(dev); + priv->rx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT) + { + if (priv->tx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT); + arlan_interrupt_lancpu(dev); + priv->tx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + { + arlan_drop_tx(dev); + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + }; + if (arlan_debug & ARLAN_DEBUG_RESET) + printk(KERN_ERR "%s: Doing chip reset\n", dev->name); + priv->lastReset = jiffies; + WRITESHM(arlan->commandByte, 0, u_char); + /* hold card in reset state */ + setHardwareReset(dev); + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + clearChannelAttention(dev); + clearHardwareReset(dev); + priv->numResets++; + priv->card_polling_interval = HZ / 4; + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; +// priv->waiting_command_mask |= ARLAN_COMMAND_RX; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK) + { + clearHardwareReset(dev); + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF; + priv->under_config = 1; + priv->under_reset = 0; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + { + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + } + dev->start = 0; + arlan_drop_tx(dev); + setInterruptEnable(dev); + arlan_hw_config(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF; + priv->card_polling_interval = HZ / 10; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT) + { + if (READSHMB(arlan->configuredStatusFlag) != 0 && + READSHMB(arlan->diagnosticInfo) == 0xff) + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; + priv->waiting_command_mask |= ARLAN_COMMAND_RX; + priv->card_polling_interval = HZ / 10; + priv->tx_command_given = 0; + priv->under_config = 0; + if (dev->tbusy || !dev->start) + { + dev->tbusy = 0; + dev->start = 1; + mark_bh(NET_BH); + }; + } + else + { + priv->card_polling_interval = 1; + if (arlan_debug & ARLAN_DEBUG_TIMING) + printk(KERN_ERR "configure delayed \n"); + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX) + { + if (!registrationBad(dev)) + { + setInterruptEnable(dev); + memset_io((void *) arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); + WRITESHMB(arlan->commandParameter[0], conf->rxParameter); + arlan_interrupt_lancpu(dev); + priv->rx_command_given; + priv->last_rx_time = arlan_time(); + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; + priv->card_polling_interval = 1; + } + else + priv->card_polling_interval = 2; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) + { + if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) + { + if ((time_mks - priv->last_tx_time > conf->rx_tweak1) || + (time_mks - priv->last_rx_int_ack_time < conf->rx_tweak2)) + { + setInterruptEnable(dev); + memset_io((void *) arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT); + memcpy_toio((void *) arlan->commandParameter, &TXLAST(dev), 14); +// for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i])); + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies; + arlan_interrupt_lancpu(dev); + priv->last_tx_time = arlan_time(); + priv->tx_command_given = 1; + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + priv->card_polling_interval = 1; + } + else + { + priv->tx_command_given = 0; + priv->card_polling_interval = 1; + } + } + else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "tx command when tx chain locked \n"); + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT) + { + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT); + } + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN) + { + setPowerOff(dev); + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN; + priv->card_polling_interval = 3 * HZ; + } + arlan_unlock_card_access(dev); + for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++) + udelay(10); + if (READSHMB(arlan->commandByte)) + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "card busy leaving command %x \n", priv->waiting_command_mask); + + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + priv->last_command_buff_free_time = jiffies; + return 0; + +card_busy_end: + if (jiffies - priv->last_command_buff_free_time > HZ) + priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET; + + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "%s arlan_command card busy end \n", dev->name); + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + return 1; + +bad_end: + printk(KERN_ERR "%s arlan_command bad end \n", dev->name); + + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + + return -1; + +command_busy_end: + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "%s arlan_command command busy end \n", dev->name); + ARLAN_DEBUG_EXIT("arlan_command"); + return 2; + +}; + +extern inline void arlan_command_process(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + int times = 0; + while (priv->waiting_command_mask && times < 8) + { + if (priv->waiting_command_mask) + { + if (arlan_command(dev, 0)) + break; + times++; + } + /* if long command, we wont repeat trying */ ; + if (priv->card_polling_interval > 1) + break; + times++; + } +} + + +extern inline void arlan_retransmit_now(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + + ARLAN_DEBUG_ENTRY("arlan_retransmit_now"); + if (TXLAST(dev).offset == 0) + { + if (TXHEAD(dev).offset) + { + priv->txLast = 0; + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n"); + + } + else if (TXTAIL(dev).offset) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n"); + priv->txLast = 1; + } + else + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty"); + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + return; + + } + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->nof_tx++; + + priv->Conf->driverRetransmissions++; + priv->retransmissions++; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length); + + ARLAN_DEBUG_EXIT("arlan_retransmit_now"); +} + + + +static void arlan_registration_timer(unsigned long data) +{ + struct device *dev = (struct device *) data; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + int lostTime = ((int) (jiffies - priv->registrationLastSeen)) * 1000 / HZ; + int bh_mark_needed = 0; + int next_tick = 1; + + + priv->timer_chain_active = 1; + + + if (registrationBad(dev)) + { + //debug=100; + priv->registrationLostCount++; + if (lostTime > 7000 && lostTime < 7200) + { + printk(KERN_NOTICE "%s registration Lost \n", dev->name); + } + if (lostTime / priv->reRegisterExp > 2000) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + if (lostTime / (priv->reRegisterExp) > 3500) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + if (priv->reRegisterExp < 400) + priv->reRegisterExp += 2; + if (lostTime > 7200) + { + next_tick = HZ; + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + } + } + else + { + if (priv->Conf->registrationMode && lostTime > 10000 && + priv->registrationLostCount) + { + printk(KERN_NOTICE "%s registration is back after %d milliseconds\n", dev->name, + ((int) (jiffies - priv->registrationLastSeen) * 1000) / HZ); + } + priv->registrationLastSeen = jiffies; + priv->registrationLostCount = 0; + priv->reRegisterExp = 1; + if (dev->start == 0) + { + dev->start = 1; + mark_bh(NET_BH); + } + } + + + if (!registrationBad(dev) && priv->ReTransmitRequested) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "Retranmit from timer \n"); + priv->ReTransmitRequested = 0; + arlan_retransmit_now(dev); + } + if (!registrationBad(dev) && + priv->tx_done_delayed < jiffies && + priv->tx_done_delayed != 0) + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!(TXHEAD(dev).offset && TXTAIL(dev).offset)) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + priv->tx_done_delayed = 0; + bh_mark_needed = 1; + } + if (bh_mark_needed) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + arlan_process_interrupt(dev); + + if (next_tick < priv->card_polling_interval) + next_tick = priv->card_polling_interval; + + priv->timer_chain_active = 0; + priv->timer.expires = jiffies + next_tick; + + add_timer(&priv->timer); +} + + + + +static void arlan_print_registers(struct device *dev, int line) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage, + txStatus, rxStatus, interruptInProgress, commandByte; + + + ARLAN_DEBUG_ENTRY("arlan_print_registers"); + READSHM(interruptInProgress, arlan->interruptInProgress, u_char); + READSHM(hostcpuLock, arlan->hostcpuLock, u_char); + READSHM(lancpuLock, arlan->lancpuLock, u_char); + READSHM(controlRegister, arlan->controlRegister, u_char); + READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char); + READSHM(txStatus, arlan->txStatus, u_char); + READSHM(rxStatus, arlan->rxStatus, u_char); + READSHM(commandByte, arlan->commandByte, u_char); + + printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n", + line, interruptInProgress, hostcpuLock, lancpuLock, commandByte, + controlRegister, cntrlRegImage, txStatus, rxStatus); + + ARLAN_DEBUG_EXIT("arlan_print_registers"); +} + + +static int arlan_hw_tx(struct device *dev, char *buf, int length) +{ + int i; + + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + int tailStarts = 0x800; + int headEnds = 0x0; + + + ARLAN_DEBUG_ENTRY("arlan_hw_tx"); + if (TXHEAD(dev).offset) + headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 1) * 64; + if (TXTAIL(dev).offset) + tailStarts = 0x800 - (((TXTAIL(dev).offset - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 2) * 64; + + + if (!TXHEAD(dev).offset && length < tailStarts) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts); + + TXHEAD(dev).offset = + (((int) arlan->txBuffer) - ((int) arlan)); + TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXHEAD(dev).dest[i] = buf[i]; + TXHEAD(dev).clear = conf->txClear; + TXHEAD(dev).retries = conf->txRetries; /* 0 is use default */ + TXHEAD(dev).routing = conf->txRouting; + TXHEAD(dev).scrambled = conf->txScrambled; + memcpy_toio(((char *) arlan + TXHEAD(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length); + } + else if (!TXTAIL(dev).offset && length < (0x800 - headEnds)) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds); + + TXTAIL(dev).offset = + (((int) arlan->txBuffer) - ((int) arlan)) + 0x800 - (length / 64 + 2) * 64; + TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXTAIL(dev).dest[i] = buf[i]; + TXTAIL(dev).clear = conf->txClear; + TXTAIL(dev).retries = conf->txRetries; + TXTAIL(dev).routing = conf->txRouting; + TXTAIL(dev).scrambled = conf->txScrambled; + memcpy_toio(((char *) arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length); + } + else + { + dev->tbusy = 1; + return -1; + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds); + } + priv->out_bytes += length; + priv->out_bytes10 += length; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (jiffies - priv->out_time > conf->measure_rate * HZ) + { + conf->out_speed = priv->out_bytes / conf->measure_rate; + priv->out_bytes = 0; + priv->out_time = jiffies; + } + if (jiffies - priv->out_time10 > conf->measure_rate * HZ * 10) + { + conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate); + priv->out_bytes10 = 0; + priv->out_time10 = jiffies; + } + if (TXHEAD(dev).offset && TXTAIL(dev).offset) + { + dev->tbusy = 1; + return 0; + } + else + dev->tbusy = 0; + + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, + (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3], + (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7], + (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]); + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast); + + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies; + priv->nof_tx++; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length); + + ARLAN_DEBUG_EXIT("arlan_hw_tx"); + + return 0; +} + + +static int arlan_hw_config(struct device *dev) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + ARLAN_DEBUG_ENTRY("arlan_hw_config"); + + printk(KERN_NOTICE "%s arlan configure called \n", dev->name); + if (arlan_EEPROM_bad) + printk(KERN_NOTICE "arlan configure with eeprom bad option \n"); + + + WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char); + WRITESHM(arlan->channelSet, conf->channelSet, u_char); + + if (arlan_EEPROM_bad) + WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char); + + WRITESHM(arlan->channelNumber, conf->channelNumber, u_char); + + WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char); + WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char); + + WRITESHM(arlan->systemId, conf->systemId, u_int); + + WRITESHM(arlan->maxRetries, conf->maxRetries, u_char); + WRITESHM(arlan->receiveMode, conf->receiveMode, u_char); + WRITESHM(arlan->priority, conf->priority, u_char); + WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char); + WRITESHM(arlan->SID, conf->SID, u_int); + + WRITESHM(arlan->registrationMode, conf->registrationMode, u_char); + + WRITESHM(arlan->registrationFill, conf->registrationFill, u_char); + WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char); + WRITESHM(arlan->codeFormat, conf->codeFormat, u_char); + WRITESHM(arlan->numChannels, conf->numChannels, u_char); + WRITESHM(arlan->channel1, conf->channel1, u_char); + WRITESHM(arlan->channel2, conf->channel2, u_char); + WRITESHM(arlan->channel3, conf->channel3, u_char); + WRITESHM(arlan->channel4, conf->channel4, u_char); + WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short); + WRITESHM(arlan->SID, conf->SID, u_int); + WRITESHM(arlan->waitTime, conf->waitTime, u_short); + WRITESHM(arlan->lParameter, conf->lParameter, u_short); + memcpy_toio(&(arlan->_15), &(conf->_15), 3); + WRITESHM(arlan->_15, conf->_15, u_short); + WRITESHM(arlan->headerSize, conf->headerSize, u_short); + if (arlan_EEPROM_bad) + WRITESHM(arlan->hardwareType, conf->hardwareType, u_char); + WRITESHM(arlan->radioType, conf->radioType, u_char); + if (arlan_EEPROM_bad) + WRITESHM(arlan->radioModule, conf->radioType, u_char); + + memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8); + memcpy_toio(arlan->name, conf->siteName, 16); + + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF); /* do configure */ + memset_io(arlan->commandParameter, 0, 0xf); /* 0xf */ + memset_io(arlan->commandParameter + 1, 0, 2); + if (conf->writeEEPROM) + { + memset_io(arlan->commandParameter, conf->writeEEPROM, 1); +// conf->writeEEPROM=0; + } + if (conf->registrationMode && conf->registrationInterrupts) + memset_io(arlan->commandParameter + 3, 1, 1); + else + memset_io(arlan->commandParameter + 3, 0, 1); + + priv->irq_test_done = 0; + + if (conf->tx_queue_len) + dev->tx_queue_len = conf->tx_queue_len; + udelay(100); + + ARLAN_DEBUG_EXIT("arlan_hw_config"); + return 0; +} + + +static int arlan_read_card_configuration(struct device *dev) +{ + u_char tlx415; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_read_card_configuration"); + + if (radioNodeId == radioNodeIdUNKNOWN) + { + READSHM(conf->radioNodeId, arlan->radioNodeId, u_short); + } + else + conf->radioNodeId = radioNodeId; + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (spreadingCode == spreadingCodeUNKNOWN) + { + READSHM(conf->spreadingCode, arlan->spreadingCode, u_char); + } + else + conf->spreadingCode = spreadingCode; + + if (channelSet == channelSetUNKNOWN) + { + READSHM(conf->channelSet, arlan->channelSet, u_char); + } + else conf->channelSet = channelSet; + + if (channelNumber == channelNumberUNKNOWN) + { + READSHM(conf->channelNumber, arlan->channelNumber, u_char); + } + else conf->channelNumber = channelNumber; + + READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char); + READSHM(conf->txAttenuation, arlan->txAttenuation, u_char); + + if (systemId == systemIdUNKNOWN) + { + READSHM(conf->systemId, arlan->systemId, u_int); + } + else conf->systemId = systemId; + + READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short); + READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short); + READSHM(conf->maxRetries, arlan->maxRetries, u_char); + READSHM(conf->receiveMode, arlan->receiveMode, u_char); + READSHM(conf->priority, arlan->priority, u_char); + READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char); + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (registrationMode == registrationModeUNKNOWN) + { + READSHM(conf->registrationMode, arlan->registrationMode, u_char); + } + else conf->registrationMode = registrationMode; + + READSHM(conf->registrationFill, arlan->registrationFill, u_char); + READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char); + READSHM(conf->codeFormat, arlan->codeFormat, u_char); + READSHM(conf->numChannels, arlan->numChannels, u_char); + READSHM(conf->channel1, arlan->channel1, u_char); + READSHM(conf->channel2, arlan->channel2, u_char); + READSHM(conf->channel3, arlan->channel3, u_char); + READSHM(conf->channel4, arlan->channel4, u_char); + READSHM(conf->waitTime, arlan->waitTime, u_short); + READSHM(conf->lParameter, arlan->lParameter, u_short); + READSHM(conf->_15, arlan->_15, u_short); + READSHM(conf->headerSize, arlan->headerSize, u_short); + READSHM(conf->hardwareType, arlan->hardwareType, u_char); + READSHM(conf->radioType, arlan->radioModule, u_char); + + if (conf->radioType == 0) + conf->radioType = 0xc; + + WRITESHM(arlan->configStatus, 0xA5, u_char); + READSHM(tlx415, arlan->configStatus, u_char); + + if (tlx415 != 0xA5) + printk(KERN_INFO "%s tlx415 chip \n", dev->name); + + conf->txClear = 0; + conf->txRetries = 1; + conf->txRouting = 1; + conf->txScrambled = 0; + conf->rxParameter = 1; + conf->txTimeoutMs = 4000; + conf->waitCardTimeout = 100000; + conf->receiveMode = ARLAN_RCV_CLEAN; + memcpy_fromio(conf->siteName, arlan->name, 16); + conf->siteName[16] = '\0'; + conf->retries = retries; + conf->tx_delay_ms = tx_delay_ms; + conf->async = async; + conf->ReTransmitPacketMaxSize = 200; + conf->waitReTransmitPacketMaxSize = 200; + conf->txAckTimeoutMs = 900; + conf->fastReTransCount = 3; + + ARLAN_DEBUG_EXIT("arlan_read_card_configuration"); + + return 0; +} + + +static int lastFoundAt = 0xbe000; + + +/* + * 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. + */ + +__initfunctio(static int arlan_check_fingerprint(int memaddr)) +{ + static char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; + char tempBuf[49]; + volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr; + + ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); + memcpy_fromio(tempBuf, arlan->textRegion, 29); + tempBuf[30] = 0; + + /* check for card at this address */ + if (0 != strncmp(tempBuf, probeText, 29)) + return -ENODEV; + +// printk(KERN_INFO "arlan found at 0x%x \n",memaddr); + ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); + + return 0; + + +} + +__initfunctio(int arlan_probe_everywhere(struct device *dev)) +{ + int m; + int probed = 0; + int found = 0; + + ARLAN_DEBUG_ENTRY("arlan_probe_everywhere"); + if (mem != 0 && numDevices == 1) /* Check a single specified location. */ + { + if (arlan_probe_here(dev, mem) == 0) + return 0; + else + return -ENODEV; + } + for (m = lastFoundAt + 0x2000; m <= 0xDE000; m += 0x2000) + { + if (arlan_probe_here(dev, m) == 0) + { + found++; + lastFoundAt = m; + break; + } + probed++; + } + if (found == 0 && probed != 0) + { + if (lastFoundAt == 0xbe000) + printk(KERN_ERR "arlan: No Arlan devices found \n"); + return ENODEV; + } + else + return 0; + + ARLAN_DEBUG_EXIT("arlan_probe_everywhere"); + + return ENODEV; +} + +__initfunctio(int arlan_find_devices(void)) +{ + int m; + int found = 0; + + ARLAN_DEBUG_ENTRY("arlan_find_devices"); + if (mem != 0 && numDevices == 1) /* Check a single specified location. */ + return 1; + for (m = 0xc000; m <= 0xDE000; m += 0x2000) + { + if (arlan_check_fingerprint(m) == 0) + found++; + } + ARLAN_DEBUG_EXIT("arlan_find_devices"); + + return found; +} + + +static int arlan_change_mtu(struct device *dev, int new_mtu) +{ + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_change_mtu"); + if ((new_mtu < 68) || (new_mtu > 2032)) + return -EINVAL; + dev->mtu = new_mtu; + if (new_mtu < 256) + new_mtu = 256; /* cards book suggests 1600 */ + conf->maxDatagramSize = new_mtu; + conf->maxFrameSize = new_mtu + 48; + + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu); + + ARLAN_DEBUG_EXIT("arlan_change_mtu"); + + return 0; +} + +static int arlan_mac_addr(struct device *dev, void *p) +{ + struct sockaddr *addr = p; + + + ARLAN_DEBUG_ENTRY("arlan_mac_addr"); + return -EINVAL; + + if (dev->start) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + ARLAN_DEBUG_EXIT("arlan_mac_addr"); + return 0; +} + + + + +__initfunctio(static int + arlan_allocate_device(int num, struct device *devs)) +{ + + struct device *dev; + + ARLAN_DEBUG_ENTRY("arlan_allocate_device"); + + if (!devs) + dev = init_etherdev(0, sizeof(struct arlan_private)); + else + { + dev = devs; + dev->priv = kmalloc(sizeof(struct arlan_private), GFP_KERNEL); + }; + + if (dev == NULL || dev->priv == NULL) + { + printk(KERN_CRIT "init_etherdev failed "); + return 0; + } + ((struct arlan_private *) dev->priv)->conf = + kmalloc(sizeof(struct arlan_shmem), GFP_KERNEL); + + if (dev == NULL || dev->priv == NULL || + ((struct arlan_private *) dev->priv)->conf == NULL) + { + return 0; + printk(KERN_CRIT " No memory at arlan_allocate_device \n"); + } + /* Fill in the 'dev' fields. */ + dev->base_addr = 0; + dev->mem_start = 0; + dev->mem_end = 0; + dev->mtu = 1500; + dev->flags = 0; /* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */ + dev->irq = 0; + dev->dma = 0; + dev->tx_queue_len = tx_queue_len; + ether_setup(dev); + dev->tx_queue_len = tx_queue_len; + dev->open = arlan_open; + dev->stop = arlan_close; + dev->hard_start_xmit = arlan_tx; + dev->get_stats = arlan_statistics; + dev->set_multicast_list = arlan_set_multicast; + dev->change_mtu = arlan_change_mtu; + dev->set_mac_address = arlan_mac_addr; + ((struct arlan_private *) dev->priv)->irq_test_done = 0; + arlan_device[num] = dev; + ((struct arlan_private *) arlan_device[num]->priv)->Conf = &(arlan_conf[num]); + + ((struct arlan_private *) dev->priv)->Conf->pre_Command_Wait = 40; + ((struct arlan_private *) dev->priv)->Conf->rx_tweak1 = 30; + ((struct arlan_private *) dev->priv)->Conf->rx_tweak2 = 0; + + ARLAN_DEBUG_EXIT("arlan_allocate_device"); + return (int) dev; +} + + +__initfunctio(int arlan_probe_here(struct device *dev, int memaddr)) +{ + volatile struct arlan_shmem *arlan; + + ARLAN_DEBUG_ENTRY("arlan_probe_here"); + + if (arlan_check_fingerprint(memaddr)) + return -ENODEV; + + printk(KERN_NOTICE "%s: Arlan found at %#5x, \n ", dev->name, memaddr); + + if (!arlan_allocate_device(arlans_found, dev)) + return -1; + + ((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr; + arlan = (void *) memaddr; + + dev->mem_start = memaddr; + dev->mem_end = memaddr + 0x1FFF; + + if (dev->irq < 2) + { + READSHM(dev->irq, arlan->irqLevel, u_char); + } else if (dev->irq == 2) + dev->irq = 9; + + arlan_read_card_configuration(dev); + + ARLAN_DEBUG_EXIT("arlan_probe_here"); + return 0; +} + + + + +static int arlan_open(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + int ret = 0; + + ARLAN_DEBUG_ENTRY("arlan_open"); + + if (dev->mem_start == 0) + ret = arlan_probe_everywhere(dev); + if (ret != 0) + return ret; + + arlan = ((struct arlan_private *) dev->priv)->card; + + if (request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev)) + { + printk(KERN_ERR "%s: unable to get IRQ %d .\n", + dev->name, dev->irq); + return -EAGAIN; + } + arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); + + priv->bad = 0; + priv->lastReset = 0; + priv->reset = 0; + priv->open_time = jiffies; + memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6); + memset(dev->broadcast, 0xff, 6); + dev->tbusy = 1; + priv->txOffset = 0; + dev->interrupt = 0; + dev->start = 1; + dev->tx_queue_len = tx_queue_len; + init_timer(&priv->timer); + priv->timer.expires = jiffies + HZ / 10; + priv->timer.data = (unsigned long) dev; + priv->timer.function = &arlan_registration_timer; /* timer handler */ + priv->interrupt_processing_active = 0; + priv->command_lock = 0; + add_timer(&priv->timer); + + init_mutex(&priv->card_lock); + myATOMIC_INIT(priv->card_users, 1); /* damn 2.0.33 */ + priv->registrationLostCount = 0; + priv->registrationLastSeen = jiffies; + priv->txLast = 0; + priv->tx_command_given = 0; + + priv->reRegisterExp = 1; + priv->nof_tx = 0; + priv->nof_tx_ack = 0; + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies - 1; + priv->tx_last_cleared = jiffies; + priv->Conf->writeEEPROM = 0; + priv->Conf->registrationInterrupts = 1; + + dev->tbusy = 0; + + MOD_INC_USE_COUNT; +#ifdef CONFIG_PROC_FS +#ifndef MODULE + if (arlan_device[0]) + init_arlan_proc(); +#endif +#endif + ARLAN_DEBUG_EXIT("arlan_open"); + return 0; +} + + + + +static int arlan_tx(struct sk_buff *skb, struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_tx"); + + 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. + */ + int tickssofar = jiffies - dev->trans_start; + + if (((tickssofar * 1000) / HZ) * 2 > conf->txTimeoutMs) + arlan_command(dev, ARLAN_COMMAND_TX_ABORT); + + if (((tickssofar * 1000) / HZ) < conf->txTimeoutMs) + { + // up(&priv->card_lock); + goto bad_end; + } + printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name); + /* Try to restart the adaptor. */ + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + dev->trans_start = jiffies; + goto bad_end; + + } + /* + * 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_ERR "%s: Transmitter access conflict.\n", + dev->name); + } + else + { + short length; + unsigned char *buf; + + /* + * If some higher layer thinks we've missed an tx-done interrupt + * we are passed NULL. Caution: dev_tint() handles the cli()/sti() + * itself. + */ + + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + buf = skb->data; + + if (priv->txOffset + length + 0x12 > 0x800) + printk(KERN_ERR "TX RING overflow \n"); + + if (arlan_hw_tx(dev, buf, length) == -1) + goto bad_end; + + dev->trans_start = jiffies; + } + dev_kfree_skb(skb); + + arlan_process_interrupt(dev); + priv->tx_chain_active = 0; + ARLAN_DEBUG_EXIT("arlan_tx"); + return 0; + +bad_end: + arlan_process_interrupt(dev); + priv->tx_chain_active = 0; + ARLAN_DEBUG_EXIT("arlan_tx"); + return 1; +} + + +extern inline int DoNotReTransmitCrap(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize) + return 1; + return 0; + +} + +extern inline int DoNotWaitReTransmitCrap(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize) + return 1; + return 0; +} + +extern inline void arlan_queue_retransmit(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("arlan_queue_retransmit"); + + if (DoNotWaitReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } else + priv->ReTransmitRequested++; + + ARLAN_DEBUG_EXIT("arlan_queue_retransmit"); +}; + +extern inline void RetryOrFail(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("RetryOrFail"); + + if (priv->retransmissions > priv->Conf->retries || + DoNotReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } + else if (priv->bad <= priv->Conf->fastReTransCount) + { + arlan_retransmit_now(dev); + } + else arlan_queue_retransmit(dev); + + ARLAN_DEBUG_EXIT("RetryOrFail"); +} + + +static void arlan_tx_done_interrupt(struct device *dev, int status) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt"); + + priv->tx_last_cleared = jiffies; + priv->tx_command_given = 0; + priv->nof_tx_ack++; + switch (status) + { + case 1: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit OK\n"); + priv->stats.tx_packets++; + priv->bad = 0; + priv->reset = 0; + priv->retransmissions = 0; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;; + } + else + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!TXHEAD(dev).offset || !TXTAIL(dev).offset) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + } + break; + + case 2: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit timed out\n"); + priv->bad += 1; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 3: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit max retries\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 4: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit aborted\n"); + priv->bad += 1; + arlan_queue_retransmit(dev); + //RetryOrFail(dev); + } + break; + + case 5: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit not registered\n"); + priv->bad += 1; + //debug=101; + arlan_queue_retransmit(dev); + } + break; + + case 6: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit destination full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 7: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit unknown ack\n"); + priv->bad += 1; + priv->reset = 0; + arlan_queue_retransmit(dev); + } + break; + + case 8: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit dest mail box full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 9: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit root dest not reg.\n"); + priv->bad += 1; + priv->reset = 1; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + default: + { + printk(KERN_ERR "arlan intr: transmit status unknown\n"); + priv->bad += 1; + priv->reset = 1; + arlan_drop_tx(dev); + } + } + + ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt"); +} + + +static void arlan_rx_interrupt(struct device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len) +{ + char *skbtmp; + int i = 0; + + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + + ARLAN_DEBUG_ENTRY("arlan_rx_interrupt"); + // by spec, not WRITESHMB(arlan->rxStatus,0x00); + // prohibited here arlan_command(dev, ARLAN_COMMAND_RX); + + if (pkt_len < 10 || pkt_len > 2048) + { + printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len); + return; + } + if (rxOffset + pkt_len > 0x2000) + { + printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset); + return; + } + priv->in_bytes += pkt_len; + priv->in_bytes10 += pkt_len; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (jiffies - priv->in_time > conf->measure_rate * HZ) + { + conf->in_speed = priv->in_bytes / conf->measure_rate; + priv->in_bytes = 0; + priv->in_time = jiffies; + } + if (jiffies - priv->in_time10 > conf->measure_rate * HZ * 10) + { + conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate); + priv->in_bytes10 = 0; + priv->in_time10 = jiffies; + } + DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char); + switch (rxStatus) + { + case 1: + case 2: + case 3: + { + /* Malloc up new buffer. */ + struct sk_buff *skb; + + DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short); + DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char); + DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char); + + /* here we do multicast filtering to avoid slow 8-bit memcopy */ +#ifdef ARLAN_MULTICAST + if (!(dev->flags & IFF_ALLMULTI) && + !(dev->flags & IFF_PROMISC) && + dev->mc_list) + { + char hw_dst_addr[6]; + struct dev_mc_list *dmi = dev->mc_list; + int i; + + memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6); + if (hw_dst_addr[0] == 0x01) + { + if (mdebug) + if (hw_dst_addr[1] == 0x00) + printk(KERN_ERR "%s mcast 0x0100 \n", dev->name); + else if (hw_dst_addr[1] == 0x40) + printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); + while (dmi) + { if (dmi->dmi_addrlen == 6) + { + if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + for (i = 0; i < 6; i++) + if (dmi->dmi_addr[i] != hw_dst_addr[i]) + break; + if (i == 6) + break; + } + else + printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); + dmi = dmi->next; + } + /* we reach here if multicast filtering is on and packet + * is multicast and not for receive */ + goto end_of_interupt; + } + } +#endif // ARLAN_MULTICAST + /* multicast filtering ends here */ + pkt_len += ARLAN_FAKE_HDR_LEN; + + skb = dev_alloc_skb(pkt_len + 4); + if (skb == NULL) + { + printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); + priv->stats.rx_dropped++; + break; + } + skb_reserve(skb, 2); + skb->dev = dev; + skbtmp = skb_put(skb, pkt_len); + + memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN); + memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6); + memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6); + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + { + char immedDestAddress[6]; + char immedSrcAddress[6]; + memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); + memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); + + printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name, + (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3], + (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7], + (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11], + immedDestAddress[0], immedDestAddress[1], immedDestAddress[2], + immedDestAddress[3], immedDestAddress[4], immedDestAddress[5], + immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2], + immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]); + } + skb->protocol = eth_type_trans(skb, dev); + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + if (skb->protocol != 0x608 && skb->protocol != 0x8) + { + for (i = 0; i <= 22; i++) + printk("%02x:", (u_char) skbtmp[i + 12]); + printk(KERN_ERR "\n"); + printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); + } + netif_rx(skb); + priv->stats.rx_packets++; + } + break; + + default: + printk(KERN_ERR "arlan intr: recieved unknown status\n"); + priv->stats.rx_crc_errors++; + break; + } + ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); +} + +static void arlan_process_interrupt(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + u_short rxOffset = READSHMS(arlan->rxOffset); + u_short pkt_len = READSHMS(arlan->rxLength); + int interrupt_count = 0; + + ARLAN_DEBUG_ENTRY("arlan_process_interrupt"); + + if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active)) + { + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "interrupt chain reentering \n"); + goto end_int_process; + } + while ((rxStatus || txStatus || priv->interrupt_ack_requested) + && (interrupt_count < 5)) + { + if (rxStatus) + priv->last_rx_int_ack_time = arlan_time(); + + arlan_command(dev, ARLAN_COMMAND_INT_ACK); + arlan_command(dev, ARLAN_COMMAND_INT_ENABLE); + + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_ERR "%s: got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n", + dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte), + rxOffset, pkt_len); + + if (rxStatus == 0 && txStatus == 0) + { + priv->last_command_was_rx = 0; + if (priv->irq_test_done) + { + if (!registrationBad(dev)) + IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + } else { + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq); + + } + priv->interrupt_ack_requested = 0; + goto ends; + } + if (txStatus != 0) + { + WRITESHMB(arlan->txStatus, 0x00); + arlan_tx_done_interrupt(dev, txStatus); + goto ends; + } + if (rxStatus == 1 || rxStatus == 2) + { /* a packet waiting */ + arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len); + goto ends; + } + if (rxStatus > 2 && rxStatus < 0xff) + { + priv->last_command_was_rx = 0; + WRITESHMB(arlan->rxStatus, 0x00); + printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + goto ends; + } + if (rxStatus == 0xff) + { + priv->last_command_was_rx = 0; + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + if (registrationBad(dev)) + dev->start = 0; + if (!registrationBad(dev)) + { + priv->registrationLastSeen = jiffies; + if (!dev->tbusy && !priv->under_reset && !priv->under_config) + { + mark_bh(NET_BH); + dev->start = 1; + } + } + goto ends; + } +ends: + + arlan_command_process(dev); + + rxStatus = READSHMB(arlan->rxStatus); + txStatus = READSHMB(arlan->txStatus); + rxOffset = READSHMS(arlan->rxOffset); + pkt_len = READSHMS(arlan->rxLength); + + + priv->irq_test_done = 1; + + interrupt_count++; + } + priv->interrupt_processing_active = 0; + +end_int_process: + arlan_command_process(dev); + + ARLAN_DEBUG_EXIT("arlan_process_interrupt"); + return; +} + +static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = dev_id; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + + ARLAN_DEBUG_ENTRY("arlan_interrupt"); + + + if (!rxStatus && !txStatus) + priv->interrupt_ack_requested++; + dev->interrupt++; + + arlan_process_interrupt(dev); + + priv->irq_test_done = 1; + dev->interrupt--; + + ARLAN_DEBUG_EXIT("arlan_interrupt"); + return; + +} + + +static int arlan_close(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + if (!dev) + { + printk(KERN_CRIT "arlan: No Device\n"); + return 0; + } + priv = (struct arlan_private *) dev->priv; + if (!priv) + { + printk(KERN_CRIT "arlan: No Device priv \n"); + return 0; + } + ARLAN_DEBUG_ENTRY("arlan_close"); + + IFDEBUG(ARLAN_DEBUG_STARTUP) + printk(KERN_NOTICE "%s: Closing device\n", dev->name); + + priv->open_time = 0; + dev->tbusy = 1; + dev->start = 0; + del_timer(&priv->timer); + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; + + ARLAN_DEBUG_EXIT("arlan_close"); + return 0; +} + + +static long alignLong(volatile u_char * ptr) +{ + long ret; + memcpy_fromio(&ret, (void *) ptr, 4); + return ret; +} + + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ + +static struct enet_statistics *arlan_statistics(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + + ARLAN_DEBUG_ENTRY("arlan_statistics"); + + /* Update the statistics from the device registers. */ + + READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int); + READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int); + READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int); + READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); + READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); + READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int); + READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int); + READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); + READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); + READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); + READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); + READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); + READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int); + + ARLAN_DEBUG_EXIT("arlan_statistics"); + + return &priv->stats; +} + + +static void arlan_set_multicast(struct device *dev) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + int board_conf_needed = 0; + + + ARLAN_DEBUG_ENTRY("arlan_set_multicast"); + + if (dev->flags & IFF_PROMISC) + { + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL); + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + else + { + /* turn off promiscuous mode */ + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL; + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + if (board_conf_needed) + arlan_command(dev, ARLAN_COMMAND_CONF); + + ARLAN_DEBUG_EXIT("arlan_set_multicast"); +} + + +__initfunctio(int arlan_probe(struct device *dev)) +{ + printk("Arlan driver %s\n", arlan_version); + + if (arlan_probe_everywhere(dev)) + return ENODEV; + + arlans_found++; + + if (arlans_found == 1) + siteName = kmalloc(100, GFP_KERNEL); + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + int i = 0; + + ARLAN_DEBUG_ENTRY("init_module"); + + if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) + { + printk(KERN_WARNING "arlan: wrong module params for multiple devices\n "); + return -1; + } + numDevices = arlan_find_devices(); + if (numDevices == 0) + { + printk(KERN_ERR "arlan: no devices found \n"); + return -1; + } + + siteName = kmalloc(100, GFP_KERNEL); + if(siteName==NULL) + { + printk(KERN_ERR "arlan: No memory for site name.\n"); + return -1; + } + for (i = 0; i < numDevices && i < MAX_ARLANS; i++) + { + if (!arlan_allocate_device(i, NULL)) + return -1; + if (arlan_device[i] == NULL) + { + printk(KERN_CRIT "arlan: Not Enough memory \n"); + return -1; + } + if (probe) + arlan_probe_everywhere(arlan_device[i]); + } + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + ARLAN_DEBUG_EXIT("init_module"); + return 0; +} + + +void cleanup_module(void) +{ + int i = 0; + + ARLAN_DEBUG_ENTRY("cleanup_module"); + + IFDEBUG(ARLAN_DEBUG_SHUTDOWN) + printk(KERN_INFO "arlan: unloading module\n"); + for (i = 0; i < MAX_ARLANS; i++) + { + if (arlan_device[i]) + { + unregister_netdev(arlan_device[i]); + if (arlan_device[i]->priv) + { + if (((struct arlan_private *) arlan_device[i]->priv)->conf) + kfree(((struct arlan_private *) arlan_device[i]->priv)->conf); + kfree(arlan_device[i]); + } + arlan_device[i] = NULL; + } + } + ARLAN_DEBUG_EXIT("cleanup_module"); +} + + +#endif diff -u --recursive --new-file v2.3.9/linux/drivers/net/arlan.h linux/drivers/net/arlan.h --- v2.3.9/linux/drivers/net/arlan.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arlan.h Mon Jul 5 20:09:40 1999 @@ -0,0 +1,574 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * Gnu Public License applies + */ +#include + +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include /* For ARPHRD_ETHER */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG 1 + +#define ARLAN_PROC_INTERFACE +#define MAX_ARLANS 4 /* not more than 4 ! */ +#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */ + +#define ARLAN_MAX_MULTICAST_ADDRS 16 +#define ARLAN_RCV_CLEAN 0 +#define ARLAN_RCV_PROMISC 1 +#define ARLAN_RCV_CONTROL 2 + + +#ifdef CONFIG_PROC_FS +extern int init_arlan_proc(void); +#endif + +extern struct device *arlan_device[MAX_ARLANS]; +static int arlan_debug; +static char * siteName; +static int arlan_entry_debug; +static int arlan_exit_debug; +static int arlan_entry_and_exit_debug; +static int testMemory; +static const char* arlan_version; + +#define SIDUNKNOWN -1 +#define radioNodeIdUNKNOWN -1 +#define encryptionKeyUNKNOWN '\0'; +#define irqUNKNOWN 0 +#define memUNKNOWN 0 +#define debugUNKNOWN 0 +#define probeUNKNOWN 1 +#define numDevicesUNKNOWN 1 +#define testMemoryUNKNOWN 1 +#define spreadingCodeUNKNOWN 0 +#define channelNumberUNKNOWN 0 +#define channelSetUNKNOWN 0 +#define systemIdUNKNOWN -1 +#define registrationModeUNKNOWN -1 +#define siteNameUNKNOWN "LinuxSite" + + + +#define IFDEBUG( L ) if ( (L) & arlan_debug ) +#define ARLAN_FAKE_HDR_LEN 12 + +#ifdef DEBUG + #define ARLAN_ENTRY_EXIT_DEBUGING 1 + #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) +#else + #define ARLAN_DEBUG(a,b) +#endif + +struct arlan_shmem +{ + /* Header Signature */ + volatile char textRegion[48]; + volatile u_char resetFlag; + volatile u_char diagnosticInfo; + volatile u_short diagnosticOffset; + volatile u_char _1[12]; + volatile u_char lanCardNodeId[6]; + volatile u_char broadcastAddress[6]; + volatile u_char hardwareType; + volatile u_char majorHardwareVersion; + volatile u_char minorHardwareVersion; + volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111 + volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A + volatile u_char _2[47]; + + /* Control/Status Block - 0x0080 */ + volatile u_char interruptInProgress; /* not used by lancpu */ + volatile u_char cntrlRegImage; /* not used by lancpu */ + volatile u_char _3[13]; + volatile u_char dumpByte; + volatile u_char commandByte; /* non-zero = active */ + volatile u_char commandParameter[15]; + + /* Receive Status - 0x00a0 */ + volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */ + volatile u_char rxFrmType; + volatile u_short rxOffset; + volatile u_short rxLength; + volatile u_char rxSrc[6]; + volatile u_char rxBroadcastFlag; + volatile u_char rxQuality; + volatile u_char scrambled; + volatile u_char _4[1]; + + /* Transmit Status - 0x00b0 */ + volatile u_char txStatus; + volatile u_char txAckQuality; + volatile u_char numRetries; + volatile u_char _5[14]; + volatile u_char registeredRouter[6]; + volatile u_char backboneRouter[6]; + volatile u_char registrationStatus; + volatile u_char configuredStatusFlag; + volatile u_char _6[1]; + volatile u_char ultimateDestAddress[6]; + volatile u_char immedDestAddress[6]; + volatile u_char immedSrcAddress[6]; + volatile u_short rxSequenceNumber; + volatile u_char assignedLocaltalkAddress; + volatile u_char _7[27]; + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + volatile u_short txTimeout; + volatile u_short transportTime; + volatile u_char _8[4]; + + /* - Configuration Parameters */ + volatile u_char irqLevel; + volatile u_char spreadingCode; + volatile u_char channelSet; + volatile u_char channelNumber; + volatile u_short radioNodeId; + volatile u_char _9[2]; + volatile u_char scramblingDisable; + volatile u_char radioType; + volatile u_short routerId; + volatile u_char _10[9]; + volatile u_char txAttenuation; + volatile u_char systemId[4]; + volatile u_short globalChecksum; + volatile u_char _11[4]; + volatile u_short maxDatagramSize; + volatile u_short maxFrameSize; + volatile u_char maxRetries; + volatile u_char receiveMode; + volatile u_char priority; + volatile u_char rootOrRepeater; + volatile u_char specifiedRouter[6]; + volatile u_short fastPollPeriod; + volatile u_char pollDecay; + volatile u_char fastPollDelay[2]; + volatile u_char arlThreshold; + volatile u_char arlDecay; + volatile u_char _12[1]; + volatile u_short specRouterTimeout; + volatile u_char _13[5]; + + /* Scrambled Area */ + volatile u_char SID[4]; + volatile u_char encryptionKey[12]; + volatile u_char _14[2]; + volatile u_char waitTime[2]; + volatile u_char lParameter[2]; + volatile u_char _15[3]; + volatile u_short headerSize; + volatile u_short sectionChecksum; + + volatile u_char registrationMode; + volatile u_char registrationFill; + volatile u_short pollPeriod; + volatile u_short refreshPeriod; + volatile u_char name[16]; + volatile u_char NID[6]; + volatile u_char localTalkAddress; + volatile u_char codeFormat; + volatile u_char numChannels; + volatile u_char channel1; + volatile u_char channel2; + volatile u_char channel3; + volatile u_char channel4; + volatile u_char SSCode[59]; + + volatile u_char _16[0xC0]; + volatile u_short auxCmd; + volatile u_char dumpPtr[4]; + volatile u_char dumpVal; + volatile u_char _17[0x6A]; + volatile u_char wireTest; + volatile u_char _18[14]; + + /* Statistics Block - 0x0300 */ + volatile u_char hostcpuLock; + volatile u_char lancpuLock; + volatile u_char resetTime[18]; + + volatile u_char numDatagramsTransmitted[4]; + volatile u_char numReTransmissions[4]; + volatile u_char numFramesDiscarded[4]; + volatile u_char numDatagramsReceived[4]; + volatile u_char numDuplicateReceivedFrames[4]; + volatile u_char numDatagramsDiscarded[4]; + + volatile u_short maxNumReTransmitDatagram; + volatile u_short maxNumReTransmitFrames; + volatile u_short maxNumConsecutiveDuplicateFrames; + /* misaligned here so we have to go to characters */ + + volatile u_char numBytesTransmitted[4]; + volatile u_char numBytesReceived[4]; + volatile u_char numCRCErrors[4]; + volatile u_char numLengthErrors[4]; + volatile u_char numAbortErrors[4]; + volatile u_char numTXUnderruns[4]; + volatile u_char numRXOverruns[4]; + volatile u_char numHoldOffs[4]; + volatile u_char numFramesTransmitted[4]; + volatile u_char numFramesReceived[4]; + volatile u_char numReceiveFramesLost[4]; + volatile u_char numRXBufferOverflows[4]; + volatile u_char numFramesDiscardedAddrMismatch[4]; + volatile u_char numFramesDiscardedSIDMismatch[4]; + volatile u_char numPollsTransmistted[4]; + volatile u_char numPollAcknowledges[4]; + volatile u_char numStatusTimeouts[4]; + volatile u_char numNACKReceived[4]; + + volatile u_char _19[0x86]; + + volatile u_char txBuffer[0x800]; + volatile u_char rxBuffer[0x800]; + + volatile u_char _20[0x800]; + volatile u_char _21[0x3fb]; + volatile u_char configStatus; + volatile u_char _22; + volatile u_char progIOCtrl; + volatile u_char shareMBase; + volatile u_char controlRegister; +}; + +struct arlan_conf_stru { + int spreadingCode; + int channelSet; + int channelNumber; + int scramblingDisable; + int txAttenuation; + int systemId; + int maxDatagramSize; + int maxFrameSize; + int maxRetries; + int receiveMode; + int priority; + int rootOrRepeater; + int SID; + int radioNodeId; + int registrationMode; + int registrationFill; + int localTalkAddress; + int codeFormat; + int numChannels; + int channel1; + int channel2; + int channel3; + int channel4; + int txClear; + int txRetries; + int txRouting; + int txScrambled; + int rxParameter; + int txTimeoutMs; + int txAckTimeoutMs; + int waitCardTimeout; + int waitTime; + int lParameter; + int _15; + int headerSize; + int async; + int retries; + int tx_delay_ms; + int waitReTransmitPacketMaxSize; + int ReTransmitPacketMaxSize; + int fastReTransCount; + int driverRetransmissions; + int registrationInterrupts; + int hardwareType; + int radioType; + int writeRadioType; + int writeEEPROM; + char siteName[17]; + int measure_rate; + int in_speed; + int out_speed; + int in_speed10; + int out_speed10; + int in_speed_max; + int out_speed_max; + int pre_Command_Wait; + int rx_tweak1; + int rx_tweak2; + int tx_queue_len; +}; + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; + +struct TxParam +{ + volatile short offset; + volatile short length; + volatile u_char dest[6]; + volatile unsigned char clear; + volatile unsigned char retries; + volatile unsigned char routing; + volatile unsigned char scrambled; +}; + +struct TxRingPoint { + struct TxParam txParam; + + +}; + +#define TX_RING_SIZE 2 +/* Information that need to be kept for each board. */ +struct arlan_private { + struct enet_statistics stats; + long open_time; /* Useless example local info. */ + struct arlan_shmem * card; + struct arlan_shmem * conf; + struct TxParam txParam; + int multicastLength; + char multicastList[ARLAN_MAX_MULTICAST_ADDRS][6]; + int promiscModeEnabled; + struct arlan_conf_stru * Conf; + int bad; + int reset; + long long lastReset; + struct timer_list timer; + struct timer_list tx_delay_timer; + struct timer_list tx_retry_timer; + struct timer_list rx_check_timer; + struct semaphore card_lock; + atomic_t card_users; + atomic_t delay_on; + atomic_t retr_on; + int registrationLostCount; + int reRegisterExp; + int nof_tx; + int nof_tx_ack; + int last_nof_tx; + int last_nof_tx_ack; + int irq_test_done; + int last_command_was_rx; + struct TxParam txRing[TX_RING_SIZE]; + char reTransmitBuff[0x800]; + volatile int txLast; + volatile int txNew; + volatile int txOffset; + volatile char ReTransmitRequested; + volatile long long tx_done_delayed; + volatile long long registrationLastSeen; + volatile char under_command; + volatile char under_toggle; + volatile long long tx_last_sent; + volatile long long tx_last_cleared; + volatile u_char under_tx; + volatile int retransmissions; + volatile int tx_chain_active; + volatile int timer_chain_active; + volatile int interrupt_ack_requested; + volatile int command_lock; + volatile int rx_command_needed; + volatile int tx_command_needed; + volatile int waiting_command_mask; + volatile int card_polling_interval; + volatile int last_command_buff_free_time; + volatile int numResets; + volatile int under_reset; + volatile int under_config; + volatile int rx_command_given; + volatile int tx_command_given; + volatile int interrupt_processing_active; + volatile long long last_tx_time; + volatile long long last_rx_time; + volatile long long last_rx_int_ack_time; + int in_bytes; + int out_bytes; + int in_time; + int out_time; + int in_time10; + int out_time10; + int in_bytes10; + int out_bytes10; +}; + + + +#define ARLAN_CLEAR 0x00 +#define ARLAN_RESET 0x01 +#define ARLAN_CHANNEL_ATTENTION 0x02 +#define ARLAN_INTERRUPT_ENABLE 0x04 +#define ARLAN_CLEAR_INTERRUPT 0x08 +#define ARLAN_POWER 0x40 +#define ARLAN_ACCESS 0x80 + +#define ARLAN_COM_CONF 0x01 +#define ARLAN_COM_RX_ENABLE 0x03 +#define ARLAN_COM_RX_ABORT 0x04 +#define ARLAN_COM_TX_ENABLE 0x05 +#define ARLAN_COM_TX_ABORT 0x06 +#define ARLAN_COM_NOP 0x07 +#define ARLAN_COM_STANDBY 0x08 +#define ARLAN_COM_ACTIVATE 0x09 +#define ARLAN_COM_GOTO_SLOW_POLL 0x0a +#define ARLAN_COM_INT 0x80 + + +#define TXLAST(dev) (((struct arlan_private *)dev->priv)->txRing[((struct arlan_private *)dev->priv)->txLast]) +#define TXHEAD(dev) (((struct arlan_private *)dev->priv)->txRing[0]) +#define TXTAIL(dev) (((struct arlan_private *)dev->priv)->txRing[1]) + +#define TXBuffStart(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->txBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) ) +#define TXBuffEnd(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->rxBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) + +#define READSHM(to,from,atype) {\ + atype tmp;\ + memcpy_fromio(&(tmp),&(from),sizeof(atype));\ + to = tmp;\ + } + +#define READSHMEM(from,atype)\ + atype from; \ + READSHM(from, arlan->from, atype); + +#define WRITESHM(to,from,atype) \ + { atype tmpSHM = from;\ + memcpy_toio(&(to),&tmpSHM,sizeof(atype));\ + } + +#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \ + { atype tmpSHM; \ + memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\ + IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\ + } + +#define WRITESHMB(to, val) \ + writeb(val,&(to)) +#define READSHMB(to) \ + readb(&(to)) +#define WRITESHMS(to, val) \ + writew(val,&(to)) +#define READSHMS(to) \ + readw(&(to)) +#define WRITESHMI(to, val) \ + writel(val,&(to)) +#define READSHMI(to) \ + readl(&(to)) + + + + + +#define registrationBad(dev)\ + ( ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationMode) > 0) && \ + ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationStatus) == 0) ) + + +#define readControlRegister(dev)\ + READSHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage) + +#define writeControlRegister(dev, v){\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage ,((v) &0xF) );\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->controlRegister ,(v) );} + + +#define arlan_interrupt_lancpu(dev) {\ + int cr; \ + \ + priv->under_toggle++; \ + cr = readControlRegister(dev);\ + if (cr & ARLAN_CHANNEL_ATTENTION){ \ + writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\ + }else \ + writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\ + priv->under_toggle=0; \ +} + +#define clearChannelAttention(dev){ \ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);} +#define setHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);} +#define clearHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);} +#define setInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;} +#define clearInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;} +#define setClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;} +#define clearClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);} +#define setPowerOff(dev){\ + writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define setPowerOn(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); } +#define arlan_lock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define arlan_unlock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); } + + + + +#define ARLAN_COMMAND_RX 0x00001 +#define ARLAN_COMMAND_NOOP 0x00002 +#define ARLAN_COMMAND_NOOPINT 0x00004 +#define ARLAN_COMMAND_TX 0x00008 +#define ARLAN_COMMAND_CONF 0x00010 +#define ARLAN_COMMAND_RESET 0x00020 +#define ARLAN_COMMAND_TX_ABORT 0x00040 +#define ARLAN_COMMAND_RX_ABORT 0x00080 +#define ARLAN_COMMAND_POWERDOWN 0x00100 +#define ARLAN_COMMAND_POWERUP 0x00200 +#define ARLAN_COMMAND_SLOW_POLL 0x00400 +#define ARLAN_COMMAND_ACTIVATE 0x00800 +#define ARLAN_COMMAND_INT_ACK 0x01000 +#define ARLAN_COMMAND_INT_ENABLE 0x02000 +#define ARLAN_COMMAND_WAIT_NOW 0x04000 +#define ARLAN_COMMAND_LONG_WAIT_NOW 0x08000 +#define ARLAN_COMMAND_STANDBY 0x10000 +#define ARLAN_COMMAND_INT_RACK 0x20000 +#define ARLAN_COMMAND_INT_RENABLE 0x40000 +#define ARLAN_COMMAND_CONF_WAIT 0x80000 +#define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_CONF) +#define ARLAN_COMMAND_CLEAN_AND_RESET (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_RESET) + + + +#define ARLAN_DEBUG_CHAIN_LOCKS 0x00001 +#define ARLAN_DEBUG_RESET 0x00002 +#define ARLAN_DEBUG_TIMING 0x00004 +#define ARLAN_DEBUG_CARD_STATE 0x00008 +#define ARLAN_DEBUG_TX_CHAIN 0x00010 +#define ARLAN_DEBUG_MULTICAST 0x00020 +#define ARLAN_DEBUG_HEADER_DUMP 0x00040 +#define ARLAN_DEBUG_INTERRUPT 0x00080 +#define ARLAN_DEBUG_STARTUP 0x00100 +#define ARLAN_DEBUG_SHUTDOWN 0x00200 + \ No newline at end of file diff -u --recursive --new-file v2.3.9/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c --- v2.3.9/linux/drivers/net/atari_bionet.c Sat Jun 13 13:28:34 1998 +++ linux/drivers/net/atari_bionet.c Tue Jul 6 19:05:49 1999 @@ -324,8 +324,8 @@ /* Check for a network adaptor of this type, and return '0' if one exists. */ -__initfunc(int -bionet_probe(struct device *dev)) { +int __init +bionet_probe(struct device *dev){ unsigned char station_addr[6]; static unsigned version_printed = 0; static int no_more_found = 0; /* avoid "Probing for..." printed 4 times */ diff -u --recursive --new-file v2.3.9/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c --- v2.3.9/linux/drivers/net/atari_pamsnet.c Wed Oct 7 15:51:45 1998 +++ linux/drivers/net/atari_pamsnet.c Tue Jul 6 19:05:49 1999 @@ -561,8 +561,8 @@ /* Check for a network adaptor of this type, and return '0' if one exists. */ -__initfunc(extern int -pamsnet_probe (dev)) +extern int __init +pamsnet_probe (dev) struct device *dev; { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c --- v2.3.9/linux/drivers/net/atarilance.c Fri Feb 20 17:55:45 1998 +++ linux/drivers/net/atarilance.c Tue Jul 6 19:05:49 1999 @@ -370,9 +370,9 @@ } -__initfunc(int atarilance_probe( struct device *dev )) - -{ int i; +int __init atarilance_probe( struct device *dev ) +{ + int i; static int found = 0; if (!MACH_IS_ATARI || found) @@ -393,9 +393,9 @@ /* Derived from hwreg_present() in atari/config.c: */ -__initfunc(static int addr_accessible( volatile void *regp, int wordflag, int writeflag )) - -{ int ret; +static int __init addr_accessible( volatile void *regp, int wordflag, int writeflag ) +{ + int ret; long flags; long *vbr, save_berr; @@ -443,10 +443,10 @@ } -__initfunc(static unsigned long lance_probe1( struct device *dev, - struct lance_addr *init_rec )) - -{ volatile unsigned short *memaddr = +static unsigned long __init lance_probe1( struct device *dev, + struct lance_addr *init_rec ) +{ + volatile unsigned short *memaddr = (volatile unsigned short *)init_rec->memaddr; volatile unsigned short *ioaddr = (volatile unsigned short *)init_rec->ioaddr; diff -u --recursive --new-file v2.3.9/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.3.9/linux/drivers/net/atp.c Fri Nov 20 08:44:06 1998 +++ linux/drivers/net/atp.c Tue Jul 6 19:05:49 1999 @@ -150,8 +150,8 @@ If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ -__initfunc(int -atp_init(struct device *dev)) +int __init +atp_init(struct device *dev) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; int base_addr = dev->base_addr; @@ -173,7 +173,7 @@ return ENODEV; } -__initfunc(static int atp_probe1(struct device *dev, short ioaddr)) +static int __init atp_probe1(struct device *dev, short ioaddr) { int saved_ctrl_reg, status; @@ -259,7 +259,7 @@ } /* Read the station address PROM, usually a word-wide EEPROM. */ -__initfunc(static void get_node_ID(struct device *dev)) +static void __init get_node_ID(struct device *dev) { short ioaddr = dev->base_addr; int sa_offset = 0; @@ -291,7 +291,7 @@ * DO : _________X_______X */ -__initfunc(static unsigned short eeprom_op(short ioaddr, unsigned int cmd)) +static unsigned short __init eeprom_op(short ioaddr, unsigned int cmd) { unsigned eedata_out = 0; int num_bits = EE_CMD_SIZE; diff -u --recursive --new-file v2.3.9/linux/drivers/net/com20020.c linux/drivers/net/com20020.c --- v2.3.9/linux/drivers/net/com20020.c Mon Sep 14 11:32:22 1998 +++ linux/drivers/net/com20020.c Tue Jul 6 19:05:49 1999 @@ -96,7 +96,7 @@ MODULE_PARM(backplane,"i"); MODULE_PARM(clock,"i"); #else -__initfunc(void com20020_setup (char *str, int *ints)); +void __init com20020_setup (char *str, int *ints); extern struct device arcnet_devs[]; extern char arcnet_dev_names[][10]; extern int arcnet_num_devs; @@ -224,7 +224,7 @@ * it's where we were told it was, and even autoirq */ -__initfunc(int arc20020_probe(struct device *dev)) +int __init arc20020_probe(struct device *dev) { int ioaddr=dev->base_addr,status,delayval; unsigned long airqmask; @@ -327,7 +327,7 @@ /* Set up the struct device associated with this card. Called after * probing succeeds. */ -__initfunc(int arc20020_found(struct device *dev,int ioaddr,int airq)) +int __init arc20020_found(struct device *dev,int ioaddr,int airq) { struct arcnet_local *lp; @@ -1035,7 +1035,7 @@ #else -__initfunc(void com20020_setup (char *str, int *ints)) +void __init com20020_setup (char *str, int *ints) { struct device *dev; diff -u --recursive --new-file v2.3.9/linux/drivers/net/com90io.c linux/drivers/net/com90io.c --- v2.3.9/linux/drivers/net/com90io.c Mon Sep 14 11:32:22 1998 +++ linux/drivers/net/com90io.c Tue Jul 6 19:05:49 1999 @@ -87,7 +87,7 @@ MODULE_PARM(irq, "i"); MODULE_PARM(device, "s"); #else -__initfunc(void com90io_setup (char *str, int *ints)); +void __init com90io_setup (char *str, int *ints); extern struct device arcnet_devs[]; extern char arcnet_dev_names[][10]; extern int arcnet_num_devs; @@ -193,7 +193,7 @@ * it's where we were told it was, and even autoirq */ -__initfunc(int arc90io_probe(struct device *dev)) +int __init arc90io_probe(struct device *dev) { int ioaddr=dev->base_addr,status,delayval; unsigned long airqmask; @@ -287,7 +287,7 @@ /* Set up the struct device associated with this card. Called after * probing succeeds. */ -__initfunc(int arc90io_found(struct device *dev,int ioaddr,int airq)) +int __init arc90io_found(struct device *dev,int ioaddr,int airq) { struct arcnet_local *lp; @@ -914,7 +914,7 @@ #else -__initfunc(void com90io_setup (char *str, int *ints)) +void __init com90io_setup (char *str, int *ints) { struct device *dev; diff -u --recursive --new-file v2.3.9/linux/drivers/net/com90xx.c linux/drivers/net/com90xx.c --- v2.3.9/linux/drivers/net/com90xx.c Mon Sep 14 11:32:22 1998 +++ linux/drivers/net/com90xx.c Tue Jul 6 19:05:49 1999 @@ -117,7 +117,7 @@ MODULE_PARM(shmem, "i"); MODULE_PARM(device, "s"); #else -__initfunc(void com90xx_setup(char *str, int *ints)); +void __init com90xx_setup(char *str, int *ints); char __initdata com90xx_explicit = 0; extern struct device arcnet_devs[]; @@ -179,7 +179,7 @@ 0 }; -__initfunc(int arc90xx_probe(struct device *dev)) +int __init arc90xx_probe(struct device *dev) { static int init_once = 0; static int numports = sizeof(ports) / sizeof(ports[0]), numshmems = sizeof(shmems) / sizeof(shmems[0]); @@ -399,7 +399,7 @@ */ airqmask = probe_irq_on(); AINTMASK(NORXflag); - udelay(1); + mdelay(1); AINTMASK(0); airq = probe_irq_off(airqmask); @@ -493,7 +493,7 @@ /* Set up the struct device associated with this card. Called after * probing succeeds. */ -__initfunc(static int arc90xx_found(struct device *dev, int ioaddr, int airq, u_long shmem, int more)) +static int __init arc90xx_found(struct device *dev, int ioaddr, int airq, u_long shmem, int more) { struct arcnet_local *lp; u_long first_mirror, last_mirror; @@ -1121,7 +1121,7 @@ #else -__initfunc(void com90xx_setup(char *str, int *ints)) +void __init com90xx_setup(char *str, int *ints) { struct device *dev; diff -u --recursive --new-file v2.3.9/linux/drivers/net/cops.c linux/drivers/net/cops.c --- v2.3.9/linux/drivers/net/cops.c Wed Oct 7 15:51:45 1998 +++ linux/drivers/net/cops.c Tue Jul 6 19:05:49 1999 @@ -218,7 +218,7 @@ * If dev->base_addr in [1..0x1ff], always return failure. * otherwise go with what we pass in. */ -__initfunc(int cops_probe(struct device *dev)) +int __init cops_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -252,7 +252,7 @@ * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ -__initfunc(static int cops_probe1(struct device *dev, int ioaddr)) +static int __init cops_probe1(struct device *dev, int ioaddr) { struct cops_local *lp; static unsigned version_printed = 0; @@ -348,7 +348,7 @@ return 0; } -__initfunc(static int cops_irq (int ioaddr, int board)) +static int __init cops_irq (int ioaddr, int board) { /* * This does not use the IRQ to determine where the IRQ is. We just * assume that when we get a correct status response that it's the IRQ. diff -u --recursive --new-file v2.3.9/linux/drivers/net/cosa.c linux/drivers/net/cosa.c --- v2.3.9/linux/drivers/net/cosa.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/cosa.c Tue Jul 6 19:05:49 1999 @@ -362,7 +362,7 @@ #ifdef MODULE int init_module(void) #else -__initfunc(static int cosa_init(void)) +static int __init cosa_init(void) #endif { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.3.9/linux/drivers/net/cs89x0.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/cs89x0.c Tue Jul 6 19:05:49 1999 @@ -145,8 +145,8 @@ struct netdev_entry netcard_drv = {"netcard", cs89x0_probe1, NETCARD_IO_EXTENT, netcard_portlist}; #else -__initfunc(int -cs89x0_probe(struct device *dev)) +int __init +cs89x0_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -195,8 +195,8 @@ outw(value, dev->base_addr + portno); } -__initfunc(static int -wait_eeprom_ready(struct device *dev)) +static int __init +wait_eeprom_ready(struct device *dev) { int timeout = jiffies; /* check to see if the EEPROM is ready, a timeout is used - @@ -208,8 +208,8 @@ return 0; } -__initfunc(static int -get_eeprom_data(struct device *dev, int off, int len, int *buffer)) +static int __init +get_eeprom_data(struct device *dev, int off, int len, int *buffer) { int i; @@ -226,8 +226,8 @@ return 0; } -__initfunc(static int -get_eeprom_cksum(int off, int len, int *buffer)) +static int __init +get_eeprom_cksum(int off, int len, int *buffer) { int i, cksum; @@ -244,7 +244,7 @@ probes on the ISA bus. A good device probes avoids doing writes, and verifies that the correct device exists and functions. */ -__initfunc(static int cs89x0_probe1(struct device *dev, int ioaddr)) +static int __init cs89x0_probe1(struct device *dev, int ioaddr) { struct net_local *lp; static unsigned version_printed = 0; @@ -390,10 +390,8 @@ return 0; } - - -__initfunc(void -reset_chip(struct device *dev)) +void __init +reset_chip(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; diff -u --recursive --new-file v2.3.9/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.3.9/linux/drivers/net/de4x5.c Sat May 8 19:46:44 1999 +++ linux/drivers/net/de4x5.c Tue Jul 6 19:05:49 1999 @@ -1106,8 +1106,8 @@ ** Autoprobing in modules is allowed here. See the top of the file for ** more info. */ -__initfunc(int -de4x5_probe(struct device *dev)) +int __init +de4x5_probe(struct device *dev) { u_long iobase = dev->base_addr; @@ -1121,8 +1121,8 @@ return (dev->priv ? 0 : -ENODEV); } -__initfunc(static int -de4x5_hw_init(struct device *dev, u_long iobase)) +static int __init +de4x5_hw_init(struct device *dev, u_long iobase) { struct bus_type *lp = &bus; int i, status=0; @@ -2054,8 +2054,8 @@ ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. Upto 15 EISA devices are supported. */ -__initfunc(static void -eisa_probe(struct device *dev, u_long ioaddr)) +static void __init +eisa_probe(struct device *dev, u_long ioaddr) { int i, maxSlots, status, device; u_char irq; @@ -2136,8 +2136,8 @@ */ #define PCI_LAST_DEV 32 -__initfunc(static void -pci_probe(struct device *dev, u_long ioaddr)) +static void __init +pci_probe(struct device *dev, u_long ioaddr) { u_char pb, pbus, dev_num, dnum, timer; u_short vendor, index, status; @@ -2248,8 +2248,8 @@ ** DECchips, we can find the base SROM irrespective of the BIOS scan direction. ** For single port cards this is a time waster... */ -__initfunc(static void -srom_search(struct pci_dev *dev)) +static void __init +srom_search(struct pci_dev *dev) { u_char pb; u_short vendor, status; @@ -2307,8 +2307,8 @@ return; } -__initfunc(static void -link_modules(struct device *dev, struct device *tmp)) +static void __init +link_modules(struct device *dev, struct device *tmp) { struct device *p=dev; @@ -5559,17 +5559,15 @@ switch(ioc->cmd) { case DE4X5_GET_HWADDR: /* Get the hardware address */ ioc->len = ETH_ALEN; - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; for (i=0; idev_addr[i]; } - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; case DE4X5_SET_HWADDR: /* Set the hardware address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN)) return -EFAULT; - copy_from_user(tmp.addr, ioc->data, ETH_ALEN); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT; for (i=0; idev_addr[i] = tmp.addr[i]; } @@ -5612,9 +5610,8 @@ case DE4X5_GET_STATS: /* Get the driver statistics */ ioc->len = sizeof(lp->pktStats); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; spin_lock_irqsave(&lp->lock, flags); - copy_to_user(ioc->data, &lp->pktStats, ioc->len); + if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) return -EFAULT; spin_unlock_irqrestore(&lp->lock, flags); break; @@ -5627,14 +5624,12 @@ case DE4X5_GET_OMR: /* Get the OMR Register contents */ tmp.addr[0] = inl(DE4X5_OMR); - if (verify_area(VERIFY_WRITE, ioc->data, 1)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, 1); + if (copy_to_user(ioc->data, tmp.addr, 1)) return -EFAULT; break; case DE4X5_SET_OMR: /* Set the OMR Register contents */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, ioc->data, 1)) return -EFAULT; - copy_from_user(tmp.addr, ioc->data, 1); + if (copy_from_user(tmp.addr, ioc->data, 1)) return -EFAULT; outl(tmp.addr[0], DE4X5_OMR); break; @@ -5649,8 +5644,7 @@ tmp.lval[6] = inl(DE4X5_STRR); j+=4; tmp.lval[7] = inl(DE4X5_SIGR); j+=4; ioc->len = j; - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; #define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */ @@ -5739,8 +5733,7 @@ tmp.addr[j++] = dev->tbusy; ioc->len = j; - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; */ @@ -5863,8 +5856,8 @@ ** If at end of eth device list and can't use current entry, malloc ** one up. If memory could not be allocated, print an error message. */ -__initfunc(static struct device * -insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))) +static struct device * __init +insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)) { struct device *new; diff -u --recursive --new-file v2.3.9/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.3.9/linux/drivers/net/de600.c Tue Feb 10 12:56:44 1998 +++ linux/drivers/net/de600.c Tue Jul 6 19:05:49 1999 @@ -627,8 +627,8 @@ */ } -__initfunc(int -de600_probe(struct device *dev)) +int __init +de600_probe(struct device *dev) { int i; static struct net_device_stats de600_netstats; diff -u --recursive --new-file v2.3.9/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v2.3.9/linux/drivers/net/de620.c Sat May 15 23:43:04 1999 +++ linux/drivers/net/de620.c Tue Jul 6 19:05:49 1999 @@ -820,8 +820,8 @@ * * Check if there is a DE-620 connected */ -__initfunc(int -de620_probe(struct device *dev)) +int __init +de620_probe(struct device *dev) { static struct net_device_stats de620_netstats; int i; @@ -913,8 +913,8 @@ */ #define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister); -__initfunc(static unsigned short -ReadAWord(struct device *dev, int from)) +static unsigned short __init +ReadAWord(struct device *dev, int from) { unsigned short data; int nbits; @@ -956,8 +956,8 @@ return data; } -__initfunc(static int -read_eeprom(struct device *dev)) +static int __init +read_eeprom(struct device *dev) { unsigned short wrd; diff -u --recursive --new-file v2.3.9/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.3.9/linux/drivers/net/defxx.c Fri Apr 16 13:58:46 1999 +++ linux/drivers/net/defxx.c Tue Jul 6 19:05:49 1999 @@ -446,11 +446,8 @@ * the device structure. */ -__initfunc(int dfx_probe( - struct device *dev - )) - - { +int __init dfx_probe(struct device *dev) +{ int i; /* used in for loops */ int version_disp; /* was version info string already displayed? */ int port_len; /* length of port address range (in bytes) */ @@ -641,12 +638,8 @@ * None */ -__initfunc(struct device *dfx_alloc_device( - struct device *dev, - u16 iobase - )) - - { +struct device __init *dfx_alloc_device( struct device *dev, u16 iobase) +{ struct device *tmp_dev; /* pointer to a device structure */ DBG_printk("In dfx_alloc_device...\n"); @@ -736,11 +729,8 @@ * enabled yet. */ -__initfunc(void dfx_bus_init( - struct device *dev - )) - - { +void __init dfx_bus_init(struct device *dev) +{ DFX_board_t *bp = (DFX_board_t *)dev->priv; u8 val; /* used for I/O read/writes */ @@ -871,11 +861,8 @@ * None */ -__initfunc(void dfx_bus_config_check( - DFX_board_t *bp - )) - - { +void __init dfx_bus_config_check(DFX_board_t *bp) +{ int status; /* return code from adapter port control call */ u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */ u32 host_data; /* LW data returned from port control call */ @@ -975,11 +962,8 @@ * returning from this routine. */ -__initfunc(int dfx_driver_init( - struct device *dev - )) - - { +int __init dfx_driver_init(struct device *dev) +{ DFX_board_t *bp = (DFX_board_t *)dev->priv; int alloc_size; /* total buffer size needed */ char *top_v, *curr_v; /* virtual addrs into memory block */ diff -u --recursive --new-file v2.3.9/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.3.9/linux/drivers/net/depca.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/net/depca.c Tue Jul 6 19:05:49 1999 @@ -476,10 +476,8 @@ outw(CSR0, DEPCA_ADDR);\ outw(STOP, DEPCA_DATA) - - -__initfunc(int -depca_probe(struct device *dev)) +int __init +depca_probe(struct device *dev) { int tmp = num_depcas, status = -ENODEV; u_long iobase = dev->base_addr; @@ -512,8 +510,8 @@ return status; } -__initfunc(static int -depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot)) +static int __init +depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot) { struct depca_private *lp; int i, j, offset, netRAM, mem_len, status=0; @@ -1250,8 +1248,8 @@ /* ** Microchannel bus I/O device probe */ -__initfunc(static void -mca_probe(struct device *dev, u_long ioaddr)) +static void __init +mca_probe(struct device *dev, u_long ioaddr) { unsigned char pos[2]; unsigned char where; @@ -1399,8 +1397,8 @@ /* ** ISA bus I/O device probe */ -__initfunc(static void -isa_probe(struct device *dev, u_long ioaddr)) +static void __init +isa_probe(struct device *dev, u_long ioaddr) { int i = num_depcas, maxSlots; s32 ports[] = DEPCA_IO_PORTS; @@ -1438,8 +1436,8 @@ ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. Upto 15 EISA devices are supported. */ -__initfunc(static void -eisa_probe(struct device *dev, u_long ioaddr)) +static void __init +eisa_probe(struct device *dev, u_long ioaddr) { int i, maxSlots; u_long iobase; @@ -1485,8 +1483,8 @@ ** are not available then insert a new device structure at the end of ** the current list. */ -__initfunc(static struct device * -alloc_device(struct device *dev, u_long iobase)) +static struct device * __init +alloc_device(struct device *dev, u_long iobase) { struct device *adev = NULL; int fixed = 0, new_dev = 0; @@ -1530,8 +1528,8 @@ ** If at end of eth device list and can't use current entry, malloc ** one up. If memory could not be allocated, print an error message. */ -__initfunc(static struct device * -insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))) +static struct device * __init +insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)) { struct device *new; @@ -1556,8 +1554,8 @@ return dev; } -__initfunc(static int -depca_dev_index(char *s)) +static int __init +depca_dev_index(char *s) { int i=0, j=0; @@ -1576,8 +1574,8 @@ ** and Boot (readb) ROM. This will also give us a clue to the network RAM ** base address. */ -__initfunc(static void -DepcaSignature(char *name, u_long paddr)) +static void __init +DepcaSignature(char *name, u_long paddr) { u_int i,j,k; const char *signatures[] = DEPCA_SIGNATURE; @@ -1629,8 +1627,8 @@ ** PROM address counter is correctly positioned at the start of the ** ethernet address for later read out. */ -__initfunc(static int -DevicePresent(u_long ioaddr)) +static int __init +DevicePresent(u_long ioaddr) { union { struct { @@ -1682,8 +1680,8 @@ ** reason: access the upper half of the PROM with x=0; access the lower half ** with x=1. */ -__initfunc(static int -get_hw_addr(struct device *dev)) +static int __init +get_hw_addr(struct device *dev) { u_long ioaddr = dev->base_addr; int i, k, tmp, status = 0; @@ -1771,8 +1769,8 @@ /* ** Look for a particular board name in the EISA configuration space */ -__initfunc(static int -EISA_signature(char *name, s32 eisa_id)) +static int __init +EISA_signature(char *name, s32 eisa_id) { u_int i; const char *signatures[] = DEPCA_SIGNATURE; diff -u --recursive --new-file v2.3.9/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.3.9/linux/drivers/net/dgrs.c Tue Dec 29 11:32:06 1998 +++ linux/drivers/net/dgrs.c Tue Jul 6 19:05:49 1999 @@ -991,8 +991,8 @@ /* * Download the board firmware */ -__initfunc(static int -dgrs_download(struct device *dev0)) +static int __init +dgrs_download(struct device *dev0) { DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; int is; @@ -1150,8 +1150,8 @@ /* * Probe (init) a board */ -__initfunc(int -dgrs_probe1(struct device *dev)) +int __init +dgrs_probe1(struct device *dev) { DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; int i; @@ -1224,8 +1224,8 @@ return (0); } -__initfunc(int -dgrs_initclone(struct device *dev)) +int __init +dgrs_initclone(struct device *dev) { DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; int i; @@ -1239,7 +1239,7 @@ return (0); } -__initfunc(static int +static int __init dgrs_found_device( struct device *dev, int io, @@ -1247,7 +1247,7 @@ int irq, ulong plxreg, ulong plxdma -)) +) { DGRS_PRIV *priv; @@ -1360,8 +1360,8 @@ */ static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 }; -__initfunc(static int -dgrs_scan(struct device *dev)) +static int __init +dgrs_scan(struct device *dev) { int cards_found = 0; uint io; @@ -1614,8 +1614,8 @@ #else -__initfunc(int -dgrs_probe(struct device *dev)) +int __init +dgrs_probe(struct device *dev) { int cards_found; diff -u --recursive --new-file v2.3.9/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.3.9/linux/drivers/net/dlci.c Wed May 6 10:56:04 1998 +++ linux/drivers/net/dlci.c Tue Jul 6 19:05:49 1999 @@ -601,7 +601,7 @@ return(0); } -__initfunc(int dlci_setup(void)) +int __init dlci_setup(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/dummy.c linux/drivers/net/dummy.c --- v2.3.9/linux/drivers/net/dummy.c Sun Oct 4 10:21:00 1998 +++ linux/drivers/net/dummy.c Tue Jul 6 19:05:49 1999 @@ -80,7 +80,7 @@ } #endif -__initfunc(int dummy_init(struct device *dev)) +int __init dummy_init(struct device *dev) { /* Initialize the device structure. */ dev->hard_start_xmit = dummy_xmit; @@ -127,7 +127,7 @@ #ifdef MODULE -__initfunc(static int dummy_probe(struct device *dev)) +static int __init dummy_probe(struct device *dev) { dummy_init(dev); return 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v2.3.9/linux/drivers/net/e2100.c Wed Dec 16 13:35:49 1998 +++ linux/drivers/net/e2100.c Tue Jul 6 19:05:49 1999 @@ -117,7 +117,7 @@ station address). */ -__initfunc(int e2100_probe(struct device *dev)) +int __init e2100_probe(struct device *dev) { int *port; int base_addr = dev->base_addr; @@ -137,7 +137,7 @@ return ENODEV; } -__initfunc(int e21_probe1(struct device *dev, int ioaddr)) +int __init e21_probe1(struct device *dev, int ioaddr) { int i, status; unsigned char *station_addr = dev->dev_addr; diff -u --recursive --new-file v2.3.9/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.3.9/linux/drivers/net/eepro100.c Sat Feb 6 12:46:21 1999 +++ linux/drivers/net/eepro100.c Mon Jul 5 20:09:40 1999 @@ -41,7 +41,7 @@ static int max_interrupt_work = 200; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ -static int multicast_filter_limit = 64; +static int multicast_filter_limit = 3; #include @@ -343,7 +343,8 @@ const char *product_name; struct device *next_module; spinlock_t lock; - struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */ + struct TxFD tx_ring[TX_RING_SIZE] /* Commands (usually CmdTxPacket). */ + __attribute__ ((aligned (L1_CACHE_BYTES)));; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct descriptor *last_cmd; /* Last command sent. */ diff -u --recursive --new-file v2.3.9/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.3.9/linux/drivers/net/eexpress.c Sun May 30 10:18:49 1999 +++ linux/drivers/net/eexpress.c Tue Jul 6 19:05:49 1999 @@ -325,7 +325,7 @@ * checks for presence of EtherExpress card */ -__initfunc(int express_probe(struct device *dev)) +int __init express_probe(struct device *dev) { unsigned short *port; static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 }; @@ -961,7 +961,7 @@ * than one card in a machine. */ -__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)) +static int __init eexp_hw_probe(struct device *dev, unsigned short ioaddr) { unsigned short hw_addr[3]; unsigned char buswidth; @@ -1084,8 +1084,8 @@ * Read a word from the EtherExpress on-board serial EEPROM. * The EEPROM contains 64 words of 16 bits. */ -__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, - unsigned char location)) +static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr, + unsigned char location) { unsigned short cmd = 0x180|(location&0x7f); unsigned short rval = 0,wval = EC_CS|i586_RST; diff -u --recursive --new-file v2.3.9/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.3.9/linux/drivers/net/eql.c Mon May 10 13:00:10 1999 +++ linux/drivers/net/eql.c Mon Jul 5 20:09:40 1999 @@ -209,7 +209,7 @@ --------------------------------------------------------- */ -__initfunc(int eql_init(struct device *dev)) +int __init eql_init(struct device *dev) { static unsigned version_printed = 0; /* static unsigned num_masters = 0; */ @@ -411,16 +411,15 @@ slaving_request_t srq; int err; - err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t)); + err = copy_from_user(&srq, srqp, sizeof (slaving_request_t)); if (err) { #ifdef EQL_DEBUG if (eql_debug >= 20) - printk ("EQL enslave: error detected by verify_area\n"); + printk ("EQL enslave: error detected by copy_from_user\n"); #endif return err; } - copy_from_user (&srq, srqp, sizeof (slaving_request_t)); #ifdef EQL_DEBUG if (eql_debug >= 20) @@ -473,11 +472,10 @@ slaving_request_t srq; int err; - err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t)); + err = copy_from_user(&srq, srqp, sizeof (slaving_request_t)); if (err) return err; - copy_from_user (&srq, srqp, sizeof (slaving_request_t)); #ifdef EQL_DEBUG if (eql_debug >= 20) printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name); @@ -504,11 +502,10 @@ slave_config_t sc; int err; - err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t)); + err = copy_from_user (&sc, scp, sizeof (slave_config_t)); if (err) return err; - copy_from_user (&sc, scp, sizeof (slave_config_t)); #ifdef EQL_DEBUG if (eql_debug >= 20) printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name); @@ -541,7 +538,7 @@ slave_config_t sc; int err; - err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t)); + err = copy_from_user (&sc, scp, sizeof (slave_config_t)); if (err) return err; @@ -550,7 +547,6 @@ printk ("%s: set config for slave `%s'\n", dev->name, sc.slave_name); #endif - copy_from_user (&sc, scp, sizeof (slave_config_t)); eql = (equalizer_t *) dev->priv; slave_dev = dev_get (sc.slave_name); @@ -583,13 +579,12 @@ if ( eql_is_master (dev) ) { int err; - err = verify_area(VERIFY_WRITE, (void *)mcp, sizeof (master_config_t)); - if (err) - return err; eql = (equalizer_t *) dev->priv; mc.max_slaves = eql->max_slaves; mc.min_slaves = eql->min_slaves; - copy_to_user (mcp, &mc, sizeof (master_config_t)); + err = copy_to_user (mcp, &mc, sizeof (master_config_t)); + if (err) + return err; return 0; } return -EINVAL; @@ -602,14 +597,13 @@ master_config_t mc; int err; - err = verify_area(VERIFY_READ, (void *)mcp, sizeof (master_config_t)); + err = copy_from_user (&mc, mcp, sizeof (master_config_t)); if (err) return err; #if EQL_DEBUG if (eql_debug >= 20) printk ("%s: set master config\n", dev->name); #endif - copy_from_user (&mc, mcp, sizeof (master_config_t)); if ( eql_is_master (dev) ) { eql = (equalizer_t *) dev->priv; diff -u --recursive --new-file v2.3.9/linux/drivers/net/es3210.c linux/drivers/net/es3210.c --- v2.3.9/linux/drivers/net/es3210.c Wed Dec 16 13:35:49 1998 +++ linux/drivers/net/es3210.c Tue Jul 6 19:05:49 1999 @@ -124,7 +124,7 @@ * PROM for a match against the Racal-Interlan assigned value. */ -__initfunc(int es_probe(struct device *dev)) +int __init es_probe(struct device *dev) { unsigned short ioaddr = dev->base_addr; @@ -151,7 +151,7 @@ return ENODEV; } -__initfunc(int es_probe1(struct device *dev, int ioaddr)) +int __init es_probe1(struct device *dev, int ioaddr) { int i; unsigned long eisa_id; diff -u --recursive --new-file v2.3.9/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.3.9/linux/drivers/net/eth16i.c Thu Jan 7 08:46:59 1999 +++ linux/drivers/net/eth16i.c Mon Jul 5 20:09:40 1999 @@ -450,7 +450,7 @@ #else /* Not HAVE_DEVLIST */ -__initfunc(int eth16i_probe(struct device *dev)) +int __init eth16i_probe(struct device *dev) { int i; int ioaddr; @@ -484,7 +484,7 @@ } #endif /* Not HAVE_DEVLIST */ -__initfunc(static int eth16i_probe1(struct device *dev, int ioaddr)) +static int __init eth16i_probe1(struct device *dev, int ioaddr) { static unsigned version_printed = 0; boot = 1; /* To inform initilization that we are in boot probe */ @@ -886,7 +886,7 @@ creg[0] &= 0x0F; /* Mask collision cnr */ creg[2] &= 0x7F; /* Mask DCLEN bit */ -#ifdef 0 +#if 0 /* This was removed because the card was sometimes left to state from which it couldn't be find anymore. If there is need diff -u --recursive --new-file v2.3.9/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c --- v2.3.9/linux/drivers/net/ethertap.c Tue May 11 08:24:31 1999 +++ linux/drivers/net/ethertap.c Tue Jul 6 19:05:49 1999 @@ -65,7 +65,7 @@ * hardware it would have to check what was present. */ -__initfunc(int ethertap_probe(struct device *dev)) +int __init ethertap_probe(struct device *dev) { memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6); if (dev->mem_start & 0xf) diff -u --recursive --new-file v2.3.9/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.3.9/linux/drivers/net/ewrk3.c Thu May 21 14:24:06 1998 +++ linux/drivers/net/ewrk3.c Mon Jul 5 20:09:40 1999 @@ -342,11 +342,8 @@ outb(EEPROM_INIT, EWRK3_IOPR);\ mdelay(1);\ } - - - -__initfunc(int ewrk3_probe(struct device *dev)) +int __init ewrk3_probe(struct device *dev) { int tmp = num_ewrk3s, status = -ENODEV; u_long iobase = dev->base_addr; @@ -378,8 +375,8 @@ return status; } -__initfunc(static int - ewrk3_hw_init(struct device *dev, u_long iobase)) +static int __init +ewrk3_hw_init(struct device *dev, u_long iobase) { struct ewrk3_private *lp; int i, status = 0; @@ -1285,7 +1282,7 @@ /* ** ISA bus I/O device probe */ -__initfunc(static void isa_probe(struct device *dev, u_long ioaddr)) +static void __init isa_probe(struct device *dev, u_long ioaddr) { int i = num_ewrk3s, maxSlots; u_long iobase; @@ -1325,7 +1322,7 @@ ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. */ -__initfunc(static void eisa_probe(struct device *dev, u_long ioaddr)) +static void __init eisa_probe(struct device *dev, u_long ioaddr) { int i, maxSlots; u_long iobase; @@ -1372,8 +1369,8 @@ ** are not available then insert a new device structure at the end of ** the current list. */ -__initfunc(static struct device * - alloc_device(struct device *dev, u_long iobase)) +static struct device * __init +alloc_device(struct device *dev, u_long iobase) { struct device *adev = NULL; int fixed = 0, new_dev = 0; @@ -1417,8 +1414,8 @@ ** If at end of eth device list and can't use current entry, malloc ** one up. If memory could not be allocated, print an error message. */ -__initfunc(static struct device * - insert_device(struct device *dev, u_long iobase, int (*init) (struct device *))) +static __init struct device * +insert_device(struct device *dev, u_long iobase, int (*init) (struct device *)) { struct device *new; @@ -1443,8 +1440,8 @@ return dev; } -__initfunc(static int - ewrk3_dev_index(char *s)) +static int __init +ewrk3_dev_index(char *s) { int i = 0, j = 0; @@ -1499,7 +1496,7 @@ /* ** Look for a particular board name in the on-board EEPROM. */ -__initfunc(static void EthwrkSignature(char *name, char *eeprom_image)) +static void __init EthwrkSignature(char *name, char *eeprom_image) { u_long i, j, k; char *signatures[] = EWRK3_SIGNATURE; @@ -1536,7 +1533,7 @@ ** ethernet address for later read out. */ -__initfunc(static int DevicePresent(u_long iobase)) +static int __init DevicePresent(u_long iobase) { union { struct { @@ -1573,7 +1570,7 @@ return status; } -__initfunc(static u_char get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType)) +static u_char __init get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType) { int i, j, k; u_short chksum; @@ -1624,7 +1621,7 @@ /* ** Look for a particular board name in the EISA configuration space */ -__initfunc(static int EISA_signature(char *name, s32 eisa_id)) +static int __init EISA_signature(char *name, s32 eisa_id) { u_long i; char *signatures[] = EWRK3_SIGNATURE; @@ -1679,18 +1676,20 @@ tmp.addr[i] = dev->dev_addr[i]; } ioc->len = ETH_ALEN; - if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) { + status = -EFAULT; + break; } - break; case EWRK3_SET_HWADDR: /* Set the hardware address */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) { csr = inb(EWRK3_CSR); csr |= (CSR_TXD | CSR_RXD); outb(csr, EWRK3_CSR); /* Disable the TX and RX */ - copy_from_user(tmp.addr, ioc->data, ETH_ALEN); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) { + status = -EFAULT; + break; + } for (i = 0; i < ETH_ALEN; i++) { dev->dev_addr[i] = tmp.addr[i]; outb(tmp.addr[i], EWRK3_PAR0 + i); @@ -1698,7 +1697,6 @@ csr &= ~(CSR_TXD | CSR_RXD); /* Enable the TX and RX */ outb(csr, EWRK3_CSR); - } } else { status = -EPERM; } @@ -1730,7 +1728,6 @@ break; case EWRK3_GET_MCA: /* Get the multicast address table */ - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); @@ -1743,17 +1740,21 @@ memcpy_fromio(tmp.addr, (char *) (lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3)); } ioc->len = (HASH_TABLE_LEN >> 3); - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) { + status = -EFAULT; + break; + } + lp->lock = 0; /* Unlock the page register */ break; case EWRK3_SET_MCA: /* Set a multicast address */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) { - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); - set_multicast_list(dev); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) { + status = -EFAULT; + break; } + set_multicast_list(dev); } else { status = -EPERM; } @@ -1781,9 +1782,8 @@ case EWRK3_GET_STATS: /* Get the driver statistics */ cli(); ioc->len = sizeof(lp->pktStats); - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - } + if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) + status = -EFAULT; sti(); break; @@ -1800,16 +1800,16 @@ case EWRK3_GET_CSR: /* Get the CSR Register contents */ tmp.addr[0] = inb(EWRK3_CSR); ioc->len = 1; - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + status = -EFAULT; break; case EWRK3_SET_CSR: /* Set the CSR Register contents */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, ioc->data, 1))) { - copy_from_user(tmp.addr, ioc->data, 1); - outb(tmp.addr[0], EWRK3_CSR); + if (copy_from_user(tmp.addr, ioc->data, 1)) { + status = -EFAULT; + break; } + outb(tmp.addr[0], EWRK3_CSR); } else { status = -EPERM; } @@ -1826,9 +1826,8 @@ tmp.addr[i++] = inb(EWRK3_PAR0 + j); } ioc->len = EEPROM_MAX + 1 + ETH_ALEN; - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + status = -EFAULT; } else { status = -EPERM; } @@ -1836,11 +1835,12 @@ break; case EWRK3_SET_EEPROM: /* Set the EEPROM contents */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) { - copy_from_user(tmp.addr, ioc->data, EEPROM_MAX); - for (i = 0; i < (EEPROM_MAX >> 1); i++) { - Write_EEPROM(tmp.val[i], iobase, i); - } + if (copy_from_user(tmp.addr, ioc->data, EEPROM_MAX)) { + status = -EFAULT; + break; + } + for (i = 0; i < (EEPROM_MAX >> 1); i++) { + Write_EEPROM(tmp.val[i], iobase, i); } } else { status = -EPERM; @@ -1850,9 +1850,8 @@ case EWRK3_GET_CMR: /* Get the CMR Register contents */ tmp.addr[0] = inb(EWRK3_CMR); ioc->len = 1; - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + status = -EFAULT; break; case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */ if (suser()) { diff -u --recursive --new-file v2.3.9/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c --- v2.3.9/linux/drivers/net/fmv18x.c Tue Jan 19 10:13:13 1999 +++ linux/drivers/net/fmv18x.c Tue Jul 6 19:05:49 1999 @@ -132,8 +132,8 @@ struct netdev_entry fmv18x_drv = {"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list}; #else -__initfunc(int -fmv18x_probe(struct device *dev)) +int __init +fmv18x_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -163,7 +163,7 @@ that can be done is checking a few bits and then diving right into MAC address check. */ -__initfunc(int fmv18x_probe1(struct device *dev, short ioaddr)) +int __init fmv18x_probe1(struct device *dev, short ioaddr) { char irqmap[4] = {3, 7, 10, 15}; char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15}; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c --- v2.3.9/linux/drivers/net/hamradio/6pack.c Fri Nov 20 08:44:06 1998 +++ linux/drivers/net/hamradio/6pack.c Tue Jul 6 19:05:49 1999 @@ -726,7 +726,7 @@ #ifdef MODULE static int sixpack_init_ctrl_dev(void) #else /* !MODULE */ -__initfunc(int sixpack_init_ctrl_dev(struct device *dummy)) +int __init sixpack_init_ctrl_dev(struct device *dummy) #endif /* !MODULE */ { int status; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c --- v2.3.9/linux/drivers/net/hamradio/baycom_par.c Fri Oct 9 12:20:27 1998 +++ linux/drivers/net/hamradio/baycom_par.c Tue Jul 6 19:05:49 1999 @@ -533,7 +533,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(int baycom_par_init(void)) +int __init baycom_par_init(void) { int i, j, found = 0; char set_hw = 1; @@ -593,7 +593,7 @@ #endif -__initfunc(int init_module(void)) +int __init init_module(void) { int i; @@ -633,7 +633,7 @@ * mode: par96,picpar */ -__initfunc(void baycom_par_setup(char *str, int *ints)) +void __init baycom_par_setup(char *str, int *ints) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c --- v2.3.9/linux/drivers/net/hamradio/baycom_ser_fdx.c Sun Jan 17 18:28:06 1999 +++ linux/drivers/net/hamradio/baycom_ser_fdx.c Tue Jul 6 19:05:49 1999 @@ -605,7 +605,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(int baycom_ser_fdx_init(void)) +int __init baycom_ser_fdx_init(void) { int i, j, found = 0; char set_hw = 1; @@ -673,7 +673,7 @@ #endif -__initfunc(int init_module(void)) +int __init init_module(void) { int i; @@ -716,7 +716,7 @@ * * indicates sofware DCD */ -__initfunc(void baycom_ser_fdx_setup(char *str, int *ints)) +void __init baycom_ser_fdx_setup(char *str, int *ints) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c --- v2.3.9/linux/drivers/net/hamradio/baycom_ser_hdx.c Sun Jan 17 18:28:06 1999 +++ linux/drivers/net/hamradio/baycom_ser_hdx.c Tue Jul 6 19:05:49 1999 @@ -643,7 +643,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(int baycom_ser_hdx_init(void)) +int __init baycom_ser_hdx_init(void) { int i, j, found = 0; char set_hw = 1; @@ -707,7 +707,7 @@ #endif -__initfunc(int init_module(void)) +int __init init_module(void) { int i; @@ -749,7 +749,7 @@ * * indicates sofware DCD */ -__initfunc(void baycom_ser_hdx_setup(char *str, int *ints)) +void __init baycom_ser_hdx_setup(char *str, int *ints) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c --- v2.3.9/linux/drivers/net/hamradio/bpqether.c Tue May 25 13:06:34 1999 +++ linux/drivers/net/hamradio/bpqether.c Tue Jul 6 19:05:49 1999 @@ -621,7 +621,7 @@ * Initialize driver. To be called from af_ax25 if not compiled as a * module */ -__initfunc(int bpq_init(void)) +int __init bpq_init(void) { struct device *dev; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c --- v2.3.9/linux/drivers/net/hamradio/dmascc.c Fri Oct 9 11:56:59 1998 +++ linux/drivers/net/hamradio/dmascc.c Tue Jul 6 19:05:49 1999 @@ -336,7 +336,7 @@ #else -__initfunc(void dmascc_setup(char *str, int *ints)) +void __init dmascc_setup(char *str, int *ints) { int i; @@ -350,7 +350,7 @@ /* Initialization functions */ -__initfunc(int dmascc_init(void)) +int __init dmascc_init(void) { int h, i, j, n; int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], @@ -453,8 +453,7 @@ return -EIO; } - -__initfunc(int setup_adapter(int io, int h, int n)) +int __init setup_adapter(int io, int h, int n) { int i, irq, chip; struct scc_info *info; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c --- v2.3.9/linux/drivers/net/hamradio/hdlcdrv.c Tue Dec 29 11:30:56 1998 +++ linux/drivers/net/hamradio/hdlcdrv.c Tue Jul 6 19:05:49 1999 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -936,7 +935,7 @@ /* --------------------------------------------------------------------- */ -__initfunc(int init_module(void)) +int __init init_module(void) { printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n"); printk(KERN_INFO "hdlcdrv: version 0.6 compiled " __TIME__ " " __DATE__ "\n"); diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c --- v2.3.9/linux/drivers/net/hamradio/mkiss.c Fri Nov 13 10:29:44 1998 +++ linux/drivers/net/hamradio/mkiss.c Tue Jul 6 19:05:50 1999 @@ -937,7 +937,7 @@ } /* Initialize AX25 control device -- register AX25 line discipline */ -__initfunc(int mkiss_init_ctrl_dev(void)) +int __init mkiss_init_ctrl_dev(void) { int status; @@ -1154,7 +1154,7 @@ /* * Init MKISS driver * */ /* ******************************************************************** */ -__initfunc(static int mkiss_init(void)) +static int __init mkiss_init(void) { memset(&mkiss_driver, 0, sizeof(struct tty_driver)); diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/pi2.c linux/drivers/net/hamradio/pi2.c --- v2.3.9/linux/drivers/net/hamradio/pi2.c Tue Feb 10 13:07:50 1998 +++ linux/drivers/net/hamradio/pi2.c Tue Jul 6 19:05:50 1999 @@ -927,7 +927,7 @@ /* Probe for a PI card. */ /* This routine also initializes the timer chip */ -__initfunc(static int hw_probe(int ioaddr)) +static int __init hw_probe(int ioaddr) { int time = 1000; /* Number of milliseconds for test */ unsigned long start_time, end_time; @@ -1182,7 +1182,7 @@ } -__initfunc(int pi_init(void)) +int __init pi_init(void) { int *port; int ioaddr = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/pt.c linux/drivers/net/hamradio/pt.c --- v2.3.9/linux/drivers/net/hamradio/pt.c Tue Feb 10 13:07:50 1998 +++ linux/drivers/net/hamradio/pt.c Tue Jul 6 19:05:50 1999 @@ -474,8 +474,7 @@ } /* chipset_init() */ - -__initfunc(int pt_init(void)) +int __init pt_init(void) { int *port; int ioaddr = 0; @@ -537,7 +536,7 @@ /* * Probe for PT card. Also initialises the timers */ -__initfunc(static int hw_probe(int ioaddr)) +static int __init hw_probe(int ioaddr) { int time = 1000; /* Number of milliseconds to test */ int a = 1; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c --- v2.3.9/linux/drivers/net/hamradio/scc.c Fri Dec 18 13:57:21 1998 +++ linux/drivers/net/hamradio/scc.c Tue Jul 6 19:05:50 1999 @@ -2193,7 +2193,7 @@ /* * Init SCC driver * */ /* ******************************************************************** */ -__initfunc(int scc_init (void)) +int __init scc_init (void) { int chip, chan, k, result; char devname[10]; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c --- v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.c Sun Jan 17 18:28:06 1999 +++ linux/drivers/net/hamradio/soundmodem/sm.c Tue Jul 6 19:05:50 1999 @@ -640,9 +640,9 @@ /* --------------------------------------------------------------------- */ #ifdef MODULE -__initfunc(static int sm_init(void)) +static int __init sm_init(void) #else /* MODULE */ -__initfunc(int sm_init(void)) +int __init sm_init(void) #endif /* MODULE */ { int i, j, found = 0; @@ -724,7 +724,7 @@ #endif -__initfunc(int init_module(void)) +int __init init_module(void) { if (mode) { if (iobase == -1) @@ -778,7 +778,7 @@ * modem: afsk1200, fsk9600 */ -__initfunc(void sm_setup(char *str, int *ints)) +void __init sm_setup(char *str, int *ints) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.h linux/drivers/net/hamradio/soundmodem/sm.h --- v2.3.9/linux/drivers/net/hamradio/soundmodem/sm.h Fri Jul 10 14:01:13 1998 +++ linux/drivers/net/hamradio/soundmodem/sm.h Mon Jul 5 20:35:18 1999 @@ -296,8 +296,6 @@ #ifdef __i386__ -#include - #define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC) /* diff -u --recursive --new-file v2.3.9/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c --- v2.3.9/linux/drivers/net/hostess_sv11.c Thu Feb 18 16:28:49 1999 +++ linux/drivers/net/hostess_sv11.c Mon Jul 5 20:09:40 1999 @@ -389,7 +389,8 @@ free_irq(dev->sync.irq, dev); if(dma) { - free_dma(dev->sync.chanA.rxdma); + if(dma==1) + free_dma(dev->sync.chanA.rxdma); free_dma(dev->sync.chanA.txdma); } release_region(dev->sync.chanA.ctrlio-1, 8); diff -u --recursive --new-file v2.3.9/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c --- v2.3.9/linux/drivers/net/hp-plus.c Wed Dec 16 13:35:49 1998 +++ linux/drivers/net/hp-plus.c Tue Jul 6 19:05:50 1999 @@ -123,7 +123,7 @@ {"hpplus", hpp_probe1, HP_IO_EXTENT, hpplus_portlist}; #else -__initfunc(int hp_plus_probe(struct device *dev)) +int __init hp_plus_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -146,7 +146,7 @@ #endif /* Do the interesting part of the probe at a single address. */ -__initfunc(int hpp_probe1(struct device *dev, int ioaddr)) +int __init hpp_probe1(struct device *dev, int ioaddr) { int i; unsigned char checksum = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v2.3.9/linux/drivers/net/hp.c Wed Dec 16 13:35:49 1998 +++ linux/drivers/net/hp.c Tue Jul 6 19:05:50 1999 @@ -84,7 +84,7 @@ {"hp", hp_probe1, HP_IO_EXTENT, hppclan_portlist}; #else -__initfunc(int hp_probe(struct device *dev)) +int __init hp_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -106,7 +106,7 @@ } #endif -__initfunc(int hp_probe1(struct device *dev, int ioaddr)) +int __init hp_probe1(struct device *dev, int ioaddr) { int i, board_id, wordmode; const char *name; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.3.9/linux/drivers/net/hp100.c Mon Jan 11 10:55:29 1999 +++ linux/drivers/net/hp100.c Tue Jul 6 19:05:50 1999 @@ -106,6 +106,7 @@ #include #include /* for CONFIG_PCI */ #include +#include #if LINUX_VERSION_CODE >= 0x020100 #define LINUX_2_1 @@ -347,7 +348,7 @@ * since this could cause problems when the card is not installed. */ -__initfunc(int hp100_probe( struct device *dev )) +int __init hp100_probe( struct device *dev ) { int base_addr = dev ? dev -> base_addr : 0; int ioaddr = 0; @@ -524,9 +525,9 @@ #ifdef LINUX_2_1 -__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev )) +static int __init hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev ) #else -__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn )) +static int __init hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ) #endif { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hplance.c linux/drivers/net/hplance.c --- v2.3.9/linux/drivers/net/hplance.c Thu Jun 25 11:03:42 1998 +++ linux/drivers/net/hplance.c Tue Jul 6 19:05:50 1999 @@ -67,7 +67,7 @@ #endif /* Find all the HP Lance boards and initialise them... */ -__initfunc(int hplance_probe(struct device *dev)) +int __init hplance_probe(struct device *dev) { int cards = 0, called = 0; @@ -98,7 +98,7 @@ } /* Initialise a single lance board at the given select code */ -__initfunc (static int hplance_init(struct device *dev, int scode)) +static int __init hplance_init(struct device *dev, int scode) { /* const char *name = dio_scodetoname(scode); */ static const char name[] = "HP LANCE"; diff -u --recursive --new-file v2.3.9/linux/drivers/net/hydra.c linux/drivers/net/hydra.c --- v2.3.9/linux/drivers/net/hydra.c Tue Feb 10 12:56:44 1998 +++ linux/drivers/net/hydra.c Tue Jul 6 19:05:50 1999 @@ -157,7 +157,7 @@ #endif -__initfunc(int hydra_probe(struct device *dev)) +int __init hydra_probe(struct device *dev) { struct hydra_private *priv; u32 board; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.3.9/linux/drivers/net/ibmtr.c Wed Jun 16 19:26:27 1999 +++ linux/drivers/net/ibmtr.c Tue Jul 6 19:05:50 1999 @@ -138,11 +138,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -173,7 +171,7 @@ "ISA", "MCA", "ISA P&P" }; -__initfunc(char *adapter_def(char type)) +char __init *adapter_def(char type) { switch (type) { @@ -223,7 +221,7 @@ static __u32 ibmtr_mem_base = 0xd0000; -__initfunc(static void PrtChanID(char *pcid, short stride) ) +static void __init PrtChanID(char *pcid, short stride) { short i, j; for (i=0, j=0; i<24; i++, j+=stride) @@ -231,7 +229,7 @@ printk("\n"); } -__initfunc(static void HWPrtChanID (__u32 pcid, short stride)) +static void __init HWPrtChanID (__u32 pcid, short stride) { short i, j; for (i=0, j=0; i<24; i++, j+=stride) @@ -252,7 +250,7 @@ * which references it. */ -__initfunc(int ibmtr_probe(struct device *dev)) +int __init ibmtr_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -295,7 +293,7 @@ return -ENODEV; } -__initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) +static int __init ibmtr_probe1(struct device *dev, int PIOaddr) { unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0; __u32 t_mmio=0; @@ -750,7 +748,7 @@ /* query the adapter for the size of shared RAM */ -__initfunc(static unsigned char get_sram_size(struct tok_info *adapt_info)) +static unsigned char __init get_sram_size(struct tok_info *adapt_info) { unsigned char avail_sram_code; @@ -769,7 +767,7 @@ return 1<<((readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4); } -__initfunc(static int trdev_init(struct device *dev)) +static int __init trdev_init(struct device *dev) { struct tok_info *ti=(struct tok_info *)dev->priv; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/actisys.c linux/drivers/net/irda/actisys.c --- v2.3.9/linux/drivers/net/irda/actisys.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/actisys.c Tue Jul 6 19:05:49 1999 @@ -61,7 +61,7 @@ actisys_init_qos, }; -__initfunc(int actisys_init(void)) +int __init actisys_init(void) { int ret; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/esi.c linux/drivers/net/irda/esi.c --- v2.3.9/linux/drivers/net/irda/esi.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/esi.c Tue Jul 6 19:05:49 1999 @@ -52,7 +52,7 @@ esi_qos_init, }; -__initfunc(int esi_init(void)) +int __init esi_init(void) { return irda_device_register_dongle(&dongle); } diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/girbil.c linux/drivers/net/irda/girbil.c --- v2.3.9/linux/drivers/net/irda/girbil.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/girbil.c Tue Jul 6 19:05:49 1999 @@ -76,7 +76,7 @@ girbil_init_qos, }; -__initfunc(int girbil_init(void)) +int __init girbil_init(void) { return irda_device_register_dongle(&dongle); } diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c --- v2.3.9/linux/drivers/net/irda/irport.c Wed Jun 16 19:26:27 1999 +++ linux/drivers/net/irda/irport.c Tue Jul 6 19:05:49 1999 @@ -86,7 +86,7 @@ static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts); static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len); -__initfunc(int irport_init(void)) +int __init irport_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c --- v2.3.9/linux/drivers/net/irda/irtty.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/net/irda/irtty.c Tue Jul 6 19:05:49 1999 @@ -64,7 +64,7 @@ char *, int); char *driver_name = "irtty"; -__initfunc(int irtty_init(void)) +int __init irtty_init(void) { int status; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/litelink.c linux/drivers/net/irda/litelink.c --- v2.3.9/linux/drivers/net/irda/litelink.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/litelink.c Tue Jul 6 19:05:49 1999 @@ -60,7 +60,7 @@ litelink_init_qos, }; -__initfunc(int litelink_init(void)) +int __init litelink_init(void) { return irda_device_register_dongle(&dongle); } diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/pc87108.c linux/drivers/net/irda/pc87108.c --- v2.3.9/linux/drivers/net/irda/pc87108.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/pc87108.c Tue Jul 6 19:05:49 1999 @@ -127,7 +127,7 @@ * Initialize chip. Just try to find out how many chips we are dealing with * and where they are */ -__initfunc(int pc87108_init(void)) +int __init pc87108_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c --- v2.3.9/linux/drivers/net/irda/smc-ircc.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/smc-ircc.c Tue Jul 6 19:05:49 1999 @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include @@ -102,7 +100,7 @@ * Initialize chip. Just try to find out how many chips we are dealing with * and where they are */ -__initfunc(int ircc_init(void)) +int __init ircc_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/tekram.c linux/drivers/net/irda/tekram.c --- v2.3.9/linux/drivers/net/irda/tekram.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/tekram.c Tue Jul 6 19:05:49 1999 @@ -56,7 +56,7 @@ tekram_init_qos, }; -__initfunc(int tekram_init(void)) +int __init tekram_init(void) { return irda_device_register_dongle(&dongle); } diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.3.9/linux/drivers/net/irda/toshoboe.c Sun May 30 10:27:04 1999 +++ linux/drivers/net/irda/toshoboe.c Mon Jul 5 20:09:40 1999 @@ -568,11 +568,11 @@ self->rxs = inb_p (OBOE_RCVT); self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET; -#ifdef 0 +#if 0 self->rxs = 0; self->txs = 0; #endif -#ifdef 0 +#if 0 self->rxs = RX_SLOTS - 1; self->txs = 0; #endif @@ -838,7 +838,7 @@ return (0); } -__initfunc (int toshoboe_init (void)) +int __init toshoboe_init (void) { struct pci_dev *pci_dev = NULL; int found = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/uircc.c linux/drivers/net/irda/uircc.c --- v2.3.9/linux/drivers/net/irda/uircc.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/uircc.c Tue Jul 6 19:05:49 1999 @@ -36,8 +36,6 @@ #include #include #include -#include -#include #include #include @@ -90,7 +88,7 @@ * Initialize chip. Just try to find out how many chips we are dealing with * and where they are */ -__initfunc(int uircc_init(void)) +int __init uircc_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c --- v2.3.9/linux/drivers/net/irda/w83977af_ir.c Mon Jun 7 16:18:58 1999 +++ linux/drivers/net/irda/w83977af_ir.c Tue Jul 6 19:05:49 1999 @@ -105,7 +105,7 @@ * Initialize chip. Just try to find out how many chips we are dealing with * and where they are */ -__initfunc(int w83977af_init(void)) +int __init w83977af_init(void) { int i; diff -u --recursive --new-file v2.3.9/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.3.9/linux/drivers/net/lance.c Mon Dec 28 11:05:14 1998 +++ linux/drivers/net/lance.c Tue Jul 6 19:05:49 1999 @@ -420,7 +420,7 @@ return -ENODEV; } -__initfunc(int lance_probe1(struct device *dev, int ioaddr, int irq, int options)) +int __init lance_probe1(struct device *dev, int ioaddr, int irq, int options) { struct lance_private *lp; short dma_channels; /* Mark spuriously-busy DMA channels */ @@ -499,6 +499,8 @@ lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, GFP_DMA | GFP_KERNEL)+7) & ~7); + if(lp==NULL) + return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); memset(lp, 0, sizeof(*lp)); dev->priv = lp; diff -u --recursive --new-file v2.3.9/linux/drivers/net/lne390.c linux/drivers/net/lne390.c --- v2.3.9/linux/drivers/net/lne390.c Wed Dec 16 13:35:49 1998 +++ linux/drivers/net/lne390.c Tue Jul 6 19:08:33 1999 @@ -100,7 +100,7 @@ * PROM for a match against the value assigned to Mylex. */ -__initfunc(int lne390_probe(struct device *dev)) +int __init lne390_probe(struct device *dev) { unsigned short ioaddr = dev->base_addr; @@ -127,7 +127,7 @@ return ENODEV; } -__initfunc(int lne390_probe1(struct device *dev, int ioaddr)) +int __init lne390_probe1(struct device *dev, int ioaddr) { int i, revision; unsigned long eisa_id; diff -u --recursive --new-file v2.3.9/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.3.9/linux/drivers/net/loopback.c Thu Jun 11 22:52:33 1998 +++ linux/drivers/net/loopback.c Tue Jul 6 19:08:33 1999 @@ -114,7 +114,7 @@ } /* Initialize the rest of the LOOPBACK device. */ -__initfunc(int loopback_init(struct device *dev)) +int __init loopback_init(struct device *dev) { dev->mtu = LOOPBACK_MTU; dev->tbusy = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.3.9/linux/drivers/net/ltpc.c Fri Jan 15 14:36:21 1999 +++ linux/drivers/net/ltpc.c Tue Jul 6 19:08:33 1999 @@ -1018,7 +1018,7 @@ /* initialization stuff */ -__initfunc(int ltpc_probe_dma(int base)) +int __init ltpc_probe_dma(int base) { int dma = 0; int timeout; @@ -1088,7 +1088,7 @@ return dma; } -__initfunc(int ltpc_probe(struct device *dev)) +int __init ltpc_probe(struct device *dev) { int err; int x=0,y=0; @@ -1250,7 +1250,7 @@ } /* handles "ltpc=io,irq,dma" kernel command lines */ -__initfunc(void ltpc_setup(char *str, int *ints)) +void __init ltpc_setup(char *str, int *ints) { if (ints[0] == 0) { if (str && !strncmp(str, "auto", 4)) { diff -u --recursive --new-file v2.3.9/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.3.9/linux/drivers/net/myri_sbus.c Wed Jun 9 14:45:36 1999 +++ linux/drivers/net/myri_sbus.c Tue Jul 6 19:08:33 1999 @@ -1074,7 +1074,7 @@ return 0; } -__initfunc(int myri_sbus_probe(struct device *dev)) +int __init myri_sbus_probe(struct device *dev) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.3.9/linux/drivers/net/ne.c Sun Mar 7 15:47:46 1999 +++ linux/drivers/net/ne.c Tue Jul 6 19:08:33 1999 @@ -177,7 +177,7 @@ * the card. */ -__initfunc(int ne_probe(struct device *dev)) +int __init ne_probe(struct device *dev) { int base_addr = dev ? dev->base_addr : 0; @@ -209,7 +209,7 @@ #endif #ifdef CONFIG_PCI -__initfunc(static int ne_probe_pci(struct device *dev)) +static int __init ne_probe_pci(struct device *dev) { int i; @@ -243,7 +243,7 @@ } #endif /* CONFIG_PCI */ -__initfunc(static int ne_probe1(struct device *dev, int ioaddr)) +static int __init ne_probe1(struct device *dev, int ioaddr) { int i; unsigned char SA_prom[32]; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne2.c linux/drivers/net/ne2.c --- v2.3.9/linux/drivers/net/ne2.c Wed Mar 10 16:51:35 1999 +++ linux/drivers/net/ne2.c Tue Jul 6 19:08:33 1999 @@ -146,7 +146,7 @@ * Note that at boot, this probe only picks up one card at a time. */ -__initfunc (int ne2_probe(struct device *dev)) +int __init ne2_probe(struct device *dev) { static int current_mca_slot = -1; int i; @@ -198,8 +198,7 @@ return len; } - -__initfunc (static int ne2_probe1(struct device *dev, int slot)) +static int __init ne2_probe1(struct device *dev, int slot) { int i, base_addr, irq; unsigned char POS; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.3.9/linux/drivers/net/ne2k-pci.c Sun Jan 24 22:04:02 1999 +++ linux/drivers/net/ne2k-pci.c Mon Jul 5 20:11:07 1999 @@ -24,11 +24,8 @@ /* Our copyright info must remain in the binary. */ static const char *version = -"ne2k-pci.c:v0.99L 2/7/98 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n"; +"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n"; -#ifdef MODVERSIONS -#include -#endif #include #include #include @@ -44,6 +41,13 @@ #include #include "8390.h" +#if defined(__powerpc__) +#define inl_le(addr) le32_to_cpu(inl(addr)) +#define inw_le(addr) le16_to_cpu(inw(addr)) +#define insl insl_ns +#define outsl outsl_ns +#endif + /* Set statically or when loading the driver module. */ static int debug = 1; @@ -58,19 +62,34 @@ /* 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! */ +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. */ + STOP_PG_0x60=0x100, +}; + +/* This will eventually be converted to the standard PCI probe table. */ + static struct { unsigned short vendor, dev_id; char *name; + int flags; } pci_clone_list[] __initdata = { - {0x10ec, 0x8029, "RealTek RTL-8029"}, - {0x1050, 0x0940, "Winbond 89C940"}, - {0x11f6, 0x1401, "Compex RL2000"}, - {0x8e2e, 0x3000, "KTI ET32P2"}, - {0x4a14, 0x5000, "NetVin NV5000SC"}, - {0x1106, 0x0926, "Via 82C926"}, - {0x10bd, 0x0e34, "SureCom NE34"}, - {0x1050, 0x5a5a, "Winbond"}, + {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,} }; @@ -86,7 +105,8 @@ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ int ne2k_pci_probe(struct device *dev); -static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq); +static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq, + int chip_idx); static int ne2k_pci_open(struct device *dev); static int ne2k_pci_close(struct device *dev); @@ -115,17 +135,13 @@ int init_module(void) { - int retval; - /* We must emit version information. */ if (debug) printk(KERN_INFO "%s", version); - retval = ne2k_pci_probe(0); - - if (retval) { - printk(KERN_NOTICE "ne2k-pci.c: no (useable) cards found, driver NOT installed.\n"); - return retval; + if (ne2k_pci_probe(0)) { + printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n"); + return -ENODEV; } lock_8390_module(); return 0; @@ -170,7 +186,7 @@ {"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0}; #endif -__initfunc (int ne2k_pci_probe(struct device *dev)) +int __init ne2k_pci_probe(struct device *dev) { struct pci_dev *pdev = NULL; int cards_found = 0; @@ -225,7 +241,7 @@ printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n", pci_clone_list[i].name, pci_ioaddr, pci_irq_line); - dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line); + dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line, i); if (dev == 0) { /* Should not happen. */ printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n", @@ -247,11 +263,10 @@ return cards_found ? 0 : -ENODEV; } -__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq)) +static struct device __init *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq, int chip_idx) { int i; unsigned char SA_prom[32]; - const char *name = NULL; int start_page, stop_page; int reg0 = inb(ioaddr); @@ -273,6 +288,8 @@ } } + dev = init_etherdev(dev, 0); + /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; @@ -321,59 +338,47 @@ } -#ifdef notdef - /* Some broken PCI cards don't respect the byte-wide - request in program_seq above, and hence don't have doubled up values. - */ - for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { - SA_prom[i] = inb(ioaddr + NE_DATAPORT); - SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); - if (SA_prom[i] != SA_prom[i+1]) - sa_prom_doubled = 0; - } - - if (sa_prom_doubled) - for (i = 0; i < 16; i++) - SA_prom[i] = SA_prom[i+i]; -#else - for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++) - SA_prom[i] = inb(ioaddr + NE_DATAPORT); + /* 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. */ -#endif + if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) { + for (i = 0; i < 4 ; i++) + ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT)); + } else + for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++) + SA_prom[i] = inb(ioaddr + NE_DATAPORT); /* We always set the 8390 registers for word mode. */ outb(0x49, ioaddr + EN0_DCFG); start_page = NESM_START_PG; - stop_page = NESM_STOP_PG; - /* Set up the rest of the parameters. */ - name = "PCI NE2000"; - - dev = init_etherdev(dev, 0); + stop_page = + pci_clone_list[chip_idx].flags&STOP_PG_0x60 ? 0x60 : NESM_STOP_PG; + /* Set up the rest of the parameters. */ dev->irq = irq; dev->base_addr = ioaddr; /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { printk ("%s: unable to get memory for dev->priv.\n", dev->name); - kfree(dev); return 0; } request_region(ioaddr, NE_IO_EXTENT, dev->name); printk("%s: %s found at %#x, IRQ %d, ", - dev->name, name, ioaddr, dev->irq); + dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); for(i = 0; i < 6; i++) { printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); dev->dev_addr[i] = SA_prom[i]; } - ei_status.name = name; + ei_status.name = pci_clone_list[chip_idx].name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; ei_status.word16 = 1; + ei_status.ne2k_flags = pci_clone_list[chip_idx].flags; ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE @@ -447,9 +452,9 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", + "[DMAstat:%d][irqlock:%d][intr:%d].\n", dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + (int)dev->interrupt); return; } @@ -461,11 +466,12 @@ outb(ring_page, nic_base + EN0_RSARHI); outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); -#if defined(USE_LONGIO) - *(u32*)hdr = inl(NE_BASE + NE_DATAPORT); -#else - insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); -#endif + if (ei_status.ne2k_flags & ONLY_16BIT_IO) { + insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); + } else { + *(u32*)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT)); + le16_to_cpus(&hdr->count); + } outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; @@ -485,12 +491,14 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_block_input " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", + "[DMAstat:%d][irqlock:%d][intr:%d].\n", dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + (int)dev->interrupt); return; } ei_status.dmaing |= 0x01; + if (ei_status.ne2k_flags & ONLY_32BIT_IO) + count = (count + 3) & 0xFFFC; outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); outb(count & 0xff, nic_base + EN0_RCNTLO); outb(count >> 8, nic_base + EN0_RCNTHI); @@ -498,21 +506,21 @@ outb(ring_offset >> 8, nic_base + EN0_RSARHI); outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); -#if defined(USE_LONGIO) - insl(NE_BASE + NE_DATAPORT, buf, count>>2); - if (count & 3) { - buf += count & ~3; - if (count & 2) - *((u16*)buf)++ = inw(NE_BASE + NE_DATAPORT); - if (count & 1) - *buf = inb(NE_BASE + NE_DATAPORT); - } -#else - insw(NE_BASE + NE_DATAPORT,buf,count>>1); - if (count & 0x01) { - buf[count-1] = inb(NE_BASE + NE_DATAPORT); + if (ei_status.ne2k_flags & ONLY_16BIT_IO) { + insw(NE_BASE + NE_DATAPORT,buf,count>>1); + if (count & 0x01) { + buf[count-1] = inb(NE_BASE + NE_DATAPORT); + } + } else { + insl(NE_BASE + NE_DATAPORT, buf, count>>2); + if (count & 3) { + buf += count & ~3; + if (count & 2) + *((u16*)buf)++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT)); + if (count & 1) + *buf = inb(NE_BASE + NE_DATAPORT); + } } -#endif outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; @@ -527,15 +535,18 @@ /* On little-endian it's always safe to round the count up for word writes. */ - if (count & 0x01) - count++; + if (ei_status.ne2k_flags & ONLY_32BIT_IO) + count = (count + 3) & 0xFFFC; + else + if (count & 0x01) + count++; /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_block_output." - "[DMAstat:%d][irqlock:%d][intr:%ld]\n", + "[DMAstat:%d][irqlock:%d][intr:%d]\n", dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + (int)dev->interrupt); return; } ei_status.dmaing |= 0x01; @@ -561,16 +572,16 @@ outb(0x00, nic_base + EN0_RSARLO); outb(start_page, nic_base + EN0_RSARHI); outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); -#if defined(USE_LONGIO) - outsl(NE_BASE + NE_DATAPORT, buf, count>>2); - if (count & 3) { - buf += count & ~3; - if (count & 2) - outw(*((u16*)buf)++, NE_BASE + NE_DATAPORT); + if (ei_status.ne2k_flags & ONLY_16BIT_IO) { + outsw(NE_BASE + NE_DATAPORT, buf, count>>1); + } else { + outsl(NE_BASE + NE_DATAPORT, buf, count>>2); + if (count & 3) { + buf += count & ~3; + if (count & 2) + outw(cpu_to_le16(*((u16*)buf)++), NE_BASE + NE_DATAPORT); + } } -#else - outsw(NE_BASE + NE_DATAPORT, buf, count>>1); -#endif dma_start = jiffies; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ne3210.c linux/drivers/net/ne3210.c --- v2.3.9/linux/drivers/net/ne3210.c Wed Dec 16 13:35:49 1998 +++ linux/drivers/net/ne3210.c Tue Jul 6 19:08:33 1999 @@ -95,7 +95,7 @@ * PROM for a match against the value assigned to Novell. */ -__initfunc(int ne3210_probe(struct device *dev)) +int __init ne3210_probe(struct device *dev) { unsigned short ioaddr = dev->base_addr; @@ -122,7 +122,7 @@ return ENODEV; } -__initfunc(int ne3210_probe1(struct device *dev, int ioaddr)) +int __init ne3210_probe1(struct device *dev, int ioaddr) { int i; unsigned long eisa_id; diff -u --recursive --new-file v2.3.9/linux/drivers/net/olympic.c linux/drivers/net/olympic.c --- v2.3.9/linux/drivers/net/olympic.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/olympic.c Tue Jul 6 10:11:40 1999 @@ -0,0 +1,1663 @@ +/* + * olympic.c (c) 1999 Peter De Schrijver All Rights Reserved + * 1999 Mike Phillips (phillim@amtrak.com) + * + * Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic + * chipset. + * + * Base Driver Skeleton: + * Written 1993-94 by Donald Becker. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their + * assistance and perserverance with the testing of this driver. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * 4/27/99 - Alpha Release 0.1.0 + * First release to the public + * + * 6/8/99 - Official Release 0.2.0 + * Merged into the kernel code + * + * To Do: + * + * Sanitize for smp + * + * If Problems do Occur + * Most problems can be rectified by either closing and opening the interface + * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult + * if compiled into the kernel). + */ + +/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */ + +#define OLYMPIC_DEBUG 0 + +/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel. + * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the + * kernel. + * Intended to be used to create a ring-error reporting network module + * i.e. it will give you the source address of beaconers on the ring + */ + +#define OLYMPIC_NETWORK_MONITOR 0 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "olympic.h" + +/* I've got to put some intelligence into the version number so that Peter and I know + * which version of the code somebody has got. + * Version Number = a.b.c.d where a.b.c is the level of code and d is the latest author. + * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike + * + * Official releases will only have an a.b.c version number format. + */ + +static char *version = +"Olympic.c v0.2.0 6/8/99 - Peter De Schrijver & Mike Phillips" ; + +static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", + "Address Verification", "Neighbor Notification (Ring Poll)", + "Request Parameters","FDX Registration Request", + "FDX Duplicate Address Check", "Station registration Query Wait", + "Unknown stage"}; + +static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Wire Fault", + "Ring Speed Mismatch", "Timeout","Ring Failure","Ring Beaconing", + "Duplicate Node Address","Request Parameters","Remove Received", + "Reserved", "Reserved", "No Monitor Detected for RPL", + "Monitor Contention failer for RPL", "FDX Protocol Error"}; + +/* Module paramters */ + +/* Ring Speed 0,4,16,100 + * 0 = Autosense + * 4,16 = Selected speed only, no autosense + * This allows the card to be the first on the ring + * and become the active monitor. + * 100 = Nothing at present, 100mbps is autodetected + * if FDX is turned on. May be implemented in the future to + * fail if 100mpbs is not detected. + * + * WARNING: Some hubs will allow you to insert + * at the wrong speed + */ + +static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(ringspeed, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i"); + +/* Packet buffer size */ + +static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; + +/* Message Level */ + +static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(message_level, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; + +static int olympic_scan(struct device *dev); +static int olympic_init(struct device *dev); +static int olympic_open(struct device *dev); +static int olympic_xmit(struct sk_buff *skb, struct device *dev); +static int olympic_close(struct device *dev); +static void olympic_set_rx_mode(struct device *dev); +static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats * olympic_get_stats(struct device *dev); +static int olympic_set_mac_address(struct device *dev, void *addr) ; +static void olympic_arb_cmd(struct device *dev); +static int olympic_change_mtu(struct device *dev, int mtu); +static void olympic_srb_bh(struct device *dev) ; +static void olympic_asb_bh(struct device *dev) ; +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS +static int sprintf_info(char *buffer, struct device *dev) ; +#endif +#endif + +__initfunc(int olympic_probe(struct device *dev)) +{ + int cards_found; + + cards_found=olympic_scan(dev); + return cards_found ? 0 : -ENODEV; +} + +__initfunc(static int olympic_scan(struct device *dev)) +{ + struct pci_dev *pci_device = NULL ; + struct olympic_private *olympic_priv; + int card_no = 0 ; + if (pci_present()) { + + while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) { + + pci_set_master(pci_device); + + /* Check to see if io has been allocated, if so, we've already done this card, + so continue on the card discovery loop */ + + if (check_region(pci_device->base_address[0] & (~3), OLYMPIC_IO_SPACE)) { + card_no++ ; + continue ; + } + + olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL); + memset(olympic_priv, 0, sizeof(struct olympic_private)); + init_waitqueue_head(&olympic_priv->srb_wait); + init_waitqueue_head(&olympic_priv->trb_wait); +#ifndef MODULE + dev=init_trdev(dev, 0); +#endif + dev->priv=(void *)olympic_priv; +#if OLYMPIC_DEBUG + printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv); +#endif + dev->irq=pci_device->irq; + dev->base_addr=pci_device->base_address[0] & (~3); + dev->init=&olympic_init; + olympic_priv->olympic_mmio=ioremap(pci_device->base_address[1],256); + olympic_priv->olympic_lap=ioremap(pci_device->base_address[2],2048); + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) + olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; + else + olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; + + olympic_priv->olympic_ring_speed = ringspeed[card_no] ; + olympic_priv->olympic_message_level = message_level[card_no] ; + olympic_priv->olympic_multicast_set = 0 ; + + if(olympic_init(dev)==-1) { + unregister_netdevice(dev); + kfree(dev->priv); + return 0; + } + + dev->open=&olympic_open; + dev->hard_start_xmit=&olympic_xmit; + dev->change_mtu=&olympic_change_mtu; + + dev->stop=&olympic_close; + dev->do_ioctl=NULL; + dev->set_multicast_list=&olympic_set_rx_mode; + dev->get_stats=&olympic_get_stats ; + dev->set_mac_address=&olympic_set_mac_address ; + return 1; + } + } + return 0 ; +} + + +__initfunc(static int olympic_init(struct device *dev)) +{ + struct olympic_private *olympic_priv; + __u8 *olympic_mmio, *init_srb,*adapter_addr; + unsigned long t; + unsigned int uaa_addr; + + olympic_priv=(struct olympic_private *)dev->priv; + olympic_mmio=olympic_priv->olympic_mmio; + + printk("%s \n", version); + printk("%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq); + + request_region(dev->base_addr, OLYMPIC_IO_SPACE, "olympic"); + writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL); + t=jiffies; + while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); + release_region(dev->base_addr, OLYMPIC_IO_SPACE) ; + return -1; + } + } + +#if OLYMPIC_DEBUG + printk("BCTL: %x\n",readl(olympic_mmio+BCTL)); + printk("GPR: %x\n",readw(olympic_mmio+GPR)); + printk("SISRMASK: %x\n",readl(olympic_mmio+SISR_MASK)); +#endif + /* Aaaahhh, You have got to be real careful setting GPR, the card + holds the previous values from flash memory, including autosense + and ring speed */ + + writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL); + + if (olympic_priv->olympic_ring_speed == 0) { /* Autosense */ + writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR); + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Ringspeed autosense mode on\n",dev->name); + } else if (olympic_priv->olympic_ring_speed == 16) { + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", dev->name); + writel(GPR_16MBPS, olympic_mmio+GPR); + } else if (olympic_priv->olympic_ring_speed == 4) { + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", dev->name) ; + writel(0, olympic_mmio+GPR); + } + + writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR); + +#if OLYMPIC_DEBUG + printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; +#endif + /* start solo init */ + writel((1<<15),olympic_mmio+SISR_MASK_SUM); + + t=jiffies; + while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); + release_region(dev->base_addr, OLYMPIC_IO_SPACE); + return -1; + } + } + + writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); + +#if OLYMPIC_DEBUG + printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); +#endif + + init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800)); + +#if OLYMPIC_DEBUG +{ + int i; + printk("init_srb(%p): ",init_srb); + for(i=0;i<20;i++) + printk("%x ",readb(init_srb+i)); + printk("\n"); +} +#endif + if(readw(init_srb+6)) { + printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",readw(init_srb+6)); + release_region(dev->base_addr, OLYMPIC_IO_SPACE); + return -1; + } + + uaa_addr=ntohs(readw(init_srb+8)); + +#if OLYMPIC_DEBUG + printk("UAA resides at %x\n",uaa_addr); +#endif + + writel(uaa_addr,olympic_mmio+LAPA); + adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800)); + +#if OLYMPIC_DEBUG + printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n", + readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2), + readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5)); +#endif + + memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); + + olympic_priv->olympic_addr_table_addr = ntohs(readw(init_srb + 12)) ; + olympic_priv->olympic_parms_addr = ntohs(readw(init_srb + 14)) ; + + return 0; + +} + +static int olympic_open(struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; + unsigned long flags; + char open_error[255] ; + int i, open_finished = 1 ; + +#if OLYMPIC_NETWORK_MONITOR + __u8 *oat ; + __u8 *opt ; +#endif + + if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) { + return -EAGAIN; + } + +#if OLYMPIC_DEBUG + printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); + printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR)); +#endif + + writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); + + writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */ + + writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */ + + /* adapter is closed, so SRB is pointed to by LAPWWO */ + + writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); + init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800)); + +#if OLYMPIC_DEBUG + printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); + printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK)); + printk("Before the open command \n"); +#endif + do { + int i; + + save_flags(flags); + cli(); + for(i=0;iolympic_laa[0]) { + writeb(olympic_priv->olympic_laa[0],init_srb+12); + writeb(olympic_priv->olympic_laa[1],init_srb+13); + writeb(olympic_priv->olympic_laa[2],init_srb+14); + writeb(olympic_priv->olympic_laa[3],init_srb+15); + writeb(olympic_priv->olympic_laa[4],init_srb+16); + writeb(olympic_priv->olympic_laa[5],init_srb+17); + memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ; + } + writeb(1,init_srb+30); + + olympic_priv->srb_queued=1; + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + while(olympic_priv->srb_queued) { + interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ); + if(signal_pending(current)) { + printk(KERN_WARNING "%s: SRB timed out.\n", + dev->name); + printk(KERN_WARNING "SISR=%x MISR=%x\n", + readl(olympic_mmio+SISR), + readl(olympic_mmio+LISR)); + olympic_priv->srb_queued=0; + break; + } + } + restore_flags(flags); +#if OLYMPIC_DEBUG + printk("init_srb(%p): ",init_srb); + for(i=0;i<20;i++) + printk("%x ",readb(init_srb+i)); + printk("\n"); +#endif + + /* If we get the same return response as we set, the interrupt wasn't raised and the open + * timed out. + */ + + if(readb(init_srb+2)== OLYMPIC_CLEAR_RET_CODE) { + printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; + return -EIO ; + } + + if(readb(init_srb+2)!=0) { + if (readb(init_srb+2) == 0x07) { + if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */ + printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); + open_finished = 0 ; + } else { + + strcpy(open_error, open_maj_error[(readb(init_srb+7) & 0xf0) >> 4]) ; + strcat(open_error," - ") ; + strcat(open_error, open_min_error[(readb(init_srb+7) & 0x0f)]) ; + + if (!olympic_priv->olympic_ring_speed && ((readb(init_srb+7) & 0x0f) == 0x0d)) { + printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name); + printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name); + free_irq(dev->irq, dev); + return -EIO ; + } + + printk(KERN_WARNING "%s: %s\n",dev->name,open_error); + free_irq(dev->irq,dev) ; + return -EIO ; + + } /* if autosense && open_finished */ + } else { + printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]); + free_irq(dev->irq, dev); + return -EIO; + } + } else + open_finished = 1 ; + } while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ + + if (readb(init_srb+18) & (1<<3)) + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name); + + if (readb(init_srb+18) & (1<<1)) + olympic_priv->olympic_ring_speed = 100 ; + else if (readb(init_srb+18) & 1) + olympic_priv->olympic_ring_speed = 16 ; + else + olympic_priv->olympic_ring_speed = 4 ; + + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed); + + olympic_priv->asb=ntohs(readw(init_srb+8)); + olympic_priv->srb=ntohs(readw(init_srb+10)); + olympic_priv->arb=ntohs(readw(init_srb+12)); + olympic_priv->trb=ntohs(readw(init_srb+16)); + + olympic_priv->olympic_receive_options = 0x01 ; + olympic_priv->olympic_copy_all_options = 0 ; + + /* setup rx ring */ + + writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ + + writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */ + + for(i=0;ipkt_buf_sz); + if(skb == NULL) + break; + + skb->dev = dev; + + olympic_priv->olympic_rx_ring[i].buffer=virt_to_bus(skb->data); + olympic_priv->olympic_rx_ring[i].res_length = olympic_priv->pkt_buf_sz ; + olympic_priv->rx_ring_skb[i]=skb; + } + + if (i==0) { + printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name); + free_irq(dev->irq, dev); + return -EIO; + } + + writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXDESCQ); + writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXCDA); + writew(i,olympic_mmio+RXDESCQCNT); + + writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXSTATQ); + writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXCSA); + + olympic_priv->rx_ring_last_received=OLYMPIC_RX_RING_SIZE-1; /* last processed rx status */ + olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE-1; + + writew(i,olympic_mmio+RXSTATQCNT); + +#if OLYMPIC_DEBUG + printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); + printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]); + printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) ); + printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) ); + printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7]) ); + + printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]); +#endif + + writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ); + +#if OLYMPIC_DEBUG + printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); + printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]); + printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]); +#endif + + writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM); + + /* setup tx ring */ + + writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */ + for(i=0;iolympic_tx_ring[i].buffer=0xdeadbeef; + + olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE; + writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXDESCQ_1); + writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXCDA_1); + writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXDESCQCNT_1); + + writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1); + writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1); + writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1); + + olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */ + olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */ + + writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM); + +#if OLYMPIC_DEBUG + printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); + printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK)); +#endif + +#if OLYMPIC_NETWORK_MONITOR + oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + + printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5)); + printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); + + printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5)); + + +#endif + + dev->start = 1; + dev->interrupt=0; + dev->tbusy=0; + + MOD_INC_USE_COUNT ; + return 0; + +} + +/* + * When we enter the rx routine we do not know how many frames have been + * queued on the rx channel. Therefore we start at the next rx status + * position and travel around the receive ring until we have completed + * all the frames. + * + * This means that we may process the frame before we receive the end + * of frame interrupt. This is why we always test the status instead + * of blindly processing the next frame. + * + */ +static void olympic_rx(struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + struct olympic_rx_status *rx_status; + struct olympic_rx_desc *rx_desc ; + int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len; + struct sk_buff *skb, *skb2; + int i; + + rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; + + while (rx_status->status_buffercnt) { + + olympic_priv->rx_status_last_received++ ; + olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1); +#if OLYMPIC_DEBUG + printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); + printk("rx status: %x rx len: %x \n",rx_status->status_buffercnt,rx_status->fragmentcnt_framelen); +#endif + length=rx_status->fragmentcnt_framelen & 0xffff; + buffer_cnt = rx_status->status_buffercnt & 0xffff ; + i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ + frag_len = rx_status->fragmentcnt_framelen >> 16 ; + +#if OLYMPIC_DEBUG + printk("length: %x, frag_len: %x, buffer_cnt: %x\n",length,frag_len,buffer_cnt); +#endif + + if(rx_status->status_buffercnt & 0xC0000000) { + if (rx_status->status_buffercnt & 0x3B000000) { + if (olympic_priv->olympic_message_level) { + if (rx_status->status_buffercnt & (1<<29)) /* Rx Frame Truncated */ + printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name); + if (rx_status->status_buffercnt & (1<<28)) /*Rx receive overrun */ + printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name); + if (rx_status->status_buffercnt & (1<<27)) /* No receive buffers */ + printk(KERN_WARNING "%s: No receive buffers \n",dev->name); + if (rx_status->status_buffercnt & (1<<25)) /* Receive frame error detect */ + printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name); + if (rx_status->status_buffercnt & (1<<24)) /* Received Error Detect */ + printk(KERN_WARNING "%s: Received Error Detect \n",dev->name); + } + olympic_priv->rx_ring_last_received += i ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; + olympic_priv->olympic_stats.rx_errors++; + } else { + + if (buffer_cnt == 1) { + skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; + } else { + skb = dev_alloc_skb(length) ; + } + + if (skb == NULL) { + printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ; + olympic_priv->olympic_stats.rx_dropped++ ; + /* Update counters even though we don't transfer the frame */ + olympic_priv->rx_ring_last_received += i ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; + } else { + skb->dev = dev ; + + /* Optimise based upon number of buffers used. + If only one buffer is used we can simply swap the buffers around. + If more than one then we must use the new buffer and copy the information + first. Ideally all frames would be in a single buffer, this can be tuned by + altering the buffer size. */ + + if (buffer_cnt==1) { + olympic_priv->rx_ring_last_received++ ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); + rx_ring_last_received = olympic_priv->rx_ring_last_received ; + skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; + skb_put(skb2,length); + skb2->protocol = tr_type_trans(skb2,dev); + olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer=virt_to_bus(skb->data); + olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = olympic_priv->pkt_buf_sz ; + olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; + netif_rx(skb2) ; + } else { + do { /* Walk the buffers */ + olympic_priv->rx_ring_last_received++ ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); + rx_ring_last_received = olympic_priv->rx_ring_last_received ; + rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); + cpy_length = (i == 1 ? frag_len : rx_desc->res_length); + memcpy(skb_put(skb, cpy_length), bus_to_virt(rx_desc->buffer), cpy_length) ; + } while (--i) ; + + skb->protocol = tr_type_trans(skb,dev); + netif_rx(skb) ; + } + olympic_priv->olympic_stats.rx_packets++ ; + olympic_priv->olympic_stats.rx_bytes += length ; + } /* if skb == null */ + } /* If status & 0x3b */ + + } else { /*if buffercnt & 0xC */ + olympic_priv->rx_ring_last_received += i ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; + } + + rx_status->fragmentcnt_framelen = 0 ; + rx_status->status_buffercnt = 0 ; + rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]); + + writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | buffer_cnt , olympic_mmio+RXENQ); + } /* while */ + +} + +static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev= (struct device *)dev_id; + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + __u32 sisr; + __u8 *adapter_check_area ; + + sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ + + if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ + return ; + + if (dev->interrupt) + printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; + + dev->interrupt = 1 ; + + if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK | + SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) { + + if(sisr & SISR_SRB_REPLY) { + if(olympic_priv->srb_queued==1) { + wake_up_interruptible(&olympic_priv->srb_wait); + } else if (olympic_priv->srb_queued==2) { + olympic_srb_bh(dev) ; + } + olympic_priv->srb_queued=0; + } /* SISR_SRB_REPLY */ + + if (sisr & SISR_TX1_EOF) { + olympic_priv->tx_ring_last_status++; + olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1); + olympic_priv->free_tx_ring_entries++; + olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len; + olympic_priv->olympic_stats.tx_packets++ ; + dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef; + olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; + + if(dev->tbusy) { + dev->tbusy=0; + mark_bh(NET_BH); + } + } /* SISR_TX1_EOF */ + + if (sisr & SISR_RX_STATUS) { + olympic_rx(dev); + } /* SISR_RX_STATUS */ + + if (sisr & SISR_ADAPTER_CHECK) { + printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); + writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); + adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; + printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; + dev->interrupt = 0 ; + free_irq(dev->irq, dev) ; + + } /* SISR_ADAPTER_CHECK */ + + if (sisr & SISR_ASB_FREE) { + /* Wake up anything that is waiting for the asb response */ + if (olympic_priv->asb_queued) { + olympic_asb_bh(dev) ; + } + } /* SISR_ASB_FREE */ + + if (sisr & SISR_ARB_CMD) { + olympic_arb_cmd(dev) ; + } /* SISR_ARB_CMD */ + + if (sisr & SISR_TRB_REPLY) { + /* Wake up anything that is waiting for the trb response */ + if (olympic_priv->trb_queued) { + wake_up_interruptible(&olympic_priv->trb_wait); + } + olympic_priv->trb_queued = 0 ; + } /* SISR_TRB_REPLY */ + + if (sisr & SISR_RX_NOBUF) { + /* According to the documentation, we don't have to do anything, but trapping it keeps it out of + /var/log/messages. */ + } /* SISR_RX_NOBUF */ + } else { + printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr); + printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ; + } /* One if the interrupts we want */ + + dev->interrupt = 0 ; + + writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); + +} + +static int olympic_xmit(struct sk_buff *skb, struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + return 1; + } + + if(olympic_priv->free_tx_ring_entries) { + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data); + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000); + olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb; + olympic_priv->free_tx_ring_entries--; + + olympic_priv->tx_ring_free++; + olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1); + + + writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1); + + dev->tbusy=0; + + return 0; + } else + return 1; + +} + + +static int olympic_close(struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb; + unsigned long flags; + int i; + + writel(olympic_priv->srb,olympic_mmio+LAPA); + srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); + + writeb(SRB_CLOSE_ADAPTER,srb+0); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + + save_flags(flags); + cli(); + + olympic_priv->srb_queued=1; + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + while(olympic_priv->srb_queued) { + interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ); + if(signal_pending(current)) { + printk(KERN_WARNING "%s: SRB timed out.\n", + dev->name); + printk(KERN_WARNING "SISR=%x MISR=%x\n", + readl(olympic_mmio+SISR), + readl(olympic_mmio+LISR)); + olympic_priv->srb_queued=0; + break; + } + } + + restore_flags(flags) ; + olympic_priv->rx_status_last_received++; + olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; + + for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); + olympic_priv->rx_status_last_received++; + olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; + } + + /* reset tx/rx fifo's and busmaster logic */ + + writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL); + udelay(1); + writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); + +#if OLYMPIC_DEBUG + printk("srb(%p): ",srb); + for(i=0;i<4;i++) + printk("%x ",readb(srb+i)); + printk("\n"); +#endif + dev->start = 0; + free_irq(dev->irq,dev); + + MOD_DEC_USE_COUNT ; + return 0; + +} + +static void olympic_set_rx_mode(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + __u8 *olympic_mmio = olympic_priv->olympic_mmio ; + __u8 options = 0, set_mc_list = 0 ; + __u8 *srb, *ata ; + struct dev_mc_list *dmi ; + + writel(olympic_priv->srb,olympic_mmio+LAPA); + srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); + options = olympic_priv->olympic_copy_all_options; + + if (dev->flags&IFF_PROMISC) + options |= (3<<5) ; /* All LLC and MAC frames, all through the main rx channel */ + else + options &= ~(3<<5) ; + + if (dev->mc_count) { + set_mc_list = 1 ; + } + + /* Only issue the srb if there is a change in options */ + + if ((options ^ olympic_priv->olympic_copy_all_options)) { + + /* Now to issue the srb command to alter the copy.all.options */ + + writeb(SRB_MODIFY_RECEIVE_OPTIONS,srb); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(olympic_priv->olympic_receive_options,srb+4); + writeb(options,srb+5); + + olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + olympic_priv->olympic_copy_all_options = options ; + + return ; + } + + if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */ + + dmi = dev->mc_list ; + + if (set_mc_list) { /* Turn multicast on */ + + /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00 + * We do this with a set functional address mask. + */ + + ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ; + if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */ + writeb(SRB_SET_FUNC_ADDRESS,srb+0); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(0,srb+4); + writeb(0,srb+5); + writeb(readb(ata+10),srb+6); + writeb(readb(ata+11)|4,srb+7); + writeb(readb(ata+12),srb+8); + writeb(readb(ata+13),srb+9); + + olympic_priv->srb_queued = 2 ; + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + olympic_priv->olympic_multicast_set = 1 ; + } + + + } else { /* Turn multicast off */ + + ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ; + if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */ + writeb(SRB_SET_FUNC_ADDRESS,srb+0); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(0,srb+4); + writeb(0,srb+5); + writeb(readb(ata+10),srb+6); + writeb(readb(ata+11) & ~4,srb+7); + writeb(readb(ata+12),srb+8); + writeb(readb(ata+13),srb+9); + + olympic_priv->srb_queued = 2 ; + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + olympic_priv->olympic_multicast_set = 0 ; + } + } + + } + + +} + +static void olympic_srb_bh(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + __u8 *olympic_mmio = olympic_priv->olympic_mmio ; + __u8 *srb; + + writel(olympic_priv->srb,olympic_mmio+LAPA); + srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); + + switch (readb(srb)) { + + /* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) + * At some point we should do something if we get an error, such as + * resetting the IFF_PROMISC flag in dev + */ + + case SRB_MODIFY_RECEIVE_OPTIONS: + switch (readb(srb+2)) { + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); + break ; + default: + if (olympic_priv->olympic_message_level) + printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n",dev->name,olympic_priv->olympic_copy_all_options, olympic_priv->olympic_receive_options) ; + break ; + } /* switch srb[2] */ + break ; + + /* SRB_SET_GROUP_ADDRESS - Multicast group setting + */ + + case SRB_SET_GROUP_ADDRESS: + switch (readb(srb+2)) { + case 0x00: + olympic_priv->olympic_multicast_set = 1 ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); + break ; + case 0x3c: + printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n",dev->name) ; + break ; + case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */ + printk(KERN_WARNING "%s: Group address registers full\n",dev->name) ; + break ; + case 0x55: + printk(KERN_INFO "%s: Group Address already set.\n",dev->name) ; + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + /* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list + */ + + case SRB_RESET_GROUP_ADDRESS: + switch (readb(srb+2)) { + case 0x00: + olympic_priv->olympic_multicast_set = 0 ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + case 0x39: /* Must deal with this if individual multicast addresses used */ + printk(KERN_INFO "%s: Group address not found \n",dev->name); + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + + /* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode + */ + + case SRB_SET_FUNC_ADDRESS: + switch (readb(srb+2)) { + case 0x00: + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Functional Address Mask Set \n",dev->name) ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + /* SRB_READ_LOG - Read and reset the adapter error counters + */ + + case SRB_READ_LOG: + switch (readb(srb+2)) { + case 0x00: + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + + } /* switch srb[2] */ + break ; + + /* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */ + + case SRB_READ_SR_COUNTERS: + switch (readb(srb+2)) { + case 0x00: + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + default: + printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n",dev->name); + break ; + } /* switch srb[0] */ + +} + +static struct net_device_stats * olympic_get_stats(struct device *dev) +{ + struct olympic_private *olympic_priv ; + olympic_priv=(struct olympic_private *) dev->priv; + return (struct net_device_stats *) &olympic_priv->olympic_stats; +} + +static int olympic_set_mac_address (struct device *dev, void *addr) +{ + struct sockaddr *saddr = addr ; + struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; + + if (dev->start) { + printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; + return -EIO ; + } + + memcpy(olympic_priv->olympic_laa, saddr->sa_data,dev->addr_len) ; + + if (olympic_priv->olympic_message_level) { + printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n",dev->name, olympic_priv->olympic_laa[0], + olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2], + olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4], + olympic_priv->olympic_laa[5]); + } + + return 0 ; +} + +static void olympic_arb_cmd(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + __u8 *arb_block, *asb_block, *srb ; + __u8 header_len ; + __u16 frame_len, buffer_len ; + struct sk_buff *mac_frame ; + __u8 *buf_ptr ; + __u8 *frame_data ; + __u16 buff_off ; + __u16 lan_status = 0, lan_status_diff ; /* Initialize to stop compiler warning */ + __u8 fdx_prot_error ; + __u16 next_ptr; + +#if OLYMPIC_NETWORK_MONITOR + struct trh_hdr *mac_hdr ; +#endif + + arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; + srb = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; + writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO); + + if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ + + header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */ + frame_len = ntohs(readw(arb_block + 10)) ; + + buff_off = ntohs(readw(arb_block + 6)) ; + + buf_ptr = olympic_priv->olympic_lap + buff_off ; + +#if OLYMPIC_DEBUG +{ + int i; + frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; + + for (i=0 ; i < 14 ; i++) { + printk("Loc %d = %02x\n",i,readb(frame_data + i)); + } + + printk("next %04x, fs %02x, len %04x \n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); +} +#endif + mac_frame = dev_alloc_skb(frame_len) ; + + /* Walk the buffer chain, creating the frame */ + + do { + frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; + buffer_len = ntohs(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); + memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ; + next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); + + } while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr))); + +#if OLYMPIC_NETWORK_MONITOR + printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ; + mac_hdr = (struct trh_hdr *)mac_frame->data ; + printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; + printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; +#endif + mac_frame->dev = dev ; + mac_frame->protocol = tr_type_trans(mac_frame,dev); + netif_rx(mac_frame) ; + + /* Now tell the card we have dealt with the received frame */ + + /* Set LISR Bit 1 */ + writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM); + + /* Is the ASB free ? */ + + if (!(readl(olympic_priv->olympic_mmio + SISR) & SISR_ASB_FREE)) { + olympic_priv->asb_queued = 1 ; + writel(LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); + return ; + /* Drop out and wait for the bottom half to be run */ + } + + writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */ + writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */ + writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */ + writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */ + + writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); + + olympic_priv->asb_queued = 2 ; + + return ; + + } else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */ + lan_status = readw(arb_block+6); + fdx_prot_error = readb(arb_block+8) ; + + /* Issue ARB Free */ + writel(LISR_ARB_FREE,olympic_priv->olympic_mmio+LISR_SUM); + + lan_status_diff = olympic_priv->olympic_lan_status ^ lan_status ; + + if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { + if (lan_status_diff & LSC_LWF) + printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name); + if (lan_status_diff & LSC_ARW) + printk(KERN_WARNING "%s: Auto removal error\n",dev->name); + if (lan_status_diff & LSC_FPE) + printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name); + if (lan_status_diff & LSC_RR) + printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name); + + /* Adapter has been closed by the hardware */ + + /* reset tx/rx fifo's and busmaster logic */ + + writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL); + udelay(1); + writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); + dev->tbusy = 1 ; + dev->interrupt = 1 ; + dev->start = 0 ; + olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; + free_irq(dev->irq,dev); + + printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; + + } /* If serious error */ + + if (olympic_priv->olympic_message_level) { + if (lan_status_diff & LSC_SIG_LOSS) + printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; + if (lan_status_diff & LSC_HARD_ERR) + printk(KERN_INFO "%s: Beaconing \n",dev->name); + if (lan_status_diff & LSC_SOFT_ERR) + printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name); + if (lan_status_diff & LSC_TRAN_BCN) + printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + if (lan_status_diff & LSC_SS) + printk(KERN_INFO "%s: Single Station on the ring \n", dev->name); + if (lan_status_diff & LSC_RING_REC) + printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name); + if (lan_status_diff & LSC_FDX_MODE) + printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name); + } + + if (lan_status_diff & LSC_CO) { + + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Counter Overflow \n", dev->name); + + /* Issue READ.LOG command */ + + writeb(SRB_READ_LOG, srb); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(0,srb+4); + writeb(0,srb+5); + + olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + } + + if (lan_status_diff & LSC_SR_CO) { + + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); + + /* Issue a READ.SR.COUNTERS */ + + writeb(SRB_READ_SR_COUNTERS,srb); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + + olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + } + + olympic_priv->olympic_lan_status = lan_status ; + + } /* Lan.change.status */ + else + printk(KERN_WARNING "%s: Unknown arb command \n", dev->name); +} + +static void olympic_asb_bh(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + __u8 *arb_block, *asb_block ; + + arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; + + if (olympic_priv->asb_queued == 1) { /* Dropped through the first time */ + + writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */ + writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */ + writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */ + writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */ + + writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); + olympic_priv->asb_queued = 2 ; + + return ; + } + + if (olympic_priv->asb_queued == 2) { + switch (readb(asb_block+2)) { + case 0x01: + printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name); + break ; + case 0x26: + printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name); + break ; + case 0xFF: + /* Valid response, everything should be ok again */ + break ; + default: + printk(KERN_WARNING "%s: Invalid return code in asb\n",dev->name); + break ; + } + } + olympic_priv->asb_queued = 0 ; +} + +static int olympic_change_mtu(struct device *dev, int mtu) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + __u16 max_mtu ; + + if (olympic_priv->olympic_ring_speed == 4) + max_mtu = 4500 ; + else + max_mtu = 18000 ; + + if (mtu > max_mtu) + return -EINVAL ; + if (mtu < 100) + return -EINVAL ; + + dev->mtu = mtu ; + olympic_priv->pkt_buf_sz = mtu + TR_HLEN ; + + return 0 ; +} + +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS +static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + struct pci_dev *pci_device = NULL ; + int len=0; + off_t begin=0; + off_t pos=0; + int size; + + struct device *dev; + + + size = sprintf(buffer, + "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapters\n"); + + pos+=size; + len+=size; + + + while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) { + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (dev->base_addr == (pci_device->base_address[0] & (~3)) ) { /* Yep, an Olympic device */ + size = sprintf_info(buffer+len, dev); + len+=size; + pos=begin+len; + + if(posoffset+length) + break; + } /* if */ + } /* for */ + } /* While */ + + *start=buffer+(offset-begin); /* Start of wanted data */ + len-=(offset-begin); /* Start slop */ + if(len>length) + len=length; /* Ending slop */ + return len; +} + +static int sprintf_info(char *buffer, struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + __u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + int size = 0 ; + + size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", + dev->name); + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n", + dev->name, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5], + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); + + size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name); + + size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", + dev->name) ; + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n", + dev->name, + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); + + size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", + dev->name) ; + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, + readb(opt+offsetof(struct olympic_parameters_table, source_addr)), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, local_ring))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, mon_error))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, frame_correl)))); + + size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", + dev->name) ; + + size += sprintf(buffer+size, "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n", + dev->name, + ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3)); + + + return size; +} +#endif +#endif + +#ifdef MODULE + +static struct device* dev_olympic[OLYMPIC_MAX_ADAPTERS]; + +int init_module(void) +{ + int i; + +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *ent ; + + ent = create_proc_entry("net/olympic_tr",0,0); + ent->read_proc = &olympic_proc_info ; +#endif +#endif + for (i = 0; (iinit = &olympic_probe; + + if (register_trdev(dev_olympic[i]) != 0) { + kfree_s(dev_olympic[i], sizeof(struct device)); + dev_olympic[i] = NULL; + if (i == 0) { + printk("Olympic: No IBM PCI Token Ring cards found in system.\n"); + return -EIO; + } else { + printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; + return 0; + } + } + } + + return 0; +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++) + if (dev_olympic[i]) { + unregister_trdev(dev_olympic[i]); + release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE); + kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private)); + kfree_s(dev_olympic[i], sizeof(struct device)); + dev_olympic[i] = NULL; + } + +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + remove_proc_entry("net/olympic_tr", NULL) ; +#endif +#endif +} +#endif /* MODULE */ + diff -u --recursive --new-file v2.3.9/linux/drivers/net/olympic.h linux/drivers/net/olympic.h --- v2.3.9/linux/drivers/net/olympic.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/olympic.h Mon Jul 5 19:54:55 1999 @@ -0,0 +1,303 @@ +/* + * olympic.h (c) 1999 Peter De Schrijver All Rights Reserved + * 1999 Mike Phillips (phillim@amtrak.com) + * + * Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset. + * + * Base Driver Skeleton: + * Written 1993-94 by Donald Becker. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + */ + +#define CID 0x4e + +#define BCTL 0x70 +#define BCTL_SOFTRESET (1<<15) +#define BCTL_MIMREB (1<<6) + +#define GPR 0x4a +#define GPR_OPTI_BF (1<<6) +#define GPR_NEPTUNE_BF (1<<4) +#define GPR_AUTOSENSE (1<<2) +#define GPR_16MBPS (1<<3) + +#define PAG 0x85 +#define LBC 0x8e + +#define LISR 0x10 +#define LISR_SUM 0x14 +#define LISR_RWM 0x18 + +#define LISR_LIE (1<<15) +#define LISR_SLIM (1<<13) +#define LISR_SLI (1<<12) +#define LISR_PCMSRMASK (1<<11) +#define LISR_PCMSRINT (1<<10) +#define LISR_WOLMASK (1<<9) +#define LISR_WOL (1<<8) +#define LISR_SRB_CMD (1<<5) +#define LISR_ASB_REPLY (1<<4) +#define LISR_ASB_FREE_REQ (1<<2) +#define LISR_ARB_FREE (1<<1) +#define LISR_TRB_FRAME (1<<0) + +#define SISR 0x20 +#define SISR_SUM 0x24 +#define SISR_RWM 0x28 +#define SISR_RR 0x2C +#define SISR_RESMASK 0x30 +#define SISR_MASK 0x54 +#define SISR_MASK_SUM 0x58 +#define SISR_MASK_RWM 0x5C + +#define SISR_TX2_IDLE (1<<31) +#define SISR_TX2_HALT (1<<29) +#define SISR_TX2_EOF (1<<28) +#define SISR_TX1_IDLE (1<<27) +#define SISR_TX1_HALT (1<<25) +#define SISR_TX1_EOF (1<<24) +#define SISR_TIMEOUT (1<<23) +#define SISR_RX_NOBUF (1<<22) +#define SISR_RX_STATUS (1<<21) +#define SISR_RX_HALT (1<<18) +#define SISR_RX_EOF_EARLY (1<<16) +#define SISR_MI (1<<15) +#define SISR_PI (1<<13) +#define SISR_ERR (1<<9) +#define SISR_ADAPTER_CHECK (1<<6) +#define SISR_SRB_REPLY (1<<5) +#define SISR_ASB_FREE (1<<4) +#define SISR_ARB_CMD (1<<3) +#define SISR_TRB_REPLY (1<<2) + +#define EISR 0x34 +#define EISR_RWM 0x38 +#define EISR_MASK 0x3c + +#define LAPA 0x60 +#define LAPWWO 0x64 +#define LAPWWC 0x68 +#define LAPCTL 0x6C +#define LAIPD 0x78 +#define LAIPDDINC 0x7C + +#define TIMER 0x50 + +#define CLKCTL 0x74 + +#define PM_CON 0x4 + +#define BMCTL_SUM 0x40 +#define BMCTL_RWM 0x44 +#define BMCTL_TX2_DIS (1<<30) +#define BMCTL_TX1_DIS (1<<26) +#define BMCTL_RX_DIS (1<<22) + +#define BMASR 0xcc + +#define RXDESCQ 0x90 +#define RXDESCQCNT 0x94 +#define RXCDA 0x98 +#define RXENQ 0x9C +#define RXSTATQ 0xA0 +#define RXSTATQCNT 0xA4 +#define RXCSA 0xA8 +#define RXCLEN 0xAC +#define RXHLEN 0xAE + +#define TXDESCQ_1 0xb0 +#define TXDESCQ_2 0xd0 +#define TXDESCQCNT_1 0xb4 +#define TXDESCQCNT_2 0xd4 +#define TXCDA_1 0xb8 +#define TXCDA_2 0xd8 +#define TXENQ_1 0xbc +#define TXENQ_2 0xdc +#define TXSTATQ_1 0xc0 +#define TXSTATQ_2 0xe0 +#define TXSTATQCNT_1 0xc4 +#define TXSTATQCNT_2 0xe4 +#define TXCSA_1 0xc8 +#define TXCSA_2 0xe8 + +#define OLYMPIC_IO_SPACE 256 + +#define SRB_COMMAND_SIZE 50 + +#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ + +/* Defines for LAN STATUS CHANGE reports */ +#define LSC_SIG_LOSS 0x8000 +#define LSC_HARD_ERR 0x4000 +#define LSC_SOFT_ERR 0x2000 +#define LSC_TRAN_BCN 0x1000 +#define LSC_LWF 0x0800 +#define LSC_ARW 0x0400 +#define LSC_FPE 0x0200 +#define LSC_RR 0x0100 +#define LSC_CO 0x0080 +#define LSC_SS 0x0040 +#define LSC_RING_REC 0x0020 +#define LSC_SR_CO 0x0010 +#define LSC_FDX_MODE 0x0004 + +/* Defines for OPEN ADAPTER command */ + +#define OPEN_ADAPTER_EXT_WRAP (1<<15) +#define OPEN_ADAPTER_DIS_HARDEE (1<<14) +#define OPEN_ADAPTER_DIS_SOFTERR (1<<13) +#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12) +#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11) +#define OPEN_ADAPTER_ENABLE_EC (1<<10) +#define OPEN_ADAPTER_CONTENDER (1<<8) +#define OPEN_ADAPTER_PASS_BEACON (1<<7) +#define OPEN_ADAPTER_ENABLE_FDX (1<<6) +#define OPEN_ADAPTER_ENABLE_RPL (1<<5) +#define OPEN_ADAPTER_INHIBIT_ETR (1<<4) +#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3) +#define OPEN_ADAPTER_USE_OPTS2 (1<<0) + +#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15) + +/* Defines for SRB Commands */ + +#define SRB_ACCESS_REGISTER 0x1f +#define SRB_CLOSE_ADAPTER 0x04 +#define SRB_CONFIGURE_BRIDGE 0x0c +#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a +#define SRB_MODIFY_BRIDGE_PARMS 0x15 +#define SRB_MODIFY_OPEN_OPTIONS 0x01 +#define SRB_MODIFY_RECEIVE_OPTIONS 0x17 +#define SRB_NO_OPERATION 0x00 +#define SRB_OPEN_ADAPTER 0x03 +#define SRB_READ_LOG 0x08 +#define SRB_READ_SR_COUNTERS 0x16 +#define SRB_RESET_GROUP_ADDRESS 0x02 +#define SRB_SAVE_CONFIGURATION 0x1b +#define SRB_SET_BRIDGE_PARMS 0x09 +#define SRB_SET_BRIDGE_TARGETS 0x10 +#define SRB_SET_FUNC_ADDRESS 0x07 +#define SRB_SET_GROUP_ADDRESS 0x06 +#define SRB_SET_GROUP_ADDR_OPTIONS 0x11 +#define SRB_UPDATE_WAKEUP_PATTERN 0x19 + +/* Clear return code */ + +#define OLYMPIC_CLEAR_RET_CODE 0xfe + +/* ARB Commands */ +#define ARB_RECEIVE_DATA 0x81 +#define ARB_LAN_CHANGE_STATUS 0x84 +/* ASB Response commands */ + +#define ASB_RECEIVE_DATA 0x81 + + +/* Olympic defaults for buffers */ + +#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */ +#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */ + +#define PKT_BUF_SZ 4096 /* Default packet size */ + +/* Olympic data structures */ + +struct olympic_tx_desc { + __u32 buffer; + __u32 status_length; +}; + +struct olympic_tx_status { + __u32 status; +}; + +struct olympic_rx_desc { + __u32 buffer; + __u32 res_length ; +}; + +struct olympic_rx_status { + __u32 fragmentcnt_framelen; + __u32 status_buffercnt; +}; + +struct mac_receive_buffer { + __u16 next ; + __u8 padding ; + __u8 frame_status ; + __u16 buffer_length ; + __u8 frame_data ; +}; + +struct olympic_private { + + __u16 srb; + __u16 trb; + __u16 arb; + __u16 asb; + + __u8 *olympic_mmio; + __u8 *olympic_lap; + + volatile int srb_queued; /* True if an SRB is still posted */ + wait_queue_head_t srb_wait; + + volatile int asb_queued; /* True if an ASB is posted */ + + volatile int trb_queued; /* True if a TRB is posted */ + wait_queue_head_t trb_wait ; + + struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE]; + struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE]; + struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE]; + struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE]; + struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE]; + int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries; + + struct net_device_stats olympic_stats ; + __u16 olympic_lan_status ; + __u8 olympic_ring_speed ; + __u16 pkt_buf_sz ; + __u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level; + __u8 olympic_multicast_set ; + __u16 olympic_addr_table_addr, olympic_parms_addr ; + __u8 olympic_laa[6] ; +}; + +struct olympic_adapter_addr_table { + + __u8 node_addr[6] ; + __u8 reserved[4] ; + __u8 func_addr[4] ; +} ; + +struct olympic_parameters_table { + + __u8 phys_addr[4] ; + __u8 up_node_addr[6] ; + __u8 up_phys_addr[6] ; + __u8 poll_addr[6] ; + __u16 reserved ; + __u16 acc_priority ; + __u16 auth_source_class ; + __u16 att_code ; + __u8 source_addr[6] ; + __u16 beacon_type ; + __u16 major_vector ; + __u16 lan_status ; + __u16 soft_error_time ; + __u16 reserved1 ; + __u16 local_ring ; + __u16 mon_error ; + __u16 beacon_transmit ; + __u16 beacon_receive ; + __u16 frame_correl ; + __u8 beacon_naun[6] ; + __u32 reserved2 ; + __u8 beacon_phys[4] ; +}; diff -u --recursive --new-file v2.3.9/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.3.9/linux/drivers/net/ppp.c Wed May 12 08:41:15 1999 +++ linux/drivers/net/ppp.c Mon Jul 5 20:35:18 1999 @@ -60,7 +60,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ #include diff -u --recursive --new-file v2.3.9/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c --- v2.3.9/linux/drivers/net/rtl8139.c Sun Nov 22 09:47:52 1998 +++ linux/drivers/net/rtl8139.c Mon Jul 5 19:56:46 1999 @@ -1,6 +1,6 @@ /* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */ /* - Written 1997-1998 by Donald Becker. + Written 1997-1999 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -16,11 +16,11 @@ Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html - Twister-tuning code contributed by Kinston . + Twister-tuning table provided by Kinston . */ static const char *version = -"rtl8139.c:v1.04 9/22/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; +"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; /* A few user-configurable values. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ @@ -178,7 +178,9 @@ 0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, { "RealTek RTL8139 Fast Ethernet", 0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "RealTek RTL8139 Fast Ethernet (mislabeled)", + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", + 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, + { "Accton MPX5030 (RealTek RTL8139)", 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, {0,}, /* 0 terminated list. */ }; @@ -235,13 +237,13 @@ RxBadAlign=0x0002, RxStatusOK=0x0001, }; +/* Twister tuning parameters from RealTek. + Completely undocumented, but required to tune bad links. */ enum CSCRBits { CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, CSCR_LinkDownCmd=0x0f3c0, -}; - -/* Twister tuning parameters from RealTek. Completely undocumented. */ +}; unsigned long param[4][4]={ {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43}, {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, @@ -270,9 +272,10 @@ unsigned char *rx_ring; unsigned char *tx_bufs; /* Tx bounce buffer region. */ char phys[4]; /* MII device addresses. */ + char twistie, twist_cnt; /* Twister tune state. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int duplex_lock:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ @@ -325,7 +328,7 @@ if ( ! pcibios_present()) return -ENODEV; - for (;pci_index < 0xff; pci_index++) { + for (; pci_index < 0xff; pci_index++) { u16 vendor, device, pci_command, new_command; int chip_idx, irq; long ioaddr; @@ -402,9 +405,9 @@ return cards_found ? 0 : -ENODEV; } -static struct device * rtl8129_probe1(int pci_bus, int pci_devfn, - struct device *dev, long ioaddr, - int irq, int chip_idx, int found_cnt) +static struct device *rtl8129_probe1(int pci_bus, int pci_devfn, + struct device *dev, long ioaddr, + int irq, int chip_idx, int found_cnt) { static int did_version = 0; /* Already printed version info. */ struct rtl8129_private *tp; @@ -470,9 +473,8 @@ dev->name); tp->phys[0] = -1; } - } else { - tp->phys[0] = 32; - } + } else + tp->phys[0] = 32; /* Put the chip into low-power mode. */ outb(0xC0, ioaddr + Cfg9346); @@ -601,7 +603,7 @@ int retval = 0; int i; - if ((phy_id & 0x1f) == 0) { /* Really a 8139. Use internal registers. */ + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ return location < 8 && mii_2_8139_map[location] ? inw(dev->base_addr + mii_2_8139_map[location]) : 0; } @@ -633,7 +635,7 @@ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; - if (phy_id == 32) { /* Really a 8139. Use internal registers. */ + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ if (location < 8 && mii_2_8139_map[location]) outw(value, dev->base_addr + mii_2_8139_map[location]); return; @@ -736,7 +738,7 @@ /* Enable all known interrupts by setting the interrupt mask. */ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); + | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); if (rtl8129_debug > 1) printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" @@ -749,7 +751,7 @@ init_timer(&tp->timer); tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ tp->timer.data = (unsigned long)dev; - tp->timer.function = &rtl8129_timer; /* timer handler */ + tp->timer.function = &rtl8129_timer; add_timer(&tp->timer); return 0; @@ -760,7 +762,7 @@ struct device *dev = (struct device *)data; struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; - int next_tick = 0; + int next_tick = 60*HZ; int mii_reg5 = mdio_read(dev, tp->phys[0], 5); if (! tp->duplex_lock && mii_reg5 != 0xffff) { @@ -774,8 +776,65 @@ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(0x00, ioaddr + Cfg9346); } - next_tick = 60*HZ; } + /* Check for bogusness. */ + if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) { + int status = inw(ioaddr + IntrStatus); + if (status & (TxOK | RxOK)) { /* Double check */ + printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n", + dev->name, status); + rtl8129_interrupt(dev->irq, dev, 0); + } + } + if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT) + rtl8129_tx_timeout(dev); + +#if 0 + if (tp->twistie) { + unsigned int CSCRval = inw(ioaddr + CSCR); /* Read link status. */ + if (tp->twistie == 1) { + if (CSCRval & CSCR_LinkOKBit) { + outw(CSCR_LinkDownOffCmd, ioaddr + CSCR); + tp->twistie = 2; + next_tick = HZ/10; + } else { + outw(CSCR_LinkDownCmd, ioaddr + CSCR); + outl(FIFOTMS_default,ioaddr + FIFOTMS); + outl(PARA78_default ,ioaddr + PARA78); + outl(PARA7c_default ,ioaddr + PARA7c); + tp->twistie = 0; + } + } else if (tp->twistie == 2) { + int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12; + int row; + if (linkcase >= 0x7000) row = 3; + else if (linkcase >= 0x3000) row = 2; + else if (linkcase >= 0x1000) row = 1; + else row = 0; + tp->twistie == row + 3; + outw(0,ioaddr+FIFOTMS); + outl(param[row][0], ioaddr+PARA7c); + tp->twist_cnt = 1; + } else { + outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c); + if (++tp->twist_cnt < 4) { + next_tick = HZ/10; + } else if (tp->twistie-3 == 3) { + if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) { + outl(PARA7c_xxx, ioaddr+PARA7c); + next_tick = HZ/10; /* 100ms. */ + outl(FIFOTMS_default, ioaddr+FIFOTMS); + outl(PARA78_default, ioaddr+PARA78); + outl(PARA7c_default, ioaddr+PARA7c); + tp->twistie == 3 + 3; + outw(0,ioaddr+FIFOTMS); + outl(param[3][0], ioaddr+PARA7c); + tp->twist_cnt = 1; + } + } + } + } +#endif if (rtl8129_debug > 2) { if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR) @@ -792,10 +851,8 @@ dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1)); } - if (next_tick) { - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); - } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); } static void rtl8129_tx_timeout(struct device *dev) @@ -861,7 +918,7 @@ } tp->cur_tx = i; while (i < NUM_TX_DESC) - tp->tx_skbuff[i] = 0; + tp->tx_skbuff[i++] = 0; if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ dev->tbusy = 0; tp->tx_full = 0; @@ -906,9 +963,8 @@ /* 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; - rtl8129_tx_timeout(dev); + if (jiffies - dev->trans_start >= TX_TIMEOUT) + rtl8129_tx_timeout(dev); return 1; } @@ -925,7 +981,7 @@ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), ioaddr + TxStatus0 + entry*4); - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ + if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */ clear_bit(0, (void*)&dev->tbusy); } else { tp->tx_full = 1; @@ -946,7 +1002,7 @@ struct device *dev = (struct device *)dev_instance; struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; int boguscnt = max_interrupt_work; - int status; + int status, link_changed = 0; long ioaddr = dev->base_addr; #if defined(__i386__) @@ -967,7 +1023,10 @@ do { status = inw(ioaddr + IntrStatus); - /* Acknowledge all of the current interrupt sources ASAP. */ + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if ((status & RxUnderrun) && inw(ioaddr+CSCR) & CSCR_LinkChangeBit) + link_changed = 1; outw(status, ioaddr + IntrStatus); if (rtl8129_debug > 4) @@ -982,9 +1041,9 @@ rtl8129_rx(dev); if (status & (TxOK | TxErr)) { - unsigned int dirty_tx; + unsigned int dirty_tx = tp->dirty_tx; - for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) { + while (tp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus = inl(ioaddr + TxStatus0 + entry*4); @@ -994,11 +1053,9 @@ /* Note: TxCarrierLost is always asserted at 100mbps. */ if (txstatus & (TxOutOfWindow | TxAborted)) { /* There was an major error, log it. */ -#ifndef final_version if (rtl8129_debug > 1) printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); -#endif tp->stats.tx_errors++; if (txstatus&TxAborted) { tp->stats.tx_aborted_errors++; @@ -1011,9 +1068,6 @@ tp->stats.collisions16++; #endif } else { -#ifdef ETHER_STATS - /* No count for tp->stats.tx_deferred */ -#endif if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ if (tp->tx_flag < 0x00300000) @@ -1030,6 +1084,13 @@ /* Free the original skb. */ dev_free_skb(tp->tx_skbuff[entry]); tp->tx_skbuff[entry] = 0; + if (tp->tx_full) { + /* The ring is no longer full, clear tbusy. */ + tp->tx_full = 0; + clear_bit(0, (void*)&dev->tbusy); + mark_bh(NET_BH); + } + dirty_tx++; } #ifndef final_version @@ -1039,14 +1100,6 @@ dirty_tx += NUM_TX_DESC; } #endif - - if (tp->tx_full && dirty_tx > tp->cur_tx - NUM_TX_DESC) { - /* The ring is no longer full, clear tbusy. */ - tp->tx_full = 0; - dev->tbusy = 0; - mark_bh(NET_BH); - } - tp->dirty_tx = dirty_tx; } @@ -1063,7 +1116,7 @@ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); - if ((status & RxUnderrun) && + if ((status & RxUnderrun) && link_changed && (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) { /* Really link-change on new chips. */ int lpar = inw(ioaddr + NWayLPAR); @@ -1284,12 +1337,12 @@ data[0] = tp->phys[0] & 0x3f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + data[3] = mdio_read(dev, data[0], 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]); + mdio_write(dev, data[0], data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; @@ -1318,7 +1371,7 @@ { 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) diff -u --recursive --new-file v2.3.9/linux/drivers/net/sealevel.c linux/drivers/net/sealevel.c --- v2.3.9/linux/drivers/net/sealevel.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sealevel.c Mon Jul 5 19:56:46 1999 @@ -0,0 +1,471 @@ +#define LINUX_21 + +/* + * Sealevel Systems 4021 driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * (c) Copyright 1999 Building Number Three Ltd + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "syncppp.h" +#include "z85230.h" + + +struct slvl_device +{ + struct z8530_channel *chan; + struct ppp_device netdev; + char name[16]; + int channel; +}; + + +struct slvl_board +{ + struct slvl_device dev[2]; + struct z8530_dev board; + int iobase; +}; + +/* + * Network driver support routines + */ + +/* + * Frame receive. Simple for our card as we do sync ppp and there + * is no funny garbage involved + */ + +static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) +{ + /* Drop the CRC - its not a good idea to try and negotiate it ;) */ + skb_trim(skb, skb->len-2); + skb->protocol=htons(ETH_P_WAN_PPP); + skb->mac.raw=skb->data; + skb->dev=c->netdevice; + /* + * Send it to the PPP layer. We dont have time to process + * it right now. + */ + netif_rx(skb); +} + +/* + * We've been placed in the UP state + */ + +static int sealevel_open(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int err = -1; + int unit = slvl->channel; + + /* + * Link layer up. + */ + + switch(unit) + { + case 0: + err=z8530_sync_dma_open(d, slvl->chan); + break; + case 1: + err=z8530_sync_open(d, slvl->chan); + break; + } + + if(err) + return err; + /* + * Begin PPP + */ + err=sppp_open(d); + if(err) + { + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + return err; + } + + slvl->chan->rx_function=sealevel_input; + + /* + * Go go go + */ + d->tbusy=0; + MOD_INC_USE_COUNT; + return 0; +} + +static int sealevel_close(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int unit = slvl->channel; + + /* + * Discard new frames + */ + + slvl->chan->rx_function=z8530_null_rx; + + /* + * PPP off + */ + sppp_close(d); + /* + * Link layer down + */ + d->tbusy=1; + + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + MOD_DEC_USE_COUNT; + return 0; +} + +static int sealevel_ioctl(struct device *d, struct ifreq *ifr, int cmd) +{ + /* struct slvl_device *slvl=d->priv; + z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ + return sppp_do_ioctl(d, ifr,cmd); +} + +static struct enet_statistics *sealevel_get_stats(struct device *d) +{ + struct slvl_device *slvl=d->priv; + if(slvl) + return z8530_get_stats(slvl->chan); + else + return NULL; +} + +/* + * Passed PPP frames, fire them downwind. + */ + +static int sealevel_queue_xmit(struct sk_buff *skb, struct device *d) +{ + struct slvl_device *slvl=d->priv; + return z8530_queue_xmit(slvl->chan, skb); +} + +#ifdef LINUX_21 +static int sealevel_neigh_setup(struct neighbour *n) +{ + if (n->nud_state == NUD_NONE) { + n->ops = &arp_broken_ops; + n->output = n->ops->output; + } + return 0; +} + +static int sealevel_neigh_setup_dev(struct device *dev, struct neigh_parms *p) +{ + if (p->tbl->family == AF_INET) { + p->neigh_setup = sealevel_neigh_setup; + p->ucast_probes = 0; + p->mcast_probes = 0; + } + return 0; +} + +#else + +static int return_0(struct device *d) +{ + return 0; +} + +#endif + +/* + * Description block for a Comtrol Hostess SV11 card + */ + +static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow) +{ + struct z8530_dev *dev; + struct slvl_device *sv; + struct slvl_board *b; + + int i; + unsigned long flags; + int u; + + /* + * Get the needed I/O space + */ + + if(check_region(iobase, 8)) + { + printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); + return NULL; + } + request_region(iobase, 8, "Sealevel 4021"); + + b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); + if(!b) + goto fail3; + + memset(b, 0, sizeof(*sv)); + + b->dev[0].chan = &b->board.chanA; + b->dev[1].chan = &b->board.chanB; + + dev=&b->board; + + /* + * Stuff in the I/O addressing + */ + + dev->active = 0; + + b->iobase = iobase; + + /* + * Select 8530 delays for the old board + */ + + if(slow) + iobase |= Z8530_PORT_SLEEP; + + dev->chanA.ctrlio=iobase+1; + dev->chanA.dataio=iobase; + dev->chanB.ctrlio=iobase+3; + dev->chanB.dataio=iobase+2; + + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + + /* + * Assert DTR enable DMA + */ + + outb(3|(1<<7), b->iobase+4); + + + /* We want a fast IRQ for this device. Actually we'd like an even faster + IRQ ;) - This is one driver RtLinux is made for */ + + if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0) + { + printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); + goto fail2; + } + + dev->irq=irq; + dev->chanA.private=&b->dev[0]; + dev->chanB.private=&b->dev[1]; + dev->chanA.netdevice=&b->dev[0].netdev.dev; + dev->chanB.netdevice=&b->dev[1].netdev.dev; + dev->chanA.dev=dev; + dev->chanB.dev=dev; + dev->name=b->dev[0].name; + + dev->chanA.txdma=3; + dev->chanA.rxdma=1; + if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0) + goto fail; + + if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0) + goto dmafail; + + save_flags(flags); + cli(); + + /* + * Begin normal initialise + */ + + if(z8530_init(dev)!=0) + { + printk(KERN_ERR "Z8530 series device not found.\n"); + goto dmafail2; + } + if(dev->type==Z85C30) + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); + } + else + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); + } + + /* + * Now we can take the IRQ + */ + + restore_flags(flags); + + for(u=0; u<2; u++) + { + sv=&b->dev[u]; + sv->channel = u; + + for(i=0;i<999;i++) + { + sprintf(sv->name,"hdlc%d", i); + if(dev_get(sv->name)==NULL) + { + struct device *d=sv->chan->netdevice; + + /* + * Initialise the PPP components + */ + sppp_attach(&sv->netdev); + + /* + * Local fields + */ + sprintf(sv->name,"hdlc%d", i); + + d->name = sv->name; + d->base_addr = iobase; + d->irq = irq; + d->priv = sv; + d->init = NULL; + + d->open = sealevel_open; + d->stop = sealevel_close; + d->hard_start_xmit = sealevel_queue_xmit; + d->get_stats = sealevel_get_stats; + d->set_multicast_list = NULL; + d->do_ioctl = sealevel_ioctl; +#ifdef LINUX_21 + d->neigh_setup = sealevel_neigh_setup_dev; + dev_init_buffers(d); +#else + d->init = return_0; +#endif + d->set_mac_address = NULL; + + if(register_netdev(d)==-1) + { + printk(KERN_ERR "%s: unable to register device.\n", + sv->name); + goto fail_unit; + } + + break; + } + } + } + z8530_describe(dev, "I/O", iobase); + dev->active=1; + return b; + +fail_unit: + if(u==1) + unregister_netdev(b->dev[0].chan->netdevice); + +dmafail2: + free_dma(dev->chanA.rxdma); +dmafail: + free_dma(dev->chanA.txdma); +fail: + free_irq(irq, dev); +fail2: + kfree(b); +fail3: + release_region(iobase,8); + return NULL; +} + +static void slvl_shutdown(struct slvl_board *b) +{ + int u; + + z8530_shutdown(&b->board); + + for(u=0; u<2; u++) + { + sppp_detach(&b->dev[u].netdev.dev); + unregister_netdev(&b->dev[u].netdev.dev); + } + + free_irq(b->board.irq, &b->board); + free_dma(b->board.chanA.rxdma); + free_dma(b->board.chanA.txdma); + /* DMA off on the card, drop DTR */ + outb(0, b->iobase); + release_region(b->iobase, 8); +} + +#ifdef MODULE + +static int io=0x238; +static int txdma=1; +static int rxdma=3; +static int irq=5; +static int slow=0; + +#ifdef LINUX_21 +MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); +MODULE_PARM(txdma,"i"); +MODULE_PARM_DESC(txdma, "Transmit DMA channel"); +MODULE_PARM(rxdma,"i"); +MODULE_PARM_DESC(rxdma, "Receive DMA channel"); +MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); +MODULE_PARM(slow,"i"); +MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); + +MODULE_AUTHOR("Bulding Number Three Ltd"); +MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); +#endif + +static struct slvl_board *slvl_unit; + +int init_module(void) +{ + printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n"); + printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); + if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL) + return -ENODEV; + return 0; +} + +void cleanup_module(void) +{ + if(slvl_unit) + slvl_shutdown(slvl_unit); +} + +#endif + diff -u --recursive --new-file v2.3.9/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.3.9/linux/drivers/net/seeq8005.c Tue Dec 29 11:32:06 1998 +++ linux/drivers/net/seeq8005.c Mon Jul 5 19:56:46 1999 @@ -108,8 +108,8 @@ struct netdev_entry seeq8005_drv = {"seeq8005", seeq8005_probe1, SEEQ8005_IO_EXTENT, seeq8005_portlist}; #else -__initfunc(int -seeq8005_probe(struct device *dev)) +int __init +seeq8005_probe(struct device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -135,7 +135,7 @@ probes on the ISA bus. A good device probes avoids doing writes, and verifies that the correct device exists and functions. */ -__initfunc(static int seeq8005_probe1(struct device *dev, int ioaddr)) +static int __init seeq8005_probe1(struct device *dev, int ioaddr) { static unsigned version_printed = 0; int i,j; @@ -736,6 +736,54 @@ outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); } +#ifdef MODULE + +static char devicename[9] = { 0, }; + +static struct device dev_seeq = +{ + devicename, /* device name is inserted by linux/drivers/net/net_init.c */ + 0, 0, 0, 0, + 0x300, 5, + 0, 0, 0, NULL, seeq8005_probe +}; + +static int io=0x320; +static int irq=10; +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); + +int init_module(void) +{ + dev_seeq.irq=irq; + dev_seeq.base_addr=io; + if (register_netdev(&dev_seeq) != 0) + return -EIO; + return 0; +} + +void cleanup_module(void) +{ + /* + * No need to check MOD_IN_USE, as sys_delete_module() checks. + */ + + unregister_netdev(&dev_seeq); + + /* + * Free up the private structure, or leak memory :-) + */ + + kfree(dev_seeq.priv); + dev_seeq.priv = NULL; /* gets re-allocated by el1_probe1 */ + + /* + * If we don't do this, we can't re-insmod it later. + */ + release_region(dev_seeq.base_addr, EL1_IO_EXTENT); +} + +#endif /* MODULE */ /* * Local variables: diff -u --recursive --new-file v2.3.9/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.3.9/linux/drivers/net/slhc.c Fri Dec 18 09:40:56 1998 +++ linux/drivers/net/slhc.c Mon Jul 5 20:35:18 1999 @@ -77,7 +77,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c --- v2.3.9/linux/drivers/net/sunbmac.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/net/sunbmac.c Mon Jul 5 20:35:18 1999 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.3.9/linux/drivers/net/sunhme.c Thu May 27 09:55:21 1999 +++ linux/drivers/net/sunhme.c Sun Jul 4 09:53:12 1999 @@ -3406,7 +3406,7 @@ /* Set the latency timer and cache line size as well, * PROM leaves it at zero. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); #ifdef __sparc_v9__ /* NOTE: Cache line size is in 32-bit word units. */ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); diff -u --recursive --new-file v2.3.9/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.3.9/linux/drivers/net/sunlance.c Sun Mar 21 07:22:00 1999 +++ linux/drivers/net/sunlance.c Mon Jul 5 20:35:18 1999 @@ -108,7 +108,6 @@ #include #include -#include #include /* Define: 2^4 Tx buffers and 2^4 Rx buffers */ diff -u --recursive --new-file v2.3.9/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.3.9/linux/drivers/net/tulip.c Tue Jan 19 13:18:45 1999 +++ linux/drivers/net/tulip.c Mon Jul 5 19:56:46 1999 @@ -327,6 +327,10 @@ TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, }; +enum desc_status_bits { + DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, +}; + /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { s32 status; @@ -469,10 +473,12 @@ (PCI_CLASS_NETWORK_ETHERNET << 8, reverse_probe ? 0xfe - pci_index : pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) + { if (reverse_probe) continue; else break; + } pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pci_bus, pci_device_fn, @@ -1536,10 +1542,12 @@ outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13); } else { /* Unknown chip type with no media table. */ if (tp->default_port == 0) - if (tp->mii_cnt) { + { + if (tp->mii_cnt) dev->if_port = 11; - } else + else dev->if_port = 3; + } if (media_cap[dev->if_port] & MediaIsMII) { new_csr6 = 0x020E0000; } else if (media_cap[dev->if_port] & MediaIsFx) { @@ -2698,8 +2706,8 @@ /* Same setup recently queued, we need not add it. */ } else { unsigned long flags; - unsigned int entry; - + unsigned int entry, dummy = 0; + save_flags(flags); cli(); entry = tp->cur_tx++ % TX_RING_SIZE; @@ -2709,7 +2717,8 @@ tp->tx_ring[entry].length = (entry == TX_RING_SIZE-1) ? 0x02000000 : 0; tp->tx_ring[entry].buffer1 = 0; - tp->tx_ring[entry].status = 0x80000000; + /* race with chip, set DescOwned later */ + dummy = entry; entry = tp->cur_tx++ % TX_RING_SIZE; } @@ -2724,6 +2733,8 @@ dev->tbusy = 1; tp->tx_full = 1; } + if (dummy >= 0) + tp->tx_ring[dummy].status = DescOwned; restore_flags(flags); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); diff -u --recursive --new-file v2.3.9/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.9/linux/drivers/net/via-rhine.c Mon May 10 13:00:10 1999 +++ linux/drivers/net/via-rhine.c Mon Jul 5 19:56:46 1999 @@ -1,6 +1,6 @@ /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */ /* - Written 1998 by Donald Becker. + Written 1998-1999 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License (GPL), incorporated herein by reference. @@ -20,7 +20,7 @@ */ static const char *versionA = -"via-rhine.c:v1.00 9/5/98 Written by Donald Becker\n"; +"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"; @@ -81,9 +81,11 @@ #include #include -/* This driver was written to use PCI memory space, however some boards - only work with I/O space accesses. */ +/* 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 #ifdef VIA_USE_IO #undef readb #undef readw @@ -105,6 +107,7 @@ #define RUN_AT(x) (jiffies + (x)) #if (LINUX_VERSION_CODE >= 0x20100) +char kernel_version[] = UTS_RELEASE; #else #ifndef __alpha__ #define ioremap vremap @@ -502,6 +505,7 @@ #ifndef MODULE int via_rhine_probe(struct device *dev) { + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); return pci_etherdev_probe(dev, pci_tbl); } #endif @@ -510,13 +514,9 @@ struct device *dev, long ioaddr, int irq, int chip_id, int card_idx) { - static int did_version = 0; /* Already printed version info */ struct netdev_private *np; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - if (debug > 0 && did_version++ == 0) - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); - dev = init_etherdev(dev, 0); printk(KERN_INFO "%s: %s at 0x%lx, ", @@ -685,6 +685,8 @@ ioaddr + IntrEnable); np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; + if (np->duplex_lock) + np->chip_cmd |= CmdFDuplex; writew(np->chip_cmd, ioaddr + ChipCmd); check_duplex(dev); @@ -1053,7 +1055,6 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - np->stats.rx_bytes += pkt_len; np->stats.rx_packets++; } entry = (++np->cur_rx) % RX_RING_SIZE; @@ -1182,7 +1183,7 @@ } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); - rx_mode = 0x0C; + rx_mode = 0x08; } writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig); } diff -u --recursive --new-file v2.3.9/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.3.9/linux/drivers/net/wavelan.c Thu Apr 29 11:53:41 1999 +++ linux/drivers/net/wavelan.c Tue Jul 6 19:08:33 1999 @@ -64,8 +64,8 @@ /* * Translate PSA irq parameter to irq number */ -__initfunc(static int -wv_psa_to_irq(u_char irqval)) +static int __init +wv_psa_to_irq(u_char irqval) { int irq; @@ -2087,12 +2087,6 @@ { struct iw_range range; - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - sizeof(struct iw_range)); - if(ret) - break; - /* Set the length (useless: it's constant). */ wrq->u.data.length = sizeof(struct iw_range); @@ -2118,8 +2112,8 @@ range.max_qual.noise = MMR_SILENCE_LVL; /* Copy structure to the user buffer. */ - copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range)); + if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range))) + ret = -EFAULT; } break; @@ -2136,18 +2130,12 @@ { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, }; - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - sizeof(priv)); - if(ret) - break; - /* Set the number of available ioctls. */ wrq->u.data.length = 4; /* Copy structure to the user buffer. */ - copy_to_user(wrq->u.data.pointer, (u_char *) priv, - sizeof(priv)); + if (copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv))) + ret = -EFAULT; } break; @@ -2169,14 +2157,11 @@ struct sockaddr address[IW_MAX_SPY]; int i; - /* Verify where the user has set his addresses. */ - ret = verify_area(VERIFY_READ, wrq->u.data.pointer, - sizeof(struct sockaddr) * lp->spy_number); - if(ret) - break; /* Copy addresses to the driver. */ - copy_from_user(address, wrq->u.data.pointer, - sizeof(struct sockaddr) * lp->spy_number); + if (copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number)) { + ret = -EFAULT; + break; + } /* Copy addresses to the lp structure. */ for(i = 0; i < lp->spy_number; i++) @@ -2215,13 +2200,6 @@ struct sockaddr address[IW_MAX_SPY]; int i; - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - (sizeof(iw_qual) + sizeof(struct sockaddr)) - * IW_MAX_SPY); - if(ret) - break; - /* Copy addresses from the lp structure. */ for(i = 0; i < lp->spy_number; i++) { @@ -2231,13 +2209,18 @@ } /* Copy addresses to the user buffer. */ - copy_to_user(wrq->u.data.pointer, address, - sizeof(struct sockaddr) * lp->spy_number); - + if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number)) { + ret = -EFAULT; + break; + } + /* Copy stats to the user buffer (just after). */ - copy_to_user(wrq->u.data.pointer + + if (copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number); + lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) { + ret = -EFAULT; + break; + } /* Reset updated flags. */ for(i = 0; i < lp->spy_number; i++) @@ -2283,14 +2266,11 @@ /* Are there addresses to copy? */ if(lp->his_number > 0) { - /* Verify where the user has set his addresses. */ - ret = verify_area(VERIFY_READ, wrq->u.data.pointer, - sizeof(char) * lp->his_number); - if(ret) - break; /* Copy interval ranges to the driver */ - copy_from_user(lp->his_range, wrq->u.data.pointer, - sizeof(char) * lp->his_number); + if (copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number)) { + ret = -EFAULT; + break; + } /* Reset structure. */ memset(lp->his_sum, 0x00, sizeof(long) * 16); @@ -2304,15 +2284,10 @@ /* Give back the distribution statistics */ if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) { - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - sizeof(long) * 16); - if(ret) - break; - /* Copy data to the user buffer. */ - copy_to_user(wrq->u.data.pointer, lp->his_sum, - sizeof(long) * lp->his_number); + if (copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number)) + ret = -EFAULT; + } /* if(pointer != NULL) */ break; #endif /* HISTOGRAM */ @@ -4015,8 +3990,8 @@ * device structure * (called by wavelan_probe() and via init_module()). */ -__initfunc(static int -wavelan_config(device * dev)) +static int __init +wavelan_config(device * dev) { u_long ioaddr = dev->base_addr; u_char irq_mask; @@ -4132,8 +4107,8 @@ * We follow the example in drivers/net/ne.c. * (called in "Space.c") */ -__initfunc(int -wavelan_probe(device * dev)) +int __init +wavelan_probe(device * dev) { short base_addr; mac_addr mac; /* MAC address (check existence of WaveLAN) */ @@ -4265,6 +4240,11 @@ /* Create device and set basic arguments. */ dev = kmalloc(sizeof(struct device), GFP_KERNEL); + if(dev==NULL) + { + ret = -ENOMEM; + break; + } memset(dev, 0x00, sizeof(struct device)); dev->name = name[i]; dev->base_addr = io[i]; diff -u --recursive --new-file v2.3.9/linux/drivers/net/z85230.c linux/drivers/net/z85230.c --- v2.3.9/linux/drivers/net/z85230.c Sat Apr 24 17:51:48 1999 +++ linux/drivers/net/z85230.c Mon Jul 5 19:56:46 1999 @@ -23,7 +23,8 @@ * Z85230: * Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud * X.25 is not unrealistic on all machines. DMA mode can in theory - * handle T1/E1 quite nicely. + * handle T1/E1 quite nicely. In practice the limit seems to be about + * 512Kbit->1Mbit depending on motherboard. * * Z85C30: * 64K will take DMA, 9600 baud X.25 should be ok. @@ -187,7 +188,6 @@ 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx, 9, NV|MIE|NORESET, 23, 3, /* Extended mode AUTO TX and EOM*/ - 31, 3, /* Extended mode AUTO TX and EOM*/ 255 }; @@ -834,6 +834,8 @@ int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c) { + unsigned long flags; + printk("Opening sync interface for TX-DMA\n"); c->sync = 1; c->mtu = dev->mtu+64; @@ -889,14 +891,21 @@ c->regs[R14]|= DTRREQ; write_zsreg(c, R14, c->regs[R14]); + c->regs[R1]&= ~TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); + /* * Set up the DMA configuration */ + flags = claim_dma_lock(); + disable_dma(c->txdma); clear_dma_ff(c->txdma); set_dma_mode(c->txdma, DMA_MODE_WRITE); disable_dma(c->txdma); + + release_dma_lock(flags); /* * Select the DMA interrupt handlers @@ -918,6 +927,7 @@ int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c) { + unsigned long flags; u8 chk; c->irqs = &z8530_nop; c->max = 0; @@ -927,10 +937,14 @@ * Disable the PC DMA channels */ + flags = claim_dma_lock(); + disable_dma(c->txdma); clear_dma_ff(c->txdma); c->txdma_on = 0; c->tx_dma_used = 0; + + release_dma_lock(flags); /* * Disable DMA control mode diff -u --recursive --new-file v2.3.9/linux/drivers/net/zlib.c linux/drivers/net/zlib.c --- v2.3.9/linux/drivers/net/zlib.c Tue Feb 10 12:56:45 1998 +++ linux/drivers/net/zlib.c Mon Jul 5 20:35:18 1999 @@ -5113,10 +5113,6 @@ /* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ -#ifdef DEBUG_ZLIB -#include -#endif - /* #include "zutil.h" */ #ifndef NO_DUMMY_DECL diff -u --recursive --new-file v2.3.9/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c --- v2.3.9/linux/drivers/pci/oldproc.c Wed Jun 9 16:59:15 1999 +++ linux/drivers/pci/oldproc.c Thu Jul 8 14:50:20 1999 @@ -263,6 +263,7 @@ DEVICE( BROOKTREE, BROOKTREE_878, "Bt878"), DEVICE( BROOKTREE, BROOKTREE_8474, "Bt8474"), DEVICE( SIERRA, SIERRA_STB, "STB Horizon 64"), + DEVICE( SGI, SGI_IOC3, "IOC3"), DEVICE( ACC, ACC_2056, "2056"), DEVICE( WINBOND, WINBOND_83769, "W83769F"), DEVICE( WINBOND, WINBOND_82C105, "SL82C105"), @@ -308,6 +309,7 @@ DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZVPLUS, "MagicGraph 128ZV+"), DEVICE( ASP, ASP_ABP940, "ABP940"), DEVICE( ASP, ASP_ABP940U, "ABP940U"), DEVICE( ASP, ASP_ABP940UW, "ABP940UW"), @@ -465,6 +467,7 @@ DEVICE( SATSAGEM, SATSAGEM_PCR2101,"PCR2101 DVB receiver"), DEVICE( SATSAGEM, SATSAGEM_TELSATTURBO,"Telsat Turbo DVB"), DEVICE( HUGHES, HUGHES_DIRECPC, "DirecPC"), + DEVICE( ENSONIQ, ENSONIQ_ES1371, "ES1371"), DEVICE( ENSONIQ, ENSONIQ_AUDIOPCI,"AudioPCI"), DEVICE( ALTEON, ALTEON_ACENIC, "AceNIC"), DEVICE( PICTUREL, PICTUREL_PCIVST,"PCIVST"), @@ -503,6 +506,7 @@ DEVICE( S3, S3_ViRGE_MXPMV, "ViRGE/MX+MV"), DEVICE( S3, S3_SONICVIBES, "SonicVibes"), DEVICE( DCI, DCI_PCCOM4, "PC COM PCI Bus 4 port serial Adapter"), + DEVICE( GENROCO, GENROCO_HFP832, "TURBOstor HFP832"), DEVICE( INTEL, INTEL_82375, "82375EB"), DEVICE( INTEL, INTEL_82424, "82424ZX Saturn"), DEVICE( INTEL, INTEL_82378, "82378IB"), @@ -541,6 +545,7 @@ DEVICE( KTI, KTI_ET32P2, "ET32P2"), DEVICE( ADAPTEC, ADAPTEC_7810, "AIC-7810 RAID"), DEVICE( ADAPTEC, ADAPTEC_7821, "AIC-7860"), + DEVICE( ADAPTEC, ADAPTEC_38602, "AIC-7860"), DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"), @@ -831,6 +836,7 @@ case PCI_VENDOR_ID_NETVIN: return "NetVin"; case PCI_VENDOR_ID_S3: return "S3 Inc."; case PCI_VENDOR_ID_DCI: return "Decision Computer Int."; + case PCI_VENDOR_ID_GENROCO: return "Genroco"; case PCI_VENDOR_ID_INTEL: return "Intel"; case PCI_VENDOR_ID_KTI: return "KTI"; case PCI_VENDOR_ID_ADAPTEC: return "Adaptec"; @@ -1027,7 +1033,7 @@ 0, &proc_array_inode_operations }; -__initfunc(void proc_old_pci_init(void)) +void __init proc_old_pci_init(void) { proc_register(&proc_root, &proc_old_pci); } diff -u --recursive --new-file v2.3.9/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.9/linux/drivers/pci/pci.c Sat Jun 19 18:20:13 1999 +++ linux/drivers/pci/pci.c Mon Jul 5 19:56:46 1999 @@ -138,7 +138,7 @@ } } -__initfunc(void pci_read_bases(struct pci_dev *dev, unsigned int howmany)) +void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany) { unsigned int reg; u32 l; @@ -166,7 +166,7 @@ } -__initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) +unsigned int __init pci_scan_bus(struct pci_bus *bus) { unsigned int devfn, l, max, class; unsigned char cmd, irq, tmp, hdr_type, is_multi = 0; @@ -192,6 +192,11 @@ continue; dev = kmalloc(sizeof(*dev), GFP_ATOMIC); + if(dev==NULL) + { + printk(KERN_ERR "pci: out of memory.\n"); + continue; + } memset(dev, 0, sizeof(*dev)); dev->bus = bus; dev->devfn = devfn; @@ -300,6 +305,11 @@ * Insert it into the tree of buses. */ child = kmalloc(sizeof(*child), GFP_ATOMIC); + if(child==NULL) + { + printk(KERN_ERR "pci: out of memory for bridge.\n"); + continue; + } memset(child, 0, sizeof(*child)); child->next = bus->children; bus->children = child; @@ -389,7 +399,7 @@ return b; } -__initfunc(void pci_init(void)) +void __init pci_init(void) { pcibios_init(); @@ -415,7 +425,7 @@ #endif } -__initfunc(void pci_setup (char *str, int *ints)) +void __init pci_setup (char *str, int *ints) { while (str) { char *k = strchr(str, ','); diff -u --recursive --new-file v2.3.9/linux/drivers/pnp/Config.in linux/drivers/pnp/Config.in --- v2.3.9/linux/drivers/pnp/Config.in Wed Jul 23 11:14:31 1997 +++ linux/drivers/pnp/Config.in Thu Jul 1 14:22:57 1999 @@ -1,16 +1,3 @@ # # Plug and Play configuration # - -mainmenu_option next_comment -comment 'Plug and Play support' - -bool 'Plug and Play support' CONFIG_PNP - -if [ "$CONFIG_PNP" = "y" ]; then - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Auto-probe for parallel devices' CONFIG_PNP_PARPORT $CONFIG_PARPORT - fi -fi - -endmenu diff -u --recursive --new-file v2.3.9/linux/drivers/pnp/Makefile linux/drivers/pnp/Makefile --- v2.3.9/linux/drivers/pnp/Makefile Wed Jul 23 11:14:31 1997 +++ linux/drivers/pnp/Makefile Thu Jul 1 14:22:57 1999 @@ -7,10 +7,6 @@ # # Note 2! The CFLAGS definitions are now inherited from the # parent makes.. -# -# Note 3! Plug and Play is the Borg. We have assimilated some other -# drivers in the `char', `net' and `scsi' directories, but left them -# there to allay suspicion. SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) @@ -21,13 +17,5 @@ LX_OBJS := MI_OBJS := MIX_OBJS := - -ifeq ($(CONFIG_PNP_PARPORT),y) - LX_OBJS += parport_probe.o -else - ifeq ($(CONFIG_PNP_PARPORT),m) - MX_OBJS += parport_probe.o - endif -endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.9/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c --- v2.3.9/linux/drivers/pnp/parport_probe.c Wed Jan 20 13:29:18 1999 +++ linux/drivers/pnp/parport_probe.c Wed Dec 31 16:00:00 1969 @@ -1,288 +0,0 @@ -/* $Id: parport_probe.c,v 1.3 1997/10/19 18:18:46 phil Exp $ - * Parallel port device probing code - * - * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de - * Philip Blundell - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#undef DEBUG_PROBE - -static inline int read_nibble(struct parport *port) -{ - unsigned char i; - i = parport_read_status(port)>>3; - i &= ~8; - if ((i & 0x10) == 0) i |= 8; - return (i & 0x0f); -} - -static void read_terminate(struct parport *port) { - parport_write_control(port, (parport_read_control(port) & ~2) | 8); - /* SelectIN high, AutoFeed low */ - if (parport_wait_peripheral(port, 0x80, 0)) - /* timeout, SelectIN high, Autofeed low */ - return; - parport_write_control(port, parport_read_control(port) | 2); - /* AutoFeed high */ - parport_wait_peripheral(port, 0x80, 0x80); - /* no timeout possible, Autofeed low, SelectIN high */ - parport_write_control(port, (parport_read_control(port) & ~2) | 8); -} - -static long read_polled(struct parport *port, char *buf, - unsigned long length) -{ - int i; - char *temp=buf; - unsigned int count = 0; - unsigned char z=0; - unsigned char Byte=0; - unsigned long igiveupat=jiffies+5*HZ; - - for (i=0; time_before(jiffies, igiveupat); i++) { - /* if(current->need_resched) schedule(); */ - parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */ - if (parport_wait_peripheral(port, 0x40, 0)) { -#ifdef DEBUG_PROBE - /* Some peripherals just time out when they've sent - all their data. */ - printk("%s: read1 timeout.\n", port->name); -#endif - parport_write_control(port, parport_read_control(port) & ~2); - break; - } - z = read_nibble(port); - parport_write_control(port, parport_read_control(port) & ~2); /* AutoFeed low */ - if (parport_wait_peripheral(port, 0x40, 0x40)) { - printk("%s: read2 timeout.\n", port->name); - break; - } - if ((i & 1) != 0) { - Byte |= (z<<4); - if (temp) - *(temp++) = Byte; - if (++count == length) - temp = NULL; - /* Does the error line indicate end of data? */ - if ((parport_read_status(port) & LP_PERRORP) == - LP_PERRORP) - break; - } else - Byte=z; - } - read_terminate(port); - return count; -} - -int parport_probe(struct parport *port, char *buffer, int len) -{ - struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev); - - int result = 0; - - if (!dev) { - printk("%s: unable to register for probe.\n", port->name); - return -EINVAL; - } - - parport_claim_or_block(dev); - - switch (parport_ieee1284_nibble_mode_ok(port, 4)) { - case 2: - current->state=TASK_INTERRUPTIBLE; - /* HACK: wait 10ms because printer seems to ack wrong */ - schedule_timeout((HZ+99)/100); - result = read_polled(port, buffer, len); - break; - default: - result = -EIO; - break; - } - - parport_release(dev); - parport_unregister_device(dev); - - return result; -} - -static struct { - char *token; - char *descr; -} classes[] = { - { "", "Legacy device" }, - { "PRINTER", "Printer" }, - { "MODEM", "Modem" }, - { "NET", "Network device" }, - { "HDC", "Hard disk" }, - { "PCMCIA", "PCMCIA" }, - { "MEDIA", "Multimedia device" }, - { "FDC", "Floppy disk" }, - { "PORTS", "Ports" }, - { "SCANNER", "Scanner" }, - { "DIGICAM", "Digital camera" }, - { "", "Unknown device" }, - { "", "Unspecified" }, - { NULL, NULL } -}; - -static char *strdup(char *str) -{ - int n = strlen(str)+1; - char *s = kmalloc(n, GFP_KERNEL); - if (!s) return NULL; - return strcpy(s, str); -} - -static void parse_data(struct parport *port, char *str) -{ - char *txt = kmalloc(strlen(str)+1, GFP_KERNEL); - char *p = txt, *q; - int guessed_class = PARPORT_CLASS_UNSPEC; - - if (!txt) { - printk("%s probe: memory squeeze\n", port->name); - return; - } - strcpy(txt, str); - while (p) { - char *sep; - q = strchr(p, ';'); - if (q) *q = 0; - sep = strchr(p, ':'); - if (sep) { - char *u = p; - *(sep++) = 0; - while (*u) { - *u = toupper(*u); - u++; - } - if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) { - if (port->probe_info.mfr) - kfree (port->probe_info.mfr); - port->probe_info.mfr = strdup(sep); - } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) { - if (port->probe_info.model) - kfree (port->probe_info.model); - port->probe_info.model = strdup(sep); - } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) { - int i; - if (port->probe_info.class_name) - kfree (port->probe_info.class_name); - port->probe_info.class_name = strdup(sep); - for (u = sep; *u; u++) - *u = toupper(*u); - for (i = 0; classes[i].token; i++) { - if (!strcmp(classes[i].token, sep)) { - port->probe_info.class = i; - goto rock_on; - } - } - printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep); - port->probe_info.class = PARPORT_CLASS_OTHER; - } else if (!strcmp(p, "CMD") || !strcmp(p, "COMMAND SET")) { - if (port->probe_info.cmdset) - kfree (port->probe_info.cmdset); - port->probe_info.cmdset = strdup(sep); - /* if it speaks printer language, it's - probably a printer */ - if (strstr(sep, "PJL") || strstr(sep, "PCL")) - guessed_class = PARPORT_CLASS_PRINTER; - } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) { - if (port->probe_info.description) - kfree (port->probe_info.description); - port->probe_info.description = strdup(sep); - } - } - rock_on: - if (q) p = q+1; else p=NULL; - } - - /* If the device didn't tell us its class, maybe we have managed to - guess one from the things it did say. */ - if (port->probe_info.class == PARPORT_CLASS_UNSPEC) - port->probe_info.class = guessed_class; - - kfree(txt); -} - -static void pretty_print(struct parport *port) -{ - printk(KERN_INFO "%s: %s", port->name, - classes[port->probe_info.class].descr); - if (port->probe_info.class) { - printk(", %s %s", port->probe_info.mfr, - port->probe_info.model); - } - printk("\n"); -} - -void parport_probe_one(struct parport *port) -{ - char *buffer = kmalloc(2048, GFP_KERNEL); - int r; - - MOD_INC_USE_COUNT; - port->probe_info.model = strdup ("Unknown device"); - port->probe_info.mfr = strdup ("Unknown vendor"); - port->probe_info.description = port->probe_info.cmdset = NULL; - port->probe_info.class = PARPORT_CLASS_UNSPEC; - port->probe_info.class_name = NULL; - - if (!buffer) { - printk(KERN_ERR "%s probe: Memory squeeze.\n", port->name); - return; - } - - r = parport_probe(port, buffer, 2047); - - if (r < 0) { - printk(KERN_INFO "%s: no IEEE-1284 device present.\n", - port->name); - port->probe_info.class = PARPORT_CLASS_LEGACY; - } else if (r == 0) { - printk(KERN_INFO "%s: no ID data returned by device.\n", - port->name); - } else { - buffer[r] = 0; -#ifdef DEBUG_PROBE - printk("%s id: %s\n", port->name, buffer+2); -#endif - parse_data(port, buffer+2); - pretty_print(port); - } - kfree(buffer); - MOD_DEC_USE_COUNT; -} - -#if MODULE -int init_module(void) -{ - struct parport *p; - for (p = parport_enumerate(); p; p = p->next) - parport_probe_one(p); - parport_probe_hook = &parport_probe_one; - return 0; -} - -void cleanup_module(void) -{ - parport_probe_hook = NULL; -} -#endif diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c --- v2.3.9/linux/drivers/sbus/char/bpp.c Wed Jun 9 14:44:25 1999 +++ linux/drivers/sbus/char/bpp.c Mon Jul 5 20:35:18 1999 @@ -20,10 +20,10 @@ #include #include -#include +#include +#include #if defined(__i386__) -# include # include # include #endif @@ -34,7 +34,6 @@ # include /* OpenProm Library */ # include /* struct linux_sbus *SBus_chain */ -# include /* sparc_alloc_io() */ #endif #include diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.3.9/linux/drivers/sbus/char/sab82532.c Wed May 12 08:41:15 1999 +++ linux/drivers/sbus/char/sab82532.c Sun Jul 4 09:53:12 1999 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.31 1999/05/12 11:15:10 davem Exp $ +/* $Id: sab82532.c,v 1.32 1999/07/03 08:57:41 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -1672,7 +1672,6 @@ #endif while (info->xmit_cnt || !info->all_sent) { current->state = TASK_INTERRUPTIBLE; - current->counter = 0; schedule_timeout(char_time); if (signal_pending(current)) break; @@ -2136,7 +2135,7 @@ __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.31 $"; + char *revision = "$Revision: 1.32 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.3.9/linux/drivers/sbus/char/su.c Thu Jun 17 01:08:50 1999 +++ linux/drivers/sbus/char/su.c Sun Jul 4 09:53:12 1999 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.21 1999/06/11 10:23:42 davem Exp $ +/* $Id: su.c,v 1.22 1999/07/03 08:57:43 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -1836,7 +1836,6 @@ printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; @@ -2215,7 +2214,7 @@ */ __initfunc(static __inline__ void show_su_version(void)) { - char *revision = "$Revision: 1.21 $"; + char *revision = "$Revision: 1.22 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.3.9/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c --- v2.3.9/linux/drivers/sbus/sbus.c Mon May 31 22:08:10 1999 +++ linux/drivers/sbus/sbus.c Mon Jul 5 20:35:18 1999 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c --- v2.3.9/linux/drivers/scsi/53c7xx.c Mon Oct 5 13:43:31 1998 +++ linux/drivers/scsi/53c7xx.c Mon Jul 5 20:35:18 1999 @@ -254,9 +254,9 @@ #include #include #include +#include #ifdef CONFIG_AMIGA -#include #include #include #include @@ -266,7 +266,6 @@ #endif #ifdef CONFIG_MVME16x -#include #include #define BIG_ENDIAN @@ -275,7 +274,6 @@ #endif #ifdef CONFIG_BVME6000 -#include #include #define BIG_ENDIAN diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c --- v2.3.9/linux/drivers/scsi/NCR53C9x.c Fri Dec 18 09:47:38 1998 +++ linux/drivers/scsi/NCR53C9x.c Mon Jul 5 19:56:46 1999 @@ -3390,6 +3390,7 @@ struct ESP_regs *eregs; Scsi_Cmnd *SCptr; int what_next = do_intr_end; + unsigned long flags; #ifdef CONFIG_SCSI_SUNESP struct sparc_dma_registers *dregs = (struct sparc_dma_registers*) esp->dregs; @@ -3610,7 +3611,9 @@ } SCptr->result = (DID_RESET << 16); + spin_lock_irqsave(&io_request_lock,flags); SCptr->scsi_done(SCptr); + spin_unlock_irqrestore(&io_request_lock, flags); } esp->current_SC = NULL; if(esp->disconnected_SC) { @@ -3625,7 +3628,9 @@ } SCptr->result = (DID_RESET << 16); + spin_lock_irqsave(&io_request_lock,flags); SCptr->scsi_done(SCptr); + spin_unlock_irqrestore(&io_request_lock, flags); } } esp->resetting_bus = 0; diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.3.9/linux/drivers/scsi/aha152x.c Wed May 12 13:19:17 1999 +++ linux/drivers/scsi/aha152x.c Tue Jul 6 19:08:33 1999 @@ -183,7 +183,7 @@ ************************************************************************** - + DESCRIPTION: This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI @@ -192,30 +192,30 @@ CONFIGURATION ARGUMENTS: - IOPORT base io address (0x340/0x140) - IRQ interrupt level (9-12; default 11) - SCSI_ID scsi id of controller (0-7; default 7) - RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on]) - PARITY enable parity checking (0/1; default 1 [on]) - SYNCHRONOUS enable synchronous transfers (0/1; default 0 [off]) - (NOT WORKING YET) - DELAY: bus reset delay (default 100) - EXT_TRANS: enable extended translation (0/1: default 0 [off]) - (see NOTES below) + IOPORT base io address (0x340/0x140) + IRQ interrupt level (9-12; default 11) + SCSI_ID scsi id of controller (0-7; default 7) + RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on]) + PARITY enable parity checking (0/1; default 1 [on]) + SYNCHRONOUS enable synchronous transfers (0/1; default 0 [off]) + (NOT WORKING YET) + DELAY: bus reset delay (default 100) + EXT_TRANS: enable extended translation (0/1: default 0 [off]) + (see NOTES below) COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile): -DAUTOCONF - use configuration the controller reports (AHA-152x only) + use configuration the controller reports (AHA-152x only) -DSKIP_BIOSTEST - Don't test for BIOS signature (AHA-1510 or disabled BIOS) + Don't test for BIOS signature (AHA-1510 or disabled BIOS) -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" - override for the first controller - + override for the first controller + -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" - override for the second controller + override for the second controller LILO COMMAND LINE OPTIONS: @@ -230,13 +230,13 @@ SYMBOLS FOR MODULE CONFIGURATION: - - aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS - configuration override of first controller - - - aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS - configuration override of second controller + + aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS + configuration override of first controller + + + aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS + configuration override of second controller NOTES ON EXT_TRANS: @@ -287,14 +287,14 @@ - for disks<1GB: use default translation (C/32/64) - for disks>1GB: - - take current geometry from the partition table - (using scsicam_bios_param and accept only `valid' geometries, - ie. either (C/32/64) or (C/63/255)). This can be extended - translation even if it's not enabled in the driver. - - if that fails, take extended translation if enabled by override, - kernel or module parameter, otherwise take default translation and - ask the user for verification. This might on not yet partitioned - disks or + - take current geometry from the partition table + (using scsicam_bios_param and accept only `valid' geometries, + ie. either (C/32/64) or (C/63/255)). This can be extended + translation even if it's not enabled in the driver. + - if that fails, take extended translation if enabled by override, + kernel or module parameter, otherwise take default translation and + ask the user for verification. This might on not yet partitioned + disks or REFERENCES USED: @@ -308,7 +308,7 @@ "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu) "Adaptec 1520/1522 User's Guide", Adaptec Corporation. - + Michael K. Johnson (johnsonm@sunsite.unc.edu) Drew Eckhardt (drew@cs.colorado.edu) @@ -350,9 +350,10 @@ #include -struct proc_dir_entry proc_scsi_aha152x = { - PROC_SCSI_AHA152X, 7, "aha152x", - S_IFDIR | S_IRUGO | S_IXUGO, 2 +struct proc_dir_entry proc_scsi_aha152x = +{ + PROC_SCSI_AHA152X, 7, "aha152x", + S_IFDIR | S_IRUGO | S_IXUGO, 2 }; /* DEFINES */ @@ -370,25 +371,25 @@ #if defined(DEBUG_AHA152X) -#undef SKIP_PORTS /* don't display ports */ +#undef SKIP_PORTS /* don't display ports */ -#undef DEBUG_QUEUE /* debug queue() */ -#undef DEBUG_RESET /* debug reset() */ -#undef DEBUG_INTR /* debug intr() */ -#undef DEBUG_SELECTION /* debug selection part in intr() */ -#undef DEBUG_MSGO /* debug message out phase in intr() */ -#undef DEBUG_MSGI /* debug message in phase in intr() */ -#undef DEBUG_STATUS /* debug status phase in intr() */ -#undef DEBUG_CMD /* debug command phase in intr() */ -#undef DEBUG_DATAI /* debug data in phase in intr() */ -#undef DEBUG_DATAO /* debug data out phase in intr() */ -#undef DEBUG_ABORT /* debug abort() */ -#undef DEBUG_DONE /* debug done() */ -#undef DEBUG_BIOSPARAM /* debug biosparam() */ - -#undef DEBUG_RACE /* debug race conditions */ -#undef DEBUG_PHASES /* debug phases (useful to trace) */ -#undef DEBUG_QUEUES /* debug reselection */ +#undef DEBUG_QUEUE /* debug queue() */ +#undef DEBUG_RESET /* debug reset() */ +#undef DEBUG_INTR /* debug intr() */ +#undef DEBUG_SELECTION /* debug selection part in intr() */ +#undef DEBUG_MSGO /* debug message out phase in intr() */ +#undef DEBUG_MSGI /* debug message in phase in intr() */ +#undef DEBUG_STATUS /* debug status phase in intr() */ +#undef DEBUG_CMD /* debug command phase in intr() */ +#undef DEBUG_DATAI /* debug data in phase in intr() */ +#undef DEBUG_DATAO /* debug data out phase in intr() */ +#undef DEBUG_ABORT /* debug abort() */ +#undef DEBUG_DONE /* debug done() */ +#undef DEBUG_BIOSPARAM /* debug biosparam() */ + +#undef DEBUG_RACE /* debug race conditions */ +#undef DEBUG_PHASES /* debug phases (useful to trace) */ +#undef DEBUG_QUEUES /* debug reselection */ /* recently used for debugging */ #if 0 @@ -424,46 +425,50 @@ #define IRQS IRQ_MAX-IRQ_MIN+1 enum { - not_issued = 0x0001, - in_selection = 0x0002, - disconnected = 0x0004, - aborted = 0x0008, - sent_ident = 0x0010, - in_other = 0x0020, - in_sync = 0x0040, - sync_ok = 0x0080, + not_issued = 0x0001, + in_selection = 0x0002, + disconnected = 0x0004, + aborted = 0x0008, + sent_ident = 0x0010, + in_other = 0x0020, + in_sync = 0x0040, + sync_ok = 0x0080, }; #if defined(MODULE) #if defined(DEBUG_AHA152X) -int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT }; -int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT }; +int aha152x[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; +int aha152x1[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; MODULE_PARM(aha152x, "1-9i"); MODULE_PARM(aha152x1, "1-9i"); #else -int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; -int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; +int aha152x[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; +int aha152x1[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; MODULE_PARM(aha152x, "1-8i"); MODULE_PARM(aha152x1, "1-8i"); #endif #endif /* set by aha152x_setup according to the command line */ -static int setup_count=0; -static int registered_count=0; +static int setup_count = 0; +static int registered_count = 0; static struct aha152x_setup { - int io_port; - int irq; - int scsiid; - int reconnect; - int parity; - int synchronous; - int delay; - int ext_trans; + int io_port; + int irq; + int scsiid; + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; #ifdef DEBUG_AHA152X - int debug; + int debug; #endif - char *conf; + char *conf; } setup[2]; static struct Scsi_Host *aha152x_host[IRQS]; @@ -480,30 +485,30 @@ #define ADDMSG(x) (MSG(MSGLEN++)=x) struct aha152x_hostdata { - Scsi_Cmnd *issue_SC; - Scsi_Cmnd *current_SC; - Scsi_Cmnd *disconnected_SC; - int aborting; - int abortion_complete; - int abort_result; - int commands; - - int reconnect; - int parity; - int synchronous; - int delay; - int ext_trans; - - int swint; - int service; - - unsigned char syncrate[8]; - - unsigned char message[256]; - int message_len; + Scsi_Cmnd *issue_SC; + Scsi_Cmnd *current_SC; + Scsi_Cmnd *disconnected_SC; + int aborting; + int abortion_complete; + int abort_result; + int commands; + + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; + + int swint; + int service; + + unsigned char syncrate[8]; + + unsigned char message[256]; + int message_len; #ifdef DEBUG_AHA152X - int debug; + int debug; #endif }; @@ -516,7 +521,7 @@ static void aha152x_panic(struct Scsi_Host *shpnt, char *msg); static void disp_ports(struct Scsi_Host *shpnt); -static void show_command(Scsi_Cmnd *ptr); +static void show_command(Scsi_Cmnd * ptr); static void show_queues(struct Scsi_Host *shpnt); static void disp_enintr(struct Scsi_Host *shpnt); @@ -528,8 +533,8 @@ /* possible i/o addresses for the AIC-6260 */ static unsigned short ports[] = { - 0x340, /* default first */ - 0x140 + 0x340, /* default first */ + 0x140 }; #define PORT_COUNT (sizeof(ports) / sizeof(unsigned short)) @@ -537,15 +542,15 @@ /* possible locations for the Adaptec BIOS */ static unsigned int addresses[] = { - 0xdc000, /* default first */ - 0xc8000, - 0xcc000, - 0xd0000, - 0xd4000, - 0xd8000, - 0xe0000, - 0xeb800, /* VTech Platinum SMP */ - 0xf0000, + 0xdc000, /* default first */ + 0xc8000, + 0xcc000, + 0xd0000, + 0xd4000, + 0xd8000, + 0xe0000, + 0xeb800, /* VTech Platinum SMP */ + 0xf0000, }; #define ADDRESS_COUNT (sizeof(addresses) / sizeof(unsigned int)) @@ -557,80 +562,103 @@ needed anyway. May be an information whether or not the BIOS supports extended translation could be also useful here. */ static struct signature { - unsigned char *signature; - int sig_offset; - int sig_length; + unsigned char *signature; + int sig_offset; + int sig_length; } signatures[] = + { - { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, /* Adaptec 152x */ - { "Adaptec AHA-1520B", 0x0b, 19 }, /* Adaptec 152x rev B */ - { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, /* on-board controller */ - { "Adaptec BIOS: ASW-B626", 0x0f, 22 }, /* on-board controller */ - { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, /* on-board controller */ - { "Adaptec BIOS:AIC-6360", 0xc, 21 }, /* on-board controller */ - { "ScsiPro SP-360 BIOS", 0x2873, 19 }, /* ScsiPro-Controller */ - { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, /* Gigabyte Local-Bus-SCSI */ - { "Adaptec BIOS:AVA-282X", 0xc, 21 }, /* Adaptec 282x */ - { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, /* IBM Thinkpad Dock II */ - { "Adaptec BIOS:AHA-1532P", 0x1c, 22 }, /* IBM Thinkpad Dock II SCSI */ - { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, /* DTC 3520A ISA SCSI */ + { + "Adaptec AHA-1520 BIOS", 0x102e, 21 + }, /* Adaptec 152x */ + { + "Adaptec AHA-1520B", 0x0b, 19 + }, /* Adaptec 152x rev B */ + { + "Adaptec ASW-B626 BIOS", 0x1029, 21 + }, /* on-board controller */ + { + "Adaptec BIOS: ASW-B626", 0x0f, 22 + }, /* on-board controller */ + { + "Adaptec ASW-B626 S2", 0x2e6c, 19 + }, /* on-board controller */ + { + "Adaptec BIOS:AIC-6360", 0xc, 21 + }, /* on-board controller */ + { + "ScsiPro SP-360 BIOS", 0x2873, 19 + }, /* ScsiPro-Controller */ + { + "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 + }, /* Gigabyte Local-Bus-SCSI */ + { + "Adaptec BIOS:AVA-282X", 0xc, 21 + }, /* Adaptec 282x */ + { + "Adaptec IBM Dock II SCSI", 0x2edd, 24 + }, /* IBM Thinkpad Dock II */ + { + "Adaptec BIOS:AHA-1532P", 0x1c, 22 + }, /* IBM Thinkpad Dock II SCSI */ + { + "DTC3520A Host Adapter BIOS", 0x318a, 26 + }, /* DTC 3520A ISA SCSI */ }; + #define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature)) #endif -static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */ -{ - unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ +static void do_pause(unsigned amount) +{ /* Pause for amount*10 milliseconds */ + unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ - while (time_before(jiffies, the_time)) - barrier(); + while (time_before(jiffies, the_time)) + barrier(); } /* * queue services: */ -static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +static inline void append_SC(Scsi_Cmnd ** SC, Scsi_Cmnd * new_SC) { - Scsi_Cmnd *end; + Scsi_Cmnd *end; - new_SC->host_scribble = (unsigned char *) NULL; - if(!*SC) - *SC=new_SC; - else { - for(end=*SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble) - ; - end->host_scribble = (unsigned char *) new_SC; - } + new_SC->host_scribble = (unsigned char *) NULL; + if (!*SC) + *SC = new_SC; + else { + for (end = *SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble); + end->host_scribble = (unsigned char *) new_SC; + } } -static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) +static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC) { - Scsi_Cmnd *ptr; + Scsi_Cmnd *ptr; - ptr=*SC; - if(ptr) - *SC= (Scsi_Cmnd *) (*SC)->host_scribble; - return ptr; + ptr = *SC; + if (ptr) + *SC = (Scsi_Cmnd *) (*SC)->host_scribble; + return ptr; } -static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun) +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd ** SC, int target, int lun) { - Scsi_Cmnd *ptr, *prev; - - for(ptr=*SC, prev=NULL; - ptr && ((ptr->target!=target) || (ptr->lun!=lun)); - prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble) - ; + Scsi_Cmnd *ptr, *prev; - if(ptr){ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - *SC= (Scsi_Cmnd *) ptr->host_scribble; - } + for (ptr = *SC, prev = NULL; + ptr && ((ptr->target != target) || (ptr->lun != lun)); + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); - return ptr; + if (ptr) { + if (prev) + prev->host_scribble = ptr->host_scribble; + else + *SC = (Scsi_Cmnd *) ptr->host_scribble; + } + return ptr; } /* @@ -638,12 +666,12 @@ */ static void make_acklow(struct Scsi_Host *shpnt) { - SETPORT(SXFRCTL0, CH1|SPIOEN); - GETPORT(SCSIDAT); - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1 | SPIOEN); + GETPORT(SCSIDAT); + SETPORT(SXFRCTL0, CH1); - while(TESTHI(SCSISIG, ACKI)) - barrier(); + while (TESTHI(SCSISIG, ACKI)) + barrier(); } /* @@ -658,61 +686,61 @@ */ static int getphase(struct Scsi_Host *shpnt) { - int phase, sstat1; - - while(1) { - do { - while(!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE|SCSIRSTI|REQINIT))) - barrier(); - if(sstat1 & BUSFREE) - return P_BUSFREE; - if(sstat1 & SCSIRSTI) { - printk("aha152x: RESET IN\n"); - SETPORT(SSTAT1, SCSIRSTI); - } - } while(TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT)); - - SETPORT(SSTAT1, CLRSCSIPERR); - - phase = GETPORT(SCSISIG) & P_MASK ; - - if(TESTHI(SSTAT1, SCSIPERR)) { - if((phase & (CDO|MSGO))==0) /* DATA phase */ - return P_PARITY; - - make_acklow(shpnt); - } else - return phase; - } + int phase, sstat1; + + while (1) { + do { + while (!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE | SCSIRSTI | REQINIT))) + barrier(); + if (sstat1 & BUSFREE) + return P_BUSFREE; + if (sstat1 & SCSIRSTI) { + printk("aha152x: RESET IN\n"); + SETPORT(SSTAT1, SCSIRSTI); + } + } while (TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT)); + + SETPORT(SSTAT1, CLRSCSIPERR); + + phase = GETPORT(SCSISIG) & P_MASK; + + if (TESTHI(SSTAT1, SCSIPERR)) { + if ((phase & (CDO | MSGO)) == 0) /* DATA phase */ + return P_PARITY; + + make_acklow(shpnt); + } else + return phase; + } } /* called from init/main.c */ void aha152x_setup(char *str, int *ints) { - if(setup_count>2) - panic("aha152x: you can only configure up to two controllers\n"); + if (setup_count > 2) + panic("aha152x: you can only configure up to two controllers\n"); - setup[setup_count].conf = str; - setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; - setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; - setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; - setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; - setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; - setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */; - setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; - setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; + setup[setup_count].conf = str; + setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; + setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; + setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; + setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; + setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; + setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */ ; + setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; + setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; #ifdef DEBUG_AHA152X - setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; - if(ints[0]>9) { - printk("aha152x: usage: aha152x=[,[," - "[,[,[,[,[,[,]]]]]]]]\n"); + setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; + if (ints[0] > 9) { + printk("aha152x: usage: aha152x=[,[," + "[,[,[,[,[,[,]]]]]]]]\n"); #else - if(ints[0]>8) { - printk("aha152x: usage: aha152x=[,[," - "[,[,[,[,[,]]]]]]]\n"); + if (ints[0] > 8) { + printk("aha152x: usage: aha152x=[,[," + "[,[,[,[,[,]]]]]]]\n"); #endif - } else - setup_count++; + } else + setup_count++; } /* @@ -720,598 +748,589 @@ */ static int aha152x_porttest(int io_port) { - int i; + int i; - if(check_region(io_port, IO_RANGE)) - return 0; + if (check_region(io_port, IO_RANGE)) + return 0; - SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */ - for(i=0; i<16; i++) - SETPORT(io_port+O_STACK, i); + SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ + for (i = 0; i < 16; i++) + SETPORT(io_port + O_STACK, i); - SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */ - for(i=0; i<16 && GETPORT(io_port+O_STACK)==i; i++) - ; + SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ + for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++); - return(i==16); + return (i == 16); } int aha152x_checksetup(struct aha152x_setup *setup) { - int i; - + int i; + #ifndef PCMCIA - for(i=0; iio_port != ports[i]); i++) - ; - - if(i==PORT_COUNT) - return 0; -#endif - - if(!aha152x_porttest(setup->io_port)) - return 0; - - if((setup->irqirq>IRQ_MAX)) - return 0; - - if((setup->scsiid < 0) || (setup->scsiid > 7)) - return 0; - - if((setup->reconnect < 0) || (setup->reconnect > 1)) - return 0; - - if((setup->parity < 0) || (setup->parity > 1)) - return 0; - - if((setup->synchronous < 0) || (setup->synchronous > 1)) - return 0; - - if((setup->ext_trans < 0) || (setup->ext_trans > 1)) - return 0; - - - return 1; + for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++); + + if (i == PORT_COUNT) + return 0; +#endif + + if (!aha152x_porttest(setup->io_port)) + return 0; + + if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX)) + return 0; + + if ((setup->scsiid < 0) || (setup->scsiid > 7)) + return 0; + + if ((setup->reconnect < 0) || (setup->reconnect > 1)) + return 0; + + if ((setup->parity < 0) || (setup->parity > 1)) + return 0; + + if ((setup->synchronous < 0) || (setup->synchronous > 1)) + return 0; + + if ((setup->ext_trans < 0) || (setup->ext_trans > 1)) + return 0; + + + return 1; } -void aha152x_swintr(int irqno, void *dev_id, struct pt_regs * regs) +void aha152x_swintr(int irqno, void *dev_id, struct pt_regs *regs) { - struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; + struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN]; - if(!shpnt) - panic("aha152x: catched software interrupt for unknown controller.\n"); + if (!shpnt) + panic("aha152x: catched software interrupt for unknown controller.\n"); - HOSTDATA(shpnt)->swint++; + HOSTDATA(shpnt)->swint++; } int aha152x_detect(Scsi_Host_Template * tpnt) { - int i, j, ok; + int i, j, ok; #if defined(AUTOCONF) - aha152x_config conf; + aha152x_config conf; #endif - - tpnt->proc_dir = &proc_scsi_aha152x; - for(i=0; iproc_dir = &proc_scsi_aha152x; + + for (i = 0; i < IRQS; i++) + aha152x_host[i] = (struct Scsi_Host *) NULL; + + if (setup_count) { + printk("aha152x: processing commandline: "); + + for (i = 0; i < setup_count; i++) + if (!aha152x_checksetup(&setup[i])) { + printk("\naha152x: %s\n", setup[i].conf); + printk("aha152x: invalid line (controller=%d)\n", i + 1); + } + printk("ok\n"); + } #ifdef SETUP0 - if(setup_count<2) { - struct aha152x_setup override = SETUP0; + if (setup_count < 2) { + struct aha152x_setup override = SETUP0; - if(setup_count==0 || (override.io_port != setup[0].io_port)) - if(!aha152x_checksetup(&override)) { - printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", - override.io_port, - override.irq, - override.scsiid, - override.reconnect, - override.parity, - override.synchronous, - override.delay, - override.ext_trans); - } else - setup[setup_count++] = override; - } + if (setup_count == 0 || (override.io_port != setup[0].io_port)) + if (!aha152x_checksetup(&override)) { + printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } #endif #ifdef SETUP1 - if(setup_count<2) { - struct aha152x_setup override = SETUP1; + if (setup_count < 2) { + struct aha152x_setup override = SETUP1; - if(setup_count==0 || (override.io_port != setup[0].io_port)) - if(!aha152x_checksetup(&override)) { - printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", - override.io_port, - override.irq, - override.scsiid, - override.reconnect, - override.parity, - override.synchronous, - override.delay, - override.ext_trans); - } else - setup[setup_count++] = override; - } + if (setup_count == 0 || (override.io_port != setup[0].io_port)) + if (!aha152x_checksetup(&override)) { + printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } #endif #if defined(MODULE) - if(setup_count<2 && aha152x[0]!=0) { - setup[setup_count].conf = ""; - setup[setup_count].io_port = aha152x[0]; - setup[setup_count].irq = aha152x[1]; - setup[setup_count].scsiid = aha152x[2]; - setup[setup_count].reconnect = aha152x[3]; - setup[setup_count].parity = aha152x[4]; - setup[setup_count].synchronous = aha152x[5]; - setup[setup_count].delay = aha152x[6]; - setup[setup_count].ext_trans = aha152x[7]; + if (setup_count < 2 && aha152x[0] != 0) { + setup[setup_count].conf = ""; + setup[setup_count].io_port = aha152x[0]; + setup[setup_count].irq = aha152x[1]; + setup[setup_count].scsiid = aha152x[2]; + setup[setup_count].reconnect = aha152x[3]; + setup[setup_count].parity = aha152x[4]; + setup[setup_count].synchronous = aha152x[5]; + setup[setup_count].delay = aha152x[6]; + setup[setup_count].ext_trans = aha152x[7]; #ifdef DEBUG_AHA152X - setup[setup_count].debug = aha152x[8]; + setup[setup_count].debug = aha152x[8]; #endif - if(aha152x_checksetup(&setup[setup_count])) - setup_count++; - else - printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n", - setup[setup_count].io_port, - setup[setup_count].irq, - setup[setup_count].scsiid, - setup[setup_count].reconnect, - setup[setup_count].parity, - setup[setup_count].synchronous, - setup[setup_count].delay, - setup[setup_count].ext_trans); - } - - if(setup_count<2 && aha152x1[0]!=0) { - setup[setup_count].conf = ""; - setup[setup_count].io_port = aha152x1[0]; - setup[setup_count].irq = aha152x1[1]; - setup[setup_count].scsiid = aha152x1[2]; - setup[setup_count].reconnect = aha152x1[3]; - setup[setup_count].parity = aha152x1[4]; - setup[setup_count].synchronous = aha152x1[5]; - setup[setup_count].delay = aha152x1[6]; - setup[setup_count].ext_trans = aha152x1[7]; + if (aha152x_checksetup(&setup[setup_count])) + setup_count++; + else + printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + setup[setup_count].io_port, + setup[setup_count].irq, + setup[setup_count].scsiid, + setup[setup_count].reconnect, + setup[setup_count].parity, + setup[setup_count].synchronous, + setup[setup_count].delay, + setup[setup_count].ext_trans); + } + if (setup_count < 2 && aha152x1[0] != 0) { + setup[setup_count].conf = ""; + setup[setup_count].io_port = aha152x1[0]; + setup[setup_count].irq = aha152x1[1]; + setup[setup_count].scsiid = aha152x1[2]; + setup[setup_count].reconnect = aha152x1[3]; + setup[setup_count].parity = aha152x1[4]; + setup[setup_count].synchronous = aha152x1[5]; + setup[setup_count].delay = aha152x1[6]; + setup[setup_count].ext_trans = aha152x1[7]; #ifdef DEBUG_AHA152X - setup[setup_count].debug = aha152x1[8]; + setup[setup_count].debug = aha152x1[8]; #endif - if(aha152x_checksetup(&setup[setup_count])) - setup_count++; - else - printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n", - setup[setup_count].io_port, - setup[setup_count].irq, - setup[setup_count].scsiid, - setup[setup_count].reconnect, - setup[setup_count].parity, - setup[setup_count].synchronous, - setup[setup_count].delay, - setup[setup_count].ext_trans); - } + if (aha152x_checksetup(&setup[setup_count])) + setup_count++; + else + printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + setup[setup_count].io_port, + setup[setup_count].irq, + setup[setup_count].scsiid, + setup[setup_count].reconnect, + setup[setup_count].parity, + setup[setup_count].synchronous, + setup[setup_count].delay, + setup[setup_count].ext_trans); + } #endif - + #if defined(AUTOCONF) - if(setup_count<2) { + if (setup_count < 2) { #if !defined(SKIP_BIOSTEST) - ok=0; - for(i=0; i < ADDRESS_COUNT && !ok; i++) - for(j=0; (j < SIGNATURE_COUNT) && !ok; j++) - ok = check_signature(addresses[i]+signatures[j].sig_offset, - signatures[j].signature, signatures[j].sig_length); + ok = 0; + for (i = 0; i < ADDRESS_COUNT && !ok; i++) + for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++) + ok = check_signature(addresses[i] + signatures[j].sig_offset, + signatures[j].signature, signatures[j].sig_length); - if(!ok && setup_count==0) - return 0; + if (!ok && setup_count == 0) + return 0; - printk("aha152x: BIOS test: passed, "); + printk("aha152x: BIOS test: passed, "); #else - printk("aha152x: "); -#endif /* !SKIP_BIOSTEST */ - - ok=0; - for(i=0; iio_port = setup[i].io_port; + shpnt->n_io_port = IO_RANGE; + shpnt->irq = setup[i].irq; + + ISSUE_SC = (Scsi_Cmnd *) NULL; + CURRENT_SC = (Scsi_Cmnd *) NULL; + DISCONNECTED_SC = (Scsi_Cmnd *) NULL; + + HOSTDATA(shpnt)->reconnect = setup[i].reconnect; + HOSTDATA(shpnt)->parity = setup[i].parity; + HOSTDATA(shpnt)->synchronous = setup[i].synchronous; + HOSTDATA(shpnt)->delay = setup[i].delay; + HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans; +#ifdef DEBUG_AHA152X + HOSTDATA(shpnt)->debug = setup[i].debug; +#endif - shpnt = aha152x_host[setup[i].irq-IRQ_MIN] = - scsi_register(tpnt, sizeof(struct aha152x_hostdata)); - registered_count++; + HOSTDATA(shpnt)->aborting = 0; + HOSTDATA(shpnt)->abortion_complete = 0; + HOSTDATA(shpnt)->abort_result = 0; + HOSTDATA(shpnt)->commands = 0; + + HOSTDATA(shpnt)->message_len = 0; + + for (j = 0; j < 8; j++) + HOSTDATA(shpnt)->syncrate[j] = 0; + + SETPORT(SCSIID, setup[i].scsiid << 4); + shpnt->this_id = setup[i].scsiid; + + if (setup[i].reconnect) + shpnt->can_queue = AHA152X_MAXQUEUE; + + /* RESET OUT */ + SETBITS(SCSISEQ, SCSIRSTO); + do_pause(30); + CLRBITS(SCSISEQ, SCSIRSTO); + do_pause(setup[i].delay); + + aha152x_reset_ports(shpnt); + + printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d," + " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", + i, + shpnt->io_port, + shpnt->irq, + shpnt->this_id, + HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", + HOSTDATA(shpnt)->parity ? "enabled" : "disabled", + HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", + HOSTDATA(shpnt)->delay, + HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled"); + + request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ + + /* not expecting any interrupts */ + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, 0); + + SETBITS(DMACNTRL0, INTEN); + + ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt); + if (ok < 0) { + if (ok == -EINVAL) + printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); + else if (ok == -EBUSY) + printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq); + else + printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); + printk("aha152x: driver needs an IRQ.\n"); + + scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; + continue; + } + HOSTDATA(shpnt)->swint = 0; - shpnt->io_port = setup[i].io_port; - shpnt->n_io_port = IO_RANGE; - shpnt->irq = setup[i].irq; + printk("aha152x: trying software interrupt, "); + SETBITS(DMACNTRL0, SWINT); - ISSUE_SC = (Scsi_Cmnd *) NULL; - CURRENT_SC = (Scsi_Cmnd *) NULL; - DISCONNECTED_SC = (Scsi_Cmnd *) NULL; + the_time = jiffies + 100; + while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time)) + barrier(); + + free_irq(shpnt->irq, shpnt); + + if (!HOSTDATA(shpnt)->swint) { + if (TESTHI(DMASTAT, INTSTAT)) { + printk("lost.\n"); + } else { + printk("failed.\n"); + } + + printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); + + scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; + continue; + } + printk("ok.\n"); - HOSTDATA(shpnt)->reconnect = setup[i].reconnect; - HOSTDATA(shpnt)->parity = setup[i].parity; - HOSTDATA(shpnt)->synchronous = setup[i].synchronous; - HOSTDATA(shpnt)->delay = setup[i].delay; - HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans; -#ifdef DEBUG_AHA152X - HOSTDATA(shpnt)->debug = setup[i].debug; -#endif + CLRBITS(DMACNTRL0, SWINT); - HOSTDATA(shpnt)->aborting = 0; - HOSTDATA(shpnt)->abortion_complete = 0; - HOSTDATA(shpnt)->abort_result = 0; - HOSTDATA(shpnt)->commands = 0; - - HOSTDATA(shpnt)->message_len = 0; - - for(j=0; j<8; j++) - HOSTDATA(shpnt)->syncrate[j] = 0; - - SETPORT(SCSIID, setup[i].scsiid << 4); - shpnt->this_id=setup[i].scsiid; - - if(setup[i].reconnect) - shpnt->can_queue=AHA152X_MAXQUEUE; - - /* RESET OUT */ - SETBITS(SCSISEQ, SCSIRSTO); - do_pause(30); - CLRBITS(SCSISEQ, SCSIRSTO); - do_pause(setup[i].delay); - - aha152x_reset_ports(shpnt); - - printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d," - " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", - i, - shpnt->io_port, - shpnt->irq, - shpnt->this_id, - HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", - HOSTDATA(shpnt)->parity ? "enabled" : "disabled", - HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", - HOSTDATA(shpnt)->delay, - HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled"); - - request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ - - /* not expecting any interrupts */ - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, 0); - - SETBITS(DMACNTRL0, INTEN); - - ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt); - if(ok<0) { - if(ok == -EINVAL) - printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); - else if(ok == -EBUSY) - printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq); - else - printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); - printk("aha152x: driver needs an IRQ.\n"); - - scsi_unregister(shpnt); - registered_count--; - release_region(shpnt->io_port, IO_RANGE); - shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; - continue; - } - - HOSTDATA(shpnt)->swint=0; - - printk("aha152x: trying software interrupt, "); - SETBITS(DMACNTRL0, SWINT); - - the_time=jiffies+100; - while(!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time)) - barrier(); - - free_irq(shpnt->irq,shpnt); - - if(!HOSTDATA(shpnt)->swint) { - if(TESTHI(DMASTAT, INTSTAT)) { - printk("lost.\n"); - } else { - printk("failed.\n"); - } - - printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); - - scsi_unregister(shpnt); - registered_count--; - release_region(shpnt->io_port, IO_RANGE); - shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; - continue; - } - - printk("ok.\n"); - - CLRBITS(DMACNTRL0, SWINT); - - /* clear interrupts */ - SETPORT(SSTAT0, 0x7f); - SETPORT(SSTAT1, 0xef); - - if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",shpnt)<0) { - printk("aha152x: failed to reassign interrupt.\n"); - } - } - - return (registered_count>0); + /* clear interrupts */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); + + if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) { + printk("aha152x: failed to reassign interrupt.\n"); + } + } + + return (registered_count > 0); } int aha152x_release(struct Scsi_Host *shpnt) { - if (shpnt->irq) - free_irq(shpnt->irq, shpnt); - if (shpnt->io_port) - release_region(shpnt->io_port, IO_RANGE); + if (shpnt->irq) + free_irq(shpnt->irq, shpnt); + if (shpnt->io_port) + release_region(shpnt->io_port, IO_RANGE); - return 0; + return 0; } /* * Queue a command and setup interrupts for a free bus. */ -int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { - struct Scsi_Host *shpnt = SCpnt->host; - unsigned long flags; + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; #if defined(DEBUG_RACE) - enter_driver("queue"); + enter_driver("queue"); #else #if defined(DEBUG_QUEUE) - if(HOSTDATA(shpnt)->debug & debug_queue) - printk("aha152x: queue(), "); + if (HOSTDATA(shpnt)->debug & debug_queue) + printk("aha152x: queue(), "); #endif #endif #if defined(DEBUG_QUEUE) - if(HOSTDATA(shpnt)->debug & debug_queue) { - printk("SCpnt (target = %d lun = %d cmnd = ", - SCpnt->target, SCpnt->lun); - print_command(SCpnt->cmnd); - printk(", cmd_len=%d, pieces = %d size = %u), ", - SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); - disp_ports(shpnt); - } -#endif - - SCpnt->scsi_done = done; - - /* setup scratch area - SCp.ptr : buffer pointer - SCp.this_residual : buffer length - SCp.buffer : next buffer - SCp.buffers_residual : left buffers in list - SCp.phase : current state of the command */ - SCpnt->SCp.phase = not_issued; - if (SCpnt->use_sg) { - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; - SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; - } else { - SCpnt->SCp.ptr = (char *)SCpnt->request_buffer; - SCpnt->SCp.this_residual = SCpnt->request_bufflen; - SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; - } - - SCpnt->SCp.Status = CHECK_CONDITION; - SCpnt->SCp.Message = 0; - SCpnt->SCp.have_data_in = 0; - SCpnt->SCp.sent_command = 0; - - /* Turn led on, when this is the first command. */ - save_flags(flags); - cli(); - HOSTDATA(shpnt)->commands++; - if(HOSTDATA(shpnt)->commands==1) - SETPORT(PORTA, 1); + if (HOSTDATA(shpnt)->debug & debug_queue) { + printk("SCpnt (target = %d lun = %d cmnd = ", + SCpnt->target, SCpnt->lun); + print_command(SCpnt->cmnd); + printk(", cmd_len=%d, pieces = %d size = %u), ", + SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); + disp_ports(shpnt); + } +#endif + + SCpnt->scsi_done = done; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + SCpnt->SCp.phase = not_issued; + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.sent_command = 0; + + /* Turn led on, when this is the first command. */ + save_flags(flags); + cli(); + HOSTDATA(shpnt)->commands++; + if (HOSTDATA(shpnt)->commands == 1) + SETPORT(PORTA, 1); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i+ (%d), ", HOSTDATA(shpnt)->commands); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("i+ (%d), ", HOSTDATA(shpnt)->commands); #endif - append_SC(&ISSUE_SC, SCpnt); - - /* Enable bus free interrupt, when we aren't currently on the bus */ - if(!CURRENT_SC) { - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - } - restore_flags(flags); + append_SC(&ISSUE_SC, SCpnt); + + /* Enable bus free interrupt, when we aren't currently on the bus */ + if (!CURRENT_SC) { + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + } + restore_flags(flags); #if defined(DEBUG_RACE) - leave_driver("queue"); + leave_driver("queue"); #endif - return 0; + return 0; } /* * We only support commands in interrupt-driven fashion */ -int aha152x_command(Scsi_Cmnd *SCpnt) +int aha152x_command(Scsi_Cmnd * SCpnt) { - printk("aha152x: interrupt driven driver; use aha152x_queue()\n"); - return -1; + printk("aha152x: interrupt driven driver; use aha152x_queue()\n"); + return -1; } /* * Abort a queued command * (commands that are on the bus can't be aborted easily) */ -int aha152x_abort(Scsi_Cmnd *SCpnt) +int aha152x_abort(Scsi_Cmnd * SCpnt) { - struct Scsi_Host *shpnt = SCpnt->host; - unsigned long flags; - Scsi_Cmnd *ptr, *prev; + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; + Scsi_Cmnd *ptr, *prev; - save_flags(flags); - cli(); + save_flags(flags); + cli(); #if defined(DEBUG_ABORT) - if(HOSTDATA(shpnt)->debug & debug_abort) { - printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); - show_queues(shpnt); - } -#endif - - /* look for command in issue queue */ - for(ptr=ISSUE_SC, prev=NULL; - ptr && ptr!=SCpnt; - prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) - ; - - if(ptr) { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; - - HOSTDATA(shpnt)->commands--; - - restore_flags(flags); - - ptr->host_scribble = NULL; - ptr->result = DID_ABORT << 16; - ptr->scsi_done(ptr); - - return SCSI_ABORT_SUCCESS; - } - - /* if the bus is busy or a command is currently processed, - we can't do anything more */ - if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC!=SCpnt)) { - /* fail abortion, if bus is busy */ - - if(!CURRENT_SC) - printk("bus busy w/o current command, "); - - restore_flags(flags); - - return SCSI_ABORT_BUSY; - } - - /* bus is free */ - - if(CURRENT_SC) { - HOSTDATA(shpnt)->commands--; - - /* target entered bus free before COMMAND COMPLETE, nothing to abort */ - restore_flags(flags); - CURRENT_SC->result = DID_ERROR << 16; - CURRENT_SC->scsi_done(CURRENT_SC); - CURRENT_SC = (Scsi_Cmnd *) NULL; - - return SCSI_ABORT_SUCCESS; - } - - /* look for command in disconnected queue */ - for(ptr=DISCONNECTED_SC, prev=NULL; - ptr && ptr!=SCpnt; - prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) - ; - - if(!ptr) { - /* command wasn't found */ - printk("command not found\n"); - restore_flags(flags); - - return SCSI_ABORT_NOT_RUNNING; - } - - if(!HOSTDATA(shpnt)->aborting) { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - - HOSTDATA(shpnt)->commands--; - - /* set command current and initiate selection, - let the interrupt routine take care of the abortion */ - CURRENT_SC = ptr; - ptr->SCp.phase = in_selection|aborted; - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); - - ADDMSG(ABORT); - - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); - - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); - - SETBITS(DMACNTRL0, INTEN); - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->aborting++; - HOSTDATA(shpnt)->abortion_complete=0; - - restore_flags(flags); - - /* sleep until the abortion is complete */ - while(!HOSTDATA(shpnt)->abortion_complete) - barrier(); - HOSTDATA(shpnt)->aborting=0; - - return HOSTDATA(shpnt)->abort_result; - } else { - /* we're already aborting a command */ - restore_flags(flags); + if (HOSTDATA(shpnt)->debug & debug_abort) { + printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); + show_queues(shpnt); + } +#endif + + /* look for command in issue queue */ + for (ptr = ISSUE_SC, prev = NULL; + ptr && ptr != SCpnt; + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); + + if (ptr) { + /* dequeue */ + if (prev) + prev->host_scribble = ptr->host_scribble; + else + ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; + + HOSTDATA(shpnt)->commands--; + + restore_flags(flags); + + ptr->host_scribble = NULL; + ptr->result = DID_ABORT << 16; + spin_lock_irqsave(&io_request_lock, flags); + ptr->scsi_done(ptr); + spin_unlock_irqrestore(&io_request_lock, flags); + + return SCSI_ABORT_SUCCESS; + } + /* if the bus is busy or a command is currently processed, + we can't do anything more */ + if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) { + /* fail abortion, if bus is busy */ + + if (!CURRENT_SC) + printk("bus busy w/o current command, "); + + restore_flags(flags); + + return SCSI_ABORT_BUSY; + } + /* bus is free */ + + if (CURRENT_SC) { + HOSTDATA(shpnt)->commands--; + + /* target entered bus free before COMMAND COMPLETE, nothing to abort */ + restore_flags(flags); + spin_lock_irqsave(&io_request_lock, flags); + CURRENT_SC->result = DID_ERROR << 16; + CURRENT_SC->scsi_done(CURRENT_SC); + CURRENT_SC = (Scsi_Cmnd *) NULL; + spin_unlock_irqrestore(&io_request_lock, flags); + + return SCSI_ABORT_SUCCESS; + } + /* look for command in disconnected queue */ + for (ptr = DISCONNECTED_SC, prev = NULL; + ptr && ptr != SCpnt; + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); + + if (!ptr) { + /* command wasn't found */ + printk("command not found\n"); + restore_flags(flags); + + return SCSI_ABORT_NOT_RUNNING; + } + if (!HOSTDATA(shpnt)->aborting) { + /* dequeue */ + if (prev) + prev->host_scribble = ptr->host_scribble; + else + DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; + + HOSTDATA(shpnt)->commands--; + + /* set command current and initiate selection, + let the interrupt routine take care of the abortion */ + CURRENT_SC = ptr; + ptr->SCp.phase = in_selection | aborted; + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + + ADDMSG(ABORT); + + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + SETBITS(DMACNTRL0, INTEN); + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->aborting++; + HOSTDATA(shpnt)->abortion_complete = 0; + + restore_flags(flags); + + /* sleep until the abortion is complete */ + while (!HOSTDATA(shpnt)->abortion_complete) + barrier(); + HOSTDATA(shpnt)->aborting = 0; + + return HOSTDATA(shpnt)->abort_result; + } else { + /* we're already aborting a command */ + restore_flags(flags); - return SCSI_ABORT_BUSY; - } + return SCSI_ABORT_BUSY; + } } /* @@ -1319,110 +1338,113 @@ */ static void aha152x_reset_ports(struct Scsi_Host *shpnt) { - /* disable interrupts */ - SETPORT(DMACNTRL0, RSTFIFO); + /* disable interrupts */ + SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(SCSISEQ, 0); + SETPORT(SCSISEQ, 0); - SETPORT(SXFRCTL1, 0); - SETPORT(SCSISIG, 0); - SETPORT(SCSIRATE, 0); + SETPORT(SXFRCTL1, 0); + SETPORT(SCSISIG, 0); + SETPORT(SCSIRATE, 0); - /* clear all interrupt conditions */ - SETPORT(SSTAT0, 0x7f); - SETPORT(SSTAT1, 0xef); + /* clear all interrupt conditions */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); - SETPORT(SSTAT4, SYNCERR|FWERR|FRERR); + SETPORT(SSTAT4, SYNCERR | FWERR | FRERR); - SETPORT(DMACNTRL0, 0); - SETPORT(DMACNTRL1, 0); + SETPORT(DMACNTRL0, 0); + SETPORT(DMACNTRL1, 0); - SETPORT(BRSTCNTRL, 0xf1); + SETPORT(BRSTCNTRL, 0xf1); - /* clear SCSI fifo and transfer count */ - SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); - SETPORT(SXFRCTL0, CH1); + /* clear SCSI fifo and transfer count */ + SETPORT(SXFRCTL0, CH1 | CLRCH1 | CLRSTCNT); + SETPORT(SXFRCTL0, CH1); - /* enable interrupts */ - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + /* enable interrupts */ + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); } /* * Reset registers, reset a hanging bus and * kill active and disconnected commands for target w/o soft reset */ -int aha152x_reset(Scsi_Cmnd *SCpnt, unsigned int unused) +int aha152x_reset(Scsi_Cmnd * SCpnt, unsigned int unused) { - struct Scsi_Host *shpnt = SCpnt->host; - unsigned long flags; - Scsi_Cmnd *ptr, *prev, *next; + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; + Scsi_Cmnd *ptr, *prev, *next; - aha152x_reset_ports(shpnt); + aha152x_reset_ports(shpnt); - /* Reset, if bus hangs */ - if(TESTLO(SSTAT1, BUSFREE)) { - CLRBITS(DMACNTRL0, INTEN); + /* Reset, if bus hangs */ + if (TESTLO(SSTAT1, BUSFREE)) { + CLRBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RESET) - if(HOSTDATA(shpnt)->debug & debug_reset) { - printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); - show_queues(shpnt); - } -#endif - - ptr=CURRENT_SC; - if(ptr && !ptr->device->soft_reset) { - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->scsi_done(CURRENT_SC); - CURRENT_SC=NULL; - } - - save_flags(flags); - cli(); - prev=NULL; ptr=DISCONNECTED_SC; - while(ptr) { - if(!ptr->device->soft_reset) { - if(prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - - next = (Scsi_Cmnd *) ptr->host_scribble; - - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->scsi_done(ptr); - - ptr = next; - } else { - prev=ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble; - } - } - restore_flags(flags); + if (HOSTDATA(shpnt)->debug & debug_reset) { + printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); + show_queues(shpnt); + } +#endif + + ptr = CURRENT_SC; + if (ptr && !ptr->device->soft_reset) { + ptr->host_scribble = NULL; + ptr->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + ptr->scsi_done(CURRENT_SC); + spin_unlock_irqrestore(&io_request_lock, flags); + CURRENT_SC = NULL; + } + save_flags(flags); + cli(); + prev = NULL; + ptr = DISCONNECTED_SC; + while (ptr) { + if (!ptr->device->soft_reset) { + if (prev) + prev->host_scribble = ptr->host_scribble; + else + DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; + + next = (Scsi_Cmnd *) ptr->host_scribble; + + ptr->host_scribble = NULL; + ptr->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + ptr->scsi_done(ptr); + spin_unlock_irqrestore(&io_request_lock, flags); + + ptr = next; + } else { + prev = ptr; + ptr = (Scsi_Cmnd *) ptr->host_scribble; + } + } + restore_flags(flags); #if defined(DEBUG_RESET) - if(HOSTDATA(shpnt)->debug & debug_reset) { - printk("commands on targets w/ soft-resets:\n"); - show_queues(shpnt); - } + if (HOSTDATA(shpnt)->debug & debug_reset) { + printk("commands on targets w/ soft-resets:\n"); + show_queues(shpnt); + } #endif - /* RESET OUT */ - SETPORT(SCSISEQ, SCSIRSTO); - do_pause(30); - SETPORT(SCSISEQ, 0); - do_pause(DELAY); - - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + /* RESET OUT */ + SETPORT(SCSISEQ, SCSIRSTO); + do_pause(30); + SETPORT(SCSISEQ, 0); + do_pause(DELAY); - SETPORT(DMACNTRL0, INTEN); - } + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - return SCSI_RESET_SUCCESS; + SETPORT(DMACNTRL0, INTEN); + } + return SCSI_RESET_SUCCESS; } /* @@ -1430,59 +1452,58 @@ */ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) { - struct Scsi_Host *shpnt=disk->device->host; + struct Scsi_Host *shpnt = disk->device->host; #if defined(DEBUG_BIOSPARAM) - if(HOSTDATA(shpnt)->debug & debug_biosparam) - printk("aha152x_biosparam: dev=%s, size=%d, ", - kdevname(dev), disk->capacity); -#endif - - /* try default translation */ - info_array[0]=64; - info_array[1]=32; - info_array[2]=disk->capacity / (64 * 32); - - /* for disks >1GB do some guessing */ - if(info_array[2]>=1024) { - int info[3]; - - /* try to figure out the geometry from the partition table */ - if(scsicam_bios_param(disk, dev, info)<0 || - !((info[0]==64 && info[1]==32) || (info[0]==255 && info[1]==63))) { - if(EXT_TRANS) { - printk("aha152x: unable to verify geometry for disk with >1GB.\n" - " using extended translation.\n"); - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = disk->capacity / (255 * 63); - } else { - printk("aha152x: unable to verify geometry for disk with >1GB.\n" - " Using default translation. Please verify yourself.\n" - " Perhaps you need to enable extended translation in the driver.\n" - " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n"); - } - } else { - info_array[0]=info[0]; - info_array[1]=info[1]; - info_array[2]=info[2]; - - if(info[0]==255 && !EXT_TRANS) { - printk("aha152x: current partition table is using extended translation.\n" - " using it also, although it's not explicty enabled.\n"); - } - } - } - + if (HOSTDATA(shpnt)->debug & debug_biosparam) + printk("aha152x_biosparam: dev=%s, size=%d, ", + kdevname(dev), disk->capacity); +#endif + + /* try default translation */ + info_array[0] = 64; + info_array[1] = 32; + info_array[2] = disk->capacity / (64 * 32); + + /* for disks >1GB do some guessing */ + if (info_array[2] >= 1024) { + int info[3]; + + /* try to figure out the geometry from the partition table */ + if (scsicam_bios_param(disk, dev, info) < 0 || + !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { + if (EXT_TRANS) { + printk("aha152x: unable to verify geometry for disk with >1GB.\n" + " using extended translation.\n"); + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = disk->capacity / (255 * 63); + } else { + printk("aha152x: unable to verify geometry for disk with >1GB.\n" + " Using default translation. Please verify yourself.\n" + " Perhaps you need to enable extended translation in the driver.\n" + " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n"); + } + } else { + info_array[0] = info[0]; + info_array[1] = info[1]; + info_array[2] = info[2]; + + if (info[0] == 255 && !EXT_TRANS) { + printk("aha152x: current partition table is using extended translation.\n" + " using it also, although it's not explicty enabled.\n"); + } + } + } #if defined(DEBUG_BIOSPARAM) - if(HOSTDATA(shpnt)->debug & debug_biosparam) { - printk("bios geometry: head=%d, sec=%d, cyl=%d\n", - info_array[0], info_array[1], info_array[2]); - printk("WARNING: check, if the bios geometry is correct.\n"); - } + if (HOSTDATA(shpnt)->debug & debug_biosparam) { + printk("bios geometry: head=%d, sec=%d, cyl=%d\n", + info_array[0], info_array[1], info_array[2]); + printk("WARNING: check, if the bios geometry is correct.\n"); + } #endif - return 0; + return 0; } /* @@ -1490,71 +1511,73 @@ */ void aha152x_done(struct Scsi_Host *shpnt, int error) { - unsigned long flags; - Scsi_Cmnd *done_SC; + unsigned long flags; + Scsi_Cmnd *done_SC; #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) { - printk("\naha152x: done(), "); - disp_ports(shpnt); - } + if (HOSTDATA(shpnt)->debug & debug_done) { + printk("\naha152x: done(), "); + disp_ports(shpnt); + } #endif - if(CURRENT_SC) { + if (CURRENT_SC) { #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("done(%x), ", error); + if (HOSTDATA(shpnt)->debug & debug_done) + printk("done(%x), ", error); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); - done_SC = CURRENT_SC; - CURRENT_SC = NULL; + done_SC = CURRENT_SC; + CURRENT_SC = NULL; - /* turn led off, when no commands are in the driver */ - HOSTDATA(shpnt)->commands--; - if(!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); /* turn led off */ + /* turn led off, when no commands are in the driver */ + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("ok (%d), ", HOSTDATA(shpnt)->commands); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("ok (%d), ", HOSTDATA(shpnt)->commands); #endif - restore_flags(flags); + restore_flags(flags); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); #if 0 /* Why poll for the BUS FREE phase, when we have setup the interrupt!? */ #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE loop, "); + if (HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE loop, "); #endif - while(TESTLO(SSTAT1, BUSFREE)) - barrier(); + while (TESTLO(SSTAT1, BUSFREE)) + barrier(); #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE\n"); + if (HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE\n"); #endif #endif - done_SC->result = error; - if(done_SC->scsi_done) { + done_SC->result = error; + if (done_SC->scsi_done) { #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("calling scsi_done, "); + if (HOSTDATA(shpnt)->debug & debug_done) + printk("calling scsi_done, "); #endif - done_SC->scsi_done(done_SC); + spin_lock_irqsave(&io_request_lock, flags); + done_SC->scsi_done(done_SC); + spin_unlock_irqrestore(&io_request_lock, flags); #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("done returned, "); + if (HOSTDATA(shpnt)->debug & debug_done) + printk("done returned, "); #endif - } else - panic("aha152x: current_SC->scsi_done() == NULL"); - } else - aha152x_panic(shpnt, "done() called outside of command"); + } else + panic("aha152x: current_SC->scsi_done() == NULL"); + } else + aha152x_panic(shpnt, "done() called outside of command"); } @@ -1563,41 +1586,39 @@ static struct tq_struct aha152x_tq; /* - * Run service completions on the card with interrupts enabled. + * Run service completions on the card with interrupts enabled. */ - + static void aha152x_run(void) { int i; - for(i=0;iservice) - { - HOSTDATA(shpnt)->service=0; + for (i = 0; i < IRQS; i++) { + struct Scsi_Host *shpnt = aha152x_host[i]; + if (shpnt && HOSTDATA(shpnt)->service) { + HOSTDATA(shpnt)->service = 0; aha152x_complete(shpnt); } } } /* - * Interrupts handler (main routine of the driver) + * Interrupts handler (main routine of the driver) */ -static void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs) +static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs) { - struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; + struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN]; #if defined(DEBUG_RACE) enter_driver("intr"); #else #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) + if (HOSTDATA(shpnt)->debug & debug_intr) printk("\naha152x: intr(), "); #endif #endif - if(!shpnt) + if (!shpnt) panic("aha152x: catched interrupt for unknown controller.\n"); /* no more interrupts from the controller, while we're busy. @@ -1606,9 +1627,9 @@ CLRBITS(DMACNTRL0, INTEN); /* Poke the BH handler */ - - HOSTDATA(shpnt)->service=1; - aha152x_tq.routine = (void *)aha152x_run; + + HOSTDATA(shpnt)->service = 1; + aha152x_tq.routine = (void *) aha152x_run; queue_task(&aha152x_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } @@ -1616,1020 +1637,1001 @@ static void aha152x_complete(struct Scsi_Host *shpnt) { unsigned int flags; - int done=0, phase; + int done = 0, phase; /* disconnected target is trying to reconnect. Only possible, if we have disconnected nexuses and nothing is occupying the bus. */ - - if(TESTHI(SSTAT0, SELDI) && - DISCONNECTED_SC && - (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection)) ) { - int identify_msg, target, i; - - /* Avoid conflicts when a target reconnects - while we are trying to connect to another. */ - if(CURRENT_SC) { + + if (TESTHI(SSTAT0, SELDI) && + DISCONNECTED_SC && + (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) { + int identify_msg, target, i; + + /* Avoid conflicts when a target reconnects + while we are trying to connect to another. */ + if (CURRENT_SC) { #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i+, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("i+, "); #endif - save_flags(flags); - cli(); - append_SC(&ISSUE_SC, CURRENT_SC); - CURRENT_SC=NULL; - restore_flags(flags); - } - - /* disable sequences */ - SETPORT(SCSISEQ, 0); - SETPORT(SSTAT0, CLRSELDI); - SETPORT(SSTAT1, CLRBUSFREE); + save_flags(flags); + cli(); + append_SC(&ISSUE_SC, CURRENT_SC); + CURRENT_SC = NULL; + restore_flags(flags); + } + /* disable sequences */ + SETPORT(SCSISEQ, 0); + SETPORT(SSTAT0, CLRSELDI); + SETPORT(SSTAT1, CLRBUSFREE); #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_queues|debug_phases)) - printk("reselected, "); + if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases)) + printk("reselected, "); #endif - i = GETPORT(SELID) & ~(1 << shpnt->this_id); - target=0; + i = GETPORT(SELID) & ~(1 << shpnt->this_id); + target = 0; - if(i==0) - aha152x_panic(shpnt, "reconnecting target unknown"); + if (i == 0) + aha152x_panic(shpnt, "reconnecting target unknown"); - for(; (i & 1)==0; target++, i>>=1) - ; + for (; (i & 1) == 0; target++, i >>= 1); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | target); - SETPORT(SCSISEQ, ENRESELI); - - if(TESTLO(SSTAT0, SELDI)) - aha152x_panic(shpnt, "RESELI failed"); - - SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target]&0x7f); + SETPORT(SCSIID, (shpnt->this_id << OID_) | target); + SETPORT(SCSISEQ, ENRESELI); - SETPORT(SCSISIG, P_MSGI); + if (TESTLO(SSTAT0, SELDI)) + aha152x_panic(shpnt, "RESELI failed"); - /* Get identify message */ - if((i=getphase(shpnt))!=P_MSGI) { - printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); - aha152x_panic(shpnt, "unknown lun"); - } - SETPORT(SCSISEQ, 0); + SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f); - SETPORT(SXFRCTL0, CH1); + SETPORT(SCSISIG, P_MSGI); - identify_msg = GETPORT(SCSIBUS); + /* Get identify message */ + if ((i = getphase(shpnt)) != P_MSGI) { + printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); + aha152x_panic(shpnt, "unknown lun"); + } + SETPORT(SCSISEQ, 0); - if(!(identify_msg & IDENTIFY_BASE)) { - printk("target=%d, inbound message (%02x) != IDENTIFY\n", - target, identify_msg); - aha152x_panic(shpnt, "unknown lun"); - } + SETPORT(SXFRCTL0, CH1); + identify_msg = GETPORT(SCSIBUS); + if (!(identify_msg & IDENTIFY_BASE)) { + printk("target=%d, inbound message (%02x) != IDENTIFY\n", + target, identify_msg); + aha152x_panic(shpnt, "unknown lun"); + } #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("d-, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("d-, "); #endif - CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); + CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); + + if (!CURRENT_SC) { + printk("lun=%d, ", identify_msg & 0x3f); + aha152x_panic(shpnt, "no disconnected command for that lun"); + } + CURRENT_SC->SCp.phase &= ~disconnected; + restore_flags(flags); - if(!CURRENT_SC) { - printk("lun=%d, ", identify_msg & 0x3f); - aha152x_panic(shpnt, "no disconnected command for that lun"); - } - - CURRENT_SC->SCp.phase &= ~disconnected; - restore_flags(flags); - - make_acklow(shpnt); - if(getphase(shpnt)!=P_MSGI) { - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + make_acklow(shpnt); + if (getphase(shpnt) != P_MSGI) { + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); #if defined(DEBUG_RACE) - leave_driver("(reselected) intr"); + leave_driver("(reselected) intr"); #endif - SETBITS(DMACNTRL0, INTEN); - return; - } - } - - /* Check, if we aren't busy with a command */ - if(!CURRENT_SC) { - /* bus is free to issue a queued command */ - if(TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) { - save_flags(flags); - cli(); + SETBITS(DMACNTRL0, INTEN); + return; + } + } + /* Check, if we aren't busy with a command */ + if (!CURRENT_SC) { + /* bus is free to issue a queued command */ + if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) { + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i-, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("i-, "); #endif - CURRENT_SC = remove_first_SC(&ISSUE_SC); - restore_flags(flags); + CURRENT_SC = remove_first_SC(&ISSUE_SC); + restore_flags(flags); #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) - printk("issuing command, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) + printk("issuing command, "); #endif - CURRENT_SC->SCp.phase = in_selection; + CURRENT_SC->SCp.phase = in_selection; #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) - printk("selecting %d, ", CURRENT_SC->target); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) + printk("selecting %d, ", CURRENT_SC->target); #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); - /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ - SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK|ENSTIMER) : ENSTIMER); + /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ + SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER); - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); - - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); - - } else { - /* No command we are busy with and no new to issue */ - printk("aha152x: ignoring spurious interrupt, nothing to do\n"); - if(TESTHI(DMACNTRL0, SWINT)) { - printk("aha152x: SWINT is set! Why?\n"); - CLRBITS(DMACNTRL0, SWINT); - } - show_queues(shpnt); - } + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + } else { + /* No command we are busy with and no new to issue */ + printk("aha152x: ignoring spurious interrupt, nothing to do\n"); + if (TESTHI(DMACNTRL0, SWINT)) { + printk("aha152x: SWINT is set! Why?\n"); + CLRBITS(DMACNTRL0, SWINT); + } + show_queues(shpnt); + } #if defined(DEBUG_RACE) - leave_driver("(selecting) intr"); + leave_driver("(selecting) intr"); #endif - SETBITS(DMACNTRL0, INTEN); - return; - } - - /* the bus is busy with something */ + SETBITS(DMACNTRL0, INTEN); + return; + } + /* the bus is busy with something */ #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - disp_ports(shpnt); + if (HOSTDATA(shpnt)->debug & debug_intr) + disp_ports(shpnt); #endif - /* we are waiting for the result of a selection attempt */ - if(CURRENT_SC->SCp.phase & in_selection) { - if(TESTLO(SSTAT1, SELTO)) { - /* no timeout */ - if(TESTHI(SSTAT0, SELDO)) { - /* clear BUS FREE interrupt */ - SETPORT(SSTAT1, CLRBUSFREE); - - /* Disable SELECTION OUT sequence */ - CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); - - /* Disable SELECTION OUT DONE interrupt */ - CLRBITS(SIMODE0, ENSELDO); - CLRBITS(SIMODE1, ENSELTIMO); + /* we are waiting for the result of a selection attempt */ + if (CURRENT_SC->SCp.phase & in_selection) { + if (TESTLO(SSTAT1, SELTO)) { + /* no timeout */ + if (TESTHI(SSTAT0, SELDO)) { + /* clear BUS FREE interrupt */ + SETPORT(SSTAT1, CLRBUSFREE); + + /* Disable SELECTION OUT sequence */ + CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + /* Disable SELECTION OUT DONE interrupt */ + CLRBITS(SIMODE0, ENSELDO); + CLRBITS(SIMODE1, ENSELTIMO); - if(TESTLO(SSTAT0, SELDO)) { - printk("aha152x: passing bus free condition\n"); + if (TESTLO(SSTAT0, SELDO)) { + printk("aha152x: passing bus free condition\n"); #if defined(DEBUG_RACE) - leave_driver("(passing bus free) intr"); + leave_driver("(passing bus free) intr"); #endif - SETBITS(DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); - if(CURRENT_SC->SCp.phase & aborted) { - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } + if (CURRENT_SC->SCp.phase & aborted) { + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } + aha152x_done(shpnt, DID_NO_CONNECT << 16); - aha152x_done(shpnt, DID_NO_CONNECT << 16); - - return; - } + return; + } #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) - printk("SELDO (SELID=%x), ", GETPORT(SELID)); + if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) + printk("SELDO (SELID=%x), ", GETPORT(SELID)); #endif - /* selection was done */ - SETPORT(SSTAT0, CLRSELDO); + /* selection was done */ + SETPORT(SSTAT0, CLRSELDO); #if defined(DEBUG_ABORT) - if((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) - printk("(ABORT) target selected, "); + if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) + printk("(ABORT) target selected, "); #endif - CURRENT_SC->SCp.phase &= ~in_selection; - CURRENT_SC->SCp.phase |= in_other; - - ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)); + CURRENT_SC->SCp.phase &= ~in_selection; + CURRENT_SC->SCp.phase |= in_other; - if(!(SYNCRATE&0x80) && HOSTDATA(shpnt)->synchronous) { - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - ADDMSG(50); - ADDMSG(8); + ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)); - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN-5)); + if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) { + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + ADDMSG(50); + ADDMSG(8); - SYNCRATE=0x80; - CURRENT_SC->SCp.phase |= in_sync; - } + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN - 5)); + SYNCRATE = 0x80; + CURRENT_SC->SCp.phase |= in_sync; + } #if defined(DEBUG_RACE) - leave_driver("(SELDO) intr"); + leave_driver("(SELDO) intr"); #endif - SETPORT(SCSIRATE, SYNCRATE&0x7f); + SETPORT(SCSIRATE, SYNCRATE & 0x7f); - SETPORT(SCSISIG, P_MSGO); + SETPORT(SCSISIG, P_MSGO); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); - SETBITS(DMACNTRL0, INTEN); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); + SETBITS(DMACNTRL0, INTEN); - return; - } else - aha152x_panic(shpnt, "neither timeout nor selection\007"); - } else { + return; + } else + aha152x_panic(shpnt, "neither timeout nor selection\007"); + } else { #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) - printk("SELTO, "); + if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) + printk("SELTO, "); #endif - /* end selection attempt */ - CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); + /* end selection attempt */ + CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); - /* timeout */ - SETPORT(SSTAT1, CLRSELTIMO); + /* timeout */ + SETPORT(SSTAT1, CLRSELTIMO); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS(DMACNTRL0, INTEN); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(SELTO) intr"); + leave_driver("(SELTO) intr"); #endif - if(CURRENT_SC->SCp.phase & aborted) { + if (CURRENT_SC->SCp.phase & aborted) { #if defined(DEBUG_ABORT) - if(HOSTDATA(shpnt)->debug & debug_abort) - printk("(ABORT) selection timeout, "); + if (HOSTDATA(shpnt)->debug & debug_abort) + printk("(ABORT) selection timeout, "); #endif - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } - - if(TESTLO(SSTAT0, SELINGO)) - /* ARBITRATION not won */ - aha152x_done(shpnt, DID_BUS_BUSY << 16); - else - /* ARBITRATION won, but SELECTION failed */ - aha152x_done(shpnt, DID_NO_CONNECT << 16); - - return; - } - } - - /* enable interrupt, when target leaves current phase */ - phase = getphase(shpnt); - if(!(phase & ~P_MASK)) /* "real" phase */ - SETPORT(SCSISIG, phase); - SETPORT(SSTAT1, CLRPHASECHG); - CURRENT_SC->SCp.phase = - (CURRENT_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16); - - /* information transfer phase */ - switch(phase) { - case P_MSGO: /* MESSAGE OUT */ - { - int i, identify=0, abort=0; + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } + if (TESTLO(SSTAT0, SELINGO)) + /* ARBITRATION not won */ + aha152x_done(shpnt, DID_BUS_BUSY << 16); + else + /* ARBITRATION won, but SELECTION failed */ + aha152x_done(shpnt, DID_NO_CONNECT << 16); + + return; + } + } + /* enable interrupt, when target leaves current phase */ + phase = getphase(shpnt); + if (!(phase & ~P_MASK)) /* "real" phase */ + SETPORT(SCSISIG, phase); + SETPORT(SSTAT1, CLRPHASECHG); + CURRENT_SC->SCp.phase = + (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16); + + /* information transfer phase */ + switch (phase) { + case P_MSGO: /* MESSAGE OUT */ + { + int i, identify = 0, abort = 0; #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgo|debug_phases)) - printk("MESSAGE OUT, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases)) + printk("MESSAGE OUT, "); #endif - if(MSGLEN==0) { - ADDMSG(MESSAGE_REJECT); + if (MSGLEN == 0) { + ADDMSG(MESSAGE_REJECT); #if defined(DEBUG_MSGO) - if(HOSTDATA(shpnt)->debug & debug_msgo) - printk("unexpected MESSAGE OUT phase; rejecting, "); + if (HOSTDATA(shpnt)->debug & debug_msgo) + printk("unexpected MESSAGE OUT phase; rejecting, "); #endif - } - - CLRBITS(SXFRCTL0, ENDMA); - - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); - - /* wait for data latch to become ready or a phase change */ - while(TESTLO(DMASTAT, INTSTAT)) - barrier(); - + } + CLRBITS(SXFRCTL0, ENDMA); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); + + /* wait for data latch to become ready or a phase change */ + while (TESTLO(DMASTAT, INTSTAT)) + barrier(); + #if defined(DEBUG_MSGO) - if(HOSTDATA(shpnt)->debug & debug_msgo) { - int i; - - printk("messages ("); - for(i=0; idebug & debug_msgo) { + int i; + + printk("messages ("); + for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" ")); + printk("), "); + } #endif - - for(i=0; idebug & debug_msgo) - printk("%x ", MSG(i)); + if (HOSTDATA(shpnt)->debug & debug_msgo) + printk("%x ", MSG(i)); #endif - if(i==MSGLEN-1) { - /* Leave MESSAGE OUT after transfer */ - SETPORT(SSTAT1, CLRATNO); - } - - SETPORT(SCSIDAT, MSG(i)); + if (i == MSGLEN - 1) { + /* Leave MESSAGE OUT after transfer */ + SETPORT(SSTAT1, CLRATNO); + } + SETPORT(SCSIDAT, MSG(i)); - make_acklow(shpnt); - getphase(shpnt); + make_acklow(shpnt); + getphase(shpnt); - if(MSG(i)==IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)) - identify++; + if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)) + identify++; - if(MSG(i)==ABORT) - abort++; + if (MSG(i) == ABORT) + abort++; - } + } - MSGLEN=0; + MSGLEN = 0; - if(identify) - CURRENT_SC->SCp.phase |= sent_ident; + if (identify) + CURRENT_SC->SCp.phase |= sent_ident; - if(abort) { - /* revive abort(); abort() enables interrupts */ - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->abortion_complete++; + if (abort) { + /* revive abort(); abort() enables interrupts */ + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->abortion_complete++; - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK << 16); - /* exit */ - SETBITS(DMACNTRL0, INTEN); + /* exit */ + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(ABORT) intr"); + leave_driver("(ABORT) intr"); #endif - aha152x_done(shpnt, DID_ABORT<<16); + aha152x_done(shpnt, DID_ABORT << 16); - return; - } - } - break; + return; + } + } + break; - case P_CMD: /* COMMAND phase */ + case P_CMD: /* COMMAND phase */ #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_cmd|debug_phases)) - printk("COMMAND, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_cmd | debug_phases)) + printk("COMMAND, "); #endif - if(!(CURRENT_SC->SCp.sent_command)) { - int i; + if (!(CURRENT_SC->SCp.sent_command)) { + int i; + + CLRBITS(SXFRCTL0, ENDMA); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); + + /* wait for data latch to become ready or a phase change */ + while (TESTLO(DMASTAT, INTSTAT)) + barrier(); - CLRBITS(SXFRCTL0, ENDMA); + for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { + SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); + + make_acklow(shpnt); + getphase(shpnt); + } + + if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS)) + aha152x_panic(shpnt, "target left COMMAND"); + + CURRENT_SC->SCp.sent_command++; + } else + aha152x_panic(shpnt, "Nothing to send while in COMMAND"); + break; + + case P_MSGI: /* MESSAGE IN phase */ + { + int start_sync = 0; - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); - - /* wait for data latch to become ready or a phase change */ - while(TESTLO(DMASTAT, INTSTAT)) - barrier(); - - for(i=0; icmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { - SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); - - make_acklow(shpnt); - getphase(shpnt); - } - - if(icmd_len && TESTHI(SSTAT1, PHASEMIS)) - aha152x_panic(shpnt, "target left COMMAND"); - - CURRENT_SC->SCp.sent_command++; - } else - aha152x_panic(shpnt, "Nothing to send while in COMMAND"); - break; - - case P_MSGI: /* MESSAGE IN phase */ - { - int start_sync=0; - #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgi|debug_phases)) - printk("MESSAGE IN, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgi | debug_phases)) + printk("MESSAGE IN, "); #endif - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENBUSFREE); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENBUSFREE); - - while(phase == P_MSGI) { - CURRENT_SC->SCp.Message = GETPORT(SCSIDAT); - switch(CURRENT_SC->SCp.Message) { - case DISCONNECT: + while (phase == P_MSGI) { + CURRENT_SC->SCp.Message = GETPORT(SCSIDAT); + switch (CURRENT_SC->SCp.Message) { + case DISCONNECT: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) - printk("target disconnected, "); + if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases)) + printk("target disconnected, "); #endif - CURRENT_SC->SCp.Message = 0; - CURRENT_SC->SCp.phase |= disconnected; - if(!HOSTDATA(shpnt)->reconnect) - aha152x_panic(shpnt, "target was not allowed to disconnect"); - - break; - - case COMMAND_COMPLETE: + CURRENT_SC->SCp.Message = 0; + CURRENT_SC->SCp.phase |= disconnected; + if (!HOSTDATA(shpnt)->reconnect) + aha152x_panic(shpnt, "target was not allowed to disconnect"); + + break; + + case COMMAND_COMPLETE: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) - printk("inbound message (COMMAND COMPLETE), "); + if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases)) + printk("inbound message (COMMAND COMPLETE), "); #endif - done++; - break; + done++; + break; - case MESSAGE_REJECT: - if(CURRENT_SC->SCp.phase & in_sync) { - CURRENT_SC->SCp.phase &= ~in_sync; - SYNCRATE=0x80; - printk("synchronous rejected, "); - } else - printk("inbound message (MESSAGE REJECT), "); + case MESSAGE_REJECT: + if (CURRENT_SC->SCp.phase & in_sync) { + CURRENT_SC->SCp.phase &= ~in_sync; + SYNCRATE = 0x80; + printk("synchronous rejected, "); + } else + printk("inbound message (MESSAGE REJECT), "); #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (MESSAGE REJECT), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (MESSAGE REJECT), "); #endif - break; + break; - case SAVE_POINTERS: + case SAVE_POINTERS: #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (SAVE DATA POINTERS), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (SAVE DATA POINTERS), "); #endif - break; + break; - case RESTORE_POINTERS: + case RESTORE_POINTERS: #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (RESTORE DATA POINTERS), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (RESTORE DATA POINTERS), "); #endif - break; + break; - case EXTENDED_MESSAGE: - { - char buffer[16]; - int i; + case EXTENDED_MESSAGE: + { + char buffer[16]; + int i; #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (EXTENDED MESSAGE), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (EXTENDED MESSAGE), "); #endif - make_acklow(shpnt); - if(getphase(shpnt)!=P_MSGI) - break; - - buffer[0]=EXTENDED_MESSAGE; - buffer[1]=GETPORT(SCSIDAT); - - for(i=0; idebug & debug_msgi) - print_msg(buffer); + if (HOSTDATA(shpnt)->debug & debug_msgi) + print_msg(buffer); #endif - switch(buffer [2]) { - case EXTENDED_SDTR: - { - long ticks; - - if(buffer[1]!=3) - aha152x_panic(shpnt, "SDTR message length != 3"); - - if(!HOSTDATA(shpnt)->synchronous) - break; - - printk("inbound SDTR: "); print_msg(buffer); - - ticks=(buffer[3]*4+49)/50; - - if(CURRENT_SC->SCp.phase & in_sync) { - /* we initiated SDTR */ - if(ticks>9 || buffer[4]<1 || buffer[4]>8) - aha152x_panic(shpnt, "received SDTR invalid"); - - SYNCRATE |= ((ticks-2)<<4) + buffer[4]; - } else if(ticks<=9 && buffer[4]>=1) { - if(buffer[4]>8) - buffer[4]=8; - - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - if(ticks<4) { - ticks=4; - ADDMSG(50); - } else - ADDMSG(buffer[3]); - - ADDMSG(buffer[4]); - - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN-5)); - - CURRENT_SC->SCp.phase |= in_sync; - - SYNCRATE |= ((ticks-2)<<4) + buffer[4]; - - start_sync++; - } else { - /* requested SDTR is too slow, do it asynchronously */ - ADDMSG(MESSAGE_REJECT); - SYNCRATE = 0; - } - - SETPORT(SCSIRATE, SYNCRATE&0x7f); - } - break; - - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - case EXTENDED_WDTR: - default: - ADDMSG(MESSAGE_REJECT); - break; - } - } - break; - - default: - printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); - break; - - } - - make_acklow(shpnt); - phase=getphase(shpnt); - } - - if(start_sync) - CURRENT_SC->SCp.phase |= in_sync; - else - CURRENT_SC->SCp.phase &= ~in_sync; - - if(MSGLEN>0) - SETPORT(SCSISIG, P_MSGI|ATNO); - - /* clear SCSI fifo on BUSFREE */ - if(phase==P_BUSFREE) - SETPORT(SXFRCTL0, CH1|CLRCH1); - - if(CURRENT_SC->SCp.phase & disconnected) { - save_flags(flags); - cli(); + switch (buffer[2]) { + case EXTENDED_SDTR: + { + long ticks; + + if (buffer[1] != 3) + aha152x_panic(shpnt, "SDTR message length != 3"); + + if (!HOSTDATA(shpnt)->synchronous) + break; + + printk("inbound SDTR: "); + print_msg(buffer); + + ticks = (buffer[3] * 4 + 49) / 50; + + if (CURRENT_SC->SCp.phase & in_sync) { + /* we initiated SDTR */ + if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8) + aha152x_panic(shpnt, "received SDTR invalid"); + + SYNCRATE |= ((ticks - 2) << 4) + buffer[4]; + } else if (ticks <= 9 && buffer[4] >= 1) { + if (buffer[4] > 8) + buffer[4] = 8; + + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + if (ticks < 4) { + ticks = 4; + ADDMSG(50); + } else + ADDMSG(buffer[3]); + + ADDMSG(buffer[4]); + + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN - 5)); + + CURRENT_SC->SCp.phase |= in_sync; + + SYNCRATE |= ((ticks - 2) << 4) + buffer[4]; + + start_sync++; + } else { + /* requested SDTR is too slow, do it asynchronously */ + ADDMSG(MESSAGE_REJECT); + SYNCRATE = 0; + } + + SETPORT(SCSIRATE, SYNCRATE & 0x7f); + } + break; + + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + case EXTENDED_WDTR: + default: + ADDMSG(MESSAGE_REJECT); + break; + } + } + break; + + default: + printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); + break; + + } + + make_acklow(shpnt); + phase = getphase(shpnt); + } + + if (start_sync) + CURRENT_SC->SCp.phase |= in_sync; + else + CURRENT_SC->SCp.phase &= ~in_sync; + + if (MSGLEN > 0) + SETPORT(SCSISIG, P_MSGI | ATNO); + + /* clear SCSI fifo on BUSFREE */ + if (phase == P_BUSFREE) + SETPORT(SXFRCTL0, CH1 | CLRCH1); + + if (CURRENT_SC->SCp.phase & disconnected) { + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("d+, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("d+, "); #endif - append_SC(&DISCONNECTED_SC, CURRENT_SC); - CURRENT_SC->SCp.phase |= 1<<16; - CURRENT_SC = NULL; - restore_flags(flags); + append_SC(&DISCONNECTED_SC, CURRENT_SC); + CURRENT_SC->SCp.phase |= 1 << 16; + CURRENT_SC = NULL; + restore_flags(flags); - SETBITS(SCSISEQ, ENRESELI); + SETBITS(SCSISEQ, ENRESELI); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS(DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); - return; - } - } - break; + return; + } + } + break; - case P_STATUS: /* STATUS IN phase */ + case P_STATUS: /* STATUS IN phase */ #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_status|debug_intr|debug_phases)) - printk("STATUS, "); + if (HOSTDATA(shpnt)->debug & (debug_status | debug_intr | debug_phases)) + printk("STATUS, "); #endif - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); - if(TESTHI(SSTAT1, PHASEMIS)) - printk("aha152x: passing STATUS phase"); - - CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); - make_acklow(shpnt); - getphase(shpnt); + if (TESTHI(SSTAT1, PHASEMIS)) + printk("aha152x: passing STATUS phase"); + + CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); + make_acklow(shpnt); + getphase(shpnt); #if defined(DEBUG_STATUS) - if(HOSTDATA(shpnt)->debug & debug_status) { - printk("inbound status "); - print_status(CURRENT_SC->SCp.Status); - printk(", "); - } -#endif - break; - - case P_DATAI: /* DATA IN phase */ - { - int fifodata, data_count, done; + if (HOSTDATA(shpnt)->debug & debug_status) { + printk("inbound status "); + print_status(CURRENT_SC->SCp.Status); + printk(", "); + } +#endif + break; + + case P_DATAI: /* DATA IN phase */ + { + int fifodata, data_count, done; #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr|debug_phases)) - printk("DATA IN, "); + if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases)) + printk("DATA IN, "); #endif #if 0 - if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) - printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); + if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) + printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT)); #endif - /* reset host fifo */ - SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(DMACNTRL0, RSTFIFO|ENDMA); + /* reset host fifo */ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO | ENDMA); - SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); + SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); - /* done is set when the FIFO is empty after the target left DATA IN */ - done=0; - - /* while the target stays in DATA to transfer data */ - while (!done) { + /* done is set when the FIFO is empty after the target left DATA IN */ + done = 0; + + /* while the target stays in DATA to transfer data */ + while (!done) { #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("expecting data, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("expecting data, "); #endif - /* wait for PHASEMIS or full FIFO */ - while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) - barrier(); + /* wait for PHASEMIS or full FIFO */ + while (TESTLO(DMASTAT, DFIFOFULL | INTSTAT)) + barrier(); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("ok, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("ok, "); #endif - - if(TESTHI(DMASTAT, DFIFOFULL)) - fifodata=GETPORT(FIFOSTAT); - else { - /* wait for SCSI fifo to get empty */ - while(TESTLO(SSTAT2, SEMPTY)) - barrier(); - /* rest of data in FIFO */ - fifodata=GETPORT(FIFOSTAT); + if (TESTHI(DMASTAT, DFIFOFULL)) + fifodata = GETPORT(FIFOSTAT); + else { + /* wait for SCSI fifo to get empty */ + while (TESTLO(SSTAT2, SEMPTY)) + barrier(); + + /* rest of data in FIFO */ + fifodata = GETPORT(FIFOSTAT); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("last transfer, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("last transfer, "); #endif - done=1; - } - + done = 1; + } + #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("fifodata=%d, ", fifodata); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("fifodata=%d, ", fifodata); #endif - while(fifodata && CURRENT_SC->SCp.this_residual) { - data_count=fifodata; - - /* limit data transfer to size of first sg buffer */ - if(data_count > CURRENT_SC->SCp.this_residual) - data_count = CURRENT_SC->SCp.this_residual; - - fifodata -= data_count; + while (fifodata && CURRENT_SC->SCp.this_residual) { + data_count = fifodata; + + /* limit data transfer to size of first sg buffer */ + if (data_count > CURRENT_SC->SCp.this_residual) + data_count = CURRENT_SC->SCp.this_residual; + + fifodata -= data_count; #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("data_count=%d, ", data_count); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("data_count=%d, ", data_count); #endif - - if(data_count&1) { - /* get a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); - CURRENT_SC->SCp.this_residual--; - } - - if(data_count>1) { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* Number of words */ - insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + + if (data_count & 1) { + /* get a single byte in byte mode */ + SETBITS(DMACNTRL0, _8BIT); + *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); + CURRENT_SC->SCp.this_residual--; + } + if (data_count > 1) { + CLRBITS(DMACNTRL0, _8BIT); + data_count >>= 1; /* Number of words */ + insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - /* show what comes with the last transfer */ - if(done) { + if (HOSTDATA(shpnt)->debug & debug_datai) + /* show what comes with the last transfer */ + if (done) { #if 0 - int i; - unsigned char *data; + int i; + unsigned char *data; #endif - - printk("data on last transfer (%d bytes) ", - 2*data_count); -#if 0 - printk("data on last transfer (%d bytes: ", - 2*data_count); - data = (unsigned char *) CURRENT_SC->SCp.ptr; - for(i=0; i<2*data_count; i++) - printk("%2x ", *data++); - printk("), "); -#endif - } -#endif - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - - /* if this buffer is full and there are more buffers left */ - if(!CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - } - - /* - * FIFO should be empty - */ - if(fifodata>0) { - printk("aha152x: more data than expected (%d bytes)\n", - GETPORT(FIFOSTAT)); - SETBITS(DMACNTRL0, _8BIT); - printk("aha152x: data ("); - while(fifodata--) - printk("%2x ", GETPORT(DATAPORT)); - printk(")\n"); - } + printk("data on last transfer (%d bytes) ", + 2 * data_count); +#if 0 + printk("data on last transfer (%d bytes: ", + 2 * data_count); + data = (unsigned char *) CURRENT_SC->SCp.ptr; + for (i = 0; i < 2 * data_count; i++) + printk("%2x ", *data++); + printk("), "); +#endif + } +#endif + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + } + /* if this buffer is full and there are more buffers left */ + if (!CURRENT_SC->SCp.this_residual && + CURRENT_SC->SCp.buffers_residual) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + + /* + * FIFO should be empty + */ + if (fifodata > 0) { + printk("aha152x: more data than expected (%d bytes)\n", + GETPORT(FIFOSTAT)); + SETBITS(DMACNTRL0, _8BIT); + printk("aha152x: data ("); + while (fifodata--) + printk("%2x ", GETPORT(DATAPORT)); + printk(")\n"); + } #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - if(!fifodata) - printk("fifo empty, "); - else - printk("something left in fifo, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + if (!fifodata) + printk("fifo empty, "); + else + printk("something left in fifo, "); #endif - } + } #if defined(DEBUG_DATAI) - if((HOSTDATA(shpnt)->debug & debug_datai) && - (CURRENT_SC->SCp.buffers_residual || - CURRENT_SC->SCp.this_residual)) - printk("left buffers (buffers=%d, bytes=%d), ", - CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual); -#endif - /* transfer can be considered ended, when SCSIEN reads back zero */ - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - while(TESTHI(SXFRCTL0, SCSIEN)) - barrier(); - CLRBITS(DMACNTRL0, ENDMA); + if ((HOSTDATA(shpnt)->debug & debug_datai) && + (CURRENT_SC->SCp.buffers_residual || + CURRENT_SC->SCp.this_residual)) + printk("left buffers (buffers=%d, bytes=%d), ", + CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual); +#endif + /* transfer can be considered ended, when SCSIEN reads back zero */ + CLRBITS(SXFRCTL0, SCSIEN | DMAEN); + while (TESTHI(SXFRCTL0, SCSIEN)) + barrier(); + CLRBITS(DMACNTRL0, ENDMA); #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr)) - printk("got %d bytes, ", GETSTCNT()); + if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr)) + printk("got %d bytes, ", GETSTCNT()); #endif - CURRENT_SC->SCp.have_data_in++; - } - break; + CURRENT_SC->SCp.have_data_in++; + } + break; - case P_DATAO: /* DATA OUT phase */ - { - int data_count; + case P_DATAO: /* DATA OUT phase */ + { + int data_count; #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr|debug_phases)) - printk("DATA OUT, "); + if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr | debug_phases)) + printk("DATA OUT, "); #endif #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("got data to send (bytes=%d, buffers=%d), ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - - if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) { - printk("%d(%d) left in FIFO, ", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); - aha152x_panic(shpnt, "FIFO should be empty"); - } - - SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1); - SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); - - SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); - SETPORT(DMACNTRL0, ENDMA|WRITE_READ); - - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); - - /* while current buffer is not empty or - there are more buffers to transfer */ - while(TESTLO(SSTAT1, PHASEMIS) && - (CURRENT_SC->SCp.this_residual || - CURRENT_SC->SCp.buffers_residual)) { + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("got data to send (bytes=%d, buffers=%d), ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + + if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) { + printk("%d(%d) left in FIFO, ", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT)); + aha152x_panic(shpnt, "FIFO should be empty"); + } + SETPORT(SXFRCTL0, CH1 | CLRSTCNT | CLRCH1); + SETPORT(SXFRCTL0, SCSIEN | DMAEN | CH1); + + SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); + SETPORT(DMACNTRL0, ENDMA | WRITE_READ); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); + + /* while current buffer is not empty or + there are more buffers to transfer */ + while (TESTLO(SSTAT1, PHASEMIS) && + (CURRENT_SC->SCp.this_residual || + CURRENT_SC->SCp.buffers_residual)) { #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("sending data (left: bytes=%d, buffers=%d), waiting, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - /* transfer rest of buffer, but max. 128 byte */ - data_count = - CURRENT_SC->SCp.this_residual > 128 ? - 128 : CURRENT_SC->SCp.this_residual ; + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("sending data (left: bytes=%d, buffers=%d), waiting, ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + /* transfer rest of buffer, but max. 128 byte */ + data_count = + CURRENT_SC->SCp.this_residual > 128 ? + 128 : CURRENT_SC->SCp.this_residual; #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("data_count=%d, ", data_count); + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("data_count=%d, ", data_count); #endif - - if(data_count&1) { - /* put a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); - CURRENT_SC->SCp.this_residual--; - } - if(data_count>1) { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* number of words */ - outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - - /* wait for FIFO to get empty */ - while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) - barrier(); + + if (data_count & 1) { + /* put a single byte in byte mode */ + SETBITS(DMACNTRL0, _8BIT); + SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); + CURRENT_SC->SCp.this_residual--; + } + if (data_count > 1) { + CLRBITS(DMACNTRL0, _8BIT); + data_count >>= 1; /* number of words */ + outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + } + /* wait for FIFO to get empty */ + while (TESTLO(DMASTAT, DFIFOEMP | INTSTAT)) + barrier(); #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("fifo (%d bytes), transfered (%d bytes), ", - GETPORT(FIFOSTAT), GETSTCNT()); -#endif - - /* if this buffer is empty and there are more buffers left */ - if(TESTLO(SSTAT1, PHASEMIS) && - !CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - } - - if(CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { - /* target leaves DATA OUT for an other phase (perhaps disconnect) */ - - /* data in fifos has to be resend */ - data_count = GETPORT(SSTAT2) & (SFULL|SFCNT); - - data_count += GETPORT(FIFOSTAT) ; - CURRENT_SC->SCp.ptr -= data_count; - CURRENT_SC->SCp.this_residual += data_count; + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("fifo (%d bytes), transfered (%d bytes), ", + GETPORT(FIFOSTAT), GETSTCNT()); +#endif + + /* if this buffer is empty and there are more buffers left */ + if (TESTLO(SSTAT1, PHASEMIS) && + !CURRENT_SC->SCp.this_residual && + CURRENT_SC->SCp.buffers_residual) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + + if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { + /* target leaves DATA OUT for an other phase (perhaps disconnect) */ + + /* data in fifos has to be resend */ + data_count = GETPORT(SSTAT2) & (SFULL | SFCNT); + + data_count += GETPORT(FIFOSTAT); + CURRENT_SC->SCp.ptr -= data_count; + CURRENT_SC->SCp.this_residual += data_count; #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), " - "transfer incomplete, resetting fifo, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual, - data_count); -#endif - SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - CLRBITS(DMACNTRL0, ENDMA); - } else { + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), " + "transfer incomplete, resetting fifo, ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual, + data_count); +#endif + SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); + CLRBITS(SXFRCTL0, SCSIEN | DMAEN); + CLRBITS(DMACNTRL0, ENDMA); + } else { #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("waiting for SCSI fifo to get empty, "); + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("waiting for SCSI fifo to get empty, "); #endif - /* wait for SCSI fifo to get empty */ - while(TESTLO(SSTAT2, SEMPTY)) - barrier(); + /* wait for SCSI fifo to get empty */ + while (TESTLO(SSTAT2, SEMPTY)) + barrier(); #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("ok, left data (bytes=%d, buffers=%d) ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - - /* transfer can be considered ended, when SCSIEN reads back zero */ - while(TESTHI(SXFRCTL0, SCSIEN)) - barrier(); + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("ok, left data (bytes=%d, buffers=%d) ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + CLRBITS(SXFRCTL0, SCSIEN | DMAEN); + + /* transfer can be considered ended, when SCSIEN reads back zero */ + while (TESTHI(SXFRCTL0, SCSIEN)) + barrier(); - CLRBITS(DMACNTRL0, ENDMA); - } + CLRBITS(DMACNTRL0, ENDMA); + } #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr)) - printk("sent %d data bytes, ", GETSTCNT()); + if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr)) + printk("sent %d data bytes, ", GETSTCNT()); #endif - } - break; + } + break; - case P_BUSFREE: /* BUSFREE */ + case P_BUSFREE: /* BUSFREE */ #if defined(DEBUG_RACE) - leave_driver("(BUSFREE) intr"); + leave_driver("(BUSFREE) intr"); #endif #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("unexpected BUS FREE, "); + if (HOSTDATA(shpnt)->debug & debug_phases) + printk("unexpected BUS FREE, "); #endif - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK << 16); - aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ - return; - break; + aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ + return; + break; - case P_PARITY: /* parity error in DATA phase */ + case P_PARITY: /* parity error in DATA phase */ #if defined(DEBUG_RACE) - leave_driver("(DID_PARITY) intr"); + leave_driver("(DID_PARITY) intr"); #endif - printk("PARITY error in DATA phase, "); + printk("PARITY error in DATA phase, "); - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK << 16); - SETBITS(DMACNTRL0, INTEN); - aha152x_done(shpnt, DID_PARITY << 16); - return; - break; + SETBITS(DMACNTRL0, INTEN); + aha152x_done(shpnt, DID_PARITY << 16); + return; + break; - default: - printk("aha152x: unexpected phase\n"); - break; - } + default: + printk("aha152x: unexpected phase\n"); + break; + } - if(done) { + if (done) { #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - printk("command done.\n"); + if (HOSTDATA(shpnt)->debug & debug_intr) + printk("command done.\n"); #endif #if defined(DEBUG_RACE) - leave_driver("(done) intr"); + leave_driver("(done) intr"); #endif - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); - - SETBITS(DMACNTRL0, INTEN); - - aha152x_done(shpnt, - (CURRENT_SC->SCp.Status & 0xff) - | ((CURRENT_SC->SCp.Message & 0xff) << 8) - | (DID_OK << 16)); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + + SETBITS(DMACNTRL0, INTEN); + + aha152x_done(shpnt, + (CURRENT_SC->SCp.Status & 0xff) + | ((CURRENT_SC->SCp.Message & 0xff) << 8) + | (DID_OK << 16)); #if defined(DEBUG_RACE) - printk("done returned (DID_OK: Status=%x; Message=%x).\n", - CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); + printk("done returned (DID_OK: Status=%x; Message=%x).\n", + CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); #endif - return; - } - - if(CURRENT_SC) - CURRENT_SC->SCp.phase |= 1<<16; + return; + } + if (CURRENT_SC) + CURRENT_SC->SCp.phase |= 1 << 16; - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - disp_enintr(shpnt); + if (HOSTDATA(shpnt)->debug & debug_intr) + disp_enintr(shpnt); #endif #if defined(DEBUG_RACE) - leave_driver("(PHASEEND) intr"); + leave_driver("(PHASEEND) intr"); #endif - SETBITS(DMACNTRL0, INTEN); - return; + SETBITS(DMACNTRL0, INTEN); + return; } /* @@ -2637,9 +2639,9 @@ */ static void aha152x_panic(struct Scsi_Host *shpnt, char *msg) { - printk("\naha152x: %s\n", msg); - show_queues(shpnt); - panic("aha152x panic"); + printk("\naha152x: %s\n", msg); + show_queues(shpnt); + panic("aha152x panic"); } /* @@ -2648,166 +2650,231 @@ static void disp_ports(struct Scsi_Host *shpnt) { #ifdef DEBUG_AHA152X - int s; + int s; #ifdef SKIP_PORTS - if(HOSTDATA(shpnt)->debug & debug_skipports) - return; + if (HOSTDATA(shpnt)->debug & debug_skipports) + return; #endif - printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); - s=GETPORT(SCSISEQ); - printk("SCSISEQ ("); - if(s & TEMODEO) printk("TARGET MODE "); - if(s & ENSELO) printk("SELO "); - if(s & ENSELI) printk("SELI "); - if(s & ENRESELI) printk("RESELI "); - if(s & ENAUTOATNO) printk("AUTOATNO "); - if(s & ENAUTOATNI) printk("AUTOATNI "); - if(s & ENAUTOATNP) printk("AUTOATNP "); - if(s & SCSIRSTO) printk("SCSIRSTO "); - printk(");"); - - printk(" SCSISIG ("); - s=GETPORT(SCSISIG); - switch(s & P_MASK) { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*illegal*"); - break; - } - - printk("); "); - - printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - - printk("SSTAT ("); - s=GETPORT(SSTAT0); - if(s & TARGET) printk("TARGET "); - if(s & SELDO) printk("SELDO "); - if(s & SELDI) printk("SELDI "); - if(s & SELINGO) printk("SELINGO "); - if(s & SWRAP) printk("SWRAP "); - if(s & SDONE) printk("SDONE "); - if(s & SPIORDY) printk("SPIORDY "); - if(s & DMADONE) printk("DMADONE "); - - s=GETPORT(SSTAT1); - if(s & SELTO) printk("SELTO "); - if(s & ATNTARG) printk("ATNTARG "); - if(s & SCSIRSTI) printk("SCSIRSTI "); - if(s & PHASEMIS) printk("PHASEMIS "); - if(s & BUSFREE) printk("BUSFREE "); - if(s & SCSIPERR) printk("SCSIPERR "); - if(s & PHASECHG) printk("PHASECHG "); - if(s & REQINIT) printk("REQINIT "); - printk("); "); - - - printk("SSTAT ("); - - s=GETPORT(SSTAT0) & GETPORT(SIMODE0); - - if(s & TARGET) printk("TARGET "); - if(s & SELDO) printk("SELDO "); - if(s & SELDI) printk("SELDI "); - if(s & SELINGO) printk("SELINGO "); - if(s & SWRAP) printk("SWRAP "); - if(s & SDONE) printk("SDONE "); - if(s & SPIORDY) printk("SPIORDY "); - if(s & DMADONE) printk("DMADONE "); - - s=GETPORT(SSTAT1) & GETPORT(SIMODE1); - - if(s & SELTO) printk("SELTO "); - if(s & ATNTARG) printk("ATNTARG "); - if(s & SCSIRSTI) printk("SCSIRSTI "); - if(s & PHASEMIS) printk("PHASEMIS "); - if(s & BUSFREE) printk("BUSFREE "); - if(s & SCSIPERR) printk("SCSIPERR "); - if(s & PHASECHG) printk("PHASECHG "); - if(s & REQINIT) printk("REQINIT "); - printk("); "); - - printk("SXFRCTL0 ("); - - s=GETPORT(SXFRCTL0); - if(s & SCSIEN) printk("SCSIEN "); - if(s & DMAEN) printk("DMAEN "); - if(s & CH1) printk("CH1 "); - if(s & CLRSTCNT) printk("CLRSTCNT "); - if(s & SPIOEN) printk("SPIOEN "); - if(s & CLRCH1) printk("CLRCH1 "); - printk("); "); - - printk("SIGNAL ("); - - s=GETPORT(SCSISIG); - if(s & ATNI) printk("ATNI "); - if(s & SELI) printk("SELI "); - if(s & BSYI) printk("BSYI "); - if(s & REQI) printk("REQI "); - if(s & ACKI) printk("ACKI "); - printk("); "); - - printk("SELID (%02x), ", GETPORT(SELID)); - - printk("SSTAT2 ("); - - s=GETPORT(SSTAT2); - if(s & SOFFSET) printk("SOFFSET "); - if(s & SEMPTY) printk("SEMPTY "); - if(s & SFULL) printk("SFULL "); - printk("); SFCNT (%d); ", s & (SFULL|SFCNT)); - - s=GETPORT(SSTAT3); - printk("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f); - - printk("SSTAT4 ("); - s=GETPORT(SSTAT4); - if(s & SYNCERR) printk("SYNCERR "); - if(s & FWERR) printk("FWERR "); - if(s & FRERR) printk("FRERR "); - printk("); "); - - printk("DMACNTRL0 ("); - s=GETPORT(DMACNTRL0); - printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); - printk("%s ", s & DMA ? "DMA" : "PIO" ); - printk("%s ", s & WRITE_READ ? "WRITE" : "READ" ); - if(s & ENDMA) printk("ENDMA "); - if(s & INTEN) printk("INTEN "); - if(s & RSTFIFO) printk("RSTFIFO "); - if(s & SWINT) printk("SWINT "); - printk("); "); - - printk("DMASTAT ("); - s=GETPORT(DMASTAT); - if(s & ATDONE) printk("ATDONE "); - if(s & WORDRDY) printk("WORDRDY "); - if(s & DFIFOFULL) printk("DFIFOFULL "); - if(s & DFIFOEMP) printk("DFIFOEMP "); - printk(")"); + s = GETPORT(SCSISEQ); + printk("SCSISEQ ("); + if (s & TEMODEO) + printk("TARGET MODE "); + if (s & ENSELO) + printk("SELO "); + if (s & ENSELI) + printk("SELI "); + if (s & ENRESELI) + printk("RESELI "); + if (s & ENAUTOATNO) + printk("AUTOATNO "); + if (s & ENAUTOATNI) + printk("AUTOATNI "); + if (s & ENAUTOATNP) + printk("AUTOATNP "); + if (s & SCSIRSTO) + printk("SCSIRSTO "); + printk(");"); + + printk(" SCSISIG ("); + s = GETPORT(SCSISIG); + switch (s & P_MASK) { + case P_DATAO: + printk("DATA OUT"); + break; + case P_DATAI: + printk("DATA IN"); + break; + case P_CMD: + printk("COMMAND"); + break; + case P_STATUS: + printk("STATUS"); + break; + case P_MSGO: + printk("MESSAGE OUT"); + break; + case P_MSGI: + printk("MESSAGE IN"); + break; + default: + printk("*illegal*"); + break; + } + + printk("); "); + + printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - printk("\n"); + printk("SSTAT ("); + s = GETPORT(SSTAT0); + if (s & TARGET) + printk("TARGET "); + if (s & SELDO) + printk("SELDO "); + if (s & SELDI) + printk("SELDI "); + if (s & SELINGO) + printk("SELINGO "); + if (s & SWRAP) + printk("SWRAP "); + if (s & SDONE) + printk("SDONE "); + if (s & SPIORDY) + printk("SPIORDY "); + if (s & DMADONE) + printk("DMADONE "); + + s = GETPORT(SSTAT1); + if (s & SELTO) + printk("SELTO "); + if (s & ATNTARG) + printk("ATNTARG "); + if (s & SCSIRSTI) + printk("SCSIRSTI "); + if (s & PHASEMIS) + printk("PHASEMIS "); + if (s & BUSFREE) + printk("BUSFREE "); + if (s & SCSIPERR) + printk("SCSIPERR "); + if (s & PHASECHG) + printk("PHASECHG "); + if (s & REQINIT) + printk("REQINIT "); + printk("); "); + + + printk("SSTAT ("); + + s = GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if (s & TARGET) + printk("TARGET "); + if (s & SELDO) + printk("SELDO "); + if (s & SELDI) + printk("SELDI "); + if (s & SELINGO) + printk("SELINGO "); + if (s & SWRAP) + printk("SWRAP "); + if (s & SDONE) + printk("SDONE "); + if (s & SPIORDY) + printk("SPIORDY "); + if (s & DMADONE) + printk("DMADONE "); + + s = GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if (s & SELTO) + printk("SELTO "); + if (s & ATNTARG) + printk("ATNTARG "); + if (s & SCSIRSTI) + printk("SCSIRSTI "); + if (s & PHASEMIS) + printk("PHASEMIS "); + if (s & BUSFREE) + printk("BUSFREE "); + if (s & SCSIPERR) + printk("SCSIPERR "); + if (s & PHASECHG) + printk("PHASECHG "); + if (s & REQINIT) + printk("REQINIT "); + printk("); "); + + printk("SXFRCTL0 ("); + + s = GETPORT(SXFRCTL0); + if (s & SCSIEN) + printk("SCSIEN "); + if (s & DMAEN) + printk("DMAEN "); + if (s & CH1) + printk("CH1 "); + if (s & CLRSTCNT) + printk("CLRSTCNT "); + if (s & SPIOEN) + printk("SPIOEN "); + if (s & CLRCH1) + printk("CLRCH1 "); + printk("); "); + + printk("SIGNAL ("); + + s = GETPORT(SCSISIG); + if (s & ATNI) + printk("ATNI "); + if (s & SELI) + printk("SELI "); + if (s & BSYI) + printk("BSYI "); + if (s & REQI) + printk("REQI "); + if (s & ACKI) + printk("ACKI "); + printk("); "); + + printk("SELID (%02x), ", GETPORT(SELID)); + + printk("SSTAT2 ("); + + s = GETPORT(SSTAT2); + if (s & SOFFSET) + printk("SOFFSET "); + if (s & SEMPTY) + printk("SEMPTY "); + if (s & SFULL) + printk("SFULL "); + printk("); SFCNT (%d); ", s & (SFULL | SFCNT)); + + s = GETPORT(SSTAT3); + printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); + + printk("SSTAT4 ("); + s = GETPORT(SSTAT4); + if (s & SYNCERR) + printk("SYNCERR "); + if (s & FWERR) + printk("FWERR "); + if (s & FRERR) + printk("FRERR "); + printk("); "); + + printk("DMACNTRL0 ("); + s = GETPORT(DMACNTRL0); + printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); + printk("%s ", s & DMA ? "DMA" : "PIO"); + printk("%s ", s & WRITE_READ ? "WRITE" : "READ"); + if (s & ENDMA) + printk("ENDMA "); + if (s & INTEN) + printk("INTEN "); + if (s & RSTFIFO) + printk("RSTFIFO "); + if (s & SWINT) + printk("SWINT "); + printk("); "); + + printk("DMASTAT ("); + s = GETPORT(DMASTAT); + if (s & ATDONE) + printk("ATDONE "); + if (s & WORDRDY) + printk("WORDRDY "); + if (s & DFIFOFULL) + printk("DFIFOFULL "); + if (s & DFIFOEMP) + printk("DFIFOEMP "); + printk(")"); + + printk("\n"); #endif } @@ -2816,518 +2883,618 @@ */ static void disp_enintr(struct Scsi_Host *shpnt) { - int s; + int s; + + printk("enabled interrupts ("); - printk("enabled interrupts ("); - - s=GETPORT(SIMODE0); - if(s & ENSELDO) printk("ENSELDO "); - if(s & ENSELDI) printk("ENSELDI "); - if(s & ENSELINGO) printk("ENSELINGO "); - if(s & ENSWRAP) printk("ENSWRAP "); - if(s & ENSDONE) printk("ENSDONE "); - if(s & ENSPIORDY) printk("ENSPIORDY "); - if(s & ENDMADONE) printk("ENDMADONE "); - - s=GETPORT(SIMODE1); - if(s & ENSELTIMO) printk("ENSELTIMO "); - if(s & ENATNTARG) printk("ENATNTARG "); - if(s & ENPHASEMIS) printk("ENPHASEMIS "); - if(s & ENBUSFREE) printk("ENBUSFREE "); - if(s & ENSCSIPERR) printk("ENSCSIPERR "); - if(s & ENPHASECHG) printk("ENPHASECHG "); - if(s & ENREQINIT) printk("ENREQINIT "); - printk(")\n"); + s = GETPORT(SIMODE0); + if (s & ENSELDO) + printk("ENSELDO "); + if (s & ENSELDI) + printk("ENSELDI "); + if (s & ENSELINGO) + printk("ENSELINGO "); + if (s & ENSWRAP) + printk("ENSWRAP "); + if (s & ENSDONE) + printk("ENSDONE "); + if (s & ENSPIORDY) + printk("ENSPIORDY "); + if (s & ENDMADONE) + printk("ENDMADONE "); + + s = GETPORT(SIMODE1); + if (s & ENSELTIMO) + printk("ENSELTIMO "); + if (s & ENATNTARG) + printk("ENATNTARG "); + if (s & ENPHASEMIS) + printk("ENPHASEMIS "); + if (s & ENBUSFREE) + printk("ENBUSFREE "); + if (s & ENSCSIPERR) + printk("ENSCSIPERR "); + if (s & ENPHASECHG) + printk("ENPHASECHG "); + if (s & ENREQINIT) + printk("ENREQINIT "); + printk(")\n"); } #if defined(DEBUG_RACE) static const char *should_leave; -static int in_driver=0; +static int in_driver = 0; /* * Only one routine can be in the driver at once. */ static void enter_driver(const char *func) { - unsigned long flags; + unsigned long flags; - save_flags(flags); - cli(); - printk("aha152x: entering %s() (%x)\n", func, jiffies); - if(in_driver) { - printk("%s should leave first.\n", should_leave); - panic("aha152x: already in driver\n"); - } - - in_driver++; - should_leave=func; - restore_flags(flags); + save_flags(flags); + cli(); + printk("aha152x: entering %s() (%x)\n", func, jiffies); + if (in_driver) { + printk("%s should leave first.\n", should_leave); + panic("aha152x: already in driver\n"); + } + in_driver++; + should_leave = func; + restore_flags(flags); } static void leave_driver(const char *func) { - unsigned long flags; + unsigned long flags; - save_flags(flags); - cli(); - printk("\naha152x: leaving %s() (%x)\n", func, jiffies); - if(!in_driver) { - printk("aha152x: %s already left.\n", should_leave); - panic("aha152x: %s already left driver.\n"); - } - - in_driver--; - should_leave=func; - restore_flags(flags); + save_flags(flags); + cli(); + printk("\naha152x: leaving %s() (%x)\n", func, jiffies); + if (!in_driver) { + printk("aha152x: %s already left.\n", should_leave); + panic("aha152x: %s already left driver.\n"); + } + in_driver--; + should_leave = func; + restore_flags(flags); } #endif /* * Show the command data of a command */ -static void show_command(Scsi_Cmnd *ptr) +static void show_command(Scsi_Cmnd * ptr) { - printk("0x%08x: target=%d; lun=%d; cmnd=(", - (unsigned int) ptr, ptr->target, ptr->lun); - - print_command(ptr->cmnd); - - printk("); residual=%d; buffers=%d; phase |", - ptr->SCp.this_residual, ptr->SCp.buffers_residual); - - if(ptr->SCp.phase & not_issued ) printk("not issued|"); - if(ptr->SCp.phase & in_selection) printk("in selection|"); - if(ptr->SCp.phase & disconnected) printk("disconnected|"); - if(ptr->SCp.phase & aborted ) printk("aborted|"); - if(ptr->SCp.phase & sent_ident ) printk("send_ident|"); - if(ptr->SCp.phase & in_other) { - printk("; in other("); - switch((ptr->SCp.phase >> 16) & P_MASK) { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*illegal*"); - break; - } - printk(")"); - if(ptr->SCp.phase & (1<<16)) - printk("; phaseend"); - } - printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble); + printk("0x%08x: target=%d; lun=%d; cmnd=(", + (unsigned int) ptr, ptr->target, ptr->lun); + + print_command(ptr->cmnd); + + printk("); residual=%d; buffers=%d; phase |", + ptr->SCp.this_residual, ptr->SCp.buffers_residual); + + if (ptr->SCp.phase & not_issued) + printk("not issued|"); + if (ptr->SCp.phase & in_selection) + printk("in selection|"); + if (ptr->SCp.phase & disconnected) + printk("disconnected|"); + if (ptr->SCp.phase & aborted) + printk("aborted|"); + if (ptr->SCp.phase & sent_ident) + printk("send_ident|"); + if (ptr->SCp.phase & in_other) { + printk("; in other("); + switch ((ptr->SCp.phase >> 16) & P_MASK) { + case P_DATAO: + printk("DATA OUT"); + break; + case P_DATAI: + printk("DATA IN"); + break; + case P_CMD: + printk("COMMAND"); + break; + case P_STATUS: + printk("STATUS"); + break; + case P_MSGO: + printk("MESSAGE OUT"); + break; + case P_MSGI: + printk("MESSAGE IN"); + break; + default: + printk("*illegal*"); + break; + } + printk(")"); + if (ptr->SCp.phase & (1 << 16)) + printk("; phaseend"); + } + printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble); } - + /* * Dump the queued data */ static void show_queues(struct Scsi_Host *shpnt) { - unsigned long flags; - Scsi_Cmnd *ptr; + unsigned long flags; + Scsi_Cmnd *ptr; - save_flags(flags); - cli(); - printk("QUEUE STATUS:\nissue_SC:\n"); - for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - show_command(ptr); - - printk("current_SC:\n"); - if(CURRENT_SC) - show_command(CURRENT_SC); - else - printk("none\n"); - - printk("disconnected_SC:\n"); - for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - show_command(ptr); - - disp_ports(shpnt); - disp_enintr(shpnt); - restore_flags(flags); + save_flags(flags); + cli(); + printk("QUEUE STATUS:\nissue_SC:\n"); + for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + show_command(ptr); + + printk("current_SC:\n"); + if (CURRENT_SC) + show_command(CURRENT_SC); + else + printk("none\n"); + + printk("disconnected_SC:\n"); + for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + show_command(ptr); + + disp_ports(shpnt); + disp_enintr(shpnt); + restore_flags(flags); } int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) { - return(-ENOSYS); /* Currently this is a no-op */ + return (-ENOSYS); /* Currently this is a no-op */ } #undef SPRINTF #define SPRINTF(args...) pos += sprintf(pos, ## args) -static int get_command(char *pos, Scsi_Cmnd *ptr) +static int get_command(char *pos, Scsi_Cmnd * ptr) { - char *start = pos; - int i; - - SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", - (unsigned int) ptr, ptr->target, ptr->lun); - - for(i=0; icmnd[0]); i++) - SPRINTF("0x%02x ", ptr->cmnd[i]); - - SPRINTF("); residual=%d; buffers=%d; phase |", - ptr->SCp.this_residual, ptr->SCp.buffers_residual); - - if(ptr->SCp.phase & not_issued ) SPRINTF("not issued|"); - if(ptr->SCp.phase & in_selection) SPRINTF("in selection|"); - if(ptr->SCp.phase & disconnected) SPRINTF("disconnected|"); - if(ptr->SCp.phase & aborted ) SPRINTF("aborted|"); - if(ptr->SCp.phase & sent_ident ) SPRINTF("send_ident|"); - if(ptr->SCp.phase & in_other) { - SPRINTF("; in other("); - switch((ptr->SCp.phase >> 16) & P_MASK) { - case P_DATAO: - SPRINTF("DATA OUT"); - break; - case P_DATAI: - SPRINTF("DATA IN"); - break; - case P_CMD: - SPRINTF("COMMAND"); - break; - case P_STATUS: - SPRINTF("STATUS"); - break; - case P_MSGO: - SPRINTF("MESSAGE OUT"); - break; - case P_MSGI: - SPRINTF("MESSAGE IN"); - break; - default: - SPRINTF("*illegal*"); - break; - } - SPRINTF(")"); - if(ptr->SCp.phase & (1<<16)) - SPRINTF("; phaseend"); - } - SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble); - - return(pos-start); + char *start = pos; + int i; + + SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", + (unsigned int) ptr, ptr->target, ptr->lun); + + for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) + SPRINTF("0x%02x ", ptr->cmnd[i]); + + SPRINTF("); residual=%d; buffers=%d; phase |", + ptr->SCp.this_residual, ptr->SCp.buffers_residual); + + if (ptr->SCp.phase & not_issued) + SPRINTF("not issued|"); + if (ptr->SCp.phase & in_selection) + SPRINTF("in selection|"); + if (ptr->SCp.phase & disconnected) + SPRINTF("disconnected|"); + if (ptr->SCp.phase & aborted) + SPRINTF("aborted|"); + if (ptr->SCp.phase & sent_ident) + SPRINTF("send_ident|"); + if (ptr->SCp.phase & in_other) { + SPRINTF("; in other("); + switch ((ptr->SCp.phase >> 16) & P_MASK) { + case P_DATAO: + SPRINTF("DATA OUT"); + break; + case P_DATAI: + SPRINTF("DATA IN"); + break; + case P_CMD: + SPRINTF("COMMAND"); + break; + case P_STATUS: + SPRINTF("STATUS"); + break; + case P_MSGO: + SPRINTF("MESSAGE OUT"); + break; + case P_MSGI: + SPRINTF("MESSAGE IN"); + break; + default: + SPRINTF("*illegal*"); + break; + } + SPRINTF(")"); + if (ptr->SCp.phase & (1 << 16)) + SPRINTF("; phaseend"); + } + SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble); + + return (pos - start); } static int get_ports(struct Scsi_Host *shpnt, char *pos) { - char *start = pos; - int s; + char *start = pos; + int s; #ifdef SKIP_PORTS - if(HOSTDATA(shpnt)->debug & debug_skipports) - return; + if (HOSTDATA(shpnt)->debug & debug_skipports) + return; #endif - SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + + s = GETPORT(SCSISEQ); + SPRINTF("SCSISEQ ("); + if (s & TEMODEO) + SPRINTF("TARGET MODE "); + if (s & ENSELO) + SPRINTF("SELO "); + if (s & ENSELI) + SPRINTF("SELI "); + if (s & ENRESELI) + SPRINTF("RESELI "); + if (s & ENAUTOATNO) + SPRINTF("AUTOATNO "); + if (s & ENAUTOATNI) + SPRINTF("AUTOATNI "); + if (s & ENAUTOATNP) + SPRINTF("AUTOATNP "); + if (s & SCSIRSTO) + SPRINTF("SCSIRSTO "); + SPRINTF(");"); + + SPRINTF(" SCSISIG ("); + s = GETPORT(SCSISIG); + switch (s & P_MASK) { + case P_DATAO: + SPRINTF("DATA OUT"); + break; + case P_DATAI: + SPRINTF("DATA IN"); + break; + case P_CMD: + SPRINTF("COMMAND"); + break; + case P_STATUS: + SPRINTF("STATUS"); + break; + case P_MSGO: + SPRINTF("MESSAGE OUT"); + break; + case P_MSGI: + SPRINTF("MESSAGE IN"); + break; + default: + SPRINTF("*illegal*"); + break; + } + + SPRINTF("); "); + + SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - s=GETPORT(SCSISEQ); - SPRINTF("SCSISEQ ("); - if(s & TEMODEO) SPRINTF("TARGET MODE "); - if(s & ENSELO) SPRINTF("SELO "); - if(s & ENSELI) SPRINTF("SELI "); - if(s & ENRESELI) SPRINTF("RESELI "); - if(s & ENAUTOATNO) SPRINTF("AUTOATNO "); - if(s & ENAUTOATNI) SPRINTF("AUTOATNI "); - if(s & ENAUTOATNP) SPRINTF("AUTOATNP "); - if(s & SCSIRSTO) SPRINTF("SCSIRSTO "); - SPRINTF(");"); - - SPRINTF(" SCSISIG ("); - s=GETPORT(SCSISIG); - switch(s & P_MASK) { - case P_DATAO: - SPRINTF("DATA OUT"); - break; - case P_DATAI: - SPRINTF("DATA IN"); - break; - case P_CMD: - SPRINTF("COMMAND"); - break; - case P_STATUS: - SPRINTF("STATUS"); - break; - case P_MSGO: - SPRINTF("MESSAGE OUT"); - break; - case P_MSGI: - SPRINTF("MESSAGE IN"); - break; - default: - SPRINTF("*illegal*"); - break; - } - - SPRINTF("); "); - - SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - - SPRINTF("SSTAT ("); - s=GETPORT(SSTAT0); - if(s & TARGET) SPRINTF("TARGET "); - if(s & SELDO) SPRINTF("SELDO "); - if(s & SELDI) SPRINTF("SELDI "); - if(s & SELINGO) SPRINTF("SELINGO "); - if(s & SWRAP) SPRINTF("SWRAP "); - if(s & SDONE) SPRINTF("SDONE "); - if(s & SPIORDY) SPRINTF("SPIORDY "); - if(s & DMADONE) SPRINTF("DMADONE "); - - s=GETPORT(SSTAT1); - if(s & SELTO) SPRINTF("SELTO "); - if(s & ATNTARG) SPRINTF("ATNTARG "); - if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); - if(s & PHASEMIS) SPRINTF("PHASEMIS "); - if(s & BUSFREE) SPRINTF("BUSFREE "); - if(s & SCSIPERR) SPRINTF("SCSIPERR "); - if(s & PHASECHG) SPRINTF("PHASECHG "); - if(s & REQINIT) SPRINTF("REQINIT "); - SPRINTF("); "); - - - SPRINTF("SSTAT ("); - - s=GETPORT(SSTAT0) & GETPORT(SIMODE0); - - if(s & TARGET) SPRINTF("TARGET "); - if(s & SELDO) SPRINTF("SELDO "); - if(s & SELDI) SPRINTF("SELDI "); - if(s & SELINGO) SPRINTF("SELINGO "); - if(s & SWRAP) SPRINTF("SWRAP "); - if(s & SDONE) SPRINTF("SDONE "); - if(s & SPIORDY) SPRINTF("SPIORDY "); - if(s & DMADONE) SPRINTF("DMADONE "); - - s=GETPORT(SSTAT1) & GETPORT(SIMODE1); - - if(s & SELTO) SPRINTF("SELTO "); - if(s & ATNTARG) SPRINTF("ATNTARG "); - if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); - if(s & PHASEMIS) SPRINTF("PHASEMIS "); - if(s & BUSFREE) SPRINTF("BUSFREE "); - if(s & SCSIPERR) SPRINTF("SCSIPERR "); - if(s & PHASECHG) SPRINTF("PHASECHG "); - if(s & REQINIT) SPRINTF("REQINIT "); - SPRINTF("); "); - - SPRINTF("SXFRCTL0 ("); - - s=GETPORT(SXFRCTL0); - if(s & SCSIEN) SPRINTF("SCSIEN "); - if(s & DMAEN) SPRINTF("DMAEN "); - if(s & CH1) SPRINTF("CH1 "); - if(s & CLRSTCNT) SPRINTF("CLRSTCNT "); - if(s & SPIOEN) SPRINTF("SPIOEN "); - if(s & CLRCH1) SPRINTF("CLRCH1 "); - SPRINTF("); "); - - SPRINTF("SIGNAL ("); - - s=GETPORT(SCSISIG); - if(s & ATNI) SPRINTF("ATNI "); - if(s & SELI) SPRINTF("SELI "); - if(s & BSYI) SPRINTF("BSYI "); - if(s & REQI) SPRINTF("REQI "); - if(s & ACKI) SPRINTF("ACKI "); - SPRINTF("); "); - - SPRINTF("SELID (%02x), ", GETPORT(SELID)); - - SPRINTF("SSTAT2 ("); - - s=GETPORT(SSTAT2); - if(s & SOFFSET) SPRINTF("SOFFSET "); - if(s & SEMPTY) SPRINTF("SEMPTY "); - if(s & SFULL) SPRINTF("SFULL "); - SPRINTF("); SFCNT (%d); ", s & (SFULL|SFCNT)); - - s=GETPORT(SSTAT3); - SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f); - - SPRINTF("SSTAT4 ("); - s=GETPORT(SSTAT4); - if(s & SYNCERR) SPRINTF("SYNCERR "); - if(s & FWERR) SPRINTF("FWERR "); - if(s & FRERR) SPRINTF("FRERR "); - SPRINTF("); "); - - SPRINTF("DMACNTRL0 ("); - s=GETPORT(DMACNTRL0); - SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); - SPRINTF("%s ", s & DMA ? "DMA" : "PIO" ); - SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ" ); - if(s & ENDMA) SPRINTF("ENDMA "); - if(s & INTEN) SPRINTF("INTEN "); - if(s & RSTFIFO) SPRINTF("RSTFIFO "); - if(s & SWINT) SPRINTF("SWINT "); - SPRINTF("); "); - - SPRINTF("DMASTAT ("); - s=GETPORT(DMASTAT); - if(s & ATDONE) SPRINTF("ATDONE "); - if(s & WORDRDY) SPRINTF("WORDRDY "); - if(s & DFIFOFULL) SPRINTF("DFIFOFULL "); - if(s & DFIFOEMP) SPRINTF("DFIFOEMP "); - SPRINTF(")\n\n"); - - SPRINTF("enabled interrupts ("); - - s=GETPORT(SIMODE0); - if(s & ENSELDO) SPRINTF("ENSELDO "); - if(s & ENSELDI) SPRINTF("ENSELDI "); - if(s & ENSELINGO) SPRINTF("ENSELINGO "); - if(s & ENSWRAP) SPRINTF("ENSWRAP "); - if(s & ENSDONE) SPRINTF("ENSDONE "); - if(s & ENSPIORDY) SPRINTF("ENSPIORDY "); - if(s & ENDMADONE) SPRINTF("ENDMADONE "); - - s=GETPORT(SIMODE1); - if(s & ENSELTIMO) SPRINTF("ENSELTIMO "); - if(s & ENATNTARG) SPRINTF("ENATNTARG "); - if(s & ENPHASEMIS) SPRINTF("ENPHASEMIS "); - if(s & ENBUSFREE) SPRINTF("ENBUSFREE "); - if(s & ENSCSIPERR) SPRINTF("ENSCSIPERR "); - if(s & ENPHASECHG) SPRINTF("ENPHASECHG "); - if(s & ENREQINIT) SPRINTF("ENREQINIT "); - SPRINTF(")\n"); - - return (pos-start); + SPRINTF("SSTAT ("); + s = GETPORT(SSTAT0); + if (s & TARGET) + SPRINTF("TARGET "); + if (s & SELDO) + SPRINTF("SELDO "); + if (s & SELDI) + SPRINTF("SELDI "); + if (s & SELINGO) + SPRINTF("SELINGO "); + if (s & SWRAP) + SPRINTF("SWRAP "); + if (s & SDONE) + SPRINTF("SDONE "); + if (s & SPIORDY) + SPRINTF("SPIORDY "); + if (s & DMADONE) + SPRINTF("DMADONE "); + + s = GETPORT(SSTAT1); + if (s & SELTO) + SPRINTF("SELTO "); + if (s & ATNTARG) + SPRINTF("ATNTARG "); + if (s & SCSIRSTI) + SPRINTF("SCSIRSTI "); + if (s & PHASEMIS) + SPRINTF("PHASEMIS "); + if (s & BUSFREE) + SPRINTF("BUSFREE "); + if (s & SCSIPERR) + SPRINTF("SCSIPERR "); + if (s & PHASECHG) + SPRINTF("PHASECHG "); + if (s & REQINIT) + SPRINTF("REQINIT "); + SPRINTF("); "); + + + SPRINTF("SSTAT ("); + + s = GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if (s & TARGET) + SPRINTF("TARGET "); + if (s & SELDO) + SPRINTF("SELDO "); + if (s & SELDI) + SPRINTF("SELDI "); + if (s & SELINGO) + SPRINTF("SELINGO "); + if (s & SWRAP) + SPRINTF("SWRAP "); + if (s & SDONE) + SPRINTF("SDONE "); + if (s & SPIORDY) + SPRINTF("SPIORDY "); + if (s & DMADONE) + SPRINTF("DMADONE "); + + s = GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if (s & SELTO) + SPRINTF("SELTO "); + if (s & ATNTARG) + SPRINTF("ATNTARG "); + if (s & SCSIRSTI) + SPRINTF("SCSIRSTI "); + if (s & PHASEMIS) + SPRINTF("PHASEMIS "); + if (s & BUSFREE) + SPRINTF("BUSFREE "); + if (s & SCSIPERR) + SPRINTF("SCSIPERR "); + if (s & PHASECHG) + SPRINTF("PHASECHG "); + if (s & REQINIT) + SPRINTF("REQINIT "); + SPRINTF("); "); + + SPRINTF("SXFRCTL0 ("); + + s = GETPORT(SXFRCTL0); + if (s & SCSIEN) + SPRINTF("SCSIEN "); + if (s & DMAEN) + SPRINTF("DMAEN "); + if (s & CH1) + SPRINTF("CH1 "); + if (s & CLRSTCNT) + SPRINTF("CLRSTCNT "); + if (s & SPIOEN) + SPRINTF("SPIOEN "); + if (s & CLRCH1) + SPRINTF("CLRCH1 "); + SPRINTF("); "); + + SPRINTF("SIGNAL ("); + + s = GETPORT(SCSISIG); + if (s & ATNI) + SPRINTF("ATNI "); + if (s & SELI) + SPRINTF("SELI "); + if (s & BSYI) + SPRINTF("BSYI "); + if (s & REQI) + SPRINTF("REQI "); + if (s & ACKI) + SPRINTF("ACKI "); + SPRINTF("); "); + + SPRINTF("SELID (%02x), ", GETPORT(SELID)); + + SPRINTF("SSTAT2 ("); + + s = GETPORT(SSTAT2); + if (s & SOFFSET) + SPRINTF("SOFFSET "); + if (s & SEMPTY) + SPRINTF("SEMPTY "); + if (s & SFULL) + SPRINTF("SFULL "); + SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT)); + + s = GETPORT(SSTAT3); + SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); + + SPRINTF("SSTAT4 ("); + s = GETPORT(SSTAT4); + if (s & SYNCERR) + SPRINTF("SYNCERR "); + if (s & FWERR) + SPRINTF("FWERR "); + if (s & FRERR) + SPRINTF("FRERR "); + SPRINTF("); "); + + SPRINTF("DMACNTRL0 ("); + s = GETPORT(DMACNTRL0); + SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); + SPRINTF("%s ", s & DMA ? "DMA" : "PIO"); + SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ"); + if (s & ENDMA) + SPRINTF("ENDMA "); + if (s & INTEN) + SPRINTF("INTEN "); + if (s & RSTFIFO) + SPRINTF("RSTFIFO "); + if (s & SWINT) + SPRINTF("SWINT "); + SPRINTF("); "); + + SPRINTF("DMASTAT ("); + s = GETPORT(DMASTAT); + if (s & ATDONE) + SPRINTF("ATDONE "); + if (s & WORDRDY) + SPRINTF("WORDRDY "); + if (s & DFIFOFULL) + SPRINTF("DFIFOFULL "); + if (s & DFIFOEMP) + SPRINTF("DFIFOEMP "); + SPRINTF(")\n\n"); + + SPRINTF("enabled interrupts ("); + + s = GETPORT(SIMODE0); + if (s & ENSELDO) + SPRINTF("ENSELDO "); + if (s & ENSELDI) + SPRINTF("ENSELDI "); + if (s & ENSELINGO) + SPRINTF("ENSELINGO "); + if (s & ENSWRAP) + SPRINTF("ENSWRAP "); + if (s & ENSDONE) + SPRINTF("ENSDONE "); + if (s & ENSPIORDY) + SPRINTF("ENSPIORDY "); + if (s & ENDMADONE) + SPRINTF("ENDMADONE "); + + s = GETPORT(SIMODE1); + if (s & ENSELTIMO) + SPRINTF("ENSELTIMO "); + if (s & ENATNTARG) + SPRINTF("ENATNTARG "); + if (s & ENPHASEMIS) + SPRINTF("ENPHASEMIS "); + if (s & ENBUSFREE) + SPRINTF("ENBUSFREE "); + if (s & ENSCSIPERR) + SPRINTF("ENSCSIPERR "); + if (s & ENPHASECHG) + SPRINTF("ENPHASECHG "); + if (s & ENREQINIT) + SPRINTF("ENREQINIT "); + SPRINTF(")\n"); + + return (pos - start); } #undef SPRINTF #define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) int aha152x_proc_info(char *buffer, char **start, - off_t offset, int length, int hostno, int inout) + off_t offset, int length, int hostno, int inout) { - int i; - char *pos = buffer; - struct Scsi_Host *shpnt; - unsigned long flags; - Scsi_Cmnd *ptr; - - for(i=0, shpnt= (struct Scsi_Host *) NULL; ihost_no == hostno) - shpnt=aha152x_host[i]; - - if(!shpnt) - return(-ESRCH); - - if(inout) /* Has data been written to the file ? */ - return(aha152x_set_info(buffer, length, shpnt)); - - SPRINTF(AHA152X_REVID "\n"); - - save_flags(flags); - cli(); - - SPRINTF("ioports 0x%04lx to 0x%04lx\n", - shpnt->io_port, shpnt->io_port+shpnt->n_io_port-1); - SPRINTF("interrupt 0x%02x\n", shpnt->irq); - SPRINTF("disconnection/reconnection %s\n", - HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled"); - SPRINTF("parity checking %s\n", - HOSTDATA(shpnt)->parity ? "enabled" : "disabled"); - SPRINTF("synchronous transfers %s\n", - HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled"); - SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); - - if(HOSTDATA(shpnt)->synchronous) { + int i; + char *pos = buffer; + struct Scsi_Host *shpnt; + unsigned long flags; + Scsi_Cmnd *ptr; + + for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++) + if (aha152x_host[i] && aha152x_host[i]->host_no == hostno) + shpnt = aha152x_host[i]; + + if (!shpnt) + return (-ESRCH); + + if (inout) /* Has data been written to the file ? */ + return (aha152x_set_info(buffer, length, shpnt)); + + SPRINTF(AHA152X_REVID "\n"); + + save_flags(flags); + cli(); + + SPRINTF("ioports 0x%04lx to 0x%04lx\n", + shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); + SPRINTF("interrupt 0x%02x\n", shpnt->irq); + SPRINTF("disconnection/reconnection %s\n", + HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled"); + SPRINTF("parity checking %s\n", + HOSTDATA(shpnt)->parity ? "enabled" : "disabled"); + SPRINTF("synchronous transfers %s\n", + HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled"); + SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); + + if (HOSTDATA(shpnt)->synchronous) { #if 0 - SPRINTF("synchronously operating targets (tick=%ld ns):\n", - 250000000/loops_per_sec); - for(i=0; i<8; i++) - if(HOSTDATA(shpnt)->syncrate[i]&0x7f) - SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)* - 250000000/loops_per_sec, - HOSTDATA(shpnt)->syncrate[i]&0x0f); + SPRINTF("synchronously operating targets (tick=%ld ns):\n", + 250000000 / loops_per_sec); + for (i = 0; i < 8; i++) + if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) + SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n", + i, + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * + 250000000 / loops_per_sec, + HOSTDATA(shpnt)->syncrate[i] & 0x0f); #else - SPRINTF("synchronously operating targets (tick=50 ns):\n"); - for(i=0; i<8; i++) - if(HOSTDATA(shpnt)->syncrate[i]&0x7f) - SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*50, - HOSTDATA(shpnt)->syncrate[i]&0x0f); + SPRINTF("synchronously operating targets (tick=50 ns):\n"); + for (i = 0; i < 8; i++) + if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) + SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", + i, + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, + HOSTDATA(shpnt)->syncrate[i] & 0x0f); #endif - } - + } #ifdef DEBUG_AHA152X #define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt); - - SPRINTF("enabled debugging options: "); - - PDEBUG(debug_skipports, "skip ports"); - PDEBUG(debug_queue, "queue"); - PDEBUG(debug_intr, "interrupt"); - PDEBUG(debug_selection, "selection"); - PDEBUG(debug_msgo, "message out"); - PDEBUG(debug_msgi, "message in"); - PDEBUG(debug_status, "status"); - PDEBUG(debug_cmd, "command"); - PDEBUG(debug_datai, "data in"); - PDEBUG(debug_datao, "data out"); - PDEBUG(debug_abort, "abort"); - PDEBUG(debug_done, "done"); - PDEBUG(debug_biosparam, "bios parameters"); - PDEBUG(debug_phases, "phases"); - PDEBUG(debug_queues, "queues"); - PDEBUG(debug_reset, "reset"); - - SPRINTF("\n"); -#endif - - SPRINTF("\nqueue status:\n"); - if(ISSUE_SC) { - SPRINTF("not yet issued commands:\n"); - for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos += get_command(pos, ptr); - } else - SPRINTF("no not yet issued commands\n"); - - if(CURRENT_SC) { - SPRINTF("current command:\n"); - pos += get_command(pos, CURRENT_SC); - } else - SPRINTF("no current command\n"); - - if(DISCONNECTED_SC) { - SPRINTF("disconnected commands:\n"); - for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos += get_command(pos, ptr); - } else - SPRINTF("no disconnected commands\n"); - - restore_flags(flags); - - pos += get_ports(shpnt, pos); - - *start=buffer+offset; - if (pos - buffer < offset) - return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - else - return length; + + SPRINTF("enabled debugging options: "); + + PDEBUG(debug_skipports, "skip ports"); + PDEBUG(debug_queue, "queue"); + PDEBUG(debug_intr, "interrupt"); + PDEBUG(debug_selection, "selection"); + PDEBUG(debug_msgo, "message out"); + PDEBUG(debug_msgi, "message in"); + PDEBUG(debug_status, "status"); + PDEBUG(debug_cmd, "command"); + PDEBUG(debug_datai, "data in"); + PDEBUG(debug_datao, "data out"); + PDEBUG(debug_abort, "abort"); + PDEBUG(debug_done, "done"); + PDEBUG(debug_biosparam, "bios parameters"); + PDEBUG(debug_phases, "phases"); + PDEBUG(debug_queues, "queues"); + PDEBUG(debug_reset, "reset"); + + SPRINTF("\n"); +#endif + + SPRINTF("\nqueue status:\n"); + if (ISSUE_SC) { + SPRINTF("not yet issued commands:\n"); + for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos += get_command(pos, ptr); + } else + SPRINTF("no not yet issued commands\n"); + + if (CURRENT_SC) { + SPRINTF("current command:\n"); + pos += get_command(pos, CURRENT_SC); + } else + SPRINTF("no current command\n"); + + if (DISCONNECTED_SC) { + SPRINTF("disconnected commands:\n"); + for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos += get_command(pos, ptr); + } else + SPRINTF("no disconnected commands\n"); + + restore_flags(flags); + + pos += get_ports(shpnt, pos); + + *start = buffer + offset; + if (pos - buffer < offset) + return 0; + else if (pos - buffer - offset < length) + return pos - buffer - offset; + else + return length; } #ifdef MODULE diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.3.9/linux/drivers/scsi/aic7xxx/aic7xxx.reg Wed Jun 9 16:59:15 1999 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Mon Jul 5 19:56:46 1999 @@ -845,7 +845,7 @@ bit CRCENDCHKEN 0x20 /* CRC End Check Enable */ bit CRCREQCHKEN 0x10 bit TARGCRCENDEN 0x08 /* Enable End CRC transfer when target */ - bit TARGCRCCNTEN 0x40 /* Enable CRC transfer when target */ + bit TARGCRCCNTEN 0x04 /* Enable CRC transfer when target */ } /* diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.3.9/linux/drivers/scsi/aic7xxx.c Wed Jun 9 16:59:15 1999 +++ linux/drivers/scsi/aic7xxx.c Mon Jul 5 19:56:46 1999 @@ -270,7 +270,7 @@ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.17" +#define AIC7XXX_C_VERSION "5.1.18" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -7186,7 +7186,7 @@ static int acquire_seeprom(struct aic7xxx_host *p) { - int wait; + int count=0; /* * Request access of the memory port. When access is @@ -7196,11 +7196,10 @@ * should be no contention. */ aic_outb(p, SEEMS, SEECTL); - wait = 1000; /* 1000 msec = 1 second */ - while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0)) - { - wait--; - mdelay(1); /* 1 msec */ + while( ((aic_inb(p, SEECTL) & SEERDY) == 0) && count < 1000) { + mb(); + udelay(1); + count++; } if ((aic_inb(p, SEECTL) & SEERDY) == 0) { @@ -7412,73 +7411,78 @@ /*+F************************************************************************* * Function: - * write_brdctl + * read_brdctl * * Description: - * Writes a value to the BRDCTL register. + * Reads the BRDCTL register. *-F*************************************************************************/ -static void -write_brdctl(struct aic7xxx_host *p, unsigned char value) +static unsigned char +read_brdctl(struct aic7xxx_host *p) { unsigned char brdctl; if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - brdctl = BRDSTB; + brdctl = BRDRW; if (p->flags & AHC_CHNLB) brdctl |= BRDCS; } else if (p->features & AHC_ULTRA2) - brdctl = 0; - else - brdctl = BRDSTB | BRDCS; - aic_outb(p, brdctl, BRDCTL); - udelay(1); - brdctl |= value; - aic_outb(p, brdctl, BRDCTL); - udelay(1); - if (p->features & AHC_ULTRA2) - brdctl |= BRDSTB_ULTRA2; - else - brdctl &= ~BRDSTB; - aic_outb(p, brdctl, BRDCTL); - udelay(1); - if (p->features & AHC_ULTRA2) - brdctl = 0; + brdctl = BRDRW_ULTRA2; else - brdctl &= ~BRDCS; + brdctl = BRDRW | BRDCS; aic_outb(p, brdctl, BRDCTL); - udelay(1); + udelay(10); + return (aic_inb(p, BRDCTL)); } /*+F************************************************************************* * Function: - * read_brdctl + * write_brdctl * * Description: - * Reads the BRDCTL register. + * Writes a value to the BRDCTL register. *-F*************************************************************************/ -static unsigned char -read_brdctl(struct aic7xxx_host *p) +static void +write_brdctl(struct aic7xxx_host *p, unsigned char value) { - unsigned char brdctl, value; + unsigned char brdctl; if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - brdctl = BRDRW; + brdctl = BRDSTB; if (p->flags & AHC_CHNLB) brdctl |= BRDCS; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + brdctl |= value; } else if (p->features & AHC_ULTRA2) - brdctl = BRDRW_ULTRA2; + { + brdctl = value; + } else - brdctl = BRDRW | BRDCS; + { + brdctl = BRDSTB | BRDCS; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + brdctl |= value; + } aic_outb(p, brdctl, BRDCTL); - udelay(1); - value = aic_inb(p, BRDCTL); - aic_outb(p, 0, BRDCTL); - udelay(1); - return (value); + udelay(4); + if (p->features & AHC_ULTRA2) + brdctl |= BRDSTB_ULTRA2; + else + brdctl &= ~BRDSTB; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + if (p->features & AHC_ULTRA2) + brdctl &= ~BRDSTB_ULTRA2; + else + brdctl &= ~BRDCS; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + read_brdctl(p); } /*+F************************************************************************* @@ -7495,11 +7499,10 @@ unsigned char brdctl; aic_outb(p, BRDRW | BRDCS, BRDCTL); - udelay(1); + udelay(4); aic_outb(p, 0, BRDCTL); - udelay(1); + udelay(4); brdctl = aic_inb(p, BRDCTL); - udelay(1); *int_50 = !(brdctl & BRDDAT5); *ext_present = !(brdctl & BRDDAT6); *eeprom = (aic_inb(p, SPIOCAP) & EEPROM); @@ -7608,6 +7611,7 @@ else max_target = 8; aic_outb(p, SEEMS | SEECS, SEECTL); + udelay(4); sxfrctl1 &= ~STPWEN; if ( (p->adapter_control & CFAUTOTERM) || (p->features & AHC_ULTRA2) ) @@ -7732,25 +7736,33 @@ p->host_no); } - if (enableLVD_low != 0) + if (enableLVD_high != 0) { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_LVD; + brddat |= BRDDAT4; if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n", + printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n", p->host_no); } - if (enableLVD_high != 0) + if (enableLVD_low != 0) { - brddat |= BRDDAT4; + sxfrctl1 |= STPWEN; + p->flags |= AHC_TERM_ENB_LVD; if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n", + printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n", p->host_no); } } else { + if (p->adapter_control & CFWSTERM) + { + brddat |= BRDDAT6; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", + p->host_no); + } + if (p->adapter_control & CFSTERM) { if (p->features & AHC_ULTRA2) @@ -7761,18 +7773,10 @@ printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", p->host_no); } - - if (p->adapter_control & CFWSTERM) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); - } } + aic_outb(p, sxfrctl1, SXFRCTL1); write_brdctl(p, brddat); release_seeprom(p); - aic_outb(p, sxfrctl1, SXFRCTL1); } } @@ -8086,7 +8090,7 @@ /* Select channel B */ aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0; + term = (aic_inb(p, SXFRCTL1) & STPWEN); aic_outb(p, p->scsi_id_b, SCSIID); scsi_conf = aic_inb(p, SCSICONF + 1); aic_outb(p, DFON | SPIOEN, SXFRCTL0); @@ -8100,11 +8104,15 @@ aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); } - term = ((p->flags & AHC_TERM_ENB_SE_LOW) != 0) ? STPWEN : 0; if (p->features & AHC_ULTRA2) + { aic_outb(p, p->scsi_id, SCSIID_ULTRA2); + } else + { aic_outb(p, p->scsi_id, SCSIID); + } + term = (aic_inb(p, SXFRCTL1) & STPWEN); scsi_conf = aic_inb(p, SCSICONF); aic_outb(p, DFON | SPIOEN, SXFRCTL0); aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | @@ -8794,27 +8802,33 @@ } if (p->flags & AHC_NEWEEPROM_FMT) { - if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && - !(p->features & AHC_ULTRA2) ) + if ( !(p->features & AHC_ULTRA2) ) { /* * I know of two different Ultra BIOSes that do this differently. * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to - * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s + * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s * while on the IBM Netfinity 5000 they want the same thing * to be something else, while flags[i] & CFXFER == 0x03 and - * SYNCISULTRA false should be 40MByte/s. So, we set both to + * SYNCHISULTRA false should be 40MByte/s. So, we set both to * 40MByte/s and the lower speeds be damned. People will have * to select around the conversely mapped lower speeds in order * to select lower speeds on these boards. */ - if ((sc->device_flags[i] & (CFXFER)) == 0x03) + if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && + ((sc->device_flags[i] & CFXFER) == 0x03) ) { sc->device_flags[i] &= ~CFXFER; sc->device_flags[i] |= CFSYNCHISULTRA; } + if (sc->device_flags[i] & CFSYNCHISULTRA) + { + p->ultraenb |= mask; + } } - if (sc->device_flags[i] & CFSYNCHISULTRA) + else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) && + (p->features & AHC_ULTRA2) && + (sc->device_flags[i] & CFSYNCHISULTRA) ) { p->ultraenb |= mask; } @@ -9290,6 +9304,10 @@ AHC_AIC7860_FE, 7, 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7860_FE, 7, 32, C46 }, diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h --- v2.3.9/linux/drivers/scsi/aic7xxx_reg.h Wed Jun 9 16:59:15 1999 +++ linux/drivers/scsi/aic7xxx_reg.h Mon Jul 5 19:56:46 1999 @@ -459,11 +459,11 @@ #define CRCCONTROL1 0x9d #define CRCONSEEN 0x80 -#define TARGCRCCNTEN 0x40 #define CRCVALCHKEN 0x40 #define CRCENDCHKEN 0x20 #define CRCREQCHKEN 0x10 #define TARGCRCENDEN 0x08 +#define TARGCRCCNTEN 0x04 #define SCSIPHASE 0x9e #define SP_STATUS 0x20 diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c --- v2.3.9/linux/drivers/scsi/atp870u.c Wed Feb 24 16:27:54 1999 +++ linux/drivers/scsi/atp870u.c Mon Jul 5 19:56:46 1999 @@ -3,7 +3,9 @@ * * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski - * + * + * Marcelo Tosatti : SMP fixes + * */ #include @@ -17,6 +19,7 @@ #include #include #include +#include #include #include #include "scsi.h" @@ -60,6 +63,7 @@ static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; unsigned short int tmpcip,id; unsigned char i,j,h,tarid,lun; unsigned char *prd; @@ -364,7 +368,10 @@ outb(0x80,tmport); } */ go_42: + spin_lock_irqsave(&io_request_lock, flags); (*workrequ->scsi_done)(workrequ); + spin_unlock_irqrestore(&io_request_lock, flags); + curr_req[h][tarid]=0; workingu[h]--; if (wide_idu[h] != 0) diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c --- v2.3.9/linux/drivers/scsi/constants.c Sun Dec 21 17:04:48 1997 +++ linux/drivers/scsi/constants.c Mon Jul 5 19:56:46 1999 @@ -1,6 +1,8 @@ /* * ASCII values for a number of symbolic constants, printing functions, * etc. + * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422) + * */ #define __NO_VERSION__ @@ -37,7 +39,7 @@ /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", +/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", /* 1e-1f */ "Prevent/Allow Medium Removal", unknown, @@ -46,37 +48,57 @@ static const char *group_1_commands[] = { /* 20-22 */ unknown, unknown, unknown, -/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", -/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, +/* 23-28 */ unknown, "Define window parameters", "Read Capacity", + unknown, unknown, "Read (10)", +/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", + "Read updated block", /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", -/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", +/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", + "Read Buffer", /* 3d-3f */ "Update Block", "Read Long", "Write Long", }; static const char *group_2_commands[] = { /* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ unknown, "Read TOC", unknown, unknown, unknown, unknown, unknown, -/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown, +/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", + "Play audio (10)", unknown, "Play audio msf", + "Play audio track/index", +/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", + "Log Select", "Log Sense", unknown, unknown, /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, /* 5c-5f */ unknown, unknown, unknown, }; +/* The following are 12 byte commands in group 5 */ +static const char *group_5_commands[] = { +/* a0-a5 */ unknown, unknown, unknown, unknown, unknown, + "Move medium/play audio(12)", +/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", +/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, + "Write and verify(12)", +/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", +/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown, +/* b5-b6 */ "Request volume element address", "Send volume tag", +/* b7-b9 */ "Read defect data(12)", "Read element status", unknown, +/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown, +}; + + #define group(opcode) (((opcode) >> 5) & 7) #define RESERVED_GROUP 0 #define VENDOR_GROUP 1 -#define NOTEXT_GROUP 2 static const char **commands[] = { group_0_commands, group_1_commands, group_2_commands, (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, - (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, + group_5_commands, (const char **) VENDOR_GROUP, (const char **) VENDOR_GROUP }; @@ -89,9 +111,6 @@ case RESERVED_GROUP: printk("%s(0x%02x) ", reserved, opcode); break; - case NOTEXT_GROUP: - printk("%s(0x%02x) ", unknown, opcode); - break; case VENDOR_GROUP: printk("%s(0x%02x) ", vendor, opcode); break; @@ -119,15 +138,18 @@ #if (CONSTANTS & CONST_STATUS) static const char * statuses[] = { -/* 0-4 */ "Good", "Check Condition", "Condition Good", unknown, "Busy", -/* 5-9 */ unknown, unknown, unknown, "Intermediate Good", unknown, -/* a-d */ "Intermediate Good", unknown, "Reservation Conflict", unknown, -/* e-f */ unknown, unknown, +/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", +/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, +/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict", +/* d-10 */ unknown, unknown, unknown, unknown, +/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full", +/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown, +/* 1b-1f */ unknown, unknown, unknown, unknown, unknown, }; #endif void print_status (int status) { - status = (status >> 1) & 0xf; + status = (status >> 1) & 0x1f; #if (CONSTANTS & CONST_STATUS) printk("%s ",statuses[status]); #else @@ -405,8 +427,10 @@ s = sizeof(SCpnt->sense_buffer); if (!valid) - printk("extra data not valid "); - + printk("[valid=0] "); + printk("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) | + (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | + sense_buffer[6])); if (sense_buffer[2] & 0x80) printk( "FMK "); /* current command has read a filemark */ if (sense_buffer[2] & 0x40) @@ -427,7 +451,7 @@ error = "Invalid"; } - printk("%s error ", error); + printk("%s ", error); #if (CONSTANTS & CONST_SENSE) printk( "%s%s: sense key %s\n", devclass, @@ -603,7 +627,8 @@ #if (CONSTANTS & CONST_HOST) static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", -"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL}; +"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", +"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; void print_hostbyte(int scsiresult) { static int maxcode=0; diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c --- v2.3.9/linux/drivers/scsi/i60uscsi.c Wed Feb 24 16:27:54 1999 +++ linux/drivers/scsi/i60uscsi.c Mon Jul 5 20:36:12 1999 @@ -765,11 +765,11 @@ 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) - continue; + } else if (inia100_adpt[i].ADPT_BASE < wBASE) + continue; } for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) { inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE; diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.3.9/linux/drivers/scsi/ide-scsi.c Thu May 13 23:23:27 1999 +++ linux/drivers/scsi/ide-scsi.c Tue Jul 6 19:08:33 1999 @@ -1,7 +1,7 @@ /* - * linux/drivers/scsi/ide-scsi.c Version 0.6 Jan 27, 1998 + * linux/drivers/scsi/ide-scsi.c Version 0.9 Jul 4, 1999 * - * Copyright (C) 1996 - 1998 Gadi Oxman + * Copyright (C) 1996 - 1999 Gadi Oxman */ /* @@ -25,10 +25,11 @@ * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation. * Ver 0.7 Dec 04 98 Ignore commands where lun != 0 to avoid multiple * detection of devices with CONFIG_SCSI_MULTI_LUN - * Ver 0.8 Feb 05 99 Optical media need translation too. + * Ver 0.8 Feb 05 99 Optical media need translation too. Reverse 0.7. + * Ver 0.9 Jul 04 99 Fix a bug in SG_SET_TRANSFORM. */ -#define IDESCSI_VERSION "0.6" +#define IDESCSI_VERSION "0.9" #include #include @@ -631,9 +632,13 @@ { ide_drive_t *drive = idescsi_drives[dev->id]; idescsi_scsi_t *scsi = drive->driver_data; + int enable = (int) arg; if (cmd == SG_SET_TRANSFORM) { - set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); + if (enable) + set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); + else + clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); return 0; } else if (cmd == SG_GET_TRANSFORM) return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg); diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c --- v2.3.9/linux/drivers/scsi/ini9100u.c Tue Jan 19 11:23:23 1999 +++ linux/drivers/scsi/ini9100u.c Mon Jul 5 20:35:18 1999 @@ -109,19 +109,13 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) #include -#include #include -#include #include -#include -#include #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92) #include #endif #include -#include #include -#include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23) #include #endif @@ -129,39 +123,28 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) #include #endif -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "ini9100u.h" #include -#include #include #else -#include #include #include +#include +#include "../block/blk.h" +#endif + +#include #include #include - #include #include -#include #include -#include "../block/blk.h" #include "scsi.h" #include "sd.h" #include "hosts.h" #include #include "ini9100u.h" -#endif - -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93) -#ifdef CONFIG_PCI -#include -#endif -#endif #ifdef DEBUG_i91u unsigned int i91u_debug = DEBUG_DEFAULT; diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c --- v2.3.9/linux/drivers/scsi/inia100.c Wed Feb 24 16:27:54 1999 +++ linux/drivers/scsi/inia100.c Mon Jul 5 20:35:18 1999 @@ -73,19 +73,13 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) #include -#include #include -#include #include -#include -#include #include -#include #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92) #include #endif #include -#include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23) #include #endif @@ -93,33 +87,27 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) #include #endif -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "inia100.h" #include -#include - #else -#include #include #include +#include +#include "../block/blk.h" +#endif + +#include #include #include - #include #include -#include #include -#include "../block/blk.h" #include "scsi.h" #include "sd.h" #include "hosts.h" #include #include "inia100.h" -#endif #ifdef MODULE Scsi_Host_Template driver_template = INIA100; diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.3.9/linux/drivers/scsi/megaraid.c Tue May 11 15:48:45 1999 +++ linux/drivers/scsi/megaraid.c Mon Jul 5 20:35:18 1999 @@ -129,9 +129,7 @@ #include #include -#include #include -#include /* for kmalloc() */ #if LINUX_VERSION_CODE < 0x20100 #include #else diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/mvme16x.c linux/drivers/scsi/mvme16x.c --- v2.3.9/linux/drivers/scsi/mvme16x.c Thu Jul 30 11:17:11 1998 +++ linux/drivers/scsi/mvme16x.c Mon Jul 5 20:35:18 1999 @@ -18,7 +18,6 @@ #include "hosts.h" #include "53c7xx.h" #include "mvme16x.h" -#include "asm/mvme16xhw.h" #include diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.3.9/linux/drivers/scsi/ncr53c8xx.c Mon Apr 12 09:51:04 1999 +++ linux/drivers/scsi/ncr53c8xx.c Sun Jul 4 09:53:12 1999 @@ -9858,7 +9858,7 @@ } if (!latency_timer) { - latency_timer = 128; + latency_timer = 64; if (initverbose >= 2) printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer); pcibios_write_config_byte(bus, device_fn, diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c --- v2.3.9/linux/drivers/scsi/pas16.c Sat Apr 11 11:13:25 1998 +++ linux/drivers/scsi/pas16.c Mon Jul 5 20:35:18 1999 @@ -577,6 +577,5 @@ /* Eventually this will go into an include file, but this will be later */ Scsi_Host_Template driver_template = MV_PAS16; -#include #include "scsi_module.c" #endif diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.3.9/linux/drivers/scsi/ppa.c Fri May 7 10:57:42 1999 +++ linux/drivers/scsi/ppa.c Thu Jul 1 14:22:57 1999 @@ -158,14 +158,14 @@ */ ppa_hosts[i].mode = PPA_NIBBLE; - if (modes & PARPORT_MODE_PCPS2) + if (modes & PARPORT_MODE_TRISTATE) ppa_hosts[i].mode = PPA_PS2; - if (modes & PARPORT_MODE_PCECPPS2) { + if (modes & PARPORT_MODE_ECP) { w_ecr(ppb, 0x20); ppa_hosts[i].mode = PPA_PS2; } - if (modes & PARPORT_MODE_PCECPEPP) + if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP)) w_ecr(ppb, 0x80); /* Done configuration */ diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.3.9/linux/drivers/scsi/qlogicfc.c Thu Apr 15 05:42:43 1999 +++ linux/drivers/scsi/qlogicfc.c Mon Jul 5 19:58:24 1999 @@ -155,16 +155,16 @@ #endif /* DEBUG ISP2100_INTR */ -#if defined(__i386__) -#define virt_to_bus_low32(x) virt_to_bus(x) -#define virt_to_bus_high32(x) 0x0 -#define bus_to_virt_low32(x) bus_to_virt(x) -#define bus_to_virt_high32(x) 0x0 -#elif defined(__alpha__) +#if BITS_PER_LONG > 32 #define virt_to_bus_low32(x) ((u32) (0xffffffff & virt_to_bus(x))) #define virt_to_bus_high32(x) ((u32) (0xffffffff & (virt_to_bus(x)>>32))) #define bus_to_virt_low32(x) ((u32) (0xffffffff & bus_to_virt(x))) #define bus_to_virt_high32(x) ((u32) (0xffffffff & (bus_to_virt(x)>>32))) +#else +#define virt_to_bus_low32(x) virt_to_bus(x) +#define virt_to_bus_high32(x) 0x0 +#define bus_to_virt_low32(x) bus_to_virt(x) +#define bus_to_virt_high32(x) 0x0 #endif #define ISP2100_REV_ID 1 @@ -228,19 +228,47 @@ }; /* entry header type commands */ +#if BITS_PER_LONG > 32 #define ENTRY_COMMAND 0x19 #define ENTRY_CONTINUATION 0x0a +#else +#define ENTRY_COMMAND 0x11 +#define ENTRY_CONTINUATION 0x02 +#endif #define ENTRY_STATUS 0x03 #define ENTRY_MARKER 0x04 + /* entry header flag definitions */ #define EFLAG_BUSY 2 #define EFLAG_BAD_HEADER 4 #define EFLAG_BAD_PAYLOAD 8 +#if BITS_PER_LONG > 32 +struct dataseg { + u_int d_base; + u_int d_base_hi; + u_int d_count; +}; + +struct Command_Entry { + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short rsvd1; + u_short control_flags; + u_short rsvd2; + u_short time_out; + u_short segment_cnt; + u_char cdb[16]; + u_int total_byte_cnt; + struct dataseg dataseg[DATASEGS_PER_COMMAND]; +}; + +#else struct dataseg { - u_int d_base_lo; - u_int d_base_high; + u_int d_base; u_int d_count; }; @@ -256,9 +284,12 @@ u_short segment_cnt; u_char cdb[16]; u_int total_byte_cnt; - struct dataseg dataseg[2]; + struct dataseg dataseg[DATASEGS_PER_COMMAND]; }; +#endif + + /* command entry control flag definitions */ #define CFLAG_NODISC 0x01 #define CFLAG_HEAD_TAG 0x02 @@ -281,10 +312,18 @@ u_char cdb[44]; }; +#if BITS_PER_LONG > 32 +struct Continuation_Entry { + struct Entry_header hdr; + struct dataseg dataseg[DATASEGS_PER_CONT]; +}; +#else struct Continuation_Entry { struct Entry_header hdr; - struct dataseg dataseg[5]; + u32 rsvd; + struct dataseg dataseg[DATASEGS_PER_CONT]; }; +#endif struct Marker_Entry { struct Entry_header hdr; @@ -549,7 +588,7 @@ u_int response_high; u_short sub_len; u_short res2; - u_short data[22]; + u_char data[44]; }; /* address of instance of this struct is passed to adapter to initialize things @@ -586,9 +625,17 @@ #if ISP2100_FABRIC #define QLOGICFC_MAX_ID 0xff #else -#define QLOGICFC_MAX_ID 0x80 +#define QLOGICFC_MAX_ID 0x7d #endif +#define QLOGICFC_MAX_LOOP_ID 0x7d + +/* adapter_state values */ +#define AS_FIRMWARE_DEAD -1 +#define AS_LOOP_DOWN 0 +#define AS_LOOP_GOOD 1 +#define AS_REDO_PORTDB 2 + struct isp2100_hostdata { u_char revision; struct pci_dev *pci_dev; @@ -602,7 +649,7 @@ char res[RES_QUEUE_LEN + 1][QUEUE_ENTRY_LEN]; char req[QLOGICFC_REQ_QUEUE_LEN + 1][QUEUE_ENTRY_LEN]; struct init_cb control_block; - int loop_up; + int adapter_state; unsigned long int tag_ages[126]; Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1]; unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1]; @@ -611,6 +658,7 @@ u64 wwn; u_int port_id; u_char queued; + u_char host_id; }; @@ -643,7 +691,9 @@ static void isp2100_print_scsi_cmd(Scsi_Cmnd *); #endif +#if DEBUG_ISP2100_INTR static void isp2100_print_status_entry(struct Status_Entry *); +#endif static struct proc_dir_entry proc_scsi_isp2100 = { @@ -693,7 +743,7 @@ hostdata->queued = 0; /* set up the control block */ hostdata->control_block.version = 0x0f; - hostdata->control_block.firm_opts = 0x010c; + hostdata->control_block.firm_opts = 0x0108; hostdata->control_block.max_frame_len = 2048; hostdata->control_block.max_iocb = 256; hostdata->control_block.exec_throttle = 8; @@ -711,8 +761,9 @@ hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req); hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req); - hostdata->loop_up = 0; - + hostdata->adapter_state = AS_LOOP_DOWN; + hostdata->host_id = hosts; + if (isp2100_init(host) || isp2100_reset_hardware(host)) { scsi_unregister(host); continue; @@ -720,15 +771,15 @@ host->this_id = 0; if (request_irq(host->irq, do_isp2100_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { - printk("qlogicfc : interrupt %d already in use\n", - host->irq); + printk("qlogicfc%d : interrupt %d already in use\n", + hostdata->host_id, host->irq); scsi_unregister(host); continue; } if (check_region(host->io_port, 0xff)) { - printk("qlogicfc : i/o region 0x%lx-0x%lx already " + printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " "in use\n", - host->io_port, host->io_port + 0xff); + hostdata->host_id, host->io_port, host->io_port + 0xff); free_irq(host->irq, host); scsi_unregister(host); continue; @@ -739,15 +790,11 @@ outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); isp2100_enable_irqs(host); /* wait for the loop to come up */ - for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->loop_up == 0;) + for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;) barrier(); - if (hostdata->loop_up == 0) { - printk("qlogicfc: loop is not up\n"); - release_region(host->io_port, 0xff); - free_irq(host->irq, host); - scsi_unregister(host); - continue; + if (hostdata->adapter_state == AS_LOOP_DOWN) { + printk("qlogicfc%d : loop is not up\n", hostdata->host_id); } hosts++; } @@ -790,7 +837,7 @@ isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("logout failed %x %x\n", i, param[0]); + printk("qlogicfc%d : logout failed %x %x\n", hostdata->host_id, i, param[0]); } } #endif @@ -807,13 +854,14 @@ temp[0].wwn = hostdata->wwn; } else { - printk("qlogicfc: error getting scsi id.\n"); + printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id); } - for (i = 1, j = 1; i <= QLOGICFC_MAX_ID; i++) { - temp[i].loop_id = temp[0].loop_id; - - param[0] = MBOX_GET_PORT_NAME; + for (i = 0; i <=QLOGICFC_MAX_ID; i++) + temp[i].loop_id = temp[0].loop_id; + + for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) { + param[0] = MBOX_GET_PORT_NAME; param[1] = (i << 8) & 0xff00; isp2100_mbox_command(host, param); @@ -856,7 +904,7 @@ } } if (j == QLOGICFC_MAX_ID + 1) - printk("qlogicfc.c: Too many scsi devices, no more room in port map.\n"); + printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id); if (!hostdata->port_db[j].wwn) { hostdata->port_db[j].loop_id = temp[i].loop_id; hostdata->port_db[j].wwn = temp[i].wwn; @@ -874,14 +922,18 @@ #if ISP2100_FABRIC -int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int j) +#define FABRIC_PORT 0x7e +#define FABRIC_CONTROLLER 0x7f +#define FABRIC_SNS 0x80 + +int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id) { u_short param[8]; u64 wwn; int done = 0; u_short loop_id = 0x81; - u_short scsi_id = j; + u_short scsi_id = cur_scsi_id; u_int port_id; struct sns_cb req; u_char sns_response[608]; @@ -889,18 +941,42 @@ hostdata = (struct isp2100_hostdata *) host->hostdata; - DEBUG_FABRIC(printk("qlogicfc.c: Checking for a fabric.\n")); + DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); param[0] = MBOX_GET_PORT_NAME; - param[1] = 0x7E00; + param[1] = (u16)FABRIC_PORT << 8; isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("fabric check result %x\n", param[0])); + DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0])); return 0; } - printk("qlogicfc.c: Fabric found.\n"); + printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); + + memset(&req, 0, sizeof(req)); + + req.len = 8; + req.response_low = virt_to_bus_low32(sns_response); + req.response_high = virt_to_bus_high32(sns_response); + req.sub_len = 22; + req.data[0] = 0x17; + req.data[1] = 0x02; + req.data[8] = (u_char) (hostdata->port_id & 0xff); + req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); + req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); + req.data[13] = 0x01; + param[0] = MBOX_SEND_SNS; + param[1] = 30; + param[2] = virt_to_bus_low32(&req) >> 16; + param[3] = virt_to_bus_low32(&req); + param[6] = virt_to_bus_high32(&req) >> 16; + param[7] = virt_to_bus_high32(&req); + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) + printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); port_id = hostdata->port_id; while (!done) { @@ -910,9 +986,11 @@ req.response_low = virt_to_bus_low32(sns_response); req.response_high = virt_to_bus_high32(sns_response); req.sub_len = 6; - req.data[0] = 0x0100; - req.data[4] = (u_short) (port_id & 0xffff); - req.data[5] = (u_short) (port_id >> 16 & 0xffff); + req.data[0] = 0x00; + req.data[1] = 0x01; + req.data[8] = (u_char) (port_id & 0xff); + req.data[9] = (u_char) (port_id >> 8 & 0xff); + req.data[10] = (u_char) (port_id >> 16 & 0xff); param[0] = MBOX_SEND_SNS; param[1] = 14; @@ -924,7 +1002,7 @@ isp2100_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("found node %02x%02x%02x%02x%02x%02x%02x%02x ", sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); + DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); DEBUG_FABRIC(printk(" port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19])); port_id = ((u_int) sns_response[17]) << 16; port_id |= ((u_int) sns_response[18]) << 8; @@ -938,7 +1016,7 @@ wwn |= ((u64) sns_response[26]) << 8; wwn |= ((u64) sns_response[27]); if (hostdata->port_id >> 8 != port_id >> 8) { - DEBUG_FABRIC(printk("adding a fabric port: %x\n", port_id)); + DEBUG_FABRIC(printk("qlogicfc%d : adding a fabric port: %x\n", hostdata->host_id, port_id)); param[0] = MBOX_PORT_LOGIN; param[1] = loop_id << 8; param[2] = (u_short) (port_id >> 16); @@ -952,15 +1030,15 @@ loop_id++; scsi_id++; } else { - printk("qlogicfc.c: Error performing port login %x\n", param[0]); - DEBUG_FABRIC(printk("loop_id: %x\n", loop_id)); + printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]); + DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id)); } } if (hostdata->port_id == port_id) done = 1; } else { - printk("qlogicfc.c: Get All Next failed %x.\n", param[0]); + printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); return 0; } } @@ -1034,15 +1112,16 @@ DEBUG(isp2100_print_scsi_cmd(Cmnd)); - if (hostdata->loop_up == 2) { - hostdata->loop_up = 1; + if (hostdata->adapter_state == AS_REDO_PORTDB) { + hostdata->adapter_state = AS_LOOP_GOOD; isp2100_make_portdb(host); + printk("qlogicfc%d : Port Database\n", hostdata->host_id); for (i = 0; hostdata->port_db[i].wwn != 0; i++) { - DEBUG(printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id)); + printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id); } } - if (hostdata->loop_up == -1) { - printk("qlogicfc.c: The firmware is dead, just return.\n"); + if (hostdata->adapter_state == AS_FIRMWARE_DEAD) { + printk("qlogicfc%d : The firmware is dead, just return.\n", hostdata->host_id); host->max_id = 0; return 0; } @@ -1050,13 +1129,13 @@ out_ptr = inw(host->io_port + MBOX4); in_ptr = hostdata->req_in_ptr; - DEBUG(printk("qlogicfc : request queue depth %d\n", + DEBUG(printk("qlogicfc%d : request queue depth %d\n", hostdata->host_id, REQ_QUEUE_DEPTH(in_ptr, out_ptr))); cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { - DEBUG(printk("qlogicfc : request queue overflow\n")); + DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id)); return 1; } if (hostdata->send_marker) { @@ -1064,7 +1143,7 @@ TRACE("queue marker", in_ptr, 0); - DEBUG(printk("qlogicfc : adding marker entry\n")); + DEBUG(printk("qlogicfc%d : adding marker entry\n", hostdata->host_id)); marker = (struct Marker_Entry *) cmd; memset(marker, 0, sizeof(struct Marker_Entry)); @@ -1077,7 +1156,7 @@ if (((in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN) == out_ptr) { outw(in_ptr, host->io_port + MBOX4); hostdata->req_in_ptr = in_ptr; - DEBUG(printk("qlogicfc : request queue overflow\n")); + DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id)); return 1; } cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; @@ -1094,8 +1173,15 @@ cmd->handle = i; hostdata->handle_ptrs[i] = Cmnd; hostdata->handle_serials[i] = Cmnd->serial_number; - } else - printk("qlogicfc: no handle slots, this should not happen.\n"); + } else { + printk("qlogicfc%d : no handle slots, this should not happen.\n", hostdata->host_id); + printk("hostdata->queued is %x, in_ptr: %x\n", hostdata->queued, in_ptr); + for (i = 0; i <= QLOGICFC_REQ_QUEUE_LEN; i++){ + if (!hostdata->handle_ptrs[i]){ + printk("slot %d has %p\n", i, hostdata->handle_ptrs[i]); + } + } + } cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; @@ -1106,7 +1192,7 @@ cmd->target_id = Cmnd->target; #endif cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen; - cmd->time_out = (SCSI_TIMEOUT / HZ) * 5; + cmd->time_out = 0; memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { @@ -1115,15 +1201,18 @@ ds = cmd->dataseg; /* fill in first two sg entries: */ n = sg_count; - if (n > 2) - n = 2; + if (n > DATASEGS_PER_COMMAND) + n = DATASEGS_PER_COMMAND; + for (i = 0; i < n; i++) { - ds[i].d_base_lo = virt_to_bus_low32(sg->address); - ds[i].d_base_high = virt_to_bus_high32(sg->address); + ds[i].d_base = virt_to_bus_low32(sg->address); +#if BITS_PER_LONG > 32 + ds[i].d_base_hi = virt_to_bus_high32(sg->address); +#endif ds[i].d_count = sg->length; ++sg; } - sg_count -= 2; + sg_count -= DATASEGS_PER_COMMAND; while (sg_count > 0) { ++cmd->hdr.entry_cnt; @@ -1132,28 +1221,31 @@ memset(cont, 0, sizeof(struct Continuation_Entry)); in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { - DEBUG(printk("isp2100: unexpected request queue overflow\n")); + DEBUG(printk("qlogicfc%d : unexpected request queue overflow\n", hostdata->host_id)); return 1; } TRACE("queue continuation", in_ptr, 0); cont->hdr.entry_type = ENTRY_CONTINUATION; ds = cont->dataseg; n = sg_count; - if (n > 5) - n = 5; + if (n > DATASEGS_PER_CONT) + n = DATASEGS_PER_CONT; for (i = 0; i < n; ++i) { - ds[i].d_base_lo = virt_to_bus_low32(sg->address); - ds[i].d_base_high = virt_to_bus_high32(sg->address); + ds[i].d_base = virt_to_bus_low32(sg->address); +#if BITS_PER_LONG > 32 + ds[i].d_base_hi = virt_to_bus_high32(sg->address); +#endif ds[i].d_count = sg->length; ++sg; } sg_count -= n; } } else { - cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->request_buffer); - cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->request_buffer); - cmd->dataseg[0].d_count = - (u_int) Cmnd->request_bufflen; + cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer); +#if BITS_PER_LONG > 32 + cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); +#endif + cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen; cmd->segment_cnt = 1; } @@ -1161,12 +1253,15 @@ case WRITE_10: case WRITE_6: case WRITE_BUFFER: + case MODE_SELECT: cmd->control_flags = CFLAG_WRITE; break; case REQUEST_SENSE: /* scsi.c expects sense info in a different buffer */ - cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->sense_buffer); - cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->sense_buffer); + cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer); +#if BITS_PER_LONG > 32 + cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); +#endif cmd->segment_cnt = 1; cmd->control_flags = CFLAG_READ; break; @@ -1197,6 +1292,7 @@ hostdata->req_in_ptr = in_ptr; hostdata->queued++; + num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); num_free = (num_free > 2) ? num_free - 2 : 0; host->can_queue = hostdata->queued + num_free; @@ -1207,7 +1303,7 @@ /* this is really gross */ if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) - DEBUG(printk("qlogicfc.c crosses its fingers.\n")); + DEBUG(printk("qlogicfc%d.c crosses its fingers.\n", hostdata->host_id)); host->can_queue = host->host_busy + 1; } @@ -1242,11 +1338,11 @@ hostdata = (struct isp2100_hostdata *) host->hostdata; - DEBUG_INTR(printk("qlogicfc : interrupt on line %d\n", irq)); + DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq)); if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) { /* spurious interrupts can happen legally */ - DEBUG_INTR(printk("qlogicfc: got spurious interrupt\n")); + DEBUG_INTR(printk("qlogicfc%d : got spurious interrupt\n", hostdata->host_id)); return; } in_ptr = inw(host->io_port + MBOX5); @@ -1255,26 +1351,28 @@ if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { status = inw(host->io_port + MBOX0); - DEBUG_INTR(printk("qlogicfc : mbox completion status: %x\n", - status)); + DEBUG_INTR(printk("qlogicfc%d : mbox completion status: %x\n", + hostdata->host_id, status)); switch (status) { case LOOP_UP: - hostdata->loop_up = 2; + printk("qlogicfc%d : loop is up\n", hostdata->host_id); + hostdata->adapter_state = AS_REDO_PORTDB; break; case LOOP_DOWN: - hostdata->loop_up = 0; + printk("qlogicfc%d : loop is down\n", hostdata->host_id); + hostdata->adapter_state = AS_LOOP_DOWN; break; case LIP_OCCURED: case CHANGE_NOTIFICATION: case PORT_DB_CHANGED: case LIP_RECEIVED: - if (hostdata->loop_up == 1) - hostdata->loop_up = 2; + if (hostdata->adapter_state == AS_LOOP_GOOD) + hostdata->adapter_state = AS_REDO_PORTDB; break; case SYSTEM_ERROR: - printk("The firmware just choked.\n"); - hostdata->loop_up = -1; + printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id); + hostdata->adapter_state = AS_FIRMWARE_DEAD; break; case SCSI_COMMAND_COMPLETE: handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16); @@ -1286,7 +1384,7 @@ Cmnd->result = 0x0; (*Cmnd->scsi_done) (Cmnd); } else - printk("qlogicfc.c: got a null value out of handle_ptrs, this sucks\n"); + printk("qlogicfc%d.c : got a null value out of handle_ptrs, this sucks\n", hostdata->host_id); break; case MBOX_COMMAND_COMPLETE: case INVALID_COMMAND: @@ -1301,12 +1399,12 @@ outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); return; default: - printk("qlogicfc: got an unknown status? %x\n", status); + printk("qlogicfc%d : got an unknown status? %x\n", hostdata->host_id, status); } outw(0x0, host->io_port + PCI_SEMAPHORE); } else { - DEBUG_INTR(printk("qlogicfc : response queue update\n")); - DEBUG_INTR(printk("qlogicfc : response queue depth %d\n", RES_QUEUE_DEPTH(in_ptr, out_ptr))); + DEBUG_INTR(printk("qlogicfc%d : response queue update\n", hostdata->host_id)); + DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr))); while (out_ptr != in_ptr) { sts = (struct Status_Entry *) &hostdata->res[out_ptr][0]; @@ -1314,24 +1412,41 @@ TRACE("done", out_ptr, Cmnd); DEBUG_INTR(isp2100_print_status_entry(sts)); - if (sts->hdr.entry_type == ENTRY_STATUS) { - Cmnd = hostdata->handle_ptrs[sts->handle]; + if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) { Cmnd->result = isp2100_return_status(sts); hostdata->handle_ptrs[sts->handle] = NULL; hostdata->queued--; - if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number) { + + /* + * if any of the following are true we do not + * call scsi_done. if the status is CS_ABORTED + * we dont have to call done because the upper + * level should already know its aborted. + */ + if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number + || sts->completion_status == CS_ABORTED){ hostdata->handle_serials[sts->handle] = 0; outw(out_ptr, host->io_port + MBOX5); continue; } - hostdata->handle_serials[sts->handle] = 0; + /* + * if we get back an error indicating the port + * is not there or if the loop is down and + * this is a device that used to be there + * allow the command to timeout. + * the device may well be back in a couple of + * seconds. + */ + if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){ + outw(out_ptr, host->io_port + MBOX5); + continue; + } } else { outw(out_ptr, host->io_port + MBOX5); continue; } if (sts->completion_status == CS_RESET_OCCURRED - || sts->completion_status == CS_ABORTED || (sts->status_flags & STF_BUS_RESET)) hostdata->send_marker = 1; @@ -1345,7 +1460,7 @@ if (Cmnd->scsi_done != NULL) { (*Cmnd->scsi_done) (Cmnd); } else - printk("Ouch, scsi done is NULL\n"); + printk("qlogicfc%d : Ouch, scsi done is NULL\n", hostdata->host_id); } hostdata->res_out_ptr = out_ptr; } @@ -1363,7 +1478,7 @@ if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) - DEBUG(printk("qlogicfc crosses its fingers.\n")); + DEBUG(printk("qlogicfc%d : crosses its fingers.\n", hostdata->host_id)); host->can_queue = host->host_busy + 1; } @@ -1448,7 +1563,7 @@ int i; struct Scsi_Host *host; struct isp2100_hostdata *hostdata; - int return_status = SCSI_ABORT_SUCCESS; + int return_status = SUCCESS; ENTER("isp2100_abort"); @@ -1459,27 +1574,39 @@ if (hostdata->handle_ptrs[i] == Cmnd) break; - if (i == QLOGICFC_REQ_QUEUE_LEN) - return SCSI_ABORT_ERROR; + if (i == QLOGICFC_REQ_QUEUE_LEN){ + return SUCCESS; + } isp2100_disable_irqs(host); param[0] = MBOX_ABORT_IOCB; +#if ISP2100_PORTDB + param[1] = (((u_short) hostdata->port_db[Cmnd->target].loop_id) << 8) | Cmnd->lun; +#else param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; - param[2] = i >> 16; - param[3] = i & 0xffff; +#endif + param[2] = i & 0xffff; + param[3] = i >> 16; isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : scsi abort failure: %x\n", param[0]); + printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]); if (param[0] == 0x4005) Cmnd->result = DID_ERROR << 16; if (param[0] == 0x4006) Cmnd->result = DID_BAD_TARGET << 16; - (*Cmnd->scsi_done) (Cmnd); - return_status = SCSI_ABORT_ERROR; + return_status = FAILED; } + + if (return_status != SUCCESS){ + param[0] = MBOX_GET_FIRMWARE_STATE; + isp2100_mbox_command(host, param); + printk("qlogicfc%d : abort failed\n", hostdata->host_id); + printk("qlogicfc%d : firmware status is %x %x\n", hostdata->host_id, param[0], param[1]); + } + isp2100_enable_irqs(host); LEAVE("isp2100_abort"); @@ -1507,7 +1634,7 @@ isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : scsi bus reset failure: %x\n", param[0]); + printk("qlogicfc%d : scsi bus reset failure: %x\n", hostdata->host_id, param[0]); return_status = SCSI_RESET_ERROR; } isp2100_enable_irqs(host); @@ -1546,6 +1673,8 @@ ENTER("isp2100_reset_hardware"); + hostdata = (struct isp2100_hostdata *) host->hostdata; + outw(0x01, host->io_port + ISP_CTRL_STATUS); outw(HCCR_RESET, host->io_port + HOST_HCCR); outw(HCCR_RELEASE, host->io_port + HOST_HCCR); @@ -1555,22 +1684,22 @@ while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) barrier(); if (!loop_count) - printk("qlogicfc: reset_hardware loop timeout\n"); + printk("qlogicfc%d : reset_hardware loop timeout\n", hostdata->host_id); #if DEBUG_ISP2100 - printk("qlogicfc : mbox 0 0x%04x \n", inw(host->io_port + MBOX0)); - printk("qlogicfc : mbox 1 0x%04x \n", inw(host->io_port + MBOX1)); - printk("qlogicfc : mbox 2 0x%04x \n", inw(host->io_port + MBOX2)); - printk("qlogicfc : mbox 3 0x%04x \n", inw(host->io_port + MBOX3)); - printk("qlogicfc : mbox 4 0x%04x \n", inw(host->io_port + MBOX4)); - printk("qlogicfc : mbox 5 0x%04x \n", inw(host->io_port + MBOX5)); - printk("qlogicfc : mbox 6 0x%04x \n", inw(host->io_port + MBOX6)); - printk("qlogicfc : mbox 7 0x%04x \n", inw(host->io_port + MBOX7)); + printk("qlogicfc%d : mbox 0 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX0)); + printk("qlogicfc%d : mbox 1 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX1)); + printk("qlogicfc%d : mbox 2 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX2)); + printk("qlogicfc%d : mbox 3 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX3)); + printk("qlogicfc%d : mbox 4 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX4)); + printk("qlogicfc%d : mbox 5 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX5)); + printk("qlogicfc%d : mbox 6 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX6)); + printk("qlogicfc%d : mbox 7 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX7)); #endif /* DEBUG_ISP2100 */ - DEBUG(printk("qlogicfc : verifying checksum\n")); + DEBUG(printk("qlogicfc%d : verifying checksum\n", hostdata->host_id)); #if RELOAD_FIRMWARE { @@ -1583,7 +1712,7 @@ isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : firmware load failure\n"); + printk("qlogicfc%d : firmware load failure\n", hostdata->host_id); return 1; } } @@ -1596,10 +1725,10 @@ isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : ram checksum failure\n"); + printk("qlogicfc%d : ram checksum failure\n", hostdata->host_id); return 1; } - DEBUG(printk("qlogicfc : executing firmware\n")); + DEBUG(printk("qlogicfc%d : executing firmware\n", hostdata->host_id)); param[0] = MBOX_EXEC_FIRMWARE; param[1] = risc_code_addr01; @@ -1611,18 +1740,16 @@ isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : about firmware failure\n"); + printk("qlogicfc%d : about firmware failure\n", hostdata->host_id); return 1; } - DEBUG(printk("qlogicfc : firmware major revision %d\n", param[1])); - DEBUG(printk("qlogicfc : firmware minor revision %d\n", param[2])); - - hostdata = (struct isp2100_hostdata *) host->hostdata; + DEBUG(printk("qlogicfc%d : firmware major revision %d\n", hostdata->host_id, param[1])); + DEBUG(printk("qlogicfc%d : firmware minor revision %d\n", hostdata->host_id, param[2])); #ifdef USE_NVRAM_DEFAULTS if (isp2100_get_nvram_defaults(host, &hostdata->control_block) != 0) { - printk("qlogicfc: Could not read from NVRAM\n"); + printk("qlogicfc%d : Could not read from NVRAM\n", hostdata->host_id); } #endif @@ -1644,13 +1771,13 @@ param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff); isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc.c: Ouch 0x%04x\n", param[0]); + printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); return 1; } param[0] = MBOX_GET_FIRMWARE_STATE; isp2100_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc.c: 0x%04x\n", param[0]); + printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); return 1; } @@ -1698,7 +1825,7 @@ if (pci_read_config_word(pdev, PCI_COMMAND, &command) || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) { - printk("qlogicfc : error reading PCI configuration\n"); + printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id); return 1; } io_base = pdev->base_address[0]; @@ -1707,28 +1834,28 @@ if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { - printk("qlogicfc : 0x%04x is not QLogic vendor ID\n", + printk("qlogicfc%d : 0x%04x is not QLogic vendor ID\n", hostdata->host_id, pdev->vendor); return 1; } if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100) { - printk("qlogicfc : 0x%04x does not match ISP2100 device id\n", + printk("qlogicfc%d : 0x%04x does not match ISP2100 device id\n", hostdata->host_id, pdev->device); return 1; } if (command & PCI_COMMAND_IO && (io_base & 3) == 1) io_base &= PCI_BASE_ADDRESS_IO_MASK; else { - printk("qlogicfc : i/o mapping is disabled\n"); + printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id); return 1; } if (!(command & PCI_COMMAND_MASTER)) { - printk("qlogicfc : bus mastering is disabled\n"); + printk("qlogicfc%d : bus mastering is disabled\n", hostdata->host_id); return 1; } if (revision != ISP2100_REV_ID && revision != ISP2100_REV_ID3) - printk("qlogicfc : new isp2100 revision ID (%d)\n", revision); + printk("qlogicfc%d : new isp2100 revision ID (%d)\n", hostdata->host_id, revision); hostdata->revision = revision; @@ -1800,21 +1927,22 @@ int loop_count; struct isp2100_hostdata *hostdata = (struct isp2100_hostdata *) host->hostdata; - if (mbox_param[param[0]] == 0) + if (mbox_param[param[0]] == 0 || hostdata->adapter_state == AS_FIRMWARE_DEAD) return 1; loop_count = DEFAULT_LOOP_COUNT; while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080) barrier(); if (!loop_count) { - printk("qlogicfc: mbox_command loop timeout #1\n"); + printk("qlogicfc%d : mbox_command loop timeout #1\n", hostdata->host_id); param[0] = 0x4006; + hostdata->adapter_state = AS_FIRMWARE_DEAD; return 1; } hostdata->mbox_done = 0; if (mbox_param[param[0]] == 0) - printk("qlogicfc: invalid mbox command\n"); + printk("qlogicfc%d : invalid mbox command\n", hostdata->host_id); if (mbox_param[param[0]] & 0x80) outw(param[7], host->io_port + MBOX7); @@ -1843,7 +1971,8 @@ } if (!loop_count) { - printk("qlogicfc: mbox_command loop timeout #2\n"); + hostdata->adapter_state = AS_FIRMWARE_DEAD; + printk("qlogicfc%d : mbox_command loop timeout #2\n", hostdata->host_id); break; } isp2100_intr_handler(host->irq, host, NULL); @@ -1858,7 +1987,7 @@ barrier(); } if (!loop_count) - printk("qlogicfc: mbox_command loop timeout #3\n"); + printk("qlogicfc%d : mbox_command loop timeout #3\n", hostdata->host_id); param[7] = inw(host->io_port + MBOX7); param[6] = inw(host->io_port + MBOX6); @@ -1873,19 +2002,21 @@ outw(0x0, host->io_port + PCI_SEMAPHORE); if (inw(host->io_port + HOST_HCCR) & 0x0080) { - printk("mbox op is still pending\n"); + hostdata->adapter_state = AS_FIRMWARE_DEAD; + printk("qlogicfc%d : mbox op is still pending\n", hostdata->host_id); } return 0; } +#if DEBUG_ISP2100_INTR void isp2100_print_status_entry(struct Status_Entry *status) { - printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", + printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n", status->scsi_status, status->completion_status); - printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", + printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", status->state_flags, status->status_flags); printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n", status->res_info_len, status->req_sense_len); @@ -1893,6 +2024,7 @@ } +#endif /* DEBUG_ISP2100_INTR */ #if DEBUG_ISP2100 @@ -1901,7 +2033,7 @@ { int i; - printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", cmd->target, cmd->lun, cmd->cmd_len); printk("qlogicfc : command = "); for (i = 0; i < cmd->cmd_len; i++) diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h --- v2.3.9/linux/drivers/scsi/qlogicfc.h Wed Feb 24 16:27:54 1999 +++ linux/drivers/scsi/qlogicfc.h Mon Jul 5 19:58:24 1999 @@ -61,8 +61,17 @@ * requests are queued serially and the scatter/gather limit is * determined for each queue request anew. */ -#define QLOGICFC_REQ_QUEUE_LEN 63 /* must be power of two - 1 */ -#define QLOGICFC_MAX_SG(ql) (2 + (((ql) > 0) ? 5*((ql) - 1) : 0)) + +#if BITS_PER_LONG > 32 +#define DATASEGS_PER_COMMAND 2 +#define DATASEGS_PER_CONT 5 +#else +#define DATASEGS_PER_COMMAND 3 +#define DATASEGS_PER_CONT 7 +#endif + +#define QLOGICFC_REQ_QUEUE_LEN 127 /* must be power of two - 1 */ +#define QLOGICFC_MAX_SG(ql) (DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0)) #define QLOGICFC_CMD_PER_LUN 8 int isp2100_detect(Scsi_Host_Template *); @@ -84,16 +93,16 @@ release: isp2100_release, \ info: isp2100_info, \ queuecommand: isp2100_queuecommand, \ - abort: isp2100_abort, \ + eh_abort_handler: isp2100_abort, \ reset: isp2100_reset, \ bios_param: isp2100_biosparam, \ can_queue: QLOGICFC_REQ_QUEUE_LEN, \ this_id: -1, \ sg_tablesize: QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN), \ - cmd_per_lun: QLOGICFC_CMD_PER_LUN, \ + cmd_per_lun: QLOGICFC_CMD_PER_LUN, \ present: 0, \ unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING \ + use_clustering: ENABLE_CLUSTERING \ } #endif /* _QLOGICFC_H */ diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.3.9/linux/drivers/scsi/qlogicisp.c Thu Apr 22 19:30:08 1999 +++ linux/drivers/scsi/qlogicisp.c Mon Jul 5 19:58:24 1999 @@ -1065,8 +1065,10 @@ ip[0] = 255; ip[1] = 63; ip[2] = size / (ip[0] * ip[1]); +#if 0 if (ip[2] > 1023) ip[2] = 1023; +#endif } LEAVE("isp1020_biosparam"); diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v2.3.9/linux/drivers/scsi/scsi_debug.c Sat Jan 2 10:23:01 1999 +++ linux/drivers/scsi/scsi_debug.c Mon Jul 5 20:35:18 1999 @@ -22,10 +22,6 @@ #include #include -#ifdef MODULE -#include -#endif - #include #include "scsi.h" #include "hosts.h" diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.3.9/linux/drivers/scsi/sd.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/scsi/sd.c Tue Jul 6 19:08:33 1999 @@ -1050,6 +1050,7 @@ SCpnt->transfersize = rscsi_disks[dev].sector_size; SCpnt->underflow = this_count << 9; + SCpnt->cmd_len = 0; scsi_do_cmd (SCpnt, (void *) cmd, buff, this_count * rscsi_disks[dev].sector_size, rw_intr, diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.9/linux/drivers/scsi/st.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/scsi/st.c Sat Jul 3 10:42:38 1999 @@ -890,7 +890,7 @@ kdev_t devt = inode->i_rdev; int dev; - if (atomic_read(&filp->f_count) > 1) + if (file_count(filp) > 1) return 0; dev = TAPE_NR(devt); diff -u --recursive --new-file v2.3.9/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c --- v2.3.9/linux/drivers/scsi/sym53c416.c Wed Feb 24 16:28:43 1999 +++ linux/drivers/scsi/sym53c416.c Mon Jul 5 20:35:18 1999 @@ -3,6 +3,10 @@ * Low-level SCSI driver for sym53c416 chip. * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) * + * Changes : + * + * Marcelo Tosatti : Added io_request_lock locking + * * LILO command line usage: sym53c416=[,] * * This program is free software; you can redistribute it and/or modify it @@ -25,11 +29,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include "scsi.h" @@ -371,7 +375,9 @@ printk("sym53c416: Warning: Reset received\n"); current_command->SCp.phase = idle; current_command->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(int_reg & ILCMD) /* Illegal Command */ @@ -379,7 +385,9 @@ printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG)); current_command->SCp.phase = idle; current_command->result = DID_ERROR << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(status_reg & GE) /* Gross Error */ @@ -387,7 +395,9 @@ printk("sym53c416: Warning: Gross Error\n"); current_command->SCp.phase = idle; current_command->result = DID_ERROR << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(status_reg & PE) /* Parity Error */ @@ -395,7 +405,9 @@ printk("sym53c416: Warning: Parity Error\n"); current_command->SCp.phase = idle; current_command->result = DID_PARITY << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(pio_int_reg & (CE | OUE)) @@ -403,7 +415,9 @@ printk("sym53c416: Warning: PIO Interrupt Error\n"); current_command->SCp.phase = idle; current_command->result = DID_ERROR << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(int_reg & DIS) /* Disconnect */ @@ -413,7 +427,10 @@ else current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16); current_command->SCp.phase = idle; + + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } /* Now we handle SCSI phases */ diff -u --recursive --new-file v2.3.9/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c --- v2.3.9/linux/drivers/sgi/char/graphics.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/sgi/char/graphics.c Fri Jul 2 15:15:51 1999 @@ -262,8 +262,7 @@ NULL, /* no special mmap-advise */ sgi_graphics_nopage, /* our magic no-page fault handler */ NULL, /* no special mmap-wppage */ - NULL, /* no special mmap-swapout */ - NULL /* no special mmap-swapin */ + NULL /* no special mmap-swapout */ }; int diff -u --recursive --new-file v2.3.9/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c --- v2.3.9/linux/drivers/sgi/char/shmiq.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/sgi/char/shmiq.c Fri Jul 2 15:15:51 1999 @@ -302,8 +302,7 @@ NULL, /* no special mmap-advise */ shmiq_nopage, /* our magic no-page fault handler */ NULL, /* no special mmap-wppage */ - NULL, /* no special mmap-swapout */ - NULL /* no special mmap-swapin */ + NULL /* no special mmap-swapout */ }; static int diff -u --recursive --new-file v2.3.9/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c --- v2.3.9/linux/drivers/sgi/char/usema.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/sgi/char/usema.c Mon Jul 5 19:44:57 1999 @@ -53,8 +53,8 @@ if (newfd < 0) return newfd; - current->files->fd [newfd] = usema->filp; - atomic_inc(&usema->filp->f_count); + get_file(usema->filp); + fd_install(newfd, usema->filp); /* Is that it? */ printk("UIOCATTACHSEMA: new usema fd is %d", newfd); return newfd; diff -u --recursive --new-file v2.3.9/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.3.9/linux/drivers/sound/cmpci.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/sound/cmpci.c Mon Jul 5 19:58:24 1999 @@ -2311,9 +2311,7 @@ index++; continue; - err_dev4: unregister_sound_midi(s->dev_midi); - err_dev3: unregister_sound_mixer(s->dev_mixer); err_dev2: unregister_sound_dsp(s->dev_audio); @@ -2328,7 +2326,6 @@ #ifdef CONFIG_SOUND_CMPCI_MIDI release_region(s->iomidi, CM_EXTENT_MIDI); #endif - err_region4: release_region(s->iobase, CM_EXTENT_CODEC); err_region5: kfree_s(s, sizeof(struct cm_state)); diff -u --recursive --new-file v2.3.9/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.3.9/linux/drivers/sound/dev_table.h Thu May 13 23:22:48 1999 +++ linux/drivers/sound/dev_table.h Mon Jul 5 19:58:24 1999 @@ -25,30 +25,18 @@ #define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ #define SNDCARD_VIDC 28 /* ARMs VIDC */ #define SNDCARD_SBPNP 29 -#define SNDCARD_OPL3SA1 38 -#define SNDCARD_OPL3SA1_SB 39 -#define SNDCARD_OPL3SA1_MPU 40 #define SNDCARD_SOFTOSS 36 #define SNDCARD_VMIDI 37 +#define SNDCARD_OPL3SA1 38 /* Note: clash in msnd.h */ +#define SNDCARD_OPL3SA1_SB 39 +#define SNDCARD_OPL3SA1_MPU 40 #define SNDCARD_WAVEFRONT 41 #define SNDCARD_OPL3SA2 42 #define SNDCARD_OPL3SA2_MPU 43 #define SNDCARD_WAVEARTIST 44 +#define SNDCARD_OPL3SA2_MSS 45 /* Originally missed */ #define SNDCARD_AD1816 88 -void attach_opl3sa_wss (struct address_info *hw_config); -int probe_opl3sa_wss (struct address_info *hw_config); -void attach_opl3sa_sb (struct address_info *hw_config); -int probe_opl3sa_sb (struct address_info *hw_config); -void attach_opl3sa_mpu (struct address_info *hw_config); -int probe_opl3sa_mpu (struct address_info *hw_config); -void unload_opl3sa_wss(struct address_info *hw_info); -void unload_opl3sa_sb(struct address_info *hw_info); -void unload_opl3sa_mpu(struct address_info *hw_info); -void attach_softsyn_card (struct address_info *hw_config); -int probe_softsyn (struct address_info *hw_config); -void unload_softsyn (struct address_info *hw_config); - /* * NOTE! NOTE! NOTE! NOTE! * @@ -424,6 +412,7 @@ #ifdef CONFIG_SOUND_OPL3SA2 {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2}, + {"OPL3SA2MSS", 1, SNDCARD_OPL3SA2_MSS, "OPL3SA2 MSS", attach_opl3sa2_mss, probe_opl3sa2_mss, unload_opl3sa2_mss}, {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu}, #endif @@ -587,10 +576,11 @@ #ifndef CONFIG_OPL3SA2_DMA2 #define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA #endif + {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_CTRL_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, + {SNDCARD_OPL3SA2_MSS, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, #ifdef CONFIG_OPL3SA2_MPU_BASE - {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, CONFIG_OPL3SA2_DMA, -1}, SND_DEFAULT_ENABLE}, #endif - {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SGALAXY diff -u --recursive --new-file v2.3.9/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.3.9/linux/drivers/sound/es1370.c Fri Jun 18 10:45:58 1999 +++ linux/drivers/sound/es1370.c Mon Jul 5 19:58:24 1999 @@ -2308,9 +2308,9 @@ }; #ifdef MODULE -__initfunc(int init_module(void)) +int __init init_module(void) #else -__initfunc(int init_es1370(void)) +int __init init_es1370(void) #endif { struct es1370_state *s; diff -u --recursive --new-file v2.3.9/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.3.9/linux/drivers/sound/es1371.c Fri Jun 18 10:45:58 1999 +++ linux/drivers/sound/es1371.c Mon Jul 5 19:58:24 1999 @@ -2723,9 +2723,9 @@ }; #ifdef MODULE -__initfunc(int init_module(void)) +int __init init_module(void) #else -__initfunc(int init_es1371(void)) +int __init init_es1371(void) #endif { struct es1371_state *s; diff -u --recursive --new-file v2.3.9/linux/drivers/sound/lowlevel/awe_compat-fbsd.h linux/drivers/sound/lowlevel/awe_compat-fbsd.h --- v2.3.9/linux/drivers/sound/lowlevel/awe_compat-fbsd.h Wed Dec 16 12:52:01 1998 +++ linux/drivers/sound/lowlevel/awe_compat-fbsd.h Mon Jul 5 20:35:18 1999 @@ -51,7 +51,6 @@ #ifdef AWE_OBSOLETE_VOXWARE -#include #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32) #define CONFIG_AWE32_SYNTH #endif diff -u --recursive --new-file v2.3.9/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.3.9/linux/drivers/sound/maui.c Thu Nov 5 09:58:46 1998 +++ linux/drivers/sound/maui.c Mon Jul 5 19:58:24 1999 @@ -15,9 +15,12 @@ * system * * Status: - * Untested + * Andrew J. Kroll Tested 06/01/1999 with: + * * OSWF.MOT File Version: 1.15 + * * OSWF.MOT File Dated: 09/12/94 + * * Older versions will cause problems. */ - + #include #include #include diff -u --recursive --new-file v2.3.9/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.3.9/linux/drivers/sound/msnd_pinnacle.c Tue May 11 23:40:50 1999 +++ linux/drivers/sound/msnd_pinnacle.c Mon Jul 5 19:58:24 1999 @@ -1165,7 +1165,7 @@ return -EIO; } -__initfunc(static int probe_multisound(void)) +static int __init probe_multisound(void) { #ifndef MSND_CLASSIC char *xv, *rev = NULL; @@ -1305,7 +1305,7 @@ return 0; } -__initfunc(static int calibrate_adc(WORD srate)) +static int __init calibrate_adc(WORD srate) { writew(srate, dev.SMA + SMA_wCalFreqAtoD); if (dev.calibrate_signal == 0) @@ -1427,7 +1427,7 @@ return rv; } -__initfunc(static int attach_multisound(void)) +static int __init attach_multisound(void) { int err; @@ -1491,7 +1491,7 @@ /* Pinnacle/Fiji Logical Device Configuration */ -__initfunc(static int msnd_write_cfg(int cfg, int reg, int value)) +static int __init msnd_write_cfg(int cfg, int reg, int value) { outb(reg, cfg); outb(value, cfg + 1); @@ -1502,7 +1502,7 @@ return 0; } -__initfunc(static int msnd_write_cfg_io0(int cfg, int num, WORD io)) +static int __init msnd_write_cfg_io0(int cfg, int num, WORD io) { if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -1513,7 +1513,7 @@ return 0; } -__initfunc(static int msnd_write_cfg_io1(int cfg, int num, WORD io)) +static int __init msnd_write_cfg_io1(int cfg, int num, WORD io) { if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -1524,7 +1524,7 @@ return 0; } -__initfunc(static int msnd_write_cfg_irq(int cfg, int num, WORD irq)) +static int __init msnd_write_cfg_irq(int cfg, int num, WORD irq) { if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -1535,7 +1535,7 @@ return 0; } -__initfunc(static int msnd_write_cfg_mem(int cfg, int num, int mem)) +static int __init msnd_write_cfg_mem(int cfg, int num, int mem) { WORD wmem; @@ -1553,7 +1553,7 @@ return 0; } -__initfunc(static int msnd_activate_logical(int cfg, int num)) +static int __init msnd_activate_logical(int cfg, int num) { if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -1562,7 +1562,7 @@ return 0; } -__initfunc(static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem)) +static int __init msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem) { if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) return -EIO; @@ -1584,7 +1584,7 @@ int mem; } msnd_pinnacle_cfg_t[4]; -__initfunc(static int msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device)) +static int __init msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device) { int i; @@ -1767,9 +1767,9 @@ calibrate_signal __initdata = CONFIG_MSND_CALSIGNAL; #ifdef MSND_CLASSIC -__initfunc(int msnd_classic_init(void)) +int __init msnd_classic_init(void) #else -__initfunc(int msnd_pinnacle_init(void)) +int __init msnd_pinnacle_init(void) #endif /* MSND_CLASSIC */ #endif /* MODULE */ diff -u --recursive --new-file v2.3.9/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c --- v2.3.9/linux/drivers/sound/opl3sa2.c Thu Jan 7 09:24:00 1999 +++ linux/drivers/sound/opl3sa2.c Mon Jul 5 19:58:24 1999 @@ -467,13 +467,13 @@ } -static int probe_opl3sa2_mss(struct address_info *hw_config) +int probe_opl3sa2_mss(struct address_info *hw_config) { return probe_ms_sound(hw_config); } -static void attach_opl3sa2_mss(struct address_info *hw_config) +void attach_opl3sa2_mss(struct address_info *hw_config) { char mixer_name[64]; @@ -516,7 +516,7 @@ } -static void unload_opl3sa2_mss(struct address_info *hw_config) +void unload_opl3sa2_mss(struct address_info *hw_config) { unload_ms_sound(hw_config); } @@ -592,6 +592,9 @@ { /* Generate a pretty name */ sprintf(chipset_name, "OPL3-SA%c", tag); +#if defined(CONFIG_OPL3SA2_MPU_BASE) && !defined(MODULE) + sound_getconf(SNDCARD_OPL3SA2_MPU)->always_detect = 1; +#endif return 1; } return 0; diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c --- v2.3.9/linux/drivers/sound/sb_ess.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/sound/sb_ess.c Tue Jul 6 10:11:40 1999 @@ -40,10 +40,10 @@ * recording problems for high samplerates. I * fixed this by removing ess_calc_best_speed () * and just doing what the documentation says. - *Javier Achirica(May 15 1999): Major cleanup, MPU IRQ sharing, hardware - * volume support, PNP chip configuration, - * full duplex in most cards, sample rate fine - * tuning. + * Andy Sloane (June 4 1999): Stole some code from ALSA to fix the playback + * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888. + * 1879's were previously ignored by this driver; + * added (untested) support for those. * * This files contains ESS chip specifics. It's based on the existing ESS * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This @@ -183,7 +183,6 @@ * ES1946 yes This is a PCI chip; not handled by this driver */ -#include #include #include "sound_config.h" @@ -195,29 +194,22 @@ #define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */ #define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */ -int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */ +int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */ -#define SUBMDL_ES688 0x00 /* Subtype ES688 for specific handling */ -#define SUBMDL_ES1688 0x08 /* Subtype ES1688 for specific handling */ #define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ #define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ #define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ #define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ -#define SUBMDL_ES1879 0x14 /* Subtype ES1879 for specific handling */ -#define SUBMDL_ES1887 0x15 /* Subtype ES1887 for specific handling */ -#define SUBMDL_ES1888 0x16 /* Subtype ES1888 for specific handling */ - - /* Recording mixer, stereo full duplex */ -#define ESSCAP_NEW 0x00000100 - /* ISA PnP configuration */ -#define ESSCAP_PNP 0x00000200 - /* Full duplex, 6-bit volume, hardware volume controls */ -#define ESSCAP_ES18 0x00000400 - /* New interrupt handling system (ESS 1887) */ -#define ESSCAP_IRQ 0x00000800 - -#define ESSFMT_16 0x00000001 -#define ESSFMT_SIGNED 0x00000004 +#define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */ +#define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ +#define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ + +#define SB_CAP_ES18XX_RATE 0x100 + +#define ES1688_CLOCK1 795444 /* 128 - div */ +#define ES1688_CLOCK2 397722 /* 256 - div */ +#define ES18XX_CLOCK1 793800 /* 128 - div */ +#define ES18XX_CLOCK2 768000 /* 256 - div */ #ifdef FKS_LOGGING static void ess_show_mixerregs (sb_devc *devc); @@ -233,6 +225,52 @@ * * ****************************************************************************/ +struct ess_command {short cmd; short data;}; + +/* + * Commands for initializing Audio 1 for input (record) + */ +static struct ess_command ess_i08m[] = /* input 8 bit mono */ + { {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; +static struct ess_command ess_i16m[] = /* input 16 bit mono */ + { {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; +static struct ess_command ess_i08s[] = /* input 8 bit stereo */ + { {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; +static struct ess_command ess_i16s[] = /* input 16 bit stereo */ + { {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; + +static struct ess_command *ess_inp_cmds[] = + { ess_i08m, ess_i16m, ess_i08s, ess_i16s }; + + +/* + * Commands for initializing Audio 1 for output (playback) + */ +static struct ess_command ess_o08m[] = /* output 8 bit mono */ + { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; +static struct ess_command ess_o16m[] = /* output 16 bit mono */ + { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; +static struct ess_command ess_o08s[] = /* output 8 bit stereo */ + { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; +static struct ess_command ess_o16s[] = /* output 16 bit stereo */ + { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; + +static struct ess_command *ess_out_cmds[] = + { ess_o08m, ess_o16m, ess_o08s, ess_o16s }; + +static void ess_exec_commands + (sb_devc *devc, struct ess_command *cmdtab[]) +{ + struct ess_command *cmd; + + cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ]; + + while (cmd->cmd != -1) { + ess_write (devc, cmd->cmd, cmd->data); + cmd++; + } +} + static void ess_change (sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val) { @@ -272,21 +310,53 @@ devc->irq_mode = IMODE_INPUT; } -static int ess_calc_div (int clock, int *speedp, int *diffp) +static int ess_calc_div (int clock, int revert, int *speedp, int *diffp) { int divider; int speed, diff; + int retval; speed = *speedp; divider = (clock + speed / 2) / speed; - if (divider > 127) { - divider = 127; - } + retval = revert - divider; + if (retval > revert - 1) { + retval = revert - 1; + divider = revert - retval; + } + /* This line is suggested. Must be wrong I think + *speedp = (clock + divider / 2) / divider; + So I chose the next one */ + *speedp = clock / divider; diff = speed - *speedp; - *diffp = diff < 0 ? -diff : diff; + if (diff < 0) diff =-diff; + *diffp = diff; + + return retval; +} + +static int ess_calc_best_speed + (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) +{ + int speed1 = *speedp, speed2 = *speedp; + int div1, div2; + int diff1, diff2; + int retval; + + div1 = ess_calc_div (clock1, rev1, &speed1, &diff1); + div2 = ess_calc_div (clock2, rev2, &speed2, &diff2); + + if (diff1 < diff2) { + *divp = div1; + *speedp = speed1; + retval = 1; + } else { + *divp = div2; + *speedp = speed2; + retval = 2; + } - return 128 - divider; + return retval; } /* @@ -299,30 +369,24 @@ */ static void ess_common_speed (sb_devc *devc, int *speedp, int *divp) { - int speed1 = *speedp, speed2 = *speedp; - int div1, div2; - int diff1, diff2; + int diff = 0, div; - if (devc->caps & ESSCAP_NEW) { - div1 = 0x000 | ess_calc_div (793800, &speed1, &diff1); - div2 = 0x080 | ess_calc_div (768000, &speed2, &diff2); + if (devc->duplex) { + /* + * The 0x80 is important for the first audio channel + */ + div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); + } else if(devc->caps & SB_CAP_ES18XX_RATE) { + ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, + &div, speedp); } else { if (*speedp > 22000) { - div1 = 0x080 | ess_calc_div (795444, &speed1, &diff1); - div2 = 0x180 | ess_calc_div (793800, &speed2, &diff2); + div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff); } else { - div1 = 0x000 | ess_calc_div (397722, &speed1, &diff1); - div2 = 0x100 | ess_calc_div (396900, &speed2, &diff2); + div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff); } } - - if (diff1 < diff2) { - *divp = div1; - *speedp = speed1; - } else { - *divp = div2; - *speedp = speed2; - } + *divp = div; } static void ess_speed (sb_devc *devc, int audionum) @@ -341,13 +405,21 @@ div2 = 256 - 7160000 / (speed * 82); - if ((devc->caps & ESSCAP_NEW) && audionum != 1) { - ess_setmixer (devc, 0x70, div); - ess_setmixer (devc, 0x72, div2); + if (!devc->duplex) audionum = 1; + + if (audionum == 1) { + /* Change behaviour of register A1 * + sb_chg_mixer(devc, 0x71, 0x20, 0x20) + * For ES1869 only??? */ + ess_write (devc, 0xa1, div); + ess_write (devc, 0xa2, div2); } else { - ess_change (devc, 0xba, 0x40, (div & 0x100) ? 0x40 : 0x00); - ess_write (devc, 0xa1, div & 0xff); + ess_setmixer (devc, 0x70, div); + /* + * FKS: fascinating: 0x72 doesn't seem to work. + */ ess_write (devc, 0xa2, div2); + ess_setmixer (devc, 0x72, div2); } } @@ -355,14 +427,77 @@ { sb_devc *devc = audio_devs[dev]->devc; + ess_speed(devc, 1); + + sb_dsp_command(devc, DSP_CMD_SPKOFF); + ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */ - ess_change (devc, 0xa8, 0x0b, 3 - devc->channels); /* Mono/stereo */ + ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ + ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ + ess_exec_commands (devc, ess_inp_cmds); + + ess_change (devc, 0xb1, 0xf0, 0x50); + ess_change (devc, 0xb2, 0xf0, 0x50); + + devc->trigger_bits = 0; + return 0; +} + +static int ess_audio_prepare_for_output_audio1 (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + sb_dsp_reset(devc); ess_speed(devc, 1); + ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ + ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ + ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ - ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51); - ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) | - ((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40)); + ess_exec_commands (devc, ess_out_cmds); + + ess_change (devc, 0xb1, 0xf0, 0x50); /* Enable DMA */ + ess_change (devc, 0xb2, 0xf0, 0x50); /* Enable IRQ */ + + sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */ + + devc->trigger_bits = 0; + return 0; +} + +static int ess_audio_prepare_for_output_audio2 (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + unsigned char bits; + +/* FKS: qqq + sb_dsp_reset(devc); +*/ + + /* + * Auto-Initialize: + * DMA mode + demand mode (8 bytes/request, yes I want it all!) + * But leave 16-bit DMA bit untouched! + */ + ess_chgmixer (devc, 0x78, 0xd0, 0xd0); + + ess_speed(devc, 2); + + /* bits 4:3 on ES1887 represent recording source. Keep them! */ + bits = ess_getmixer (devc, 0x7a) & 0x18; + + /* Set stereo/mono */ + if (devc->channels != 1) bits |= 0x02; + + /* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */ + if (devc->bits != AFMT_U8) bits |= 0x05; /* 16 bit */ + + /* Enable DMA, IRQ will be shared (hopefully)*/ + bits |= 0x60; + + ess_setmixer (devc, 0x7a, bits); + + ess_mixer_reload (devc, SOUND_MIXER_PCM); /* There be sound! */ devc->trigger_bits = 0; return 0; @@ -378,79 +513,144 @@ #endif if (devc->duplex) { - ess_speed(devc, 2); + return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount); + } else { + return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount); + } +} - ess_chgmixer (devc, 0x7a, 0x07, ((devc->bits & ESSFMT_SIGNED) ? 4 : 0) | - ((devc->bits & ESSFMT_16) ? 1 : 0) | ((devc->channels > 1) ? 2 : 0)); +static void ess_audio_halt_xfer(int dev) +{ + unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; - if (devc->caps & ESSCAP_NEW) - ess_mixer_reload (devc, SOUND_MIXER_PCM); /* There be sound! */ - else - sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */ - } else { - ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ - ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ + save_flags(flags); + cli(); + sb_dsp_reset(devc); + restore_flags(flags); - ess_speed(devc, 1); + /* + * Audio 2 may still be operational! Creates awful sounds! + */ + if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00); +} - ess_write (devc, 0xb6, (devc->bits & ESSFMT_SIGNED) ? 0 : 0x80); - ess_write (devc, 0xb7, (devc->bits & ESSFMT_SIGNED) ? 0x71 : 0x51); - ess_write (devc, 0xb7, 0x90 | ((devc->bits & ESSFMT_SIGNED) ? 0x20 : 0) | - ((devc->bits & ESSFMT_16) ? 4 : 0) | ((devc->channels > 1) ? 8 : 0x40)); +static void ess_audio_start_input + (int dev, unsigned long buf, int nr_bytes, int intrflag) +{ + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; - sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */ - } - devc->trigger_bits = 0; - return 0; + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + if (audio_devs[dev]->dmap_in->dma > 3) count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + + ess_change (devc, 0xb8, 0x0f, 0x0f); /* Go */ + devc->intr_active = 1; } -static void ess_audio_halt_xfer(int dev) +static void ess_audio_output_block_audio1 + (int dev, unsigned long buf, int nr_bytes, int intrflag) { + int count = nr_bytes; sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; - sb_dsp_command (devc, DSP_CMD_SPKOFF); + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; - if (devc->caps & ESSCAP_NEW) { - ess_setmixer (devc, 0x7c, 0); - } + devc->irq_mode = IMODE_OUTPUT; - ess_change (devc, 0xb8, 0x0f, 0x00); /* Stop */ + ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - if (devc->duplex) { /* Audio 2 may still be operational! */ - ess_chgmixer (devc, 0x78, 0x03, 0x00); + ess_change (devc, 0xb8, 0x05, 0x05); /* Go */ + devc->intr_active = 1; +} + +static void ess_audio_output_block_audio2 + (int dev, unsigned long buf, int nr_bytes, int intrflag) +{ + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; + + if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1; + count--; + + ess_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff)); + ess_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */ + + devc->irq_mode_16 = IMODE_OUTPUT; + devc->intr_active_16 = 1; +} + +static void ess_audio_output_block + (int dev, unsigned long buf, int nr_bytes, int intrflag) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (devc->duplex) { + ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag); + } else { + ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag); } } +/* + * FKS: the if-statements for both bits and bits_16 are quite alike. + * Combine this... + */ static void ess_audio_trigger(int dev, int bits) { sb_devc *devc = audio_devs[dev]->devc; - int bits_16 = bits & devc->irq_mode_16 & IMODE_OUTPUT; + int bits_16 = bits & devc->irq_mode_16; bits &= devc->irq_mode; if (!bits && !bits_16) { - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - ess_chgmixer (devc, 0x78, 0x04, 0x00); /* Halt DMA 2 */ + /* FKS oh oh.... wrong?? for dma 16? */ + sb_dsp_command(devc, 0xd0); /* Halt DMA */ } if (bits) { - short c = -devc->trg_bytes; - - ess_write (devc, 0xa4, (unsigned char)((unsigned short) c & 0xff)); - ess_write (devc, 0xa5, (unsigned char)((unsigned short) c >> 8)); - ess_change (devc, 0xb8, 0x0f, (devc->irq_mode==IMODE_INPUT)?0x0f:0x05); + switch (devc->irq_mode) + { + case IMODE_INPUT: + ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; - devc->intr_active = 1; + case IMODE_OUTPUT: + ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } } if (bits_16) { - short c = -devc->trg_bytes_16; - - ess_setmixer (devc, 0x74, (unsigned char)((unsigned short) c & 0xff)); - ess_setmixer (devc, 0x76, (unsigned char)((unsigned short) c >> 8)); - ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */ + switch (devc->irq_mode_16) { + case IMODE_INPUT: + ess_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16, + devc->trg_intrflag_16); + break; - devc->intr_active_16 = 1; + case IMODE_OUTPUT: + ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16, + devc->trg_intrflag_16); + break; + } } devc->trigger_bits = bits | bits_16; @@ -462,8 +662,8 @@ int minspeed, maxspeed, dummydiv; if (speed > 0) { - minspeed = (devc->caps & ESSCAP_NEW) ? 6047 : 3125; - maxspeed = 48000; + minspeed = (devc->duplex ? 6215 : 5000 ); + maxspeed = (devc->duplex ? 44100 : 48000); if (speed < minspeed) speed = minspeed; if (speed > maxspeed) speed = maxspeed; @@ -474,46 +674,38 @@ return devc->speed; } +/* + * FKS: This is a one-on-one copy of sb1_audio_set_bits + */ static unsigned int ess_audio_set_bits(int dev, unsigned int bits) { sb_devc *devc = audio_devs[dev]->devc; - switch (bits) { - case 0: - break; - case AFMT_S16_LE: - devc->bits = ESSFMT_16 | ESSFMT_SIGNED; - break; - case AFMT_U16_LE: - devc->bits = ESSFMT_16; - break; - case AFMT_S8: - devc->bits = ESSFMT_SIGNED; - break; - default: - devc->bits = 0; - break; + if (bits != 0) { + if (bits == AFMT_U8 || bits == AFMT_S16_LE) { + devc->bits = bits; + } else { + devc->bits = AFMT_U8; + } } return devc->bits; } +/* + * FKS: This is a one-on-one copy of sbpro_audio_set_channels + * (*) Modified it!! + */ static short ess_audio_set_channels(int dev, short channels) { sb_devc *devc = audio_devs[dev]->devc; - if (devc->fullduplex && !(devc->caps & ESSCAP_NEW)) { - devc->channels = 1; - } else { - if (channels == 1 || channels == 2) { - devc->channels = channels; - } - } + if (channels == 1 || channels == 2) devc->channels = channels; return devc->channels; } -static struct audio_driver ess_audio_driver = /* ESS ES688/1688/18xx */ +static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ { sb_audio_open, sb_audio_close, @@ -540,7 +732,7 @@ (sb_devc *devc, int *audio_flags, int *format_mask) { *audio_flags = DMA_AUTOMODE; - *format_mask |= AFMT_S16_LE | AFMT_U16_LE | AFMT_S8; + *format_mask |= AFMT_S16_LE; if (devc->duplex) { int tmp_dma; @@ -563,8 +755,10 @@ * ESS common * * * ****************************************************************************/ -static void ess_handle_channel (int dev, int irq_mode) +static void ess_handle_channel + (char *channel, int dev, int intr_active, unsigned char flag, int irq_mode) { + if (!intr_active || !flag) return; #ifdef FKS_REG_LOGGING printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode); #endif @@ -586,77 +780,48 @@ } /* - * In the ESS 1888 model, how do we found out if the MPU interrupted ??? + * FKS: TODO!!! Finish this! + * + * I think midi stuff uses uart401, without interrupts. + * So IMODE_MIDI isn't a value for devc->irq_mode. */ void ess_intr (sb_devc *devc) { int status; unsigned char src; - if (devc->caps & ESSCAP_PNP) { - outb (devc->pcibase + 7, 0); /* Mask IRQs */ - src = inb (devc->pcibase + 6) & 0x0f; - } else if (devc->caps & ESSCAP_IRQ) { + if (devc->submodel == SUBMDL_ES1887) { src = ess_getmixer (devc, 0x7f) >> 4; } else { - src = inb (DSP_STATUS) & 0x01; - if (devc->duplex && (ess_getmixer (devc, 0x7a) & 0x80)) { - src |= 0x02; - } - if ((devc->caps & ESSCAP_ES18) && (ess_getmixer (devc, 0x64) & 0x10)) { - src |= 0x04; - } -#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401) - /* - * This should work if dev_conf wasn't local to mpu401.c - */ -#if 0 - if ((int)devc->midi_irq_cookie >= 0 && - !(inb(dev_conf[(int)devc->midi_irq_cookie].base + 1) & 0x80)) { - src |= 0x08; - } -#endif -#endif + src = 0xff; } #ifdef FKS_REG_LOGGING printk(KERN_INFO "FKS: sbintr src=%x\n",(int)src); #endif - if (src & 0x01) { - status = inb(DSP_DATA_AVAIL); /* Acknowledge interrupt */ - if (devc->intr_active) - ess_handle_channel (devc->dev, devc->irq_mode ); - } - - if (src & 0x02) { - ess_chgmixer (devc, 0x7a, 0x80, 0x00); /* Acknowledge interrupt */ - if (devc->intr_active_16) - ess_handle_channel (devc->dev, devc->irq_mode_16); + ess_handle_channel + ( "Audio 1" + , devc->dev, devc->intr_active , src & 0x01, devc->irq_mode ); + ess_handle_channel + ( "Audio 2" + , devc->dev, devc->intr_active_16, src & 0x02, devc->irq_mode_16); + /* + * Acknowledge interrupts + */ + if (devc->submodel == SUBMDL_ES1887 && (src & 0x02)) { + ess_chgmixer (devc, 0x7a, 0x80, 0x00); } - if (src & 0x04) { - int left, right; - - ess_setmixer (devc, 0x66, 0x00); /* Hardware volume IRQ ack */ - - left = ess_getmixer (devc, 0x60); - right = ess_getmixer (devc, 0x62); - - left = (left & 0x40) ? 0 : ((left * 100 + 31)/ 63); /* Mute or scale */ - right = (right & 0x40) ? 0 : ((right * 100 + 31)/ 63); - - devc->levels[SOUND_MIXER_VOLUME] = left | (right << 8); + if (src & 0x01) { + status = inb(DSP_DATA_AVAIL); } +} -#if defined(CONFIG_MIDI) && defined(CONFIG_SOUND_MPU401) - if ((int)devc->midi_irq_cookie >= 0 && (src & 0x08)) { - mpuintr (devc->irq, devc->midi_irq_cookie, NULL); - } -#endif +static void ess_extended (sb_devc * devc) +{ + /* Enable extended mode */ - if (devc->caps & ESSCAP_PNP) { - outb (devc->pcibase + 7, 0xff); /* Unmask IRQs */ - } + sb_dsp_command(devc, 0xc6); } static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data) @@ -686,7 +851,7 @@ int ess_dsp_reset(sb_devc * devc) { - int loopc, val; + int loopc; #ifdef FKS_REG_LOGGING printk(KERN_INFO "FKS: ess_dsp_reset 1\n"); @@ -707,102 +872,79 @@ DDB(printk("sb: No response to RESET\n")); return 0; /* Sorry */ } + ess_extended (devc); - sb_dsp_command(devc, 0xc6); /* Enable extended mode */ - if (!(devc->caps & ESSCAP_PNP)) { - ess_setmixer (devc, 0x40, 0x03); /* Enable joystick and OPL3 */ - - switch (devc->irq) { - case 2: - case 9: - val = 1; - break; - case 5: - val = 2; - break; - case 7: - val = 3; - break; - case 10: - val = 4; - break; - case 11: - val = 5; - break; - default: - val = 0; - } /* IRQ config */ - ess_write (devc, 0xb1, 0xf0 | ((val && val != 5) ? val - 1 : 0)); + DEB(printk("sb_dsp_reset() OK\n")); - if (devc->caps & ESSCAP_IRQ) { - ess_setmixer (devc, 0x7f, 0x01 | (val << 1)); /* IRQ config */ - } +#ifdef FKS_LOGGING +printk(KERN_INFO "FKS: dsp_reset 2\n"); +ess_show_mixerregs (devc); +#endif - switch ((devc->duplex) ? devc->dma16 : devc->dma8) { - case 0: - val = 0x54; - break; - case 1: - val = 0x58; - break; - case 3: - val = 0x5c; - break; - default: - val = 0; - } - ess_write (devc, 0xb2, val); /* DMA1 config */ + return 1; +} - if (devc->duplex) { - switch (devc->dma8) { - case 0: - val = 0x04; - break; - case 1: - val = 0x05; - break; - case 3: - val = 0x06; - break; - case 5: - val = 0x07; - break; - default: - val = 0; - } - ess_write (devc, 0x7d, val); /* DMA2 config */ - } - } - ess_change (devc, 0xb1, 0xf0, 0x50); /* Enable IRQ 1 */ - ess_change (devc, 0xb2, 0xf0, 0x50); /* Enable DMA 1 */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ - ess_setmixer (devc, 0x7a, 0x40); /* Enable IRQ 2 */ - /* Auto-Initialize DMA mode + demand mode (8 bytes/request) */ - if (devc->caps & ESSCAP_PNP) { - ess_setmixer (devc, 0x78, 0xd0); - ess_setmixer (devc, 0x64, 0x82); /* Enable HW volume interrupt */ - } else { - ess_setmixer (devc, 0x78, (devc->dma8 > 4) ? 0xf0 : 0xd0); - ess_setmixer (devc, 0x64, 0x42); /* Enable HW volume interrupt */ - } +static int ess_irq_bits (int irq) +{ + switch (irq) { + case 2: + case 9: + return 0; - if (devc->caps & ESSCAP_NEW) { - ess_setmixer (devc, 0x71, 0x32); /* Change behaviour of register A1 */ - ess_setmixer (devc, 0x1c, 0x05); /* Recording source is mixer */ - } else { - ess_change (devc, 0xb7, 0x80, 0x80); /* Enable DMA FIFO */ + case 5: + return 1; + + case 7: + return 2; + + case 10: + return 3; + + default: + printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq); + return -1; } +} - DEB(printk("sb_dsp_reset() OK\n")); +/* + * Set IRQ configuration register for all ESS models + */ +static int ess_common_set_irq_hw (sb_devc * devc) +{ + int irq_bits; -#ifdef FKS_LOGGING -printk(KERN_INFO "FKS: dsp_reset 2\n"); -ess_show_mixerregs (devc); -#endif + if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return 0; + if (!ess_write (devc, 0xb1, 0x50 | (irq_bits << 2))) { + printk(KERN_ERR "ES1688: Failed to write to IRQ config register\n"); + return 0; + } return 1; } +/* + * I wanna use modern ES1887 mixer irq handling. Funny is the + * fact that my BIOS wants the same. But suppose someone's BIOS + * doesn't do this! + * This is independent of duplex. If there's a 1887 this will + * prevent it from going into 1888 mode. + */ +static void ess_es1887_set_irq_hw (sb_devc * devc) +{ + int irq_bits; + + if ((irq_bits = ess_irq_bits (devc->irq)) == -1) return; + + ess_chgmixer (devc, 0x7f, 0x0f, 0x01 | ((irq_bits + 1) << 1)); +} + +static int ess_set_irq_hw (sb_devc * devc) +{ + if (devc->submodel == SUBMDL_ES1887) ess_es1887_set_irq_hw (devc); + + return ess_common_set_irq_hw (devc); +} + #ifdef FKS_TEST /* @@ -826,7 +968,7 @@ }; #endif -static unsigned int ess_identify (sb_devc * devc, int *control) +static unsigned int ess_identify (sb_devc * devc) { unsigned int val; unsigned long flags; @@ -840,15 +982,8 @@ udelay(20); val |= inb(MIXER_DATA); udelay(20); - *control = inb(MIXER_DATA) << 8; - udelay(20); - *control |= inb(MIXER_DATA); - udelay(20); restore_flags(flags); - if (*control < 0 || *control > 0x3ff || check_region (*control, 8)) - *control = 0; - return val; } @@ -875,6 +1010,7 @@ int ess_init(sb_devc * devc, struct address_info *hw_config) { + unsigned char cfg; int ess_major = 0, ess_minor = 0; int i; static char name[100], modelname[10]; @@ -882,7 +1018,6 @@ /* * Try to detect ESS chips. */ - devc->pcibase = 0; sb_dsp_command(devc, 0xe7); /* Return identification */ @@ -934,10 +1069,10 @@ case ESSTYPE_LIKE20: break; case 688: - submodel = SUBMDL_ES688; + submodel = 0x00; break; case 1688: - submodel = SUBMDL_ES1688; + submodel = 0x08; break; case 1868: submodel = SUBMDL_ES1868; @@ -986,7 +1121,7 @@ if (chip == NULL) { int type; - type = ess_identify (devc, &devc->pcibase); + type = ess_identify (devc); switch (type) { case 0x1868: @@ -1063,72 +1198,139 @@ strcpy(name, "Jazz16"); } - switch (devc->submodel) { - case SUBMDL_ES1869: - case SUBMDL_ES1879: - devc->caps |= ESSCAP_NEW; - case SUBMDL_ES1868: - case SUBMDL_ES1878: - devc->caps |= ESSCAP_PNP | ESSCAP_ES18; - break; - case SUBMDL_ES1887: - devc->caps |= ESSCAP_IRQ; - case SUBMDL_ES1888: - devc->caps |= ESSCAP_NEW | ESSCAP_ES18; - } - if (devc->caps & ESSCAP_PNP) { - if (!devc->pcibase) { - printk (KERN_ERR "ESS PnP chip without PnP registers. Ignored\n"); - return 0; - } - request_region (devc->pcibase, 8, "ESS18xx ctrl"); + /* AAS: info stolen from ALSA: these boards have different clocks */ + switch(devc->submodel) { + case SUBMDL_ES1869: + case SUBMDL_ES1887: + case SUBMDL_ES1888: + devc->caps |= SB_CAP_ES18XX_RATE; + break; + } + + hw_config->name = name; + /* FKS: sb_dsp_reset to enable extended mode???? */ + sb_dsp_reset(devc); /* Turn on extended mode */ - outb (0x07, devc->pcibase); /* Selects logical device #1 */ - outb (0x01, devc->pcibase + 1); - outb (0x28, devc->pcibase); - i = inb (devc->pcibase + 1) & 0x0f; - outb (0x28, devc->pcibase); /* Sets HW volume IRQ */ - outb (devc->irq << 4 | i, devc->pcibase + 1); - outb (0x70, devc->pcibase); /* Sets IRQ 1 */ - outb (devc->irq, devc->pcibase + 1); - outb (0x72, devc->pcibase); /* Sets IRQ 2 */ - outb (devc->irq, devc->pcibase + 1); - outb (0x74, devc->pcibase); /* Sets DMA 1 */ - outb (hw_config->dma, devc->pcibase + 1); - outb (0x75, devc->pcibase); /* Sets DMA 2 */ - outb (hw_config->dma2 >= 0 ? hw_config->dma2 : 4, devc->pcibase + 1); - } else if (devc->pcibase) { - printk (KERN_INFO "Non-PnP ESS card with PnP registers at %04Xh, ignoring them.\n", devc->pcibase); - devc->pcibase = 0; + /* + * Enable joystick and OPL3 + */ + cfg = ess_getmixer (devc, 0x40); + ess_setmixer (devc, 0x40, cfg | 0x03); + if (devc->submodel >= 8) { /* ES1688 */ + devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ } + sb_dsp_reset (devc); - devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ + /* + * This is important! If it's not done, the IRQ probe in sb_dsp_init + * may fail. + */ + return ess_set_irq_hw (devc); +} - hw_config->name = name; +static int ess_set_dma_hw(sb_devc * devc) +{ + unsigned char cfg, dma_bits = 0, dma16_bits; + int dma; - sb_dsp_reset(devc); /* Turn on extended mode */ +#ifdef FKS_LOGGING +printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n" +, devc->dma8, devc->dma16, devc->duplex); +#endif - ess_setmixer (devc, 0x00, 0x00); /* Reset mixer registers */ + /* + * FKS: It seems as if this duplex flag isn't set yet. Check it. + */ + dma = devc->dma8; + if (dma > 3 || dma < 0 || dma == 2) { + dma_bits = 0; + printk(KERN_ERR "ESS1688: Invalid DMA8 %d\n", dma); + return 0; + } else { + /* Extended mode DMA enable */ + cfg = 0x50; + + if (dma == 3) { + dma_bits = 3; + } else { + dma_bits = dma + 1; + } + } + + if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) { + printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n"); + return 0; + } + + if (devc->duplex) { + dma = devc->dma16; + dma16_bits = 0; + + if (dma >= 0) { + switch (dma) { + case 0: + dma_bits = 0x04; + break; + case 1: + dma_bits = 0x05; + break; + case 3: + dma_bits = 0x06; + break; + case 5: + dma_bits = 0x07; + dma16_bits = 0x20; + break; + default: + printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma); + return 0; + }; + ess_chgmixer (devc, 0x78, 0x20, dma16_bits); + ess_chgmixer (devc, 0x7d, 0x07, dma_bits); + } + } return 1; } /* * This one is called from sb_dsp_init. + * + * Return values: + * 0: Failed + * 1: Succeeded or doesn't apply (not SUBMDL_ES1887) */ int ess_dsp_init (sb_devc *devc, struct address_info *hw_config) { /* + * This for ES1887 to run Full Duplex. Actually ES1888 + * is allowed to do so too. I have no idea yet if this + * will work for ES1888 however. + * * For SB16 having both dma8 and dma16 means enable - * Full Duplex. Let's try this too + * Full Duplex. Let's try this for ES1887 too + * */ - if ((devc->caps & ESSCAP_ES18) && hw_config->dma2 >= 0) { - devc->dma16 = hw_config->dma2; - if (devc->dma8 != devc->dma16) { + if (devc->submodel == SUBMDL_ES1887) { + if (hw_config->dma2 != -1) { + devc->dma16 = hw_config->dma2; + } + /* + * devc->duplex initialization is put here, cause + * ess_set_dma_hw needs it. + */ + if (devc->dma8 != devc->dma16 && devc->dma16 != -1) { devc->duplex = 1; } + + if (!ess_set_dma_hw (devc)) { + free_irq(devc->irq, devc); + return 0; + } + return 1; + } else { + return -1; } - return 1; } /**************************************************************************** @@ -1149,13 +1351,13 @@ #define ES1688_MIXER_DEVICES \ ( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV ) -#define ES_NEW_RECORDING_DEVICES \ +#define ES1887_RECORDING_DEVICES \ ( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH) -#define ES_NEW_MIXER_DEVICES \ +#define ES1887_MIXER_DEVICES \ ( ES1688_MIXER_DEVICES ) /* - * Mixer registers of ES18xx with new capabilities + * Mixer registers of ES1887 * * These registers specifically take care of recording levels. To make the * mapping from playback devices to recording devices every recording @@ -1285,11 +1487,11 @@ }; /* - * This one is for new ES's. It's little different from es_rec_mix: it - * has 0x7c for PCM playback level. This is because uses + * This one is for ES1887. It's little different from es_rec_mix: it + * has 0x7c for PCM playback level. This is because ES1887 uses * Audio 2 for playback. */ -static mixer_tab es_new_mix = { +static mixer_tab es1887_mix = { MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), @@ -1323,6 +1525,16 @@ MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0) }; +static int ess_has_rec_mixer (int submodel) +{ + switch (submodel) { + case SUBMDL_ES1887: + return 1; + default: + return 0; + }; +}; + #ifdef FKS_LOGGING static int ess_mixer_mon_regs[] = { 0x70, 0x71, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7f @@ -1353,13 +1565,15 @@ save_flags(flags); cli(); + if (port >= 0xa0) { + ess_write (devc, port, value); + } else { + outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - - udelay(20); - outb(((unsigned char) (value & 0xff)), MIXER_DATA); - udelay(20); - + udelay(20); + outb(((unsigned char) (value & 0xff)), MIXER_DATA); + udelay(20); + }; restore_flags(flags); } @@ -1371,12 +1585,15 @@ save_flags(flags); cli(); - outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - - udelay(20); - val = inb(MIXER_DATA); - udelay(20); + if (port >= 0xa0) { + val = ess_read (devc, port); + } else { + outb(((unsigned char) (port & 0xff)), MIXER_ADDR); + udelay(20); + val = inb(MIXER_DATA); + udelay(20); + } restore_flags(flags); return val; @@ -1400,21 +1617,23 @@ devc->mixer_caps = SOUND_CAP_EXCL_INPUT; /* - * Take care of new ES's specifics... + * Take care of ES1887 specifics... */ - if (devc->caps & ESSCAP_NEW) { - devc->supported_devices = ES_NEW_MIXER_DEVICES; - devc->supported_rec_devices = ES_NEW_RECORDING_DEVICES; + switch (devc->submodel) { + case SUBMDL_ES1887: + devc->supported_devices = ES1887_MIXER_DEVICES; + devc->supported_rec_devices = ES1887_RECORDING_DEVICES; #ifdef FKS_LOGGING printk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex); #endif if (devc->duplex) { - devc->iomap = &es_new_mix; + devc->iomap = &es1887_mix; } else { devc->iomap = &es_rec_mix; } - } else { - if (devc->submodel == SUBMDL_ES688) { + break; + default: + if (devc->submodel < 8) { devc->supported_devices = ES688_MIXER_DEVICES; devc->supported_rec_devices = ES688_RECORDING_DEVICES; devc->iomap = &es688_mix; @@ -1425,10 +1644,10 @@ */ devc->supported_devices = ES1688_MIXER_DEVICES; devc->supported_rec_devices = ES1688_RECORDING_DEVICES; - if (devc->caps & ESSCAP_ES18) { - devc->iomap = &es1688later_mix; - } else { + if (devc->submodel < 0x10) { devc->iomap = &es1688_mix; + } else { + devc->iomap = &es1688later_mix; } } } @@ -1440,15 +1659,9 @@ */ int ess_mixer_set(sb_devc *devc, int dev, int left, int right) { - if ((devc->caps & ESSCAP_NEW) && (devc->recmask & (1 << dev))) { + if (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) { sb_common_mixer_set (devc, dev + ES_REC_MIXER_RECDIFF, left, right); } - /* Set & unmute master volume */ - if ((devc->caps & ESSCAP_ES18) && (dev == SOUND_MIXER_VOLUME)) { - ess_chgmixer (devc, 0x60, 0x7f, 0x3f & ((left * 0x3f + 50) / 100)); - ess_chgmixer (devc, 0x62, 0x7f, 0x3f & ((right * 0x3f + 50) / 100)); - return left | (right << 8); - } return sb_common_mixer_set (devc, dev, left, right); } @@ -1494,6 +1707,7 @@ right = (value & 0x0000ff00) >> 8; } else { /* Turn it off (3) */ left = 0; + left = 0; right = 0; } sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right); @@ -1506,7 +1720,7 @@ { /* This applies to ESS chips with record mixers only! */ - if (devc->caps & ESSCAP_NEW) { + if (ess_has_rec_mixer (devc->submodel)) { *mask = es_rec_set_recmask (devc, *mask); return 1; /* Applied */ } else { @@ -1522,7 +1736,18 @@ /* * Separate actions for ESS chips with a record mixer: */ - if (devc->caps & ESSCAP_NEW) { + if (ess_has_rec_mixer (devc->submodel)) { + switch (devc->submodel) { + case SUBMDL_ES1887: + /* + * Separate actions for ES1887: + * Change registers 7a and 1c to make the record mixer the + * actual recording source. + */ + ess_chgmixer(devc, 0x7a, 0x18, 0x08); + ess_chgmixer(devc, 0x1c, 0x07, 0x07); + break; + }; /* * Call set_recmask for proper initialization */ @@ -1542,80 +1767,50 @@ * * ****************************************************************************/ +/* + * FKS: IRQ may be shared. Hm. And if so? Then What? + */ int ess_midi_init(sb_devc * devc, struct address_info *hw_config) { - int val; + unsigned char cfg, tmp; - if (devc->submodel == SUBMDL_ES688) { - return 0; /* ES688 doesn't support MPU401 mode */ + cfg = ess_getmixer (devc, 0x40) & 0x03; + + if (devc->submodel < 8) { + ess_setmixer (devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ + return 0; /* ES688 doesn't support MPU401 mode */ } + tmp = (hw_config->io_base & 0x0f0) >> 4; - if (hw_config->irq < 2) { - hw_config->irq = devc->irq; + if (tmp > 3) { + ess_setmixer (devc, 0x40, cfg); + return 0; } + cfg |= tmp << 3; - if (devc->caps & ESSCAP_PNP) { - outb (0x07, devc->pcibase); /* Selects logical device #1 */ - outb (0x01, devc->pcibase + 1); - outb (0x28, devc->pcibase); - val = inb (devc->pcibase + 1) & 0xf0; - outb (0x28, devc->pcibase); /* Sets MPU IRQ */ - outb (hw_config->irq | val, devc->pcibase + 1); - if (hw_config->io_base) { - outb (0x64, devc->pcibase); /* Sets MPU I/O address */ - outb ((hw_config->io_base & 0xf00) >> 8, devc->pcibase + 1); - outb (0x65, devc->pcibase); /* Sets MPU I/O address */ - outb (hw_config->io_base & 0xfc, devc->pcibase + 1); - } else { - outb (0x64, devc->pcibase); /* Read MPU I/O address */ - hw_config->io_base = (inb (devc->pcibase + 1) & 0x0f) << 8; - outb (0x65, devc->pcibase); /* Read MPU I/O address */ - hw_config->io_base |= inb (devc->pcibase + 1) & 0xfc; - } + tmp = 1; /* MPU enabled without interrupts */ - ess_setmixer (devc, 0x64, 0xc2); /* Enable MPU interrupt */ - } else { - if (devc->irq == hw_config->irq && (devc->caps & ESSCAP_IRQ)) { - val = 0x43; - } - else switch (hw_config->irq) { - case 11: - if (!(devc->caps & ESSCAP_IRQ)) { - return 0; - } - val = 0x63; - break; - case 2: - case 9: - val = 0x83; - break; - case 5: - val = 0xa3; - break; - case 7: - val = 0xc3; - break; - case 10: - val = 0xe3; - break; - default: - return 0; - } - switch (hw_config->io_base) { - case 0x300: - case 0x310: - case 0x320: - case 0x330: - ess_setmixer (devc, 0x40, val - | ((hw_config->io_base & 0x0f0) >> 1)); - break; - default: - return 0; - } + /* May be shared: if so the value is -ve */ + + switch (abs(hw_config->irq)) { + case 9: + tmp = 0x4; + break; + case 5: + tmp = 0x5; + break; + case 7: + tmp = 0x6; + break; + case 10: + tmp = 0x7; + break; + default: + return 0; } - if (devc->irq == hw_config->irq) /* Shared IRQ */ - hw_config->irq = -devc->irq; + cfg |= tmp << 5; + ess_setmixer (devc, 0x40, cfg | 0x03); return 1; } diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.3.9/linux/drivers/sound/sb_mixer.c Mon Apr 12 16:18:27 1999 +++ linux/drivers/sound/sb_mixer.c Mon Jul 5 19:58:25 1999 @@ -13,6 +13,7 @@ * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch] + * Stanislav Voronyi : Support for AWE 3DSE device (Jun 7 1999) */ #include @@ -550,14 +551,37 @@ int val, ret; /* - * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1). + * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). + * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1) + * or mode==2 put 3DSE state to mode. */ - if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) - { - if (get_user(val, (int *)arg)) - return -EFAULT; - sb_setmixer(devc, 0x43, (~val) & 0x01); - return 0; + if (devc->model == MDL_SB16) { + if (cmd == SOUND_MIXER_AGC) + { + if (get_user(val, (int *)arg)) + return -EFAULT; + sb_setmixer(devc, 0x43, (~val) & 0x01); + return 0; + } + if (cmd == SOUND_MIXER_3DSE) + { + /* I put here 15, but I don't know the exact version. + At least my 4.13 havn't 3DSE, 4.16 has it. */ + if (devc->minor < 15) + return -EINVAL; + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val == 0 || val == 1) + sb_chgmixer(devc, AWE_3DSE, 0x01, val); + else if (val == 2) + { + ret = sb_getmixer(devc, AWE_3DSE)&0x01; + return put_user(ret, (int *)arg); + } + else + return -EINVAL; + return 0; + } } if (((cmd >> 8) & 0xff) == 'M') { diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v2.3.9/linux/drivers/sound/sb_mixer.h Thu Jan 7 09:24:00 1999 +++ linux/drivers/sound/sb_mixer.h Mon Jul 5 19:58:25 1999 @@ -78,6 +78,11 @@ #define RIGHT_CHN 1 /* + * 3DSE register of AWE32/64 + */ +#define AWE_3DSE 0x90 + +/* * Mixer registers of ALS007 */ #define ALS007_RECORD_SRC 0x6c diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c --- v2.3.9/linux/drivers/sound/sgalaxy.c Sun Nov 8 13:56:11 1998 +++ linux/drivers/sound/sgalaxy.c Mon Jul 5 19:58:25 1999 @@ -2,7 +2,7 @@ * sound/sgalaxy.c * * Low level driver for Aztech Sound Galaxy cards. - * Copyright 1998 Artur Skawina + * Copyright 1998 Artur Skawina * * Supported cards: * Aztech Sound Galaxy Waverider Pro 32 - 3D diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.3.9/linux/drivers/sound/sonicvibes.c Fri Jun 18 10:45:58 1999 +++ linux/drivers/sound/sonicvibes.c Mon Jul 5 19:58:25 1999 @@ -2312,9 +2312,9 @@ }; #ifdef MODULE -__initfunc(int init_module(void)) +int __init init_module(void) #else -__initfunc(int init_sonicvibes(void)) +int __init init_sonicvibes(void) #endif { struct sv_state *s; diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.3.9/linux/drivers/sound/sound_calls.h Mon Jan 4 11:37:30 1999 +++ linux/drivers/sound/sound_calls.h Mon Jul 5 19:58:25 1999 @@ -256,21 +256,39 @@ void unload_trix_mpu(struct address_info *hw_info); void unload_cs4232(struct address_info *hw_info); void unload_cs4232_mpu(struct address_info *hw_info); +void unload_opl3sa_wss(struct address_info *hw_info); +void unload_opl3sa_sb(struct address_info *hw_info); +void unload_opl3sa_mpu(struct address_info *hw_info); void unload_opl3sa2(struct address_info *hw_info); void unload_opl3sa2_mpu(struct address_info *hw_info); +void unload_opl3sa2_mss(struct address_info *hw_info); +void unload_softsyn (struct address_info *hw_config); -/* From cs4232.c */ - +/* From cs4232.c */ int probe_cs4232 (struct address_info *hw_config); void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); void attach_cs4232_mpu (struct address_info *hw_config); -/* From opl3sa2.c */ +/* From opl3sa.c */ +void attach_opl3sa_wss (struct address_info *hw_config); +int probe_opl3sa_wss (struct address_info *hw_config); +void attach_opl3sa_sb (struct address_info *hw_config); +int probe_opl3sa_sb (struct address_info *hw_config); +void attach_opl3sa_mpu (struct address_info *hw_config); +int probe_opl3sa_mpu (struct address_info *hw_config); + +/* From opl3sa2.c */ int probe_opl3sa2 (struct address_info *hw_config); void attach_opl3sa2 (struct address_info *hw_config); int probe_opl3sa2_mpu (struct address_info *hw_config); void attach_opl3sa2_mpu (struct address_info *hw_config); +int probe_opl3sa2_mss (struct address_info *hw_config); +void attach_opl3sa2_mss (struct address_info *hw_config); + +/* From softoss.c */ +void attach_softsyn_card (struct address_info *hw_config); +int probe_softsyn (struct address_info *hw_config); /* From maui.c */ void attach_maui(struct address_info * hw_config); @@ -291,12 +309,12 @@ int probe_waveartist(struct address_info *hw_config); void unload_waveartist(struct address_info *hw_config); -/* From wavefront.c */ +/* From wavefront.c */ void attach_wavefront (struct address_info *hw_config); int probe_wavefront (struct address_info *hw_config); void unload_wavefront (struct address_info *hw_config); -/* From wf_midi.c */ +/* From wf_midi.c */ void attach_wf_mpu(struct address_info * hw_config); int probe_wf_mpu(struct address_info *hw_config); void unload_wf_mpu(struct address_info *hw_config); diff -u --recursive --new-file v2.3.9/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c --- v2.3.9/linux/drivers/sound/sound_syms.c Mon Jan 4 11:37:30 1999 +++ linux/drivers/sound/sound_syms.c Mon Jul 5 19:58:25 1999 @@ -3,6 +3,9 @@ * modulespace. * * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL + * + * Thu May 27 1999 Andrew J. Kroll + * left out exported symbol... fixed */ #include @@ -43,6 +46,7 @@ EXPORT_SYMBOL(load_mixer_volumes); +EXPORT_SYMBOL(trace_init); /* oops! this is needed for maui.c -- AJK */ EXPORT_SYMBOL(conf_printf); EXPORT_SYMBOL(conf_printf2); diff -u --recursive --new-file v2.3.9/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.3.9/linux/drivers/sound/trix.c Sun Mar 7 15:22:06 1999 +++ linux/drivers/sound/trix.c Mon Jul 5 19:58:25 1999 @@ -42,6 +42,12 @@ static int mpu = 0; +#ifdef TRIX_JOYSTICK +static int joystick=1; +#else +static int joystick=0; +#endif + static unsigned char trix_read(int addr) { outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ @@ -196,9 +202,8 @@ if (ret) { -#ifdef TRIX_ENABLE_JOYSTICK - trix_write(0x15, 0x80); -#endif + if(joystick==1) + trix_write(0x15, 0x80); request_region(0x390, 2, "AudioTrix"); } return ret; @@ -477,7 +482,7 @@ MODULE_PARM(sb_irq,"i"); MODULE_PARM(mpu_io,"i"); MODULE_PARM(mpu_irq,"i"); - +MODULE_PARM(joystick, "i"); struct address_info config; struct address_info sb_config; struct address_info mpu_config; diff -u --recursive --new-file v2.3.9/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.3.9/linux/drivers/sound/wavfront.c Tue May 11 23:40:50 1999 +++ linux/drivers/sound/wavfront.c Mon Jul 5 19:58:25 1999 @@ -2474,8 +2474,7 @@ return (1); } -__initfunc (static int detect_wavefront (int irq, int io_base)) - +static int __init detect_wavefront (int irq, int io_base) { unsigned char rbuf[4], wbuf[4]; @@ -2653,8 +2652,7 @@ return 1; } -__initfunc (static int wavefront_config_midi (void)) - +static int __init wavefront_config_midi (void) { unsigned char rbuf[4], wbuf[4]; @@ -2728,7 +2726,6 @@ static int wavefront_do_reset (int atboot) - { char voices[1]; @@ -2832,7 +2829,6 @@ static int wavefront_init (int atboot) - { int samples_are_from_rom; @@ -2861,7 +2857,7 @@ return (0); } -__initfunc (static int install_wavefront (void)) +static int __init install_wavefront (void) { if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) { @@ -2919,7 +2915,7 @@ #endif OSS_SUPPORT_SEQ uninstall_wf_mpu (); } - + /***********************************************************************/ /* WaveFront FX control */ /***********************************************************************/ @@ -2955,8 +2951,7 @@ return (1); } -__initfunc (static int detect_wffx (void)) - +static int __init detect_wffx (void) { /* This is a crude check, but its the best one I have for now. Certainly on the Maui and the Tropez, wffx_idle() will @@ -2972,8 +2967,7 @@ return 0; } -__initfunc (static int attach_wffx (void)) - +static int __init attach_wffx (void) { if ((dev.fx_mididev = sound_alloc_mididev ()) < 0) { printk (KERN_WARNING LOGNAME "cannot install FX Midi driver\n"); diff -u --recursive --new-file v2.3.9/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c --- v2.3.9/linux/drivers/sound/wf_midi.c Thu Jan 14 22:59:47 1999 +++ linux/drivers/sound/wf_midi.c Mon Jul 5 19:58:25 1999 @@ -803,7 +803,7 @@ return 0; } -__initfunc (static int detect_wf_mpu (int irq, int io_base)) +static int __init detect_wf_mpu (int irq, int io_base) { if (check_region (io_base, 2)) { @@ -820,8 +820,7 @@ return 0; } -__initfunc (int install_wf_mpu (void)) - +int __init install_wf_mpu (void) { if ((phys_dev->devno = sound_alloc_mididev()) < 0){ diff -u --recursive --new-file v2.3.9/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS --- v2.3.9/linux/drivers/usb/CREDITS Tue Jun 8 10:52:26 1999 +++ linux/drivers/usb/CREDITS Thu Jul 1 10:45:57 1999 @@ -29,7 +29,7 @@ THANKS file in Inaky's driver): The following corporations have helped us in the development -of Linux USB / UUSBD: + of Linux USB / UUSBD: - USAR Systems provided us with one of their excellent USB Evaluation Kits. It allows us to test the Linux-USB driver diff -u --recursive --new-file v2.3.9/linux/drivers/usb/hub.h linux/drivers/usb/hub.h --- v2.3.9/linux/drivers/usb/hub.h Wed Apr 21 05:41:59 1999 +++ linux/drivers/usb/hub.h Thu Jul 8 15:19:55 1999 @@ -12,6 +12,7 @@ /* * Port feature numbers */ +#define USB_PORT_FEAT_CONNECTION 0 #define USB_PORT_FEAT_ENABLE 1 #define USB_PORT_FEAT_SUSPEND 2 #define USB_PORT_FEAT_OVER_CURRENT 3 @@ -40,7 +41,7 @@ #define USB_PORT_STAT_C_OVERCURRENT 0x0008 #define USB_PORT_STAT_C_RESET 0x0010 -/* Characteristics */ +/* wHubCharacteristics (masks) */ #define HUB_CHAR_LPSM 0x0003 #define HUB_CHAR_COMPOUND 0x0004 #define HUB_CHAR_OCPM 0x0018 diff -u --recursive --new-file v2.3.9/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c --- v2.3.9/linux/drivers/usb/ohci-debug.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/ohci-debug.c Sat Jul 3 18:07:29 1999 @@ -119,10 +119,9 @@ (td_toggle < 2) ? " " : (td_toggle & 1) ? "Data1" : "Data0", "ErrorCnt ", td_errcnt); - printk(KERN_DEBUG " ComplCode 0x%x, %sAccessed, %sActive\n", + printk(KERN_DEBUG " ComplCode 0x%x, %sAccessed\n", td_cc, - td_cc_accessed(*td) ? "" : "Not ", - td_active(*td) ? "" : "Not "); + td_cc_accessed(*td) ? "" : "Not "); printk(KERN_DEBUG " %s%s\n", td_allocated(*td) ? "Allocated" : "Free", @@ -159,7 +158,7 @@ if (td_dummy(*cur_td)) break; } - printk(KERN_DEBUG "--- End TD Chain %lx: ---\n", virt_to_bus(td)); + printk(KERN_DEBUG "--- End TD Chain %lx. ---\n", virt_to_bus(td)); } /* show_ohci_td_chain () */ diff -u --recursive --new-file v2.3.9/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c --- v2.3.9/linux/drivers/usb/ohci.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/ohci.c Sat Jul 3 18:07:29 1999 @@ -179,27 +179,27 @@ /* .......... */ -inline void ohci_start_control(struct ohci *ohci) +void ohci_start_control(struct ohci *ohci) { /* tell the HC to start processing the control list */ writel_set(OHCI_USB_CLE, &ohci->regs->control); writel_set(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); } -inline void ohci_start_bulk(struct ohci *ohci) +void ohci_start_bulk(struct ohci *ohci) { /* tell the HC to start processing the bulk list */ writel_set(OHCI_USB_BLE, &ohci->regs->control); writel_set(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); } -inline void ohci_start_periodic(struct ohci *ohci) +void ohci_start_periodic(struct ohci *ohci) { /* enable processing periodic (intr) transfers starting next frame */ writel_set(OHCI_USB_PLE, &ohci->regs->control); } -inline void ohci_start_isoc(struct ohci *ohci) +void ohci_start_isoc(struct ohci *ohci) { /* enable processing isoc. transfers starting next frame */ writel_set(OHCI_USB_IE, &ohci->regs->control); @@ -658,7 +658,7 @@ * dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP * toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1 */ -inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed) +struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed) { /* hardware fields */ td->info = cpu_to_le32(OHCI_TD_CC_NEW | @@ -846,16 +846,20 @@ return 0; /* if cur_buf is 0, all data has been transferred */ - bus_data_end = td->cur_buf ? td->cur_buf : td->buf_end; + if (!td->cur_buf) { + return td->buf_end - bus_data_start + 1; + } + + bus_data_end = td->cur_buf; /* is it on the same page? */ if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) { - result = bus_data_end - bus_data_start + 1; + result = bus_data_end - bus_data_start; } else { /* compute the amount transferred on the first page */ result = 0x1000 - (bus_data_start & 0xfff); /* add the amount done in the second page */ - result += (bus_data_end & 0xfff) + 1; + result += (bus_data_end & 0xfff); } return result; @@ -1190,16 +1194,12 @@ if (stats == USB_ST_NOERROR) req->_bytes_done += len; -#ifdef OHCI_DEBUG - printk(KERN_DEBUG "ohci_bulk_td_handler %d bytes done\n", req->_bytes_done); -#endif - /* call the real completion handler when done or on an error */ if ((stats != USB_ST_NOERROR) || (req->_bytes_done >= req->length && req->completion != NULL)) { *req->bytes_transferred_p += req->_bytes_done; #ifdef OHCI_DEBUG - printk(KERN_DEBUG "usb-ohci: bulk request %p ending after %d bytes\n", req, req->_bytes_done); + printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req); #endif req->completion(stats, buffer, req->_bytes_done, req->dev_id); } @@ -1282,13 +1282,13 @@ #ifdef OHCI_DEBUG -/* if (MegaDebug) { */ - /* complete transaction debugging output (before) */ + if (MegaDebug) { + /* complete request debugging output (before) */ printk(KERN_DEBUG " Bulk ED %lx:\n", virt_to_bus(bulk_ed)); show_ohci_ed(bulk_ed); printk(KERN_DEBUG " Bulk TDs %lx:\n", virt_to_bus(head_td)); show_ohci_td_chain(head_td); -/* } */ + } #endif /* Give the ED to the HC */ @@ -1303,6 +1303,9 @@ static int ohci_bulk_msg_completed(int stats, void *buffer, int len, void *dev_id) { +#ifdef OHCI_DEBUG + printk("ohci_bulk_msg_completed %x, %p, %d, %p\n", stats, buffer, len, dev_id); +#endif if (dev_id != NULL) { int *completion_status = (int *)dev_id; *completion_status = stats; @@ -1320,12 +1323,15 @@ struct ohci_bulk_request_state req; struct ohci_ed *req_ed; - /* ....... */ - #ifdef OHCI_DEBUG printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p); #endif + /* initialize bytes transferred to nothing */ + *bytes_transferred_p = 0; + + /* Hopefully this is similar to the "URP" (USB Request Packet) code + * that michael gee is working on... */ req.usb_dev = usb_dev; req.pipe = pipe; req.data = data; @@ -1345,9 +1351,44 @@ /* FIXME this should to wait for a caller specified time... */ schedule_timeout(HZ*5); + /* it'll only stay in this state of the request never finished */ + if (completion_status == USB_ST_INTERNALERROR) { + struct ohci_device *dev = usb_to_ohci(usb_dev); + struct ohci_regs *regs = dev->ohci->regs; + #ifdef OHCI_DEBUG - printk(KERN_DEBUG "ohci_bulk_msg request completed or timed out w/ status %x\n", completion_status); + printk(KERN_DEBUG "ohci_bulk_msg timing out\n"); #endif + /* XXX This code should go into a function used to stop + * a previously requested bulk transfer. -greg */ + + /* stop the transfer & collect the number of bytes */ + ohci_wait_for_ed_safe(regs, req_ed, HCD_ED_BULK); + + /* Get the number of bytes transferred out of the head TD + * on the ED if it didn't finish while we were waiting. */ + if ( ed_head_td(req_ed) && + (ed_head_td(req_ed) != ed_tail_td(req_ed)) ) { + struct ohci_td *partial_td; + partial_td = bus_to_virt(ed_head_td(req_ed)); + +#ifdef OHCI_DEBUG + if (MegaDebug) { + show_ohci_td(partial_td); + } +#endif + /* Record the bytes as transferred */ + *bytes_transferred_p += ohci_td_bytes_done(partial_td); + + /* If there was an unreported error, return it. + * Otherwise return a timeout */ + completion_status = OHCI_TD_CC_GET(partial_td->info); + if (completion_status == USB_ST_NOERROR) { + completion_status = USB_ST_TIMEOUT; + } + } + + } remove_wait_queue(&bulk_wakeup, &wait); @@ -1356,7 +1397,7 @@ ohci_free_ed(req_ed); /* return it to the pool */ #ifdef OHCI_DEBUG - printk(KERN_DEBUG "ohci_bulk_msg done.\n"); + printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", completion_status, *bytes_transferred_p); #endif return completion_status; @@ -1761,7 +1802,7 @@ struct ohci_td *td; /* used for walking the list */ /* um... isn't this dangerous to do in an interrupt handler? -greg */ - spin_lock(&ohci_edtd_lock); +// spin_lock(&ohci_edtd_lock); /* create the FIFO ordered donelist */ td = ohci_reverse_donelist(ohci); @@ -1832,6 +1873,7 @@ /* insert it back on its ED */ ohci_add_td_to_ed(td, td, td->ed); + ohci_unhalt_ed(td->ed); } else { /* return it to the pool of free TDs */ if (can_auto_free(*td)) @@ -1841,7 +1883,7 @@ td = next_td; } - spin_unlock(&ohci_edtd_lock); +// spin_unlock(&ohci_edtd_lock); } /* ohci_reap_donelist() */ diff -u --recursive --new-file v2.3.9/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h --- v2.3.9/linux/drivers/usb/ohci.h Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/ohci.h Sat Jul 3 18:07:29 1999 @@ -71,7 +71,6 @@ #define td_cc_notaccessed(td) ((le32_to_cpup(&(td).info) >> 29) == 7) #define td_cc_accessed(td) ((le32_to_cpup(&(td).info) >> 29) != 7) #define td_cc_noerror(td) (((le32_to_cpup(&(td).info)) & OHCI_TD_CC) == 0) -#define td_active(td) (!td_cc_noerror((td)) && (td_errorcount((td)) < 3)) #define td_done(td) (td_cc_noerror((td)) || (td_errorcount((td)) == 3)) /* diff -u --recursive --new-file v2.3.9/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.3.9/linux/drivers/usb/printer.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/printer.c Thu Jul 8 15:19:55 1999 @@ -124,6 +124,7 @@ return -EBUSY; } if (!(p->obuf = (char *)__get_free_page(GFP_KERNEL))) { + p->isopen = 0; return -ENOMEM; } @@ -166,7 +167,6 @@ do { char *obuf = p->obuf; unsigned long thistime; - partial = 0; thistime = copy_size = (count > p->maxout) ? p->maxout : count; if (copy_from_user(p->obuf, buffer, copy_size)) @@ -303,7 +303,11 @@ minor_data[i] = PPDATA(dev->private); minor_data[i]->minor = i; minor_data[i]->pusb_dev = dev; - minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16; + /* The max packet size can't be more than 64 (& will be 64 for + * any decent bulk device); this calculation was silly. -greg + * minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16; + */ + minor_data[i]->maxout = 8192; if (minor_data[i]->maxout > PAGE_SIZE) { minor_data[i]->maxout = PAGE_SIZE; } diff -u --recursive --new-file v2.3.9/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.9/linux/drivers/usb/uhci.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/uhci.c Thu Jul 8 15:19:55 1999 @@ -32,14 +32,9 @@ #include #include #include - -#include #include -#include #include - - #include #include #include @@ -70,7 +65,7 @@ return USB_ST_BITSTUFF; if (status & 0x04) { /* CRC/Timeout */ if (dir_out) - return USB_ST_TIMEOUT; + return USB_ST_NORESPONSE; else return USB_ST_CRC; } @@ -104,7 +99,7 @@ if (status) { /* must reset the toggle on first error */ if (uhci_debug) { - printk("Set toggle from %x rval %d\n", (unsigned int)tmp, rval ? *rval : 0); + printk("Set toggle from %x rval %ld\n", (unsigned int)tmp, rval ? *rval : 0); } usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), usb_pipeout(tmp->info), (tmp->info >> 19) & 1); break; @@ -1442,10 +1437,12 @@ /* We need exactly one page (per UHCI specs), how convenient */ uhci->fl = (void *)__get_free_page(GFP_KERNEL); + if (!uhci->fl) + goto au_free_uhci; bus = kmalloc(sizeof(*bus), GFP_KERNEL); if (!bus) - return NULL; + goto au_free_fl; memset(bus, 0, sizeof(*bus)); @@ -1465,7 +1462,7 @@ */ usb = uhci_usb_allocate(NULL); if (!usb) - return NULL; + goto au_free_bus; usb->bus = bus; dev = usb_to_uhci(usb); @@ -1536,6 +1533,18 @@ } return uhci; + +/* + * error exits: + */ + +au_free_bus: + kfree (bus); +au_free_fl: + free_page ((unsigned long)uhci->fl); +au_free_uhci: + kfree (uhci); + return NULL; } diff -u --recursive --new-file v2.3.9/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h --- v2.3.9/linux/drivers/usb/uhci.h Tue Jun 22 14:42:27 1999 +++ linux/drivers/usb/uhci.h Thu Jul 8 15:31:47 1999 @@ -167,12 +167,12 @@ * Linus: * * generic-iso-QH -> dev1-iso-QH -> generic-irq-QH -> dev1-irq-QH -> ... - * | | | | - * End dev1-iso-TD1 End dev1-irq-TD1 - * | - * dev1-iso-TD2 - * | - * .... + * | | | | + * End dev1-iso-TD1 End dev1-irq-TD1 + * | + * dev1-iso-TD2 + * | + * .... * * This may vary a bit (the UHCI docs don't explicitly say you can put iso * transfers in QH's and all of their pictures don't have that either) but diff -u --recursive --new-file v2.3.9/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.9/linux/drivers/usb/usb.c Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/usb.c Thu Jul 8 15:31:47 1999 @@ -260,7 +260,7 @@ static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len) { - int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7); + int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE); int i; if (parsed < 0) @@ -284,7 +284,7 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface_descriptor *interface, unsigned char *ptr, int len) { int i; - int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9); + int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE); int retval; if (parsed < 0) @@ -848,29 +848,40 @@ int usb_get_configuration(struct usb_device *dev) { unsigned int cfgno; - unsigned char buffer[400]; unsigned char * bufptr; - + unsigned char * buffer; + int parse; + + buffer = (unsigned char *) __get_free_page (GFP_KERNEL); + if (!buffer) + return -1; + bufptr = buffer; for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) { unsigned int size; /* Get the first 8 bytes - guaranteed */ - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) + if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) { + __free_page ((struct page *) buffer); return -1; + } /* Get the full buffer */ size = le16_to_cpup((unsigned short *)(bufptr+2)); - if (bufptr+size > buffer+sizeof(buffer)) { + if (bufptr+size > buffer+PAGE_SIZE) { printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); - size = buffer+sizeof(buffer)-bufptr; + size = buffer+PAGE_SIZE-bufptr; } - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) + if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) { + __free_page ((struct page *) buffer); return -1; + } /* Prepare for next configuration */ bufptr += size; } - return usb_parse_configuration(dev, buffer, bufptr - buffer); + parse = usb_parse_configuration(dev, buffer, bufptr - buffer); + __free_page ((struct page *) buffer); + return parse; } int usb_get_stringtable(struct usb_device *dev) diff -u --recursive --new-file v2.3.9/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.9/linux/drivers/usb/usb.h Wed Jun 30 13:38:20 1999 +++ linux/drivers/usb/usb.h Thu Jul 8 15:31:47 1999 @@ -31,9 +31,16 @@ } devrequest; /* - * Class codes + * Device and/or Interface Class codes */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 #define USB_CLASS_HUB 9 +#define USB_CLASS_VENDOR_SPEC 0xff /* * Descriptor types @@ -48,6 +55,28 @@ #define USB_DT_HID 0x21 /* + * Descriptor sizes per descriptor type + */ +#define USB_DT_DEVICE_SIZE 18 +#define USB_DT_CONFIG_SIZE 9 +#define USB_DT_INTERFACE_SIZE 9 +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_HUB_NONVAR_SIZE 7 + +/* + * USB Request Type and Endpoint Directions + */ +#define USB_DIR_OUT 0 +#define USB_DIR_IN 0x80 + +/* + * USB Packet IDs (PIDs) + */ +#define USB_PID_OUT 0xe1 +#define USB_PID_IN 0x69 +#define USB_PID_SETUP 0x2d + +/* * Standard requests */ #define USB_REQ_GET_STATUS 0x00 @@ -97,16 +126,16 @@ #define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE) /* - * Status codes + * Status codes (these follow an OHCI controllers condition codes) */ #define USB_ST_NOERROR 0x0 #define USB_ST_CRC 0x1 #define USB_ST_BITSTUFF 0x2 -#define USB_ST_DTMISMATCH 0x3 +#define USB_ST_DTMISMATCH 0x3 /* data toggle mismatch */ #define USB_ST_STALL 0x4 -#define USB_ST_TIMEOUT 0x5 -#define USB_ST_PIDCHECK 0x6 -#define USB_ST_PIDUNDEF 0x7 +#define USB_ST_NORESPONSE 0x5 /* device not responding/handshaking */ +#define USB_ST_PIDCHECK 0x6 /* Check bits on PID failed */ +#define USB_ST_PIDUNDEF 0x7 /* PID unexpected/undefined */ #define USB_ST_DATAOVERRUN 0x8 #define USB_ST_DATAUNDERRUN 0x9 #define USB_ST_RESERVED1 0xA @@ -118,6 +147,7 @@ /* internal errors */ #define USB_ST_REMOVED 0x100 +#define USB_ST_TIMEOUT 0x110 #define USB_ST_INTERNALERROR -1 /* @@ -275,7 +305,7 @@ struct usb_device { int devnum; /* Device number on USB bus */ int slow; /* Slow device? */ - int maxpacketsize; /* Maximum packet size */ + int maxpacketsize; /* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */ int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ int halted; /* endpoint halts */ struct usb_config_descriptor *actconfig;/* the active configuration */ @@ -342,16 +372,16 @@ * Let's not fall in that trap. We'll just encode it as a simple * unsigned int. The encoding is: * + * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) + * - direction: bit 7 (0 = Host-to-Device, 1 = Device-to-Host) * - device: bits 8-14 * - endpoint: bits 15-18 * - Data0/1: bit 19 - * - direction: bit 7 (0 = Host-to-Device, 1 = Device-to-Host) - * - speed: bit 26 (0 = High, 1 = Low Speed) - * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) + * - speed: bit 26 (00 = Full, 01 = Low Speed) * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk) * * Why? Because it's arbitrary, and whatever encoding we select is really - * up to us. This one happens to share a lot of bit positions with the UCHI + * up to us. This one happens to share a lot of bit positions with the UHCI * specification, so that much of the uhci driver can just mask the bits * appropriately. */ @@ -372,6 +402,7 @@ #define usb_pipebulk(pipe) (usb_pipetype((pipe)) == 3) #define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff) +#define PIPE_DEVEP_MASK 0x0007ff00 /* The D0/D1 toggle bits */ #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1) @@ -393,7 +424,7 @@ return (dev->slow << 26); } -/* Create control pipes.. */ +/* Create various pipes... */ #define usb_sndctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint)) #define usb_rcvctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint) | 0x80) #define usb_sndisocpipe(dev,endpoint) ((0 << 30) | __create_pipe(dev,endpoint)) diff -u --recursive --new-file v2.3.9/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.9/linux/drivers/video/Makefile Wed Jun 30 13:38:20 1999 +++ linux/drivers/video/Makefile Thu Jul 1 10:57:36 1999 @@ -192,9 +192,11 @@ ifeq ($(CONFIG_FB_TGA),y) L_OBJS += tgafb.o +CONFIG_FBGEN_BUILTIN = y else ifeq ($(CONFIG_FB_TGA),m) M_OBJS += tgafb.o + CONFIG_FBGEN_MODULE = y endif endif diff -u --recursive --new-file v2.3.9/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.3.9/linux/drivers/video/fbmem.c Thu May 13 23:48:20 1999 +++ linux/drivers/video/fbmem.c Thu Jul 1 10:57:36 1999 @@ -74,6 +74,7 @@ extern void imsttfb_setup(char *options, int *ints); extern void dnfb_init(void); extern void tgafb_init(void); +extern void tgafb_setup(char *options, int *ints); extern void virgefb_init(void); extern void virgefb_setup(char *options, int *ints); extern void resolver_video_setup(char *options, int *ints); @@ -158,7 +159,7 @@ { "s3trio", s3triofb_init, s3triofb_setup }, #endif #ifdef CONFIG_FB_TGA - { "tga", tgafb_init, NULL }, + { "tga", tgafb_init, tgafb_setup }, #endif #ifdef CONFIG_FB_VIRGE { "virge", virgefb_init, virgefb_setup }, diff -u --recursive --new-file v2.3.9/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c --- v2.3.9/linux/drivers/video/tgafb.c Mon Dec 21 14:48:04 1998 +++ linux/drivers/video/tgafb.c Thu Jul 1 10:57:36 1999 @@ -1,27 +1,29 @@ /* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * - * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1999 Martin Lucina, Tom Zerucha + * + * $Id: tgafb.c,v 1.12 1999/07/01 13:39:23 mato Exp $ * - * This driver is partly based on the original TGA console driver + * This driver is partly based on the original TGA framebuffer device, which + * was partly based on the original TGA console driver, which are * - * Copyright (C) 1995 Jay Estabrook + * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1995 Jay Estabrook * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ - /* KNOWN PROBLEMS/TO DO ===================================================== * * * - How to set a single color register on 24-plane cards? * - * - Hardware cursor (useful for other graphics boards too) - * - * - Support for more resolutions + * - Hardware cursor/other text acceleration methods * * - Some redraws can stall kernel for several seconds + * [This should now be solved by the fast memmove() patch in 2.3.6] * * KNOWN PROBLEMS/TO DO ==================================================== */ @@ -45,477 +47,459 @@ #include