diff -u --recursive --new-file v2.3.99-pre2/linux/CREDITS linux/CREDITS --- v2.3.99-pre2/linux/CREDITS Sun Mar 19 18:35:30 2000 +++ linux/CREDITS Thu Mar 23 10:34:53 2000 @@ -891,6 +891,10 @@ S: 72076 Tübingen S: Germany +N: Justin Guyett +E: jguyett@andrew.cmu.edu +D: via-rhine net driver hacking + N: Danny ter Haar E: dth@cistron.nl D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;) @@ -1143,6 +1147,7 @@ W: http://www.image.dk/~nkbj D: 4.4BSD and NeXTstep filesystem support in the old ufs. D: Openstep filesystem and NeXTstep CDROM support in the new ufs. +D: Replace CPU==[3-6]86 and __i386__ submodel flags by configuration options. D: Danish HOWTO, Linux+FreeBSD mini-HOWTO. S: Dr. Holsts Vej 34, lejl. 164 S: DK-8230 Åbyhøj @@ -1327,6 +1332,13 @@ E: akrebs@altavista.net D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards +N: Greg Kroah-Hartman +E: greg@kroah.com +W: http://www.kroah.com/linux-usb/ +D: USB Serial Converter driver framework, USB Handspring Visor driver +D: ConnectTech WHITEHeat USB driver, Generic USB Serial driver +D: bits and pieces of USB core code. + N: Russell Kroll E: rkroll@exploits.org W: http://www.exploits.org/ @@ -1360,10 +1372,13 @@ S: Germany N: Jaroslav Kysela -E: perex@jcu.cz -W: http://www.pf.jcu.cz/~perex +E: perex@suse.cz +W: http://www.perex.cz D: Original Author and Maintainer for HP 10/100 Mbit Network Adapters -S: Unix Centre of Pedagogical Faculty, University of South Bohemia +D: ISA PnP +S: Sindlovy Dvory 117 +S: 370 01 Ceske Budejovice +S: Czech Republic N: Bas Laarhoven E: bas@vimec.nl @@ -1947,6 +1962,16 @@ S: 91054 Erlangen S: Germany +N: Giuliano Procida +E: myxie@debian.org,gprocida@madge.com +D: Madge Ambassador driver (Collage 155 Server ATM adapter) +D: Madge Horizon driver (Collage 25 and 155 Client ATM adapters) +P: 1024/93898735 D3 9E F4 F7 6D 8D 2F 3A 38 BA 06 7C 2B 33 43 7D +S: Madge Networks +S: Framewood Road +S: Wexham SL3 6PJ +S: United Kingdom + N: Daniel Quinlan E: quinlan@pathname.com W: http://www.pathname.com/~quinlan/ @@ -2037,6 +2062,14 @@ S: 7000 Stuttgart 50 S: Germany +N: Christoph Rohland +E: hans-christoph.rohland@sap.com +E: ch.rohland@gmx.net +D: shm fs, SYSV semaphores, af_unix +S: Neue Heimat Str. 8 +S: D-68789 St.Leon-Rot +S: Germany + N: Stephen Rothwell E: sfr@linuxcare.com W: http://linuxcare.com.au/sfr @@ -2455,6 +2488,7 @@ D: Amiga Buddha and Catweasel chipset IDE D: Atari Falcon chipset IDE D: Amiga Gayle chipset IDE +D: mipsel NEC DDB Vrc-5074 S: C. Huysmansstraat 12 S: B-3128 Baal S: Belgium @@ -2598,6 +2632,10 @@ S: Eichenweg 16 S: 73650 Winterbach S: Germany + +N: Urban Widmark +E: urban@svenskatest.se +D: via-rhine, misc net driver hacking N: Marco van Wieringen E: mvw@planets.elm.net diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.99-pre2/linux/Documentation/Changes Sun Mar 19 18:35:30 2000 +++ linux/Documentation/Changes Wed Mar 22 09:39:11 2000 @@ -73,8 +73,11 @@ =================== To use System V shared memory, you have to mount the shm filesystem -somewhere and put the mountpoint into /proc/sys/kernel/shmpath. -Default is /var/shm. +somewhere. You can do that automatically by adding this line to /etc/fstab: + +none /var/shm shm defaults 0 0 + +Remember to create the mountpoint directory; it does not have to be /var/shm. now performs a cold reboot instead of a warm reboot for increased hardware compatibility. If you want a warm reboot and diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.99-pre2/linux/Documentation/Configure.help Sun Mar 19 18:35:30 2000 +++ linux/Documentation/Configure.help Thu Mar 23 08:38:57 2000 @@ -186,10 +186,22 @@ CONFIG_NOHIGHMEM If you are compiling a kernel which will never run on a machine with more than 1 Gigabyte total physical RAM, answer "off" - here (default choice). + here (default choice). This will result in the old "3GB/1GB" + virtual/physical memory split. 3BG are mapped so as each processus + sees a 3GB virtual memory space. + The remaining part of the 4G virtual memory space is used by the + kernel to 'permanently map' as much physical memory as possible. + Certain types of applications perform better if there is more + 'permanently mapped' kernel memory. + Certain types of applications (eg. database servers) perform + better if they have as much virtual memory per process as possible. Linux can use up to 64 Gigabytes of physical memory on x86 systems. - High memory is all the physical RAM that could not be directly + However 32-bit x86 processors have only 4 Gigabytes of virtual memory + space. + + Any potentially remaining part of physical memory is called + 'high memory' that is all the physical RAM that could not be directly mapped by the kernel - ie. 3GB if there is 4GB RAM in the system, 7GB if there is 8GB RAM in the system. @@ -202,6 +214,13 @@ processors (PPro and better). NOTE: The "64GB" kernel will not boot CPUs that not support PAE! + The actual amount of total physical memory will either be + autodetected or can be forced by using a kernel command line option + such as "mem=256M". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time. The lilo procedure is also explained in the + SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto .) + Normal PC floppy disk support CONFIG_BLK_DEV_FD If you want to use the floppy disk drive(s) of your PC under Linux, @@ -372,7 +391,7 @@ Useful information about large (>540 MB) IDE disks, multiple interfaces, what to do if ATA/IDE devices are not automatically detected, sound card ATA/IDE ports, module support, and other topics, is - contained in Documentation/ata-ide.txt. For detailed information about + contained in Documentation/ide.txt. For detailed information about hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . @@ -494,7 +513,7 @@ along with other IDE devices, as "hdb" or "hdc", or something similar, and will be mapped to a character device such as "ht0" (check the boot messages with dmesg). Be sure to consult the - drivers/block/ide-tape.c and Documentation/ide.txt files for usage + drivers/ide/ide-tape.c and Documentation/ide.txt files for usage information. If you want to compile the driver as a module ( = code which can be @@ -627,7 +646,7 @@ the latest version of the hdparm utility from ftp://metalab.unc.edu/pub/Linux/system/hardware/ . - Read the comments at the beginning of drivers/block/ide-dma.c and the + Read the comments at the beginning of drivers/ide/ide-dma.c and the file Documentation/ide.txt for more information. It is safe to say Y to this question. @@ -707,12 +726,12 @@ should say Y here, and preferably also to "Use DMA by default when available". - Please read the comments at the top of drivers/block/aec6210.c + Please read the comments at the top of drivers/ide/aec6210.c If you say Y here, then say Y to "Use DMA by default when available" as well. AEC6210 Tuning support (WIP) CONFIG_AEC6210_TUNING - Please read the comments at the top of drivers/block/aec6210.c + Please read the comments at the top of drivers/ide/aec6210.c If unsure, say N. ALI M15x3 chipset support @@ -721,16 +740,28 @@ 1535, 1535D onboard chipsets. It also tests for Simplex mode and enables normal dual channel support. - Please read the comments at the top of drivers/block/alim15x3.c + Please read the comments at the top of drivers/ide/alim15x3.c If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. +ALI M15x3 WDC support (DANGEROUS) +CONFIG_WDC_ALI15X3 + This allows for UltraDMA support for WDC drives that ignore CRC checking. + You are a fool for enabling this option, but there have been requests. + DO NOT COMPLAIN IF YOUR DRIVE HAS FS CORUPTION, IF YOU ENABLE THIS! + No one will listen, just laugh for ignoring this SERIOUS WARNING. + + Using this option can allow WDC drives to run at ATA-4/5 transfer rates with + only an ATA-2 support structure. + + SAY NO! + AMD7409 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_AMD7409 This driver ensures (U)DMA support for AMD756 Viper chipset. - Please read the comments at the top of drivers/block/amd7409.c + Please read the comments at the top of drivers/ide/amd7409.c If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -776,7 +807,7 @@ HPT34X AUTODMA support (WIP) CONFIG_HPT34X_AUTODMA This is a dangerous thing to attempt currently! - Please read the comments at the top of drivers/block/hpt34x.c + Please read the comments at the top of drivers/ide/hpt34x.c If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -795,7 +826,7 @@ 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/hpt366.c + Please read the comments at the top of drivers/ide/hpt366.c If you say Y here, then say Y to "Use DMA by default when available" as well. HPT366 Fast Interrupts (WIP) @@ -813,12 +844,12 @@ This driver adds detection and support for the NS87415 chip (used in SPARC64, among others). - Please read the comments at the top of drivers/block/ns87415.c. + Please read the comments at the top of drivers/ide/ns87415.c. OPTi 82C621 enhanced support (EXPERIMENTAL) CONFIG_BLK_DEV_OPTI621 This is a driver for the OPTi 82C621 EIDE controller. - Please read the comments at the top of drivers/block/opti621.c. + Please read the comments at the top of drivers/ide/opti621.c. Intel PIIXn chipsets support CONFIG_BLK_DEV_PIIX @@ -827,7 +858,7 @@ PIO 0-4 mode settings, this allows dynamic tuning of the chipset via the standard end-user tool 'hdparm'. - Please read the comments at the top of drivers/block/piix.c + Please read the comments at the top of drivers/ide/piix.c Should also include "PIIXn Tuning support" CONFIG_PIIX_TUNING If unsure, say Y. @@ -866,7 +897,7 @@ 1.11 or newer required. If you say Y here, then say Y to "Use DMA by default when available" as well. - Please read the comments at the top of drivers/block/pdc202xx.c + Please read the comments at the top of drivers/ide/pdc202xx.c If unsure, say N. @@ -876,7 +907,7 @@ 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 + Please read the comments at the top of drivers/ide/pdc202xx.c If unsure, say N. @@ -898,7 +929,7 @@ This driver adds support for bus master DMA transfers using the Tekram TRM290 PCI IDE chip. Volunteers are needed for further tweaking and development. - Please read the comments at the top of drivers/block/trm290.c. + Please read the comments at the top of drivers/ide/trm290.c. VIA82CXXX chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_VIA82CXXX @@ -909,7 +940,7 @@ If no command line is provided, it will try to set fifo configuration at its best. It will allow you to get a proc/ide/via display (while running a "cat") provided you enabled "proc" support. - Please read the comments at the top of drivers/block/via82cxxx.c + Please read the comments at the top of drivers/ide/via82cxxx.c If you say Y here, then say Y to "Use DMA by default when available" as well. @@ -943,14 +974,14 @@ boot parameter. It enables support for the secondary IDE interface of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster I/O speeds to be set as well. See the files Documentation/ide.txt - and drivers/block/ali14xx.c for more info. + and drivers/ide/ali14xx.c for more info. DTC-2278 support CONFIG_BLK_DEV_DTC2278 This driver is enabled at runtime using the "ide0=dtc2278" kernel boot parameter. It enables support for the secondary IDE interface of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the Documentation/ide.txt and drivers/block/dtc2278.c + well. See the Documentation/ide.txt and drivers/ide/dtc2278.c files for more info. Holtek HT6560B support @@ -958,7 +989,7 @@ This driver is enabled at runtime using the "ide0=ht6560b" kernel boot parameter. It enables support for the secondary IDE interface of the Holtek card, and permits faster I/O speeds to be set as well. - See the Documentation/ide.txt and drivers/block/ht6560b.c files for + See the Documentation/ide.txt and drivers/ide/ht6560b.c files for more info. PROMISE DC4030 support (EXPERIMENTAL) @@ -969,13 +1000,13 @@ attached to the secondary interface. CDROM and TAPE devices are not supported yet. This driver is enabled at runtime using the "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt - and drivers/block/pdc4030.c files for more info. + and drivers/ide/pdc4030.c files for more info. QDI QD6580 support CONFIG_BLK_DEV_QD6580 This driver is enabled at runtime using the "ide0=qd6580" kernel boot parameter. It permits faster I/O speeds to be set. See the - files Documentation/ide.txt and drivers/block/qd6580.c for more + files Documentation/ide.txt and drivers/ide/qd6580.c for more info. UMC 8672 support @@ -983,7 +1014,7 @@ This driver is enabled at runtime using the "ide0=umc8672" kernel boot parameter. It enables support for the secondary IDE interface of the UMC-8672, and permits faster I/O speeds to be set as well. - See the files Documentation/ide.txt and drivers/block/umc8672.c for + See the files Documentation/ide.txt and drivers/ide/umc8672.c for more info. Amiga builtin Gayle IDE interface support @@ -2135,6 +2166,14 @@ Say Y here to enable support in the dumb serial driver to support the HUB6 card. +Support for hot-pluggable devices +CONFIG_HOTPLUG + Say Y here to enable support for hot plugin of certain hardware such as + PCMCIA cards and the like. + + At this moment, few drivers support it, but as they get converted to use the + new ressource allocator/manager, their number will increase. + PCMCIA serial device support CONFIG_PCMCIA_SERIAL_CS Say Y here to enable support for 16-bit PCMCIA serial devices, @@ -2728,6 +2767,27 @@ CONFIG_FB_S3TRIO If you have a S3 Trio say Y. Say N for S3 Virge. +3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL) +CONFIG_FB_3DFX + This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 chips. + Say Y if you have such a graphics board. + + The driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called tdfxfb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +nVidia Riva support (EXPERIMENTAL) +CONFIG_FB_RIVA + This driver supports graphics boards with the nVidia Riva (aka TNTx) + chips. + Say Y if you have such a graphics board. + + The driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called rivafb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + ATI Mach64 display support (EXPERIMENTAL) CONFIG_FB_ATY This driver supports graphics boards with the ATI Mach64 chips. @@ -2808,19 +2868,36 @@ running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called vga16fb.o. +Select other compiled-in fonts +CONFIG_FBCON_FONTS + Say Y here if you would like to use fonts other than the default your frame + buffer console usually use. + + Note that the answer to this question won't directly affect the kernel: + saying N will just cause this configure script to skip all the questions + about foreign fonts. + + If unsure, say N (the default choices are safe). + VGA 8x16 font CONFIG_FONT_8x16 This is the "high resolution" font for the VGA frame buffer (the one - provided by the text console 80x25 mode. + provided by the VGA text console 80x25 mode. + + If unsure, say Y. Support only 8 pixels wide fonts CONFIG_FBCON_FONTWIDTH8_ONLY Answer Y here will make the kernel provide only the 8x8 fonts (these are the less readable). + If unsure, say N. + Sparc console 8x16 font CONFIG_FONT_SUN8x16 - This is the high resolution console font for Sun machines. Say Y. + This is the high resolution console font for Sun machines. + + Say Y. Sparc console 12x22 font (not supported by all drivers) CONFIG_FONT_SUN12x22 @@ -2834,6 +2911,7 @@ provided by the text console 80x50 (and higher) modes. Note this is a poor quality font. The VGA 8x16 font is quite a lot more readable. + Given the resolution provided by the frame buffer device, answer N here is safe. @@ -2844,13 +2922,25 @@ includes a server that supports the frame buffer device directly (XF68_FBDev). +HGA monochrome support (EXPERIMENTAL) +Hercules mono graphics console (EXPERIMENTAL) +CONFIG_FBCON_HGA + Say Y here if you have a Hercules mono graphics card. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called hgafb.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + As this card technology is 15 years old, most people will answer N here. + Matrox unified accelerated driver (EXPERIMENTAL) CONFIG_FB_MATROX Say Y here if you have Matrox Millennium, Matrox Millennium II, Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox - Mystique G200, Matrox Millennium G200 or Matrox Marvel G200 video - card in your box. At this time, support for the G100, Mystique G200 - and Marvel G200 is untested. + Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video or + Matrox G400 card in your box. At this time, support for the G100, + Mystique G200 and Marvel G200 is untested. This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). @@ -3784,6 +3874,12 @@ See Documentation/networking/decnet.txt for more information. +Appletalk interfaces support +CONFIG_APPLETALK + AppleTalk is the way Apple computers speak to each other on a + network. If your Linux box is connected to such a network and you + want to join the conversation, say Y. + AppleTalk DDP CONFIG_ATALK AppleTalk is the way Apple computers speak to each other on a @@ -6069,7 +6165,7 @@ with a similar Bonding Linux driver, a Cisco 5500 switch or a SunTrunking SunSoft driver. - This is similar to the EQL driver, but it merge etherner segments instead + This is similar to the EQL driver, but it merge ethernet segments instead of serial lines. If you want to compile this as a module ( = code which can be @@ -6718,6 +6814,17 @@ Say Y here if you have a native Econet network card installed in your computer. +Wan interfaces support +CONFIG_WAN + Wide Area Networks (WANs), such as X.25, frame relay and leased + lines, are used to interconnect Local Area Networks (LANs) over vast + distances with data transfer rates significantly higher than those + achievable with commonly used asynchronous modem connections. + + Say Y here if you want to use such interconnections. + + It is safe to say N. Most people won't need it. + WAN Router CONFIG_WAN_ROUTER Wide Area Networks (WANs), such as X.25, frame relay and leased @@ -6743,6 +6850,18 @@ If unsure, say N. +WAN router drivers +CONFIG_WAN_ROUTER_DRIVERS + Wide Area Networks (WANs), such as X.25, frame relay and leased + lines, are used to interconnect Local Area Networks (LANs) over vast + distances with data transfer rates significantly higher than those + achievable with commonly used asynchronous modem connections. + Usually, a quite expensive external device called a `WAN router' is + needed to connect to a WAN. + + Say Y here will enable the kernel to a??? as a WAN router betwenn LAN by + means of WAN adapters. + Fast switching (read help!) CONFIG_NET_FASTROUTE Saying Y here enables direct NIC-to-NIC (NIC = Network Interface @@ -7037,8 +7156,14 @@ The module will be called cosa.o. For general information about modules read Documentation/modules.txt. -# Fibre Channel driver support -# CONFIG_NET_FC +Fibre Channel driver support +CONFIG_NET_FC + Say Y here provide support for storage arrays connected to + the system using Fibre Optic and the "X3.269-199X Fibre Channel + Protocol for SCSI" specification. You'll also need the generic SCSI + support, as well as the drivers for the storage array itself and + for the interface adapter such as SOC or SOC+. This subsystem could even + serve for IP networking, with some code extensions. If unsure, say N. # Interphase 5526 Tachyon chipset based adaptor support # CONFIG_IPHASE5526 @@ -9154,6 +9279,21 @@ The module will be called dc2xx.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. + +USB Mustek MDC800 Digital Camera Support +CONFIG_USB_MDC800 + Say Y here if you want to connect this type of still camera to + your computer's USB port. This driver can be used with gphoto 0.4.3 + and higher (look at www.gphoto.org). + To use it create a devicenode with mknod /dev/mustek c 10 171 and + configure it in your software. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mdc800.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + USB Mass Storage support CONFIG_USB_STORAGE Say Y here if you want to connect USB mass storage devices to your @@ -9473,6 +9613,23 @@ say M here and read Documentation/modules.txt. The module will be called vfat.o. +Compressed ROM file system support +CONFIG_CRAMFS + This option provides support for CramFs (Compressed ROM File System). + Cramfs is designed to be a simple, small, and compressed file system for ROM + based embedded systems. + CramFs is read-only, limited to 256MB file systems (with 16MB files), don't + support neither 16/32 bits uid/gid nor hard links. Neither are timestamps. + It isn't endian aware. + + See Documentation/filesystems/cramfs.txt and fs/cramfs/README + for further information. + + If you want to compile this 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 cramfs.o. + UMSDOS: Unix-like file system on top of standard MSDOS fs CONFIG_UMSDOS_FS Say Y here if you want to run Linux from within an existing DOS @@ -9871,7 +10028,9 @@ Note that the answer to this question won't directly affect the kernel: saying N will just cause this configure script to skip all - the questions about foreign partitioning schemes. If unsure, say N. + the questions about foreign partitioning schemes. + + If unsure, say N. Alpha OSF partition support CONFIG_OSF_PARTITION @@ -11375,11 +11534,17 @@ This enable the kernel to lower the requested computer power by making some devices enter in lower power levels (standy, sleep, ... modes). Basically, this let you save power. + Two majors interfaces exist between the hardware and the OS, the older Advanced Power Management (APM) and the newer Advanced Configuration and Power Interface (ACPI). + Both are supported by the Linux Kernel. + Note that on some architectures (such as ia32), the idle task perform hlt + instructions which makes the CPU enter a low power mode. This can be seen as + the first kernel PM level. + Enter S1 for sleep (EXPERIMENTAL) CONFIG_ACPI_S1_SLEEP This enable ACPI compliant devices to enter level 1 of ACPI saving @@ -12882,22 +13047,12 @@ an ISDN-fax-machine. This must be supported by the lowlevel driver also. See Documentation/isdn/README.fax for more information. -AVM CAPI2.0 support -CONFIG_ISDN_DRV_AVMB1 - This enables support for the AVM B1/T1 ISDN networking cards.In - addition, a CAPI (Common ISDN Application Programming Interface, a +CAPI2.0 support +CONFIG_ISDN_CAPI + This provides the CAPI (Common ISDN Application Programming Interface, a standard making it easy for programs to access ISDN hardware, see - http://www.capi.org/; to browse the WWW, you need to have access to - a machine on the Internet that has a program like lynx or netscape) - interface for this card is provided. In order to use this card, - additional firmware is necessary, which has to be downloaded into - the card using a utility which is distributed separately. Please - read the file Documentation/isdn/README.avmb1. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called avmb1.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + http://www.capi.org/. This is needed for AVM's set of active ISDN + controllers like B1, T1, M1. AVM B1 ISA support CONFIG_ISDN_DRV_AVMB1_B1ISA @@ -12907,6 +13062,10 @@ CONFIG_ISDN_DRV_AVMB1_B1PCI Enable support for the PCI version of the AVM B1 card. +AVM B1 PCI V4 support +CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + Enable support for the V4 version of AVM B1 PCI card. + AVM T1/T1-B ISA support CONFIG_ISDN_DRV_AVMB1_T1ISA Enable support for the AVM T1 T1B card. @@ -12921,6 +13080,11 @@ Enable support for the AVM T1 T1B card. Note: This is a PRI card and handle 30 B-channels. +AVM C4 support +CONFIG_ISDN_DRV_AVMB1_C4 + Enable support for the AVM C4 PCI card. + This card handle 4 BRI ISDN lines (8 channels). + Verbose reason code reporting (kernel size +=7K) CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON If you say Y here, the AVM B1 driver will give verbose reasons for @@ -13144,7 +13308,7 @@ say M here and read Documentation/modules.txt. The module will be called ohci1394.o. -RAW IEEE 1394 I/O support +Raw IEEE 1394 I/O support CONFIG_IEEE1394_RAWIO Say Y here if you want support for the raw device. This is generally a good idea, so you should say Y here. The raw device enables @@ -13155,6 +13319,17 @@ say M here and read Documentation/modules.txt. The module will be called raw1394.o. +Excessive debugging output +CONFIG_IEEE1394_VERBOSEDEBUG + If you say Y here, you will get very verbose debugging logs from the + subsystem which includes a dump of the header of every sent and + received packet. This can amount to a high amount of data collected + in a very short time which is usually also saved to disk by the + system logging daemons. + + Say Y if you really want or need the debugging output, everyone else + says N. + # # m68k-specific kernel options # Documented by Chris Lawrence et al. @@ -13193,6 +13368,14 @@ If you plan to try to use the kernel on such a machine say Y here. Everybody else says N. +Sun 3X support +CONFIG_SUN3X + This option enables support for the Sun 3x series of workstations. Be + warned that this support is very experimental. You will also want to + say Y to 68020 support and N to the other processors below. + + If you don't want to compile a kernel for a Sun 3x, say N. + Sun 3 support CONFIG_SUN3 This option enables support for the Sun 3 series of workstations. Be @@ -13256,8 +13439,8 @@ mantissa and round slightly incorrect, what is more then enough for normal usage. -Advanced processor options -CONFIG_ADVANCED_CPU +Advanced configuration options +CONFIG_ADVANCED This gives you access to some advanced options for the CPU. The defaults should be fine for most users, but these options may make it possible for you to improve performance somewhat if you know what @@ -14223,45 +14406,6 @@ If you have any questions or comments about the Compaq Personal Server, send e-mail to skiff@crl.dec.com - -Virtual/Physical Memory Split -CONFIG_1GB - If you are compiling a kernel which will never run on a machine - with more than 1 Gigabyte total physical RAM, answer "3GB/1GB" - here (default choice). - - On 32-bit x86 systems Linux can use up to 64 Gigabytes of physical - memory. However 32-bit x86 processors have only 4 Gigabytes of - virtual memory space. This option specifies the maximum amount of - virtual memory space one process can potentially use. Certain types - of applications (eg. database servers) perform better if they have - as much virtual memory per process as possible. - - The remaining part of the 4G virtual memory space is used by the - kernel to 'permanently map' as much physical memory as possible. - Certain types of applications perform better if there is more - 'permanently mapped' kernel memory. - - [WARNING! Certain boards do not support PCI DMA to physical addresses - bigger than 2 Gigabytes. Non-DMA-able memory must not be permanently - mapped by the kernel, thus a 1G/3G split will not work on such boxes.] - - As you can see there is no 'perfect split' - the fundamental - problem is that 4G of 32-bit virtual memory space is short. So - you'll have to pick your own choice - depending on the application - load of your box. A 2G/2G split is typically a good choice for a - generic Linux server with lots of RAM. - - Any potentially remaining (not permanently mapped) part of physical - memory is called 'high memory'. How much total high memory the kernel - can handle is influenced by the (next) High Memory configuration option. - - The actual amount of total physical memory will either be - autodetected or can be forced by using a kernel command line option - such as "mem=256M". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time. The lilo procedure is also explained in the - SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto .) Math emulation CONFIG_NWFPE diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.3.99-pre2/linux/Documentation/DocBook/Makefile Sun Mar 19 18:35:30 2000 +++ linux/Documentation/DocBook/Makefile Tue Mar 21 11:03:17 2000 @@ -26,8 +26,11 @@ $(TOPDIR)/arch/i386/kernel/mca.c \ $(TOPDIR)/arch/i386/kernel/mtrr.c \ $(TOPDIR)/drivers/char/misc.c \ - $(TOPDIR)/drivers/char/serial.c \ $(TOPDIR)/drivers/char/videodev.c \ + $(TOPDIR)/drivers/net/net_init.c \ + $(TOPDIR)/drivers/net/8390.c \ + $(TOPDIR)/drivers/char/serial.c \ + $(TOPDIR)/drivers/pci/pci.c \ $(TOPDIR)/drivers/sound/sound_core.c \ $(TOPDIR)/drivers/sound/sound_firmware.c \ $(TOPDIR)/drivers/net/wan/syncppp.c \ diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.3.99-pre2/linux/Documentation/DocBook/kernel-api.tmpl Sun Mar 19 18:35:30 2000 +++ linux/Documentation/DocBook/kernel-api.tmpl Tue Mar 21 11:03:17 2000 @@ -49,7 +49,7 @@ - Miscellaneous Device + Miscellaneous Devices !Edrivers/char/misc.c @@ -58,6 +58,12 @@ !Edrivers/char/videodev.c + + Network devices +!Idrivers/net/net_init.c +!Edrivers/net/8390.c + + Sound Devices !Edrivers/sound/sound_core.c @@ -87,6 +93,11 @@ Z85230 Support Library !Edrivers/net/wan/z85230.c + + + + PCI Support Library +!Edrivers/pci/pci.c diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.3.99-pre2/linux/Documentation/devices.tex Fri Jan 7 19:13:21 2000 +++ linux/Documentation/devices.tex Wed Dec 31 16:00:00 1969 @@ -1,2209 +0,0 @@ -\documentstyle{article} -% $Id: devices.tex,v 1.14 1998/08/10 22:39:24 hpa Exp $ -% --------------------------------------------------------------------------- -% Adopt somewhat reasonable margins, so it doesn't take a million -% pages to print... :-) If you're actually putting this in print, you -% may wish to change these. -\oddsidemargin=0in -\textwidth=6.5in -\topmargin=0in -\headheight=0.5in -\headsep=0.25in -\textheight=7.5in -\footskip=0.75in -\footheight=0.5in -% -\begin{document} -\newcommand{\file}{\tt} % Style to use for a filename -\newcommand{\url}{\it} % Style to use for an URL -\newcommand{\hex}{\tt} % Style to use for a hex number -\newcommand{\ud}{(Under development)} % Abbreviation -\newcommand{\1}{\({}^1\)} -\newcommand{\2}{\({}^2\)} -\newcommand{\3}{\({}^3\)} -\newcommand{\4}{\({}^4\)} -\newlength{\dig} -\settowidth{\dig}{0} % Get width of digits -\newcommand{\num}[2]{\makebox[#1\dig][r]{#2}} -\newcommand{\major}[4]{\num{3}{#1}#2 \> #3 \> #4 \\} -\newcommand{\minor}[3]{\> \> \num{3}{#1} \> {\file #2} \> #3 \\} -\newcommand{\minordots}{\> \> \> \dots \\} -\newenvironment{devicelist}% - {\begin{tabbing}% -000--000 \= blockxxx \= 000 \= {\file /dev/input/keyboardxxx} \= foo \kill}% - {\end{tabbing}} -\newcommand{\link}[4]{{\file #1} \> {\file #2} \> #3 \> #4 \\} -\newcommand{\vlink}[4]{{\file #1} \> {\em #2 \/} \> #3 \> #4 \\} -\newcommand{\node}[3]{{\file #1} \> #2 \> #3 \\} -\newcommand{\tum}{$''$} -\newenvironment{nodelist}% - {\begin{tabbing}% -{\file /dev/crambamboli} \= {\file /proc/self/fd/99} \= symbolicxxx \= -foo \kill}% - {\end{tabbing}} -% -% If you reformat this document, *please* make sure this information -% gets included! This list changes frequently, so it is crucial to -% know the date of the revision. -% -\title{{\bf Linux Allocated Devices}} -\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: August 10, 1998} -\maketitle -% -\noindent -This list is the Linux Device List, the official registry of allocated -device numbers and {\file /dev} directory nodes for the Linux -operating system. - -The latest version of this list is included with the Linux kernel -sources in \LaTeX\ and ASCII form. It is also available separately -from {\url ftp://ftp.kernel.org/pub/linux/docs/device-list/}. In case -of discrepancy between the text and \LaTeX\ versions, the \LaTeX\ -version is authoritative. - -This document is included by reference into the Linux Filesystem -Standard (FSSTND). The FSSTND is available from -{\url ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/}. - -Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga -platform only. Allocations marked (68k/Atari) apply to Linux/68k on -the Atari platform only. - -This document is in the public domain. The author requests, however, -that semantically altered versions are not distributed without -permission of the author, assuming the author can be contacted without -an unreasonable effort. - -In particular, please don't sent patches for this list to Linus, at -least not without contacting me first. - -I do not have any information about these devices beyond what appears -on this list. Any such information requests will be deleted without -reply. - -\section{How to submit a device entry} - -To have a major number allocated, or a minor number in situations -where that applies (e.g. busmice), please contact me with the -appropriate device information. Also, if you have additional -information regarding any of the devices listed below, or if I have -made a mistake, I would greatly appreciate a note. - -I do, however, make two requests about the nature of your report. -This is necessary for me to be able to keep this list up to date and -correct in a timely manner. First of all, {\em please\/} include the -word ``device'' in the subject so your mail won't accidentally get -buried! I receive hundreds of email messages a day, so mail sent with -other subjects may very well get lost in the avalanche. - -Second, please include a description of the device {\em in the same -format as this list\/}. The reason for this is that it is the only -way I have found to ensure I have all the requisite information to -publish your device and avoid conflicts. - -Your cooperation is appreciated. - -\section{Major numbers} - -\begin{devicelist} -\major{ 0}{}{ }{Unnamed devices (e.g. non-device mounts)} -\major{ 1}{}{char }{Memory devices} -\major{ }{}{block}{RAM disk} -\major{ 2}{}{char }{Pseudo-TTY masters} -\major{ }{}{block}{Floppy disks} -\major{ 3}{}{char }{Pseudo-TTY slaves} -\major{ }{}{block}{First MFM, RLL or IDE hard disk/CD-ROM interface} -\major{ 4}{}{char }{TTY devices} -\major{ 5}{}{char }{Alternate TTY devices} -\major{ 6}{}{char }{Parallel printer devices} -\major{ 7}{}{char }{Virtual console access devices} -\major{ }{}{block}{Loopback devices} -\major{ 8}{}{block}{SCSI disk devices (0-15)} -\major{ 9}{}{char }{SCSI tape devices} -\major{ }{}{block}{Metadisk (RAID) devices} -\major{10}{}{char }{Non-serial mice, misc features} -\major{11}{}{char }{Raw keyboard device} -\major{ }{}{block}{SCSI CD-ROM devices} -\major{12}{}{char }{QIC-02 tape} -\major{ }{}{block}{MSCDEX CD-ROM callback support} -\major{13}{}{char }{PC speaker} -\major{ }{}{block}{8-bit MFM/RLL/IDE controller} -\major{14}{}{char }{Sound card} -\major{ }{}{block}{BIOS harddrive callback support} -\major{15}{}{char }{Joystick} -\major{ }{}{block}{Sony CDU-31A/CDU-33A CD-ROM} -\major{16}{}{char }{Non-SCSI scanners} -\major{ }{}{block}{GoldStar CD-ROM} -\major{17}{}{char }{Chase serial card} -\major{ }{}{block}{Optics Storage CD-ROM} -\major{18}{}{char }{Chase serial card -- alternate devices} -\major{ }{}{block}{Sanyo CD-ROM} -\major{19}{}{char }{Cyclades serial card} -\major{ }{}{block}{``Double'' compressed disk} -\major{20}{}{char }{Cyclades serial card -- alternate devices} -\major{ }{}{block}{Hitachi CD-ROM} -\major{21}{}{char }{Generic SCSI access} -\major{ }{}{block }{Acorn MFM hard drive interface} -\major{22}{}{char }{Digiboard serial card} -\major{ }{}{block}{Second IDE hard disk/CD-ROM interface} -\major{23}{}{char }{Digiboard serial card -- alternate devices} -\major{ }{}{block}{Mitsumi proprietary CD-ROM} -\major{24}{}{char }{Stallion serial card} -\major{ }{}{block}{Sony CDU-535 CD-ROM} -\major{25}{}{char }{Stallion serial card -- alternate devices} -\major{ }{}{block}{First Matsushita (Panasonic/SoundBlaster) CD-ROM} -\major{26}{}{char }{Quanta WinVision frame grabber} -\major{ }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM} -\major{27}{}{char }{QIC-117 tape} -\major{ }{}{block}{Third Matsushita (Panasonic/SoundBlaster) CD-ROM} -\major{28}{}{char }{Stallion serial card -- card programming} -\major{ }{}{char }{Atari SLM ACSI laser printer (68k/Atari)} -\major{ }{}{block}{Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM} -\major{ }{}{block}{ACSI disk/CD-ROM (68k/Atari)} -\major{29}{}{char }{Universal frame buffer} -\major{ }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM} -\major{30}{}{char }{iBCS-2 compatibility devices} -\major{ }{}{block}{Philips LMS CM-205 CD-ROM} -\major{31}{}{char }{MPU-401 MIDI} -\major{ }{}{block}{ROM/flash memory card} -\major{32}{}{char }{Specialix serial card} -\major{ }{}{block}{Philips LMS CM-206 CD-ROM} -\major{33}{}{char }{Specialix serial card -- alternate devices} -\major{ }{}{block}{Third IDE hard disk/CD-ROM interface} -\major{34}{}{char }{Z8530 HDLC driver} -\major{ }{}{block}{Fourth IDE hard disk/CD-ROM interface} -\major{35}{}{char }{tclmidi MIDI driver} -\major{ }{}{block}{Slow memory ramdisk} -\major{36}{}{char }{Netlink support} -\major{ }{}{block}{MCA ESDI hard disk} -\major{37}{}{char }{IDE tape} -\major{ }{}{block}{Zorro II ramdisk} -\major{38}{}{char }{Myricom PCI Myrinet board} -\major{ }{}{block}{Reserved for Linux/AP+} -\major{39}{}{char }{ML-16P experimental I/O board} -\major{ }{}{block}{Reserved for Linux/AP+} -\major{40}{}{char }{Matrox Meteor frame grabber} -\major{ }{}{block}{Syquest EZ135 parallel port removable drive} -\major{41}{}{char }{Yet Another Micro Monitor} -\major{ }{}{block}{MicroSolutions BackPack parallel port CD-ROM} -\major{42}{}{}{Demo/sample use} -\major{43}{}{char }{isdn4linux virtual modem} -\major{ }{}{block}{Network block devices} -\major{44}{}{char }{isdn4linux virtual modem -- alternate devices} -\major{ }{}{block}{Flash Translation Layer (FTL) filesystems} -\major{45}{}{char }{isdn4linux ISDN BRI driver} -\major{ }{}{block}{Parallel port IDE disk devices} -\major{46}{}{char }{Comtrol Rocketport serial card} -\major{ }{}{block}{Parallel port ATAPI CD-ROM devices} -\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices} -\major{ }{}{block}{Parallel port ATAPI disk devices} -\major{48}{}{char }{SDL RISCom serial card} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{49}{}{char }{SDL RISCom serial card -- alternate devices} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{50}{}{char}{Reserved for GLINT} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{51}{}{char }{Baycom radio modem} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{54}{}{char }{Electrocardiognosis Holter serial card} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{55}{}{char }{DSP56001 digital signal processor} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\major{56}{}{char }{Apple Desktop Bus} -\major{ }{}{block}{Fifth IDE hard disk/CD-ROM interface} -\major{57}{}{char }{Hayes ESP serial card} -\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface} -\major{58}{}{char }{Hayes ESP serial card -- alternate devices} -\major{ }{}{block}{Reserved for logical volume manager} -\major{59}{}{char }{sf firewall package} -\major{60}{--63}{}{Local/experimental use} -\major{64}{}{char }{ENskip kernel encryption package} -\major{65}{}{char }{Sundance ``plink'' Transputer boards} -\major{ }{}{block}{SCSI disk devices (16-31)} -\major{66}{}{char }{YARC PowerPC PCI coprocessor card} -\major{ }{}{block}{SCSI disk devices (32-47)} -\major{67}{}{char }{Coda network filesystem} -\major{ }{}{block}{SCSI disk devices (48-63)} -\major{68}{}{char }{CAPI 2.0 interface} -\major{ }{}{block}{SCSI disk devices (64-79)} -\major{69}{}{char }{MA16 numeric accelerator card} -\major{ }{}{block}{SCSI disk devices (80-95)} -\major{70}{}{char }{SpellCaster Protocol Services Interface} -\major{ }{}{block}{SCSI disk devices (96-111)} -\major{71}{}{char }{Computone IntelliPort II serial card} -\major{ }{}{block}{SCSI disk devices (112-127)} -\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices} -\major{73}{}{char }{Computone IntelliPort II serial card -- control devices} -\major{74}{}{char }{SCI bridge} -\major{75}{}{char }{Specialix IO8+ serial card} -\major{76}{}{char }{Specialix IO8+ serial card -- alternate devices} -\major{77}{}{char }{ComScire Quantum Noise Generator} -\major{78}{}{char }{PAM Software's multimodem boards} -\major{79}{}{char }{PAM Software's multimodem boards -- alternate devices} -\major{80}{}{char }{Photometrics AT200 CCD camera} -\major{81}{}{char }{video4linux} -\major{82}{}{char }{WiNRADiO communications receiver card} -\major{83}{}{char }{Teletext/videotext interfaces} -\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface} -\major{85}{}{char }{Linux/SGI shared memory input queue} -\major{86}{}{char }{SCSI media changer} -\major{87}{}{char }{Sony Control-A1 stereo control bus} -\major{88}{}{char }{COMX synchronous serial card} -\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface} -\major{89}{}{char }{I$^2$C bus interface} -\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface} -\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)} -\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface} -\major{91}{}{char }{CAN-Bus controller} -\major{ }{}{block}{Tenth IDE hard disk/CD-ROM interface} -\major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card} -\major{93}{}{char }{IBM Smart Capture Card frame grabber} -\major{94}{}{char }{miroVIDEO DC10/30 capture/playback device} -\major{95}{}{char }{IP filter} -\major{96}{}{char }{Parallel port ATAPI tape devices} -\major{97}{}{char }{Parallel port generic ATAPI interface} -\major{98}{}{char }{Control and Mesurement Device (comedi)} -\major{99}{}{char }{Raw parallel ports} -\major{100}{}{char }{POTS (analogue telephone) A/B port} -\major{101}{}{char }{Motorola DSP 56xxx board} -\major{102}{}{char }{Philips SAA5249 Teletext signal decoder} -\major{103}{}{char }{Arla network file system} -\major{104}{}{char }{Flash BIOS support} -\major{105}{}{char }{Comtrol VS-1000 serial card} -\major{106}{}{char }{Comtrol VS-1000 serial card -- alternate devices} -\major{107}{}{char }{3Dfx Voodoo Graphics device} -\major{108}{}{char }{Device independent PPP interface} -\major{109}{}{char }{Reserved for logical volume manager} -\major{110}{}{char }{miroMEDIA Surround board} -\major{111}{--119}{}{Unallocated} -\major{120}{--127}{}{Local/experimental use} -\major{128}{--135}{char }{Unix98 PTY masters} -\major{136}{--143}{char }{Unix98 PTY slaves} -\major{144}{--239}{}{Unallocated} -\major{240}{--254}{}{Local/experimental use} -\major{255}{}{}{Reserved} -\end{devicelist} - -\section{Minor numbers} - -\begin{devicelist} -\major{ 0}{}{}{Unnamed devices (e.g. non-device mounts)} - \minor{0}{}{reserved as null device number} -\end{devicelist} - -\begin{devicelist} -\major{ 1}{}{char}{Memory devices} - \minor{1}{/dev/mem}{Physical memory access} - \minor{2}{/dev/kmem}{Kernel virtual memory access} - \minor{3}{/dev/null}{Null device} - \minor{4}{/dev/port}{I/O port access} - \minor{5}{/dev/zero}{Null byte source} - \minor{6}{/dev/core}{OBSOLETE -- should be a link to {\file /proc/kcore}} - \minor{7}{/dev/full}{Returns ENOSPC on write} - \minor{8}{/dev/random}{Nondeterministic random number generator} - \minor{9}{/dev/urandom}{Less secure, but faster random number generator} -\\ -\major{}{}{block}{RAM disk} - \minor{0}{/dev/ram0}{First RAM disk} - \minordots - \minor{7}{/dev/ram7}{Eighth RAM disk} - \minor{250}{/dev/initrd}{Initial RAM disk} -\end{devicelist} - -\noindent -Earlier kernels had {\file /dev/ramdisk} (1, 1) here. {\file /dev/initrd} -refers to a RAM disk which was preloaded by the boot loader. - -\begin{devicelist} -\major{ 2}{}{char}{Pseudo-TTY masters} - \minor{0}{/dev/ptyp0}{First PTY master} - \minor{1}{/dev/ptyp1}{Second PTY master} - \minordots - \minor{255}{/dev/ptyef}{256th PTY master} -\end{devicelist} - -\noindent -Pseudo-TTY's are named as follows: -\begin{itemize} -\item Masters are {\file pty}, slaves are {\file tty}; -\item the fourth letter is one of {\file pqrstuvwxyzabcde} indicating -the 1st through 16th series of 16 pseudo-ttys each, and -\item the fifth letter is one of {\file 0123456789abcdef} indicating -the position within the series. -\end{itemize} - -\noindent -These are the old-style (BSD) PTY devices; Unix98 devices are on major -128 and above and use the PTY master multiplex ({\file /dev/ptmx}) to -acquire a PTY on demand. - -\begin{devicelist} -\major{}{}{block}{Floppy disks} - \minor{0}{/dev/fd0}{Controller 1, drive 1 autodetect} - \minor{1}{/dev/fd1}{Controller 1, drive 2 autodetect} - \minor{2}{/dev/fd2}{Controller 1, drive 3 autodetect} - \minor{3}{/dev/fd3}{Controller 1, drive 4 autodetect} - \minor{128}{/dev/fd4}{Controller 2, drive 1 autodetect} - \minor{129}{/dev/fd5}{Controller 2, drive 2 autodetect} - \minor{130}{/dev/fd6}{Controller 2, drive 3 autodetect} - \minor{131}{/dev/fd7}{Controller 2, drive 4 autodetect} -\\ -\major{}{}{}{To specify format, add to the autodetect device number} - \minor{ 0}{/dev/fd?}{Autodetect format} - \minor{}{}{} - \minor{ 4}{/dev/fd?d360}{5.25\tum\ \num{4}{360}K in a \num{4}{360}K drive\1} - \minor{ 20}{/dev/fd?h360}{5.25\tum\ \num{4}{360}K in a 1200K drive\1} - \minor{ 48}{/dev/fd?h410}{5.25\tum\ \num{4}{410}K in a 1200K drive} - \minor{ 64}{/dev/fd?h420}{5.25\tum\ \num{4}{420}K in a 1200K drive} - \minor{ 24}{/dev/fd?h720}{5.25\tum\ \num{4}{720}K in a 1200K drive} - \minor{ 80}{/dev/fd?h880}{5.25\tum\ \num{4}{880}K in a 1200K drive\1} - \minor{ 8}{/dev/fd?h1200}{5.25\tum\ 1200K in a 1200K drive\1} - \minor{ 40}{/dev/fd?h1440}{5.25\tum\ 1440K in a 1200K drive\1} - \minor{ 56}{/dev/fd?h1476}{5.25\tum\ 1476K in a 1200K drive} - \minor{ 72}{/dev/fd?h1494}{5.25\tum\ 1494K in a 1200K drive} - \minor{ 92}{/dev/fd?h1600}{5.25\tum\ 1600K in a 1200K drive\1} - \minor{}{}{} - \minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density\2} - \minor{ 16}{/dev/fd?u720}{3.5\tum\ \num{4}{720}K Double Density\1} - \minor{120}{/dev/fd?u800}{3.5\tum\ \num{4}{800}K Double Density\2} - \minor{ 52}{/dev/fd?u820}{3.5\tum\ \num{4}{820}K Double Density} - \minor{ 68}{/dev/fd?u830}{3.5\tum\ \num{4}{830}K Double Density} - \minor{ 84}{/dev/fd?u1040}{3.5\tum\ 1040K Double Density\1} - \minor{ 88}{/dev/fd?u1120}{3.5\tum\ 1120K Double Density\1} - \minor{ 28}{/dev/fd?u1440}{3.5\tum\ 1440K High Density\1} - \minor{124}{/dev/fd?u1600}{3.5\tum\ 1600K High Density\1} - \minor{ 44}{/dev/fd?u1680}{3.5\tum\ 1680K High Density\3} - \minor{ 60}{/dev/fd?u1722}{3.5\tum\ 1722K High Density} - \minor{ 76}{/dev/fd?u1743}{3.5\tum\ 1743K High Density} - \minor{ 96}{/dev/fd?u1760}{3.5\tum\ 1760K High Density} - \minor{116}{/dev/fd?u1840}{3.5\tum\ 1840K High Density\3} - \minor{100}{/dev/fd?u1920}{3.5\tum\ 1920K High Density\1} - \minor{ 32}{/dev/fd?u2880}{3.5\tum\ 2880K Extra Density\1} - \minor{104}{/dev/fd?u3200}{3.5\tum\ 3200K Extra Density} - \minor{108}{/dev/fd?u3520}{3.5\tum\ 3520K Extra Density} - \minor{112}{/dev/fd?u3840}{3.5\tum\ 3840K Extra Density\1} - \minor{}{}{} - \minor{36}{/dev/fd?CompaQ}{Compaq 2880K drive; probably obsolete} -\\ -\major{}{}{}{\1 Autodetectable format} -\major{}{}{}{\2 Autodetectable format in a Double Density (720K) drive only} -\major{}{}{}{\3 Autodetectable format in a High Density (1440K) drive only} -\end{devicelist} - -NOTE: The letter in the device name ({\file d}, {\file q}, {\file h} -or {\file u}) signifies the type of drive supported: 5.25\tum\ Double -Density ({\file d}), 5.25\tum\ Quad Density ({\file q}), 5.25\tum\ -High Density ({\file h}) or 3.5\tum\ (any type, {\file u}). The -capital letters {\file D}, {\file H}, or {\file E} for the 3.5\tum\ -models have been deprecated, since the drive type is insignificant for -these devices. - -\begin{devicelist} -\major{ 3}{}{char}{Pseudo-TTY slaves} - \minor{0}{/dev/ttyp0}{First PTY slave} - \minor{1}{/dev/ttyp1}{Second PTY slave} - \minordots - \minor{255}{/dev/ttyef}{256th PTY slave} -\end{devicelist} - -\noindent -These are the old-style (BSD) PTY devices; Unix98 devices are on major -136 and above. - -\begin{devicelist} -\major{}{}{block}{First MFM, RLL and IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hda}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdb}{Slave: whole disk (or CD-ROM)} -\\ -\major{}{}{}{For partitions, add to the whole disk device number} - \minor{0}{/dev/hd?}{Whole disk} - \minor{1}{/dev/hd?1}{First partition} - \minor{2}{/dev/hd?2}{Second partition} - \minordots - \minor{63}{/dev/hd?63}{63rd partition} -\end{devicelist} - -\noindent -For MS-DOS style partition tables (typically used by Linux/i386 and -sometimes on Linux/Alpha), partitions 1-4 are the primary partitions, -partitions 5 and up are logical partitions. For other partitioning -schemes, the meaning of the numbers vary. - -\begin{devicelist} -\major{ 4}{}{char }{TTY devices} - \minor{0}{/dev/tty0}{Current virtual console} - \minor{1}{/dev/tty1}{First virtual console} - \minordots - \minor{63}{/dev/tty63}{63rd virtual console} - \minor{64}{/dev/ttyS0}{First serial port} - \minordots - \minor{127}{/dev/ttyS63}{64th serial port} - \minor{128}{/dev/ptyp0}{OBSOLETE} - \minordots - \minor{191}{/dev/ptysf}{OBSOLETE} - \minor{192}{/dev/ttyp0}{OBSOLETE} - \minordots - \minor{255}{/dev/ttysf}{OBSOLETE} -\end{devicelist} - -\noindent -Older versions of the Linux kernel used this major number for BSD PTY -devices. As of Linux 2.1.115, this is no longer supported. Use major -numbers 2 and 3. - -\begin{devicelist} -\major{ 5}{}{char }{Alternate TTY devices} - \minor{0}{/dev/tty}{Current TTY device} - \minor{1}{/dev/console}{System console} - \minor{2}{/dev/ptmx}{PTY master multiplex} - \minor{64}{/dev/cua0}{Callout device corresponding to {\file ttyS0}} - \minordots - \minor{127}{/dev/cua63}{Callout device corresponding to {\file ttyS63}} -\end{devicelist} - -\noindent -(5,1) is {\file /dev/console} starting with Linux 2.1.71. See the -section on terminal devices for more information on {\file /dev/console}. - -\begin{devicelist} -\major{ 6}{}{char }{Parallel printer devices} - \minor{0}{/dev/lp0}{First parallel printer ({\hex 0x3bc})} - \minor{1}{/dev/lp1}{Second parallel printer ({\hex 0x378})} - \minor{2}{/dev/lp2}{Third parallel printer ({\hex 0x278})} -\end{devicelist} - -\noindent -Not all computers have the {\hex 0x3bc} parallel port, hence the -"first" printer may be either {\file /dev/lp0} or {\file /dev/lp1}. - -\begin{devicelist} -\major{ 7}{}{char }{Virtual console access devices} - \minor{0}{/dev/vcs}{Current vc text access} - \minor{1}{/dev/vcs1}{tty1 text access} - \minordots - \minor{63}{/dev/vcs63}{tty63 text access} - \minor{128}{/dev/vcsa}{Current vc text/attribute access} - \minor{129}{/dev/vcsa1}{tty1 text/attribute access} - \minordots - \minor{191}{/dev/vcsa63}{tty63 text/attribute access} -\end{devicelist} - -\noindent -NOTE: These devices permit both read and write access. - -\begin{devicelist} -\major{ }{}{block}{Loopback devices} - \minor{0}{/dev/loop0}{First loopback device} - \minor{1}{/dev/loop1}{Second loopback device} - \minordots -\end{devicelist} - -\noindent -The loopback devices are used to mount filesystems not associated with -block devices. The binding to the loopback devices is handled by -{\bf mount}(8) or {\bf losetup}(8). - -\begin{devicelist} -\major{ 8}{}{block}{SCSI disk devices (0-15)} - \minor{0}{/dev/sda}{First SCSI disk whole disk} - \minor{16}{/dev/sdb}{Second SCSI disk whole disk} - \minor{32}{/dev/sdc}{Third SCSI disk whole disk} - \minordots - \minor{240}{/dev/sdp}{Sixteenth SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{ 9}{}{char }{SCSI tape devices} - \minor{0}{/dev/st0}{First SCSI tape, mode 0} - \minor{1}{/dev/st1}{Second SCSI tape, mode 0} - \minordots - \minor{32}{/dev/st0l}{First SCSI tape, mode 1} - \minor{33}{/dev/st1l}{Second SCSI tape, mode 1} - \minordots - \minor{64}{/dev/st0m}{First SCSI tape, mode 2} - \minor{65}{/dev/st1m}{Second SCSI tape, mode 2} - \minordots - \minor{96}{/dev/st0a}{First SCSI tape, mode 3} - \minor{97}{/dev/st1a}{Second SCSI tape, mode 4} - \minordots - \minor{128}{/dev/nst0}{First SCSI tape, mode 0, no rewind} - \minor{129}{/dev/nst1}{Second SCSI tape, mode 0, no rewind} - \minordots - \minor{160}{/dev/nst0l}{First SCSI tape, mode 1, no rewind} - \minor{161}{/dev/nst1l}{Second SCSI tape, mode 1, no rewind} - \minordots - \minor{192}{/dev/nst0m}{First SCSI tape, mode 2, no rewind} - \minor{193}{/dev/nst1m}{Second SCSI tape, mode 2, no rewind} - \minordots - \minor{224}{/dev/nst0a}{First SCSI tape, mode 3, no rewind} - \minor{225}{/dev/nst1a}{Second SCSI tape, mode 3, no rewind} - \minordots -\end{devicelist} - -\noindent -``No rewind'' refers to the omission of the default automatic rewind -on device close. The {\file MTREW} or {\file MTOFFL} ioctl()s can be -used to rewind the tape regardless of the device used to access it. - -\begin{devicelist} -\major{ }{}{block}{Metadisk (RAID) devices} - \minor{0}{/dev/md0}{First metadisk group} - \minor{1}{/dev/md1}{Second metadisk group} - \minordots -\end{devicelist} - -\noindent -The metadisk driver is used to span a filesystem across multiple -physical disks. - -\begin{devicelist} -\major{10}{}{char }{Non-serial mice, misc features} - \minor{0}{/dev/logibm}{Logitech bus mouse} - \minor{1}{/dev/psaux}{PS/2-style mouse port} - \minor{2}{/dev/inportbm}{Microsoft Inport bus mouse} - \minor{3}{/dev/atibm}{ATI XL bus mouse} - \minor{4}{/dev/jbm}{J-mouse} - \minor{4}{/dev/amigamouse}{Amiga mouse (68k/Amiga)} - \minor{5}{/dev/atarimouse}{Atari mouse} - \minor{6}{/dev/sunmouse}{Sun mouse} - \minor{7}{/dev/amigamouse1}{Second Amiga mouse} - \minor{8}{/dev/smouse}{Simple serial mouse driver} - \minor{9}{/dev/pc110pad}{IBM PC-110 digitizer pad} - \minor{128}{/dev/beep}{Fancy beep device} - \minor{129}{/dev/modreq}{Kernel module load request} - \minor{130}{/dev/watchdog}{Watchdog timer port} - \minor{131}{/dev/temperature}{Machine internal temperature} - \minor{132}{/dev/hwtrap}{Hardware fault trap} - \minor{133}{/dev/exttrp}{External device trap} - \minor{134}{/dev/apm\_bios}{Advanced Power Management BIOS} - \minor{135}{/dev/rtc}{Real Time Clock} - \minor{139}{/dev/openprom}{SPARC OpenBoot PROM} - \minor{140}{/dev/relay8}{Berkshire Products Octal relay card} - \minor{141}{/dev/relay16}{Berkshire Products ISO-16 relay card} - \minor{142}{/dev/msr}{x86 model specific registers} - \minor{143}{/dev/pciconf}{PCI configuration space} - \minor{144}{/dev/nvram}{Non-volatile configuration RAM} - \minor{145}{/dev/hfmodem}{Soundcard shortwave modem control} - \minor{146}{/dev/graphics}{Linux/SGI graphics device} - \minor{147}{/dev/opengl}{Linux/SGI OpenGL pipe} - \minor{148}{/dev/gfx}{Linux/SGI graphics effects device} - \minor{149}{/dev/input/mouse}{Linux/SGI Irix emulation mouse} - \minor{150}{/dev/input/keyboard}{Linux/SGI Irix emulation keyboard} - \minor{151}{/dev/led}{Front panel LEDs} - \minor{153}{/dev/mergemem}{Memory merge device} - \minor{154}{/dev/pmu}{Macintosh PowerBook power manager} -\end{devicelist} - -\begin{devicelist} -\major{11}{}{char }{Raw keyboard device} - \minor{0}{/dev/kbd}{Raw keyboard device} -\end{devicelist} - -\noindent -The raw keyboard device is used on Linux/SPARC only. - -\begin{devicelist} -\major{ }{}{block}{SCSI CD-ROM devices} - \minor{0}{/dev/sr0}{First SCSI CD-ROM} - \minor{1}{/dev/sr1}{Second SCSI CD-ROM} - \minordots -\end{devicelist} - -\noindent -The prefix {\file /dev/scd} instead of {\file /dev/sr} has been used -as well, and might make more sense. - -\begin{devicelist} -\major{12}{}{char }{QIC-02 tape} - \minor{2}{/dev/ntpqic11}{QIC-11, no rewind-on-close} - \minor{3}{/dev/tpqic11}{QIC-11, rewind-on-close} - \minor{4}{/dev/ntpqic24}{QIC-24, no rewind-on-close} - \minor{5}{/dev/tpqic24}{QIC-24, rewind-on-close} - \minor{6}{/dev/ntpqic120}{QIC-120, no rewind-on-close} - \minor{7}{/dev/tpqic120}{QIC-120, rewind-on-close} - \minor{8}{/dev/ntpqic150}{QIC-150, no rewind-on-close} - \minor{9}{/dev/tpqic150}{QIC-150, rewind-on-close} -\end{devicelist} - -\noindent -The device names specified are proposed -- if there are ``standard'' -names for these devices, please let me know. - -\begin{devicelist} -\major{ }{}{block}{MSCDEX CD-ROM callback support} - \minor{0}{/dev/dos\_cd0}{First MSCDEX CD-ROM} - \minor{1}{/dev/dos\_cd1}{Second MSCDEX CD-ROM} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{13}{}{char }{PC speaker} - \minor{0}{/dev/pcmixer}{Emulates {\file /dev/mixer}} - \minor{3}{/dev/pcsp}{Emulates {\file /dev/dsp} (8-bit)} - \minor{4}{/dev/pcaudio}{Emulates {\file /dev/audio}} - \minor{5}{/dev/pcsp16}{Emulates {\file /dev/dsp} (16-bit)} -\\ -\major{ }{}{block}{8-bit MFM/RLL/IDE controller} - \minor{0}{/dev/xda}{First XT disk whole disk} - \minor{64}{/dev/xdb}{Second XT disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3). - -\begin{devicelist} -\major{14}{}{char }{Sound card} - \minor{0}{/dev/mixer}{Mixer control} - \minor{1}{/dev/sequencer}{Audio sequencer} - \minor{2}{/dev/midi00}{First MIDI port} - \minor{3}{/dev/dsp}{Digital audio} - \minor{4}{/dev/audio}{Sun-compatible digital audio} - \minor{6}{/dev/sndstat}{Sound card status information} - \minor{8}{/dev/sequencer2}{Sequencer -- alternate device} - \minor{16}{/dev/mixer1}{Second soundcard mixer control} - \minor{17}{/dev/patmgr0}{Sequencer patch manager} - \minor{18}{/dev/midi01}{Second MIDI port} - \minor{19}{/dev/dsp1}{Second soundcard digital audio} - \minor{20}{/dev/audio1}{Second soundcard Sun digital audio} - \minor{33}{/dev/patmgr1}{Sequencer patch manager} - \minor{34}{/dev/midi02}{Third MIDI port} - \minor{50}{/dev/midi03}{Fourth MIDI port} -\\ -\major{ }{}{block}{BIOS harddrive callback support} - \minor{0}{/dev/dos\_hda}{First BIOS harddrive whole disk} - \minor{64}{/dev/dos\_hdb}{Second BIOS harddrive whole disk} - \minor{128}{/dev/dos\_hdc}{Third BIOS harddrive whole disk} - \minor{192}{/dev/dos\_hdd}{Fourth BIOS harddrive whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3). - -\begin{devicelist} -\major{15}{}{char }{Joystick} - \minor{0}{/dev/js0}{First analog joystick} - \minor{1}{/dev/js1}{Second analog joystick} - \minordots - \minor{128}{/dev/djs0}{First digital joystick} - \minor{129}{/dev/djs1}{Second digital joystick} - \minordots -\\ -\major{ }{}{block}{Sony CDU-31A/CDU-33A CD-ROM} - \minor{0}{/dev/sonycd}{Sony CDU-31A CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{16}{}{char }{Non-SCSI scanners} - \minor{0}{/dev/gs4500}{Genius 4500 handheld scanner} -\\ -\major{ }{}{block}{GoldStar CD-ROM} - \minor{0}{/dev/gscd}{GoldStar CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{17}{}{char }{Chase serial card} - \minor{0}{/dev/ttyH0}{First Chase port} - \minor{1}{/dev/ttyH1}{Second Chase port} - \minordots -\\ -\major{ }{}{block}{Optics Storage CD-ROM} - \minor{0}{/dev/optcd}{Optics Storage CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{18}{}{char }{Chase serial card -- alternate devices} - \minor{0}{/dev/cuh0}{Callout device corresponding to {\file ttyH0}} - \minor{1}{/dev/cuh1}{Callout device corresponding to {\file ttyH1}} - \minordots -\\ -\major{ }{}{block}{Sanyo CD-ROM} - \minor{0}{/dev/sjcd}{Sanyo CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{19}{}{char }{Cyclades serial card} - \minor{0}{/dev/ttyC0}{First Cyclades port} - \minordots - \minor{31}{/dev/ttyC31}{32nd Cyclades port} -\\ -\major{ }{}{block}{``Double'' compressed disk} - \minor{0}{/dev/double0}{First compressed disk} - \minordots - \minor{7}{/dev/double7}{Eighth compressed disk} - \minor{128}{/dev/cdouble0}{Mirror of first compressed disk} - \minordots - \minor{135}{/dev/cdouble7}{Mirror of eighth compressed disk} -\end{devicelist} - -\noindent -See the Double documentation for an explanation of the ``mirror'' devices. - -\begin{devicelist} -\major{20}{}{char }{Cyclades serial card -- alternate devices} - \minor{0}{/dev/cub0}{Callout device corresponding to {\file ttyC0}} - \minordots - \minor{31}{/dev/cub31}{Callout device corresponding to {\file ttyC31}} -\\ -\major{ }{}{block}{Hitachi CD-ROM} - \minor{0}{/dev/hitcd}{Hitachi CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{21}{}{char }{Generic SCSI access} - \minor{0}{/dev/sg0}{First generic SCSI device} - \minor{1}{/dev/sg1}{Second generic SCSI device} - \minordots -\end{devicelist} - -\noindent -Most distributions name these {\file /dev/sga}, {\file /dev/sgb}... -This sets an unneccesary limit of 26 SCSI devices in the system, and -is counter to standard Linux device-naming practice. - -\begin{devicelist} -\major{ }{}{block }{Acorn MFM hard drive interface} - \minor{0}{/dev/mfma}{First MFM drive whole disk} - \minor{64}{/dev/mfmb}{Second MFM drive whole disk} -\end{devicelist} - -\noindent -This device is used on the ARM-based Acorn RiscPC. Partitions are -handled the same way as for IDE disks (see major number 3). - -\begin{devicelist} -\major{22}{}{char }{Digiboard serial card} - \minor{0}{/dev/ttyD0}{First Digiboard port} - \minor{1}{/dev/ttyD1}{Second Digiboard port} - \minordots -\\ -\major{ }{}{block}{Second IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hdc}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdd}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{23}{}{char }{Digiboard serial card -- alternate devices} - \minor{0}{/dev/cud0}{Callout device corresponding to {\file ttyD0}} - \minor{1}{/dev/cud1}{Callout device corresponding to {\file ttyD1}} - \minordots -\major{ }{}{block}{Mitsumi proprietary CD-ROM} - \minor{0}{/dev/mcd}{Mitsumi CD-ROM} -\end{devicelist} - -\begin{devicelist}\ -\major{24}{}{char }{Stallion serial card} - \minor{0}{/dev/ttyE0}{Stallion port 0 board 0} - \minor{1}{/dev/ttyE1}{Stallion port 1 board 0} - \minordots - \minor{64}{/dev/ttyE64}{Stallion port 0 board 1} - \minor{65}{/dev/ttyE65}{Stallion port 1 board 1} - \minordots - \minor{128}{/dev/ttyE128}{Stallion port 0 board 2} - \minor{129}{/dev/ttyE129}{Stallion port 1 board 2} - \minordots - \minor{192}{/dev/ttyE192}{Stallion port 0 board 3} - \minor{193}{/dev/ttyE193}{Stallion port 1 board 3} - \minordots -\\ -\major{ }{}{block}{Sony CDU-535 CD-ROM} - \minor{0}{/dev/cdu535}{Sony CDU-535 CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{25}{}{char }{Stallion serial card -- alternate devices} - \minor{0}{/dev/cue0}{Callout device corresponding to {\file ttyE0}} - \minor{1}{/dev/cue1}{Callout device corresponding to {\file ttyE1}} - \minordots - \minor{64}{/dev/cue64}{Callout device corresponding to {\file ttyE64}} - \minor{65}{/dev/cue65}{Callout device corresponding to {\file ttyE65}} - \minordots - \minor{128}{/dev/cue128}{Callout device corresponding to {\file ttyE128}} - \minor{129}{/dev/cue129}{Callout device corresponding to {\file ttyE129}} - \minordots - \minor{192}{/dev/cue192}{Callout device corresponding to {\file ttyE192}} - \minor{193}{/dev/cue193}{Callout device corresponding to {\file ttyE193}} - \minordots -\\ -\major{ }{}{block}{First Matsushita (Panasonic/SoundBlaster) CD-ROM} - \minor{0}{/dev/sbpcd0}{Panasonic CD-ROM controller 0 unit 0} - \minor{1}{/dev/sbpcd1}{Panasonic CD-ROM controller 0 unit 1} - \minor{2}{/dev/sbpcd2}{Panasonic CD-ROM controller 0 unit 2} - \minor{3}{/dev/sbpcd3}{Panasonic CD-ROM controller 0 unit 3} -\end{devicelist} - -\begin{devicelist} -\major{26}{}{char }{Quanta WinVision frame grabber} - \minor{0}{/dev/wvisfgrab}{Quanta WinVision frame grabber} -\\ -\major{ }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM} - \minor{0}{/dev/sbpcd4}{Panasonic CD-ROM controller 1 unit 0} - \minor{1}{/dev/sbpcd5}{Panasonic CD-ROM controller 1 unit 1} - \minor{2}{/dev/sbpcd6}{Panasonic CD-ROM controller 1 unit 2} - \minor{3}{/dev/sbpcd7}{Panasonic CD-ROM controller 1 unit 3} -\end{devicelist} - -\begin{devicelist} -\major{27}{}{char }{QIC-117 tape} - \minor{0}{/dev/qft0}{Unit 0, rewind-on-close} - \minor{1}{/dev/qft1}{Unit 1, rewind-on-close} - \minor{2}{/dev/qft2}{Unit 2, rewind-on-close} - \minor{3}{/dev/qft3}{Unit 3, rewind-on-close} - \minor{4}{/dev/nqft0}{Unit 0, no rewind-on-close} - \minor{5}{/dev/nqft1}{Unit 1, no rewind-on-close} - \minor{6}{/dev/nqft2}{Unit 2, no rewind-on-close} - \minor{7}{/dev/nqft3}{Unit 3, no rewind-on-close} - \minor{16}{/dev/zqft0}{Unit 0, rewind-on-close, compression} - \minor{17}{/dev/zqft1}{Unit 1, rewind-on-close, compression} - \minor{18}{/dev/zqft2}{Unit 2, rewind-on-close, compression} - \minor{19}{/dev/zqft3}{Unit 3, rewind-on-close, compression} - \minor{20}{/dev/nzqft0}{Unit 0, no rewind-on-close, compression} - \minor{21}{/dev/nzqft1}{Unit 1, no rewind-on-close, compression} - \minor{22}{/dev/nzqft2}{Unit 2, no rewind-on-close, compression} - \minor{23}{/dev/nzqft3}{Unit 3, no rewind-on-close, compression} - \minor{32}{/dev/rawqft0}{Unit 0, rewind-on-close, no file marks} - \minor{33}{/dev/rawqft1}{Unit 1, rewind-on-close, no file marks} - \minor{34}{/dev/rawqft2}{Unit 2, rewind-on-close, no file marks} - \minor{35}{/dev/rawqft3}{Unit 3, rewind-on-close, no file marks} - \minor{36}{/dev/nrawqft0}{Unit 0, no rewind-on-close, no file marks} - \minor{37}{/dev/nrawqft1}{Unit 1, no rewind-on-close, no file marks} - \minor{38}{/dev/nrawqft2}{Unit 2, no rewind-on-close, no file marks} - \minor{39}{/dev/nrawqft3}{Unit 3, no rewind-on-close, no file marks} -\\ -\major{ }{}{block}{Third Matsushita (Panasonic/SoundBlaster) CD-ROM} - \minor{0}{/dev/sbpcd8}{Panasonic CD-ROM controller 2 unit 0} - \minor{1}{/dev/sbpcd9}{Panasonic CD-ROM controller 2 unit 1} - \minor{2}{/dev/sbpcd10}{Panasonic CD-ROM controller 2 unit 2} - \minor{3}{/dev/sbpcd11}{Panasonic CD-ROM controller 2 unit 3} -\end{devicelist} - -\begin{devicelist} -\major{28}{}{char }{Stallion serial card -- card programming} - \minor{0}{/dev/staliomem0}{First Stallion I/O card memory} - \minor{1}{/dev/staliomem1}{Second Stallion I/O card memory} - \minor{2}{/dev/staliomem2}{Third Stallion I/O card memory} - \minor{3}{/dev/staliomem3}{Fourth Stallion I/O card memory} -\\ -\major{ }{}{char }{Atari SLM ACSI laser printer (68k/Atari)} - \minor{0}{/dev/slm0}{First SLM laser printer} - \minor{1}{/dev/slm1}{Second SLM laser printer} - \minordots -\\ -\major{ }{}{block}{Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM} - \minor{0}{/dev/sbpcd12}{Panasonic CD-ROM controller 3 unit 0} - \minor{1}{/dev/sbpcd13}{Panasonic CD-ROM controller 3 unit 1} - \minor{2}{/dev/sbpcd14}{Panasonic CD-ROM controller 3 unit 2} - \minor{3}{/dev/sbpcd15}{Panasonic CD-ROM controller 3 unit 3} -\\ -\major{ }{}{block}{ACSI disk/CD-ROM (68k/Atari)} - \minor{0}{/dev/ada}{First ACSI disk whole disk} - \minor{16}{/dev/adb}{Second ACSI disk whole disk} - \minor{32}{/dev/adc}{Third ACSI disk whole disk} - \minordots - \minor{240}{/dev/adp}{Sixteenth ACSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk (same as SCSI.) - -\begin{devicelist} -\major{29}{}{char }{Universal frame buffer} - \minor{0}{/dev/fb0}{First frame buffer} - \minor{1}{/dev/fb1}{Second frame buffer} - \minor{2}{/dev/fb2}{Third frame buffer} - \minordots - \minor{31}{/dev/fb31}{32nd frame buffer} -\end{devicelist} - -\noindent -All additional minor device numbers are reserved. - -\begin{devicelist} -\major{ }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM} - \minor{0}{/dev/aztcd}{Aztech CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{30}{}{char }{iBCS-2 compatibility devices} - \minor{0}{/dev/socksys}{Socket access} - \minor{1}{/dev/spx}{SVR3 local X interface} - \minor{2}{/dev/inet/arp}{Network access} - \minor{2}{/dev/inet/icmp}{Network access} - \minor{2}{/dev/inet/ip}{Network access} - \minor{2}{/dev/inet/udp}{Network access} - \minor{2}{/dev/inet/tcp}{Network access} -\end{devicelist} - -\noindent -Additionally, iBCS-2 requires {\file /dev/nfsd} to be a link to {\file -/dev/socksys} and {\file /dev/X0R} to be a link to {\file /dev/null}. - -\begin{devicelist} -\major{ }{}{block}{Philips LMS CM-205 CD-ROM} - \minor{0}{/dev/cm205cd}{Philips LMS CM-205 CD-ROM} -\end{devicelist} - -\noindent -{\file /dev/lmscd} is an older name for this drive. This driver does -not work with the CM-205MS CD-ROM. - -\begin{devicelist} -\major{31}{}{char }{MPU-401 MIDI} - \minor{0}{/dev/mpu401data}{MPU-401 data port} - \minor{1}{/dev/mpu401stat}{MPU-401 status port} -\\ -\major{ }{}{block}{ROM/flash memory card} - \minor{0}{/dev/rom0}{First ROM card (rw)} - \minordots - \minor{7}{/dev/rom7}{Eighth ROM card (rw)} - \minor{8}{/dev/rrom0}{First ROM card (ro)} - \minordots - \minor{15}{/dev/rrom0}{Eighth ROM card (ro)} - \minor{16}{/dev/flash0}{First flash memory card (rw)} - \minordots - \minor{23}{/dev/flash7}{Eighth flash memory card (rw)} - \minor{24}{/dev/rflash0}{First flash memory card (ro)} - \minordots - \minor{31}{/dev/rflash7}{Eighth flash memory card (ro)} -\end{devicelist} - -\noindent -The read-write (rw) devices support back-caching written data in RAM, -as well as writing to flash RAM devices. The read-only devices (ro) -support reading only. - -\begin{devicelist} -\major{32}{}{char }{Specialix serial card} - \minor{0}{/dev/ttyX0}{First Specialix port} - \minor{1}{/dev/ttyX1}{Second Specialix port} - \minordots -\\ -\major{ }{}{block}{Philips LMS CM-206 CD-ROM} - \minor{0}{/dev/cm206cd}{Philips LMS CM-206 CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{33}{}{char }{Specialix serial card -- alternate devices} - \minor{0}{/dev/cux0}{Callout device corresponding to {\file ttyX0}} - \minor{1}{/dev/cux1}{Callout device corresponding to {\file ttyX1}} - \minordots -\\ -\major{ }{}{block}{Third IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hde}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdf}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{34}{}{char }{Z8530 HDLC driver} - \minor{0}{/dev/scc0}{First Z8530, first port} - \minor{1}{/dev/scc1}{First Z8530, second port} - \minor{2}{/dev/scc2}{Second Z8530, first port} - \minor{3}{/dev/scc3}{Second Z8530, second port} - \minordots -\end{devicelist} - -\noindent -In a previous version these devices were named {\file /dev/sc1} for -{\file /dev/scc0}, {\file /dev/sc2} for {\file /dev/scc1}, and so on. - -\begin{devicelist} -\major{ }{}{block}{Fourth IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hdg}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdh}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{35}{}{char }{tclmidi MIDI driver} - \minor{0}{/dev/midi0}{First MIDI port, kernel timed} - \minor{1}{/dev/midi1}{Second MIDI port, kernel timed} - \minor{2}{/dev/midi2}{Third MIDI port, kernel timed} - \minor{3}{/dev/midi3}{Fourth MIDI port, kernel timed} - \minor{64}{/dev/rmidi0}{First MIDI port, untimed} - \minor{65}{/dev/rmidi1}{Second MIDI port, untimed} - \minor{66}{/dev/rmidi2}{Third MIDI port, untimed} - \minor{67}{/dev/rmidi3}{Fourth MIDI port, untimed} - \minor{128}{/dev/smpte0}{First MIDI port, SMPTE timed} - \minor{129}{/dev/smpte1}{Second MIDI port, SMPTE timed} - \minor{130}{/dev/smpte2}{Third MIDI port, SMPTE timed} - \minor{131}{/dev/smpte3}{Fourth MIDI port, SMPTE timed} -\\ -\major{ }{}{block}{Slow memory ramdisk} - \minor{0}{/dev/slram}{Slow memory ramdisk} -\end{devicelist} - -\begin{devicelist} -\major{36}{}{char }{Netlink support} - \minor{0}{/dev/route}{Routing, device updates (kernel to user)} - \minor{1}{/dev/skip}{enSKIP security cache control} -\\ -\major{ }{}{block}{MCA ESDI hard disk} - \minor{0}{/dev/eda}{First ESDI disk whole disk} - \minor{64}{/dev/edb}{Second ESDI disk whole disk} - \minordots -\end{devicelist} - -\noindent -Partitions are handled the same way as for IDE disks (see major number -3). - -\begin{devicelist} -\major{37}{}{char }{IDE tape} - \minor{0}{/dev/ht0}{First IDE tape} - \minor{128}{/dev/nht0}{First IDE tape, no rewind-on-close} -\end{devicelist} - -\noindent -Currently, only one IDE tape drive is supported. - -\begin{devicelist} -\major{ }{}{block}{Zorro II ramdisk} - \minor{0}{/dev/z2ram}{Zorro II ramdisk} -\end{devicelist} - -\begin{devicelist} -\major{38}{}{char }{Myricom PCI Myrinet board} - \minor{0}{/dev/mlanai0}{First Myrinet board} - \minor{1}{/dev/mlanai1}{Second Myrinet board} - \minordots -\end{devicelist} - -\noindent -This device is used for board control, status query and ``user level -packet I/O''. The board is also accessible as a regular {\file eth} -networking device. - -\begin{devicelist} -\major{ }{}{block}{Reserved for Linux/AP+} -\end{devicelist} - -\begin{devicelist} -\major{39}{}{char }{ML-16P experimental I/O board} - \minor{0}{/dev/ml16pa-a0}{First card, first analog channel} - \minor{1}{/dev/ml16pa-a1}{First card, second analog channel} - \minordots - \minor{15}{/dev/ml16pa-a15}{First card, 16th analog channel} - \minor{16}{/dev/ml16pa-d}{First card, digital lines} - \minor{17}{/dev/ml16pa-c0}{First card, first counter/timer} - \minor{18}{/dev/ml16pa-c1}{First card, second counter/timer} - \minor{19}{/dev/ml16pa-c2}{First card, third counter/timer} - \minor{32}{/dev/ml16pb-a0}{Second card, first analog channel} - \minor{33}{/dev/ml16pb-a1}{Second card, second analog channel} - \minordots - \minor{47}{/dev/ml16pb-a15}{Second card, 16th analog channel} - \minor{48}{/dev/ml16pb-d}{Second card, digital lines} - \minor{49}{/dev/ml16pb-c0}{Second card, first counter/timer} - \minor{50}{/dev/ml16pb-c1}{Second card, second counter/timer} - \minor{51}{/dev/ml16pb-c2}{Second card, third counter/timer} - \minordots -\\ -\major{ }{}{block}{Reserved for Linux/AP+} -\end{devicelist} - -\begin{devicelist} -\major{40}{}{char }{Matrox Meteor frame grabber} - \minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber} -\\ -\major{ }{}{block}{Syquest EZ135 parallel port removable drive} - \minor{0}{/dev/eza}{Parallel EZ135 drive whole disk} -\end{devicelist} - -\noindent -This device is obsolete and will be removed in a future version of -Linux. It has been replaced with the parallel port IDE disk driver at -major number 45. Partitions are handled the same way as for IDE disks -(see major number 3). - -\begin{devicelist} -\major{41}{}{char }{Yet Another Micro Monitor} - \minor{0}{/dev/yamm}{Yet Another Micro Monitor} -\\ -\major{ }{}{block}{MicroSolutions BackPack parallel port CD-ROM} - \minor{0}{/dev/bpcd}{BackPack CD-ROM} -\end{devicelist} - -\noindent -This device is obsolete and will be removed in a future version of -Linux. It has been replaced with the parallel port ATAPI CD-ROM -driver at major number 46. - -\begin{devicelist} -\major{42}{}{}{Demo/sample use} -\end{devicelist} - -\noindent -This number is intended for use in sample code, as well as a general -``example'' device number. It should never be used for a device -driver that is being distributed; either obtain an official number or -use the local/experimental range. The sudden addition or removal of a -driver with this number should not cause ill effects to the system -(bugs excepted.) - -IN PARTICULAR, ANY DISTRIBUTION WHICH CONTAINS A DEVICE DRIVER USING -MAJOR NUMBER 42 IS NONCOMPLIANT. - -\begin{devicelist} -\major{43}{}{char }{isdn4linux virtual modem} - \minor{0}{/dev/ttyI0}{First virtual modem} - \minordots - \minor{63}{/dev/ttyI63}{64th virtual modem} -\\ -\major{ }{}{block}{Network block devices} - \minor{0}{/dev/nd0}{First network block device} - \minor{1}{/dev/nd1}{Second network block device} - \minordots -\end{devicelist} - -\noindent -Network Block Device is somehow similar to loopback devices: If you -read from it, it sends packet accross network asking server for -data. If you write to it, it sends packet telling server to write. It -could be used to mounting filesystems over the net, swapping over the -net, implementing block device in userland etc. - -\begin{devicelist} -\major{44}{}{char }{isdn4linux virtual modem -- alternate devices} - \minor{0}{/dev/cui0}{Callout device corresponding to {\file ttyI0}} - \minordots - \minor{63}{/dev/cui63}{Callout device corresponding to {\file ttyI63}} -\\ -\major{ }{}{block}{Flash Translation Layer (FTL) filesystems} - \minor{0}{/dev/ftla}{FTL on first Memory Technology Device} - \minor{16}{/dev/ftlb}{FTL on second Memory Technology Device} - \minor{32}{/dev/ftlc}{FTL on third Memory Technology Device} - \minordots - \minor{240}{/dev/ftlp}{FTL on 16th Memory Technology Device} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) expect that the partition limit is 15 rather than 63 per -disk (same as SCSI.) - -\begin{devicelist} -\major{45}{}{char }{isdn4linux ISDN BRI driver} - \minor{0}{/dev/isdn0}{First virtual B channel raw data} - \minordots - \minor{63}{/dev/isdn63}{64th virtual B channel raw data} - \minor{64}{/dev/isdnctrl0}{First channel control/debug} - \minordots - \minor{127}{/dev/isdnctrl63}{64th channel control/debug} - \minor{128}{/dev/ippp0}{First SyncPPP device} - \minordots - \minor{191}{/dev/ippp63}{64th SyncPPP device} - \minor{255}{/dev/isdninfo}{ISDN monitor interface} -\\ -\major{ }{}{block}{Parallel port IDE disk devices} - \minor{0}{/dev/pda}{First parallel port IDE disk} - \minor{16}{/dev/pdb}{Second parallel port IDE disk} - \minor{32}{/dev/pdc}{Third parallel port IDE disk} - \minor{48}{/dev/pdd}{Fourth parallel port IDE disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{46}{}{char }{Comtrol Rocketport serial card} - \minor{0}{/dev/ttyR0}{First Rocketport port} - \minor{1}{/dev/ttyR1}{Second Rocketport port} - \minordots -\\ -\major{ }{}{block}{Parallel port ATAPI CD-ROM devices} - \minor{0}{/dev/pcd0}{First parallel port ATAPI CD-ROM} - \minor{1}{/dev/pcd1}{Second parallel port ATAPI CD-ROM} - \minor{2}{/dev/pcd2}{Third parallel port ATAPI CD-ROM} - \minor{3}{/dev/pcd3}{Fourth parallel port ATAPI CD-ROM} -\end{devicelist} - -\begin{devicelist} -\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices} - \minor{0}{/dev/cur0}{Callout device corresponding to {\file ttyR0}} - \minor{1}{/dev/cur1}{Callout device corresponding to {\file ttyR1}} - \minordots -\\ -\major{ }{}{block}{Parallel port ATAPI disk devices} - \minor{0}{/dev/pf0}{First parallel port ATAPI disk} - \minor{1}{/dev/pf1}{Second parallel port ATAPI disk} - \minor{2}{/dev/pf2}{Third parallel port ATAPI disk} - \minor{3}{/dev/pf3}{Fourth parallel port ATAPI disk} -\end{devicelist} - -\noindent -This driver is intended for floppy disks and similar devices and hence -does not support partitioning. - -\begin{devicelist} -\major{48}{}{char }{SDL RISCom serial card} - \minor{0}{/dev/ttyL0}{First RISCom port} - \minor{1}{/dev/ttyL1}{Second RISCom port} - \minordots -\\ -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{49}{}{char }{SDL RISCom serial card -- alternate devices} - \minor{0}{/dev/cul0}{Callout device corresponding to {\file ttyL0}} - \minor{1}{/dev/cul1}{Callout device corresponding to {\file ttyL1}} - \minordots -\\ -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{50}{}{char}{Reserved for GLINT} -\\ -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{51}{}{char }{Baycom radio modem} - \minor{0}{/dev/bc0}{First Baycom radio modem} - \minor{1}{/dev/bc1}{Second Baycom radio modem} - \minordots -\\ -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card} - \minor{0}{/dev/dcbri0}{First DataComm card} - \minor{1}{/dev/dcbri1}{Second DataComm card} - \minor{2}{/dev/dcbri2}{Third DataComm card} - \minor{3}{/dev/dcbri3}{Fourth DataComm card} -\\ -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers} - \minor{0}{/dev/pd\_bdm0}{PD BDM interface on {\file lp0}} - \minor{1}{/dev/pd\_bdm1}{PD BDM interface on {\file lp1}} - \minor{2}{/dev/pd\_bdm2}{PD BDM interface on {\file lp2}} - \minor{4}{/dev/icd\_bdm0}{ICD BDM interface on {\file lp0}} - \minor{5}{/dev/icd\_bdm1}{ICD BDM interface on {\file lp1}} - \minor{6}{/dev/icd\_bdm2}{ICD BDM interface on {\file lp2}} -\end{devicelist} - -\noindent -This device is used for the interfacing to the MC683xx -microcontrollers via Background Debug Mode by use of a Parallel Port -interface. PD is the Motorola Public Domain Interface and ICD is the -commercial interface by P\&E. - -\begin{devicelist} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{54}{}{char }{Electrocardiognosis Holter serial card} - \minor{0}{/dev/holter0}{First Holter port} - \minor{1}{/dev/holter1}{Second Holter port} - \minor{2}{/dev/holter2}{Third Holter port} -\end{devicelist} - -\noindent -A custom serial card used by Electrocardiognosis SRL -$<$mseritan@ottonel.pub.ro$>$ to transfer data from Holter 24-hour -heart monitoring equipment. - -\begin{devicelist} -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{55}{}{char }{DSP56001 digital signal processor} - \minor{0}{/dev/dsp56k}{First DSP56001} -\\ -\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} -\end{devicelist} - -\begin{devicelist} -\major{56}{}{char }{Apple Desktop Bus} - \minor{0}{/dev/adb}{ADB bus control} -\end{devicelist} - -\noindent -Additional devices will be added to this number, all starting with -{\file /dev/adb}. - -\begin{devicelist} -\major{ }{}{block}{Fifth IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hdi}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdj}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{57}{}{char }{Hayes ESP serial card} - \minor{0}{/dev/ttyP0}{First ESP port} - \minor{1}{/dev/ttyP1}{Second ESP port} - \minordots -\\ -\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hdk}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdl}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{58}{}{char }{Hayes ESP serial card -- alternate devices} - \minor{0}{/dev/cup0}{Callout device corresponding to {\file ttyP0}} - \minor{1}{/dev/cup1}{Callout device corresponding to {\file ttyP1}} - \minordots -\\ -\major{ }{}{block}{Reserved for logical volume manager} -\end{devicelist} - -\begin{devicelist} -\major{59}{}{char }{sf firewall package} - \minor{0}{/dev/firewall}{Communication with sf kernel module} -\end{devicelist} - -\begin{devicelist} -\major{60}{--63}{}{Local/experimental use} -\end{devicelist} - -\noindent -For devices not assigned official numbers, these ranges should be -used, in order to avoid conflict with future assignments. - -\begin{devicelist} -\major{64}{}{char }{ENskip kernel encryption package} - \minor{0}{/dev/enskip}{Communication with ENskip kernel - module} -\end{devicelist} - -\begin{devicelist} -\major{65}{}{char }{Sundance ``plink'' Transputer boards} - \minor{0}{/dev/plink0}{First plink device} - \minor{1}{/dev/plink1}{Second plink device} - \minor{2}{/dev/plink2}{Third plink device} - \minor{3}{/dev/plink3}{Fourth plink device} - \minor{64}{/dev/rplink0}{First plink device, raw} - \minor{65}{/dev/rplink1}{Second plink device, raw} - \minor{66}{/dev/rplink2}{Third plink device, raw} - \minor{67}{/dev/rplink3}{Fourth plink device, raw} - \minor{128}{/dev/plink0d}{First plink device, debug} - \minor{129}{/dev/plink1d}{Second plink device, debug} - \minor{130}{/dev/plink2d}{Third plink device, debug} - \minor{131}{/dev/plink3d}{Fourth plink device, debug} - \minor{192}{/dev/rplink0d}{First plink device, raw, debug} - \minor{193}{/dev/rplink1d}{Second plink device, raw, debug} - \minor{194}{/dev/rplink2d}{Third plink device, raw, debug} - \minor{195}{/dev/rplink3d}{Fourth plink device, raw, debug} -\end{devicelist} - -\noindent -This is a commercial driver; contact James Howes -$<$jth@prosig.demon.co.uk$>$ for information. - -\begin{devicelist} -\major{ }{}{block}{SCSI disk devices (16-31)} - \minor{0}{/dev/sdq}{17th SCSI disk whole disk} - \minor{16}{/dev/sdr}{18th SCSI disk whole disk} - \minor{32}{/dev/sds}{19th SCSI disk whole disk} - \minordots - \minor{240}{/dev/sdaf}{32nd SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{66}{}{char }{YARC PowerPC PCI coprocessor card} - \minor{0}{/dev/yppcpci0}{First YARC card} - \minor{1}{/dev/yppcpci1}{Second YARC card} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{SCSI disk devices (32-47)} - \minor{0}{/dev/sdag}{33rd SCSI disk whole disk} - \minor{16}{/dev/sdah}{34th SCSI disk whole disk} - \minor{32}{/dev/sdai}{35th SCSI disk whole disk} - \minordots - \minor{240}{/dev/sdav}{48th SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{67}{}{char }{Coda network filesystem} - \minor{0}{/dev/cfs0}{Coda cache manager} -\end{devicelist} - -\noindent -See {\url http://www.coda.cs.cmu.edu\/} for information about Coda. - -\begin{devicelist} -\major{ }{}{block}{SCSI disk devices (48-63)} - \minor{0}{/dev/sdaw}{49th SCSI disk whole disk} - \minor{16}{/dev/sdax}{50th SCSI disk whole disk} - \minor{32}{/dev/sday}{51st SCSI disk whole disk} - \minordots - \minor{240}{/dev/sdbl}{64th SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{68}{}{char }{CAPI 2.0 interface} - \minor{0}{/dev/capi20}{Control device} - \minor{1}{/dev/capi20.00}{First CAPI 2.0 application} - \minor{2}{/dev/capi20.01}{Second CAPI 2.0 application} - \minordots - \minor{20}{/dev/capi20.19}{19th CAPI 2.0 application} -\end{devicelist} - -\noindent -ISDN CAPI 2.0 driver for use with CAPI 2.0 applications; currently -supports the AVM B1 card. - -\begin{devicelist} -\major{ }{}{block}{SCSI disk devices (64-79)} - \minor{0}{/dev/sdbm}{65th SCSI disk whole disk} - \minor{16}{/dev/sdbn}{66th SCSI disk whole disk} - \minor{32}{/dev/sdbo}{67th SCSI disk whole disk} - \minordots - \minor{240}{/dev/sdcb}{80th SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{69}{}{char }{MA16 numeric accelerator card} - \minor{0}{/dev/ma16}{Board memory access} -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{SCSI disk devices (80-95)} - \minor{0}{/dev/sdcc}{81st SCSI disk whole disk} - \minor{16}{/dev/sdcd}{82nd SCSI disk whole disk} - \minor{32}{/dev/sdce}{83th SCSI disk whole disk} - \minordots - \minor{240}{/dev/sdcr}{96th SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{70}{}{char }{SpellCaster Protocol Services Interface} - \minor{0}{/dev/apscfg}{Configuration interface} - \minor{1}{/dev/apsauth}{Authentication interface} - \minor{2}{/dev/apslog}{Logging interface} - \minor{3}{/dev/apsdbg}{Debugging interface} - \minor{64}{/dev/apsisdn}{ISDN command interface} - \minor{65}{/dev/apsasync}{Async command interface} - \minor{128}{/dev/apsmon}{Monitor interface} -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{SCSI disk devices (96-111)} - \minor{0}{/dev/sdcs}{97th SCSI disk whole disk} - \minor{16}{/dev/sdct}{98th SCSI disk whole disk} - \minor{32}{/dev/sdcu}{99th SCSI disk whole disk} - \minordots - \minor{240}{/dev/sddh}{112th SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{71}{}{char }{Computone IntelliPort II serial card} - \minor{0}{/dev/ttyF0}{IntelliPort II board 0, port 0} - \minor{1}{/dev/ttyF1}{IntelliPort II board 0, port 1} - \minordots - \minor{63}{/dev/ttyF63}{IntelliPort II board 0, port 63} - \minor{64}{/dev/ttyF64}{IntelliPort II board 1, port 0} - \minor{65}{/dev/ttyF65}{IntelliPort II board 1, port 1} - \minordots - \minor{127}{/dev/ttyF127}{IntelliPort II board 1, port 63} - \minor{128}{/dev/ttyF128}{IntelliPort II board 2, port 0} - \minor{129}{/dev/ttyF129}{IntelliPort II board 2, port 1} - \minordots - \minor{191}{/dev/ttyF191}{IntelliPort II board 2, port 63} - \minor{192}{/dev/ttyF192}{IntelliPort II board 3, port 0} - \minor{193}{/dev/ttyF193}{IntelliPort II board 3, port 1} - \minordots - \minor{255}{/dev/ttyF255}{IntelliPort II board 3, port 63} -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{SCSI disk devices (112-127)} - \minor{0}{/dev/sddi}{113th SCSI disk whole disk} - \minor{16}{/dev/sddj}{114th SCSI disk whole disk} - \minor{32}{/dev/sddk}{115th SCSI disk whole disk} - \minordots - \minor{240}{/dev/sddx}{128th SCSI disk whole disk} -\end{devicelist} - -\noindent -Partitions are handled in the same way as for IDE disks (see major -number 3) except that the partition limit is 15 rather than 63 per -disk. - -\begin{devicelist} -\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices} - \minor{0}{/dev/cuf0}{Callout device corresponding to {\file ttyF0}} - \minor{1}{/dev/cuf1}{Callout device corresponding to {\file ttyF1}} - \minordots - \minor{63}{/dev/cuf63}{Callout device corresponding to {\file ttyF63}} - \minor{64}{/dev/cuf64}{Callout device corresponding to {\file ttyF64}} - \minor{65}{/dev/cuf65}{Callout device corresponding to {\file ttyF65}} - \minordots - \minor{127}{/dev/cuf127}{Callout device corresponding to {\file ttyF127}} - \minor{128}{/dev/cuf128}{Callout device corresponding to {\file ttyF128}} - \minor{129}{/dev/cuf129}{Callout device corresponding to {\file ttyF129}} - \minordots - \minor{191}{/dev/cuf191}{Callout device corresponding to {\file ttyF191}} - \minor{192}{/dev/cuf192}{Callout device corresponding to {\file ttyF192}} - \minor{193}{/dev/cuf193}{Callout device corresponding to {\file ttyF193}} - \minordots - \minor{255}{/dev/cuf255}{Callout device corresponding to {\file ttyF255}} -\end{devicelist} - -\begin{devicelist} -\major{73}{}{char }{Computone IntelliPort II serial card -- control devices} - \minor{0}{/dev/ip2ipl0}{Loadware device for board 0} - \minor{1}{/dev/ip2stat0}{Status device for board 0} - \minor{4}{/dev/ip2ipl1}{Loadware device for board 1} - \minor{5}{/dev/ip2stat1}{Status device for board 1} - \minor{8}{/dev/ip2ipl2}{Loadware device for board 2} - \minor{9}{/dev/ip2stat2}{Status device for board 2} - \minor{12}{/dev/ip2ipl3}{Loadware device for board 3} - \minor{13}{/dev/ip2stat3}{Status device for board 3} -\end{devicelist} - -\begin{devicelist} -\major{74}{}{char }{SCI bridge} - \minor{0}{/dev/SCI/0}{SCI device 0} - \minor{1}{/dev/SCI/1}{SCI device 1} - \minordots -\end{devicelist} - -\noindent -Currently for Dolphin Interconnect Solutions' PCI-SCI bridge. - -\begin{devicelist} -\major{75}{}{char }{Specialix IO8+ serial card} - \minor{0}{/dev/ttyW0}{First IO8+ port, first card} - \minor{1}{/dev/ttyW1}{Second IO8+ port, first card} - \minordots - \minor{8}{/dev/ttyW8}{First IO8+ port, second card} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{76}{}{char }{Specialix IO8+ serial card -- alternate devices} - \minor{0}{/dev/cuw0}{Callout device corresponding to {\file ttyW0}} - \minor{1}{/dev/cuw1}{Callout device corresponding to {\file ttyW1}} - \minordots - \minor{8}{/dev/cuw8}{Callout device corresponding to {\file ttyW8}} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{77}{}{char }{ComScire Quantum Noise Generator} - \minor{0}{/dev/qng}{ComScire Quantum Noise Generator} -\end{devicelist} - -\begin{devicelist} -\major{78}{}{char }{PAM Software's multimodem boards} - \minor{0}{/dev/ttyM0}{First PAM modem} - \minor{1}{/dev/ttyM1}{Second PAM modem} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{79}{}{char }{PAM Software's multimodem boards -- alternate devices} - \minor{0}{/dev/cum0}{Callout device corresponding to {\file ttyM0}} - \minor{1}{/dev/cum1}{Callout device corresponding to {\file ttyM1}} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{80}{}{char }{Photometrics AT200 CCD camera} - \minor{0}{/dev/at200}{Photometrics AT200 CCD camera} -\end{devicelist} - -\begin{devicelist} -\major{81}{}{char }{video4linux} - \minor{0}{/dev/video0}{Video capture/overlay device} - \minordots - \minor{63}{/dev/video63}{Video capture/overlay device} - \minor{64}{/dev/radio0}{Radio device} - \minordots - \minor{127}{/dev/radio63}{Radio device} - \minor{192}{/dev/vtx0}{Teletext device} - \minordots - \minor{223}{/dev/vtx31}{Teletext device} - \minor{224}{/dev/vbi0}{Vertical blank interupt} - \minordots - \minor{255}{/dev/vbi31}{Vertical blank interupt} -\end{devicelist} - -\begin{devicelist} -\major{82}{}{char }{WiNRADiO communications receiver card} - \minor{0}{/dev/winradio0}{First WiNRADiO card} - \minor{1}{/dev/winradio1}{Second WiNRADiO card} - \minordots -\end{devicelist} - -\noindent -The driver and documentation may be obtained from -{\url http://www.proximity.com.au/~brian/winradio/\/}. - -\begin{devicelist} -\major{83}{}{char }{Teletext/videotext interfaces} - \minor{0}{/dev/vtx}{Teletext decoder} - \minor{16}{/dev/vttuner}{TV tuner on teletext interface} -\end{devicelist} - -\noindent -Devices for the driver contained in the VideoteXt package. More information -on {\url http://home.pages.de/~videotext/\/}. - -\begin{devicelist} -\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface} - \minor{0}{/dev/ihcp0}{First Greensheet port} - \minor{1}{/dev/ihcp1}{Second Greensheet port} -\end{devicelist} - -\begin{devicelist} -\major{85}{}{char }{Linux/SGI shared memory input queue} - \minor{0}{/dev/shmiq}{Master shared input queue} - \minor{1}{/dev/qcntl0}{First device pushed} - \minor{2}{/dev/qcntl1}{Second device pushed} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{86}{}{char }{SCSI media changer} - \minor{0}{/dev/sch0}{First SCSI media changer} - \minor{1}{/dev/sch1}{Second SCSI media changer} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{87}{}{char }{Sony Control-A1 stereo control bus} - \minor{0}{/dev/controla0}{First device on chain} - \minor{1}{/dev/controla1}{Second device on chain} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{88}{}{char }{COMX synchronous serial card} - \minor{0}{/dev/comx0}{Channel 0} - \minor{1}{/dev/comx1}{Channel 1} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hdm}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdn}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{89}{}{char }{I$^2$C bus interface} - \minor{0}{/dev/i2c0}{First I$^2$C adapter} - \minor{1}{/dev/i2c1}{Second I$^2$C adapter} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hdo}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdp}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)} - \minor{0}{/dev/mtd0}{First MTD (rw)} - \minor{1}{/dev/mtdr0}{First MTD (ro)} - \minordots - \minor{30}{/dev/mtd15}{16th MTD (rw)} - \minor{31}{/dev/mtdr15}{16th MTD (ro)} -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hdq}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdr}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{91}{}{char }{CAN-Bus controller} - \minor{0}{/dev/can0}{First CAN-Bus controller} - \minor{1}{/dev/can1}{Second CAN-Bus controller} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{ }{}{block}{Tenth IDE hard disk/CD-ROM interface} - \minor{0}{/dev/hds}{Master: whole disk (or CD-ROM)} - \minor{64}{/dev/hdt}{Slave: whole disk (or CD-ROM)} -\end{devicelist} - -\noindent -Partitions are handled the same way as for the first interface (see -major number 3). - -\begin{devicelist} -\major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card} -\end{devicelist} - -\begin{devicelist} -\major{93}{}{char }{IBM Smart Capture Card frame grabber} - \minor{0}{/dev/iscc0}{First Smart Capture Card} - \minor{1}{/dev/iscc1}{Second Smart Capture Card} - \minordots - \minor{128}{/dev/isccctl0}{First Smart Capture Card control} - \minor{129}{/dev/isccctl1}{Second Smart Capture Card control} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{94}{}{char }{miroVIDEO DC10/30 capture/playback device} - \minor{0}{/dev/dcxx0}{First capture card} - \minor{1}{/dev/dcxx1}{Second capture card} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{95}{}{char }{IP filter} - \minor{0}{/dev/ipl}{Filter control device/log file} - \minor{1}{/dev/ipnat}{NAT control device/log file} - \minor{2}{/dev/ipstate}{State information log file} - \minor{3}{/dev/ipauth}{Authentication control device/log file} -\end{devicelist} - -\begin{devicelist} -\major{96}{}{char }{Parallel port ATAPI tape devices} - \minor{0}{/dev/pt0}{First parallel port ATAPI tape} - \minor{1}{/dev/pt1}{Second parallel port ATAPI tape} - \minor{2}{/dev/pt2}{Third parallel port ATAPI tape} - \minor{3}{/dev/pt3}{Fourth parallel port ATAPI tape} - \minor{128}{/dev/npt0}{First parallel port ATAPI tape, no rewind} - \minor{129}{/dev/npt1}{Second parallel port ATAPI tape, no rewind} - \minor{130}{/dev/npt2}{Third parallel port ATAPI tape, no rewind} - \minor{131}{/dev/npt3}{Fourth parallel port ATAPI tape, no rewind} -\end{devicelist} - -\begin{devicelist} -\major{97}{}{char }{Parallel port generic ATAPI interface} - \minor{0}{/dev/pg0}{First parallel port ATAPI device} - \minor{1}{/dev/pg1}{Second parallel port ATAPI device} - \minor{2}{/dev/pg2}{Third parallel port ATAPI device} - \minor{3}{/dev/pg3}{Fourth parallel port ATAPI device} -\end{devicelist} - -\noindent -These devices support the same API as the generic SCSI devices. - -\begin{devicelist} -\major{98}{}{char }{Control and Mesurement Device (comedi)} - \minor{0}{/dev/comedi0}{First comedi device} - \minor{1}{/dev/comedi1}{Second comedi device} - \minordots -\end{devicelist} - -\noindent -See {\url http://stm.lbl.gov/comedi/} or {\url -http://www.llp.fu-berlin.de/}. - -\begin{devicelist} -\major{99}{}{char }{Raw parallel ports} - \minor{0}{/dev/parport0}{First parallel port} - \minor{1}{/dev/parport1}{Second parallel port} - \minordots -\end{devicelist} - -\noindent -These devices can be used to drive parallel port devices from -user-space while interacting with the parport sharing code. - -\begin{devicelist} -\major{100}{}{char }{POTS (analogue telephone) A/B port} - \minor{0}{/dev/phone0}{First telephone port} - \minor{1}{/dev/phone1}{Second telephone port} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{101}{}{char }{Motorola DSP 56xxx board} - \minor{0}{/dev/mdspstat}{Status information} - \minor{1}{/dev/mdsp1}{First DSP board I/O and controls} - \minordots - \minor{16}{/dev/mdsp16}{16th DSP board I/O and controls} -\end{devicelist} - -\begin{devicelist} -\major{102}{}{char }{Philips SAA5249 Teletext signal decoder} - \minor{0}{/dev/tlk0}{First Teletext decoder} - \minor{1}{/dev/tlk1}{Second Teletext decoder} - \minor{2}{/dev/tlk2}{Third Teletext decoder} - \minor{3}{/dev/tlk3}{Fourth Teletext decoder} -\end{devicelist} - -\begin{devicelist} -\major{103}{}{char }{Arla network file system} - \minor{0}{/dev/xfs0}{Arla XFS} -\end{devicelist} - -\noindent -Arla is a free clone of the Andrew File System, AFS. Any resemblance -with the Swedish milk producer is coincidental. For more information -about the project, write to $<$arla-drinkers@stacken.kth.se$>$ or -subscribe to the arla-announce mailing list by sending a mail to -$<$arla-announce-request@stacken.kth.se$>$. - -\begin{devicelist} -\major{104}{}{char }{Flash BIOS support} -\end{devicelist} - -\begin{devicelist} -\major{105}{}{char }{Comtrol VS-1000 serial card} - \minor{0}{/dev/ttyV0}{First VS-1000 port} - \minor{1}{/dev/ttyV1}{Second VS-1000 port} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{106}{}{char }{Comtrol VS-1000 serial card -- alternate devices} - \minor{0}{/dev/cuv0}{Callout device corresponding to {\file ttyV0}} - \minor{1}{/dev/cuv1}{Callout device corresponding to {\file ttyV1}} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{107}{}{char }{3Dfx Voodoo Graphics device} - \minor{0}{/dev/3dfx}{Primary 3Dfx graphics device} -\end{devicelist} - -\begin{devicelist} -\major{108}{}{char }{Device independent PPP interface} - \minor{0}{/dev/ppp}{Device independent PPP interface} -\end{devicelist} - -\begin{devicelist} -\major{109}{}{char }{Reserved for logical volume manager} -\end{devicelist} - -\begin{devicelist} -\major{110}{}{char }{miroMEDIA Surround board} - \minor{0}{/dev/srnd0}{First miroMEDIA Surround board} - \minor{1}{/dev/srnd1}{First miroMEDIA Surround board} - \minordots -\end{devicelist} - -\begin{devicelist} -\major{111}{--119}{}{Unallocated} -\end{devicelist} - -\begin{devicelist} -\major{120}{--127}{}{Local/experimental use} -\end{devicelist} - -\begin{devicelist} -\major{128}{--135}{char }{Unix98 PTY masters} -\end{devicelist} - -\noindent -These devices should not have corresponding device nodes; instead they -should be accessed through the {\file /dev/ptmx} cloning device. - -\begin{devicelist} -\major{136}{--143}{char }{Unix98 PTY slaves} - \minor{0}{/dev/pts/0}{First Unix98 pseudo-TTY} - \minor{1}{/dev/pts/1}{Second Unix98 pseudo-TTY} - \minordots -\end{devicelist} - -\noindent -These device nodes are automatically generated with the proper -permissions and modes by mounting the {\file devpts} filesystem onto -{\file /dev/pts} with the appropriate mount options (distribution -dependent.) - -\begin{devicelist} -\major{144}{--239}{}{Unallocated} -\end{devicelist} - -\begin{devicelist} -\major{240}{--254}{}{Local/experimental use} -\end{devicelist} - -\begin{devicelist} -\major{255}{}{}{Reserved} -\end{devicelist} - -\noindent -This major is reserved to assist the expansion to a larger number -space. No device nodes with this major should ever be created on any -filesystem. - -\section{Additional /dev directory entries} - -This section details additional entries that should or may exist in the -{\file /dev} directory. It is preferred that symbolic links use the -same form (absolute or relative) as is indicated here. Links are -classified as {\em hard\/} or {\em symbolic\/} depending on the -preferred type of link; if possible, the indicated type of link should -be used. - -\subsection{Compulsory links} - -These links should exist on all systems: - -\begin{nodelist} -\link{/dev/fd}{/proc/self/fd}{symbolic}{File descriptors} -\link{/dev/stdin}{fd/0}{symbolic}{Standard input file descriptor} -\link{/dev/stdout}{fd/1}{symbolic}{Standard output file descriptor} -\link{/dev/stderr}{fd/2}{symbolic}{Standard error file descriptor} -\link{/dev/nfsd}{socksys}{symbolic}{Required by iBCS-2} -\link{/dev/X0R}{null}{symbolic}{Required by iBCS-2} -\end{nodelist} - -\noindent -Note: The last device is: $<$letter {\tt X}$>$-$<$digit {\tt -0}$>$-$<$letter {\tt R}$>$. - -\subsection{Recommended links} - -It is recommended that these links exist on all systems: - -\begin{nodelist} -\link{/dev/core}{/proc/kcore}{symbolic}{Backward compatibility} -\link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility} -\link{/dev/ftape}{qft0}{symbolic}{Backward compatibility} -\link{/dev/bttv0}{video0}{symbolic}{Backward compatibility} -\link{/dev/radio}{radio0}{symbolic}{Backward compatibility} -\link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs} -\end{nodelist} - -\subsection{Locally defined links} - -The following links may be established locally to conform to the -configuration of the system. This is merely a tabulation of existing -practice, and does not constitute a recommendation. However, if they -exist, they should have the following uses. - -\begin{nodelist} -\vlink{/dev/mouse}{mouse port}{symbolic}{Current mouse device} -\vlink{/dev/tape}{tape device}{symbolic}{Current tape device} -\vlink{/dev/cdrom}{CD-ROM device}{symbolic}{Current CD-ROM device} -\vlink{/dev/cdwriter}{CD-writer}{symbolic}{Current CD-writer device} -\vlink{/dev/scanner}{scanner device}{symbolic}{Current scanner device} -\vlink{/dev/modem}{modem port}{symbolic}{Current dialout device} -\vlink{/dev/root}{root device}{symbolic}{Current root filesystem} -\vlink{/dev/swap}{swap device}{symbolic}{Current swap device} -\end{nodelist} - -\noindent -{\file /dev/modem} should not be used for a modem which supports -dialin as well as dialout, as it tends to cause lock file problems. -If it exists, {\file /dev/modem} should point to the appropriate -primary TTY device (the use of the alternate callout devices is -deprecated.) - -For SCSI devices, {\file /dev/tape} and {\file /dev/cdrom} should -point to the ``cooked'' devices ({\file /dev/st*} and {\file -/dev/sr*}, respectively), whereas {\file /dev/cdwriter} and {\file -/dev/scanner} should point to the appropriate generic SCSI devices -({\file /dev/sg*}). - -{\file /dev/mouse} may point to a primary serial TTY device, a -hardware mouse device, or a socket for a mouse driver program -(e.g. {\file /dev/gpmdata}). - -\subsection{Sockets and pipes} - -Non-transient sockets or named pipes may exist in {\file /dev}. -Common entries are: - -\begin{nodelist} -\node{/dev/printer}{socket}{{\file lpd} local socket} -\node{/dev/log}{socket}{{\file syslog} local socket} -\node{/dev/gpmdata}{socket}{{\file gpm} mouse multiplexer} -\end{nodelist} - -\section{Terminal devices} - -Terminal, or TTY devices are a special class of character devices. A -terminal device is any device that could act as a controlling terminal -for a session; this includes virtual consoles, serial ports, and -pseudoterminals (PTYs). - -All terminal devices share a common set of capabilities known as line -diciplines; these include the common terminal line dicipline as well -as SLIP and PPP modes. - -All terminal devices are named similarly; this section explains the -naming and use of the various types of TTYs. Note that the naming -conventions include several historical warts; some of these are -Linux-specific, some were inherited from other systems, and some -reflect Linux outgrowing a borrowed convention. - -A hash mark ($\#$) in a device name is in all cases used here to -indicate a decimal number without leading zeroes. - -\subsection{Virtual consoles and the console device} - -Virtual consoles are full-screen terminal displays on the system video -monitor. Virtual consoles are named {\file /dev/tty$\#$}, with -numbering starting at {\file /dev/tty1}; {\file /dev/tty0} is the -current virtual console. {\file /dev/tty0} is the device that should -be used to access the system video card on those architectures for -which the frame buffer devices ({\file /dev/fb*}) are not applicable. -Do not use {\file /dev/console} for this purpose. - -The {\em console device\/}, {\file /dev/console}, is the device to -which system messages should be sent, and on which logins should be -permitted in single-user mode. Starting with Linux 2.1.71, {\file -/dev/console} is managed by the kernel; for previous versions it -should be a symbolic link to either {\file /dev/tty0}, a specific -virtual console such as {\file /dev/tty1}, or to a serial port primary -({\file tty*}, not {\file cu*}) device, depending on the configuration -of the system. - -\subsection{Serial ports} - -Serial ports are RS-232 serial ports and any device which simulates -one, either in hardware (such as internal modems) or in software (such -as the ISDN driver.) Under Linux, each serial ports has two device -names, the primary or callin device and the alternate or callout one. -Each kind of device is indicated by a different letter. For any -letter $X$, the names of the devices are {\file /dev/tty${X\#}$} and -{\file /dev/cu${x\#}$}, respectively; for historical reasons, {\file -/dev/ttyS$\#$} and {\file /dev/ttyC$\#$} correspond to {\file -/dev/cua$\#$} and {\file /dev/cub$\#$}. In the future, it should be -expected that multiple letters will be used; all letters will be upper -case for the {\file tty} device (e.g. {\file /dev/ttyDP$\#$} and lower -case for the {\file cu} device (e.g. {\file /dev/cudp$\#$}. - -The use of the callout devices is deprecated. - -The names {\file /dev/ttyQ$\#$} and {\file /dev/cuq$\#$} are reserved -for local use. - -The alternate devices provide for kernel-based exclusion and somewhat -different defaults than the primary devices. Their main purpose is to -allow the use of serial ports with programs with no inherent or broken -support for serial ports. Their use is deprecated, and they may be -removed from a future version of Linux. - -Arbitration of serial ports is provided by the use of lock files with -the names {\file /var/lock/LCK..tty${X\#}$}. The contents of the lock -file should be the PID of the locking process as an ASCII number. - -It is common practice to install links such as {\file /dev/modem\/} -which point to serial ports. In order to ensure proper locking in the -presence of these links, it is recommended that software chase -symlinks and lock all possible names; additionally, it is recommended -that a lock file be installed with the corresponding alternate -device. In order to avoid deadlocks, it is recommended that the locks -are acquired in the following order, and released in the reverse: -\begin{itemize} -\item{The symbolic link name, if any ({\file /var/lock/LCK..modem})} -\item{The {\file tty} name ({\file /var/lock/LCK..ttyS2})} -\item{The alternate device name ({\file /var/lock/LCK..cua2})} -\end{itemize} -In the case of nested symbolic links, the lock files should be -installed in the order the symlinks are resolved. - -Under no circumstances should an application hold a lock while waiting -for another to be released. In addition, applications which attempt -to create lock files for the corresponding alternate device names -should take into account the possibility of being used on a non-serial -port TTY, for which no alternate device would exist. - -\subsection{Pseudoterminals (PTYs)} - -Pseudoterminals, or PTYs, are used to create login sessions or provide -other capabilities requiring a TTY line dicipline (including SLIP or -PPP capability) to arbitrary data-generation processes. Each PTY has -a {\em master\/} side, named {\file /dev/pty[p-za-e][0-9a-f]\/}, and a -{\em slave\/} side, named {\file /dev/tty[p-za-e][0-9a-f]\/}. The -kernel arbitrates the use of PTYs by allowing each master side to be -opened only once. - -Once the master side has been opened, the corresponding slave device -can be used in the same manner as any TTY device. The master and -slave devices are connected by the kernel, generating the equivalent -of a bidirectional pipe with TTY capabilities. - -Recent versions of the Linux kernels and GNU libc contain support for -the System V/Unix98 naming scheme for PTYs, which assigns a common -device {\file /dev/ptmx\/} to all the masters (opening it will -automatically give you a previously unassigned PTY) and a subdirectory -{\file /dev/pts\/} for the slaves; the slaves are named with decimal -integers ({\file /dev/pts/$\#$\/} in our notation). This removes the -problem of exhausting the namespace and enables the kernel to -automatically create the device nodes for the slaves on demand using -the {\file devpts\/} filesystem. - -\end{document} diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.3.99-pre2/linux/Documentation/devices.txt Fri Jan 7 19:13:21 2000 +++ linux/Documentation/devices.txt Thu Mar 23 23:32:47 2000 @@ -1,7 +1,7 @@ LINUX ALLOCATED DEVICES Maintained by H. Peter Anvin - Last revised: December 16, 1999 + Last revised: March 23, 2000 This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating @@ -14,12 +14,15 @@ of this document is no longer maintained. This document is included by reference into the Filesystem Hierarchy -Standard (FHS). The FHS is available from http://www.pathname.com/fhs/. +Standard (FHS). The FHS is available from http://www.pathname.com/fhs/. Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga platform only. Allocations marked (68k/Atari) apply to Linux/68k on the Atari platform only. +The symbol {2.6} means the allocation is obsolete and scheduled for +removal once kernel version 2.6 (or equivalent) is released. + This document is in the public domain. The author requests, however, that semantically altered versions are not distributed without permission of the author, assuming the author can be contacted without @@ -198,7 +201,7 @@ Older versions of the Linux kernel used this major number for BSD PTY devices. As of Linux 2.1.115, this - is no longer supported. Use major numbers 2 and 3. + is no longer supported. Use major numbers 2 and 3. 5 char Alternate TTY devices 0 = /dev/tty Current TTY device @@ -304,8 +307,11 @@ 7 = /dev/amigamouse1 Second Amiga mouse 8 = /dev/smouse Simple serial mouse driver 9 = /dev/pc110pad IBM PC-110 digitizer pad + 10 = /dev/adbmouse Apple Desktop Bus mouse + 11 = /dev/vrtpanel Vr41xx embedded touch panel + 13 = /dev/vpcmouse Connectix Virtual PC Mouse 128 = /dev/beep Fancy beep device - 129 = /dev/modreq Kernel module load request + 129 = /dev/modreq Kernel module load request {2.6} 130 = /dev/watchdog Watchdog timer port 131 = /dev/temperature Machine internal temperature 132 = /dev/hwtrap Hardware fault trap @@ -318,7 +324,7 @@ 142 = /dev/msr x86 model-specific registers 143 = /dev/pciconf PCI configuration space 144 = /dev/nvram Non-volatile configuration RAM - 145 = /dev/hfmodem Soundcard shortwave modem control + 145 = /dev/hfmodem Soundcard shortwave modem control {2.6} 146 = /dev/graphics Linux/SGI graphics device 147 = /dev/opengl Linux/SGI OpenGL pipe 148 = /dev/gfx Linux/SGI graphics effects device @@ -352,6 +358,11 @@ 177 = /dev/cbm Serial CBM bus 178 = /dev/jsflash JavaStation OS flash SIMM 179 = /dev/xsvc High-speed shared-mem/semaphore service + 180 = /dev/vrbuttons Vr41xx button input device + 181 = /dev/toshiba Toshiba laptop SMM support + 182 = /dev/perfctr Performance-monitoring counters + 183 = /dev/intel_rng Intel i8x0 random number generator + 184 = /dev/cpu/microcode CPU microcode update interface 240-255 Reserved for local use 11 char Raw keyboard device @@ -380,7 +391,7 @@ The device names specified are proposed -- if there are "standard" names for these devices, please let me know. - block MSCDEX CD-ROM callback support + block MSCDEX CD-ROM callback support {2.6} 0 = /dev/dos_cd0 First MSCDEX CD-ROM 1 = /dev/dos_cd1 Second MSCDEX CD-ROM ... @@ -407,7 +418,7 @@ 2 = /dev/midi00 First MIDI port 3 = /dev/dsp Digital audio 4 = /dev/audio Sun-compatible digital audio - 6 = /dev/sndstat Sound card status information + 6 = /dev/sndstat Sound card status information {2.6} 7 = /dev/audioctl SPARC audio control device 8 = /dev/sequencer2 Sequencer -- alternate device 16 = /dev/mixer1 Second soundcard mixer control @@ -418,7 +429,7 @@ 33 = /dev/patmgr1 Sequencer patch manager 34 = /dev/midi02 Third MIDI port 50 = /dev/midi03 Fourth MIDI port - block BIOS harddrive callback support + block BIOS harddrive callback support {2.6} 0 = /dev/dos_hda First BIOS harddrive whole disk 64 = /dev/dos_hdb Second BIOS harddrive whole disk 128 = /dev/dos_hdc Third BIOS harddrive whole disk @@ -549,7 +560,7 @@ 2 = /dev/sbpcd2 Panasonic CD-ROM controller 0 unit 2 3 = /dev/sbpcd3 Panasonic CD-ROM controller 0 unit 3 - 26 char Quanta WinVision frame grabber + 26 char Quanta WinVision frame grabber {2.6} 0 = /dev/wvisfgrab Quanta WinVision frame grabber block Second Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd4 Panasonic CD-ROM controller 1 unit 0 @@ -569,7 +580,7 @@ 16 = /dev/zqft0 Unit 0, rewind-on-close, compression 17 = /dev/zqft1 Unit 1, rewind-on-close, compression 18 = /dev/zqft2 Unit 2, rewind-on-close, compression - 19 = /dev/zqtf3 Unit 3, rewind-on-close, compression + 19 = /dev/zqft3 Unit 3, rewind-on-close, compression 20 = /dev/nzqft0 Unit 0, no rewind-on-close, compression 21 = /dev/nzqft1 Unit 1, no rewind-on-close, compression 22 = /dev/nzqft2 Unit 2, no rewind-on-close, compression @@ -613,12 +624,11 @@ disks (see major number 3) except that the limit on partitions is 15, like SCSI. - 29 char Universal frame buffers + 29 char Universal frame buffer 0 = /dev/fb0 First frame buffer - 1 = /dev/fb1 Second frame buffer - 2 = /dev/fb2 Third frame buffer + 32 = /dev/fb1 Second frame buffer ... - 31 = /dev/fb31 32nd frame buffer + 224 = /dev/fb7 Eighth frame buffer All additional minor numbers are reserved. @@ -777,7 +787,7 @@ ... block Reserved for Linux/AP+ - 40 char Matrox Meteor frame grabber + 40 char Matrox Meteor frame grabber {2.6} 0 = /dev/mmetfgrab Matrox Meteor frame grabber block Syquest EZ135 parallel port removable drive 0 = /dev/eza Parallel EZ135 drive, whole disk @@ -1265,7 +1275,7 @@ disks (see major number 3) except that the limit on partitions is 15. - 83 char Teletext/videotext interfaces + 83 char Teletext/videotext interfaces {2.6} 0 = /dev/vtx Teletext decoder 16 = /dev/vttuner TV tuner on teletext interface @@ -1356,8 +1366,8 @@ 89 char I2C bus interface - 0 = /dev/i2c0 First I2C adapter - 1 = /dev/i2c1 Second I2C adapter + 0 = /dev/i2c-0 First I2C adapter + 1 = /dev/i2c-1 Second I2C adapter ... block Eighth IDE hard disk/CD-ROM interface @@ -1404,7 +1414,7 @@ disks (see major number 3) except that the limit on partitions is 15. - 93 char IBM Smart Capture Card frame grabber + 93 char IBM Smart Capture Card frame grabber {2.6} 0 = /dev/iscc0 First Smart Capture Card 1 = /dev/iscc1 Second Smart Capture Card ... @@ -1418,7 +1428,7 @@ ... 240 = /dev/nftlp 16th NTFL layer - 94 char miroVIDEO DC10/30 capture/playback device + 94 char miroVIDEO DC10/30 capture/playback device {2.6} 0 = /dev/dcxx0 First capture card 1 = /dev/dcxx1 Second capture card ... @@ -1462,6 +1472,11 @@ These devices support the same API as the generic SCSI devices. + block Packet writing for CD/DVD devices + 0 = /dev/pktcdvd0 First packet-writing module + 1 = /dev/pktcdvd1 Second packet-writing module + ... + 98 char Control and Measurement Device (comedi) 0 = /dev/comedi0 First comedi device 1 = /dev/comedi1 Second comedi device @@ -1469,23 +1484,34 @@ See http://stm.lbl.gov/comedi or http://www.llp.fu-berlin.de/. + block User-mode virtual block device + 0 = /dev/ubd0 First user-mode block device + 1 = /dev/ubd1 Second user-mode block device + ... + + This device is used by the user-mode virtual kernel port. + 99 char Raw parallel ports 0 = /dev/parport0 First parallel port 1 = /dev/parport1 Second parallel port ... -100 char POTS (analogue telephone) A/B port +100 char POTS (analogue telephone) A/B port {2.6} 0 = /dev/phone0 First telephone port 1 = /dev/phone1 Second telephone port ... + The names have been reallocated to Telephony For + Linux, major 159. All use of major 100 should be + considered legacy and deprecated. + 101 char Motorola DSP 56xxx board 0 = /dev/mdspstat Status information 1 = /dev/mdsp1 First DSP board I/O controls ... 16 = /dev/mdsp16 16th DSP board I/O controls -102 char Philips SAA5249 Teletext signal decoder +102 char Philips SAA5249 Teletext signal decoder {2.6} 0 = /dev/tlk0 First Teletext decoder 1 = /dev/tlk1 Second Teletext decoder 2 = /dev/tlk2 Third Teletext decoder @@ -1526,7 +1552,7 @@ 1 = /dev/srnd1 Second miroMEDIA Surround board ... -111 char Philips SAA7146-based audio/video card +111 char Philips SAA7146-based audio/video card {2.6} 0 = /dev/av0 First A/V card 1 = /dev/av1 Second A/V card ... @@ -1562,7 +1588,7 @@ Plays music using IBM BASIC style strings. -116 char Advanced Linux System Driver (ALSA) +116 char Advanced Linux Sound Driver (ALSA) 117 char COSA/SRP synchronous serial card 0 = /dev/cosa0c0 1st board, 1st channel @@ -1691,9 +1717,9 @@ 1 = /dev/gfax1 GammaLink channel 1 ... -159 char Quicknet Technologies Internet PhoneJack/LineJack - 0 = /dev/ixj0 First device - 1 = /dev/ixj1 Second device +159 char Telephony for Linux + 0 = /dev/phone0 First telephony device + 1 = /dev/phone1 Second telephony device ... 160 char General Purpose Instrument Bus (GPIB) @@ -1735,9 +1761,9 @@ 63 = /dev/ttyCH63 AT/PCI-Fast board 3, port 15 165 char Chase Research AT/PCI-Fast serial card - alternate devices - 0 = /dev/cuch0 Callout device corresponding to ttyCH0 + 0 = /dev/cuch0 Callout device for ttyCH0 ... - 63 = /dev/cuch63 Callout device corresponding to ttyCH63 + 63 = /dev/cuch63 Callout device for ttyCH63 166 char ACM USB modems 0 = /dev/ttyACM0 First ACM modem @@ -1796,13 +1822,13 @@ ... 177 char TI PCILynx memory spaces - 0 = /dev/pcilynx/aux0 AUX space of first PCILynx card + 0 = /dev/pcilynx/aux0 AUX space of first PCILynx card ... 15 = /dev/pcilynx/aux15 AUX space of 16th PCILynx card - 16 = /dev/pcilynx/rom0 ROM space of first PCILynx card + 16 = /dev/pcilynx/rom0 ROM space of first PCILynx card ... 31 = /dev/pcilynx/rom15 ROM space of 16th PCILynx card - 32 = /dev/pcilynx/ram0 RAM space of first PCILynx card + 32 = /dev/pcilynx/ram0 RAM space of first PCILynx card ... 47 = /dev/pcilynx/ram15 RAM space of 16th PCILynx card @@ -1829,6 +1855,7 @@ 48 = /dev/usb/scanner0 First USB scanner ... 63 = /dev/usb/scanner15 16th USB scanner + 64 = /dev/usb/rio500 Diamond Rio 500 181 char Conrad Electronic parallel port radio clocks 0 = /dev/pcfclock0 First Conrad radio clock @@ -1836,7 +1863,7 @@ ... 182 char Picture Elements THR2 binarizer - 0 = /dev/pethr0 First THR2 board + 0 = /dev/pethr0 First THR2 board 1 = /dev/pethr1 Second THR2 board ... @@ -1853,7 +1880,12 @@ 1 = /dev/pevss1 Second sender board ... -185 char Reserved for InterMezzo high availability file system +185 char InterMezzo high availability file system + 0 = /dev/intermezzo0 First cache manager + 1 = /dev/intermezzo1 Second cache manager + ... + + See http://www.inter-mezzo.org/ for more information. 186 char Object-based storage control device 0 = /dev/obd0 First obd control device @@ -1862,7 +1894,10 @@ See ftp://ftp.lustre.org/pub/obd for code and information. -187 char UNALLOCATED +187 char DESkey hardware encryption device + 0 = /dev/deskey0 First DES key + 1 = /dev/deskey1 Second DES key + ... 188 char USB serial converters 0 = /dev/ttyUSB0 First USB serial converter @@ -1870,11 +1905,46 @@ ... 189 char USB serial converters - alternate devices - 0 = /dev/cuusb0 Callout device corresponding to ttyUSB0 - 1 = /dev/cuusb1 Callout device corresponding to ttyUSB1 + 0 = /dev/cuusb0 Callout device for ttyUSB0 + 1 = /dev/cuusb1 Callout device for ttyUSB1 ... -190-239 UNALLOCATED +190 char Kansas City tracker/tuner card + 0 = /dev/kctt0 First KCT/T card + 1 = /dev/kctt1 Second KCT/T card + ... + +191 char Reserved for PCMCIA + +192 char Kernel profiling interface + 0 = /dev/profile Profiling control device + 1 = /dev/profile0 Profiling device for CPU 0 + 2 = /dev/profile1 Profiling device for CPU 1 + ... + +193 char Kernel event-tracing interface + 0 = /dev/trace Tracing control device + 1 = /dev/trace0 Tracing device for CPU 0 + 2 = /dev/trace1 Tracing device for CPU 1 + ... + +194 char linVideoStreams (LINVS) + 0 = /dev/mvideo/status0 Video compression status + 1 = /dev/mvideo/stream0 Video stream + 2 = /dev/mvideo/frame0 Single compressed frame + 3 = /dev/mvideo/rawframe0 Raw uncompressed frame + 4 = /dev/mvideo/codec0 Direct codec access + 5 = /dev/mvideo/video4linux0 Video4Linux compatibility + + 16 = /dev/mvideo/status1 Second device + ... + 32 = /dev/mvideo/status2 Third device + ... + ... + 240 = /dev/mvideo/status15 16th device + ... + +195-239 UNALLOCATED 240-254 LOCAL/EXPERIMENTAL USE @@ -1903,7 +1973,6 @@ /dev/stderr fd/2 symbolic stderr file descriptor /dev/nfsd socksys symbolic Required by iBCS-2 /dev/X0R null symbolic Required by iBCS-2 -/dev/i2o* /dev/i2o/* symbolic Backward compatibility Note: /dev/X0R is --. @@ -1916,6 +1985,7 @@ /dev/ftape qft0 symbolic Backward compatibility /dev/bttv0 video0 symbolic Backward compatibility /dev/radio radio0 symbolic Backward compatibility +/dev/i2o* /dev/i2o/* symbolic Backward compatibility /dev/scd? sr? hard Alternate SCSI CD-ROM name Locally defined links @@ -1983,7 +2053,7 @@ starting at /dev/tty1; /dev/tty0 is the current virtual console. /dev/tty0 is the device that should be used to access the system video card on those architectures for which the frame buffer devices -(/dev/fb*) are not applicable. Do not use /dev/console +(/dev/fb*) are not applicable. Do not use /dev/console for this purpose. The console device, /dev/console, is the device to which system @@ -2000,10 +2070,10 @@ one, either in hardware (such as internal modems) or in software (such as the ISDN driver.) Under Linux, each serial ports has two device names, the primary or callin device and the alternate or callout one. -Each kind of device is indicated by a different letter. For any +Each kind of device is indicated by a different letter. For any letter X, the names of the devices are /dev/ttyX# and /dev/cux#, respectively; for historical reasons, /dev/ttyS# and /dev/ttyC# -correspond to /dev/cua# and /dev/cub#. In the future, it should be +correspond to /dev/cua# and /dev/cub#. In the future, it should be expected that multiple letters will be used; all letters will be upper case for the "tty" device (e.g. /dev/ttyDP#) and lower case for the "cu" device (e.g. /dev/cudp#). @@ -2017,7 +2087,7 @@ removed from a future version of Linux. Arbitration of serial ports is provided by the use of lock files with -the names /var/lock/LCK..ttyX#. The contents of the lock file should +the names /var/lock/LCK..ttyX#. The contents of the lock file should be the PID of the locking process as an ASCII number. It is common practice to install links such as /dev/modem @@ -2025,7 +2095,7 @@ presence of these links, it is recommended that software chase symlinks and lock all possible names; additionally, it is recommended that a lock file be installed with the corresponding alternate -device. In order to avoid deadlocks, it is recommended that the locks +device. In order to avoid deadlocks, it is recommended that the locks are acquired in the following order, and released in the reverse: 1. The symbolic link name, if any (/var/lock/LCK..modem) @@ -2045,7 +2115,7 @@ Pseudoterminals, or PTYs, are used to create login sessions or provide other capabilities requiring a TTY line dicipline (including SLIP or -PPP capability) to arbitrary data-generation processes. Each PTY has +PPP capability) to arbitrary data-generation processes. Each PTY has a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named /dev/tty[p-za-e][0-9a-f]. The kernel arbitrates the use of PTYs by allowing each master side to be opened only once. diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/isapnp.txt linux/Documentation/isapnp.txt --- v2.3.99-pre2/linux/Documentation/isapnp.txt Thu Aug 26 13:05:34 1999 +++ linux/Documentation/isapnp.txt Sun Mar 19 18:19:22 2000 @@ -64,10 +64,10 @@ unsigned short device, struct pci_bus *from); -The above function finds a ISA PnP card. For the vendor device should +This function finds a ISA PnP card. For the vendor device should be used ISAPNP_VENDOR(a,b,c) where a,b,c are characters or integers. For the device number should be used ISAPNP_DEVICE(x) macro where x is -integer value. Both vendor and device numbers can be get from contents +integer value. Both vendor and device numbers can be taken from contents of the /proc/isapnp file. extern struct pci_dev *isapnp_find_dev(struct pci_bus *card, @@ -75,12 +75,37 @@ unsigned short function, struct pci_dev *from); -The above function finds the ISA PnP device. If card is NULL, then +This function finds the ISA PnP device. If card is NULL, then the global search mode is used (all devices are used for the searching). Otherwise only devices which belongs to the specified card are verified. For the function number can be used ISAPNP_FUNCTION(x) macro which works similarly as the ISAPNP_DEVICE(x) macro. +extern int isapnp_probe_cards(const struct isapnp_card_id *ids, + int (*probe)(struct pci_bus *card, + const struct isapnp_card_id *id)); + + +This function is a helper for drivers which requires to use more than +one device from an ISA PnP card. For each cards is called the probe +callback with appropriate information. + +Example for ids parameter initialization: + +static struct isapnp_card_id ids[] __devinitdata = { + { + ISAPNP_CARD_ID('A','D','V', 0x550a), + devs: { + ISAPNP_DEVICE_ID('A', 'D', 'V', 0x0010), + ISAPNP_DEVICE_ID('A', 'D', 'V', 0x0011) + }, + driver_data: 0x1234, + }, + { + ISAPNP_CARD_END, + } +}; + ISA PnP configuration ===================== @@ -99,18 +124,24 @@ Second way is auto-configuration -------------------------------- -These two functions gives to the driver the real power of the ISA PnP -feature. First function dev->prepare() only initialize the resource -members in the device structure. This structure contains all resources -set to auto configuration values after the initialization. The driver for -ISA PnP device may modify (or not) some resources to skip auto configuration -for the given resource. +This feature gives to the driver the real power of the ISA PnP code. +Function dev->prepare() initializes the resource members in the device +structure. This structure contains all resources set to auto configuration +values after the initialization. The device driver may modify some resources +to skip the auto configuration for a given resource. + +Once the device structure contains all requested resource values, the function +dev->activate() must be called to assign free resources to resource members +with the auto configuration value. -The function isapnp_configure does: - - resources which have the auto configuration value are configured +Function dev->activate() does: + - resources with the auto configuration value are configured - the auto configuration is created using ISA PnP resource map - the function writes configuration to ISA PnP configuration registers - the function returns to the caller actual used resources + +When the device driver is removing, function dev->deactivate() has to be +called to free all assigned resources. Example (game port initialization) ================================== diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon --- v2.3.99-pre2/linux/Documentation/isdn/README.eicon Wed Feb 16 17:03:51 2000 +++ linux/Documentation/isdn/README.eicon Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -$Id: README.eicon,v 1.6 2000/01/27 09:54:44 armin Exp $ +$Id: README.eicon,v 1.7 2000/03/06 16:38:43 armin Exp $ (c) 1999,2000 Armin Schindler (mac@melware.de) (c) 1999,2000 Cytronics & Melware (info@melware.de) @@ -77,6 +77,10 @@ Example for loading and starting a BRI card with E-DSS1 Protocol. eiconctrl [-d DriverId] load etsi + +Example for a BRI card with E-DSS1 Protocol with PtP configuration. + + eiconctrl [-d DriverId] load etsi -n -t0 -s1 Example for loading and starting a PRI card with E-DSS1 Protocol. diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/networking/tlan.txt linux/Documentation/networking/tlan.txt --- v2.3.99-pre2/linux/Documentation/networking/tlan.txt Thu Feb 10 17:11:02 2000 +++ linux/Documentation/networking/tlan.txt Wed Mar 22 09:37:59 2000 @@ -1,8 +1,8 @@ (C) 1997-1998 Caldera, Inc. (C) 1998 James Banks -(C) 1999-2000 Torben Mathiasen +(C) 1999-2000 Torben Mathiasen -TLAN driver for Linux, version 1.3 +TLAN driver for Linux, version 1.5 README diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt --- v2.3.99-pre2/linux/Documentation/networking/tulip.txt Sat Feb 26 22:31:37 2000 +++ linux/Documentation/networking/tulip.txt Tue Mar 21 12:41:35 2000 @@ -125,7 +125,7 @@ Source tree tour ----------------- +================ The following is a list of files comprising the Tulip ethernet driver in drivers/net/tulip subdirectory. @@ -138,6 +138,25 @@ tulip.h - Private driver header tulip_core.c - Driver core (a.k.a. where "everything else" goes) + + +Version history +=============== +0.9.4.2 (March 21, 2000): +* Fix 21041 CSR7, CSR13/14/15 handling +* Merge some PCI ids from tulip 0.91x +* Merge some HAS_xxx flags and flag settings from tulip 0.91x +* asm/io.h fix (submitted by many) and cleanup +* s/HAS_NWAY143/HAS_NWAY/ +* Cleanup 21041 mode reporting +* Small code cleanups + +0.9.4.1 (March 18, 2000): +* Finish PCI DMA conversion (davem) +* Do not netif_start_queue() at end of tulip_tx_timeout() (kuznet) +* PCI DMA fix (kuznet) +* eeprom.c code cleanup +* Remove Xircom Tulip crud [EOF] diff -u --recursive --new-file v2.3.99-pre2/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README --- v2.3.99-pre2/linux/Documentation/video4linux/bttv/README Tue Mar 14 19:10:38 2000 +++ linux/Documentation/video4linux/bttv/README Sun Mar 19 19:11:37 2000 @@ -84,6 +84,13 @@ mailing me directly. The chance that someone with the same card listens there is much higher... +For problems with sound: There are alot of different systems used +for TV sound all over the world. And there are also different chips +which decode the audio signal. Reports about sound problems ("stereo +does'nt work") are pretty useless unless you include some details +about your hardware and the TV sound scheme used in your country (or +at least the country you are living in). + Finally: If you mail some patches for bttv around the world (to linux-kernel/Alan/Linus/...), please Cc: me. diff -u --recursive --new-file v2.3.99-pre2/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.99-pre2/linux/MAINTAINERS Sun Mar 19 18:35:30 2000 +++ linux/MAINTAINERS Thu Mar 23 15:15:18 2000 @@ -495,36 +495,32 @@ IEEE 1394 SUBSYSTEM P: Andreas Bombe M: andreas.bombe@munich.netsurf.de -L: linux1394-devel@eclipt.uni-klu.ac.at -W: http://eclipt.uni-klu.ac.at/ieee1394 +L: linux1394-devel@lists.sourceforge.net +W: http://linux1394.sourceforge.net/ S: Maintained IEEE 1394 AIC5800 DRIVER P: Emanuel Pirker M: epirker@edu.uni-klu.ac.at L: linux1394-devel@eclipt.uni-klu.ac.at -W: http://eclipt.uni-klu.ac.at/ieee1394 S: Maintained IEEE 1394 OHCI DRIVER P: Sebastien Rougeaux M: sebastien.rougeaux@anu.edu.au L: linux1394-devel@eclipt.uni-klu.ac.at -W: http://eclipt.uni-klu.ac.at/ieee1394 S: Maintained IEEE 1394 PCILYNX DRIVER P: Andreas Bombe M: andreas.bombe@munich.netsurf.de L: linux1394-devel@eclipt.uni-klu.ac.at -W: http://eclipt.uni-klu.ac.at/ieee1394 S: Maintained IEEE 1394 RAW I/O DRIVER P: Andreas Bombe M: andreas.bombe@munich.netsurf.de L: linux1394-devel@eclipt.uni-klu.ac.at -W: http://eclipt.uni-klu.ac.at/ieee1394 S: Maintained INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT @@ -1027,6 +1023,7 @@ TLAN NETWORK DRIVER P: Torben Mathiasen M: torben.mathiasen@compaq.com +M: tmm@image.dk L: tlan@vuser.vu.union.edu S: Maintained @@ -1135,6 +1132,13 @@ L: linux-usb@suse.com S: Maintained W: http://www.kroah.com/linux-usb/ + +USB MASS STORAGE DRIVER +P: Matthew Dharm +M: mdharm-usb@one-eyed-alien.net +L: linux-usb@suse.com +S: Maintained +W: http://www.one-eyed-alien.net/~mdharm/linux-usb/ USB UHCI DRIVER P: Georg Acher diff -u --recursive --new-file v2.3.99-pre2/linux/Makefile linux/Makefile --- v2.3.99-pre2/linux/Makefile Sun Mar 19 18:35:30 2000 +++ linux/Makefile Tue Mar 21 23:38:26 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 3 SUBLEVEL = 99 -EXTRAVERSION = -pre2 +EXTRAVERSION = -pre3 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -90,6 +90,9 @@ CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer AFLAGS := $(CPPFLAGS) +# use '-fno-strict-aliasing', but only if the compiler can take it +CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) + export CPPFLAGS CFLAGS AFLAGS # @@ -143,7 +146,7 @@ DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.a DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.a DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnet.a -DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.a +DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/ide.a DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsi.a DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394.a @@ -179,14 +182,10 @@ include arch/$(ARCH)/Makefile -export CORE_FILES NETWORKS DRIVERS LIBS HEAD LDFLAGS LIBS LINKFLAGS \ - MAKEBOOT ASFLAGS - -# use '-fno-strict-aliasing', but only if the compiler can take it -CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) +export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS .S.s: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.s $< + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -traditional -o $*.s $< .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< @@ -399,6 +398,7 @@ rm -f .hdepend scripts/mkdep scripts/split-include scripts/docproc rm -f $(TOPDIR)/include/linux/modversions.h rm -rf $(TOPDIR)/include/linux/modules + make clean TOPDIR=$(TOPDIR) -C Documentation/DocBook distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ diff -u --recursive --new-file v2.3.99-pre2/linux/Rules.make linux/Rules.make --- v2.3.99-pre2/linux/Rules.make Tue Aug 31 17:29:12 1999 +++ linux/Rules.make Tue Mar 21 13:03:00 2000 @@ -244,7 +244,7 @@ endif # CONFIG_MODVERSIONS ifneq "$(strip $(SYMTAB_OBJS))" "" -$(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h $(SYMTAB_OBJS:.o=.c) +$(SYMTAB_OBJS): $(SYMTAB_OBJS:.o=.c) $(TOPDIR)/include/linux/modversions.h $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) @ ( \ echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \ diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.3.99-pre2/linux/arch/alpha/config.in Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/config.in Thu Mar 23 14:45:04 2000 @@ -55,7 +55,7 @@ # clear all implied options (don't want default values for those): unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 -unset CONFIG_PCI CONFIG_ISA CONFIG_ALPHA_EISA +unset CONFIG_ALPHA_EISA unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA @@ -66,10 +66,13 @@ # and this doesn't activate hordes of code, so do it always. define_bool CONFIG_ISA y -if [ "$CONFIG_ALPHA_GENERIC" = "y" ] +if [ "$CONFIG_ALPHA_JENSEN" = "y" ] then + define_bool CONFIG_PCI n +else define_bool CONFIG_PCI y fi + if [ "$CONFIG_ALPHA_BOOK1" = "y" ] then define_bool CONFIG_ALPHA_NONAME y @@ -77,22 +80,18 @@ if [ "$CONFIG_ALPHA_NONAME" = "y" -o "$CONFIG_ALPHA_EB66" = "y" \ -o "$CONFIG_ALPHA_EB66P" = "y" -o "$CONFIG_ALPHA_P2K" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_LCA y fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_XL" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_APECS y fi if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ - -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" \ - -o "$CONFIG_ALPHA_TAKARA" = "y" ] + -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y fi @@ -107,11 +106,9 @@ define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_APECS y fi - define_bool CONFIG_PCI y fi if [ "$CONFIG_ALPHA_SABLE" = "y" ] then - define_bool CONFIG_PCI y bool 'EV5 CPU(s) (model 5/xxx)?' CONFIG_ALPHA_GAMMA if [ "$CONFIG_ALPHA_GAMMA" = "y" ] then @@ -124,26 +121,22 @@ if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \ -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y define_bool CONFIG_ALPHA_PYXIS y fi if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_TSUNAMI y fi if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_MCPCIA y fi if [ "$CONFIG_ALPHA_RX164" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_POLARIS y fi @@ -153,7 +146,6 @@ fi if [ "$CONFIG_ALPHA_NAUTILUS" = "y" ] then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_IRONGATE y fi diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.3.99-pre2/linux/arch/alpha/defconfig Tue Mar 14 19:10:38 2000 +++ linux/arch/alpha/defconfig Thu Mar 23 14:45:04 2000 @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # +# CONFIG_UID16 is not set # # Code maturity level options @@ -44,7 +45,9 @@ # CONFIG_ALPHA_SX164 is not set # CONFIG_ALPHA_SABLE is not set # CONFIG_ALPHA_TAKARA is not set +CONFIG_ISA=y CONFIG_PCI=y +CONFIG_ALPHA_BROKEN_IRQ_MASK=y # CONFIG_SMP is not set CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set @@ -58,6 +61,10 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set CONFIG_BINFMT_EM86=y + +# +# Parallel port support +# # CONFIG_PARPORT is not set # @@ -70,7 +77,10 @@ # Block devices # CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # # Additional Block Devices @@ -79,10 +89,6 @@ # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set # # Networking options @@ -113,11 +119,14 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set # # ATA/IDE/MFM/RLL support # # CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set # # SCSI support @@ -128,9 +137,11 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 # CONFIG_CHR_DEV_SG is not set # @@ -144,6 +155,7 @@ # # SCSI low-level drivers # +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set @@ -178,6 +190,7 @@ # CONFIG_SCSI_QLOGIC_FAS is not set CONFIG_SCSI_QLOGIC_ISP=y # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -194,6 +207,7 @@ # # CONFIG_ARCNET is not set CONFIG_DUMMY=m +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_NET_SB1000 is not set @@ -207,15 +221,17 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set +# CONFIG_TULIP is not set # CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_EEPRO100 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set @@ -236,7 +252,7 @@ # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -321,15 +337,20 @@ # CONFIG_USB is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -337,7 +358,10 @@ # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set @@ -349,6 +373,7 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -361,8 +386,6 @@ # CONFIG_PARTITION_ADVANCED is not set CONFIG_OSF_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_apecs.c Thu Mar 2 14:36:22 2000 +++ linux/arch/alpha/kernel/core_apecs.c Tue Mar 21 10:46:21 2000 @@ -376,8 +376,12 @@ pci_isa_hose = hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; - hose->config_space = APECS_CONF; hose->index = 0; + + hose->sparse_mem_base = APECS_SPARSE_MEM - IDENT_ADDR; + hose->dense_mem_base = APECS_DENSE_MEM - IDENT_ADDR; + hose->sparse_io_base = APECS_IO - IDENT_ADDR; + hose->dense_io_base = 0; /* * Set up the PCI to main memory translation windows. diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_cia.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/core_cia.c Tue Mar 21 10:46:21 2000 @@ -529,7 +529,7 @@ /* Fifth, verify that a previously invalid PTE entry gets filled from the page table. */ - data0 = 0xabcdef123; + data0 = 0xabcdef12; page[0] = data0; arena->ptes[5] = pte0; mcheck_expected(0) = 1; @@ -640,7 +640,6 @@ pci_isa_hose = hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; - hose->config_space = CIA_CONF; hose->index = 0; if (! is_pyxis) { @@ -654,6 +653,16 @@ if (request_resource(&iomem_resource, hae_mem) < 0) printk(KERN_ERR "Failed to request HAE_MEM\n"); + + hose->sparse_mem_base = CIA_SPARSE_MEM - IDENT_ADDR; + hose->dense_mem_base = CIA_DENSE_MEM - IDENT_ADDR; + hose->sparse_io_base = CIA_IO - IDENT_ADDR; + hose->dense_io_base = 0; + } else { + hose->sparse_mem_base = 0; + hose->dense_mem_base = CIA_BW_MEM - IDENT_ADDR; + hose->sparse_io_base = 0; + hose->dense_io_base = CIA_BW_IO - IDENT_ADDR; } /* diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_irongate.c linux/arch/alpha/kernel/core_irongate.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_irongate.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/core_irongate.c Tue Mar 21 10:46:21 2000 @@ -346,11 +346,21 @@ * Create our single hose. */ - hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; - hose->config_space = IRONGATE_CONF; hose->index = 0; + + /* This is for userland consumption. For some reason, the 40-bit + PIO bias that we use in the kernel through KSEG didn't work for + the page table based user mappings. So make sure we get the + 43-bit PIO bias. */ + hose->sparse_mem_base = 0; + hose->sparse_io_base = 0; + hose->dense_mem_base + = (IRONGATE_MEM & 0xffffffffff) | 0x80000000000; + hose->dense_io_base + = (IRONGATE_IO & 0xffffffffff) | 0x80000000000; hose->sg_isa = hose->sg_pci = NULL; __direct_map_base = 0; diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_lca.c Thu Mar 2 14:36:22 2000 +++ linux/arch/alpha/kernel/core_lca.c Tue Mar 21 10:46:21 2000 @@ -298,8 +298,12 @@ pci_isa_hose = hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; - hose->config_space = LCA_CONF; hose->index = 0; + + hose->sparse_mem_base = LCA_SPARSE_MEM - IDENT_ADDR; + hose->dense_mem_base = LCA_DENSE_MEM - IDENT_ADDR; + hose->sparse_io_base = LCA_IO - IDENT_ADDR; + hose->dense_io_base = 0; /* * Set up the PCI to main memory translation windows. diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_mcpcia.c Thu Mar 2 14:36:22 2000 +++ linux/arch/alpha/kernel/core_mcpcia.c Tue Mar 21 10:46:21 2000 @@ -189,7 +189,7 @@ bus = 0; addr = (bus << 16) | (devfn << 8) | (where); addr <<= 5; /* swizzle for SPARSE */ - addr |= hose->config_space; + addr |= hose->config_space_base; *pci_addr = addr; DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); @@ -337,13 +337,19 @@ int mid = MCPCIA_HOSE2MID(h); hose = alloc_pci_controler(); + if (h == 0) + pci_isa_hose = hose; io = alloc_resource(); mem = alloc_resource(); hae_mem = alloc_resource(); hose->io_space = io; hose->mem_space = hae_mem; - hose->config_space = MCPCIA_CONF(mid); + hose->sparse_mem_base = MCPCIA_SPARSE(mid) - IDENT_ADDR; + hose->dense_mem_base = MCPCIA_DENSE(mid) - IDENT_ADDR; + hose->sparse_io_base = MCPCIA_IO(mid) - IDENT_ADDR; + hose->dense_io_base = 0; + hose->config_space_base = MCPCIA_CONF(mid); hose->index = h; io->start = MCPCIA_IO(mid) - MCPCIA_IO_BIAS; diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_polaris.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/core_polaris.c Tue Mar 21 10:46:21 2000 @@ -192,11 +192,15 @@ * Create our single hose. */ - hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; - hose->config_space = POLARIS_DENSE_CONFIG_BASE; hose->index = 0; + + hose->sparse_mem_base = 0; + hose->dense_mem_base = POLARIS_DENSE_MEM_BASE - IDENT_ADDR; + hose->sparse_io_base = 0; + hose->dense_io_base = POLARIS_DENSE_IO_BASE - IDENT_ADDR; hose->sg_isa = hose->sg_pci = NULL; diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_t2.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/core_t2.c Tue Mar 21 10:46:21 2000 @@ -384,11 +384,15 @@ * Create our single hose. */ - hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controler(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; - hose->config_space = T2_CONF; hose->index = 0; + + hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR; + hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR; + hose->sparse_io_base = T2_IO - IDENT_ADDR; + hose->dense_io_base = 0; hose->sg_isa = hose->sg_pci = NULL; __direct_map_base = 0x40000000; diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.3.99-pre2/linux/arch/alpha/kernel/core_tsunami.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/core_tsunami.c Tue Mar 21 10:46:21 2000 @@ -104,7 +104,7 @@ *type1 = (bus != 0); addr = (bus << 16) | (device_fn << 8) | where; - addr |= hose->config_space; + addr |= hose->config_space_base; *pci_addr = addr; DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); @@ -291,7 +291,18 @@ hose->io_space = alloc_resource(); hose->mem_space = alloc_resource(); - hose->config_space = TSUNAMI_CONF(index); + /* This is for userland consumption. For some reason, the 40-bit + PIO bias that we use in the kernel through KSEG didn't work for + the page table based user mappings. So make sure we get the + 43-bit PIO bias. */ + hose->sparse_mem_base = 0; + hose->sparse_io_base = 0; + hose->dense_mem_base + = (TSUNAMI_MEM(index) & 0xffffffffff) | 0x80000000000; + hose->dense_io_base + = (TSUNAMI_IO(index) & 0xffffffffff) | 0x80000000000; + + hose->config_space_base = TSUNAMI_CONF(index); hose->index = index; hose->io_space->start = TSUNAMI_IO(index) - TSUNAMI_IO_BIAS; diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.3.99-pre2/linux/arch/alpha/kernel/entry.S Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/entry.S Tue Mar 21 10:46:21 2000 @@ -8,7 +8,7 @@ #define SIGCHLD 20 -#define NR_SYSCALLS 376 +#define NR_SYSCALLS 377 /* * These offsets must match with alpha_mv in . @@ -1156,3 +1156,4 @@ .quad sys_ni_syscall /* sys_dipc */ .quad sys_pivot_root .quad sys_mincore /* 375 */ + .quad sys_pciconfig_iobase diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.3.99-pre2/linux/arch/alpha/kernel/osf_sys.c Sun Mar 19 18:35:30 2000 +++ linux/arch/alpha/kernel/osf_sys.c Tue Mar 21 10:47:06 2000 @@ -811,21 +811,8 @@ /* Return current software fp control & status bits. */ /* Note that DU doesn't verify available space here. */ - /* EV6 implements most of the bits in hardware. If - UNDZ is not set, UNFD is maintained in software. */ - if (implver() == IMPLVER_EV6) { - unsigned long fpcr = rdfpcr(); - w = ieee_fpcr_to_swcr(fpcr); - if (!(fpcr & FPCR_UNDZ)) { - w &= ~IEEE_TRAP_ENABLE_UNF; - w |= (current->thread.flags - & IEEE_TRAP_ENABLE_UNF); - } - } else { - /* Otherwise we are forced to do everything in sw. */ - w = current->thread.flags & IEEE_SW_MASK; - } - + w = current->thread.flags & IEEE_SW_MASK; + w = swcr_update_status(w, rdfpcr()); if (put_user(w, (unsigned long *) buffer)) return -EFAULT; return 0; @@ -876,7 +863,7 @@ { switch (op) { case SSI_IEEE_FP_CONTROL: { - unsigned long swcr, fpcr, undz; + unsigned long swcr, fpcr; /* * Alpha Architecture Handbook 4.7.7.3: @@ -891,14 +878,18 @@ current->thread.flags &= ~IEEE_SW_MASK; current->thread.flags |= swcr & IEEE_SW_MASK; - /* Update the real fpcr. Keep UNFD off if not UNDZ. */ + /* Update the real fpcr. */ fpcr = rdfpcr(); - undz = (fpcr & FPCR_UNDZ); - fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ); + fpcr &= FPCR_DYN_MASK; fpcr |= ieee_swcr_to_fpcr(swcr); - fpcr &= ~(undz << 1); wrfpcr(fpcr); - + + /* If any exceptions are now unmasked, send a signal. */ + if (((swcr & IEEE_STATUS_MASK) + >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr) { + send_sig(SIGFPE, current, 1); + } + return 0; } diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.3.99-pre2/linux/arch/alpha/kernel/pci.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/pci.c Tue Mar 21 10:46:21 2000 @@ -377,3 +377,39 @@ return res; } + + +/* Provide information on locations of various I/O regions in physical + memory. Do this on a per-card basis so that we choose the right hose. */ + +asmlinkage long +sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) +{ + struct pci_controler *hose; + struct pci_dev *dev; + + /* Special hook for ISA access. */ + if (bus == 0 && dfn == 0) { + hose = pci_isa_hose; + } else { + dev = pci_find_slot(bus, dfn); + if (!dev) + return -ENODEV; + hose = dev->sysdata; + } + + switch (which) { + case IOBASE_HOSE: + return hose->index; + case IOBASE_SPARSE_MEM: + return hose->sparse_mem_base; + case IOBASE_DENSE_MEM: + return hose->dense_mem_base; + case IOBASE_SPARSE_IO: + return hose->sparse_io_base; + case IOBASE_DENSE_IO: + return hose->dense_io_base; + } + + return -EOPNOTSUPP; +} diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.3.99-pre2/linux/arch/alpha/kernel/process.c Sat Feb 26 22:31:38 2000 +++ linux/arch/alpha/kernel/process.c Tue Mar 21 10:47:06 2000 @@ -251,12 +251,9 @@ flush_thread(void) { /* Arrange for each exec'ed process to start off with a clean slate - with respect to the FPU. This is all exceptions disabled. Note - that EV6 defines UNFD valid only with UNDZ, which we don't want - for IEEE conformance -- so that disabled bit remains in software. */ - + with respect to the FPU. This is all exceptions disabled. */ current->thread.flags &= ~IEEE_SW_MASK; - wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED); + wrfpcr(FPCR_DYN_NORMAL | ieee_swcr_to_fpcr(0)); } void diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.3.99-pre2/linux/arch/alpha/kernel/ptrace.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/ptrace.c Tue Mar 21 10:47:06 2000 @@ -17,6 +17,7 @@ #include #include #include +#include #include "proto.h" @@ -113,18 +114,30 @@ /* * Get contents of register REGNO in task TASK. */ -static inline long +static long get_reg(struct task_struct * task, unsigned long regno) { + /* Special hack for fpcr -- combine hardware and software bits. */ + if (regno == 63) { + unsigned long fpcr = *get_reg_addr(task, regno); + unsigned long swcr = task->thread.flags & IEEE_SW_MASK; + swcr = swcr_update_status(swcr, fpcr); + return fpcr | swcr; + } return *get_reg_addr(task, regno); } /* * Write contents of register REGNO in task TASK. */ -static inline int +static int put_reg(struct task_struct *task, unsigned long regno, long data) { + if (regno == 63) { + task->thread.flags = ((task->thread.flags & ~IEEE_SW_MASK) + | (data & IEEE_SW_MASK)); + data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data); + } *get_reg_addr(task, regno) = data; return 0; } diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c --- v2.3.99-pre2/linux/arch/alpha/kernel/sys_jensen.c Thu Mar 2 14:36:22 2000 +++ linux/arch/alpha/kernel/sys_jensen.c Tue Mar 21 10:46:21 2000 @@ -29,6 +29,7 @@ #include "proto.h" #include "irq_impl.h" +#include "pci_impl.h" #include "machvec_impl.h" @@ -123,6 +124,22 @@ static void __init jensen_init_arch(void) { + struct pci_controler *hose; + + /* Create a hose so that we can report i/o base addresses to + userland. */ + + pci_isa_hose = hose = alloc_pci_controler(); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->index = 0; + + hose->sparse_mem_base = EISA_MEM - IDENT_ADDR; + hose->dense_mem_base = 0; + hose->sparse_io_base = EISA_IO - IDENT_ADDR; + hose->dense_io_base = 0; + + hose->sg_isa = hose->sg_pci = NULL; __direct_map_base = 0; __direct_map_size = 0xffffffff; } diff -u --recursive --new-file v2.3.99-pre2/linux/arch/alpha/math-emu/math.c linux/arch/alpha/math-emu/math.c --- v2.3.99-pre2/linux/arch/alpha/math-emu/math.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/math-emu/math.c Tue Mar 21 10:47:06 2000 @@ -160,8 +160,7 @@ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); unsigned long fa, fb, fc, func, mode, src; - unsigned long fpcw = current->thread.flags; - unsigned long res, va, vb, vc, fpcr; + unsigned long res, va, vb, vc, swcr, fpcr; __u32 insn; MOD_INC_USE_COUNT; @@ -175,10 +174,11 @@ mode = (insn >> 11) & 0x3; fpcr = rdfpcr(); + swcr = swcr_update_status(current->thread.flags, fpcr); if (mode == 3) { - /* Dynamic -- get rounding mode from fpcr. */ - mode = (fpcr >> FPCR_DYN_SHIFT) & 3; + /* Dynamic -- get rounding mode from fpcr. */ + mode = (fpcr >> FPCR_DYN_SHIFT) & 3; } switch (src) { @@ -231,9 +231,14 @@ } FP_CMP_D(res, DA, DB, 3); vc = 0x4000000000000000; - /* CMPTEQ, CMPTUN don't trap on QNaN, while CMPTLT and CMPTLE do */ - if (res == 3 && ((func & 3) >= 2 || FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB))) + /* CMPTEQ, CMPTUN don't trap on QNaN, + while CMPTLT and CMPTLE do */ + if (res == 3 + && ((func & 3) >= 2 + || FP_ISSIGNAN_D(DA) + || FP_ISSIGNAN_D(DB))) { FP_SET_EXCEPTION(FP_EX_INVALID); + } switch (func) { case FOP_FNC_CMPxUN: if (res != 3) vc = 0; break; case FOP_FNC_CMPxEQ: if (res) vc = 0; break; @@ -285,9 +290,11 @@ } case FOP_FNC_CVTxQ: - if (DB_c == FP_CLS_NAN && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D)) - vc = 0; /* AAHB Table B-2 sais QNaN should not trigger INV */ - else + if (DB_c == FP_CLS_NAN + && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D)) { + /* AAHB Table B-2 says QNaN should not trigger INV */ + vc = 0; + } else FP_TO_INT_ROUND_D(vc, DB, 64, 2); goto done_d; } @@ -321,11 +328,15 @@ pack_s: FP_PACK_SP(&vc, SR); + if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ)) + vc = 0; alpha_write_fp_reg_s(fc, vc); goto done; pack_d: FP_PACK_DP(&vc, DR); + if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ)) + vc = 0; done_d: alpha_write_fp_reg(fc, vc); goto done; @@ -345,16 +356,16 @@ done: if (_fex) { /* Record exceptions in software control word. */ - current->thread.flags - = fpcw |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); + swcr |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); + current->thread.flags |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); - /* Update hardware control register */ + /* Update hardware control register. */ fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); - fpcr |= ieee_swcr_to_fpcr(fpcw); + fpcr |= ieee_swcr_to_fpcr(swcr); wrfpcr(fpcr); /* Do we generate a signal? */ - if (_fex & fpcw & IEEE_TRAP_ENABLE_MASK) { + if (_fex & swcr & IEEE_TRAP_ENABLE_MASK) { MOD_DEC_USE_COUNT; return 0; } @@ -378,7 +389,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) { unsigned long trigger_pc = regs->pc - 4; - unsigned long insn, opcode, rc; + unsigned long insn, opcode, rc, no_signal = 0; MOD_INC_USE_COUNT; @@ -402,15 +413,13 @@ case OPC_PAL: case OPC_JSR: case 0x30 ... 0x3f: /* branches */ - MOD_DEC_USE_COUNT; - return 0; + goto egress; case OPC_MISC: switch (insn & 0xffff) { case MISC_TRAPB: case MISC_EXCB: - MOD_DEC_USE_COUNT; - return 0; + goto egress; default: break; @@ -432,16 +441,15 @@ break; } if (!write_mask) { - if (alpha_fp_emul(trigger_pc)) { - /* re-execute insns in trap-shadow: */ - regs->pc = trigger_pc + 4; - MOD_DEC_USE_COUNT; - return 1; - } - break; + /* Re-execute insns in the trap-shadow. */ + regs->pc = trigger_pc + 4; + no_signal = alpha_fp_emul(trigger_pc); + goto egress; } trigger_pc -= 4; } + +egress: MOD_DEC_USE_COUNT; - return 0; + return no_signal; } diff -u --recursive --new-file v2.3.99-pre2/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.3.99-pre2/linux/arch/arm/config.in Sun Mar 19 18:35:30 2000 +++ linux/arch/arm/config.in Thu Mar 23 14:45:04 2000 @@ -119,6 +119,8 @@ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then define_bool CONFIG_PCI y source drivers/pci/Config.in +else + define_bool CONFIG_PCI n fi # @@ -127,8 +129,10 @@ if [ "$CONFIG_ARCH_CATS" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" ]; then + define_bool CONFIG_ISA y define_bool CONFIG_ISA_DMA y else + define_bool CONFIG_ISA n define_bool CONFIG_ISA_DMA n fi diff -u --recursive --new-file v2.3.99-pre2/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.3.99-pre2/linux/arch/arm/defconfig Tue Mar 14 19:10:38 2000 +++ linux/arch/arm/defconfig Thu Mar 23 14:45:04 2000 @@ -2,6 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +CONFIG_UID16=y # # Code maturity level options @@ -19,14 +20,17 @@ CONFIG_HOST_FOOTBRIDGE=y # CONFIG_ADDIN_FOOTBRIDGE is not set CONFIG_ARCH_EBSA285=y -# CONFIG_CATS is not set +# CONFIG_ARCH_CATS is not set CONFIG_ARCH_NETWINDER=y +# CONFIG_ARCH_PERSONAL_SERVER is not set # CONFIG_ARCH_ACORN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set CONFIG_CPU_32v4=y CONFIG_CPU_SA110=y CONFIG_PCI=y +CONFIG_PCI_NAMES=y +CONFIG_ISA=y CONFIG_ISA_DMA=y # CONFIG_ALIGNMENT_TRAP is not set @@ -51,10 +55,14 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_ARTHUR is not set + +# +# Parallel port support +# CONFIG_PARPORT=y CONFIG_PARPORT_PC=y CONFIG_PARPORT_PC_FIFO=y -# CONFIG_PARPORT_PC_PCMCIA is not set +# CONFIG_PARPORT_PC_SUPERIO is not set # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -68,6 +76,11 @@ # CONFIG_LEDS_CPU is not set # +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# # I2O device support # # CONFIG_I2O is not set @@ -87,24 +100,9 @@ # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_STRIPED=m -CONFIG_MD_MIRRORING=m -CONFIG_MD_RAID5=m -CONFIG_BLK_DEV_RAM=y -# CONFIG_BLK_DEV_INITRD is not set # CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -CONFIG_PARIDE_PARPORT=y CONFIG_PARIDE=m +CONFIG_PARIDE_PARPORT=y # # Parallel IDE high-level drivers @@ -132,6 +130,19 @@ CONFIG_PARIDE_KTTI=m CONFIG_PARIDE_ON20=m CONFIG_PARIDE_ON26=m +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_STRIPED=m +CONFIG_BLK_DEV_RAM=y +# CONFIG_BLK_DEV_INITRD is not set # # Character devices @@ -149,6 +160,11 @@ # CONFIG_PPDEV is not set # +# I2C support +# +# CONFIG_I2C is not set + +# # Mice # # CONFIG_BUSMOUSE is not set @@ -172,6 +188,7 @@ CONFIG_SOFT_WATCHDOG=y # CONFIG_PCWATCHDOG is not set # CONFIG_ACQUIRE_WDT is not set +# CONFIG_MIXCOMWD is not set # CONFIG_21285_WATCHDOG is not set CONFIG_977_WATCHDOG=m CONFIG_DS1620=y @@ -188,29 +205,32 @@ # CONFIG_I2C_PARPORT is not set # -# Radio/Video Adapters +# Radio Adapters # # CONFIG_RADIO_CADET is not set # CONFIG_RADIO_RTRACK is not set # CONFIG_RADIO_RTRACK2 is not set # CONFIG_RADIO_AZTECH is not set -# CONFIG_VIDEO_BT848 is not set # CONFIG_RADIO_GEMTEK is not set -# CONFIG_VIDEO_PMS is not set # CONFIG_RADIO_MIROPCM20 is not set -# CONFIG_VIDEO_BWQCAM is not set -# CONFIG_VIDEO_CQCAM is not set -# CONFIG_VIDEO_SAA5249 is not set # CONFIG_RADIO_SF16FMI is not set -# CONFIG_VIDEO_STRADIS is not set # CONFIG_RADIO_TERRATEC is not set # CONFIG_RADIO_TRUST is not set # CONFIG_RADIO_TYPHOON is not set # CONFIG_RADIO_ZOLTRIX is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set # CONFIG_VIDEO_ZORAN is not set # CONFIG_VIDEO_BUZ is not set # CONFIG_VIDEO_ZR36120 is not set -CONFIG_VIDEO_CYBERPRO=m # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -221,15 +241,10 @@ # CONFIG_FTAPE is not set # CONFIG_DRM is not set # CONFIG_DRM_TDFX is not set - -# -# PCMCIA character device support -# -# CONFIG_PCMCIA_SERIAL_CS is not set # CONFIG_AGP is not set # -# Support for USB +# USB support # CONFIG_USB=m @@ -237,32 +252,49 @@ # USB Controllers # # CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=m -CONFIG_USB_OHCI_DEBUG=y -CONFIG_USB_OHCI_HCD=m -CONFIG_USB_OHCI_VROOTHUB=y # # Miscellaneous USB options # -# CONFIG_USB_DEBUG_ISOC is not set -CONFIG_USB_PROC=y -# CONFIG_USB_EZUSB is not set +CONFIG_USB_DEVICEFS=y # # USB Devices # -CONFIG_USB_MOUSE=m -# CONFIG_USB_HP_SCANNER is not set -CONFIG_USB_KBD=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_SCANNER is not set CONFIG_USB_AUDIO=m CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m # CONFIG_USB_SERIAL is not set # CONFIG_USB_CPIA is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set -# CONFIG_USB_SCSI is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_STORAGE is not set # CONFIG_USB_USS720 is not set +# CONFIG_USB_DABUSB is not set +# CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_DSBR is not set + +# +# USB HID +# +# CONFIG_USB_HID is not set +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +# CONFIG_USB_WACOM is not set +# CONFIG_USB_WMFORCE is not set +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_MIX=y +# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set # # Console drivers @@ -300,6 +332,7 @@ # CONFIG_FBCON_MAC is not set # CONFIG_FBCON_VGA_PLANES is not set CONFIG_FBCON_VGA=y +# CONFIG_FBCON_HGA is not set # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y CONFIG_FONT_8x8=y @@ -379,6 +412,7 @@ # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_NET_SB1000 is not set @@ -398,30 +432,30 @@ # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set -CONFIG_DEC_ELCP=m +CONFIG_TULIP=m # CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set CONFIG_NE2K_PCI=y +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # @@ -449,7 +483,7 @@ # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -462,22 +496,23 @@ # CONFIG_WAN is not set # -# PCMCIA network device support +# ATA/IDE/MFM/RLL support # -# CONFIG_NET_PCMCIA is not set +CONFIG_IDE=y # -# ATA/IDE/MFM/RLL support +# IDE, ATA and ATAPI Block devices # -CONFIG_IDE=y CONFIG_BLK_DEV_IDE=y # # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDECS is not set # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -487,32 +522,44 @@ # IDE chipset support/bugfixes # # CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_OFFBOARD=y CONFIG_IDEDMA_PCI_AUTO=y -CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y +CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PCI_EXPERIMENTAL=y -CONFIG_BLK_DEV_OFFBOARD=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_AEC6210_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD7409 is not set +# CONFIG_AMD7409_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_CMD64X_RAID is not set CONFIG_BLK_DEV_CY82C693=y +# CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_HPT366_FIP is not set +# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_PDC202XX=y # CONFIG_PDC202XX_BURST is not set # CONFIG_PDC202XX_MASTER is not set +# CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set CONFIG_BLK_DEV_SL82C105=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y CONFIG_BLK_DEV_IDE_MODES=y -# CONFIG_BLK_DEV_HD is not set # # SCSI support @@ -533,8 +580,12 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set # CONFIG_SOUND_AD1816 is not set # CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set # CONFIG_SOUND_CS4232 is not set # CONFIG_SOUND_SSCAPE is not set # CONFIG_SOUND_GUS is not set @@ -545,9 +596,11 @@ # CONFIG_SOUND_NM256 is not set # CONFIG_SOUND_MAD16 is not set # CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set # CONFIG_SOUND_PSS is not set # CONFIG_SOUND_SOFTOSS is not set CONFIG_SOUND_SB=m +# CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set # CONFIG_SOUND_VIA82CXXX is not set @@ -555,24 +608,18 @@ # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set # CONFIG_SOUND_VIDC is not set CONFIG_SOUND_WAVEARTIST=m -CONFIG_WAVEARTIST_BASE=250 -CONFIG_WAVEARTIST_IRQ=12 -CONFIG_WAVEARTIST_DMA=3 -CONFIG_WAVEARTIST_DMA2=7 # -# Additional low level sound drivers -# -# CONFIG_LOWLEVEL_SOUND is not set - -# -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set CONFIG_ADFS_FS=y +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set @@ -581,12 +628,15 @@ # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=m CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set @@ -612,7 +662,14 @@ # Partition Types # CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_ICS is not set +CONFIG_ACORN_PARTITION_ADFS=y +# CONFIG_ACORN_PARTITION_POWERTEC is not set +# CONFIG_ACORN_PARTITION_RISCIX is not set # CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set @@ -620,13 +677,6 @@ # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -CONFIG_ACORN_PARTITION=y -CONFIG_ACORN_PARTITION_ADFS=y -# CONFIG_ACORN_PARTITION_ICS is not set -# CONFIG_ACORN_PARTITION_POWERTEC is not set -# CONFIG_ACORN_PARTITION_RISCIX is not set CONFIG_NLS=y # diff -u --recursive --new-file v2.3.99-pre2/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.3.99-pre2/linux/arch/i386/Makefile Sun Mar 19 18:35:30 2000 +++ linux/arch/i386/Makefile Wed Mar 22 22:23:54 2000 @@ -30,56 +30,42 @@ CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi) ifdef CONFIG_M386 -CFLAGS := $(CFLAGS) -DCPU=386 CFLAGS += $(shell if $(CC) -march=i386 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i386"; else echo "-m386"; fi) -AFLAGS := $(AFLAGS) -DCPU=386 endif ifdef CONFIG_M486 -CFLAGS := $(CFLAGS) -DCPU=486 CFLAGS += $(shell if $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i486"; else echo "-m486"; fi) -AFLAGS := $(AFLAGS) -DCPU=486 endif ifdef CONFIG_M586 -CFLAGS := $(CFLAGS) -DCPU=586 CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi) -AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_M586TSC -CFLAGS := $(CFLAGS) -DCPU=586 CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi) -AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_M686 -CFLAGS := $(CFLAGS) -DCPU=686 CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) -AFLAGS := $(AFLAGS) -DCPU=686 endif ifdef CONFIG_MK6 -CFLAGS := $(CFLAGS) -DCPU=586 CFLAGS += $(shell if $(CC) -march=k6 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=k6"; fi) -AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_MK7 -CFLAGS := $(CFLAGS) -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations -DCPU=686 -CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) -AFLAGS := $(AFLAGS) -DCPU=686 +CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations endif HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o -SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib +SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a ifdef CONFIG_MATH_EMULATION -SUBDIRS := $(SUBDIRS) arch/i386/math-emu -DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a +SUBDIRS += arch/i386/math-emu +DRIVERS += arch/i386/math-emu/math.a endif arch/i386/kernel: dummy diff -u --recursive --new-file v2.3.99-pre2/linux/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c --- v2.3.99-pre2/linux/arch/i386/boot/compressed/misc.c Tue Nov 23 22:42:20 1999 +++ linux/arch/i386/boot/compressed/misc.c Mon Mar 20 08:24:54 2000 @@ -145,7 +145,7 @@ free_mem_ptr = (long) *ptr; } -static void scroll() +static void scroll(void) { int i; @@ -197,6 +197,7 @@ char *ss = (char*)s; for (i=0;i IRQ %d\n", i, ints[i+1]); + printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* * PIRQs are mapped upside down, usually. */ @@ -289,7 +289,7 @@ unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } - printk("Broken MPtable reports ISA irq %d\n", irq); + printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); return 0; } @@ -338,7 +338,7 @@ } default: { - printk("broken BIOS!!\n"); + printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } @@ -352,7 +352,7 @@ } case 2: /* reserved */ { - printk("broken BIOS!!\n"); + printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } @@ -363,7 +363,7 @@ } default: /* invalid */ { - printk("broken BIOS!!\n"); + printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } @@ -402,7 +402,7 @@ } default: { - printk("broken BIOS!!\n"); + printk(KERN_WARNING "broken BIOS!!\n"); trigger = 1; break; } @@ -416,7 +416,7 @@ } case 2: /* reserved */ { - printk("broken BIOS!!\n"); + printk(KERN_WARNING "broken BIOS!!\n"); trigger = 1; break; } @@ -427,7 +427,7 @@ } default: /* invalid */ { - printk("broken BIOS!!\n"); + printk(KERN_WARNING "broken BIOS!!\n"); trigger = 0; break; } @@ -454,7 +454,7 @@ * Debugging check, we are in big trouble if this message pops up! */ if (mp_irqs[idx].mpc_dstirq != pin) - printk("broken BIOS or MPTABLE parser, ayiee!!\n"); + printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); switch (mp_bus_id_to_type[bus]) { @@ -477,7 +477,7 @@ } default: { - printk("unknown bus type %d.\n",bus); + printk(KERN_ERR "unknown bus type %d.\n",bus); irq = 0; break; } @@ -489,10 +489,10 @@ if ((pin >= 16) && (pin <= 23)) { if (pirq_entries[pin-16] != -1) { if (!pirq_entries[pin-16]) { - printk("disabling PIRQ%d\n", pin-16); + printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); } else { irq = pirq_entries[pin-16]; - printk("using PIRQ%d -> IRQ %d\n", + printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", pin-16, irq); } } @@ -549,7 +549,7 @@ struct IO_APIC_route_entry entry; int apic, pin, idx, irq, first_notcon = 1, vector; - printk("init IO_APIC IRQs\n"); + printk(KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -567,7 +567,7 @@ idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(" IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); + printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); first_notcon = 0; } else printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin); @@ -658,8 +658,8 @@ void __init UNEXPECTED_IO_APIC(void) { - printk(" WARNING: unexpected IO-APIC, please mail\n"); - printk(" to linux-smp@vger.rutgers.edu\n"); + printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n"); + printk(KERN_WARNING " to linux-smp@vger.rutgers.edu\n"); } void __init print_IO_APIC(void) @@ -669,15 +669,16 @@ struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_02 reg_02; - printk("number of MP IRQ sources: %d.\n", mp_irq_entries); + printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) - printk("number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); + printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", + mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); /* * We are a bit conservative about what we expect. We have to * know about every hardware change ASAP. */ - printk("testing the IO APIC.......................\n"); + printk(KERN_INFO "testing the IO APIC.......................\n"); for (apic = 0; apic < nr_ioapics; apic++) { @@ -686,14 +687,15 @@ if (reg_01.version >= 0x10) *(int *)®_02 = io_apic_read(apic, 2); - printk("\nIO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); - printk(".... register #00: %08X\n", *(int *)®_00); - printk("....... : physical APIC id: %02X\n", reg_00.ID); + printk("\n"); + printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); + printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)®_00); + printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.ID); if (reg_00.__reserved_1 || reg_00.__reserved_2) UNEXPECTED_IO_APIC(); - printk(".... register #01: %08X\n", *(int *)®_01); - printk("....... : max redirection entries: %04X\n", reg_01.entries); + printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); + printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.entries); if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */ (reg_01.entries != 0x17) && /* typical ISA+PCI boards */ (reg_01.entries != 0x1b) && /* Compaq Proliant boards */ @@ -704,7 +706,7 @@ ) UNEXPECTED_IO_APIC(); - printk("....... : IO APIC version: %04X\n", reg_01.version); + printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.version); if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */ (reg_01.version != 0x10) && /* oldest IO-APICs */ (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */ @@ -715,16 +717,16 @@ UNEXPECTED_IO_APIC(); if (reg_01.version >= 0x10) { - printk(".... register #02: %08X\n", *(int *)®_02); - printk("....... : arbitration: %02X\n", reg_02.arbitration); + printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)®_02); + printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration); if (reg_02.__reserved_1 || reg_02.__reserved_2) UNEXPECTED_IO_APIC(); } - printk(".... IRQ redirection table:\n"); + printk(KERN_DEBUG ".... IRQ redirection table:\n"); - printk(" NR Log Phy "); - printk("Mask Trig IRR Pol Stat Dest Deli Vect: \n"); + printk(KERN_DEBUG " NR Log Phy "); + printk(KERN_DEBUG "Mask Trig IRR Pol Stat Dest Deli Vect: \n"); for (i = 0; i <= reg_01.entries; i++) { struct IO_APIC_route_entry entry; @@ -732,7 +734,7 @@ *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); - printk(" %02x %03X %02X ", + printk(KERN_DEBUG " %02x %03X %02X ", i, entry.dest.logical.logical_dest, entry.dest.physical.physical_dest @@ -765,7 +767,7 @@ printk("\n"); } - printk(".................................... done.\n"); + printk(KERN_INFO ".................................... done.\n"); return; } @@ -775,7 +777,7 @@ unsigned int v; int i, j; - printk("0123456789abcdef0123456789abcdef\n"); + printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); for (i = 0; i < 8; i++) { v = apic_read(base + i*0x10); for (j = 0; j < 32; j++) { @@ -792,40 +794,40 @@ { unsigned int v, ver, maxlvt; - printk("\nprinting local APIC contents on CPU#%d/%d:\n", + printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", smp_processor_id(), hard_smp_processor_id()); v = apic_read(APIC_ID); - printk("... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v)); + printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v)); v = apic_read(APIC_LVR); - printk("... APIC VERSION: %08x\n", v); + printk(KERN_INFO "... APIC VERSION: %08x\n", v); ver = GET_APIC_VERSION(v); maxlvt = get_maxlvt(); v = apic_read(APIC_TASKPRI); - printk("... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); + printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); if (APIC_INTEGRATED(ver)) { /* !82489DX */ v = apic_read(APIC_ARBPRI); - printk("... APIC ARBPRI: %08x (%02x)\n", v, + printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, v & APIC_ARBPRI_MASK); v = apic_read(APIC_PROCPRI); - printk("... APIC PROCPRI: %08x\n", v); + printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); } v = apic_read(APIC_EOI); - printk("... APIC EOI: %08x\n", v); + printk(KERN_DEBUG "... APIC EOI: %08x\n", v); v = apic_read(APIC_LDR); - printk("... APIC LDR: %08x\n", v); + printk(KERN_DEBUG "... APIC LDR: %08x\n", v); v = apic_read(APIC_DFR); - printk("... APIC DFR: %08x\n", v); + printk(KERN_DEBUG "... APIC DFR: %08x\n", v); v = apic_read(APIC_SPIV); - printk("... APIC SPIV: %08x\n", v); + printk(KERN_DEBUG "... APIC SPIV: %08x\n", v); - printk("... APIC ISR field:\n"); + printk(KERN_DEBUG "... APIC ISR field:\n"); print_APIC_bitfield(APIC_ISR); - printk("... APIC TMR field:\n"); + printk(KERN_DEBUG "... APIC TMR field:\n"); print_APIC_bitfield(APIC_TMR); - printk("... APIC IRR field:\n"); + printk(KERN_DEBUG "... APIC IRR field:\n"); print_APIC_bitfield(APIC_IRR); if (APIC_INTEGRATED(ver)) { /* !82489DX */ @@ -837,37 +839,37 @@ apic_write(APIC_ESR, 0); } v = apic_read(APIC_ESR); - printk("... APIC ESR: %08x\n", v); + printk(KERN_DEBUG "... APIC ESR: %08x\n", v); } v = apic_read(APIC_ICR); - printk("... APIC ICR: %08x\n", v); + printk(KERN_DEBUG "... APIC ICR: %08x\n", v); v = apic_read(APIC_ICR2); - printk("... APIC ICR2: %08x\n", v); + printk(KERN_DEBUG "... APIC ICR2: %08x\n", v); v = apic_read(APIC_LVTT); - printk("... APIC LVTT: %08x\n", v); + printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); if (maxlvt > 3) { /* PC is LVT#4. */ v = apic_read(APIC_LVTPC); - printk("... APIC LVTPC: %08x\n", v); + printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v); } v = apic_read(APIC_LVT0); - printk("... APIC LVT0: %08x\n", v); + printk(KERN_DEBUG "... APIC LVT0: %08x\n", v); v = apic_read(APIC_LVT1); - printk("... APIC LVT1: %08x\n", v); + printk(KERN_DEBUG "... APIC LVT1: %08x\n", v); if (maxlvt > 2) { /* ERR is LVT#3. */ v = apic_read(APIC_LVTERR); - printk("... APIC LVTERR: %08x\n", v); + printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v); } v = apic_read(APIC_TMICT); - printk("... APIC TMICT: %08x\n", v); + printk(KERN_DEBUG "... APIC TMICT: %08x\n", v); v = apic_read(APIC_TMCCT); - printk("... APIC TMCCT: %08x\n", v); + printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v); v = apic_read(APIC_TDCR); - printk("... APIC TDCR: %08x\n", v); + printk(KERN_DEBUG "... APIC TDCR: %08x\n", v); printk("\n"); } @@ -958,7 +960,7 @@ * Read the right value from the MPC table and * write it into the ID register. */ - printk("...changing IO-APIC physical APIC ID to %d ...", + printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", mp_ioapics[apic].mpc_apicid); /* @@ -1061,7 +1063,7 @@ for (j = 0; j < smp_num_cpus; j++) { cpu = cpu_logical_map(j); if (atomic_read(&nmi_counter(cpu)) - atomic_read(&tmp[cpu].__nmi_counter) <= 3) { - printk("CPU#%d NMI appears to be stuck.\n", cpu); + printk(KERN_WARNING "CPU#%d NMI appears to be stuck.\n", cpu); return 0; } } @@ -1270,7 +1272,7 @@ * is from Maciej W. Rozycki - so we do not have to EOI from * the NMI handler or the timer interrupt. */ - printk("activating NMI Watchdog ..."); + printk(KERN_INFO "activating NMI Watchdog ..."); smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1); enable_NMI_through_LVT0(NULL); @@ -1299,7 +1301,7 @@ pin1 = find_timer_pin(mp_INT); pin2 = find_timer_pin(mp_ExtINT); - printk("..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2); + printk(KERN_INFO "..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2); /* * Ok, does IRQ0 through the IOAPIC work? @@ -1317,11 +1319,11 @@ } if (pin1 != -1) { - printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); + printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); clear_IO_APIC_pin(0, pin1); } - printk("...trying to set up timer (IRQ0) through the 8259A ... "); + printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); if (pin2 != -1) { printk("\n..... (found pin %d) ...", pin2); /* @@ -1345,11 +1347,11 @@ printk(" failed.\n"); if (nmi_watchdog) { - printk("timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n"); + printk(KERN_WARNING "timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n"); nmi_watchdog = 0; } - printk("...trying to set up timer as Virtual Wire IRQ..."); + printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); disable_8259A_irq(0); irq_desc[0].handler = &lapic_irq_type; diff -u --recursive --new-file v2.3.99-pre2/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.3.99-pre2/linux/arch/i386/kernel/signal.c Thu Mar 2 14:36:22 2000 +++ linux/arch/i386/kernel/signal.c Thu Mar 23 08:15:01 2000 @@ -597,10 +597,6 @@ * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. - * - * Note that we go through the signals twice: once to check the signals that - * the kernel can handle, and then we build all the user-level signal handling - * stack-frames in one go after that. */ int do_signal(struct pt_regs *regs, sigset_t *oldset) { diff -u --recursive --new-file v2.3.99-pre2/linux/arch/i386/lib/checksum.S linux/arch/i386/lib/checksum.S --- v2.3.99-pre2/linux/arch/i386/lib/checksum.S Sun May 16 13:17:22 1999 +++ linux/arch/i386/lib/checksum.S Wed Mar 22 22:23:54 2000 @@ -25,6 +25,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include /* @@ -39,7 +40,7 @@ .align 4 .globl csum_partial -#if CPU!=686 +#ifndef CONFIG_X86_USE_PPRO_CHECKSUM /* * Experiments with Ethernet and SLIP connections show that buff @@ -114,7 +115,9 @@ popl %esi ret -#else /* CPU==686 */ +#else + +/* Version for PentiumII/PPro */ csum_partial: pushl %esi @@ -210,7 +213,7 @@ popl %esi ret -#endif /* CPU==686 */ +#endif /* unsigned int csum_partial_copy_generic (const char *src, char *dst, @@ -243,7 +246,7 @@ .align 4 .globl csum_partial_copy_generic -#if CPU!=686 +#ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 @@ -448,4 +451,4 @@ #undef ROUND #undef ROUND1 -#endif /* CPU==i686 */ +#endif diff -u --recursive --new-file v2.3.99-pre2/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.3.99-pre2/linux/arch/ia64/config.in Tue Mar 14 19:10:39 2000 +++ linux/arch/ia64/config.in Thu Mar 23 14:45:05 2000 @@ -19,11 +19,11 @@ if [ "$CONFIG_IA64_DIG" = "y" ]; then bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC - bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS n - bool ' Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS y - bool ' Enable Lion hacks' CONFIG_IA64_LION_HACKS n - bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU n - bool ' Get PCI IRQ routing from firmware/ACPI' CONFIG_IA64_IRQ_ACPI y + bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS + bool ' Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS + bool ' Enable Lion hacks' CONFIG_IA64_LION_HACKS + bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU + bool ' Get PCI IRQ routing from firmware/ACPI' CONFIG_IA64_IRQ_ACPI fi if [ "$CONFIG_IA64_GENERIC" = "y" ]; then @@ -37,33 +37,32 @@ define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore. -bool 'SMP support' CONFIG_SMP n -bool 'Performance monitor support' CONFIG_PERFMON n +bool 'SMP support' CONFIG_SMP +bool 'Performance monitor support' CONFIG_PERFMON -bool 'Networking support' CONFIG_NET n -bool 'System V IPC' CONFIG_SYSVIPC n -bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT n -bool 'Sysctl support' CONFIG_SYSCTL n +bool 'Networking support' CONFIG_NET +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -bool 'PCI support' CONFIG_PCI n +bool 'PCI support' CONFIG_PCI source drivers/pci/Config.in source drivers/pcmcia/Config.in mainmenu_option next_comment comment 'Code maturity level options' - bool 'Prompt for development and/or incomplete code/drivers' \ - CONFIG_EXPERIMENTAL n + bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL endmenu mainmenu_option next_comment comment 'Loadable module support' - bool 'Enable loadable module support' CONFIG_MODULES n + bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n - bool 'Kernel module loader' CONFIG_KMOD n + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD fi endmenu @@ -99,7 +98,7 @@ if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in - bool 'Simulated SCSI disk' CONFIG_SCSI_SIM n + bool 'Simulated SCSI disk' CONFIG_SCSI_SIM fi endmenu @@ -107,7 +106,7 @@ mainmenu_option next_comment comment 'Network device support' - bool 'Network device support' CONFIG_NETDEVICES n + bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in fi @@ -128,7 +127,7 @@ mainmenu_option next_comment comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' -bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI n +bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then source drivers/cdrom/Config.in fi @@ -145,11 +144,11 @@ if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' - bool 'VGA text console' CONFIG_VGA_CONSOLE n + bool 'VGA text console' CONFIG_VGA_CONSOLE + source drivers/video/Config.in if [ "$CONFIG_FB" = "y" ]; then define_bool CONFIG_PCI_CONSOLE y fi - source drivers/video/Config.in endmenu fi @@ -173,11 +172,11 @@ define_bool CONFIG_MATHEMU y fi -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ n -bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK n -bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG n -bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ n -bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS n +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK +bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG +bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ +bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS bool 'Built-in Kernel Debugger support' CONFIG_KDB if [ "$CONFIG_KDB" = "y" ]; then bool 'Compile the kernel with frame pointers' CONFIG_KDB_FRAMEPTR diff -u --recursive --new-file v2.3.99-pre2/linux/arch/ia64/defconfig linux/arch/ia64/defconfig --- v2.3.99-pre2/linux/arch/ia64/defconfig Tue Mar 14 19:10:39 2000 +++ linux/arch/ia64/defconfig Thu Mar 23 14:45:05 2000 @@ -3,6 +3,35 @@ # # +# General setup +# +CONFIG_IA64=y +# CONFIG_IA64_GENERIC is not set +CONFIG_IA64_HP_SIM=y +# CONFIG_IA64_SGI_SN1_SIM is not set +# CONFIG_IA64_DIG is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_KCORE_ELF=y +# CONFIG_SMP is not set +# CONFIG_PERFMON is not set +# CONFIG_NET is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_BINFMT_ELF is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_PCI=y +CONFIG_PCI_NAMES=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# # Code maturity level options # CONFIG_EXPERIMENTAL=y @@ -13,53 +42,56 @@ # CONFIG_MODULES is not set # -# General setup +# Parallel port support # -CONFIG_IA64_SIM=y -CONFIG_PCI=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y -# CONFIG_NET is not set -# CONFIG_SYSVIPC is not set -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -# CONFIG_BINFMT_ELF is not set -# CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set -# CONFIG_BINFMT_EM86 is not set # CONFIG_PARPORT is not set # -# Plug and Play support +# Plug and Play configuration # # CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # # Additional Block Devices # # CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set # # ATA/IDE/MFM/RLL support # CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# CONFIG_BLK_DEV_IDE=y # # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set # CONFIG_BLK_DEV_IDECS is not set @@ -78,24 +110,44 @@ CONFIG_BLK_DEV_IDEPCI=y CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y -# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PCI_EXPERIMENTAL=y -# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_AEC6210_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD7409 is not set +# CONFIG_AMD7409_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_CMD64X_RAID is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_HPT366_FIP is not set +# CONFIG_HPT366_MODE3 is not set CONFIG_BLK_DEV_PIIX=y CONFIG_PIIX_TUNING=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_MASTER is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y CONFIG_BLK_DEV_IDE_MODES=y -# CONFIG_BLK_DEV_HD is not set # # SCSI support # # CONFIG_SCSI is not set -# CONFIG_SCSI_G_NCR5380_PORT is not set -# CONFIG_SCSI_G_NCR5380_MEM is not set # # Amateur Radio support @@ -120,51 +172,91 @@ # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set # CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# # CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set # CONFIG_RTC is not set CONFIG_EFI_RTC=y + +# +# Video For Linux +# # CONFIG_VIDEO_DEV is not set -# CONFIG_NVRAM is not set -# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_FT_NORMAL_DEBUG is not set -# CONFIG_FT_FULL_DEBUG is not set -# CONFIG_FT_NO_TRACE is not set -# CONFIG_FT_NO_TRACE_AT_ALL is not set -# CONFIG_FT_STD_FDC is not set -# CONFIG_FT_MACH2 is not set -# CONFIG_FT_PROBE_FC10 is not set -# CONFIG_FT_ALT_FDC is not set +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set # -# Filesystems +# USB support +# +# CONFIG_USB is not set + +# +# File systems # # CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -# CONFIG_EXT2_FS is not set -# CONFIG_ISO9660_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_PROC_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_PROC_FS is not set +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SMD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_ADFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_MAC_PARTITION is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set # CONFIG_NLS is not set # @@ -175,5 +267,11 @@ # # Kernel hacking # +# CONFIG_IA32_SUPPORT is not set # CONFIG_MATHEMU is not set # CONFIG_MAGIC_SYSRQ is not set +# CONFIG_IA64_EARLY_PRINTK is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_IA64_PRINT_HAZARDS is not set +# CONFIG_KDB is not set diff -u --recursive --new-file v2.3.99-pre2/linux/arch/m68k/Makefile linux/arch/m68k/Makefile --- v2.3.99-pre2/linux/arch/m68k/Makefile Tue Sep 7 12:14:06 1999 +++ linux/arch/m68k/Makefile Thu Mar 23 08:47:44 2000 @@ -19,10 +19,6 @@ # override top level makefile AS += -m68020 LD += -m m68kelf -ifneq ($(COMPILE_ARCH),$(ARCH)) - # prefix for cross-compiling binaries - CROSS_COMPILE = m68k-linux- -endif ifndef CONFIG_SUN3 LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds diff -u --recursive --new-file v2.3.99-pre2/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.3.99-pre2/linux/arch/m68k/config.in Tue Mar 14 19:10:39 2000 +++ linux/arch/m68k/config.in Thu Mar 23 14:45:05 2000 @@ -15,6 +15,7 @@ mainmenu_option next_comment comment 'Platform dependent setup' +define_bool CONFIG_ISA n bool 'Amiga support' CONFIG_AMIGA bool 'Atari support' CONFIG_ATARI if [ "$CONFIG_ATARI" = "y" ]; then diff -u --recursive --new-file v2.3.99-pre2/linux/arch/m68k/defconfig linux/arch/m68k/defconfig --- v2.3.99-pre2/linux/arch/m68k/defconfig Tue Mar 14 19:10:39 2000 +++ linux/arch/m68k/defconfig Thu Mar 23 14:45:05 2000 @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # +CONFIG_UID16=y # # Code maturity level options @@ -8,18 +9,19 @@ CONFIG_EXPERIMENTAL=y # -# Loadable module support -# -# CONFIG_MODULES is not set -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set - -# -# Platform-dependent setup +# Platform dependent setup # +# CONFIG_ISA is not set CONFIG_AMIGA=y # CONFIG_ATARI is not set +# CONFIG_PCI is not set # CONFIG_MAC is not set +# CONFIG_APOLLO is not set +# CONFIG_VME is not set +# CONFIG_HP300 is not set +# CONFIG_SUN3X is not set +# CONFIG_SUN3 is not set +# CONFIG_Q40 is not set # # Processor type @@ -28,42 +30,48 @@ CONFIG_M68030=y CONFIG_M68040=y # CONFIG_M68060 is not set +# CONFIG_M68KFPU_EMU is not set # CONFIG_ADVANCED is not set -# CONFIG_SINGLE_MEMORY_CHUNK is not set -# CONFIG_RMW_INSNS is not set # # General setup # CONFIG_NET=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_ZORRO=y -# CONFIG_AMIGA_GSP is not set -# CONFIG_GSP_RESOLVER is not set -# CONFIG_GSP_A2410 is not set # CONFIG_AMIGA_PCMCIA is not set # CONFIG_HEARTBEAT is not set CONFIG_PROC_HARDWARE=y +# CONFIG_PARPORT is not set +# CONFIG_PRINTER is not set # -# Block device driver configuration +# Loadable module support # +# CONFIG_MODULES is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set CONFIG_AMIGA_FLOPPY=y -CONFIG_ATARI_FLOPPY=y -# CONFIG_BLK_DEV_LOOP is not set # CONFIG_AMIGA_Z2RAM is not set -# CONFIG_ATARI_ACSI is not set -# CONFIG_ACSI_MULTI_LUN is not set -# CONFIG_ATARI_SLM +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set + +# +# Additional Block Devices +# # CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y @@ -71,8 +79,9 @@ # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -88,16 +97,17 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y # CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # # # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -106,7 +116,6 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -117,6 +126,8 @@ # ATA/IDE/MFM/RLL support # # CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set # # SCSI support @@ -124,12 +135,15 @@ CONFIG_SCSI=y # -# SCSI support type (disk, tape, CDrom) +# SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 # CONFIG_CHR_DEV_SG is not set # @@ -143,6 +157,7 @@ # SCSI low-level drivers # CONFIG_A3000_SCSI=y +# CONFIG_A4000T_SCSI is not set CONFIG_A2091_SCSI=y CONFIG_GVP11_SCSI=y # CONFIG_CYBERSTORM_SCSI is not set @@ -150,13 +165,10 @@ # CONFIG_BLZ2060_SCSI is not set # CONFIG_BLZ1230_SCSI is not set # CONFIG_FASTLANE_SCSI is not set -# CONFIG_A4000T_SCSI is not set # CONFIG_A4091_SCSI is not set # CONFIG_WARPENGINE_SCSI is not set # CONFIG_BLZ603EPLUS_SCSI is not set -CONFIG_ATARI_SCSI=y -# CONFIG_ATARI_SCSI_TOSHIBA_DELAY is not set -# CONFIG_ATARI_SCSI_RESET_BOOT is not set +# CONFIG_OKTAGON_SCSI is not set # # Network device support @@ -165,80 +177,150 @@ # CONFIG_DUMMY is not set # CONFIG_SLIP is not set # CONFIG_PPP is not set +# CONFIG_EQUALIZER is not set # CONFIG_ARIADNE is not set # CONFIG_ARIADNE2 is not set # CONFIG_A2065 is not set # CONFIG_HYDRA is not set -# CONFIG_APNE is not set -# CONFIG_ATARILANCE is not set -# CONFIG_ATARI_BIONET is not set -# CONFIG_ATARI_PAMSNET is not set # -# Filesystems +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_AMIGAMOUSE=y +CONFIG_BUSMOUSE=y +CONFIG_AMIGA_BUILTIN_SERIAL=y +# CONFIG_GVPIOEXT is not set +# CONFIG_GVPIOEXT_LP is not set +# CONFIG_GVPIOEXT_PLIP is not set +# CONFIG_MULTIFACE_III_TTY is not set +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_USERIAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# Sound support +# +# CONFIG_SOUND is not set + +# +# File systems # # CONFIG_QUOTA is not set -CONFIG_MINIX_FS=y -CONFIG_EXT2_FS=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y -# CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set -# CONFIG_MSDOS_PARTITION is not set -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set -# CONFIG_SMB_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set # CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +CONFIG_MINIX_FS=y +# CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_CRAMFS is not set # -# Frame buffer devices +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_AMIGA_PARTITION=y +CONFIG_NLS=y + +# +# Native Language Support # +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Console drivers +# +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set CONFIG_FB_AMIGA=y CONFIG_FB_AMIGA_OCS=y CONFIG_FB_AMIGA_ECS=y CONFIG_FB_AMIGA_AGA=y # CONFIG_FB_CYBER is not set # CONFIG_FB_VIRGE is not set -# CONFIG_FB_CVPPC is not set # CONFIG_FB_RETINAZ3 is not set -# CONFIG_FB_CLGEN is not set -# CONFIG_FB_ATARI is not set +# CONFIG_FB_FM2 is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set - -CONFIG_NLS_CODEPAGE_437=y - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_M68K_PRINTER is not set -CONFIG_AMIGAMOUSE=y -CONFIG_ATARIMOUSE=y -CONFIG_AMIGA_BUILTIN_SERIAL=y -# CONFIG_GVPIOEXT is not set -# CONFIG_GVPIOEXT_LP is not set -# CONFIG_GVPIOEXT_PLIP is not set -# CONFIG_MULTIFACE_III_TTY is not set -# CONFIG_USERIAL is not set -# CONFIG_WATCHDOG is not set -# CONFIG_UMISC is not set - -# -# Sound -# -# CONFIG_SOUND is not set -# CONFIG_DMASOUND is not set +CONFIG_FBCON_MFB=y +CONFIG_FBCON_AFB=y +CONFIG_FBCON_ILBM=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_FONT_PEARL_8x8=y # # Kernel hacking # -CONFIG_SCSI_CONSTANTS=y +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.3.99-pre2/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.3.99-pre2/linux/arch/mips/config.in Tue Mar 14 19:10:39 2000 +++ linux/arch/mips/config.in Thu Mar 23 14:45:05 2000 @@ -26,34 +26,37 @@ # # Select some configuration options automatically for certain systems. # -unset CONFIG_PCI -unset CONFIG_ISA unset CONFIG_MIPS_JAZZ unset CONFIG_VIDEO_G364 -if [ "$CONFIG_ALGOR_P4032" = "y" ]; then +if [ "$CONFIG_ALGOR_P4032" = "y" -o "$CONFIG_SNI_RM200_PCI" = "y" -o \ + "$CONFIG_DDB5074" = "y" ]; then define_bool CONFIG_PCI y +else + define_bool CONFIG_PCI n fi +if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o "$CONFIG_OLIVETTI_M700" = "y" -o \ + "$CONFIG_SNI_RM200_PCI" = "y" -o "$CONFIG_ACER_PICA_61" = "y" ]; then + define_bool CONFIG_ISA y +else + define_bool CONFIG_ISA n +fi + if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ "$CONFIG_OLIVETTI_M700" = "y" ]; then - define_bool CONFIG_ISA y define_bool CONFIG_HAVE_IO_PORTS y define_bool CONFIG_MIPS_JAZZ y define_bool CONFIG_FB y define_bool CONFIG_FB_G364 y fi if [ "$CONFIG_ACER_PICA_61" = "y" ]; then - define_bool CONFIG_ISA y define_bool CONFIG_HAVE_IO_PORTS y define_bool CONFIG_MIPS_JAZZ y fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then - define_bool CONFIG_ISA y define_bool CONFIG_HAVE_IO_PORTS y - define_bool CONFIG_PCI y fi if [ "$CONFIG_DDB5074" = "y" ]; then - define_bool CONFIG_PCI y define_bool CONFIG_HAVE_IO_PORTS y fi endmenu diff -u --recursive --new-file v2.3.99-pre2/linux/arch/mips/defconfig linux/arch/mips/defconfig --- v2.3.99-pre2/linux/arch/mips/defconfig Tue Mar 14 19:10:39 2000 +++ linux/arch/mips/defconfig Thu Mar 23 14:45:05 2000 @@ -19,6 +19,8 @@ # CONFIG_OLIVETTI_M700 is not set CONFIG_SGI_IP22=y # CONFIG_SNI_RM200_PCI is not set +# CONFIG_PCI is not set +# CONFIG_ISA is not set # # CPU selection @@ -73,6 +75,8 @@ # Block devices # # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set # # Additional Block Devices @@ -81,8 +85,6 @@ # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set # # Networking options @@ -134,15 +136,11 @@ # CONFIG_NET_SCHED is not set # -# Telephony Support -# -# CONFIG_PHONE is not set -# CONFIG_PHONE_IXJ is not set - -# # ATA/IDE/MFM/RLL support # # CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set # # SCSI support @@ -155,7 +153,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y -CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_SR_EXTRA_DEVS=2 @@ -207,26 +204,80 @@ # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # -# I2O device support +# Network device support # -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +CONFIG_NETDEVICES=y # -# Network device support +# ARCnet devices # -CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set # CONFIG_DUMMY is not set -# CONFIG_SLIP is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set -CONFIG_SGISEEQ=y +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# AX.25 network device drivers +# +# CONFIG_MKISS is not set +# CONFIG_6PACK is not set +# CONFIG_BPQETHER is not set +# CONFIG_DMASCC is not set +# CONFIG_SCC is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_SOUNDMODEM is not set +# CONFIG_YAM is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set # # Character devices @@ -336,8 +387,15 @@ # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set CONFIG_SGI_PARTITION=y +# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # diff -u --recursive --new-file v2.3.99-pre2/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.3.99-pre2/linux/arch/mips/kernel/irixelf.c Sun Mar 19 18:35:30 2000 +++ linux/arch/mips/kernel/irixelf.c Wed Mar 22 22:15:56 2000 @@ -230,15 +230,13 @@ * an ELF header. */ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, - struct dentry * interpreter_dentry, + struct file * interpreter, unsigned int *interp_load_addr) { - struct file * file; struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; unsigned int len; unsigned int load_addr; - int elf_exec_fileno; int elf_bss; int retval; unsigned int last_bss; @@ -258,8 +256,7 @@ if((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine) || - (!interpreter_dentry->d_inode->i_fop || - !interpreter_dentry->d_inode->i_fop->mmap)) { + !interpreter->f_op->mmap) { printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); return 0xffffffff; } @@ -290,23 +287,14 @@ return 0xffffffff; } - retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff, + retval = kernel_read(interpreter, interp_elf_ex->e_phoff, (char *) elf_phdata, - sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); #ifdef DEBUG_ELF dump_phdrs(elf_phdata, interp_elf_ex->e_phnum); #endif - elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY); - if (elf_exec_fileno < 0) { - printk("Could not open IRIX interp inode.\n"); - kfree(elf_phdata); - return 0xffffffff; - } - - file = fget(elf_exec_fileno); - eppnt = elf_phdata; for(i=0; ie_phnum; i++, eppnt++) { if(eppnt->p_type == PT_LOAD) { @@ -321,12 +309,12 @@ #ifdef DEBUG_ELF printk("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", - file, vaddr, + interpreter, vaddr, (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), (unsigned long) elf_prot, (unsigned long) elf_type, (unsigned long) (eppnt->p_offset & 0xfffff000)); #endif - error = do_mmap(file, vaddr, + error = do_mmap(interpreter, vaddr, eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), elf_prot, elf_type, eppnt->p_offset & 0xfffff000); @@ -363,8 +351,6 @@ } /* Now use mmap to map the library into memory. */ - fput(file); - sys_close(elf_exec_fileno); if(error < 0 && error > -1024) { #ifdef DEBUG_ELF printk("got error %d\n", error); @@ -407,9 +393,7 @@ /* First of all, some simple consistency checks */ if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || - !elf_check_arch(ehp->e_machine) || - (!bprm->dentry->d_inode->i_fop || - !bprm->dentry->d_inode->i_fop->mmap)) { + !elf_check_arch(ehp->e_machine) || !bprm->file->f_op->mmap) { return -ENOEXEC; } @@ -435,7 +419,7 @@ /* Look for an IRIX ELF interpreter. */ static inline int look_for_irix_interpreter(char **name, - struct dentry **interpreter_dentry, + struct file **interpreter, struct elfhdr *interp_elf_ex, struct elf_phdr *epp, struct linux_binprm *bprm, int pnum) @@ -443,7 +427,7 @@ mm_segment_t old_fs; int i; int retval = -EINVAL; - struct dentry *dentry = NULL; + struct file *file = NULL; *name = NULL; for(i = 0; i < pnum; i++, epp++) { @@ -461,29 +445,27 @@ return -ENOMEM; strcpy(*name, IRIX_INTERP_PREFIX); - retval = read_exec(bprm->dentry, epp->p_offset, (*name + 16), - epp->p_filesz, 1); + retval = kernel_read(bprm->file, epp->p_offset, (*name + 16), + epp->p_filesz); if(retval < 0) goto out; - old_fs = get_fs(); set_fs(get_ds()); - dentry = namei(*name); - set_fs(old_fs); - if(IS_ERR(dentry)) { - retval = PTR_ERR(dentry); + file = open_exec(*name); + if(IS_ERR(file)) { + retval = PTR_ERR(file); goto out; } - retval = read_exec(dentry, 0, bprm->buf, 128, 1); + retval = kernel_read(file, 0, bprm->buf, 128); if(retval < 0) goto dput_and_out; *interp_elf_ex = *((struct elfhdr *) bprm->buf); } - *interpreter_dentry = dentry; + *interpreter = file; return 0; dput_and_out: - dput(dentry); + fput(file); out: kfree(*name); return retval; @@ -544,7 +526,7 @@ } static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp, - struct dentry *identry, unsigned int *iladdr, + struct file *interp, unsigned int *iladdr, int pnum, mm_segment_t old_fs, unsigned int *eentry) { @@ -560,11 +542,11 @@ return -1; set_fs(old_fs); - *eentry = load_irix_interp(ihp, identry, iladdr); + *eentry = load_irix_interp(ihp, interp, iladdr); old_fs = get_fs(); set_fs(get_ds()); - dput(identry); + fput(interp); if(*eentry == 0xffffffff) return -1; @@ -603,14 +585,13 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct elfhdr elf_ex, interp_elf_ex; - struct dentry *interpreter_dentry; + struct file *interpreter; struct elf_phdr *elf_phdata, *elf_ihdr, *elf_ephdr; unsigned int load_addr, elf_bss, elf_brk; unsigned int elf_entry, interp_load_addr = 0; unsigned int start_code, end_code, end_data, elf_stack; - int elf_exec_fileno, retval, has_interp, has_ephdr, size, i; + int retval, has_interp, has_ephdr, size, i; char *elf_interpreter; - struct file *file; mm_segment_t old_fs; load_addr = 0; @@ -636,8 +617,7 @@ goto out; } - retval = read_exec(bprm->dentry, elf_ex.e_phoff, - (char *) elf_phdata, size, 1); + retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *)elf_phdata, size); if (retval < 0) goto out_free_ph; @@ -664,10 +644,6 @@ elf_bss = 0; elf_brk = 0; - retval = open_dentry(bprm->dentry, O_RDONLY); - if (retval < 0) - goto out_free_ph; - file = fget(elf_exec_fileno = retval); elf_stack = 0xffffffff; elf_interpreter = NULL; @@ -676,7 +652,7 @@ end_data = 0; retval = look_for_irix_interpreter(&elf_interpreter, - &interpreter_dentry, + &interpreter, &interp_elf_ex, elf_phdata, bprm, elf_ex.e_phnum); if(retval) @@ -720,13 +696,13 @@ old_fs = get_fs(); set_fs(get_ds()); - map_executable(file, elf_phdata, elf_ex.e_phnum, &elf_stack, + map_executable(bprm->file, elf_phdata, elf_ex.e_phnum, &elf_stack, &load_addr, &start_code, &elf_bss, &end_code, &end_data, &elf_brk); if(elf_interpreter) { retval = map_interpreter(elf_phdata, &interp_elf_ex, - interpreter_dentry, &interp_load_addr, + interpreter, &interp_load_addr, elf_ex.e_phnum, old_fs, &elf_entry); kfree(elf_interpreter); if(retval) { @@ -741,8 +717,6 @@ set_fs(old_fs); kfree(elf_phdata); - fput(file); - sys_close(elf_exec_fileno); current->personality = PER_IRIX32; put_exec_domain(current->exec_domain); @@ -805,13 +779,11 @@ return retval; out_free_dentry: - dput(interpreter_dentry); + fput(interpreter); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); out_free_file: - fput(file); - sys_close(elf_exec_fileno); out_free_ph: kfree (elf_phdata); goto out; @@ -824,31 +796,14 @@ { struct elfhdr elf_ex; struct elf_phdr *elf_phdata = NULL; - struct dentry *dentry; - struct inode *inode; - unsigned int len; - int elf_bss; + unsigned int len = 0; + int elf_bss = 0; int retval; unsigned int bss; int error; int i,j, k; - len = 0; - dentry = file->f_dentry; - inode = dentry->d_inode; - elf_bss = 0; - - /* Seek to the beginning of the file. */ - if (file->f_op->llseek) { - if ((error = file->f_op->llseek(file, 0, 0)) != 0) - return -ENOEXEC; - } else - file->f_pos = 0; - - set_fs(KERNEL_DS); - error = file->f_op->read(file, (char *) &elf_ex, sizeof(elf_ex), - &file->f_pos); - set_fs(USER_DS); + error = kernel_read(file, 0, (char *) &elf_ex, sizeof(elf_ex)); if (error != sizeof(elf_ex)) return -ENOEXEC; @@ -857,9 +812,7 @@ /* First of all, some simple consistency checks. */ if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || - !elf_check_arch(elf_ex.e_machine) || - (!dentry->d_inode->i_fop || - !dentry->d_inode->i_fop->mmap)) + !elf_check_arch(elf_ex.e_machine) || !file->f_op->mmap) return -ENOEXEC; /* Now read in all of the header information. */ @@ -871,8 +824,8 @@ if (elf_phdata == NULL) return -ENOMEM; - retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata, - sizeof(struct elf_phdr) * elf_ex.e_phnum, 1); + retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata, + sizeof(struct elf_phdr) * elf_ex.e_phnum); j = 0; for(i=0; i #include #include -#include #include #include diff -u --recursive --new-file v2.3.99-pre2/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.3.99-pre2/linux/arch/ppc/config.in Tue Mar 14 19:10:39 2000 +++ linux/arch/ppc/config.in Thu Mar 23 14:45:05 2000 @@ -19,7 +19,7 @@ 4xx CONFIG_4xx \ 630/Power3(64-Bit) CONFIG_PPC64 \ 82xx CONFIG_82xx \ - 8xx CONFIG_8xx" 6xx/7xx + 8xx CONFIG_8xx" 6xx if [ "$CONFIG_4xx" = "y" ]; then choice 'Machine Type' \ @@ -82,20 +82,18 @@ mainmenu_option next_comment comment 'General setup' -if [ "$CONFIG_APUS" = "y" ]; then - define_bool CONFIG_PCI n -fi -if [ "$CONFIG_OAK" = "y" ]; then - define_bool CONFIG_PCI n -fi -if [ "$CONFIG_8xx" = "y" ]; then - bool 'QSpan PCI' CONFIG_PCI -fi -if [ "$CONFIG_6xx" = "y" -a "$CONFIG_APUS" != "y" ]; then - define_bool CONFIG_PCI y -fi -if [ "$CONFIG_PREP" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then - define_bool CONFIG_PCI y +define_bool CONFIG_ISA n + +if [ "$CONFIG_APUS" = "y" -o "$CONFIG_4xx" = "y" -o \ + "$CONFIG_82xx" = "y" ]; then + define_bool CONFIG_PCI n +else + if [ "$CONFIG_6xx" = "y" -o CONFIG_PPC64 ]; then + define_bool CONFIG_PCI y + else + # CONFIG_8xx + bool 'QSpan PCI' CONFIG_PCI + fi fi bool 'Networking support' CONFIG_NET diff -u --recursive --new-file v2.3.99-pre2/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.3.99-pre2/linux/arch/ppc/configs/common_defconfig Fri Mar 10 16:40:40 2000 +++ linux/arch/ppc/configs/common_defconfig Tue Mar 21 10:49:32 2000 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -33,6 +33,7 @@ # # General setup # +# CONFIG_PCI is not set CONFIG_PCI=y CONFIG_PCI=y CONFIG_NET=y @@ -56,7 +57,6 @@ CONFIG_PMAC_PBOOK=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set CONFIG_ADB=y CONFIG_ADB_CUDA=y CONFIG_ADB_MACIO=y @@ -73,49 +73,23 @@ # Plug and Play configuration # # CONFIG_PNP is not set -# CONFIG_ISAPNP is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set -CONFIG_BLK_DEV_IDE=y -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECS is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y -CONFIG_BLK_DEV_IDESCSI=y -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -# 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_CMD64X is not set -# CONFIG_BLK_DEV_CS5530 is not set -# CONFIG_BLK_DEV_OPTI621 is not set -CONFIG_BLK_DEV_SL82C105=y -CONFIG_BLK_DEV_IDE_PMAC=y -CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y -# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set + +# +# Additional Block Devices +# CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_PARIDE is not set -CONFIG_BLK_DEV_IDE_MODES=y -# CONFIG_BLK_DEV_HD is not set # # Networking options @@ -138,10 +112,18 @@ # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=y CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set @@ -160,17 +142,71 @@ # CONFIG_NET_SCHED is not set # +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_IDEDMA is not set +CONFIG_IDEDMA_PCI_EXPERIMENTAL=y +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +CONFIG_BLK_DEV_IDE_MODES=y + +# # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y -CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -254,9 +290,7 @@ # # Appletalk devices # -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -# CONFIG_IPDDP is not set +# CONFIG_APPLETALK is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -449,17 +483,28 @@ # # CONFIG_FTAPE is not set # CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set # # USB support # CONFIG_USB=y + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# Miscellaneous USB options +# # CONFIG_USB_DEVICEFS is not set + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set # CONFIG_USB_AUDIO is not set @@ -470,11 +515,15 @@ # CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set # CONFIG_USB_STORAGE is not set -# CONFIG_USB_USS720 is not set # CONFIG_USB_DABUSB is not set # CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set +# CONFIG_USB_DSBR is not set + +# +# USB HID +# # CONFIG_USB_HID is not set CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y @@ -510,7 +559,6 @@ # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set @@ -524,7 +572,6 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y @@ -596,8 +643,12 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=y +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set # CONFIG_SOUND_AD1816 is not set # CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set CONFIG_SOUND_CS4232=m # CONFIG_SOUND_SSCAPE is not set # CONFIG_SOUND_GUS is not set @@ -608,11 +659,10 @@ # CONFIG_SOUND_NM256 is not set # CONFIG_SOUND_MAD16 is not set # CONFIG_SOUND_PAS is not set -# CONFIG_PAS_JOYSTICK is not set # CONFIG_SOUND_PSS is not set -# CONFIG_PSS_HAVE_BOOT is not set # CONFIG_SOUND_SOFTOSS is not set # CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set # CONFIG_SOUND_VIA82CXXX is not set @@ -620,11 +670,7 @@ # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set - -# -# Additional low level sound drivers -# -# CONFIG_LOWLEVEL_SOUND is not set +# CONFIG_SOUND_AEDSP16 is not set # # Kernel hacking diff -u --recursive --new-file v2.3.99-pre2/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.3.99-pre2/linux/arch/ppc/defconfig Tue Mar 14 19:10:39 2000 +++ linux/arch/ppc/defconfig Thu Mar 23 14:45:05 2000 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -33,7 +33,7 @@ # # General setup # -CONFIG_PCI=y +# CONFIG_ISA is not set CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y @@ -79,15 +79,19 @@ # Block devices # # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set + +# +# Additional Block Devices +# CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_PARIDE is not set # # Networking options @@ -110,10 +114,18 @@ # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=y CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set @@ -135,48 +147,91 @@ # ATA/IDE/MFM/RLL support # CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# CONFIG_BLK_DEV_IDE=y +# +# Please see Documentation/ide.txt for help/info on IDE drives +# # CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDEFLOPPY is not set CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set # CONFIG_BLK_DEV_IDEDMA_PCI is not set # CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_BLK_DEV_IDEDMA is not set +CONFIG_IDEDMA_PCI_EXPERIMENTAL=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_AEC6210_TUNING is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD7409 is not set +# CONFIG_AMD7409_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_CMD64X_RAID is not set +# CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_HPT366_FIP is not set +# CONFIG_HPT366_MODE3 is not set +# CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set -CONFIG_BLK_DEV_SL82C105=y +# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_PDC202XX_MASTER is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_SL82C105 is not set CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y CONFIG_IDEDMA_PMAC_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y CONFIG_BLK_DEV_IDE_MODES=y -# CONFIG_BLK_DEV_HD is not set # # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y -CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -260,9 +315,7 @@ # # Appletalk devices # -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -# CONFIG_IPDDP is not set +# CONFIG_APPLETALK is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -462,10 +515,22 @@ # USB support # CONFIG_USB=y + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# Miscellaneous USB options +# # CONFIG_USB_DEVICEFS is not set + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set # CONFIG_USB_AUDIO is not set @@ -475,12 +540,18 @@ # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set # CONFIG_USB_STORAGE is not set # CONFIG_USB_USS720 is not set # CONFIG_USB_DABUSB is not set # CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set +# CONFIG_USB_DSBR is not set + +# +# USB HID +# # CONFIG_USB_HID is not set CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y @@ -602,8 +673,12 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=y +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set # CONFIG_SOUND_AD1816 is not set # CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set CONFIG_SOUND_CS4232=m # CONFIG_SOUND_SSCAPE is not set # CONFIG_SOUND_GUS is not set @@ -616,9 +691,9 @@ # CONFIG_SOUND_PAS is not set # CONFIG_PAS_JOYSTICK is not set # CONFIG_SOUND_PSS is not set -# CONFIG_PSS_HAVE_BOOT is not set # CONFIG_SOUND_SOFTOSS is not set # CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set # CONFIG_SOUND_VIA82CXXX is not set @@ -626,11 +701,7 @@ # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set - -# -# Additional low level sound drivers -# -# CONFIG_LOWLEVEL_SOUND is not set +# CONFIG_SOUND_AEDSP16 is not set # # Kernel hacking diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.3.99-pre2/linux/arch/sh/config.in Tue Mar 14 19:10:39 2000 +++ linux/arch/sh/config.in Thu Mar 23 14:45:05 2000 @@ -47,6 +47,8 @@ mainmenu_option next_comment comment 'General setup' +define_bool CONFIG_ISA n + bool 'Networking support' CONFIG_NET bool 'Directy Connected Compact Flash support' CONFIG_CF_ENABLER diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sh/defconfig linux/arch/sh/defconfig --- v2.3.99-pre2/linux/arch/sh/defconfig Tue Mar 14 19:10:39 2000 +++ linux/arch/sh/defconfig Thu Mar 23 14:45:05 2000 @@ -28,6 +28,7 @@ # # General setup # +# CONFIG_ISA is not set # CONFIG_NET is not set CONFIG_CF_ENABLER=y # CONFIG_PCI is not set @@ -39,12 +40,18 @@ # CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set + +# +# Parallel port support +# # CONFIG_PARPORT is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set # # Additional Block Devices @@ -53,21 +60,25 @@ # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set # # ATA/IDE/MFM/RLL support # CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# CONFIG_BLK_DEV_IDE=y # # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECS is not set # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -77,9 +88,11 @@ # IDE chipset support/bugfixes # # CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set # CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # SCSI support @@ -101,13 +114,20 @@ # CONFIG_UNIX98_PTYS is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set # CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set @@ -115,6 +135,10 @@ # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v2.3.99-pre2/linux/arch/sparc/Makefile Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc/Makefile Tue Mar 21 23:38:25 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.45 2000/01/29 01:08:48 anton Exp $ +# $Id: Makefile,v 1.46 2000/03/21 06:12:26 davem Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.3.99-pre2/linux/arch/sparc/config.in Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc/config.in Thu Mar 23 14:45:05 2000 @@ -36,6 +36,8 @@ if [ "$CONFIG_SUN4" != "y" ]; then bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI source drivers/pci/Config.in +else + define_bool CONFIG_PCI n fi tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile --- v2.3.99-pre2/linux/arch/sparc64/Makefile Fri Mar 10 16:40:41 2000 +++ linux/arch/sparc64/Makefile Tue Mar 21 23:38:25 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.42 2000/03/09 05:56:43 jj Exp $ +# $Id: Makefile,v 1.43 2000/03/21 06:12:28 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -17,6 +17,8 @@ NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; ) + +export NEW_GCC ifneq ($(NEW_GAS),y) AS = sparc64-linux-as diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.99-pre2/linux/arch/sparc64/config.in Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/config.in Thu Mar 23 23:36:10 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.104 2000/03/15 15:02:28 jj Exp $ +# $Id: config.in,v 1.105 2000/03/24 00:34:11 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -29,6 +29,7 @@ define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y +define_bool CONFIG_ISA n bool 'PCI support' CONFIG_PCI source drivers/pci/Config.in @@ -230,6 +231,7 @@ tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX tristate 'RealTek RTL-8139 support' CONFIG_8139TOO tristate 'PCI NE2000 support' CONFIG_NE2K_PCI + tristate 'VIA Rhine support' CONFIG_VIA_RHINE tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100 tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.99-pre2/linux/arch/sparc64/defconfig Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/defconfig Thu Mar 23 23:36:10 2000 @@ -24,6 +24,7 @@ CONFIG_SUN_CONSOLE=y CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y +# CONFIG_ISA is not set CONFIG_PCI=y CONFIG_PCI_NAMES=y CONFIG_SUN_OPENPROMFS=m @@ -218,7 +219,6 @@ # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set @@ -245,6 +245,7 @@ # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y CONFIG_BLK_DEV_IDE_MODES=y # @@ -336,6 +337,7 @@ CONFIG_VORTEX=m CONFIG_8139TOO=m CONFIG_NE2K_PCI=m +CONFIG_VIA_RHINE=m CONFIG_EEPRO100=m CONFIG_ADAPTEC_STARFIRE=m diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.3.99-pre2/linux/arch/sparc64/kernel/Makefile Thu Feb 10 17:11:06 2000 +++ linux/arch/sparc64/kernel/Makefile Tue Mar 21 23:38:25 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.51 2000/02/08 05:11:31 jj Exp $ +# $Id: Makefile,v 1.52 2000/03/19 07:00:29 ecd Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -61,7 +61,7 @@ # binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c -ifneq ($(IS_EGCS),y) +ifneq ($(NEW_GCC),y) CMODEL_CFLAG := -mmedlow else CMODEL_CFLAG := -mcmodel=medlow diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.3.99-pre2/linux/arch/sparc64/kernel/binfmt_aout32.c Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Wed Mar 22 22:15:56 2000 @@ -198,7 +198,6 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct exec ex; - struct file * file; int fd; unsigned long error; unsigned long fd_offset; @@ -209,7 +208,7 @@ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || - bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { + bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } @@ -245,21 +244,23 @@ compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == NMAGIC) { + loff_t pos = fd_offset; /* Fuck me plenty... */ error = do_brk(N_TXTADDR(ex), ex.a_text); - read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), - ex.a_text, 0); + bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex), + ex.a_text, &pos); error = do_brk(N_DATADDR(ex), ex.a_data); - read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex), - ex.a_data, 0); + bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex), + ex.a_data, &pos); goto beyond_if; } if (N_MAGIC(ex) == OMAGIC) { + loff_t pos = fd_offset; do_brk(N_TXTADDR(ex) & PAGE_MASK, ex.a_text+ex.a_data + PAGE_SIZE - 1); - read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), - ex.a_text+ex.a_data, 0); + bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex), + ex.a_text+ex.a_data, &pos); } else { static unsigned long error_time; if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && @@ -269,37 +270,36 @@ error_time = jiffies; } - fd = open_dentry(bprm->dentry, O_RDONLY); + fd = get_unused_fd(); if (fd < 0) return fd; - file = fget(fd); + get_file(bprm->file); + fd_install(fd, bprm->file); - if (!file->f_op || !file->f_op->mmap) { - fput(file); + if (!bprm->file->f_op->mmap) { + loff_t pos = fd_offset; sys_close(fd); do_brk(0, ex.a_text+ex.a_data); - read_exec(bprm->dentry, fd_offset, - (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); + bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex), + ex.a_text+ex.a_data, &pos); goto beyond_if; } - error = do_mmap(file, N_TXTADDR(ex), ex.a_text, + error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); if (error != N_TXTADDR(ex)) { - fput(file); sys_close(fd); send_sig(SIGKILL, current, 0); return error; } - error = do_mmap(file, N_DATADDR(ex), ex.a_data, + error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); - fput(file); sys_close(fd); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); @@ -349,16 +349,12 @@ unsigned long bss, start_addr, len; unsigned long error; int retval; - loff_t offset = 0; struct exec ex; inode = file->f_dentry->d_inode; retval = -ENOEXEC; - /* N.B. Save current fs? */ - set_fs(KERNEL_DS); - error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset); - set_fs(USER_DS); + error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); if (error != sizeof(ex)) goto out; diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.99-pre2/linux/arch/sparc64/kernel/ioctl32.c Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Wed Mar 22 21:50:29 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.83 2000/03/14 07:31:25 jj Exp $ +/* $Id: ioctl32.c,v 1.85 2000/03/23 05:25:41 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -1594,7 +1594,7 @@ { mm_segment_t old_fs = get_fs(); struct loop_info l; - int err = 0; + int err = -EINVAL; switch(cmd) { case LOOP_SET_STATUS: @@ -1604,11 +1604,13 @@ err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset, 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); - if (err) - return -EFAULT; - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&l); - set_fs (old_fs); + if (err) { + err = -EFAULT; + } else { + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&l); + set_fs (old_fs); + } break; case LOOP_GET_STATUS: set_fs (KERNEL_DS); @@ -1621,10 +1623,19 @@ err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset, (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); + if (err) + err = -EFAULT; } break; + default: { + static int count = 0; + if (++count <= 20) + printk("%s: Unknown loop ioctl cmd, fd(%d) " + "cmd(%08x) arg(%08lx)\n", + __FUNCTION__, fd, cmd, arg); } - return err ? -EFAULT : 0; + } + return err; } extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); @@ -1803,6 +1814,8 @@ #define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) #define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) #define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) +#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) +#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) static struct { unsigned int cmd32; @@ -1821,7 +1834,9 @@ { ATM_SETESI32, ATM_SETESI }, { ATM_SETESIF32, ATM_SETESIF }, { ATM_GETSTAT32, ATM_GETSTAT }, - { ATM_GETSTATZ32, ATM_GETSTATZ } + { ATM_GETSTATZ32, ATM_GETSTATZ }, + { ATM_GETLOOP32, ATM_GETLOOP }, + { ATM_SETLOOP32, ATM_SETLOOP } }; #define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0])) @@ -1941,8 +1956,6 @@ unsigned int cmd = 0; switch (cmd32) { - case SUNI_GETLOOP: - case SUNI_SETLOOP: case SONET_GETSTAT: case SONET_GETSTATZ: case SONET_GETDIAG: @@ -1954,7 +1967,6 @@ return do_atmif_sioc(fd, cmd32, arg); } - if (cmd == 0) { for (i = 0; i < NR_ATM_IOCTL; i++) { if (cmd32 == atm_ioctl_map[i].cmd32) { cmd = atm_ioctl_map[i].cmd; @@ -1964,7 +1976,6 @@ if (i == NR_ATM_IOCTL) { return -EINVAL; } - } switch (cmd) { case ATM_GETNAMES: @@ -1983,6 +1994,8 @@ case ATM_SETESIF: case ATM_GETSTAT: case ATM_GETSTATZ: + case ATM_GETLOOP: + case ATM_SETLOOP: return do_atmif_sioc(fd, cmd, arg); } @@ -3076,8 +3089,8 @@ HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) -HANDLE_IOCTL(SUNI_GETLOOP, do_atm_ioctl) -HANDLE_IOCTL(SUNI_SETLOOP, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.3.99-pre2/linux/arch/sparc64/kernel/sys_sparc32.c Sun Mar 19 18:35:30 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Thu Mar 23 23:36:10 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.139 2000/03/16 20:37:57 davem Exp $ +/* $Id: sys_sparc32.c,v 1.141 2000/03/24 01:31:30 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -3051,7 +3051,7 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) { struct linux_binprm bprm; - struct dentry * dentry; + struct file * file; int retval; int i; @@ -3059,28 +3059,24 @@ memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0])); lock_kernel(); - dentry = open_namei(filename); + file = open_exec(filename); unlock_kernel(); - retval = PTR_ERR(dentry); - if (IS_ERR(dentry)) + retval = PTR_ERR(file); + if (IS_ERR(file)) return retval; - bprm.dentry = dentry; + bprm.file = file; bprm.filename = filename; bprm.sh_bang = 0; bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count32(argv)) < 0) { - lock_kernel(); - dput(dentry); - unlock_kernel(); + fput(file); return bprm.argc; } if ((bprm.envc = count32(envp)) < 0) { - lock_kernel(); - dput(dentry); - unlock_kernel(); + fput(file); return bprm.envc; } @@ -3108,11 +3104,8 @@ out: /* Something went wrong, return the inode and free the argument pages*/ - if (bprm.dentry) { - lock_kernel(); - dput(bprm.dentry); - unlock_kernel(); - } + if (bprm.file) + fput(bprm.file); for (i=0 ; icr32_getfh, - &kres->cr_getfh, - sizeof(res32->cr32_getfh)); - err |= __put_user(kres->cr_debug, &res32->cr32_debug); - return err; + return copy_to_user(res32, kres, sizeof(*res32)); } extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp); diff -u --recursive --new-file v2.3.99-pre2/linux/arch/sparc64/lib/memcmp.S linux/arch/sparc64/lib/memcmp.S --- v2.3.99-pre2/linux/arch/sparc64/lib/memcmp.S Mon Apr 14 16:28:10 1997 +++ linux/arch/sparc64/lib/memcmp.S Thu Mar 23 23:36:10 2000 @@ -1,29 +1,28 @@ -/* $Id: memcmp.S,v 1.2 1997/04/01 03:43:18 davem Exp $ +/* $Id: memcmp.S,v 1.3 2000/03/23 07:51:08 davem Exp $ * Sparc64 optimized memcmp code. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 2000 David S. Miller (davem@redhat.com) */ .text - .align 4 - .globl __memcmp, memcmp + .align 32 + .globl __memcmp, memcmp __memcmp: memcmp: - brlez,pn %o2, 2f - sub %g0, %o2, %o3 - add %o0, %o2, %o0 - add %o1, %o2, %o1 - ldub [%o0 + %o3], %o4 -1: - ldub [%o1 + %o3], %o5 - sub %o4, %o5, %o4 - brnz,pn %o4, 3f - addcc %o3, 1, %o3 - bne,a,pt %xcc, 1b - ldub [%o0 + %o3], %o4 -2: - retl - clr %o0 -3: - retl - mov %o4, %o0 + cmp %o2, 0 ! IEU1 Group +loop: be,pn %icc, ret_0 ! CTI + nop ! IEU0 + ldub [%o0], %g5 ! LSU Group + ldub [%o1], %g3 ! LSU Group + sub %o2, 1, %o2 ! IEU0 + add %o0, 1, %o0 ! IEU1 + add %o1, 1, %o1 ! IEU0 Group + subcc %g5, %g3, %g3 ! IEU1 Group + be,pt %icc, loop ! CTI + cmp %o2, 0 ! IEU1 Group + +ret_n0: retl + mov %g3, %o0 +ret_0: retl + mov 0, %o0 diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/acorn/block/Makefile linux/drivers/acorn/block/Makefile --- v2.3.99-pre2/linux/drivers/acorn/block/Makefile Thu Mar 2 14:36:22 2000 +++ linux/drivers/acorn/block/Makefile Wed Mar 22 09:39:11 2000 @@ -51,9 +51,6 @@ include $(TOPDIR)/Rules.make -.S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< - fd1772_mod.o: $(FLOPPY) $(LD) -r -o $@ $(FLOPPY) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/acorn/scsi/Makefile linux/drivers/acorn/scsi/Makefile --- v2.3.99-pre2/linux/drivers/acorn/scsi/Makefile Thu Mar 2 14:36:22 2000 +++ linux/drivers/acorn/scsi/Makefile Wed Mar 22 09:39:11 2000 @@ -49,8 +49,5 @@ include $(TOPDIR)/Rules.make -.S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< - acornscsi_mod.o: acornscsi.o acornscsi-io.o $(LD) $(LD_RFLAG) -r -o $@ acornscsi.o acornscsi-io.o diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.3.99-pre2/linux/drivers/atm/Makefile Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/Makefile Tue Mar 21 23:38:26 2000 @@ -3,15 +3,15 @@ # Makefile for the Linux network (ATM) device drivers. # -L_TARGET := atm.a -L_OBJS := atmdev_init.o +O_TARGET := atm.o +O_OBJS := atmdev_init.o M_OBJS := MOD_LIST_NAME := ATM_MODULES include ../../.config ifeq ($(CONFIG_ATM_ENI),y) -L_OBJS += eni.o +O_OBJS += eni.o NEED_SUNI_LX = suni.o else ifeq ($(CONFIG_ATM_ENI),m) @@ -21,8 +21,8 @@ endif ifeq ($(CONFIG_ATM_ZATM),y) -L_OBJS += zatm.o -LX_OBJS += uPD98402.o +O_OBJS += zatm.o +OX_OBJS += uPD98402.o else ifeq ($(CONFIG_ATM_ZATM),m) M_OBJS += zatm.o @@ -31,11 +31,11 @@ endif ifeq ($(CONFIG_ATM_TNETA1570),y) -L_OBJS += tneta1570.o suni.o +O_OBJS += tneta1570.o suni.o endif ifeq ($(CONFIG_ATM_NICSTAR),y) -L_OBJS += nicstar.o +O_OBJS += nicstar.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) NEED_SUNI_LX = suni.o endif @@ -55,7 +55,7 @@ endif ifeq ($(CONFIG_ATM_HORIZON),y) -L_OBJS += horizon.o +O_OBJS += horizon.o else ifeq ($(CONFIG_ATM_HORIZON),m) M_OBJS += horizon.o @@ -63,7 +63,7 @@ endif ifeq ($(CONFIG_ATM_AMBASSADOR),y) -L_OBJS += ambassador.o +O_OBJS += ambassador.o else ifeq ($(CONFIG_ATM_AMBASSADOR),m) M_OBJS += ambassador.o @@ -71,7 +71,7 @@ endif ifeq ($(CONFIG_ATM_TCP),y) -L_OBJS += atmtcp.o +O_OBJS += atmtcp.o else ifeq ($(CONFIG_ATM_TCP),m) M_OBJS += atmtcp.o @@ -79,7 +79,7 @@ endif ifeq ($(CONFIG_ATM_IA),y) -L_OBJS += iphase.o +O_OBJS += iphase.o NEED_SUNI_LX = suni.o else ifeq ($(CONFIG_ATM_IA),m) @@ -91,13 +91,13 @@ ifeq ($(NEED_SUNI_LX),) MX_OBJS += $(NEED_SUNI_MX) else - LX_OBJS += $(NEED_SUNI_LX) + OX_OBJS += $(NEED_SUNI_LX) endif ifeq ($(NEED_IDT77105_LX),) MX_OBJS += $(NEED_IDT77105_MX) else - LX_OBJS += $(NEED_IDT77105_LX) + OX_OBJS += $(NEED_IDT77105_LX) endif ifeq ($(CONFIG_ATM_FORE200E_PCA),y) @@ -114,7 +114,7 @@ endif endif ifeq ($(CONFIG_ATM_FORE200E),y) -L_OBJS += fore200e.o $(FORE200E_FW_OBJS) +O_OBJS += fore200e.o $(FORE200E_FW_OBJS) else ifeq ($(CONFIG_ATM_FORE200E),m) M_OBJS += fore_200e.o diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c --- v2.3.99-pre2/linux/drivers/atm/ambassador.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/ambassador.c Tue Mar 21 23:38:26 2000 @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -39,7 +40,7 @@ #define maintainer_string "Giuliano Procida at Madge Networks " #define description_string "Madge ATM Ambassador driver" -#define version_string "1.2" +#define version_string "1.2.4" static inline void __init show_version (void) { printk ("%s version %s\n", description_string, version_string); @@ -97,8 +98,8 @@ The adapter is quite intelligent (fast) and has a simple interface (few features). VPI is always zero, 1024 VCIs are supported. There - is limited cell rate support. UBR channels can be kept and ABR - (explicit rate, bu not EFCI) is supported. There is no CBR or VBR + is limited cell rate support. UBR channels can be capped and ABR + (explicit rate, but not EFCI) is supported. There is no CBR or VBR support. 1. Driver <-> Adapter Communication @@ -321,8 +322,29 @@ static unsigned int rx_lats = 7; static unsigned char pci_lat = 0; +static const unsigned long onegigmask = -1 << 30; + /********** access to adapter **********/ +static inline void wr_plain (const amb_dev * dev, const u32 * addr, u32 data) { + PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x", addr, data); +#ifdef AMB_MMIO + dev->membase[addr - (u32 *) 0] = data; +#else + outl (data, dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); +#endif +} + +static inline u32 rd_plain (const amb_dev * dev, const u32 * addr) { +#ifdef AMB_MMIO + u32 data = dev->membase[addr - (u32 *) 0]; +#else + u32 data = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); +#endif + PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x", addr, data); + return data; +} + static const amb_mem * const mem = 0; static inline void wr_mem (const amb_dev * dev, const u32 * addr, u32 data) { @@ -342,7 +364,7 @@ u32 be = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32)); #endif u32 data = be32_to_cpu (be); - PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be); + PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be); return data; } @@ -350,14 +372,18 @@ static inline void dump_registers (const amb_dev * dev) { #ifdef DEBUG_AMBASSADOR - // u32 * i; - // PRINTD (DBG_REGS, "mailboxes: "); - // for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i) - // PRINTD (DBG_REGS, "%08x ", rd_mem (dev, i)); - PRINTD (DBG_REGS, "doorb %08x", rd_mem (dev, (u32 *) 0x60)); - PRINTD (DBG_REGS, "irqev %08x", rd_mem (dev, (u32 *) 0x64)); - PRINTD (DBG_REGS, "irqen %08x", rd_mem (dev, (u32 *) 0x68)); - PRINTD (DBG_REGS, "reset %08x", rd_mem (dev, (u32 *) 0x6c)); + if (debug & DBG_REGS) { + u32 * i; + PRINTD (DBG_REGS, "reading PLX control: "); + for (i = (u32 *) 0x00; i < (u32 *) 0x30; ++i) + rd_mem (dev, i); + PRINTD (DBG_REGS, "reading mailboxes: "); + for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i) + rd_mem (dev, i); + PRINTD (DBG_REGS, "reading doorb irqev irqen reset:"); + for (i = (u32 *) 0x60; i < (u32 *) 0x70; ++i) + rd_mem (dev, i); + } #else (void) dev; #endif @@ -414,8 +440,8 @@ static inline int check_area (void * start, size_t length) { // assumes length > 0 - const u32 fourmegmask = (-1)<<22; - const u32 twofivesixmask = (-1)<<8; + const u32 fourmegmask = -1 << 22; + const u32 twofivesixmask = -1 << 8; const u32 starthole = 0xE0000000; u32 startaddress = virt_to_bus (start); u32 lastaddress = startaddress+length-1; @@ -435,7 +461,7 @@ if (ATM_SKB(skb)->vcc->pop) { ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb); } else { - dev_kfree_skb (skb); + dev_kfree_skb_any (skb); } } @@ -448,7 +474,7 @@ PRINTD (DBG_FLOW|DBG_TX, "tx_complete %p %p", dev, tx); // VC layer stats - ATM_SKB(skb)->vcc->stats->tx++; + atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); // free the descriptor kfree (tx_descr); @@ -489,7 +515,7 @@ dump_skb ("<<<", vc, skb); // VC layer stats - atm_vcc->stats->rx++; + atomic_inc(&atm_vcc->stats->rx); skb->stamp = xtime; // end of our responsability atm_vcc->push (atm_vcc, skb); @@ -504,7 +530,7 @@ } else { PRINTK (KERN_INFO, "dropped over-size frame"); // should we count this? - atm_vcc->stats->rx_drop++; + atomic_inc(&atm_vcc->stats->rx_drop); } } else { @@ -524,7 +550,7 @@ dev->stats.rx.unused++; } - dev_kfree_skb (skb); + dev_kfree_skb_any (skb); return; } @@ -548,7 +574,8 @@ // sometimes does 16-bit accesses (yuk yuk yuk) static int command_do (amb_dev * dev, command * cmd) { - volatile amb_cq * cq = &dev->cq; + amb_cq * cq = &dev->cq; + volatile amb_cq_ptrs * ptrs = &cq->ptrs; command * my_slot; unsigned long timeout; @@ -562,18 +589,18 @@ // if not full... if (cq->pending < cq->maximum) { // remember my slot for later - my_slot = cq->in; + my_slot = ptrs->in; PRINTD (DBG_CMD, "command in slot %p", my_slot); dump_command (cmd); // copy command in - *cq->in = *cmd; + *ptrs->in = *cmd; cq->pending++; - cq->in = NEXTQ (cq->in, cq->start, cq->limit); + ptrs->in = NEXTQ (ptrs->in, ptrs->start, ptrs->limit); // mail the command - wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (cq->in)); + wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (ptrs->in)); // prepare to wait for cq->pending milliseconds // effectively one centisecond on i386 @@ -591,13 +618,13 @@ } // wait for my slot to be reached (all waiters are here or above, until...) - while (cq->out != my_slot) { - PRINTD (DBG_CMD, "wait: command slot (now at %p)", cq->out); + while (ptrs->out != my_slot) { + PRINTD (DBG_CMD, "wait: command slot (now at %p)", ptrs->out); schedule(); } // wait on my slot (... one gets to its slot, and... ) - while (cq->out->request != cpu_to_be32 (SRB_COMPLETE)) { + while (ptrs->out->request != cpu_to_be32 (SRB_COMPLETE)) { PRINTD (DBG_CMD, "wait: command slot completion"); schedule(); } @@ -607,12 +634,13 @@ spin_lock (&cq->lock); cq->pending--; // copy command out - *cmd = *cq->out; - cq->out = NEXTQ (cq->out, cq->start, cq->limit); + *cmd = *ptrs->out; + ptrs->out = NEXTQ (ptrs->out, ptrs->start, ptrs->limit); spin_unlock (&cq->lock); return 0; } else { + cq->filled++; spin_unlock (&cq->lock); return -EAGAIN; } @@ -796,7 +824,7 @@ return; } if (check_area (skb->data, skb->truesize)) { - dev_kfree_skb (skb); + dev_kfree_skb_any (skb); return; } // cast needed as there is no %? for pointer differences @@ -805,14 +833,14 @@ rx.handle = virt_to_bus (skb); rx.host_address = cpu_to_be32 (virt_to_bus (skb->data)); if (rx_give (dev, &rx, pool)) - dev_kfree_skb (skb); + dev_kfree_skb_any (skb); } return; } -// top up all RX pools (also called as a bottom half) +// top up all RX pools (can also be called as a bottom half) static void fill_rx_pools (amb_dev * dev) { unsigned char pool; @@ -827,25 +855,23 @@ /********** enable host interrupts **********/ static inline void interrupts_on (amb_dev * dev) { - wr_mem (dev, &mem->interrupt_control, - rd_mem (dev, &mem->interrupt_control) - | AMB_INTERRUPT_BITS); + wr_plain (dev, &mem->interrupt_control, + rd_plain (dev, &mem->interrupt_control) + | AMB_INTERRUPT_BITS); } /********** disable host interrupts **********/ static inline void interrupts_off (amb_dev * dev) { - wr_mem (dev, &mem->interrupt_control, - rd_mem (dev, &mem->interrupt_control) - &~ AMB_INTERRUPT_BITS); + wr_plain (dev, &mem->interrupt_control, + rd_plain (dev, &mem->interrupt_control) + &~ AMB_INTERRUPT_BITS); } /********** interrupt handling **********/ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs) { amb_dev * dev = amb_devs; - unsigned int irq_ok; - unsigned int irq_ok_old; (void) pt_regs; PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id); @@ -860,50 +886,56 @@ break; dev = dev->prev; } + // impossible - unless we add the device to our list after both + // registering the IRQ handler for it and enabling interrupts, AND + // the card generates an IRQ at startup - should not happen again if (!dev) { - PRINTD (DBG_IRQ, "irq not for me: %d", irq); + PRINTD (DBG_IRQ, "irq for unknown device: %d", irq); return; } + // impossible - unless we have memory corruption of dev or kernel if (irq != dev->irq) { PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq); return; } - // definitely for us - irq_ok = 0; - irq_ok_old = -1; + { + u32 interrupt = rd_plain (dev, &mem->interrupt); - // perhaps disable interrupts? (disabled at PIC by Linux) - // interrupts_off (dev); + // for us or someone else sharing the same interrupt + if (!interrupt) { + PRINTD (DBG_IRQ, "irq not for me: %d", irq); + return; + } + + // definitely for us + PRINTD (DBG_IRQ, "FYI: interrupt was %08x", interrupt); + wr_plain (dev, &mem->interrupt, -1); + } - while (irq_ok_old != irq_ok && irq_ok < 100) { + { + unsigned int irq_work = 0; unsigned char pool; - PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u", - rd_mem (dev, &mem->interrupt), irq_ok); - wr_mem (dev, &mem->interrupt, -1); - irq_ok_old = irq_ok; for (pool = 0; pool < NUM_RX_POOLS; ++pool) while (!rx_take (dev, pool)) - ++irq_ok; + ++irq_work; while (!tx_take (dev)) - ++irq_ok; - } + ++irq_work; - if (irq_ok) { -#if 0 - queue_task (&dev->bh, &tq_immediate); - mark_bh (IMMEDIATE_BH); + if (irq_work) { +#ifdef FILL_RX_POOLS_IN_BH + queue_task (&dev->bh, &tq_immediate); + mark_bh (IMMEDIATE_BH); #else - fill_rx_pools (dev); + fill_rx_pools (dev); #endif - PRINTD (DBG_IRQ, "work done: %u", irq_ok); - } else { - PRINTD (DBG_IRQ|DBG_WARN, "no work done"); + PRINTD (DBG_IRQ, "work done: %u", irq_work); + } else { + PRINTD (DBG_IRQ|DBG_WARN, "no work done"); + } } - // perhaps re-enable interrupts? (re-enabled at PIC by Linux) - // interrupts_on (dev); PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id); return; } @@ -913,6 +945,7 @@ #ifdef DEBUG_AMBASSADOR static void dont_panic (amb_dev * dev) { amb_cq * cq = &dev->cq; + volatile amb_cq_ptrs * ptrs = &cq->ptrs; amb_txq * txq; amb_rxq * rxq; command * cmd; @@ -926,10 +959,11 @@ cli(); PRINTK (KERN_INFO, "don't panic - putting adapter into reset"); - wr_mem (dev, &mem->reset_control, rd_mem (dev, &mem->reset_control) | AMB_RESET); + wr_plain (dev, &mem->reset_control, + rd_plain (dev, &mem->reset_control) | AMB_RESET_BITS); PRINTK (KERN_INFO, "marking all commands complete"); - for (cmd = cq->start; cmd < cq->limit; ++cmd) + for (cmd = ptrs->start; cmd < ptrs->limit; ++cmd) cmd->request = cpu_to_be32 (SRB_COMPLETE); PRINTK (KERN_INFO, "completing all TXs"); @@ -952,7 +986,7 @@ if (rx == rxq->in.start) rx = rxq->in.limit; --rx; - dev_kfree_skb (bus_to_virt (rx->handle)); + dev_kfree_skb_any (bus_to_virt (rx->handle)); } } @@ -972,18 +1006,19 @@ PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate); - // rates in cells per second, ITU format (nasty 16bit fp) + // rates in cells per second, ITU format (nasty 16-bit floating-point) // given 5-bit e and 9-bit m: // rate = EITHER (1+m/2^9)*2^e OR 0 // bits = EITHER 1<<14 | e<<9 | m OR 0 // (bit 15 is "reserved", bit 14 "non-zero") // smallest rate is 0 (special representation) // largest rate is (1+511/512)*2^31 = 4290772992 (< 2^32-1) + // smallest non-zero rate is (1+0/512)*2^0 = 1 (> 0) // simple algorithm: // find position of top bit, this gives e // remove top bit and shift (rounding if feeling clever) by 9-e - // ucode bug: please don't set bit 14! 0 not representable + // ucode bug: please don't set bit 14! so 0 rate not representable if (rate > 0xffc00000U) { // larger than largest representable rate @@ -1228,7 +1263,7 @@ // we are not really "immediately before allocating the connection // identifier in hardware", but it will just have to do! - atm_vcc->flags |= ATM_VF_ADDR; + set_bit(ATM_VF_ADDR,&atm_vcc->flags); if (txtp->traffic_class != ATM_NONE) { command cmd; @@ -1303,7 +1338,7 @@ atm_vcc->vci = vci; // indicate readiness - atm_vcc->flags |= ATM_VF_READY; + set_bit(ATM_VF_READY,&atm_vcc->flags); MOD_INC_USE_COUNT; return 0; @@ -1319,7 +1354,7 @@ PRINTD (DBG_VCC|DBG_FLOW, "amb_close"); // indicate unreadiness - atm_vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&atm_vcc->flags); // disable TXing if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) { @@ -1384,7 +1419,7 @@ kfree (vcc); // say the VPI/VCI is free again - atm_vcc->flags &= ~ATM_VF_ADDR; + clear_bit(ATM_VF_ADDR,&atm_vcc->flags); MOD_DEC_USE_COUNT; } @@ -1394,6 +1429,8 @@ static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) { unsigned short newdebug; if (cmd == AMB_SETDEBUG) { + if (!capable(CAP_NET_ADMIN)) + return -EPERM; if (copy_from_user (&newdebug, arg, sizeof(newdebug))) { // moan return -EFAULT; @@ -1402,6 +1439,8 @@ return 0; } } else if (cmd == AMB_DONTPANIC) { + if (!capable(CAP_NET_ADMIN)) + return -EPERM; dont_panic (dev); } else { // moan @@ -1453,7 +1492,7 @@ } if (check_area (skb->data, skb->len)) { - atm_vcc->stats->tx_err++; + atomic_inc(&atm_vcc->stats->tx_err); return -ENOMEM; // ? } @@ -1564,7 +1603,7 @@ // at. However, I note that the ATM layer calls kfree_skb rather // than dev_kfree_skb at this point so we are least covered as far // as buffer locking goes. There may be bugs if pcap clones RX skbs. - + PRINTD (DBG_FLOW|DBG_SKB, "amb_rx_free skb %p (atm_vcc %p, vcc %p)", skb, atm_vcc, vcc); @@ -1582,7 +1621,7 @@ } // just do what the ATM layer would have done - kfree_skb (skb); + dev_kfree_skb_any (skb); return; } @@ -1733,12 +1772,12 @@ cq->high = 0; cq->maximum = cmds - 1; - cq->start = cmd; - cq->in = cmd; - cq->out = cmd; - cq->limit = cmd + cmds; + cq->ptrs.start = cmd; + cq->ptrs.in = cmd; + cq->ptrs.out = cmd; + cq->ptrs.limit = cmd + cmds; - memory = cq->limit; + memory = cq->ptrs.limit; } PRINTD (DBG_TX, "TX queue pair at %p", memory); @@ -1810,7 +1849,7 @@ static void destroy_queues (amb_dev * dev) { // all queues assumed empty - void * memory = dev->cq.start; + void * memory = dev->cq.ptrs.start; // includes txq.in, txq.out, rxq[].in and rxq[].out PRINTD (DBG_FLOW, "destroy_queues %p", dev); @@ -1823,9 +1862,8 @@ /********** basic loader commands and error handling **********/ -static int __init do_loader_command (const amb_dev * dev, loader_command cmd, - volatile loader_block * lb) { - +static int __init do_loader_command (volatile loader_block * lb, + const amb_dev * dev, loader_command cmd) { // centisecond timeouts - guessing away here unsigned int command_timeouts [] = { [host_memory_test] = 15, @@ -1939,8 +1977,9 @@ lb->result = 0; lb->command = cpu_to_be32 (cmd); lb->valid = cpu_to_be32 (DMA_VALID); + // dump_registers (dev); // dump_loader_block (lb); - wr_mem (dev, &mem->doorbell, virt_to_bus (lb)); + wr_mem (dev, &mem->doorbell, virt_to_bus (lb) & ~onegigmask); timeout = command_timeouts[cmd] * HZ/100; @@ -1957,7 +1996,7 @@ if (cmd == adapter_start) { // wait for start command to acknowledge... timeout = HZ/10; - while (rd_mem (dev, &mem->doorbell)) + while (rd_plain (dev, &mem->doorbell)) if (timeout) { timeout = schedule_timeout (timeout); } else { @@ -1975,27 +2014,27 @@ /* loader: determine loader version */ -static int __init get_loader_version (const amb_dev * dev, u32 * version) { - loader_block lb; +static int __init get_loader_version (loader_block * lb, + const amb_dev * dev, u32 * version) { int res; PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version"); - res = do_loader_command (dev, get_version_number, &lb); + res = do_loader_command (lb, dev, get_version_number); if (res) return res; if (version) - *version = be32_to_cpu (lb.payload.version); + *version = be32_to_cpu (lb->payload.version); return 0; } -/* loader: read or verify memory data blocks */ +/* loader: write memory data blocks */ -static int __init loader_write (const amb_dev * dev, const u32 * data, +static int __init loader_write (loader_block * lb, + const amb_dev * dev, const u32 * data, u32 address, unsigned int count) { unsigned int i; - loader_block lb; - transfer_block * tb = &lb.payload.transfer; + transfer_block * tb = &lb->payload.transfer; PRINTD (DBG_FLOW|DBG_LOAD, "loader_write"); @@ -2005,14 +2044,16 @@ tb->count = cpu_to_be32 (count); for (i = 0; i < count; ++i) tb->data[i] = cpu_to_be32 (data[i]); - return do_loader_command (dev, write_adapter_memory, &lb); + return do_loader_command (lb, dev, write_adapter_memory); } -static int __init loader_verify (const amb_dev * dev, const u32 * data, +/* loader: verify memory data blocks */ + +static int __init loader_verify (loader_block * lb, + const amb_dev * dev, const u32 * data, u32 address, unsigned int count) { unsigned int i; - loader_block lb; - transfer_block * tb = &lb.payload.transfer; + transfer_block * tb = &lb->payload.transfer; int res; PRINTD (DBG_FLOW|DBG_LOAD, "loader_verify"); @@ -2021,7 +2062,7 @@ return -EINVAL; tb->address = cpu_to_be32 (address); tb->count = cpu_to_be32 (count); - res = do_loader_command (dev, read_adapter_memory, &lb); + res = do_loader_command (lb, dev, read_adapter_memory); if (!res) for (i = 0; i < count; ++i) if (tb->data[i] != cpu_to_be32 (data[i])) { @@ -2031,13 +2072,14 @@ return res; } -static int __init loader_start (const amb_dev * dev, u32 address) { - loader_block lb; - +/* loader: start microcode */ + +static int __init loader_start (loader_block * lb, + const amb_dev * dev, u32 address) { PRINTD (DBG_FLOW|DBG_LOAD, "loader_start"); - lb.payload.start = cpu_to_be32 (address); - return do_loader_command (dev, adapter_start, &lb); + lb->payload.start = cpu_to_be32 (address); + return do_loader_command (lb, dev, adapter_start); } /********** reset card **********/ @@ -2047,19 +2089,21 @@ PRINTD (DBG_FLOW|DBG_LOAD, "amb_reset"); - word = rd_mem (dev, &mem->reset_control); -#if 0 - // clear all interrupts just in case - wr_mem (dev, &mem->interrupt, -1); -#endif + word = rd_plain (dev, &mem->reset_control); // put card into reset state - wr_mem (dev, &mem->reset_control, word | AMB_RESET); + wr_plain (dev, &mem->reset_control, word | AMB_RESET_BITS); // wait a short while udelay (10); +#if 1 + // put card into known good state + wr_plain (dev, &mem->interrupt_control, AMB_DOORBELL_BITS); + // clear all interrupts just in case + wr_plain (dev, &mem->interrupt, -1); +#endif // clear self-test done flag - wr_mem (dev, &mem->mb.loader.ready, 0); + wr_plain (dev, &mem->mb.loader.ready, 0); // take card out of reset state - wr_mem (dev, &mem->reset_control, word &~ AMB_RESET); + wr_plain (dev, &mem->reset_control, word &~ AMB_RESET_BITS); if (diags) { unsigned long timeout; @@ -2069,7 +2113,7 @@ timeout = schedule_timeout (timeout); // half second time-out timeout = HZ/2; - while (!rd_mem (dev, &mem->mb.loader.ready)) + while (!rd_plain (dev, &mem->mb.loader.ready)) if (timeout) { timeout = schedule_timeout (timeout); } else { @@ -2078,6 +2122,7 @@ } // get results of self-test + // XXX double check byte-order word = rd_mem (dev, &mem->mb.loader.result); if (word & SELF_TEST_FAILURE) { void sf (const char * msg) { @@ -2105,7 +2150,7 @@ /********** transfer and start the microcode **********/ -static int __init ucode_init (amb_dev * dev) { +static int __init ucode_init (loader_block * lb, amb_dev * dev) { unsigned int i = 0; unsigned int total = 0; const u32 * pointer = ucode_data; @@ -2125,10 +2170,10 @@ else words = MAX_TRANSFER_DATA; total += words; - res = loader_write (dev, pointer, address, words); + res = loader_write (lb, dev, pointer, address, words); if (res) return res; - res = loader_verify (dev, pointer, address, words); + res = loader_verify (lb, dev, pointer, address, words); if (res) return res; count -= words; @@ -2138,7 +2183,7 @@ i += 1; } if (*pointer == 0xdeadbeef) { - return loader_start (dev, ucode_start); + return loader_start (lb, dev, ucode_start); } else { // cast needed as there is no %? for pointer differnces PRINTD (DBG_LOAD|DBG_ERR, @@ -2156,14 +2201,14 @@ unsigned char pool; unsigned long timeout; - static inline u32 x (void * addr) { + u32 x (void * addr) { return cpu_to_be32 (virt_to_bus (addr)); } PRINTD (DBG_FLOW, "amb_talk %p", dev); - a.command_start = x (dev->cq.start); - a.command_end = x (dev->cq.limit); + a.command_start = x (dev->cq.ptrs.start); + a.command_end = x (dev->cq.ptrs.limit); a.tx_start = x (dev->txq.in.start); a.tx_end = x (dev->txq.in.limit); a.txcom_start = x (dev->txq.out.start); @@ -2192,7 +2237,7 @@ timeout = schedule_timeout (timeout); // give the adapter another half second? timeout = HZ/2; - while (rd_mem (dev, &mem->doorbell)) + while (rd_plain (dev, &mem->doorbell)) if (timeout) { timeout = schedule_timeout (timeout); } else { @@ -2259,38 +2304,55 @@ } static int __init amb_init (amb_dev * dev) { - u32 version; + loader_block lb; - /* enable adapter doorbell */ - wr_mem (dev, &mem->interrupt_control, - rd_mem (dev, &mem->interrupt_control) - | AMB_DOORBELL_BITS); + void fixup_plx_window (void) { + // fix up the PLX-mapped window base address to match the block + unsigned long blb; + u32 mapreg; + blb = virt_to_bus (&lb); + // the kernel stack had better not ever cross a 1Gb boundary! + mapreg = rd_plain (dev, &mem->stuff[10]); + mapreg &= ~onegigmask; + mapreg |= blb & onegigmask; + wr_plain (dev, &mem->stuff[10], mapreg); + return; + } + + u32 version; if (amb_reset (dev, 1)) { PRINTK (KERN_ERR, "card reset failed!"); - } else if (get_loader_version (dev, &version)) { - PRINTK (KERN_INFO, "failed to get loader version"); } else { - PRINTK (KERN_INFO, "loader version is %08x", version); + fixup_plx_window (); - if (ucode_init (dev)) { - PRINTK (KERN_ERR, "microcode failure"); - } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) { - PRINTK (KERN_ERR, "failed to get memory for queues"); + if (get_loader_version (&lb, dev, &version)) { + PRINTK (KERN_INFO, "failed to get loader version"); } else { + PRINTK (KERN_INFO, "loader version is %08x", version); - if (amb_talk (dev)) { - PRINTK (KERN_ERR, "adapter did not accept queues"); + if (ucode_init (&lb, dev)) { + PRINTK (KERN_ERR, "microcode failure"); + } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) { + PRINTK (KERN_ERR, "failed to get memory for queues"); } else { - amb_ucode_version (dev); - return 0; - } /* amb_talk */ + if (amb_talk (dev)) { + PRINTK (KERN_ERR, "adapter did not accept queues"); + } else { + + amb_ucode_version (dev); + return 0; + + } /* amb_talk */ + + destroy_queues (dev); + } /* create_queues, ucode_init */ - destroy_queues (dev); - } /* create_queues, ucode_init */ + amb_reset (dev, 0); + } /* get_loader_version */ - } /* get_loader_version, amb_reset */ + } /* amb_reset */ return -1; } @@ -2303,81 +2365,57 @@ amb_dev * dev; // read resources from PCI configuration space - u32 * membase = bus_to_virt - (pci_dev->resource[0].start); - u32 iobase = pci_dev->resource[1].start; u8 irq = pci_dev->irq; + u32 * membase = bus_to_virt (pci_dev->resource[0].start); + u32 iobase = pci_dev->resource[1].start; - // check IO region - if (check_region (iobase, AMB_EXTENT)) { - PRINTK (KERN_ERR, "IO range already in use!"); - return; - } - - dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); - if (!dev) { - // perhaps we should be nice: deregister all adapters and abort? - PRINTK (KERN_ERR, "out of memory!"); - return; - } - memset (dev, 0, sizeof(amb_dev)); - - // set up known dev items straight away - dev->pci_dev = pci_dev; - - dev->iobase = iobase; - dev->irq = irq; - dev->membase = membase; - - // flags (currently only dead) - dev->flags = 0; - - // Allocate cell rates (fibre) - // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 - // to be really pedantic, this should be ATM_OC3c_PCR - dev->tx_avail = ATM_OC3_PCR; - dev->rx_avail = ATM_OC3_PCR; - -#if 0 - // initialise bottom half - dev->bh.next = 0; - dev->bh.sync = 0; - dev->bh.routine = (void (*)(void *)) fill_rx_pools; - dev->bh.data = dev; -#endif - - // semaphore for txer/rxer modifications - we cannot use a - // spinlock as the critical region needs to switch processes - init_MUTEX (&dev->vcc_sf); - // queue manipulation spinlocks; we want atomic reads and - // writes to the queue descriptors (handles IRQ and SMP) - // consider replacing "int pending" -> "atomic_t available" - // => problem related to who gets to move queue pointers - spin_lock_init (&dev->cq.lock); - spin_lock_init (&dev->txq.lock); - { + void setup_dev (void) { unsigned char pool; + memset (dev, 0, sizeof(amb_dev)); + + // set up known dev items straight away + dev->pci_dev = pci_dev; + + dev->iobase = iobase; + dev->irq = irq; + dev->membase = membase; + + // flags (currently only dead) + dev->flags = 0; + + // Allocate cell rates (fibre) + // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 + // to be really pedantic, this should be ATM_OC3c_PCR + dev->tx_avail = ATM_OC3_PCR; + dev->rx_avail = ATM_OC3_PCR; + +#ifdef FILL_RX_POOLS_IN_BH + // initialise bottom half + dev->bh.next = 0; + dev->bh.sync = 0; + dev->bh.routine = (void (*)(void *)) fill_rx_pools; + dev->bh.data = dev; +#endif + + // semaphore for txer/rxer modifications - we cannot use a + // spinlock as the critical region needs to switch processes + init_MUTEX (&dev->vcc_sf); + // queue manipulation spinlocks; we want atomic reads and + // writes to the queue descriptors (handles IRQ and SMP) + // consider replacing "int pending" -> "atomic_t available" + // => problem related to who gets to move queue pointers + spin_lock_init (&dev->cq.lock); + spin_lock_init (&dev->txq.lock); for (pool = 0; pool < NUM_RX_POOLS; ++pool) spin_lock_init (&dev->rxq[pool].lock); } - // grab (but share) IRQ and install handler - if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) { - PRINTK (KERN_ERR, "request IRQ failed!"); - // free_irq is at "endif" - } else { - + void setup_pci_dev (void) { unsigned char lat; - // reserve IO region - request_region (iobase, AMB_EXTENT, DEV_LABEL); - - PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at IO %x, IRQ %u, MEM %p", - iobase, irq, membase); - // enable bus master accesses pci_set_master (pci_dev); - + // frobnicate latency (upwards, usually) pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); if (pci_lat) { @@ -2389,43 +2427,78 @@ "increasing", lat, MIN_PCI_LATENCY); pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); } + } + + PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at" + " IO %x, IRQ %u, MEM %p", iobase, irq, membase); + + // check IO region + if (check_region (iobase, AMB_EXTENT)) { + PRINTK (KERN_ERR, "IO range already in use!"); + return; + } + + dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); + if (!dev) { + // perhaps we should be nice: deregister all adapters and abort? + PRINTK (KERN_ERR, "out of memory!"); + return; + } + + setup_dev(); + + if (amb_init (dev)) { + PRINTK (KERN_ERR, "adapter initialisation failure"); + } else { + + setup_pci_dev(); - if (amb_init (dev)) { - PRINTK (KERN_ERR, "adapter initialisation failure"); - } else if (!(dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, 0))) { - PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); + // grab (but share) IRQ and install handler + if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) { + PRINTK (KERN_ERR, "request IRQ failed!"); + // free_irq is at "endif" } else { - PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", - dev->atm_dev->number, dev, dev->atm_dev); - dev->atm_dev->dev_data = (void *) dev; - - // register our address - amb_esi (dev, dev->atm_dev->esi); + // reserve IO region + request_region (iobase, AMB_EXTENT, DEV_LABEL); - // 0 bits for vpi, 10 bits for vci - dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS; - dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS; - - fill_rx_pools (dev); - - /* enable host interrupts */ - interrupts_on (dev); - - // update count and linked list - ++devs; - dev->prev = amb_devs; - amb_devs = dev; - // success - return; + dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL); + if (!dev->atm_dev) { + PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); + } else { + + PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", + dev->atm_dev->number, dev, dev->atm_dev); + dev->atm_dev->dev_data = (void *) dev; + + // register our address + amb_esi (dev, dev->atm_dev->esi); + + // 0 bits for vpi, 10 bits for vci + dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS; + dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS; + + // update count and linked list + ++devs; + dev->prev = amb_devs; + amb_devs = dev; + + // enable host interrupts + interrupts_on (dev); + + // success + return; + + // not currently reached + atm_dev_deregister (dev->atm_dev); + } /* atm_dev_register */ - // not currently reached - atm_dev_deregister (dev->atm_dev); - } /* atm_dev_register, amb_init */ + release_region (iobase, AMB_EXTENT); + free_irq (irq, dev); + } /* request_region, request_irq */ - release_region (iobase, AMB_EXTENT); - free_irq (irq, dev); - } /* request_region, request_irq */ + amb_reset (dev, 0); + } /* amb_init */ kfree (dev); } /* kmalloc, end-of-fn */ @@ -2529,7 +2602,6 @@ show_version(); - // check arguments amb_check_args(); // get the juice @@ -2566,8 +2638,8 @@ PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev); // the drain should not be necessary drain_rx_pools (dev); - amb_reset (dev, 0); interrupts_off (dev); + amb_reset (dev, 0); destroy_queues (dev); atm_dev_deregister (dev->atm_dev); free_irq (dev->irq, dev); @@ -2594,7 +2666,6 @@ show_version(); - // check arguments amb_check_args(); // get the juice diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/ambassador.h linux/drivers/atm/ambassador.h --- v2.3.99-pre2/linux/drivers/atm/ambassador.h Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/ambassador.h Tue Mar 21 23:38:26 2000 @@ -237,8 +237,6 @@ #define FP_155_RATE 0x24b1 #define FP_25_RATE 0x1f9d -#define AMB_RESET 0x40 - /* #define VERSION_NUMBER 0x01000000 // initial release */ /* #define VERSION_NUMBER 0x01010000 // fixed startup probs PLX MB0 not cleared */ /* #define VERSION_NUMBER 0x01020000 // changed SUNI reset timings; allowed r/w onchip */ @@ -333,9 +331,10 @@ u32 reset_control; } amb_mem; -/* IRQ (card to host) and doorbell (host to card) enable bits */ -#define AMB_INTERRUPT_BITS 0x00030000 -#define AMB_DOORBELL_BITS 0x00000300 +/* RESET bit, IRQ (card to host) and doorbell (host to card) enable bits */ +#define AMB_RESET_BITS 0x40000000 +#define AMB_INTERRUPT_BITS 0x00000300 +#define AMB_DOORBELL_BITS 0x00030000 /* loader commands */ @@ -543,14 +542,19 @@ ( (current)+1 < (limit) ? (current)+1 : (start) ) typedef struct { - spinlock_t lock; - unsigned int pending; - unsigned int high; - unsigned int maximum; // size - 1 (q implementation) command * start; command * in; command * out; command * limit; +} amb_cq_ptrs; + +typedef struct { + spinlock_t lock; + unsigned int pending; + unsigned int high; + unsigned int filled; + unsigned int maximum; // size - 1 (q implementation) + amb_cq_ptrs ptrs; } amb_cq; typedef struct { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c --- v2.3.99-pre2/linux/drivers/atm/atmdev_init.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/atmdev_init.c Tue Mar 21 23:38:26 2000 @@ -39,7 +39,7 @@ devs = 0; #ifdef CONFIG_ATM_ENI - devs += eni_detect(); +// devs += eni_detect(); #endif #ifdef CONFIG_ATM_ZATM devs += zatm_detect(); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/atmtcp.c linux/drivers/atm/atmtcp.c --- v2.3.99-pre2/linux/drivers/atm/atmtcp.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/atmtcp.c Tue Mar 21 23:38:26 2000 @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */ @@ -36,12 +38,14 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type, - const struct atmtcp_control *msg,unsigned short flag) + const struct atmtcp_control *msg,int flag) { + DECLARE_WAITQUEUE(wait,current); struct atm_vcc *out_vcc; struct sk_buff *skb; struct atmtcp_control *new_msg; - unsigned short old_flags; + int old_test; + int error = 0; out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; if (!out_vcc) return -EUNATCH; @@ -60,16 +64,21 @@ new_msg->type = type; memset(&new_msg->vcc,0,sizeof(atm_kptr_t)); *(struct atm_vcc **) &new_msg->vcc = vcc; - old_flags = vcc->flags; + old_test = test_bit(flag,&vcc->flags); out_vcc->push(out_vcc,skb); - while (!((vcc->flags ^ old_flags) & flag)) { + add_wait_queue(&vcc->sleep,&wait); + while (test_bit(flag,&vcc->flags) == old_test) { mb(); out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; - if (!out_vcc) return -EUNATCH; - sleep_on(&vcc->sleep); - + if (!out_vcc) { + error = -EUNATCH; + break; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); } - return 0; + remove_wait_queue(&vcc->sleep,&wait); + return error; } @@ -83,10 +92,10 @@ vcc->reply = msg->result; switch (msg->type) { case ATMTCP_CTRL_OPEN: - vcc->flags ^= ATM_VF_READY; + change_bit(ATM_VF_READY,&vcc->flags); break; case ATMTCP_CTRL_CLOSE: - vcc->flags ^= ATM_VF_ADDR; + change_bit(ATM_VF_ADDR,&vcc->flags); break; default: printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n", @@ -120,8 +129,8 @@ if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0; msg.type = ATMTCP_CTRL_OPEN; msg.qos = vcc->qos; - vcc->flags |= ATM_VF_ADDR; - vcc->flags &= ~ATM_VF_READY; /* just in case ... */ + set_bit(ATM_VF_ADDR,&vcc->flags); + clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */ error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY); if (error) return error; return vcc->reply; @@ -136,7 +145,7 @@ msg.addr.sap_family = AF_ATMPVC; msg.addr.sap_addr.vpi = vcc->vpi; msg.addr.sap_addr.vci = vcc->vci; - vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&vcc->flags); (void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR); } @@ -168,13 +177,18 @@ struct atmtcp_hdr *hdr; int size; + if (vcc->qos.txtp.traffic_class == ATM_NONE) { + if (vcc->pop) vcc->pop(vcc,skb); + else dev_kfree_skb(skb); + return -EINVAL; + } dev_data = PRIV(vcc->dev); if (dev_data) out_vcc = dev_data->vcc; if (!dev_data || !out_vcc) { if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); if (dev_data) return 0; - vcc->stats->tx_err++; + atomic_inc(&vcc->stats->tx_err); return -ENOLINK; } size = skb->len+sizeof(struct atmtcp_hdr); @@ -182,7 +196,7 @@ if (!new_skb) { if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); - vcc->stats->tx_err++; + atomic_inc(&vcc->stats->tx_err); return -ENOBUFS; } hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr)); @@ -193,8 +207,8 @@ if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); out_vcc->push(out_vcc,new_skb); - vcc->stats->tx++; - out_vcc->stats->rx++; + atomic_inc(&vcc->stats->tx); + atomic_inc(&out_vcc->stats->rx); return 0; } @@ -251,7 +265,7 @@ out_vcc->qos.rxtp.traffic_class != ATM_NONE) break; if (!out_vcc) { - vcc->stats->tx_err++; + atomic_inc(&vcc->stats->tx_err); goto done; } skb_pull(skb,sizeof(struct atmtcp_hdr)); @@ -263,8 +277,8 @@ new_skb->stamp = xtime; memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); out_vcc->push(out_vcc,new_skb); - vcc->stats->tx++; - out_vcc->stats->rx++; + atomic_inc(&vcc->stats->tx); + atomic_inc(&out_vcc->stats->rx); done: if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); @@ -305,7 +319,7 @@ 999, /* dummy device number */ NULL,NULL, /* pretend not to have any VCCs */ NULL,NULL, /* no data */ - 0, /* no flags */ + { 0 }, /* no flags */ NULL, /* no local address */ { 0 } /* no ESI, no statistics */ }; @@ -318,7 +332,7 @@ dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL); if (!dev_data) return -ENOMEM; - dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,0); + dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL); if (!dev) { kfree(dev_data); return itf == -1 ? -ENOMEM : -EBUSY; @@ -352,7 +366,8 @@ } PRIV(dev)->vcc = vcc; bind_vcc(vcc,&atmtcp_control_dev); - vcc->flags |= ATM_VF_READY | ATM_VF_META; + set_bit(ATM_VF_META,&vcc->flags); + set_bit(ATM_VF_READY,&vcc->flags); vcc->dev_data = dev; (void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */ vcc->stats = &atmtcp_control_dev.stats.aal5; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.3.99-pre2/linux/drivers/atm/eni.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/eni.c Tue Mar 21 23:38:26 2000 @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -526,7 +528,7 @@ DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n", vcc->dev->number); length = 0; - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); } else { length = ATM_CELL_SIZE-1; /* no HEC */ @@ -581,7 +583,7 @@ size); } eff = length = 0; - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); } else { size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); @@ -598,7 +600,7 @@ "(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n", vcc->dev->number,vcc->vci,length,size << 2,descr); length = eff = 0; - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); } } skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL; @@ -663,6 +665,7 @@ if (rx_vcc(curr)) return; eni_dev->fast = ENI_VCC(curr)->next; ENI_VCC(curr)->next = ENI_VCC_NOS; + barrier(); ENI_VCC(curr)->servicing--; } while ((curr = eni_dev->slow)) { @@ -670,6 +673,7 @@ if (rx_vcc(curr)) return; eni_dev->slow = ENI_VCC(curr)->next; ENI_VCC(curr)->next = ENI_VCC_NOS; + barrier(); ENI_VCC(curr)->servicing--; } } @@ -768,7 +772,7 @@ vcc->push(vcc,skb); pushed++; } - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); } wake_up(&eni_dev->rx_wait); } @@ -836,10 +840,10 @@ static void close_rx(struct atm_vcc *vcc) { - unsigned long here,flags; + DECLARE_WAITQUEUE(wait,current); + unsigned long here; struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; - u32 tmp; eni_vcc = ENI_VCC(vcc); if (!eni_vcc->rx) return; @@ -858,25 +862,41 @@ /* wait for RX queue to drain */ DPRINTK("eni_close: waiting for RX ...\n"); EVENT("RX closing\n",0,0); - save_flags(flags); - cli(); - while (eni_vcc->rxing || eni_vcc->servicing) { + add_wait_queue(&eni_dev->rx_wait,&wait); + set_current_state(TASK_UNINTERRUPTIBLE); + barrier(); + for (;;) { + /* transition service->rx: rxing++, servicing-- */ + if (!eni_vcc->servicing) { + barrier(); + if (!eni_vcc->rxing) break; + } EVENT("drain PDUs (rx %ld, serv %ld)\n",eni_vcc->rxing, eni_vcc->servicing); printk(KERN_INFO "%d+%d RX left\n",eni_vcc->servicing, eni_vcc->rxing); - sleep_on(&eni_dev->rx_wait); + schedule(); + set_current_state(TASK_UNINTERRUPTIBLE); } - while (eni_vcc->rx_pos != (tmp = - readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ)>> - MID_VCI_READ_SHIFT) { + for (;;) { + unsigned long flags; + int at_end; + u32 tmp; + + spin_lock_irqsave(&eni_dev->lock,flags); + tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ; + at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT; + spin_unlock_irqrestore(&eni_dev->lock,flags); + if (at_end) break; EVENT("drain discard (host 0x%lx, nic 0x%lx)\n", eni_vcc->rx_pos,tmp); printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n", eni_vcc->rx_pos,tmp); - sleep_on(&eni_dev->rx_wait); + schedule(); + set_current_state(TASK_UNINTERRUPTIBLE); } - restore_flags(flags); + set_current_state(TASK_RUNNING); + remove_wait_queue(&eni_dev->rx_wait,&wait); } eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2); eni_vcc->rx = NULL; @@ -1054,8 +1074,9 @@ * 1 DMA xfer & 2 DMA'ed bytes (protocol layering is for wimps :-) */ + aal5 = vcc->qos.aal == ATM_AAL5; /* check space in buffer */ - if (!(aal5 = vcc->qos.aal == ATM_AAL5)) + if (!aal5) size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE; /* cell without HEC plus segmentation header (includes four-byte cell header) */ @@ -1207,7 +1228,7 @@ PCI_DMA_TODEVICE); if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb_irq(skb); - vcc->stats->tx++; + atomic_inc(&vcc->stats->tx); wake_up(&eni_dev->tx_wait); dma_complete++; } @@ -1366,34 +1387,40 @@ static void close_tx(struct atm_vcc *vcc) { + DECLARE_WAITQUEUE(wait,current); struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; - unsigned long flags; eni_vcc = ENI_VCC(vcc); if (!eni_vcc->tx) return; eni_dev = ENI_DEV(vcc->dev); /* wait for TX queue to drain */ DPRINTK("eni_close: waiting for TX ...\n"); - save_flags(flags); - cli(); - while (skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing) { + add_wait_queue(&eni_dev->tx_wait,&wait); + set_current_state(TASK_UNINTERRUPTIBLE); + for (;;) { + unsigned long flags; + int txing; + + spin_lock_irqsave(&eni_dev->lock,flags); + txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing; + spin_unlock_irqrestore(&eni_dev->lock,flags); + if (!txing) break; DPRINTK("%d TX left\n",eni_vcc->txing); - sleep_on(&eni_dev->tx_wait); - } - /* - * Looping a few times in here is probably far cheaper than keeping - * track of TX completions all the time, so let's poll a bit ... - */ - while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) != - eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index))) schedule(); - restore_flags(flags); -#if 0 - if (skb_peek(&eni_vcc->tx->backlog)) - printk(KERN_CRIT DEV_LABEL "SKBs in BACKLOG !!!\n"); -#endif + set_current_state(TASK_UNINTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&eni_dev->tx_wait,&wait); if (eni_vcc->tx != eni_dev->ubr) { + /* + * Looping a few times in here is probably far cheaper than + * keeping track of TX completions all the time, so let's poll + * a bit ... + */ + while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) != + eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index))) + schedule(); eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2); eni_vcc->tx->send = 0; eni_dev->tx_bw += eni_vcc->tx->reserved; @@ -1496,28 +1523,36 @@ if (reason & MID_RX_DMA_COMPLETE) { EVENT("INT: RX DMA complete, starting dequeue_rx\n", 0,0); + spin_lock(&eni_dev->lock); dequeue_rx(dev); EVENT("dequeue_rx done, starting poll_rx\n",0,0); poll_rx(dev); + spin_unlock(&eni_dev->lock); EVENT("poll_rx done\n",0,0); /* poll_tx ? */ } if (reason & MID_SERVICE) { EVENT("INT: service, starting get_service\n",0,0); + spin_lock(&eni_dev->lock); get_service(dev); EVENT("get_service done, starting poll_rx\n",0,0); poll_rx(dev); + spin_unlock(&eni_dev->lock); EVENT("poll_rx done\n",0,0); } if (reason & MID_TX_DMA_COMPLETE) { EVENT("INT: TX DMA COMPLETE\n",0,0); + spin_lock(&eni_dev->lock); dequeue_tx(dev); + spin_unlock(&eni_dev->lock); } if (reason & MID_TX_COMPLETE) { EVENT("INT: TX COMPLETE\n",0,0); tx_complete++; - wake_up(&eni_dev->tx_wait); + spin_lock(&eni_dev->lock); poll_tx(dev); + spin_unlock(&eni_dev->lock); + wake_up(&eni_dev->tx_wait); /* poll_rx ? */ } if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK | @@ -1532,7 +1567,7 @@ /*--------------------------------- entries ---------------------------------*/ -static const char *media_name[] __initdata = { +static const char *media_name[] __devinitdata = { "MMF", "SMF", "MMF", "03?", /* 0- 3 */ "UTP", "05?", "06?", "07?", /* 4- 7 */ "TAXI","09?", "10?", "11?", /* 8-11 */ @@ -1556,7 +1591,7 @@ } }) -static int __init get_esi_asic(struct atm_dev *dev) +static int __devinit get_esi_asic(struct atm_dev *dev) { struct eni_dev *eni_dev; unsigned char tonga; @@ -1648,7 +1683,7 @@ #undef GET_SEPROM -static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base) +static int __devinit get_esi_fpga(struct atm_dev *dev,unsigned long base) { unsigned long mac_base; int i; @@ -1659,7 +1694,7 @@ } -static int __init eni_init(struct atm_dev *dev) +static int __devinit eni_do_init(struct atm_dev *dev) { struct midway_eprom *eprom; struct eni_dev *eni_dev; @@ -1748,7 +1783,7 @@ } -static int __init eni_start(struct atm_dev *dev) +static int __devinit eni_start(struct atm_dev *dev) { struct eni_dev *eni_dev; unsigned long buf,buffer_mem; @@ -1788,6 +1823,7 @@ DPRINTK("vci 0x%lx,rx 0x%lx, tx 0x%lx,srv 0x%lx,buf 0x%lx\n", eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma, eni_dev->service,buf); + spin_lock_init(&eni_dev->lock); /* initialize memory management */ buffer_mem = eni_dev->mem-(buf-eni_dev->ram); eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2; @@ -1830,14 +1866,14 @@ { DPRINTK(">eni_close\n"); if (!ENI_VCC(vcc)) return; - vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&vcc->flags); close_rx(vcc); close_tx(vcc); DPRINTK("eni_close: done waiting\n"); /* deallocate memory */ kfree(ENI_VCC(vcc)); ENI_VCC(vcc) = NULL; - vcc->flags &= ~ATM_VF_ADDR; + clear_bit(ATM_VF_ADDR,&vcc->flags); /*foo();*/ } @@ -1855,8 +1891,8 @@ if (vcc->qos.txtp.traffic_class != ATM_NONE) { for (walk = vcc->dev->vccs; walk; walk = walk->next) - if ((walk->flags & ATM_VF_ADDR) && - walk->vci == *vci && + if (test_bit(ATM_VF_ADDR,&walk->flags) + && walk->vci == *vci && walk->qos.txtp.traffic_class != ATM_NONE) break; @@ -1872,7 +1908,7 @@ return -EADDRINUSE; if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; for (walk = vcc->dev->vccs; walk; walk = walk->next) - if ((walk->flags & ATM_VF_ADDR) && walk->vci == *vci && + if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci && walk->qos.txtp.traffic_class != ATM_NONE) return -EADDRINUSE; return 0; @@ -1887,19 +1923,19 @@ DPRINTK(">eni_open\n"); EVENT("eni_open\n",0,0); - if (!(vcc->flags & ATM_VF_PARTIAL)) ENI_VCC(vcc) = NULL; + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL; eni_dev = ENI_DEV(vcc->dev); error = get_ci(vcc,&vpi,&vci); if (error) return error; vcc->vpi = vpi; vcc->vci = vci; if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) - vcc->flags |= ATM_VF_ADDR; + set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5) return -EINVAL; DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, vcc->vci); - if (!(vcc->flags & ATM_VF_PARTIAL)) { + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL); if (!eni_vcc) return -ENOMEM; ENI_VCC(vcc) = eni_vcc; @@ -1922,7 +1958,7 @@ eni_close(vcc); return error; } - vcc->flags |= ATM_VF_READY; + set_bit(ATM_VF_READY,&vcc->flags); /* should power down SUNI while !ref_count @@@ */ return 0; } @@ -1953,8 +1989,7 @@ * Walk through the send buffer and patch the rate information in all * segmentation buffer descriptors of this VCC. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&eni_dev->lock,flags); for (skb = eni_dev->tx_queue.next; skb != (struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) { unsigned long dsc; @@ -1965,7 +2000,7 @@ (tx->prescaler << MID_SEG_PR_SHIFT) | (tx->resolution << MID_SEG_RATE_SHIFT), dsc); } - restore_flags(flags); + spin_unlock_irqrestore(&eni_dev->lock,flags); return 0; } @@ -2049,14 +2084,13 @@ } submitted++; ATM_SKB(skb)->vcc = vcc; - save_flags(flags); - cli(); /* brute force */ + spin_lock_irqsave(&ENI_DEV(vcc->dev)->lock,flags); /* brute force */ if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) { skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb); ENI_VCC(vcc)->tx->backlog_len++; backlogged++; } - restore_flags(flags); + spin_unlock_irqrestore(&ENI_DEV(vcc->dev)->lock,flags); return 0; } @@ -2206,79 +2240,86 @@ }; -int __init eni_detect(void) +static int __devinit eni_init_one(struct pci_dev *pci_dev, + const struct pci_device_id *ent) { struct atm_dev *dev; struct eni_dev *eni_dev; - int devs,type; - struct sk_buff *skb; + int error = -ENOMEM; - DPRINTK("eni_detect\n"); - if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) { - printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n", - sizeof(skb->cb),sizeof(struct eni_skb_prv)); - return 0; - } - eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev), - GFP_KERNEL); + DPRINTK("eni_init_one\n"); + eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),GFP_KERNEL); if (!eni_dev) return -ENOMEM; - devs = 0; - for (type = 0; type < 2; type++) { - struct pci_dev *pci_dev; - - pci_dev = NULL; - while ((pci_dev = pci_find_device(PCI_VENDOR_ID_EF,type ? - PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA, - pci_dev))) { - if (!devs) { - cpu_zeroes = pci_alloc_consistent(pci_dev, - ENI_ZEROES_SIZE,&zeroes); - if (!cpu_zeroes) { - kfree(eni_dev); - return -ENOMEM; - } - } - dev = atm_dev_register(DEV_LABEL,&ops,-1,0); - if (!dev) break; - eni_dev->pci_dev = pci_dev; - ENI_DEV(dev) = eni_dev; - eni_dev->asic = type; - if (eni_init(dev) || eni_start(dev)) { - atm_dev_deregister(dev); - break; - } - eni_dev->more = eni_boards; - eni_boards = dev; - devs++; - eni_dev = (struct eni_dev *) kmalloc(sizeof(struct - eni_dev),GFP_KERNEL); - if (!eni_dev) break; - } - } - if (!devs && cpu_zeroes) { - pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE, - cpu_zeroes,zeroes); - cpu_zeroes = NULL; - } + if (!cpu_zeroes) { + cpu_zeroes = pci_alloc_consistent(pci_dev,ENI_ZEROES_SIZE, + &zeroes); + if (!cpu_zeroes) goto out1; + } + dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); + if (!dev) goto out2; + pci_dev->driver_data = dev; + eni_dev->pci_dev = pci_dev; + ENI_DEV(dev) = eni_dev; + eni_dev->asic = ent->driver_data; + error = eni_do_init(dev); + if (error) goto out3; + error = eni_start(dev); + if (error) goto out3; + eni_dev->more = eni_boards; + eni_boards = dev; + MOD_INC_USE_COUNT; /* @@@ we don't support unloading yet */ + return 0; +out3: + atm_dev_deregister(dev); +out2: + pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,cpu_zeroes,zeroes); + cpu_zeroes = NULL; +out1: kfree(eni_dev); - return devs; + return error; } -#ifdef MODULE +static struct pci_device_id eni_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_FPGA, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 /* FPGA */ }, + { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_ASIC, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 1 /* ASIC */ }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci,eni_pci_tbl); + -int init_module(void) +static void __devexit eni_remove_one(struct pci_dev *pci_dev) { - if (!eni_detect()) { - printk(KERN_ERR DEV_LABEL ": no adapter found\n"); - return -ENXIO; + /* grrr */ +} + + +static struct pci_driver eni_driver = { + name: DEV_LABEL, + id_table: eni_pci_tbl, + probe: eni_init_one, + remove: eni_remove_one, +}; + + +static int __init eni_init(void) +{ + struct sk_buff *skb; /* dummy for sizeof */ + + if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) { + printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n", + sizeof(skb->cb),sizeof(struct eni_skb_prv)); + return -EIO; } - MOD_INC_USE_COUNT; - return 0; + if (pci_register_driver(&eni_driver) > 0) return 0; + pci_unregister_driver (&eni_driver); + return -ENODEV; } -void cleanup_module(void) +static void __exit eni_cleanup(void) { /* * Well, there's no way to get rid of the driver yet, so we don't @@ -2286,4 +2327,6 @@ */ } -#endif + +module_init(eni_init); +module_exit(eni_cleanup); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/eni.h linux/drivers/atm/eni.h --- v2.3.99-pre2/linux/drivers/atm/eni.h Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/eni.h Tue Mar 21 23:38:26 2000 @@ -12,6 +12,7 @@ #include #include #include +#include #include "midway.h" @@ -65,6 +66,8 @@ }; struct eni_dev { + /*-------------------------------- spinlock */ + spinlock_t lock; /* sync with interrupt */ /*-------------------------------- base pointers into Midway address space */ unsigned long phy; /* PHY interface chip registers */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c --- v2.3.99-pre2/linux/drivers/atm/fore200e.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/fore200e.c Tue Mar 21 23:38:26 2000 @@ -1,5 +1,5 @@ /* - $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $ + $Id: fore200e.c,v 1.2 2000/03/21 21:19:24 davem Exp $ A FORE Systems 200E-series driver for ATM on Linux. Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000. @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #ifdef CONFIG_ATM_FORE200E_PCA #include @@ -67,7 +69,7 @@ #define FORE200E_52BYTE_AAL0_SDU #endif -#define FORE200E_VERSION "0.2a" +#define FORE200E_VERSION "0.2b" #define FORE200E "fore200e: " @@ -187,10 +189,10 @@ /* allocate and align a chunk of memory intended to hold the data behing exchanged - between the driver and the adapter (using streaming DVMA on SBUS hosts) */ + between the driver and the adapter (using streaming DVMA) */ static int -fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment) +fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment, int direction) { unsigned long offset = 0; @@ -199,6 +201,7 @@ chunk->alloc_size = size + alignment; chunk->align_size = size; + chunk->direction = direction; chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); if (chunk->alloc_addr == NULL) @@ -209,7 +212,7 @@ chunk->align_addr = chunk->alloc_addr + offset; - chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size); + chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size, direction); return 0; } @@ -220,7 +223,7 @@ static void fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) { - fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); + fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction); fore200e_kfree(chunk->alloc_addr); } @@ -463,34 +466,32 @@ static u32 -fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction) { - u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL); + u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, direction); - DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", - virt_addr, size, dma_addr); + DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n", + virt_addr, size, direction, dma_addr); return dma_addr; } static void -fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, - PCI_DMA_BIDIRECTIONAL); + pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); } static void -fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, - PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -511,10 +512,8 @@ chunk->align_addr = chunk->alloc_addr; #else - if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0) + if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0) return -ENOMEM; - - chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size); #endif return 0; @@ -532,8 +531,6 @@ chunk->alloc_addr, chunk->dma_addr); #else - fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); - fore200e_chunk_free(fore200e, chunk); #endif } @@ -685,7 +682,7 @@ opcode.opcode = OPCODE_GET_PROM; opcode.pad = 0; - prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data)); + prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE); fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); @@ -697,7 +694,7 @@ *entry->status = STATUS_FREE; - fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data)); + fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); @@ -748,31 +745,32 @@ static u32 -fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction) { - u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size); + u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction); - DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr); + DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", + virt_addr, size, direction, dma_addr); return dma_addr; } static void -fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction); - sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); + sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } static void -fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); + sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -1002,7 +1000,8 @@ kfree(entry->data); /* remove DMA mapping */ - fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, + FORE200E_DMA_TODEVICE); /* notify tx completion */ if (entry->vcc->pop) @@ -1012,9 +1011,9 @@ /* check error condition */ if (*entry->status & STATUS_ERROR) - entry->vcc->stats->tx_err++; + atomic_inc(&entry->vcc->stats->tx_err); else - entry->vcc->stats->tx++; + atomic_inc(&entry->vcc->stats->tx); *entry->status = STATUS_FREE; @@ -1127,7 +1126,7 @@ if (skb == NULL) { printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); - vcc->stats->rx_drop++; + atomic_inc(&vcc->stats->rx_drop); return; } @@ -1146,7 +1145,7 @@ buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); /* ensure DMA synchronisation */ - fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length); + fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE); memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); } @@ -1169,7 +1168,7 @@ } vcc->push(vcc, skb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); } @@ -1404,7 +1403,7 @@ if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0; - vcc->flags |= ATM_VF_ADDR; + set_bit(ATM_VF_ADDR,&vcc->flags); vcc->itf = vcc->dev->number; DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " @@ -1467,7 +1466,7 @@ fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; - vcc->flags |= ATM_VF_READY; + clear_bit(ATM_VF_READY,&vcc->flags); return 0; } @@ -1552,11 +1551,14 @@ if(--retry > 0) goto retry_here; - vcc->stats->tx_err++; + atomic_inc(&vcc->stats->tx_err); printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", fore200e->name, fore200e->cp_queues->heartbeat); - + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); return -EIO; } } @@ -1584,6 +1586,10 @@ if (entry->data == NULL) { spin_unlock_irqrestore(&fore200e->tx_lock, flags); + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); return -ENOMEM; } @@ -1591,11 +1597,11 @@ if (skb_len < tx_len) memset(entry->data + skb_len, 0x00, tx_len - skb_len); - tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len); + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE); } else { entry->data = NULL; - tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len); + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE); } tpd->tsd[ 0 ].length = tx_len; @@ -1606,7 +1612,7 @@ spin_unlock_irqrestore(&fore200e->tx_lock, flags); /* ensure DMA synchronisation */ - fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length); + fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), @@ -1661,27 +1667,29 @@ { int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10); - fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, + FORE200E_DMA_TODEVICE); - if (ok == 0) { - printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); - - entry->vcc->stats->tx_err++; - return -EIO; - } - entry->vcc->stats->tx++; - - DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); - /* free tmp copy of misaligned data */ if (entry->data) kfree(entry->data); - + /* notify tx completion */ if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); + + if (ok == 0) { + printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); + + atomic_inc(&entry->vcc->stats->tx_err); + return -EIO; + } + atomic_inc(&entry->vcc->stats->tx); + + DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); + } #endif @@ -1704,7 +1712,7 @@ return -ENOMEM; } - stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats)); + stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); @@ -1721,7 +1729,7 @@ *entry->status = STATUS_FREE; - fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats)); + fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); @@ -1766,7 +1774,7 @@ int ok; u32 oc3_regs_dma_addr; - oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs)); + oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); @@ -1785,7 +1793,7 @@ *entry->status = STATUS_FREE; - fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs)); + fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); @@ -1842,16 +1850,16 @@ switch (loop_mode) { - case SUNI_LM_NONE: + case ATM_LM_NONE: mct_value = 0; mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE; break; - case SUNI_LM_DIAG: + case ATM_LM_LOC_PHY: mct_value = mct_mask = SUNI_MCT_DLE; break; - case SUNI_LM_LOOP: + case ATM_LM_RMT_PHY: mct_value = mct_mask = SUNI_MCT_LLE; break; @@ -1921,12 +1929,16 @@ case SONET_GETDIAG: return put_user(0, (int*)arg) ? -EFAULT : 0; - - case SUNI_SETLOOP: + + case ATM_SETLOOP: return fore200e_setloop(fore200e, (int)(unsigned long)arg); - case SUNI_GETLOOP: + case ATM_GETLOOP: return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; + + case ATM_QUERYLOOP: + return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? + -EFAULT : 0; } return -ENOSYS; /* not implemented */ @@ -1967,7 +1979,7 @@ /* update rate control parameters */ fore200e_rate_ctrl(qos, &fore200e_vcc->rate); - vcc->flags |= ATM_VF_HASQOS; + set_bit(ATM_VF_HASQOS,&vcc->flags); return 0; } @@ -2051,7 +2063,8 @@ /* allocate the receive buffer body */ if (fore200e_chunk_alloc(fore200e, - &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) { + &buffer[ i ].data, size, fore200e->bus->buffer_alignment, + FORE200E_DMA_FROMDEVICE) < 0) { while (i > 0) fore200e_chunk_free(fore200e, &buffer[ --i ].data); @@ -2485,7 +2498,8 @@ DPRINTK(2, "device %s being registered\n", fore200e->name); - atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0); + atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, + NULL); if (atm_dev == NULL) { printk(FORE200E "unable to register device %s\n", fore200e->name); return -ENODEV; @@ -2690,17 +2704,29 @@ static const char* oc3_mode[] = { "normal operation", "diagnostic loopback", - "line loopback" + "line loopback", + "unknown" }; u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release); u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release); u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision); u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); + u32 oc3_index; if (media_index < 0 || media_index > 4) media_index = 5; + switch(fore200e->loop_mode) { + case ATM_LM_NONE: oc3_index = 0; + break; + case ATM_LM_LOC_PHY: oc3_index = 1; + break; + case ATM_LM_RMT_PHY: oc3_index = 2; + break; + default: oc3_index = 3; + } + return sprintf(page, " firmware release:\t\t%d.%d.%d\n" " monitor release:\t\t%d.%d\n" @@ -2711,7 +2737,7 @@ mon960_release >> 16, mon960_release << 16 >> 16, media_name[ media_index ], oc3_revision, - oc3_mode[ fore200e->loop_mode ]); + oc3_mode[ oc3_index ]); } if (!left--) { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/fore200e.h linux/drivers/atm/fore200e.h --- v2.3.99-pre2/linux/drivers/atm/fore200e.h Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/fore200e.h Wed Mar 22 22:22:05 2000 @@ -2,6 +2,7 @@ #define _FORE200E_H #ifdef __KERNEL__ +#include /* rx buffer sizes */ @@ -559,6 +560,7 @@ void* alloc_addr; /* base address of allocated chunk */ void* align_addr; /* base address of aligned chunk */ u32 dma_addr; /* DMA address of aligned chunk */ + int direction; /* direction of DMA mapping */ u32 alloc_size; /* length of allocated chunk */ u32 align_size; /* length of aligned chunk */ } chunk_t; @@ -796,9 +798,9 @@ const unsigned int* fw_size; /* address of firmware data size */ u32 (*read)(volatile u32*); void (*write)(u32, volatile u32*); - u32 (*dma_map)(struct fore200e*, void*, int); - void (*dma_unmap)(struct fore200e*, u32, int); - void (*dma_sync)(struct fore200e*, u32, int); + u32 (*dma_map)(struct fore200e*, void*, int, int); + void (*dma_unmap)(struct fore200e*, u32, int, int); + void (*dma_sync)(struct fore200e*, u32, int, int); int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); void (*dma_chunk_free)(struct fore200e*, struct chunk*); struct fore200e* (*detect)(const struct fore200e_bus*, int); @@ -812,6 +814,31 @@ void (*irq_ack)(struct fore200e*); int (*proc_read)(struct fore200e*, char*); } fore200e_bus_t; + + +#if defined(CONFIG_ATM_FORE200E_SBA) +# if defined(CONFIG_ATM_FORE200E_PCA) +# if (PCI_DMA_BIDIRECTIONAL == SBUS_DMA_BIDIRECTIONAL) && \ + (PCI_DMA_TODEVICE == SBUS_DMA_TODEVICE) && \ + (PCI_DMA_FROMDEVICE == SBUS_DMA_FROMDEVICE) +# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE +# else + /* in that case, we'll need to add an extra indirection, e.g. + fore200e->bus->dma_direction[ fore200e_dma_direction ] */ +# error PCI and SBUS DMA direction flags differ! +# endif +# else +# define FORE200E_DMA_BIDIRECTIONAL SBA_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE SBA_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE SBA_DMA_FROMDEVICE +# endif +#else +# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE +#endif /* per-device data */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c --- v2.3.99-pre2/linux/drivers/atm/horizon.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/horizon.c Tue Mar 21 23:38:26 2000 @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -50,7 +51,7 @@ #define maintainer_string "Giuliano Procida at Madge Networks " #define description_string "Madge ATM Horizon [Ultra] driver" -#define version_string "1.2" +#define version_string "1.2.1" static inline void __init show_version (void) { printk ("%s version %s\n", description_string, version_string); @@ -246,7 +247,7 @@ Atomic test and set tx_busy until we succeed; we should implement some sort of timeout so that tx_busy will never be stuck at true. - If no TX channel is setup for this VC we wait for an idle one (if + If no TX channel is set up for this VC we wait for an idle one (if necessary) and set it up. At this point we have a TX channel ready for use. We wait for enough @@ -276,7 +277,7 @@ available handler is locked out over the same period. Data available on the card triggers an interrupt. If the data is not - suitable for out existing RX channels or we cannot allocate a buffer + suitable for our existing RX channels or we cannot allocate a buffer it is flushed. Otherwise an RX receive is scheduled. Multiple RX transfers may be scheduled for the same frame. @@ -321,7 +322,7 @@ and the frame continues to be received. The solution is to make sure any received frames are flushed when - ready. This is currently done just before the solution to 3. + ready. This is currently done just before the solution to 2. 4. PCI bus (original Horizon only, fixed in Ultra) @@ -608,7 +609,7 @@ u32 pre; // local fn to build the timer bits - inline int set_cr (void) { + int set_cr (void) { // paranoia if (div > CR_MAXD || (!pre) || pre > 1<vcc->pop) { ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb); } else { - dev_kfree_skb (skb); + dev_kfree_skb_any (skb); } } @@ -961,12 +962,11 @@ static void rx_schedule (hrz_dev * dev, int irq) { unsigned int rx_bytes; - int pio_instead; + int pio_instead = 0; #ifndef TAILRECURSIONWORKS - do { + pio_instead = 1; + while (pio_instead) { #endif - pio_instead = 0; - // bytes waiting for RX transfer rx_bytes = dev->rx_bytes; @@ -1047,7 +1047,7 @@ { struct atm_vcc * vcc = ATM_SKB(skb)->vcc; // VC layer stats - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); skb->stamp = xtime; // end of our responsability vcc->push (vcc, skb); @@ -1078,12 +1078,12 @@ #ifdef TAILRECURSIONWORKS // and we all bless optimised tail calls if (pio_instead) - rx_schedule (dev, 0); + return rx_schedule (dev, 0); return; #else // grrrrrrr! irq = 0; - } while (pio_instead); + } return; #endif } @@ -1130,11 +1130,11 @@ int append_desc = 0; - int pio_instead; + int pio_instead = 0; #ifndef TAILRECURSIONWORKS - do { + pio_instead = 1; + while (pio_instead) { #endif - pio_instead = 0; // bytes in current region waiting for TX transfer tx_bytes = dev->tx_bytes; @@ -1201,7 +1201,7 @@ dev->tx_iovec = 0; // VC layer stats - ATM_SKB(skb)->vcc->stats->tx++; + atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); // free the skb hrz_kfree_skb (skb); @@ -1236,12 +1236,12 @@ #ifdef TAILRECURSIONWORKS // and we all bless optimised tail calls if (pio_instead) - tx_schedule (dev, 0); + return tx_schedule (dev, 0); return; #else // grrrrrrr! irq = 0; - } while (pio_instead); + } return; #endif } @@ -1340,37 +1340,33 @@ if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { if (rx_len <= atm_vcc->qos.rxtp.max_sdu) { - struct sk_buff *skb = atm_alloc_charge(atm_vcc,rx_len,GFP_ATOMIC); - - // If everyone has to call atm_pdu2... why isn't it part of - // atm_charge? B'cos some people already have skb->truesize! - // WA: well. even if they think they do, they might not ... :-) - - if (skb) { - // remember this so we can push it later - dev->rx_skb = skb; - // remember this so we can flush it later - dev->rx_channel = rx_channel; - - // prepare socket buffer - skb_put (skb, rx_len); - ATM_SKB(skb)->vcc = atm_vcc; - - // simple transfer - // dev->rx_regions = 0; - // dev->rx_iovec = 0; - dev->rx_bytes = rx_len; - dev->rx_addr = skb->data; - PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)", - skb->data, rx_len); - - // do the business - rx_schedule (dev, 0); - return; - - } else { - PRINTD (DBG_INFO, "failed to get skb"); - } + + struct sk_buff * skb = atm_alloc_charge (atm_vcc, rx_len, GFP_ATOMIC); + if (skb) { + // remember this so we can push it later + dev->rx_skb = skb; + // remember this so we can flush it later + dev->rx_channel = rx_channel; + + // prepare socket buffer + skb_put (skb, rx_len); + ATM_SKB(skb)->vcc = atm_vcc; + + // simple transfer + // dev->rx_regions = 0; + // dev->rx_iovec = 0; + dev->rx_bytes = rx_len; + dev->rx_addr = skb->data; + PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)", + skb->data, rx_len); + + // do the business + rx_schedule (dev, 0); + return; + + } else { + PRINTD (DBG_SKB|DBG_WARN, "failed to get skb"); + } } else { PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel); @@ -1662,6 +1658,7 @@ if (!channel) { PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel"); + hrz_kfree_skb (skb); return -EIO; } @@ -1699,9 +1696,11 @@ #endif // wait until TX is free and grab lock - if (tx_hold (dev)) + if (tx_hold (dev)) { + hrz_kfree_skb (skb); return -ERESTARTSYS; - + } + // Wait for enough space to be available in transmit buffer memory. // should be number of cells needed + 2 (according to hardware docs) @@ -1722,6 +1721,7 @@ PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d", free_buffers, buffers_required); tx_release (dev); + hrz_kfree_skb (skb); return -ERESTARTSYS; } } @@ -1820,12 +1820,12 @@ u32 ctrl = rd_regl (dev, CONTROL_0_REG); - inline void WRITE_IT_WAIT (void) { + void WRITE_IT_WAIT (void) { wr_regl (dev, CONTROL_0_REG, ctrl); udelay (5); } - inline void CLOCK_IT (void) { + void CLOCK_IT (void) { // DI must be valid around rising SK edge ctrl &= ~SEEPROM_SK; WRITE_IT_WAIT(); @@ -2530,7 +2530,7 @@ // this is "immediately before allocating the connection identifier // in hardware" - so long as the next call does not fail :) - atm_vcc->flags |= ATM_VF_ADDR; + set_bit(ATM_VF_ADDR,&atm_vcc->flags); // any errors here are very serious and should never occur @@ -2554,7 +2554,7 @@ atm_vcc->dev_data = (void *) vccp; // indicate readiness - atm_vcc->flags |= ATM_VF_READY; + set_bit(ATM_VF_READY,&atm_vcc->flags); MOD_INC_USE_COUNT; return 0; @@ -2569,7 +2569,7 @@ PRINTD (DBG_VCC|DBG_FLOW, "hrz_close"); // indicate unreadiness - atm_vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&atm_vcc->flags); if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) { unsigned int i; @@ -2611,7 +2611,7 @@ // free our structure kfree (vcc); // say the VPI/VCI is free again - atm_vcc->flags &= ~ATM_VF_ADDR; + clear_bit(ATM_VF_ADDR,&atm_vcc->flags); MOD_DEC_USE_COUNT; } @@ -2758,13 +2758,13 @@ devs = 0; pci_dev = NULL; while ((pci_dev = pci_find_device - (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev) - )) { + (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev) + )) { hrz_dev * dev; // adapter slot free, read resources from PCI configuration space u32 iobase = pci_dev->resource[0].start; - u32 * membase = bus_to_virt(pci_dev->resource[1].start); + u32 * membase = bus_to_virt (pci_dev->resource[1].start); u8 irq = pci_dev->irq; // check IO region @@ -2795,7 +2795,7 @@ PRINTD (DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p", iobase, irq, membase); - dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0); + dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, NULL); if (!(dev->atm_dev)) { PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); } else { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/horizon.h linux/drivers/atm/horizon.h --- v2.3.99-pre2/linux/drivers/atm/horizon.h Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/horizon.h Tue Mar 21 23:38:26 2000 @@ -31,9 +31,7 @@ #define DRIVER_ATM_HORIZON_H #include - #include - #ifdef CONFIG_ATM_HORIZON_DEBUG #define DEBUG_HORIZON diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/idt77105.c linux/drivers/atm/idt77105.c --- v2.3.99-pre2/linux/drivers/atm/idt77105.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/idt77105.c Tue Mar 21 23:38:26 2000 @@ -157,36 +157,54 @@ } +static int set_loopback(struct atm_dev *dev,int mode) +{ + int diag; + + diag = GET(DIAG) & ~IDT77105_DIAG_LCMASK; + switch (mode) { + case ATM_LM_NONE: + break; + case ATM_LM_LOC_ATM: + diag |= IDT77105_DIAG_LC_PHY_LOOPBACK; + break; + case ATM_LM_RMT_ATM: + diag |= IDT77105_DIAG_LC_LINE_LOOPBACK; + break; + default: + return -EINVAL; + } + PUT(diag,DIAG); + printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", dev->type, + dev->number, + (mode == ATM_LM_NONE ? "NONE" : + (mode == ATM_LM_LOC_ATM ? "DIAG (local)" : + (mode == IDT77105_DIAG_LC_LINE_LOOPBACK ? "LOOP (remote)" : + "unknown"))) + ); + PRIV(dev)->loop_mode = mode; + return 0; +} + static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) { printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number); switch (cmd) { case IDT77105_GETSTATZ: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + /* fall through */ case IDT77105_GETSTAT: return fetch_stats(dev,(struct idt77105_stats *) arg, cmd == IDT77105_GETSTATZ); - case IDT77105_SETLOOP: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if ((int) arg < 0 || (int) arg > IDT77105_LM_LOOP) - return -EINVAL; - PUT((GET(DIAG) & ~IDT77105_DIAG_LCMASK) | - ((int) arg == IDT77105_LM_NONE ? IDT77105_DIAG_LC_NORMAL : 0) | - ((int) arg == IDT77105_LM_DIAG ? IDT77105_DIAG_LC_PHY_LOOPBACK : 0) | - ((int) arg == IDT77105_LM_LOOP ? IDT77105_DIAG_LC_LINE_LOOPBACK : 0), - DIAG); - printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", - dev->type, dev->number, - ((int) arg == IDT77105_LM_NONE ? "NONE" : - ((int) arg == IDT77105_LM_DIAG ? "DIAG (local)" : - ((int) arg == IDT77105_LM_LOOP ? "LOOP (remote)" : - "unknown"))) - ); - PRIV(dev)->loop_mode = (int) arg; - return 0; - case IDT77105_GETLOOP: + case ATM_SETLOOP: + return set_loopback(dev,(int) (long) arg); + case ATM_GETLOOP: return put_user(PRIV(dev)->loop_mode,(int *) arg) ? - -EFAULT : sizeof(int); + -EFAULT : 0; + case ATM_QUERYLOOP: + return put_user(ATM_LM_LOC_ATM | ATM_LM_RMT_ATM, + (int *) arg) ? -EFAULT : 0; default: return -ENOIOCTLCMD; } @@ -266,13 +284,13 @@ /* initialise loop mode from hardware */ switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) { case IDT77105_DIAG_LC_NORMAL: - PRIV(dev)->loop_mode = IDT77105_LM_NONE; + PRIV(dev)->loop_mode = ATM_LM_NONE; break; case IDT77105_DIAG_LC_PHY_LOOPBACK: - PRIV(dev)->loop_mode = IDT77105_LM_DIAG; + PRIV(dev)->loop_mode = ATM_LM_LOC_ATM; break; case IDT77105_DIAG_LC_LINE_LOOPBACK: - PRIV(dev)->loop_mode = IDT77105_LM_LOOP; + PRIV(dev)->loop_mode = ATM_LM_RMT_ATM; break; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/iphase.c linux/drivers/atm/iphase.c --- v2.3.99-pre2/linux/drivers/atm/iphase.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/iphase.c Tue Mar 21 23:38:26 2000 @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,7 @@ #include "suni.h" #define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) struct suni_priv { - struct sonet_stats sonet_stats; /* link diagnostics */ + struct k_sonet_stats sonet_stats; /* link diagnostics */ unsigned char loop_mode; /* loopback mode */ struct atm_dev *dev; /* device back-pointer */ struct suni_priv *next; /* next SUNI */ @@ -625,12 +626,12 @@ num_desc = ia_avail_descs(iadev); while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) { if (!(vcc = ATM_SKB(skb)->vcc)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); printk("ia_que_tx: Null vcc\n"); break; } - if ((vcc->flags & ATM_VF_READY) == 0 ) { - dev_kfree_skb(skb); + if (!test_bit(ATM_VF_READY,&vcc->flags)) { + dev_kfree_skb_any(skb); printk("Free the SKB on closed vci %d \n", vcc->vci); break; } @@ -658,14 +659,14 @@ vcc = ATM_SKB(skb)->vcc; if (!vcc) { printk("ia_tx_poll: vcc is null\n"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return; } iavcc = INPH_IA_VCC(vcc); if (!iavcc) { printk("ia_tx_poll: iavcc is null\n"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return; } @@ -682,7 +683,7 @@ (long)skb1);) } else - dev_kfree_skb(skb1); + dev_kfree_skb_any(skb1); skb1 = skb_dequeue(&iavcc->txing_skb); } if (!skb1) { @@ -696,7 +697,7 @@ IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);) } else - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); kfree(rtne); } ia_que_tx(iadev); @@ -1128,7 +1129,7 @@ status = (u_short) (buf_desc_ptr->desc_mode); if (status & (RX_CER | RX_PTE | RX_OFL)) { - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); IF_ERR(printk("IA: bad packet, dropping it");) if (status & RX_CER) { IF_ERR(printk(" cause: packet CRC error\n");) @@ -1152,7 +1153,7 @@ len = dma_addr - buf_addr; if (len > iadev->rx_buf_sz) { printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz); - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); free_desc(dev, desc); return 0; } @@ -1166,7 +1167,7 @@ if (!skb) { IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");) - vcc->stats->rx_drop++; + atomic_inc(&vcc->stats->rx_drop); atm_return(vcc, atm_pdu2truesize(len)); free_desc(dev, desc); return 0; @@ -1297,7 +1298,7 @@ if (!skb->len) { printk("rx_dle_intr: skb len 0\n"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } else { @@ -1308,15 +1309,15 @@ vcc = ATM_SKB(skb)->vcc; if (!vcc) { printk("IA: null vcc\n"); - vcc->stats->rx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->rx_err); + dev_kfree_skb_any(skb); goto INCR_DLE; } ia_vcc = INPH_IA_VCC(vcc); if (ia_vcc == NULL) { - vcc->stats->rx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->rx_err); + dev_kfree_skb_any(skb); #if LINUX_VERSION_CODE >= 0x20312 atm_return(vcc, atm_guess_pdu2truesize(skb->len)); #else @@ -1331,8 +1332,8 @@ if ((length > iadev->rx_buf_sz) || (length > (skb->len - sizeof(struct cpcs_trailer)))) { - vcc->stats->rx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->rx_err); + dev_kfree_skb_any(skb); IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)", length, skb->len);) #if LINUX_VERSION_CODE >= 0x20312 @@ -1351,7 +1352,7 @@ IF_RX(printk("rx_dle_intr: skb push");) vcc->push(vcc,skb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); iadev->rx_pkt_cnt++; } INCR_DLE: @@ -1710,13 +1711,13 @@ vcc = ATM_SKB(skb)->vcc; if (!vcc) { printk("tx_dle_intr: vcc is null\n"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return; } iavcc = INPH_IA_VCC(vcc); if (!iavcc) { printk("tx_dle_intr: iavcc is null\n"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return; } if (vcc->qos.txtp.pcr >= iadev->rate_limit) { @@ -1725,7 +1726,7 @@ vcc->pop(vcc, skb); } else { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } } else { /* Hold the rate-limited skb for flow control */ @@ -2601,7 +2602,7 @@ IF_EVENT(printk("ia_close: ia_vcc->vc_desc_cnt = %d vci = %d\n", ia_vcc->vc_desc_cnt,vcc->vci);) - vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&vcc->flags); skb_queue_head_init (&tmp_tx_backlog); skb_queue_head_init (&tmp_vcc_backlog); if (vcc->qos.txtp.traffic_class != ATM_NONE) { @@ -2611,7 +2612,7 @@ while((skb = skb_dequeue(&iadev->tx_backlog))) { if (ATM_SKB(skb)->vcc == vcc){ if (vcc->pop) vcc->pop(vcc, skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_any(skb); } else skb_queue_tail(&tmp_tx_backlog, skb); @@ -2669,7 +2670,7 @@ kfree(INPH_IA_VCC(vcc)); ia_vcc = NULL; INPH_IA_VCC(vcc) = NULL; - vcc->flags &= ~ATM_VF_ADDR; + clear_bit(ATM_VF_ADDR,&vcc->flags); return; } @@ -2678,7 +2679,7 @@ IADEV *iadev; struct ia_vcc *ia_vcc; int error; - if (!(vcc->flags & ATM_VF_PARTIAL)) + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { IF_EVENT(printk("ia: not partially allocated resources\n");) INPH_IA_VCC(vcc) = NULL; @@ -2695,7 +2696,7 @@ if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) { IF_EVENT(printk("iphase open: unspec part\n");) - vcc->flags |= ATM_VF_ADDR; + set_bit(ATM_VF_ADDR,&vcc->flags); } if (vcc->qos.aal != ATM_AAL5) return -EINVAL; @@ -2721,7 +2722,7 @@ return error; } - vcc->flags |= ATM_VF_READY; + set_bit(ATM_VF_READY,&vcc->flags); #ifndef MODULE { @@ -2749,7 +2750,7 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) { - PIA_CMDBUF ia_cmds; + IA_CMDBUF ia_cmds; IADEV *iadev; int i, board; u16 *tmps; @@ -2757,34 +2758,37 @@ if (cmd != IA_CMD) { if (!dev->phy->ioctl) return -EINVAL; return dev->phy->ioctl(dev,cmd,arg); - } - ia_cmds = (PIA_CMDBUF)arg; - board = ia_cmds->status; + } + if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT; + board = ia_cmds.status; if ((board < 0) || (board > iadev_count)) board = 0; iadev = ia_dev[board]; - switch (ia_cmds->cmd) { + switch (ia_cmds.cmd) { case MEMDUMP: { - switch (ia_cmds->sub_cmd) { + switch (ia_cmds.sub_cmd) { case MEMDUMP_DEV: - memcpy((char*)ia_cmds->buf, (char*)iadev, - sizeof(IADEV)); - ia_cmds->status = 0; + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (copy_to_user(ia_cmds.buf, iadev, sizeof(IADEV))) + return -EFAULT; + ia_cmds.status = 0; break; case MEMDUMP_SEGREG: - tmps = (u16 *)ia_cmds->buf; + if (!capable(CAP_NET_ADMIN)) return -EPERM; + tmps = (u16 *)ia_cmds.buf; for(i=0; i<0x80; i+=2, tmps++) - *tmps = *(u16*)(iadev->seg_reg+i); - ia_cmds->status = 0; - ia_cmds->len = 0x80; + if(put_user(*(u16*)(iadev->seg_reg+i), tmps)) return -EFAULT; + ia_cmds.status = 0; + ia_cmds.len = 0x80; break; case MEMDUMP_REASSREG: - tmps = (u16 *)ia_cmds->buf; + if (!capable(CAP_NET_ADMIN)) return -EPERM; + tmps = (u16 *)ia_cmds.buf; for(i=0; i<0x80; i+=2, tmps++) - *tmps = *(u16*)(iadev->reass_reg+i); - ia_cmds->status = 0; - ia_cmds->len = 0x80; + if(put_user(*(u16*)(iadev->reass_reg+i), tmps)) return -EFAULT; + ia_cmds.status = 0; + ia_cmds.len = 0x80; break; case MEMDUMP_FFL: { @@ -2792,6 +2796,7 @@ ffredn_t *ffL = ®s_local.ffredn; rfredn_t *rfL = ®s_local.rfredn; + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* Copy real rfred registers into the local copy */ for (i=0; i<(sizeof (rfredn_t))/4; i++) ((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff; @@ -2799,63 +2804,67 @@ for (i=0; i<(sizeof (ffredn_t))/4; i++) ((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff; - memcpy((char*)ia_cmds->buf,(char*)®s_local,sizeof(ia_regs_t)); + if (copy_to_user(ia_cmds.buf, ®s_local,sizeof(ia_regs_t))) + return -EFAULT; printk("Board %d registers dumped\n", board); - ia_cmds->status = 0; + ia_cmds.status = 0; } break; case READ_REG: { + if (!capable(CAP_NET_ADMIN)) return -EPERM; desc_dbg(iadev); - ia_cmds->status = 0; + ia_cmds.status = 0; } break; case 0x6: { - ia_cmds->status = 0; + ia_cmds.status = 0; printk("skb = 0x%lx\n", (long)skb_peek(&iadev->tx_backlog)); printk("rtn_q: 0x%lx\n",(long)ia_deque_rtn_q(&iadev->tx_return_q)); } break; case 0x8: { - struct sonet_stats *stats; + struct k_sonet_stats *stats; stats = &PRIV(_ia_dev[board])->sonet_stats; - printk("section_bip: %d\n", stats->section_bip); - printk("line_bip : %d\n", stats->line_bip); - printk("path_bip : %d\n", stats->path_bip); - printk("line_febe : %d\n", stats->line_febe); - printk("path_febe : %d\n", stats->path_febe); - printk("corr_hcs : %d\n", stats->corr_hcs); - printk("uncorr_hcs : %d\n", stats->uncorr_hcs); - printk("tx_cells : %d\n", stats->tx_cells); - printk("rx_cells : %d\n", stats->rx_cells); + printk("section_bip: %d\n", atomic_read(&stats->section_bip)); + printk("line_bip : %d\n", atomic_read(&stats->line_bip)); + printk("path_bip : %d\n", atomic_read(&stats->path_bip)); + printk("line_febe : %d\n", atomic_read(&stats->line_febe)); + printk("path_febe : %d\n", atomic_read(&stats->path_febe)); + printk("corr_hcs : %d\n", atomic_read(&stats->corr_hcs)); + printk("uncorr_hcs : %d\n", atomic_read(&stats->uncorr_hcs)); + printk("tx_cells : %d\n", atomic_read(&stats->tx_cells)); + printk("rx_cells : %d\n", atomic_read(&stats->rx_cells)); } - ia_cmds->status = 0; + ia_cmds.status = 0; break; case 0x9: + if (!capable(CAP_NET_ADMIN)) return -EPERM; for (i = 1; i <= iadev->num_rx_desc; i++) free_desc(_ia_dev[board], i); writew( ~(RX_FREEQ_EMPT | RX_EXCP_RCVD), iadev->reass_reg+REASS_MASK_REG); iadev->rxing = 1; - ia_cmds->status = 0; + ia_cmds.status = 0; break; case 0xb: + if (!capable(CAP_NET_ADMIN)) return -EPERM; IaFrontEndIntr(iadev); break; case 0xa: + if (!capable(CAP_NET_ADMIN)) return -EPERM; { - ia_cmds->status = 0; - IADebugFlag = ia_cmds->maddr; + ia_cmds.status = 0; + IADebugFlag = ia_cmds.maddr; printk("New debug option loaded\n"); } break; default: - memcpy((char*)ia_cmds->buf, (char*)ia_cmds->maddr, ia_cmds->len); - ia_cmds->status = 0; + ia_cmds.status = 0; break; } } @@ -2896,7 +2905,7 @@ if (!iavcc->txing) { printk("discard packet on closed VC\n"); if (vcc->pop) vcc->pop(vcc, skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_any(skb); } if (skb->len > iadev->tx_buf_sz - 8) { @@ -2904,7 +2913,7 @@ if (vcc->pop) vcc->pop(vcc, skb); else - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return 0; } if ((u32)skb->data & 3) { @@ -2912,7 +2921,7 @@ if (vcc->pop) vcc->pop(vcc, skb); else - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return 0; } /* Get a descriptor number from our free descriptor queue @@ -2929,11 +2938,11 @@ if ((desc == 0) || (desc > iadev->num_tx_desc)) { IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);) - vcc->stats->tx++; + atomic_inc(&vcc->stats->tx); if (vcc->pop) vcc->pop(vcc, skb); else - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return 0; /* return SUCCESS */ } @@ -3038,14 +3047,14 @@ ATM_DESC(skb) = vcc->vci; skb_queue_tail(&iadev->tx_dma_q, skb); - vcc->stats->tx++; + atomic_inc(&vcc->stats->tx); iadev->tx_pkt_cnt++; /* Increment transaction counter */ writel(2, iadev->dma+IPHASE5575_TX_COUNTER); #if 0 /* add flow control logic */ - if (vcc->stats->tx % 20 == 0) { + if (atomic_read(&vcc->stats->tx) % 20 == 0) { if (iavcc->vc_desc_cnt > 10) { vcc->tx_quota = vcc->tx_quota * 3 / 4; printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); @@ -3074,12 +3083,12 @@ { if (!skb) printk(KERN_CRIT "null skb in ia_send\n"); - else dev_kfree_skb(skb); + else dev_kfree_skb_any(skb); return -EINVAL; } spin_lock_irqsave(&iadev->tx_lock, flags); - if ((vcc->flags & ATM_VF_READY) == 0){ - dev_kfree_skb(skb); + if (!test_bit(ATM_VF_READY,&vcc->flags)){ + dev_kfree_skb_any(skb); spin_unlock_irqrestore(&iadev->tx_lock, flags); return -EINVAL; } @@ -3197,7 +3206,7 @@ IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n", iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn), PCI_FUNC(iadev->pci->devfn));) - dev = atm_dev_register(DEV_LABEL, &ops, -1, 0); + dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL); if (!dev) break; IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c --- v2.3.99-pre2/linux/drivers/atm/nicstar.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/nicstar.c Tue Mar 21 23:38:26 2000 @@ -37,8 +37,10 @@ #include #include #include +#include #include #include +#include #include "nicstar.h" #include "nicstarmac.h" #ifdef CONFIG_ATM_NICSTAR_USE_SUNI @@ -284,7 +286,7 @@ card = cards[i]; #ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 - if (card->max_pcr == IDT_25_PCR) { + if (card->max_pcr == ATM_25_PCR) { idt77105_stop(card->atmdev); } #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ @@ -311,7 +313,7 @@ PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) { - kfree_skb(hb); + dev_kfree_skb_any(hb); j++; } PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); @@ -319,14 +321,14 @@ PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count); while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) { - kfree_skb(iovb); + dev_kfree_skb_any(iovb); j++; } PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) - kfree_skb(lb); + dev_kfree_skb_any(lb); while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) - kfree_skb(sb); + dev_kfree_skb_any(sb); free_scq(card->scq0, NULL); for (j = 0; j < NS_FRSCD_NUM; j++) { @@ -547,7 +549,7 @@ switch(data) { case 0x00000009: printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); - card->max_pcr = IDT_25_PCR; + card->max_pcr = ATM_25_PCR; while(CMD_BUSY(card)); writel(0x00000008, card->membase + DR0); writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); @@ -857,7 +859,7 @@ card->efbie = 1; /* Register device */ - card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL); + card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL); if (card->atmdev == NULL) { printk("nicstar%d: can't register device.\n", i); @@ -891,7 +893,7 @@ #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ #ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 - if (card->max_pcr == IDT_25_PCR) { + if (card->max_pcr == ATM_25_PCR) { idt77105_init(card->atmdev); /* Note that for the IDT77105 PHY we don't need the awful * module count hack that the SUNI needs because we can @@ -936,26 +938,26 @@ { struct sk_buff *iovb; while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) - kfree_skb(iovb); + dev_kfree_skb_any(iovb); } if (error >= 15) { struct sk_buff *sb; while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) - kfree_skb(sb); + dev_kfree_skb_any(sb); free_scq(card->scq0, NULL); } if (error >= 14) { struct sk_buff *lb; while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) - kfree_skb(lb); + dev_kfree_skb_any(lb); } if (error >= 13) { struct sk_buff *hb; while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) - kfree_skb(hb); + dev_kfree_skb_any(hb); } if (error >= 12) { @@ -1039,7 +1041,7 @@ if (vcc->pop != NULL) vcc->pop(vcc, scq->skb[i]); else - dev_kfree_skb(scq->skb[i]); + dev_kfree_skb_any(scq->skb[i]); } } else /* vcc must be != NULL */ @@ -1048,7 +1050,7 @@ { printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); for (i = 0; i < scq->num_entries; i++) - dev_kfree_skb(scq->skb[i]); + dev_kfree_skb_any(scq->skb[i]); } else for (i = 0; i < scq->num_entries; i++) @@ -1058,7 +1060,7 @@ if (vcc->pop != NULL) vcc->pop(vcc, scq->skb[i]); else - dev_kfree_skb(scq->skb[i]); + dev_kfree_skb_any(scq->skb[i]); } } } @@ -1130,9 +1132,9 @@ if (card->sbfqc >= card->sbnr.max) { skb_unlink((struct sk_buff *) handle1); - kfree_skb((struct sk_buff *) handle1); + dev_kfree_skb_any((struct sk_buff *) handle1); skb_unlink((struct sk_buff *) handle2); - kfree_skb((struct sk_buff *) handle2); + dev_kfree_skb_any((struct sk_buff *) handle2); return; } else @@ -1143,9 +1145,9 @@ if (card->lbfqc >= card->lbnr.max) { skb_unlink((struct sk_buff *) handle1); - kfree_skb((struct sk_buff *) handle1); + dev_kfree_skb_any((struct sk_buff *) handle1); skb_unlink((struct sk_buff *) handle2); - kfree_skb((struct sk_buff *) handle2); + dev_kfree_skb_any((struct sk_buff *) handle2); return; } else @@ -1420,16 +1422,16 @@ return -EINVAL; } - vcc->flags |= ATM_VF_ADDR; + set_bit(ATM_VF_ADDR,&vcc->flags); /* NOTE: You are not allowed to modify an open connection's QOS. To change that, remove the ATM_VF_PARTIAL flag checking. There may be other changes needed to do that. */ - if (!(vcc->flags & ATM_VF_PARTIAL)) + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { scq_info *scq; - vcc->flags |= ATM_VF_PARTIAL; + set_bit(ATM_VF_PARTIAL,&vcc->flags); if (vcc->qos.txtp.traffic_class == ATM_CBR) { /* Check requested cell rate and availability of SCD */ @@ -1438,7 +1440,8 @@ { PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } @@ -1461,7 +1464,8 @@ if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0) { PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } } @@ -1469,14 +1473,16 @@ if (n == 0) { printk("nicstar%d: selected bandwidth < granularity.\n", card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } if (n > (card->tst_free_entries - NS_TST_RESERVED)) { PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } else @@ -1495,7 +1501,8 @@ { PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index); card->tst_free_entries += n; - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_ADDR,&vcc->flags); return -EBUSY; } @@ -1507,7 +1514,8 @@ PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index); card->scd2vc[frscdi] = NULL; card->tst_free_entries += n; - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_ADDR,&vcc->flags); return -ENOMEM; } vc->scq = scq; @@ -1553,7 +1561,7 @@ } - vcc->flags |= ATM_VF_READY; + set_bit(ATM_VF_READY,&vcc->flags); MOD_INC_USE_COUNT; return 0; } @@ -1572,7 +1580,7 @@ PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, (int) vcc->vpi, vcc->vci); - vcc->flags &= ~(ATM_VF_READY); + clear_bit(ATM_VF_READY,&vcc->flags); if (vcc->qos.rxtp.traffic_class != ATM_NONE) { @@ -1681,7 +1689,8 @@ } vcc->dev_data = NULL; - vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + clear_bit(ATM_VF_ADDR,&vcc->flags); MOD_DEC_USE_COUNT; #ifdef RX_DEBUG @@ -1778,32 +1787,32 @@ if ((vc = (vc_map *) vcc->dev_data) == NULL) { printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb_any(skb); return -EINVAL; } if (!vc->tx) { printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb_any(skb); return -EINVAL; } if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb_any(skb); return -EINVAL; } if (ATM_SKB(skb)->iovcnt != 0) { printk("nicstar%d: No scatter-gather yet.\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb_any(skb); return -EINVAL; } @@ -1847,11 +1856,11 @@ if (push_scqe(card, vc, scq, &scqe, skb) != 0) { - vcc->stats->tx_err++; - dev_kfree_skb(skb); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb_any(skb); return -EIO; } - vcc->stats->tx++; + atomic_inc(&vcc->stats->tx); return 0; } @@ -2071,7 +2080,7 @@ if (vcc->pop != NULL) vcc->pop(vcc, skb); else - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); scq->skb[i] = NULL; } if (++i == scq->num_entries) @@ -2155,15 +2164,15 @@ { printk("nicstar%d: Can't allocate buffers for aal0.\n", card->index); - vcc->stats->rx_drop += i; + atomic_add(i,&vcc->stats->rx_drop); break; } if (!atm_charge(vcc, sb->truesize)) { RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n", card->index); - vcc->stats->rx_drop += i - 1; /* already increased by 1 */ - kfree_skb(sb); + atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */ + dev_kfree_skb_any(sb); break; } /* Rebuild the header */ @@ -2177,7 +2186,7 @@ ATM_SKB(sb)->vcc = vcc; sb->stamp = xtime; vcc->push(vcc, sb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); cell += ATM_CELL_PAYLOAD; } @@ -2196,7 +2205,7 @@ if (iovb == NULL) { printk("nicstar%d: Out of iovec buffers.\n", card->index); - vcc->stats->rx_drop++; + atomic_inc(&vcc->stats->rx_drop); recycle_rx_buf(card, skb); return; } @@ -2223,7 +2232,7 @@ else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS) { printk("nicstar%d: received too big AAL5 SDU.\n", card->index); - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); ATM_SKB(iovb)->iovcnt = 0; iovb->len = 0; @@ -2242,7 +2251,7 @@ printk("nicstar%d: Expected a small buffer, and this is not one.\n", card->index); which_list(card, skb); - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); recycle_rx_buf(card, skb); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); @@ -2256,7 +2265,7 @@ printk("nicstar%d: Expected a large buffer, and this is not one.\n", card->index); which_list(card, skb); - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, ATM_SKB(iovb)->iovcnt); vc->rx_iov = NULL; @@ -2280,7 +2289,7 @@ printk(" - PDU size mismatch.\n"); else printk(".\n"); - vcc->stats->rx_err++; + atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, ATM_SKB(iovb)->iovcnt); vc->rx_iov = NULL; @@ -2308,7 +2317,7 @@ ATM_SKB(skb)->vcc = vcc; skb->stamp = xtime; vcc->push(vcc, skb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); } } else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */ @@ -2335,7 +2344,7 @@ ATM_SKB(sb)->vcc = vcc; sb->stamp = xtime; vcc->push(vcc, sb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); } push_rxbufs(card, BUF_LG, (u32) skb, @@ -2361,7 +2370,7 @@ ATM_SKB(skb)->vcc = vcc; skb->stamp = xtime; vcc->push(vcc, skb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); } push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), @@ -2384,7 +2393,7 @@ if (hb == NULL) { printk("nicstar%d: Out of huge buffers.\n", card->index); - vcc->stats->rx_drop++; + atomic_inc(&vcc->stats->rx_drop); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, ATM_SKB(iovb)->iovcnt); vc->rx_iov = NULL; @@ -2431,7 +2440,7 @@ card->hbpool.count++; } else - kfree_skb(hb); + dev_kfree_skb_any(hb); } else { @@ -2467,7 +2476,7 @@ #endif /* NS_USE_DESTRUCTORS */ hb->stamp = xtime; vcc->push(vcc, hb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); } } @@ -2556,7 +2565,7 @@ else { printk("nicstar%d: What kind of rx buffer is this?\n", card->index); - kfree_skb(skb); + dev_kfree_skb_any(skb); } } @@ -2578,7 +2587,7 @@ else { printk("nicstar%d: What kind of rx buffer is this?\n", card->index); - kfree_skb(skb); + dev_kfree_skb_any(skb); } } } @@ -2593,7 +2602,7 @@ card->iovpool.count++; } else - kfree_skb(iovb); + dev_kfree_skb_any(iovb); } @@ -2700,7 +2709,7 @@ /* Dump 25.6 Mbps PHY registers */ /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it here just in case it's needed for debugging. */ - if (card->max_pcr == IDT_25_PCR && !left--) + if (card->max_pcr == ATM_25_PCR && !left--) { u32 phy_regs[4]; u32 i; @@ -2787,7 +2796,7 @@ return -EFAULT; case NS_SETBUFLEV: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl))) return -EFAULT; @@ -2836,7 +2845,7 @@ return 0; case NS_ADJBUFLEV: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; btype = (int) arg; /* an int is the same size as a pointer */ switch (btype) @@ -2882,7 +2891,7 @@ printk("nicstar%d: huge buffer count inconsistent.\n", card->index); else - kfree_skb(hb); + dev_kfree_skb_any(hb); } while (card->hbpool.count < card->hbnr.init) @@ -2912,7 +2921,7 @@ printk("nicstar%d: iovec buffer count inconsistent.\n", card->index); else - kfree_skb(iovb); + dev_kfree_skb_any(iovb); } while (card->iovpool.count < card->iovnr.init) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/nicstar.h linux/drivers/atm/nicstar.h --- v2.3.99-pre2/linux/drivers/atm/nicstar.h Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/nicstar.h Tue Mar 21 23:38:26 2000 @@ -100,8 +100,6 @@ #define NS_IOREMAP_SIZE 4096 -#define IDT_25_PCR ((25600000 / 8 - 8000) / 54) - #define BUF_SM 0x00000000 /* These two are used for push_rxbufs() */ #define BUF_LG 0x00000001 /* CMD, Write_FreeBufQ, LBUF bit */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/suni.c linux/drivers/atm/suni.c --- v2.3.99-pre2/linux/drivers/atm/suni.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/suni.c Tue Mar 21 23:38:26 2000 @@ -1,4 +1,4 @@ -/* drivers/atm/suni.c - PMC SUNI (PHY) driver */ +/* drivers/atm/suni.c - PMC PM5346 SUNI (PHY) driver */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ @@ -18,6 +18,7 @@ #include #include #include +#include #include "suni.h" @@ -30,8 +31,8 @@ struct suni_priv { - struct sonet_stats sonet_stats; /* link diagnostics */ - unsigned char loop_mode; /* loopback mode */ + struct k_sonet_stats sonet_stats; /* link diagnostics */ + int loop_mode; /* loopback mode */ struct atm_dev *dev; /* device back-pointer */ struct suni_priv *next; /* next SUNI */ }; @@ -46,69 +47,62 @@ static struct timer_list poll_timer; -static int start_timer = 1; static struct suni_priv *sunis = NULL; +static spinlock_t sunis_lock = SPIN_LOCK_UNLOCKED; -static void suni_hz(unsigned long dummy) +#define ADD_LIMITED(s,v) \ + atomic_add((v),&stats->s); \ + if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX); + + +static void suni_hz(unsigned long from_timer) { struct suni_priv *walk; struct atm_dev *dev; - struct sonet_stats *stats; + struct k_sonet_stats *stats; for (walk = sunis; walk; walk = walk->next) { dev = walk->dev; stats = &walk->sonet_stats; PUT(0,MRI); /* latch counters */ udelay(1); - stats->section_bip += (GET(RSOP_SBL) & 0xff) | - ((GET(RSOP_SBM) & 0xff) << 8); - if (stats->section_bip < 0) stats->section_bip = LONG_MAX; - stats->line_bip += (GET(RLOP_LBL) & 0xff) | + ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) | + ((GET(RSOP_SBM) & 0xff) << 8)); + ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) | ((GET(RLOP_LB) & 0xff) << 8) | - ((GET(RLOP_LBM) & 0xf) << 16); - if (stats->line_bip < 0) stats->line_bip = LONG_MAX; - stats->path_bip += (GET(RPOP_PBL) & 0xff) | - ((GET(RPOP_PBM) & 0xff) << 8); - if (stats->path_bip < 0) stats->path_bip = LONG_MAX; - stats->line_febe += (GET(RLOP_LFL) & 0xff) | + ((GET(RLOP_LBM) & 0xf) << 16)); + ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) | + ((GET(RPOP_PBM) & 0xff) << 8)); + ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) | ((GET(RLOP_LF) & 0xff) << 8) | - ((GET(RLOP_LFM) & 0xf) << 16); - if (stats->line_febe < 0) stats->line_febe = LONG_MAX; - stats->path_febe += (GET(RPOP_PFL) & 0xff) | - ((GET(RPOP_PFM) & 0xff) << 8); - if (stats->path_febe < 0) stats->path_febe = LONG_MAX; - stats->corr_hcs += GET(RACP_CHEC) & 0xff; - if (stats->corr_hcs < 0) stats->corr_hcs = LONG_MAX; - stats->uncorr_hcs += GET(RACP_UHEC) & 0xff; - if (stats->uncorr_hcs < 0) stats->uncorr_hcs = LONG_MAX; - stats->rx_cells += (GET(RACP_RCCL) & 0xff) | + ((GET(RLOP_LFM) & 0xf) << 16)); + ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) | + ((GET(RPOP_PFM) & 0xff) << 8)); + ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff); + ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff); + ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) | ((GET(RACP_RCC) & 0xff) << 8) | - ((GET(RACP_RCCM) & 7) << 16); - if (stats->rx_cells < 0) stats->rx_cells = LONG_MAX; - stats->tx_cells += (GET(TACP_TCCL) & 0xff) | + ((GET(RACP_RCCM) & 7) << 16)); + ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) | ((GET(TACP_TCC) & 0xff) << 8) | - ((GET(TACP_TCCM) & 7) << 16); - if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX; + ((GET(TACP_TCCM) & 7) << 16)); } - if (!start_timer) mod_timer(&poll_timer,jiffies+HZ); + if (from_timer) mod_timer(&poll_timer,jiffies+HZ); } +#undef ADD_LIMITED + + static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) { - unsigned long flags; - int error; + struct sonet_stats tmp; + int error = 0; - error = 0; - save_flags(flags); - cli(); - if (arg) - error = copy_to_user(arg,&PRIV(dev)->sonet_stats, - sizeof(struct sonet_stats)); - if (zero && !error) - memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); - restore_flags(flags); + sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp); + if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); + if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp); return error ? -EFAULT : 0; } @@ -158,6 +152,29 @@ } +static int set_loopback(struct atm_dev *dev,int mode) +{ + unsigned char control; + + control = GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE); + switch (mode) { + case ATM_LM_NONE: + break; + case ATM_LM_LOC_PHY: + control |= SUNI_MCT_DLE; + break; + case ATM_LM_RMT_PHY: + control |= SUNI_MCT_LLE; + break; + default: + return -EINVAL; + } + PUT(control,MCT); + PRIV(dev)->loop_mode = mode; + return 0; +} + + static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) { switch (cmd) { @@ -172,7 +189,6 @@ case SONET_GETDIAG: return get_diag(dev,arg); case SONET_SETFRAMING: - if (!capable(CAP_NET_ADMIN)) return -EPERM; if (arg != SONET_FRAME_SONET) return -EINVAL; return 0; case SONET_GETFRAMING: @@ -180,23 +196,14 @@ -EFAULT : 0; case SONET_GETFRSENSE: return -EINVAL; - case SUNI_SETLOOP: - { - int int_arg = (int) (long) arg; - - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (int_arg < 0 || int_arg > SUNI_LM_LOOP) - return -EINVAL; - PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE)) - | (int_arg == SUNI_LM_DIAG ? SUNI_MCT_DLE : - 0) | (int_arg == SUNI_LM_LOOP ? - SUNI_MCT_LLE : 0),MCT); - PRIV(dev)->loop_mode = int_arg; - return 0; - } - case SUNI_GETLOOP: + case ATM_SETLOOP: + return set_loopback(dev,(int) (long) arg); + case ATM_GETLOOP: return put_user(PRIV(dev)->loop_mode,(int *) arg) ? -EFAULT : 0; + case ATM_QUERYLOOP: + return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, + (int *) arg) ? -EFAULT : 0; default: return -ENOIOCTLCMD; } @@ -221,33 +228,31 @@ static int suni_start(struct atm_dev *dev) { unsigned long flags; + int first; if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) return -ENOMEM; PRIV(dev)->dev = dev; - save_flags(flags); - cli(); + spin_lock_irqsave(&sunis_lock,flags); + first = !sunis; PRIV(dev)->next = sunis; sunis = PRIV(dev); - restore_flags(flags); - memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); + spin_unlock_irqrestore(&sunis_lock,flags); + memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats)); PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE); /* interrupt on loss of signal */ poll_los(dev); /* ... and clear SUNI interrupts */ if (dev->signal == ATM_PHY_SIG_LOST) printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type, dev->number); - PRIV(dev)->loop_mode = SUNI_LM_NONE; + PRIV(dev)->loop_mode = ATM_LM_NONE; suni_hz(0); /* clear SUNI counters */ (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ - cli(); - if (!start_timer) restore_flags(flags); - else { - start_timer = 0; - restore_flags(flags); + if (first) { init_timer(&poll_timer); poll_timer.expires = jiffies+HZ; poll_timer.function = suni_hz; + poll_timer.data = 1; #if 0 printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev, (unsigned long) poll_timer.next); @@ -258,10 +263,28 @@ } +static int suni_stop(struct atm_dev *dev) +{ + struct suni_priv **walk; + unsigned long flags; + + /* let SAR driver worry about stopping interrupts */ + spin_lock_irqsave(&sunis_lock,flags); + for (walk = &sunis; *walk != PRIV(dev); + walk = &PRIV((*walk)->dev)->next); + *walk = PRIV((*walk)->dev)->next; + if (!sunis) del_timer_sync(&poll_timer); + spin_unlock_irqrestore(&sunis_lock,flags); + kfree(PRIV(dev)); + return 0; +} + + static const struct atmphy_ops suni_ops = { - suni_start, - suni_ioctl, - suni_int + start: suni_start, + ioctl: suni_ioctl, + interrupt: suni_int, + stop: suni_stop, }; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/suni.h linux/drivers/atm/suni.h --- v2.3.99-pre2/linux/drivers/atm/suni.h Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/suni.h Tue Mar 21 23:38:26 2000 @@ -1,6 +1,6 @@ -/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */ +/* drivers/atm/suni.h - PMC PM5346 SUNI (PHY) declarations */ -/* Written 1995,1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #ifndef DRIVER_ATM_SUNI_H diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c --- v2.3.99-pre2/linux/drivers/atm/uPD98402.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/uPD98402.c Tue Mar 21 23:38:26 2000 @@ -11,6 +11,7 @@ #include #include #include +#include #include "uPD98402.h" @@ -23,8 +24,9 @@ struct uPD98402_priv { - struct sonet_stats sonet_stats; /* link diagnostics */ + struct k_sonet_stats sonet_stats;/* link diagnostics */ unsigned char framing; /* SONET/SDH framing */ + int loop_mode; /* loopback mode */ }; @@ -36,23 +38,18 @@ static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) { - unsigned long flags; - int error; + struct sonet_stats tmp; + int error = 0; - error = 0; - save_flags(flags); - cli(); - PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT); - if (arg) - error = copy_to_user(arg,&PRIV(dev)->sonet_stats, - sizeof(struct sonet_stats)); + atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs); + sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp); + if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); if (zero && !error) { - memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); - PRIV(dev)->sonet_stats.corr_hcs = -1; - PRIV(dev)->sonet_stats.tx_cells = -1; - PRIV(dev)->sonet_stats.rx_cells = -1; + /* unused fields are reported as -1, but we must not "adjust" + them */ + tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0; + sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp); } - restore_flags(flags); return error ? -EFAULT : 0; } @@ -102,6 +99,39 @@ } +static int set_loopback(struct atm_dev *dev,int mode) +{ + unsigned char mode_reg; + + mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP | + uPD98402_MDR_RPLP); + switch (__ATM_LM_XTLOC(mode)) { + case __ATM_LM_NONE: + break; + case __ATM_LM_PHY: + mode_reg |= uPD98402_MDR_TPLP; + break; + case __ATM_LM_ATM: + mode_reg |= uPD98402_MDR_ALP; + break; + default: + return -EINVAL; + } + switch (__ATM_LM_XTRMT(mode)) { + case __ATM_LM_NONE: + break; + case __ATM_LM_PHY: + mode_reg |= uPD98402_MDR_RPLP; + break; + default: + return -EINVAL; + } + PUT(mode_reg,MDR); + PRIV(dev)->loop_mode = mode; + return 0; +} + + static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) { switch (cmd) { @@ -117,35 +147,42 @@ -EFAULT : 0; case SONET_GETFRSENSE: return get_sense(dev,arg); + case ATM_SETLOOP: + return set_loopback(dev,(int) (long) arg); + case ATM_GETLOOP: + return put_user(PRIV(dev)->loop_mode,(int *) arg) ? + -EFAULT : 0; + case ATM_QUERYLOOP: + return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM | + ATM_LM_RMT_PHY,(int *) arg) ? -EFAULT : 0; default: - return -ENOIOCTLCMD; + return -ENOIOCTLCMD; } } +#define ADD_LIMITED(s,v) \ + { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \ + if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \ + atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); } + + static void stat_event(struct atm_dev *dev) { unsigned char events; events = GET(PCR); - if (events & uPD98402_PFM_PFEB) - if ((PRIV(dev)->sonet_stats.path_febe += GET(PFECB)) < 0) - PRIV(dev)->sonet_stats.path_febe = LONG_MAX; - if (events & uPD98402_PFM_LFEB) - if ((PRIV(dev)->sonet_stats.line_febe += GET(LECCT)) < 0) - PRIV(dev)->sonet_stats.line_febe = LONG_MAX; - if (events & uPD98402_PFM_B3E) - if ((PRIV(dev)->sonet_stats.path_bip += GET(B3ECT)) < 0) - PRIV(dev)->sonet_stats.path_bip = LONG_MAX; - if (events & uPD98402_PFM_B2E) - if ((PRIV(dev)->sonet_stats.line_bip += GET(B2ECT)) < 0) - PRIV(dev)->sonet_stats.line_bip = LONG_MAX; - if (events & uPD98402_PFM_B1E) - if ((PRIV(dev)->sonet_stats.section_bip += GET(B1ECT)) < 0) - PRIV(dev)->sonet_stats.section_bip = LONG_MAX; + if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB); + if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT); + if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT); + if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT); + if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT); } +#undef ADD_LIMITED + + static void uPD98402_int(struct atm_dev *dev) { static unsigned long silence = 0; @@ -158,7 +195,8 @@ if (reason & uPD98402_INT_PFM) stat_event(dev); if (reason & uPD98402_INT_PCO) { (void) GET(PCOCR); /* clear interrupt cause */ - PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT); + atomic_add(GET(HECCT), + &PRIV(dev)->sonet_stats.uncorr_hcs); } if ((reason & uPD98402_INT_RFO) && (time_after(jiffies, silence) || silence == 0)) { @@ -172,10 +210,10 @@ static int uPD98402_start(struct atm_dev *dev) { -DPRINTK("phy_start\n"); + DPRINTK("phy_start\n"); if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) return -ENOMEM; - memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); + memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats)); (void) GET(PCR); /* clear performance events */ PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */ (void) GET(PCOCR); /* clear overflows */ @@ -184,15 +222,26 @@ PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO | uPD98402_INT_LOS),PIMR); /* enable them */ (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ + atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1); + atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1); + atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1); return 0; } +static int uPD98402_stop(struct atm_dev *dev) +{ + /* let SAR driver worry about stopping interrupts */ + kfree(PRIV(dev)); + return 0; +} + static const struct atmphy_ops uPD98402_ops = { - uPD98402_start, - uPD98402_ioctl, /* no ioctl yet */ - uPD98402_int + start: uPD98402_start, + ioctl: uPD98402_ioctl, + interrupt: uPD98402_int, + stop: uPD98402_stop, }; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c --- v2.3.99-pre2/linux/drivers/atm/zatm.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/atm/zatm.c Tue Mar 21 23:38:26 2000 @@ -21,10 +21,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "uPD98401.h" @@ -637,7 +639,7 @@ } if (!size) { dev_kfree_skb_irq(skb); - if (vcc) vcc->stats->rx_err++; + if (vcc) atomic_inc(&vcc->stats->rx_err); continue; } if (!atm_charge(vcc,skb->truesize)) { @@ -647,7 +649,7 @@ skb->len = size; ATM_SKB(skb)->vcc = vcc; vcc->push(vcc,skb); - vcc->stats->rx++; + atomic_inc(&vcc->stats->rx); } zout(pos & 0xffff,MTA(mbx)); #if 0 /* probably a stupid idea */ @@ -914,7 +916,7 @@ skb_queue_head(&zatm_vcc->backlog,skb); break; } - vcc->stats->tx++; + atomic_inc(&vcc->stats->tx); wake_up(&zatm_vcc->tx_wait); } @@ -1537,7 +1539,7 @@ { DPRINTK(">zatm_close\n"); if (!ZATM_VCC(vcc)) return; - vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&vcc->flags); close_rx(vcc); EVENT("close_tx\n",0,0); close_tx(vcc); @@ -1545,7 +1547,7 @@ /* deallocate memory */ kfree(ZATM_VCC(vcc)); ZATM_VCC(vcc) = NULL; - vcc->flags &= ~ATM_VF_ADDR; + clear_bit(ATM_VF_ADDR,&vcc->flags); } @@ -1557,20 +1559,20 @@ DPRINTK(">zatm_open\n"); zatm_dev = ZATM_DEV(vcc->dev); - if (!(vcc->flags & ATM_VF_PARTIAL)) ZATM_VCC(vcc) = NULL; + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL; error = atm_find_ci(vcc,&vpi,&vci); if (error) return error; vcc->vpi = vpi; vcc->vci = vci; if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) - vcc->flags |= ATM_VF_ADDR; + set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */ DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, vcc->vci); - if (!(vcc->flags & ATM_VF_PARTIAL)) { + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { zatm_vcc = kmalloc(sizeof(struct zatm_vcc),GFP_KERNEL); if (!zatm_vcc) { - vcc->flags &= ~ATM_VF_ADDR; + clear_bit(ATM_VF_ADDR,&vcc->flags); return -ENOMEM; } ZATM_VCC(vcc) = zatm_vcc; @@ -1593,7 +1595,7 @@ zatm_close(vcc); return error; } - vcc->flags |= ATM_VF_READY; + set_bit(ATM_VF_READY,&vcc->flags); return 0; } @@ -1733,7 +1735,7 @@ int error; EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0); - if (!ZATM_VCC(vcc)->tx_chan || !(vcc->flags & ATM_VF_READY)) { + if (!ZATM_VCC(vcc)->tx_chan || !test_bit(ATM_VF_READY,&vcc->flags)) { if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); return -EINVAL; @@ -1809,7 +1811,7 @@ while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ? PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221, pci_dev))) { - dev = atm_dev_register(DEV_LABEL,&ops,-1,0); + dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); if (!dev) break; zatm_dev->pci_dev = pci_dev; ZATM_DEV(dev) = zatm_dev; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.3.99-pre2/linux/drivers/block/loop.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/loop.c Tue Mar 21 11:30:08 2000 @@ -190,7 +190,7 @@ page = grab_cache_page(mapping, index); if (!page) goto fail; - if (aops->prepare_write(page, offset, offset+size)) + if (aops->prepare_write(file, page, offset, offset+size)) goto unlock; kaddr = (char*)page_address(page); if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV)) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/block/lvm.c linux/drivers/block/lvm.c --- v2.3.99-pre2/linux/drivers/block/lvm.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/block/lvm.c Thu Mar 23 08:13:35 2000 @@ -2527,6 +2527,15 @@ * * Is this the real thing? * + * No, it's bollocks. md.c tries to do a bit different thing that might + * _somewhat_ work eons ago. Neither does any good these days. mount() couldn't + * care less for icache (it cares only for ->s_root->d_count and if we want + * loopback mounts even that will stop). BTW, with the form used here mount() + * would have to scan the _whole_ icache to detect the attempt - how on the + * Earth could it guess the i_ino of your dummy inode? Official line on the + * exclusion between mount()/swapon()/open()/etc. is Just Don't Do It(tm). + * If you can convince Linus that it's worth changing - fine, then you'll need + * to do blkdev_get()/blkdev_put(). Until then... */ struct inode *lvm_get_inode(int dev) { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.3.99-pre2/linux/drivers/block/md.c Sat Feb 26 22:31:44 2000 +++ linux/drivers/block/md.c Thu Mar 23 08:13:35 2000 @@ -1098,7 +1098,7 @@ } memset(rdev, 0, sizeof(*rdev)); - if (!fs_may_mount(newdev)) { + if (get_super(newdev)) { printk("md: can not import %s, has active inodes!\n", partition_name(newdev)); err = -EBUSY; @@ -1722,7 +1722,7 @@ int err = 0, resync_interrupted = 0; kdev_t dev = mddev_to_kdev(mddev); - if (!ro && !fs_may_mount (dev)) { + if (!ro && get_super(dev)) { printk (STILL_MOUNTED, mdidx(mddev)); OUT(-EBUSY); } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c --- v2.3.99-pre2/linux/drivers/block/paride/paride.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/block/paride/paride.c Thu Mar 23 08:47:04 2000 @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -335,6 +336,9 @@ int lpts[7] = {0x3bc,0x378,0x278,0x268,0x27c,0x26c,0}; s = protocol; e = s+1; + + if (!protocols[0]) + request_module ("paride_protocol"); if (autoprobe) { s = 0; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v2.3.99-pre2/linux/drivers/cdrom/cm206.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/cdrom/cm206.c Wed Mar 22 22:23:55 2000 @@ -1483,6 +1483,6 @@ #endif /* !MODULE */ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -D__SMP__ -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" * End: */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.3.99-pre2/linux/drivers/char/acquirewdt.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/acquirewdt.c Tue Mar 21 16:57:09 2000 @@ -37,8 +37,10 @@ #include #include #include +#include static int acq_is_open=0; +static spinlock_t acq_lock; /* * You must set these - there is no sane way to probe for this board. @@ -117,8 +119,12 @@ switch(MINOR(inode->i_rdev)) { case WATCHDOG_MINOR: + spin_lock(&acq_lock); if(acq_is_open) + { + spin_unlock(&acq_lock); return -EBUSY; + } MOD_INC_USE_COUNT; /* * Activate @@ -126,6 +132,7 @@ acq_is_open=1; inb_p(WDT_START); + spin_unlock(&acq_lock); return 0; default: return -ENODEV; @@ -136,10 +143,12 @@ { if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) { + spin_lock(&acq_lock); #ifndef CONFIG_WATCHDOG_NOWAYOUT inb_p(WDT_STOP); #endif acq_is_open=0; + spin_unlock(&acq_lock); } MOD_DEC_USE_COUNT; return 0; @@ -211,6 +220,7 @@ { printk("WDT driver for Acquire single board computer initialising.\n"); + spin_lock_init(&acq_lock); misc_register(&acq_miscdev); request_region(WDT_STOP, 1, "Acquire WDT"); request_region(WDT_START, 1, "Acquire WDT"); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c --- v2.3.99-pre2/linux/drivers/char/amigamouse.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/amigamouse.c Tue Mar 21 14:43:39 2000 @@ -162,6 +162,10 @@ static int open_mouse(struct inode * inode, struct file * file) { + /* Lock module first - request_irq might sleep */ + + MOD_INC_USE_COUNT; + /* * use VBL to poll mouse deltas */ @@ -169,10 +173,10 @@ if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0, "Amiga mouse", mouse_interrupt)) { printk(KERN_INFO "Installing Amiga mouse failed.\n"); + MOD_DEC_USE_COUNT; return -EIO; } - MOD_INC_USE_COUNT; #if AMIGA_OLD_INT AMI_MSE_INT_ON(); #endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c --- v2.3.99-pre2/linux/drivers/char/amiserial.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/char/amiserial.c Wed Mar 22 22:23:55 2000 @@ -2259,6 +2259,6 @@ /* Local variables: - compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c amiserial.c" + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c amiserial.c" End: */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/applicom.c linux/drivers/char/applicom.c --- v2.3.99-pre2/linux/drivers/char/applicom.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/applicom.c Tue Mar 21 14:43:39 2000 @@ -14,7 +14,7 @@ /* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */ /* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */ /* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */ -/* adresses de base des cartes, IOCTL 6 plus complet */ +/* adresses de base des cartes, IOCTL 6 plus complet */ /* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */ /* de code autre que le texte V2.6.1 en V2.8.0 */ /*****************************************************************************/ @@ -37,108 +37,102 @@ #undef DEBUG #define DEVPRIO PZERO+8 #define FALSE 0 -#define TRUE ~FALSE -#define MAX_BOARD 8 /* maximum of pc board possible */ +#define TRUE ~FALSE +#define MAX_BOARD 8 /* maximum of pc board possible */ #define MAX_ISA_BOARD 4 #define LEN_RAM_IO 0x800 #define AC_MINOR 157 #ifndef PCI_VENDOR_ID_APPLICOM -#define PCI_VENDOR_ID_APPLICOM 0x1389 +#define PCI_VENDOR_ID_APPLICOM 0x1389 #define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 #define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 #define MAX_PCI_DEVICE_NUM 3 #endif -static char *applicom_pci_devnames[]={ - "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"}; +static char *applicom_pci_devnames[] = { + "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB" +}; MODULE_AUTHOR("David Woodhouse & Applicom International"); MODULE_DESCRIPTION("Driver for Applicom Profibus card"); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(irq, "IRQ of the Applicom board"); -MODULE_PARM(mem,"i"); +MODULE_PARM(mem, "i"); MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board"); MODULE_SUPPORTED_DEVICE("ac"); struct applicom_board { - unsigned long PhysIO; - unsigned long RamIO; + unsigned long PhysIO; + unsigned long RamIO; #if LINUX_VERSION_CODE > 0x20300 - wait_queue_head_t FlagSleepSend; + wait_queue_head_t FlagSleepSend; #else - struct wait_queue *FlagSleepSend; + struct wait_queue *FlagSleepSend; #endif - long irq; + long irq; } apbs[MAX_BOARD]; -static unsigned int irq=0; /* interrupt number IRQ */ -static unsigned long mem=0; /* physical segment of board */ +static unsigned int irq = 0; /* interrupt number IRQ */ +static unsigned long mem = 0; /* physical segment of board */ -static unsigned int numboards; /* number of installed boards */ +static unsigned int numboards; /* number of installed boards */ static volatile unsigned char Dummy; #if LINUX_VERSION_CODE > 0x20300 -static DECLARE_WAIT_QUEUE_HEAD (FlagSleepRec); +static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec); #else static struct wait_queue *FlagSleepRec; #endif -static unsigned int WriteErrorCount; /* number of write error */ -static unsigned int ReadErrorCount; /* number of read error */ -static unsigned int DeviceErrorCount; /* number of device error */ +static unsigned int WriteErrorCount; /* number of write error */ +static unsigned int ReadErrorCount; /* number of read error */ +static unsigned int DeviceErrorCount; /* number of device error */ static loff_t ac_llseek(struct file *file, loff_t offset, int origin); static int ac_open(struct inode *inode, struct file *filp); -static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr); -static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos); +static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr); +static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos); static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int ac_release(struct inode *inode, struct file *file); static void ac_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -struct file_operations ac_fops={ - llseek: ac_llseek, - read: ac_read, - write: ac_write, - ioctl: ac_ioctl, - open: ac_open, - release: ac_release, +struct file_operations ac_fops = { + llseek:ac_llseek, + read:ac_read, + write:ac_write, + ioctl:ac_ioctl, + open:ac_open, + release:ac_release, }; -struct miscdevice ac_miscdev={ - AC_MINOR, - "ac", - &ac_fops +struct miscdevice ac_miscdev = { + AC_MINOR, + "ac", + &ac_fops }; -int ac_register_board(unsigned long physloc, unsigned long loc, - unsigned char boardno) +int ac_register_board(unsigned long physloc, unsigned long loc, unsigned char boardno) { volatile unsigned char byte_reset_it; - if((readb(loc + CONF_END_TEST) != 0x00) || - (readb(loc + CONF_END_TEST + 1) != 0x55) || - (readb(loc + CONF_END_TEST + 2) != 0xAA) || - (readb(loc + CONF_END_TEST + 3) != 0xFF)) - return 0; + if ((readb(loc + CONF_END_TEST) != 0x00) || (readb(loc + CONF_END_TEST + 1) != 0x55) || (readb(loc + CONF_END_TEST + 2) != 0xAA) || (readb(loc + CONF_END_TEST + 3) != 0xFF)) + return 0; if (!boardno) - boardno = readb(loc + NUMCARD_OWNER_TO_PC); + boardno = readb(loc + NUMCARD_OWNER_TO_PC); + + if (!boardno && boardno > MAX_BOARD) { + printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", boardno, physloc, MAX_BOARD); + return 0; + } - if (!boardno && boardno > MAX_BOARD) - { - printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",boardno, physloc, MAX_BOARD); - return 0; - } - - if (apbs[boardno-1].RamIO) - { - printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", - boardno, physloc, boardno, apbs[boardno-1].PhysIO); - return 0; - } + if (apbs[boardno - 1].RamIO) { + printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", boardno, physloc, boardno, apbs[boardno - 1].PhysIO); + return 0; + } boardno--; @@ -152,7 +146,7 @@ byte_reset_it = readb(loc + RAM_IT_TO_PC); numboards++; - return boardno+1; + return boardno + 1; } #ifdef MODULE @@ -164,22 +158,21 @@ int i; misc_deregister(&ac_miscdev); - for (i=0; i< MAX_BOARD; i++) - { - if (!apbs[i].RamIO) - continue; - iounmap((void *)apbs[i].RamIO); - if (apbs[i].irq) - free_irq(apbs[i].irq,&ac_open); - } - // printk("Removing Applicom module\n"); + for (i = 0; i < MAX_BOARD; i++) { + if (!apbs[i].RamIO) + continue; + iounmap((void *) apbs[i].RamIO); + if (apbs[i].irq) + free_irq(apbs[i].irq, &ac_open); + } + // printk("Removing Applicom module\n"); } -#endif /* MODULE */ +#endif /* MODULE */ int __init applicom_init(void) { - int i, numisa=0; + int i, numisa = 0; struct pci_dev *dev = NULL; void *RamIO; int boardno; @@ -190,157 +183,137 @@ #endif printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $\n"); - + /* No mem and irq given - check for a PCI card */ - - while ( (dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev))) - { - // mem = dev->base_address[0]; - // irq = dev->irq; - - RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO); - - if (!RamIO) { - printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev)); - return -EIO; - } - - printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n", - applicom_pci_devnames[dev->device-1], PCI_BASE_ADDRESS(dev), - dev->irq); - - if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev), - (unsigned long)RamIO,0))) - { - printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); - iounmap(RamIO); - continue; - } - - if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) - { - printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); - iounmap(RamIO); - apbs[boardno-1].RamIO = 0; - continue; - } - /* Enable interrupts. */ + while ((dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev))) { + // mem = dev->base_address[0]; + // irq = dev->irq; - writeb(0x40, apbs[boardno-1].RamIO + RAM_IT_FROM_PC); + RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO); + + if (!RamIO) { + printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev)); + return -EIO; + } + + printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n", applicom_pci_devnames[dev->device - 1], PCI_BASE_ADDRESS(dev), dev->irq); + + if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev), (unsigned long) RamIO, 0))) { + printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); + iounmap(RamIO); + continue; + } + + if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) { + printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); + iounmap(RamIO); + apbs[boardno - 1].RamIO = 0; + continue; + } + + /* Enable interrupts. */ + + writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC); + + apbs[boardno - 1].irq = dev->irq; + } - apbs[boardno-1].irq = dev->irq; - } - /* Finished with PCI cards. If none registered, * and there was no mem/irq specified, exit */ - if (!mem || !irq) - { - if (numboards) - goto fin; - else - { - printk(KERN_INFO "ac.o: No PCI boards found.\n"); - printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n"); - return -ENXIO; - } - } - + if (!mem || !irq) { + if (numboards) + goto fin; + else { + printk(KERN_INFO "ac.o: No PCI boards found.\n"); + printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n"); + return -ENXIO; + } + } + /* Now try the specified ISA cards */ - RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD); + RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD); if (!RamIO) { - printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n",mem); + printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem); } - - for (i=0; i< MAX_ISA_BOARD; i++) - { - RamIO = ioremap(mem+ (LEN_RAM_IO*i), LEN_RAM_IO); - - if (!RamIO) { - printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n",i+1); - continue; - } - - if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i), - (unsigned long)RamIO,i+1))) { - iounmap(RamIO); - continue; - } - - printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq); - - if (!numisa) - { - if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open)) - { - printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq); - iounmap((void *)RamIO); - apbs[boardno-1].RamIO = 0; - } - apbs[boardno-1].irq=irq; - } - else - apbs[boardno-1].irq=0; - numisa++; - } + for (i = 0; i < MAX_ISA_BOARD; i++) { + RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO); + + if (!RamIO) { + printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1); + continue; + } + + if (!(boardno = ac_register_board((unsigned long) mem + (LEN_RAM_IO * i), (unsigned long) RamIO, i + 1))) { + iounmap(RamIO); + continue; + } + + printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO * i), irq); + + if (!numisa) { + if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open)) { + printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq); + iounmap((void *) RamIO); + apbs[boardno - 1].RamIO = 0; + } + apbs[boardno - 1].irq = irq; + } else + apbs[boardno - 1].irq = 0; + + numisa++; + } if (!numisa) - printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem); + printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n", mem); #if LINUX_VERSION_CODE > 0x20300 init_waitqueue_head(&FlagSleepRec); #else - FlagSleepRec = NULL; + FlagSleepRec = NULL; #endif - WriteErrorCount = 0; - ReadErrorCount = 0; + WriteErrorCount = 0; + ReadErrorCount = 0; DeviceErrorCount = 0; -fin: - if (numboards) - { - misc_register (&ac_miscdev); - for (i=0; i> 4), (int) (readb(apbs[i].RamIO + VERS) & 0xF)); + + serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2)); + + if (serial != 0) + printk(" S/N %d\n", serial); + else + printk("\n"); + } + return 0; + } - printk("Applicom board %d: %s, PROM V%d.%d", - i+1, boardname, - (int)(readb(apbs[i].RamIO + VERS) >> 4), - (int)(readb(apbs[i].RamIO + VERS) & 0xF)); - - serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + - (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + - (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); - - if (serial != 0) - printk (" S/N %d\n", serial); - else - printk("\n"); - } - return 0; - } - else - return -ENXIO; + return -ENXIO; } #ifndef MODULE -__initcall (applicom_init); +__initcall(applicom_init); #endif static loff_t ac_llseek(struct file *file, loff_t offset, int origin) @@ -361,477 +334,455 @@ } -static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos) +static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos) { - unsigned int NumCard; /* Board number 1 -> 8 */ - unsigned int IndexCard; /* Index board number 0 -> 7 */ - unsigned char TicCard; /* Board TIC to send */ - unsigned long flags; /* Current priority */ - struct st_ram_io st_loc; - struct mailbox tmpmailbox; - - if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { - printk("Hmmm. write() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); - return -EINVAL; - } - - if(copy_from_user (&st_loc, buf, sizeof(struct st_ram_io))) { - return -EFAULT; - } - if(copy_from_user (&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) { - return -EFAULT; - } - - NumCard = st_loc.num_card; /* board number to send */ - TicCard = st_loc.tic_des_from_pc; /* tic number to send */ - IndexCard = NumCard -1; - if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) - { /* User board number not OK */ - // printk("Write to invalid Applicom board %d\n", NumCard); - return -EINVAL; /* Return error code user buffer */ - } - + unsigned int NumCard; /* Board number 1 -> 8 */ + unsigned int IndexCard; /* Index board number 0 -> 7 */ + unsigned char TicCard; /* Board TIC to send */ + unsigned long flags; /* Current priority */ + struct st_ram_io st_loc; + struct mailbox tmpmailbox; + + if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { + printk("Hmmm. write() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox)); + return -EINVAL; + } + + if (copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) { + return -EFAULT; + } + if (copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) { + return -EFAULT; + } + + NumCard = st_loc.num_card; /* board number to send */ + TicCard = st_loc.tic_des_from_pc; /* tic number to send */ + IndexCard = NumCard - 1; + if ((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) { /* User board number not OK */ + // printk("Write to invalid Applicom board %d\n", NumCard); + return -EINVAL; /* Return error code user buffer */ + } #ifdef DEBUG - { - int c; - - printk("Write to applicom card #%d. struct st_ram_io follows:",NumCard); - - - - for (c=0; c< sizeof(struct st_ram_io);) - { - printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]); - - for (c++ ; c%8 && c 2) /* Test octet ready correct */ - { - Dummy = readb(apbs[IndexCard].RamIO + VERS); - restore_flags(flags); - printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n", - IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY)); - DeviceErrorCount++; - return -EIO; - } - while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) - { - Dummy = readb(apbs[IndexCard].RamIO + VERS); - restore_flags(flags); - interruptible_sleep_on (&apbs[IndexCard].FlagSleepSend); - if (signal_pending(current)) - return -EINTR; - save_flags(flags); - cli(); - } - writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); - - // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox)); - { - unsigned char *from = (unsigned char *)&tmpmailbox; - unsigned long to = (unsigned long)apbs[IndexCard].RamIO + RAM_FROM_PC; - int c; - - for (c=0; c 2) { /* Test octet ready correct */ + Dummy = readb(apbs[IndexCard].RamIO + VERS); + restore_flags(flags); + printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n", IndexCard, (int) readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY)); + DeviceErrorCount++; + return -EIO; + } + while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) { + Dummy = readb(apbs[IndexCard].RamIO + VERS); + restore_flags(flags); + /* + * FIXME: Race on wakeup. Race on re-entering write + * in another thread. + */ + interruptible_sleep_on(&apbs[IndexCard].FlagSleepSend); + if (signal_pending(current)) + return -EINTR; + save_flags(flags); + cli(); + } + writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); + + // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox)); + { + unsigned char *from = (unsigned char *) &tmpmailbox; + unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC; + int c; + + for (c = 0; c < sizeof(struct mailbox); c++) + writeb(*(from++), to++); + } + writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC); + writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC); + writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC); + writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); + writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); + writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); + Dummy = readb(apbs[IndexCard].RamIO + VERS); + restore_flags(flags); + return 0; } -static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr) +static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr) { - unsigned int NumCard; /* board number 1 -> 8 */ - unsigned int IndexCard; /* index board number 0 -> 7 */ - unsigned long flags; - unsigned int i; - unsigned char tmp=0; - struct st_ram_io st_loc; - struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */ - - - if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { - printk("Hmmm. read() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); - return -EINVAL; - } - - save_flags(flags); - cli(); - - i = 0; - - while (tmp != 2) - { - for (i=0; i < MAX_BOARD; i++) - { - if (!apbs[i].RamIO) - continue; - - tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); - - if (tmp == 2) - break; - - if (tmp > 2) /* Test octet ready correct */ - { - Dummy = readb(apbs[i].RamIO + VERS); - restore_flags(flags); - printk("APPLICOM driver read error board %d, DataToPcReady = %d\n", - i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); - DeviceErrorCount++; - return -EIO; - } - Dummy = readb(apbs[i].RamIO + VERS); + unsigned int NumCard; /* board number 1 -> 8 */ + unsigned int IndexCard; /* index board number 0 -> 7 */ + unsigned long flags; + unsigned int i; + unsigned char tmp = 0; + struct st_ram_io st_loc; + struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */ + + if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { + printk("Hmmm. read() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox)); + return -EINVAL; } - if (tmp != 2) + + save_flags(flags); + cli(); + + i = 0; + + while (tmp != 2) { + for (i = 0; i < MAX_BOARD; i++) { + if (!apbs[i].RamIO) + continue; + + tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); + + if (tmp == 2) + break; + + if (tmp > 2) { /* Test octet ready correct */ + Dummy = readb(apbs[i].RamIO + VERS); + restore_flags(flags); + printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", i, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY)); + DeviceErrorCount++; + return -EIO; + } + Dummy = readb(apbs[i].RamIO + VERS); + + } + if (tmp != 2) { + /* + * FIXME: race on wakeup. O_NDELAY not implemented + * Parallel read threads race. + */ + restore_flags(flags); + interruptible_sleep_on(&FlagSleepRec); + if (signal_pending(current)) + return -EINTR; + save_flags(flags); + cli(); + } + } + + IndexCard = i; + NumCard = i + 1; + st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); + st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); + + + // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox)); { - restore_flags(flags); - interruptible_sleep_on (&FlagSleepRec); - if (signal_pending(current)) - return -EINTR; - save_flags(flags); - cli(); - } - } - - IndexCard = i; - NumCard = i+1; - st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); - st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); - - - // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox)); - { - unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC; - unsigned char *to = (unsigned char *)&tmpmailbox; - int c; - - for (c=0; c 2) - { - printk("APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", - i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); - DeviceErrorCount++; - } - if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && - (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) - { - printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", - i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY)); - DeviceErrorCount++; - } - if(readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) /* mailbox sent by the card ? */ - { - wake_up_interruptible(&FlagSleepRec); - } - if(readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) /* ram i/o free for write by pc ? */ - { - if(waitqueue_active(&apbs[i].FlagSleepSend)) /* process sleep during read ? */ - { - wake_up_interruptible(&apbs[i].FlagSleepSend); - } - } - Dummy = readb(apbs[i].RamIO + VERS); - - if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) - i--; /* There's another int waiting on this card */ - } - if(FlagInt) LoopCount = 0; - else LoopCount++; - } - while(LoopCount < 2); + unsigned int i; + unsigned int FlagInt; + unsigned int LoopCount; + // volatile unsigned char ResetIntBoard; + + // printk("Applicom interrupt on IRQ %d occurred\n", vec); + + LoopCount = 0; + // for(i=boardno;i 2) { + printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY)); + DeviceErrorCount++; + } + if ((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) { + printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_FROM_PC_READY)); + DeviceErrorCount++; + } + if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */ + wake_up_interruptible(&FlagSleepRec); + } + if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */ + if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */ + wake_up_interruptible(&apbs[i].FlagSleepSend); + } + } + Dummy = readb(apbs[i].RamIO + VERS); + + if (readb(apbs[i].RamIO + RAM_IT_TO_PC)) + i--; /* There's another int waiting on this card */ + } + if (FlagInt) + LoopCount = 0; + else + LoopCount++; + } + while (LoopCount < 2); } static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ /* @ ADG ou ATO selon le cas */ + int i; + unsigned char IndexCard; + unsigned long pmem; + volatile unsigned char byte_reset_it; + struct st_ram_io adgl; + unsigned char TmpRamIo[sizeof(struct st_ram_io)]; -{ /* @ ADG ou ATO selon le cas */ - int i; - unsigned char IndexCard; - unsigned long pmem ; - volatile unsigned char byte_reset_it; - struct st_ram_io adgl ; - unsigned char TmpRamIo[sizeof(struct st_ram_io)]; - - - if (copy_from_user (&adgl, (void *)arg,sizeof(struct st_ram_io))) - return -EFAULT; - - IndexCard = adgl.num_card-1; - if(cmd != 0 && cmd != 6 && - ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) - { - printk("APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); - printk("apbs[%d].RamIO = %lx\n",IndexCard, apbs[IndexCard].RamIO); - return -EINVAL; - } - - switch( cmd ) - { - case 0 : - pmem = apbs[IndexCard].RamIO; - for(i=0;i= MAX_BOARD) || !apbs[IndexCard].RamIO)) { + printk("APPLICOM driver IOCTL, bad board number %d\n", (int) IndexCard + 1); + printk("apbs[%d].RamIO = %lx\n", IndexCard, apbs[IndexCard].RamIO); + return -EINVAL; + } + + /* + * FIXME races between ioctls with multiple clients + */ + + switch (cmd) { + case 0: + pmem = apbs[IndexCard].RamIO; + for (i = 0; i < sizeof(struct st_ram_io); i++) + TmpRamIo[i] = readb(pmem++); + if (copy_to_user((void *) arg, TmpRamIo, sizeof(struct st_ram_io))) + return -EFAULT; + break; + case 1: + pmem = apbs[IndexCard].RamIO + CONF_END_TEST; + for (i = 0; i < 4; i++) + adgl.conf_end_test[i] = readb(pmem++); + for (i = 0; i < 2; i++) + adgl.error_code[i] = readb(pmem++); + for (i = 0; i < 4; i++) + adgl.parameter_error[i] = readb(pmem++); + pmem = apbs[IndexCard].RamIO + VERS; + adgl.vers = readb(pmem); + pmem = apbs[IndexCard].RamIO + TYPE_CARD; + for (i = 0; i < 20; i++) + adgl.reserv1[i] = readb(pmem++); + *(int *) &adgl.reserv1[20] = (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2)); + + if (copy_to_user((void *) arg, &adgl, sizeof(struct st_ram_io))) + return -EFAULT; + break; + case 2: + pmem = apbs[IndexCard].RamIO + CONF_END_TEST; + for (i = 0; i < 10; i++) + writeb(0xff, pmem++); + writeb(adgl.data_from_pc_ready, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); + + writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); + + /* + * FIXME: can trash waitqueue that is active. + */ #if LINUX_VERSION_CODE > 0x20300 - init_waitqueue_head (&FlagSleepRec); + init_waitqueue_head(&FlagSleepRec); #else - FlagSleepRec = NULL; + FlagSleepRec = NULL; #endif - for (i=0;i 0x20300 - init_waitqueue_head (&apbs[i].FlagSleepSend); + init_waitqueue_head(&apbs[i].FlagSleepSend); #else - apbs[i].FlagSleepSend = NULL; + apbs[i].FlagSleepSend = NULL; #endif - byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC); - } - } - break ; - case 3 : - pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC; - writeb(adgl.tic_des_from_pc, pmem); - break; - case 4 : - pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC; - adgl.tic_owner_to_pc = readb(pmem++); - adgl.numcard_owner_to_pc = readb(pmem); - if (copy_to_user ((void *)arg, &adgl,sizeof(struct st_ram_io))) - return -EFAULT; - break; - case 5 : - writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); - writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); - writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); - writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); - writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); - break ; - case 6 : - printk("APPLICOM driver release .... V2.8.0\n"); - printk("Number of installed boards . %d\n",(int)numboards); - printk("Segment of board ........... %X\n",(int)mem); - printk("Interrupt IRQ number ....... %d\n",(int)irq); - for(i=0;i> 4), - (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF), - boardname); - - - serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + - (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + - (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); - - if (serial != 0) - printk (" S/N %d\n", serial); - else - printk("\n"); - } - if(DeviceErrorCount != 0) - printk("DeviceErrorCount ........... %d\n",DeviceErrorCount); - if(ReadErrorCount != 0) - printk("ReadErrorCount ............. %d\n",ReadErrorCount); - if(WriteErrorCount != 0) - printk("WriteErrorCount ............ %d\n",WriteErrorCount); - if(waitqueue_active(&FlagSleepRec)) - printk("Process in read pending\n"); - for(i=0;i> 4), (int) (readb(apbs[IndexCard].RamIO + VERS) & 0xF), boardname); + + + serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2)); + + if (serial != 0) + printk(" S/N %d\n", serial); + else + printk("\n"); + } + if (DeviceErrorCount != 0) + printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount); + if (ReadErrorCount != 0) + printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount); + if (WriteErrorCount != 0) + printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount); + if (waitqueue_active(&FlagSleepRec)) + printk("Process in read pending\n"); + for (i = 0; i < MAX_BOARD; i++) { + if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend)) + printk("Process in write pending board %d\n", i + 1); + } + break; + default: + printk("APPLICOM driver ioctl, unknown function code %d\n", cmd); + return -EINVAL; + break; + } + Dummy = readb(apbs[IndexCard].RamIO + VERS); + return 0; } #ifndef MODULE static int __init applicom_setup(char *str) { int ints[4]; - - (void)get_options(str, 4, ints); + + (void) get_options(str, 4, ints); if (ints[0] > 2) { printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n"); } - + if (ints[0] < 2) { printk("applicom numargs: %d\n", ints[0]); return 0; } - - mem=ints[1]; - irq=ints[2]; + + mem = ints[1]; + irq = ints[2]; return 1; } + #if LINUX_VERSION_CODE > 0x20300 __setup("applicom=", applicom_setup); #endif -#endif /* MODULE */ - +#endif /* MODULE */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c --- v2.3.99-pre2/linux/drivers/char/atixlmouse.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/atixlmouse.c Wed Mar 22 15:42:57 2000 @@ -92,10 +92,14 @@ static int open_mouse(struct inode * inode, struct file * file) { + /* Lock module as request_irq may sleep */ + MOD_INC_USE_COUNT; if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL)) + { + MOD_DEC_USE_COUNT; return -EBUSY; + } ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */ - MOD_INC_USE_COUNT; return 0; } @@ -107,7 +111,13 @@ { unsigned char a,b,c; - if (check_region(ATIXL_MSE_DATA_PORT, 3)) + /* + * We must request the resource and claim it atomically + * nowdays. We can throw it away on error. Otherwise we + * may race another module load of the same I/O + */ + + if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse")) return -EIO; a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */ @@ -116,16 +126,20 @@ if (( a != b ) && ( a == c )) printk(KERN_INFO "\nATI Inport "); else + { + release_region(ATIXL_MSE_DATA_PORT,3); return -EIO; + } outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */ outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */ outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */ - request_region(ATIXL_MSE_DATA_PORT, 3, "atixl"); - msedev = register_busmouse(&atixlmouse); if (msedev < 0) + { printk("Bus mouse initialisation error.\n"); + release_region(ATIXL_MSE_DATA_PORT,3); /* Was missing */ + } else printk("Bus mouse detected and installed.\n"); return msedev < 0 ? msedev : 0; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.99-pre2/linux/drivers/char/bttv.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/bttv.c Sun Mar 19 19:11:37 2000 @@ -121,6 +121,7 @@ #define I2C_GET() (btread(BT848_I2C)&1) #define BURSTOFFSET 76 +#define BTTV_ERRORS 5 /* ----------------------------------------------------------------------- */ @@ -133,7 +134,6 @@ if (card >= bttv_num) { return -1; } - return bttvs[card].type; } @@ -146,10 +146,7 @@ } btv = &bttvs[card]; - down(&btv->lock); btaor(data, ~mask, BT848_GPIO_OUT_EN); - up(&btv->lock); - return 0; } @@ -167,15 +164,9 @@ return -ENODEV; } - down(&btv->lock); - /* prior setting BT848_GPIO_REG_INP is (probably) not needed because we set direct input on init */ - *data = btread(BT848_GPIO_DATA); - - up(&btv->lock); - return 0; } @@ -189,15 +180,9 @@ btv = &bttvs[card]; - down(&btv->lock); - /* prior setting BT848_GPIO_REG_INP is (probably) not needed because direct input is set on init */ - btaor(data & mask, ~mask, BT848_GPIO_DATA); - - up(&btv->lock); - return 0; } @@ -210,11 +195,9 @@ } btv = &bttvs[card]; - if (bttvs[card].shutdown) { return NULL; } - return &btv->gpioq; } @@ -787,7 +770,7 @@ 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, 1,1,1,1,0 }, { "Hauppauge old", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, 1,1,0,1,0 }, { "STB", 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, @@ -815,7 +798,7 @@ 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, 1,1,1,1,0 }, { "Hauppauge new (bt878)", - 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, 1,1,0,1,0 }, { "MIRO PCTV pro", 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0, @@ -1213,7 +1196,7 @@ unsigned int *pe=(unsigned int *) btv->vbi_even; if (debug) - printk("bttv%d: vbi: po=%08lx pe=%08lx\n", + printk("bttv%d: vbi1: po=%08lx pe=%08lx\n", btv->nr,virt_to_bus(po), virt_to_bus(pe)); *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; @@ -1233,8 +1216,10 @@ } *(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)); + + if (debug) + printk("bttv%d: vbi2: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); } static int fmtbppx2[16] = { @@ -1310,7 +1295,7 @@ int shift, csize; if (debug) - printk("bttv%d: prisc: ro=%08lx re=%08lx\n", + printk("bttv%d: prisc1: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); switch(fmt) @@ -1406,6 +1391,10 @@ *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); *(re++)=cpu_to_le32(btv->bus_vbi_odd); + if (debug) + printk("bttv%d: prisc2: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + return 0; } @@ -1428,7 +1417,7 @@ return make_prisctab(btv, ro, re, vbuf, width, height, palette); if (debug) - printk("bttv%d: vrisc: ro=%08lx re=%08lx\n", + printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; @@ -1478,6 +1467,10 @@ *(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); + + if (debug) + printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); return 0; } @@ -1555,7 +1548,7 @@ width=btv->win.width; height=btv->win.height; if (debug) - printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", btv->nr,btv->picture.palette,width,height,bpl,bpp); if(width > 1023) width = 1023; /* sanity check */ @@ -1662,6 +1655,10 @@ *(ro++)=cpu_to_le32(btv->bus_vbi_even); *(re++)=cpu_to_le32(BT848_RISC_JUMP); *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + if (debug) + printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); } /* @@ -1879,7 +1876,7 @@ if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) return -EBUSY; - if(mp->height <0 || mp->width <0) + if(mp->height < 32 || mp->width < 32) return -EINVAL; if (mp->format >= PALETTEFMT_MAX) return -EINVAL; @@ -1891,12 +1888,6 @@ return -EINVAL; /* - * FIXME: Check the format of the grab here. This is probably - * also less restrictive than the normal overlay grabs. Stuff - * like QCIF has meaning as a capture. - */ - - /* * Ok load up the BT848 */ @@ -1906,7 +1897,8 @@ make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); if (debug) - printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame); + printk("bttv%d: cap vgrab: queue %d (%dx%d)\n", + btv->nr,mp->frame,mp->width,mp->height); cli(); btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; @@ -1995,6 +1987,26 @@ tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0); } +static void bt848_restart(struct bttv *btv) +{ + if (verbose) + printk("bttv%d: resetting chip\n",btv->nr); + btwrite(0xfffffUL, BT848_INT_STAT); + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(0, BT848_SRESET); + btwrite(virt_to_bus(btv->risc_jmp+2), + BT848_RISC_STRT_ADD); + + /* enforce pll reprogramming */ + btv->pll.pll_current = 0; + set_pll(btv); + + btv->errors = 0; + btv->needs_restart = 0; + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); +} + /* * Open a bttv card. Right now the flags stuff is just playing */ @@ -2020,6 +2032,8 @@ for (i = 0; i < gbuffers; i++) btv->gbuf[i].stat = GBUFFER_UNUSED; + if (btv->needs_restart) + bt848_restart(btv); burst(0); set_pll(btv); btv->user++; @@ -2117,7 +2131,6 @@ btaor(datahi, ~1, BT848_O_CONTROL); } - /* * ioctl routine */ @@ -2126,7 +2139,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct bttv *btv=(struct bttv *)dev; - int i,ret; + int i,ret = 0; if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); @@ -2281,7 +2294,7 @@ if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; - + if(vw.flags || vw.width < 16 || vw.height < 16) { down(&btv->lock); @@ -2296,6 +2309,8 @@ vw.width &= ~3; } down(&btv->lock); + if (btv->needs_restart) + bt848_restart(btv); btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; @@ -2551,14 +2566,17 @@ return -EINVAL; switch (btv->gbuf[i].stat) { case GBUFFER_UNUSED: - return -EINVAL; + ret = -EINVAL; + break; case GBUFFER_GRABBING: while(btv->gbuf[i].stat==GBUFFER_GRABBING) { if (debug) printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); interruptible_sleep_on(&btv->capq); - if(signal_pending(current)) - return -EINTR; + if(signal_pending(current)) { + ret = -EINTR; + break; + } } /* fall throuth */ case GBUFFER_DONE: @@ -2567,9 +2585,13 @@ if (debug) printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); btv->gbuf[i].stat = GBUFFER_UNUSED; - return ret; } - return 0; + if (btv->needs_restart) { + down(&btv->lock); + bt848_restart(btv); + up(&btv->lock); + } + return ret; case BTTV_FIELDNR: if(copy_to_user((void *) arg, (void *) &btv->last_field, @@ -2742,6 +2764,11 @@ todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) { + if (btv->needs_restart) { + down(&btv->lock); + bt848_restart(btv); + up(&btv->lock); + } if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) return -EFAULT; todo-=q; @@ -2796,6 +2823,8 @@ struct bttv *btv=(struct bttv *)(dev-2); down(&btv->lock); + if (btv->needs_restart) + bt848_restart(btv); btv->vbip=VBIBUF_SIZE; btv->vbi_on = 1; bt848_set_risc_jmps(btv,-1); @@ -2938,8 +2967,8 @@ if(v.tuner||btv->channel) /* Only tuner 0 */ return -EINVAL; strcpy(v.name, "Radio"); - v.rangelow=(int)(87.5*16); - v.rangehigh=(int)(108*16); + v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */ + v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */ v.flags= 0; /* XXX */ v.mode = 0; /* XXX */ if(copy_to_user(arg,&v,sizeof(v))) @@ -3100,12 +3129,10 @@ /* print which board we have found */ printk(KERN_INFO "bttv%d: model: ",btv->nr); - sprintf(btv->video_dev.name,"BT%d",btv->id); - if (btv->id==848 && btv->revision==0x12) - strcat(btv->video_dev.name,"A"); - strcat(btv->video_dev.name,"("); - strcat(btv->video_dev.name, tvcards[btv->type].name); - strcat(btv->video_dev.name,")"); + sprintf(btv->video_dev.name,"BT%d%s(%.22s)", + btv->id, + (btv->id==848 && btv->revision==0x12) ? "A" : "", + tvcards[btv->type].name); printk("%s\n",btv->video_dev.name); /* board specific initialisations */ @@ -3357,6 +3384,9 @@ btv->vbibuf=0; btv->field=btv->last_field=0; + btv->errors=0; + btv->needs_restart=0; + /* i2c */ btv->tuner_type=-1; init_bttv_i2c(btv); @@ -3458,7 +3488,7 @@ { u32 stat,astat; u32 dstat; - int count; + int count,i; struct bttv *btv; btv=(struct bttv *)dev_id; @@ -3498,24 +3528,43 @@ btv->field++; } if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { - printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr, - (astat&BT848_INT_SCERR) ? " SCERR" : "", - (astat&BT848_INT_OCERR) ? " OCERR" : "", - btread(BT848_RISC_COUNT)); - bt848_set_risc_jmps(btv,0); - btwrite(0, BT848_SRESET); - btwrite(virt_to_bus(btv->risc_jmp), - BT848_RISC_STRT_ADD); - bt848_set_geo(btv,0); - bt848_set_risc_jmps(btv,-1); -#if 0 - wake_up_interruptible(&btv->vbiq); - wake_up_interruptible(&btv->capq); -#endif + if (verbose) + printk("bttv%d: irq:%s%s risc_count=%08x\n", + btv->nr, + (astat&BT848_INT_SCERR) ? " SCERR" : "", + (astat&BT848_INT_OCERR) ? " OCERR" : "", + btread(BT848_RISC_COUNT)); + btv->errors++; + if (btv->errors < BTTV_ERRORS) { + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(virt_to_bus(btv->risc_jmp+2), + BT848_RISC_STRT_ADD); + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); + } else { + if (verbose) + printk("bttv%d: aiee: error loops\n",btv->nr); + /* cancel all outstanding grab requests */ + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + if (btv->gbuf[i].stat == GBUFFER_GRABBING) + btv->gbuf[i].stat = GBUFFER_ERROR; + /* disable DMA */ + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,0); + + btv->needs_restart = 1; + wake_up_interruptible(&btv->vbiq); + wake_up_interruptible(&btv->capq); + } } if (astat&BT848_INT_RISCI) { - IDEBUG(printk ("bttv%d: IRQ_RISCI\n", btv->nr)); + if (debug > 1) + printk("bttv%d: IRQ_RISCI\n",btv->nr); /* captured VBI frame */ if (stat&(1<<28)) @@ -3527,11 +3576,12 @@ } /* captured full frame */ - if (stat&(2<<28)) + if (stat&(2<<28) && btv->gq_grab != -1) { btv->last_field=btv->field; if (debug) printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); + do_gettimeofday(&btv->gbuf[btv->gq_grab].tv); btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; btv->gq_grab = -1; if (btv->gq_in != btv->gq_out) @@ -3662,6 +3712,11 @@ btv->id=dev->device; btv->irq=dev->irq; btv->bt848_adr=dev->resource[0].start; + if (!request_mem_region(pci_resource_start(dev,0), + pci_resource_len(dev,0), + "bttv")) { + return -EBUSY; + } if (btv->id >= 878) btv->i2c_command = 0x83; else @@ -3720,15 +3775,15 @@ { printk(KERN_ERR "bttv%d: Bad irq number or handler\n", bttv_num); - return -EINVAL; + goto fail; } if (result==-EBUSY) { printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq); - return result; + goto fail; } if (result < 0) - return result; + goto fail; pci_set_master(dev); @@ -3744,11 +3799,16 @@ if (!(command&BT878_EN_TBFX)) { printk("bttv: 430FX compatibility could not be enabled\n"); - return -1; + result = -1; + goto fail; } } - return 0; + + fail: + release_mem_region(pci_resource_start(btv->dev,0), + pci_resource_len(btv->dev,0)); + return result; } static int find_bt848(void) @@ -3834,6 +3894,8 @@ if (radio[btv->nr] && btv->radio_dev.minor != -1) video_unregister_device(&btv->radio_dev); + release_mem_region(pci_resource_start(btv->dev,0), + pci_resource_len(btv->dev,0)); /* wake up any waiting processes because shutdown flag is set, no new processes (in this queue) are expected diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.3.99-pre2/linux/drivers/char/bttv.h Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/bttv.h Sun Mar 19 19:11:37 2000 @@ -21,7 +21,7 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,22) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,24) #include #include @@ -112,7 +112,8 @@ #define GBUFFER_GRABBING 1 #define GBUFFER_DONE 2 #define GBUFFER_ERROR 3 - + struct timeval tv; + u16 width; u16 height; u16 fmt; @@ -122,8 +123,7 @@ unsigned long re; }; -struct bttv -{ +struct bttv { struct video_device video_dev; struct video_device radio_dev; struct video_device vbi_dev; @@ -192,6 +192,9 @@ unsigned int last_field; /* number of last grabbed field */ int i2c_command; int triton1; + + int errors; + int needs_restart; WAIT_QUEUE gpioq; int shutdown; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.3.99-pre2/linux/drivers/char/busmouse.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/busmouse.c Wed Mar 22 22:22:05 2000 @@ -20,7 +20,6 @@ */ #include -#include #include #include #include @@ -48,8 +47,6 @@ */ /*#define BROKEN_MOUSE*/ -extern int sun_mouse_init(void); - struct busmouse_data { struct miscdevice miscdev; struct busmouse *ops; @@ -70,7 +67,13 @@ #define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev)) #define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE) +/* + * List of mice and guarding semaphore. You must take the semaphore + * before you take the misc device semaphore if you need both + */ + static struct busmouse_data *busmouse_data[NR_MICE]; +static DECLARE_MUTEX(mouse_sem); /* a mouse driver just has to interface with these functions * These are !!!OLD!!! Do not use!!! @@ -98,8 +101,7 @@ /* New interface. !!! Use this one !!! * These routines will most probably be called from interrupt. */ -void -busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons) +void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons) { struct busmouse_data *mse = busmouse_data[mousedev]; int changed; @@ -141,24 +143,21 @@ } } -void -busmouse_add_movement(int mousedev, int dx, int dy) +void busmouse_add_movement(int mousedev, int dx, int dy) { struct busmouse_data *mse = busmouse_data[mousedev]; busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons); } -void -busmouse_add_buttons(int mousedev, int clear, int eor) +void busmouse_add_buttons(int mousedev, int clear, int eor) { struct busmouse_data *mse = busmouse_data[mousedev]; busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor); } -static int -busmouse_fasync(int fd, struct file *filp, int on) +static int busmouse_fasync(int fd, struct file *filp, int on) { struct busmouse_data *mse = (struct busmouse_data *)filp->private_data; int retval; @@ -169,8 +168,7 @@ return 0; } -static int -busmouse_release(struct inode *inode, struct file *file) +static int busmouse_release(struct inode *inode, struct file *file) { struct busmouse_data *mse = (struct busmouse_data *)file->private_data; int ret = 0; @@ -190,33 +188,34 @@ return ret; } -static int -busmouse_open(struct inode *inode, struct file *file) +static int busmouse_open(struct inode *inode, struct file *file) { struct busmouse_data *mse; unsigned long flags; unsigned int mousedev; - int ret = 0; + int ret = -ENODEV; mousedev = DEV_TO_MOUSE(inode->i_rdev); if (mousedev >= NR_MICE) return -EINVAL; + + down(&mouse_sem); mse = busmouse_data[mousedev]; if (!mse) /* shouldn't happen, but... */ - return -ENODEV; - + goto end; + if (mse->ops && mse->ops->open) ret = mse->ops->open(inode, file); if (ret) - return ret; + goto end; file->private_data = mse; if (mse->active++) - return 0; + goto end; MOD_INC_USE_COUNT; @@ -231,18 +230,17 @@ mse->buttons = 7; spin_unlock_irqrestore(&mse->lock, flags); - - return 0; +end: + up(&mouse_sem); + return ret; } -static ssize_t -busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { return -EINVAL; } -static ssize_t -busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct busmouse_data *mse = (struct busmouse_data *)file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -328,8 +326,7 @@ return count; } -static unsigned int -busmouse_poll(struct file *file, poll_table *wait) +static unsigned int busmouse_poll(struct file *file, poll_table *wait) { struct busmouse_data *mse = (struct busmouse_data *)file->private_data; @@ -351,8 +348,16 @@ fasync: busmouse_fasync, }; -int -register_busmouse(struct busmouse *ops) +/** + * register_busmouse - register a bus mouse interface + * @ops: busmouse structure for the mouse + * + * Registers a mouse with the driver. The return is mouse number on + * success and a negative errno code on an error. The passed ops + * structure most not be freed until the mouser is unregistered + */ + +int register_busmouse(struct busmouse *ops) { unsigned int msedev = MINOR_TO_MOUSE(ops->minor); struct busmouse_data *mse; @@ -364,13 +369,18 @@ return -EINVAL; } - if (busmouse_data[msedev]) - return -EBUSY; - mse = kmalloc(sizeof(*mse), GFP_KERNEL); if (!mse) return -ENOMEM; + down(&mouse_sem); + if (busmouse_data[msedev]) + { + up(&mouse_sem); + kfree(mse); + return -EBUSY; + } + memset(mse, 0, sizeof(*mse)); mse->miscdev.minor = ops->minor; @@ -385,13 +395,23 @@ ret = misc_register(&mse->miscdev); if (!ret) ret = msedev; - + up(&mouse_sem); + return ret; } -int -unregister_busmouse(int mousedev) +/** + * unregister_busmouse - unregister a bus mouse interface + * @mousedev: Mouse number to release + * + * Unregister a previously installed mouse handler. The mousedev + * passed is the return code from a previous call to register_busmouse + */ + + +int unregister_busmouse(int mousedev) { + int err = -EINVAL; if (mousedev < 0) return 0; if (mousedev >= NR_MICE) { @@ -400,32 +420,27 @@ return -EINVAL; } + down(&mouse_sem); + if (!busmouse_data[mousedev]) { printk(KERN_WARNING "busmouse: trying to free free mouse" " on mousedev %d\n", mousedev); - return -EINVAL; + goto fail; } if (busmouse_data[mousedev]->active) { printk(KERN_ERR "busmouse: trying to free active mouse" " on mousedev %d\n", mousedev); - return -EINVAL; + goto fail; } - misc_deregister(&busmouse_data[mousedev]->miscdev); + err=misc_deregister(&busmouse_data[mousedev]->miscdev); kfree(busmouse_data[mousedev]); busmouse_data[mousedev] = NULL; - return 0; -} - -int __init -bus_mouse_init(void) -{ -#ifdef CONFIG_SUN_MOUSE - sun_mouse_init(); -#endif - return 0; +fail: + up(&mouse_sem); + return err; } EXPORT_SYMBOL(busmouse_add_movementbuttons); @@ -433,16 +448,3 @@ EXPORT_SYMBOL(busmouse_add_buttons); EXPORT_SYMBOL(register_busmouse); EXPORT_SYMBOL(unregister_busmouse); - -#ifdef MODULE -int -init_module(void) -{ - return bus_mouse_init(); -} - -void -cleanup_module(void) -{ -} -#endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/busmouse.h linux/drivers/char/busmouse.h --- v2.3.99-pre2/linux/drivers/char/busmouse.h Mon Aug 2 09:54:29 1999 +++ linux/drivers/char/busmouse.h Tue Mar 21 23:38:25 2000 @@ -23,6 +23,4 @@ extern int register_busmouse(struct busmouse *ops); extern int unregister_busmouse(int mousedev); -extern int bus_mouse_init(void); - #endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.3.99-pre2/linux/drivers/char/misc.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/misc.c Tue Mar 21 23:38:25 2000 @@ -57,6 +57,7 @@ * Head entry for the doubly linked miscdevice list */ static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list }; +static DECLARE_MUTEX(misc_sem); /* * Assigned numbers, used for dynamic minors @@ -96,32 +97,42 @@ static int misc_open(struct inode * inode, struct file * file) { int minor = MINOR(inode->i_rdev); - struct miscdevice *c = misc_list.next; + struct miscdevice *c; + int err = -ENODEV; + file->f_op = NULL; + + down(&misc_sem); + + c = misc_list.next; while ((c != &misc_list) && (c->minor != minor)) c = c->next; if (c == &misc_list) { char modname[20]; + up(&misc_sem); sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor); request_module(modname); + down(&misc_sem); c = misc_list.next; while ((c != &misc_list) && (c->minor != minor)) c = c->next; if (c == &misc_list) - return -ENODEV; + goto fail; } if ((file->f_op = c->fops) && file->f_op->open) - return file->f_op->open(inode,file); - else - return -ENODEV; + err=file->f_op->open(inode,file); +fail: + up(&misc_sem); + return err; } static struct file_operations misc_fops = { open: misc_open, }; + /** * misc_register - register a miscellaneous device * @misc: device structure @@ -144,12 +155,17 @@ if (misc->next || misc->prev) return -EBUSY; + down(&misc_sem); if (misc->minor == MISC_DYNAMIC_MINOR) { int i = DYNAMIC_MINORS; while (--i >= 0) if ( (misc_minors[i>>3] & (1 << (i&7))) == 0) break; - if (i<0) return -EBUSY; + if (i<0) + { + up(&misc_sem); + return -EBUSY; + } misc->minor = i; } if (misc->minor < DYNAMIC_MINORS) @@ -170,6 +186,7 @@ misc->next = misc_list.next; misc->prev->next = misc; misc->next->prev = misc; + up(&misc_sem); return 0; } @@ -188,6 +205,7 @@ int i = misc->minor; if (!misc->next || !misc->prev) return -EINVAL; + down(&misc_sem); misc->prev->next = misc->next; misc->next->prev = misc->prev; misc->next = NULL; @@ -196,6 +214,7 @@ if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } + up(&misc_sem); return 0; } @@ -205,9 +224,6 @@ int __init misc_init(void) { create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL); -#ifdef CONFIG_BUSMOUSE - bus_mouse_init(); -#endif #if defined CONFIG_82C710_MOUSE qpmouse_init(); #endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.3.99-pre2/linux/drivers/char/rtc.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/char/rtc.c Mon Mar 20 08:27:36 2000 @@ -670,10 +670,10 @@ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(year); /* This should never happen... */ - if (year > 10 && year < 44) { + if (year >= 20 && year < 48) { epoch = 1980; guess = "ARC console"; - } else if (year < 96) { + } else if (year >= 48 && year < 100) { epoch = 1952; guess = "Digital UNIX"; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.3.99-pre2/linux/drivers/char/serial.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/char/serial.c Wed Mar 22 22:23:55 2000 @@ -39,13 +39,17 @@ * * 8/99: Generalized PCI support added. Theodore Ts'o * + * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a + * few races on freeing buffers too. + * Alan Modra + * * This module exports the following rs232 io functions: * * int rs_init(void); */ -static char *serial_version = "4.92"; -static char *serial_revdate = "2000-1-27"; +static char *serial_version = "4.93"; +static char *serial_revdate = "2000-03-20"; /* * Serial driver configuration section. Here are the various options: @@ -98,7 +102,7 @@ #endif #endif -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) #ifndef ENABLE_SERIAL_PNP #define ENABLE_SERIAL_PNP #endif @@ -133,7 +137,7 @@ #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 256 -#if (defined(__i386__) && (CPU==386 || CPU==486)) +#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) #define SERIAL_INLINE #endif @@ -220,7 +224,6 @@ unsigned int minor); extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor); - static char *serial_name = "Serial driver"; static DECLARE_TASK_QUEUE(tq_serial); @@ -253,7 +256,7 @@ #endif static unsigned detect_uart_irq (struct serial_state * state); -static void autoconfig(struct serial_state * info); +static void autoconfig(struct serial_state * state); static void change_speed(struct async_struct *info, struct termios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -321,9 +324,6 @@ static struct termios *serial_termios[NR_PORTS]; static struct termios *serial_termios_locked[NR_PORTS]; -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ @@ -379,7 +379,7 @@ return inb(info->port+1); #endif case SERIAL_IO_MEM: - return readb(info->iomem_base + + return readb((unsigned long) info->iomem_base + (offset<iomem_reg_shift)); #ifdef CONFIG_SERIAL_GSC case SERIAL_IO_GSC: @@ -401,7 +401,7 @@ break; #endif case SERIAL_IO_MEM: - writeb(value, info->iomem_base + + writeb(value, (unsigned long) info->iomem_base + (offset<iomem_reg_shift)); break; #ifdef CONFIG_SERIAL_GSC @@ -481,7 +481,9 @@ return; save_flags(flags); cli(); - if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { + if (info->xmit.head != info->xmit.tail + && info->xmit.buf + && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; serial_out(info, UART_IER, info->IER); } @@ -633,7 +635,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) { int count; - + if (info->x_char) { serial_outp(info, UART_TX, info->x_char); info->state->icount.tx++; @@ -642,8 +644,9 @@ *intr_done = 0; return; } - if ((info->xmit_cnt <= 0) || info->tty->stopped || - info->tty->hw_stopped) { + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { info->IER &= ~UART_IER_THRI; serial_out(info, UART_IER, info->IER); return; @@ -651,14 +654,16 @@ count = info->xmit_fifo_size; do { - serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]); - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]); + info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); info->state->icount.tx++; - if (--info->xmit_cnt <= 0) + if (info->xmit.head == info->xmit.tail) break; } while (--count > 0); - if (info->xmit_cnt < WAKEUP_CHARS) + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); #ifdef SERIAL_DEBUG_INTR @@ -667,7 +672,7 @@ if (intr_done) *intr_done = 0; - if (info->xmit_cnt <= 0) { + if (info->xmit.head == info->xmit.tail) { info->IER &= ~UART_IER_THRI; serial_out(info, UART_IER, info->IER); } @@ -759,11 +764,11 @@ #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt(%d)...", irq); #endif - + info = IRQ_ports[irq]; if (!info) return; - + #ifdef CONFIG_SERIAL_MULTIPORT multi = &rs_multiport[irq]; if (multi->port_monitor) @@ -833,7 +838,7 @@ #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_single(%d)...", irq); #endif - + info = IRQ_ports[irq]; if (!info || !info->tty) return; @@ -888,7 +893,7 @@ #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_multi(%d)...", irq); #endif - + info = IRQ_ports[irq]; if (!info) return; @@ -1026,7 +1031,7 @@ serial_out(info, UART_IER, info->IER); info = info->next_port; } while (info); -#ifdef CONFIG_SERIAL_MULTIPORT +#ifdef CONFIG_SERIAL_MULTIPORT if (rs_multiport[i].port1) rs_interrupt_multi(i, NULL, NULL); else @@ -1117,10 +1122,10 @@ free_page(page); goto errout; } - if (info->xmit_buf) + if (info->xmit.buf) free_page(page); else - info->xmit_buf = (unsigned char *) page; + info->xmit.buf = (unsigned char *) page; #ifdef SERIAL_DEBUG_OPEN printk("starting up ttys%d (irq %d)...", info->line, state->irq); @@ -1298,7 +1303,7 @@ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + info->xmit.head = info->xmit.tail = 0; /* * Set up serial timers... @@ -1393,9 +1398,10 @@ free_irq(state->irq, &IRQ_ports[state->irq]); } - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); } info->IER = 0; @@ -1570,7 +1576,7 @@ * when DLL is 0. */ if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) && - (info->state->revision == 0x5202)) + (info->state->revision == 0x5201)) quot++; info->quot = quot; @@ -1654,7 +1660,7 @@ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } serial_outp(info, UART_FCR, fcr); /* set fcr */ - } + } restore_flags(flags); } @@ -1666,18 +1672,19 @@ if (serial_paranoia_check(info, tty->device, "rs_put_char")) return; - if (!tty || !info->xmit_buf) + if (!tty || !info->xmit.buf) return; save_flags(flags); cli(); - if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + if (CIRC_SPACE(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) == 0) { restore_flags(flags); return; } - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE-1; - info->xmit_cnt++; + info->xmit.buf[info->xmit.head] = ch; + info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); restore_flags(flags); } @@ -1689,8 +1696,10 @@ if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) return; - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) + if (info->xmit.head == info->xmit.tail + || tty->stopped + || tty->hw_stopped + || !info->xmit.buf) return; save_flags(flags); cli(); @@ -1709,16 +1718,19 @@ if (serial_paranoia_check(info, tty->device, "rs_write")) return 0; - if (!tty || !info->xmit_buf || !tmp_buf) + if (!tty || !info->xmit.buf || !tmp_buf) return 0; save_flags(flags); if (from_user) { down(&tmp_buf_sem); while (1) { - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (count < c) + c = count; if (c <= 0) break; @@ -1729,12 +1741,14 @@ break; } cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - info->xmit_head = ((info->xmit_head + c) & + c1 = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1)); - info->xmit_cnt += c; restore_flags(flags); buf += c; count -= c; @@ -1742,27 +1756,29 @@ } up(&tmp_buf_sem); } else { + cli(); while (1) { - cli(); - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (count < c) + c = count; if (c <= 0) { - restore_flags(flags); break; } - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = ((info->xmit_head + c) & + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1)); - info->xmit_cnt += c; - restore_flags(flags); buf += c; count -= c; ret += c; } + restore_flags(flags); } - if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && - !(info->IER & UART_IER_THRI)) { + if (info->xmit.head != info->xmit.tail + && !tty->stopped + && !tty->hw_stopped + && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; serial_out(info, UART_IER, info->IER); } @@ -1772,14 +1788,10 @@ static int rs_write_room(struct tty_struct *tty) { struct async_struct *info = (struct async_struct *)tty->driver_data; - int ret; - + if (serial_paranoia_check(info, tty->device, "rs_write_room")) return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); } static int rs_chars_in_buffer(struct tty_struct *tty) @@ -1788,7 +1800,7 @@ if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) return 0; - return info->xmit_cnt; + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); } static void rs_flush_buffer(struct tty_struct *tty) @@ -1799,7 +1811,7 @@ if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) return; save_flags(flags); cli(); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + info->xmit.head = info->xmit.tail = 0; restore_flags(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && @@ -2071,8 +2083,9 @@ * interrupt happens). */ if (info->x_char || - ((info->xmit_cnt > 0) && !info->tty->stopped && - !info->tty->hw_stopped)) + ((CIRC_CNT(info->xmit.head, info->xmit.tail, + SERIAL_XMIT_SIZE) > 0) && + !info->tty->stopped && !info->tty->hw_stopped)) result &= TIOCSER_TEMT; if (copy_to_user(value, &result, sizeof(int))) @@ -2708,8 +2721,8 @@ char_time = char_time / 5; if (char_time == 0) char_time = 1; - if (timeout) - char_time = MIN(char_time, timeout); + if (timeout && timeout < char_time) + char_time = timeout; /* * If the transmitter hasn't cleared in twice the approximate * amount of time to send the entire FIFO, it probably won't @@ -3060,7 +3073,7 @@ int ret; unsigned long flags; - ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", state->line, uart_config[state->type].name, state->port, state->irq); @@ -3083,9 +3096,9 @@ } save_flags(flags); cli(); status = serial_in(info, UART_MSR); - control = info ? info->MCR : serial_in(info, UART_MCR); + control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR); restore_flags(flags); - + stat_buf[0] = 0; stat_buf[1] = 0; if (control & UART_MCR_RTS) @@ -3403,7 +3416,7 @@ state->type = PORT_UNKNOWN; #ifdef SERIAL_DEBUG_AUTOCONF - printk("Testing ttyS%d (0x%04x, 0x%04x)...\n", state->line, + printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line, state->port, (unsigned) state->iomem_base); #endif @@ -3743,15 +3756,10 @@ /* enable/disable interrupts */ p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); - if (dev->vendor == PCI_VENDOR_ID_PANACOM) { - scratch = readl(p + 0x4c); - if (enable) - scratch |= 0x40; - else - scratch &= ~0x40; - writel(scratch, p + 0x4c); - } else - writel(enable ? 0x41 : 0x00, p + 0x4c); + scratch = 0x41; + if (dev->vendor == PCI_VENDOR_ID_PANACOM) + scratch = 0x43; + writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c); iounmap(p); if (!enable) @@ -3806,7 +3814,7 @@ break; } - writew(readw(p + 0x28) & data, p + 0x28); + writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28); iounmap(p); return 0; } @@ -4181,6 +4189,19 @@ { PCI_VENDOR_ID_USR, 0x1008, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0, 1, 115200 }, + /* Titan Electronic cards */ + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 2, 921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 4, 921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 4, 921600 }, /* * Untested PCI modems, sent in from various folks... */ @@ -4188,10 +4209,9 @@ { PCI_VENDOR_ID_ROCKWELL, 0x1004, 0x1048, 0x1500, SPCI_FL_BASE1, 1, 115200 }, -#ifdef CONFIG_DDB5074 +#if 0 /* No definition for PCI_DEVICE_ID_NEC_NILE4 */ /* * NEC Vrc-5074 (Nile 4) builtin UART. - * Conditionally compiled in since this is a motherboard device. */ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4, PCI_ANY_ID, PCI_ANY_ID, @@ -4306,18 +4326,41 @@ #ifdef ENABLE_SERIAL_PNP static struct pci_board pnp_devices[] __initdata = { + /* Motorola VoiceSURFR 56K Modem */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0, + SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, /* Rockwell 56K ACF II Fax+Data+Voice Modem */ { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0, + SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT, + 1, 115200 }, + /* AZT3005 PnP SOUND DEVICE */ + { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0, + SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + /* Best Data Products Inc. Smart One 336F PnP Modem */ + { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0, SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, /* Boca Research 33,600 ACF Modem */ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0, SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0, + /* Creative Modem Blaster Flash56 DI5601-1 */ + { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0, + SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + /* Creative Modem Blaster V.90 DI5660 */ + { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0, + SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + /* Pace 56 Voice Internal Plug & Play Modem */ + { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0, SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, /* SupraExpress 28.8 Data/Fax PnP modem */ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0, SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + /* US Robotics Sporster 33600 Modem */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0, + SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + /* U.S. Robotics 56K FAX INT */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0, + SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + /* These ID's are taken from M$ documentation */ /* Compaq 14400 Modem */ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0, @@ -4334,6 +4377,24 @@ { 0, } }; +static void inline avoid_irq_share(struct pci_dev *dev) +{ + int i, map = 0x1FF8; + struct serial_state *state = rs_table; + struct isapnp_irq *irq; + struct isapnp_resources *res = dev->sysdata; + + for (i = 0; i < NR_PORTS; i++) { + if (state->type != PORT_UNKNOWN) + clear_bit(state->irq, &map); + state++; + } + + for ( ; res; res = res->alt) + for(irq = res->irq; irq; irq = irq->next) + irq->map = map; +} + static void __init probe_serial_pnp(void) { struct pci_dev *dev = NULL; @@ -4352,9 +4413,9 @@ for (board = pnp_devices; board->vendor; board++) { while ((dev = isapnp_find_dev(NULL, board->vendor, board->device, dev))) { - - start_pci_pnp_board(dev, board); - + if (board->flags & SPCI_FL_NO_SHIRQ) + avoid_irq_share(dev); + start_pci_pnp_board(dev, board); } } @@ -4417,7 +4478,11 @@ #if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "serial"; #endif +#if (LINUX_VERSION_CODE > 0x2032D) serial_driver.name = "tts/%d"; +#else + serial_driver.name = "ttyS"; +#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; @@ -4461,7 +4526,11 @@ * major number and the subtype code. */ callout_driver = serial_driver; +#if (LINUX_VERSION_CODE > 0x2032D) callout_driver.name = "cua/%d"; +#else + callout_driver.name = "cua"; +#endif callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; #if (LINUX_VERSION_CODE >= 131343) @@ -4503,7 +4572,7 @@ && (state->flags & ASYNC_AUTO_IRQ) && (state->port != 0)) state->irq = detect_uart_irq(state); - printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n", + printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n", state->line + SERIAL_DEV_OFFSET, (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", state->port, state->irq, @@ -4538,7 +4607,7 @@ * The port is then probed and if neccessary the IRQ is autodetected * If this fails an error is returned. * - * On success the port is ready to use and the line number is returned. + * On success the port is ready to use and the line number is returned. */ int register_serial(struct serial_struct *req) @@ -4548,8 +4617,7 @@ struct serial_state *state; struct async_struct *info; - save_flags(flags); - cli(); + save_flags(flags); cli(); for (i = 0; i < NR_PORTS; i++) { if ((rs_table[i].port == req->port) && (rs_table[i].iomem_base == req->iomem_base)) @@ -4568,7 +4636,7 @@ state = &rs_table[i]; if (rs_table[i].count) { restore_flags(flags); - printk("Couldn't configure serial #%d (port=%d,irq=%d): " + printk("Couldn't configure serial #%d (port=%ld,irq=%d): " "device already open\n", i, req->port, req->irq); return -1; } @@ -4598,12 +4666,11 @@ if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state)) state->irq = detect_uart_irq(state); - printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n", + printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n", state->line + SERIAL_DEV_OFFSET, state->iomem_base ? "iomem" : "port", state->iomem_base ? (unsigned long)state->iomem_base : - (unsigned long)state->port, - state->irq, uart_config[state->type].name); + state->port, state->irq, uart_config[state->type].name); tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + state->line); tty_register_devfs(&callout_driver, 0, @@ -4625,8 +4692,7 @@ unsigned long flags; struct serial_state *state = &rs_table[line]; - save_flags(flags); - cli(); + save_flags(flags); cli(); if (state->info && state->info->tty) tty_hangup(state->info->tty); state->type = PORT_UNKNOWN; @@ -4642,12 +4708,7 @@ } #ifdef MODULE -int init_module(void) -{ - return rs_init(); -} - -void cleanup_module(void) +void rs_fini(void) { unsigned long flags; int e1, e2; @@ -4655,8 +4716,7 @@ struct async_struct *info; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - save_flags(flags); - cli(); + save_flags(flags); cli(); timer_active &= ~(1 << RS_TIMER); timer_table[RS_TIMER].fn = NULL; timer_table[RS_TIMER].expires = 0; @@ -4693,12 +4753,16 @@ } #endif if (tmp_buf) { - free_page((unsigned long) tmp_buf); + unsigned long pg = (unsigned long) tmp_buf; tmp_buf = NULL; + free_page(pg); } } #endif /* MODULE */ +module_init(rs_init); +module_exit(rs_fini); + /* * ------------------------------------------------------------ @@ -4960,6 +5024,6 @@ /* Local variables: - compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" End: */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c --- v2.3.99-pre2/linux/drivers/char/sysrq.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/char/sysrq.c Thu Mar 23 08:13:35 2000 @@ -28,7 +28,7 @@ extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; -extern struct vfsmount *vfsmntlist; +extern struct list_head super_blocks; /* Machine specific power off function */ void (*sysrq_power_off)(void) = NULL; @@ -174,22 +174,16 @@ } } -static void go_sync(kdev_t dev, int remount_flag) +static void go_sync(struct super_block *sb, int remount_flag) { printk(KERN_INFO "%sing device %s ... ", remount_flag ? "Remount" : "Sync", - kdevname(dev)); + kdevname(sb->s_dev)); if (remount_flag) { /* Remount R/O */ - struct super_block *sb = get_super(dev); - struct vfsmount *vfsmnt; int ret, flags; struct list_head *p; - if (!sb) { - printk("Superblock not found\n"); - return; - } if (sb->s_flags & MS_RDONLY) { printk("R/O\n"); return; @@ -204,7 +198,7 @@ } file_list_unlock(); DQUOT_OFF(sb); - fsync_dev(dev); + fsync_dev(sb->s_dev); flags = MS_RDONLY; if (sb->s_op && sb->s_op->remount_fs) { ret = sb->s_op->remount_fs(sb, &flags, NULL); @@ -217,7 +211,7 @@ } else printk("nothing to do\n"); } else { - fsync_dev(dev); /* Sync only */ + fsync_dev(sb->s_dev); /* Sync only */ printk("OK\n"); } } @@ -233,20 +227,24 @@ void do_emergency_sync(void) { - struct vfsmount *mnt; + struct super_block *sb; int remount_flag; lock_kernel(); remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT); emergency_sync_scheduled = 0; - for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) - if (is_local_disk(mnt->mnt_dev)) - go_sync(mnt->mnt_dev, remount_flag); - - for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) - if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev)) - go_sync(mnt->mnt_dev, remount_flag); + for (sb = sb_entry(super_blocks.next); + sb != sb_entry(&super_blocks); + sb = sb_entry(sb->s_list.next)) + if (is_local_disk(sb->s_dev)) + go_sync(sb, remount_flag); + + for (sb = sb_entry(super_blocks.next); + sb != sb_entry(&super_blocks); + sb = sb_entry(sb->s_list.next)) + if (!is_local_disk(sb->s_dev) && MAJOR(sb->s_dev)) + go_sync(sb, remount_flag); unlock_kernel(); printk(KERN_INFO "Done.\n"); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.99-pre2/linux/drivers/char/tty_io.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/tty_io.c Tue Mar 21 13:04:53 2000 @@ -2278,9 +2278,6 @@ #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ espserial_init(); #endif -#ifdef CONFIG_SERIAL - rs_init(); -#endif #if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) vme_scc_init(); #endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.3.99-pre2/linux/drivers/char/wdt.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/wdt.c Tue Mar 21 14:43:39 2000 @@ -159,10 +159,6 @@ * Handle an interrupt from the board. These are raised when the status * map changes in what the board considers an interesting way. That means * a failure condition occuring. - * - * FIXME: We need to pass a dev_id as the PCI card can share irqs - * although its arguably a _very_ dumb idea to share watchdog - * irq lines */ void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -494,7 +490,7 @@ int __init wdt_init(void) { printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); - if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL)) + if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", &wdt_miscdev)) { printk(KERN_ERR "IRQ %d is not free.\n", irq); return -EIO; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/i2c/i2c-algo-pcf.c linux/drivers/i2c/i2c-algo-pcf.c --- v2.3.99-pre2/linux/drivers/i2c/i2c-algo-pcf.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/i2c/i2c-algo-pcf.c Tue Mar 21 12:36:21 2000 @@ -581,7 +581,7 @@ return 0; } -static int __init i2c_algo_pcf_init (void) +int __init i2c_algo_pcf_init (void) { printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); return 0; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/Config.in linux/drivers/ide/Config.in --- v2.3.99-pre2/linux/drivers/ide/Config.in Sun Mar 19 18:35:30 2000 +++ linux/drivers/ide/Config.in Wed Mar 22 17:18:43 2000 @@ -38,11 +38,12 @@ dep_bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING $CONFIG_BLK_DEV_AEC6210 $CONFIG_IDEDMA_PCI_WIP dep_bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI + dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE $CONFIG_BLK_DEV_AMD7409 $CONFIG_IDEDMA_PCI_WIP dep_bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID $CONFIG_BLK_DEV_CMD64X $CONFIG_IDEDMA_PCI_WIP - dep_bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 $CONFIG_IDEDMA_PCI_EXPERIMENTAL + dep_bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP @@ -53,14 +54,14 @@ dep_mbool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO fi - dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_IDEDMA_PCI_EXPERIMENTAL + dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL dep_bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX dep_mbool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER $CONFIG_BLK_DEV_PDC202XX $CONFIG_IDEDMA_PCI_WIP dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 - dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_IDEDMA_PCI_EXPERIMENTAL - dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_IDEDMA_PCI_EXPERIMENTAL + dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/aec6210.c linux/drivers/ide/aec6210.c --- v2.3.99-pre2/linux/drivers/ide/aec6210.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/aec6210.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/aec6210.c Version 0.05 Feb. 10, 2000 + * linux/drivers/ide/aec6210.c Version 0.06 Mar. 18, 2000 * * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -191,6 +191,7 @@ return(err); } +#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) { struct hd_driveid *id = drive->id; @@ -230,6 +231,7 @@ ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); } +#endif /* CONFIG_BLK_DEV_IDEDMA */ static void aec6210_tune_drive (ide_drive_t *drive, byte pio) { @@ -252,6 +254,7 @@ (void) aec6210_tune_chipset(drive, speed); } +#ifdef CONFIG_BLK_DEV_IDEDMA static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -314,6 +317,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_AEC6210_TUNING */ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) @@ -336,13 +340,13 @@ { #ifdef CONFIG_AEC6210_TUNING hwif->tuneproc = &aec6210_tune_drive; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; - if (hwif->dma_base) { +#ifdef CONFIG_BLK_DEV_IDEDMA + if (hwif->dma_base) hwif->dmaproc = &aec6210_dmaproc; - } else { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - } +#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_AEC6210_TUNING */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ali14xx.c linux/drivers/ide/ali14xx.c --- v2.3.99-pre2/linux/drivers/ide/ali14xx.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ali14xx.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996 + * linux/drivers/ide/ali14xx.c Version 0.03 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c --- v2.3.99-pre2/linux/drivers/ide/alim15x3.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/alim15x3.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 + * linux/drivers/ide/alim15x3.c Version 0.09 Mar. 18, 2000 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer @@ -37,7 +37,7 @@ static int ali_get_info(char *buffer, char **addr, off_t offset, int count); extern int (*ali_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -struct pci_dev *bmide_dev; +static struct pci_dev *bmide_dev; char *fifo[4] = { "FIFO Off", @@ -67,7 +67,7 @@ "error DRQ busy" }; -static int ali_get_info(char *buffer, char **addr, off_t offset, int count) +static int ali_get_info (char *buffer, char **addr, off_t offset, int count) { byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1; unsigned int bibma; @@ -356,6 +356,12 @@ return (err); } +static void config_chipset_for_pio (ide_drive_t *drive) +{ + ali15x3_tune_drive(drive, 5); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33) { struct hd_driveid *id = drive->id; @@ -401,26 +407,21 @@ return rval; } -static void config_chipset_for_pio (ide_drive_t *drive) -{ - ali15x3_tune_drive(drive, 5); -} - - static byte ali15x3_can_ultra (ide_drive_t *drive) { +#ifdef CONFIG_WDC_ALI15X3 struct hd_driveid *id = drive->id; +#endif /* CONFIG_WDC_ALI15X3 */ -#if 0 - if (m5229_revision < 0x20) { -#else if (m5229_revision <= 0x20) { -#endif return 0; } else if ((m5229_revision < 0xC2) && - ((drive->media!=ide_disk) || - (chip_is_1543c_e && - strstr(id->model, "WDC ")))) { +#ifdef CONFIG_WDC_ALI15X3 + ((chip_is_1543c_e && strstr(id->model, "WDC ")) || + (drive->media!=ide_disk))) { +#else /* CONFIG_WDC_ALI15X3 */ + (drive->media!=ide_disk)) { +#endif /* CONFIG_WDC_ALI15X3 */ return 0; } else { return 1; @@ -495,6 +496,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) { @@ -519,9 +521,11 @@ } #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) - ali_proc = 1; - bmide_dev = dev; - ali_display_info = &ali_get_info; + if (!ali_proc) { + ali_proc = 1; + bmide_dev = dev; + ali_display_info = &ali_get_info; + } #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ return 0; @@ -666,18 +670,20 @@ } hwif->tuneproc = &ali15x3_tune_drive; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; +#ifndef CONFIG_BLK_DEV_IDEDMA + hwif->autodma = 0; + return; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + if ((hwif->dma_base) && (m5229_revision >= 0x20)) { /* * M1543C or newer for DMAing */ hwif->dmaproc = &ali15x3_dmaproc; hwif->autodma = 1; - } else { - hwif->autodma = 0; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; } - return; } void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/amd7409.c linux/drivers/ide/amd7409.c --- v2.3.99-pre2/linux/drivers/ide/amd7409.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/amd7409.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/amd7409.c Version 0.03 Feb. 10, 2000 + * linux/drivers/ide/amd7409.c Version 0.04 Mar. 18, 2000 * * Copyright (C) 2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -194,49 +194,6 @@ 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. - */ -static int config_chipset_for_dma (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - byte udma_66 = ((id->hw_config & 0x2000) && - (HWIF(drive)->udma_four)) ? 1 : 0; - byte speed = 0x00; - int rval; - - if ((id->dma_ultra & 0x0010) && (udma_66)) { - speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (udma_66)) { - speed = XFER_UDMA_3; - } else if (id->dma_ultra & 0x0004) { - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); - } - - (void) amd7409_tune_chipset(drive, speed); - - rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); - - return rval; -} - static void config_chipset_for_pio (ide_drive_t *drive) { unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; @@ -288,6 +245,52 @@ (void) amd7409_tune_chipset(drive, speed); } +#ifdef CONFIG_BLK_DEV_IDEDMA +/* + * 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. + */ +static int config_chipset_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte udma_66 = ((id->hw_config & 0x2000) && + (HWIF(drive)->udma_four)) ? 1 : 0; + byte speed = 0x00; + int rval; + + if ((id->dma_ultra & 0x0010) && (udma_66)) { + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (udma_66)) { + speed = XFER_UDMA_3; + } else if (id->dma_ultra & 0x0004) { + speed = XFER_UDMA_2; + } else if (id->dma_ultra & 0x0002) { + speed = XFER_UDMA_1; + } else if (id->dma_ultra & 0x0001) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + (void) amd7409_tune_chipset(drive, speed); + + rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); + + return rval; +} + + + static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -351,6 +354,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name) { @@ -370,9 +374,11 @@ printk("%s: simplex device: DMA will fail!!\n", name); } #if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) - amd7409_proc = 1; - bmide_dev = dev; - amd7409_display_info = &amd7409_get_info; + if (!amd7409_proc) { + amd7409_proc = 1; + bmide_dev = dev; + amd7409_display_info = &amd7409_get_info; + } #endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */ return 0; @@ -396,8 +402,17 @@ void __init ide_init_amd7409 (ide_hwif_t *hwif) { hwif->tuneproc = &amd7409_tune_drive; + +#ifndef CONFIG_BLK_DEV_IDEDMA + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; + return; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (hwif->dma_base) { hwif->dmaproc = &amd7409_dmaproc; + hwif->autodma = 1; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/buddha.c linux/drivers/ide/buddha.c --- v2.3.99-pre2/linux/drivers/ide/buddha.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/buddha.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/buddha.c -- Amiga Buddha and Catweasel IDE Driver + * linux/drivers/ide/buddha.c -- Amiga Buddha and Catweasel IDE Driver * * Copyright (C) 1997 by Geert Uytterhoeven * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/cmd640.c linux/drivers/ide/cmd640.c --- v2.3.99-pre2/linux/drivers/ide/cmd640.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/cmd640.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 + * linux/drivers/ide/cmd640.c Version 1.02 Sep 01, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/cmd64x.c linux/drivers/ide/cmd64x.c --- v2.3.99-pre2/linux/drivers/ide/cmd64x.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/ide/cmd64x.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,7 @@ /* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 * + * linux/drivers/ide/cmd64x.c Version 1.21 Mar. 18, 2000 + * * cmd64x.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. @@ -116,19 +118,27 @@ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); p += sprintf(p, " %sabled %sabled\n", - (reg72&0x80) ? "dis" : " en", (reg7a&0x80) ? "dis" : " en"); + (reg72&0x80)?"dis":" en",(reg7a&0x80)?"dis":" en"); p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (reg72&0x20) ? "yes" : "no ", (reg72&0x40) ? "yes" : "no ", (reg7a&0x20) ? "yes" : "no ", (reg7a&0x40) ? "yes" : "no " ); + (reg72&0x20)?"yes":"no ",(reg72&0x40)?"yes":"no ",(reg7a&0x20)?"yes":"no ",(reg7a&0x40)?"yes":"no "); p += sprintf(p, "DMA Mode: %s(%s) %s(%s) %s(%s) %s(%s)\n", (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO", - (reg72&0x20)?(((reg73&0x15)==0x15)?"4":((reg73&0x25)==0x25)?"3":((reg73&0x10)==0x10)?"2":((reg73&0x20)==0x20)?"1":((reg73&0x30)==0x30)?"0":"X"):"?", + (reg72&0x20)?( ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"): + ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"): + ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):"X"):"?", (reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO", - (reg72&0x40)?(((reg73&0x4A)==0x4A)?"4":((reg73&0x8A)==0x8A)?"3":((reg73&0x40)==0x40)?"2":((reg73&0x80)==0x80)?"1":((reg73&0xC0)==0xC0)?"0":"X"):"?", + (reg72&0x40)?( ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"): + ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"): + ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):"X"):"?", (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO", - (reg7a&0x20)?(((reg7b&0x15)==0x15)?"4":((reg7b&0x25)==0x25)?"3":((reg7b&0x10)==0x10)?"2":((reg7b&0x20)==0x20)?"1":((reg7b&0x30)==0x30)?"0":"X"):"?", + (reg7a&0x20)?( ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"): + ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"): + ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):"X"):"?", (reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO", - (reg7a&0x40)?(((reg7b&0x4A)==0x4A)?"4":((reg7b&0x8A)==0x8A)?"3":((reg7b&0x40)==0x40)?"2":((reg7b&0x80)==0x80)?"1":((reg7b&0xC0)==0xC0)?"0":"X"):"?" ); + (reg7a&0x40)?( ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"): + ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"): + ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):"X"):"?" ); p += sprintf(p, "PIO Mode: %s %s %s %s\n", "?", "?", "?", "?"); @@ -155,6 +165,22 @@ return p-buffer; /* => must be less than 4k! */ } + +#if 0 +static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev) +{ + char *p = buf; + p += sprintf(p, "thingy stuff\n"); + return (char *)p; +} +static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + p = cmd64x_chipset_data(buffer, bmide_dev); + return p-buffer; /* hoping it is less than 4K... */ +} +#endif + #endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */ byte cmd64x_proc = 0; @@ -305,76 +331,60 @@ setup_count, active_count, recovery_count); } +static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + byte speed= 0x00; + byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL); + + cmd64x_tuneproc(drive, set_pio); + speed = XFER_PIO_0 + set_pio; + if (set_speed) + (void) ide_config_drive_speed(drive, speed); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA static int tune_chipset_for_dma (ide_drive_t *drive, byte speed) { -#if 0 - struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); + int err = 0; - u8 reg72 = 0, reg73 = 0; /* primary */ - u8 reg7a = 0, reg7b = 0; /* secondary */ - u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; - u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; - u8 regU = (hwif->channel) ? 2 : 0; - u8 regD = (hwif->channel) ? 2 : 0; - - (void) pci_read_config_byte(dev, BMIDESR0, ®72); - (void) pci_read_config_byte(dev, UDIDETCR0, ®73); - (void) pci_read_config_byte(dev, BMIDESR1, ®7a); - (void) pci_read_config_byte(dev, UDIDETCR1, ®7b); + u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; + u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; + u8 regU = 0; + u8 regD = 0; + + (void) pci_read_config_byte(dev, pciD, ®D); + (void) pci_read_config_byte(dev, pciU, ®U); + regD &= ~(unit ? 0x40 : 0x20); + regU &= ~(unit ? 0xCA : 0x35); + (void) pci_write_config_byte(dev, pciD, regD); + (void) pci_write_config_byte(dev, pciU, regU); + (void) pci_read_config_byte(dev, pciD, ®D); + (void) pci_read_config_byte(dev, pciU, ®U); switch(speed) { - case XFER_UDMA_4: - pciU = unit ? 0x4A : 0x15; - case XFER_UDMA_3: - pciU = unit ? 0x8A : 0x25; - case XFER_UDMA_2: - pciU = unit ? 0x42 : 0x11; - case XFER_UDMA_1: - pciU = unit ? 0x82 : 0x21; - case XFER_UDMA_0: - pciU = unit ? 0xC2 : 0x31 -(reg73&0x15)?"4":(reg73&0x25)?"3":(reg73&0x11)?"2":(reg73&0x21)?"1":(reg73&0x31)?"0":"X", -(reg73&0x4A)?"4":(reg73&0x8A)?"3":(reg73&0x42)?"2":(reg73&0x82)?"1":(reg73&0xC2)?"0":"X", -(reg7b&0x15)?"4":(reg7b&0x25)?"3":(reg7b&0x11)?"2":(reg7b&0x21)?"1":(reg7b&0x31)?"0":"X", -(reg7b&0x4A)?"4":(reg7b&0x8A)?"3":(reg7b&0x42)?"2":(reg7b&0x82)?"1":(reg7b&0xC2)?"0":"X", - - case XFER_MW_DMA_2: - pciD = unit ? 0x40 : 0x10; - case XFER_MW_DMA_1: - pciD = unit ? 0x80 : 0x20; - case XFER_MW_DMA_0: - pciD = unit ? 0xC0 : 0x30; - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: -(reg73&0x10)?"2":(reg73&0x20)?"1":(reg73&0x30)?"0":"X", -(reg73&0x40)?"2":(reg73&0x80)?"1":(reg73&0xC0)?"0":"X", -(reg7b&0x10)?"2":(reg7b&0x20)?"1":(reg7b&0x30)?"0":"X", -(reg7b&0x40)?"2":(reg7b&0x80)?"1":(reg7b&0xC0)?"0":"X" ); - + case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break; + case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break; + case XFER_UDMA_2: regU |= (unit ? 0x42 : 0x11); break; + case XFER_UDMA_1: regU |= (unit ? 0x82 : 0x21); break; + case XFER_UDMA_0: regU |= (unit ? 0xC2 : 0x31); break; + case XFER_MW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; + case XFER_MW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; + case XFER_MW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; + case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; + case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; + case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; default: return 1; } + (void) pci_write_config_byte(dev, pciU, regU); + err = ide_config_drive_speed(drive, speed); + regD |= (unit ? 0x40 : 0x20); + (void) pci_write_config_byte(dev, pciD, regD); - (void) ide_config_drive_speed(drive, speed); - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); -#endif - return 0; -} - -static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) -{ - byte speed = 0x00; - byte set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL); - - cmd64x_tuneproc(drive, set_pio); - speed = XFER_PIO_0 + set_pio; - if (set_speed) - (void) ide_config_drive_speed(drive, speed); + return err; } static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) @@ -382,21 +392,17 @@ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - unsigned long dma_base = hwif->dma_base; - byte unit = (drive->select.b.unit & 0x01); byte speed = 0x00; byte set_pio = 0x00; - byte udma_timing_bits = 0x00; byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0; byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; - /* int drive_number = ((hwif->channel ? 2 : 0) + unit); */ int rval; switch(dev->device) { - case PCI_DEVICE_ID_CMD_643: - case PCI_DEVICE_ID_CMD_646: case PCI_DEVICE_ID_CMD_648: + case PCI_DEVICE_ID_CMD_646: + case PCI_DEVICE_ID_CMD_643: default: break; } @@ -416,22 +422,16 @@ * in the 646U2. * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. */ - if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { speed = XFER_UDMA_4; - udma_timing_bits = 0x10; /* 2 clock */ } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) { speed = XFER_UDMA_3; - udma_timing_bits = 0x20; /* 3 clock */ } else if ((id->dma_ultra & 0x0004) && (udma_33)) { speed = XFER_UDMA_2; - udma_timing_bits = 0x10; /* 2 clock */ } else if ((id->dma_ultra & 0x0002) && (udma_33)) { speed = XFER_UDMA_1; - udma_timing_bits = 0x20; /* 3 clock */ } else if ((id->dma_ultra & 0x0001) && (udma_33)) { speed = XFER_UDMA_0; - udma_timing_bits = 0x30; /* 4 clock */ } else if (id->dma_mword & 0x0004) { speed = XFER_MW_DMA_2; } else if (id->dma_mword & 0x0002) { @@ -453,27 +453,6 @@ if (set_pio) return ((int) ide_dma_off_quietly); -#if 1 - /* - * This the alternate access method. :-( - * The correct method is to directly setup the pci-config space. - */ - (void) ide_config_drive_speed(drive, speed); - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - - if (speed >= XFER_UDMA_0) { - byte udma_ctrl = inb(dma_base + 3); - /* Put this channel into UDMA mode. */ - udma_ctrl |= (1 << unit); - udma_ctrl &= ~(0x04 << unit); - if (udma_66) - udma_ctrl |= (0x04 << unit); - udma_ctrl &= ~(0x30 << (unit * 2)); - udma_ctrl |= (udma_timing_bits << (unit * 2)); - outb(udma_ctrl, dma_base+3); - } -#endif - if (tune_chipset_for_dma(drive, speed)) return ((int) ide_dma_off); @@ -500,17 +479,14 @@ class_rev &= 0xff; switch(dev->device) { + case PCI_DEVICE_ID_CMD_648: + can_ultra_66 = 1; case PCI_DEVICE_ID_CMD_643: - can_ultra_33 = 1; - can_ultra_66 = 0; + can_ultra_33 = 1; break; case PCI_DEVICE_ID_CMD_646: - can_ultra_33 = (class_rev >= 0x05) ? 1 : 0; - can_ultra_66 = 0; - break; - case PCI_DEVICE_ID_CMD_648: - can_ultra_33 = 1; - can_ultra_66 = 1; + can_ultra_33 = (class_rev >= 0x05) ? 1 : 0; + can_ultra_66 = 0; break; default: return hwif->dmaproc(ide_dma_off, drive); @@ -595,6 +571,7 @@ /* Other cases are done by generic IDE-DMA code. */ return cmd64x_dmaproc(func, drive); } +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) { @@ -604,9 +581,11 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; -#if 0 - if (dev->resource[PCI_ROM_RESOURCE].start) +#ifdef __i386__ + if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); + } #endif switch(dev->device) { @@ -702,7 +681,9 @@ if (!hwif->dma_base) return; +#ifdef CONFIG_BLK_DEV_IDEDMA switch(dev->device) { + case PCI_DEVICE_ID_CMD_648: case PCI_DEVICE_ID_CMD_643: hwif->dmaproc = &cmd64x_dmaproc; break; @@ -714,10 +695,8 @@ hwif->dmaproc = &cmd64x_dmaproc; } break; - case PCI_DEVICE_ID_CMD_648: - hwif->dmaproc = &cmd64x_dmaproc; - break; default: break; } +#endif /* CONFIG_BLK_DEV_IDEDMA */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/cs5530.c linux/drivers/ide/cs5530.c --- v2.3.99-pre2/linux/drivers/ide/cs5530.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/cs5530.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,8 @@ /* - * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 + * linux/drivers/ide/cs5530.c Version 0.6 Mar. 18, 2000 + * + * Copyright (C) 2000 Andre Hedrick + * Ditto of GNU General Public License. * * Copyright (C) 2000 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -23,6 +26,7 @@ #include #include #include + #include "ide_modes.h" #define DISPLAY_CS5530_TIMINGS @@ -120,6 +124,7 @@ } } +#ifdef CONFIG_BLK_DEV_IDEDMA /* * cs5530_config_dma() handles selection/setting of DMA/UDMA modes * for both the chipset and drive. @@ -241,6 +246,7 @@ /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } +#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Initialize the cs5530 bridge for reliable IDE DMA operation. @@ -322,9 +328,11 @@ restore_flags(flags); #if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) - cs5530_proc = 1; - bmide_dev = dev; - cs5530_display_info = &cs5530_get_info; + if (!cs5530_proc) { + cs5530_proc = 1; + bmide_dev = dev; + cs5530_display_info = &cs5530_get_info; + } #endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ return 0; @@ -343,7 +351,12 @@ } else { unsigned int basereg, d0_timings; +#ifdef CONFIG_BLK_DEV_IDEDMA hwif->dmaproc = &cs5530_dmaproc; +#else + hwif->autodma = 0; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + hwif->tuneproc = &cs5530_tuneproc; basereg = CS5530_BASEREG(hwif); d0_timings = inl(basereg+0); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/cy82c693.c linux/drivers/ide/cy82c693.c --- v2.3.99-pre2/linux/drivers/ide/cy82c693.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/cy82c693.c Wed Mar 22 22:22:05 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 + * linux/drivers/ide/cy82c693.c Version 0.34 Dec. 13, 1999 * * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-99 Andre Hedrick, Integrater @@ -44,6 +44,7 @@ * */ +#include #include #include #include @@ -176,6 +177,7 @@ p_pclk->time_8 = (byte)clk1; } +#ifdef CONFIG_BLK_DEV_IDEDMA /* * set DMA mode a specific channel for CY82C693 */ @@ -262,6 +264,7 @@ } return ide_dmaproc(func, drive); } +#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * tune ide drive - set PIO mode @@ -432,10 +435,14 @@ { hwif->chipset = ide_cy82c693; hwif->tuneproc = &cy82c693_tune_drive; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; + +#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &cy82c693_dmaproc; - } else { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; + hwif->autodma = 1; } +#endif /* CONFIG_BLK_DEV_IDEDMA */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/dtc2278.c linux/drivers/ide/dtc2278.c --- v2.3.99-pre2/linux/drivers/ide/dtc2278.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/dtc2278.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996 + * linux/drivers/ide/dtc2278.c Version 0.02 Feb 10, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/falconide.c linux/drivers/ide/falconide.c --- v2.3.99-pre2/linux/drivers/ide/falconide.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/falconide.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/falconide.c -- Atari Falcon IDE Driver + * linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver * * Created 12 Jul 1997 by Geert Uytterhoeven * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/gayle.c linux/drivers/ide/gayle.c --- v2.3.99-pre2/linux/drivers/ide/gayle.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/gayle.c Wed Mar 22 17:18:43 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/gayle.c -- Amiga Gayle IDE Driver + * linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver * * Created 9 Jul 1997 by Geert Uytterhoeven * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/hd.c linux/drivers/ide/hd.c --- v2.3.99-pre2/linux/drivers/ide/hd.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/hd.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/hd.c + * linux/drivers/ide/hd.c * * Copyright (C) 1991, 1992 Linus Torvalds */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/hpt34x.c linux/drivers/ide/hpt34x.c --- v2.3.99-pre2/linux/drivers/ide/hpt34x.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/hpt34x.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/hpt34x.c Version 0.29 Feb. 10, 2000 + * linux/drivers/ide/hpt34x.c Version 0.30 Mar. 18, 2000 * * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -144,6 +144,59 @@ return(err); } +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; + + 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; + } + hpt34x_clear_chipset(drive); + (void) hpt34x_tune_chipset(drive, speed); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities @@ -195,58 +248,6 @@ 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; - - 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; - } - hpt34x_clear_chipset(drive); - (void) hpt34x_tune_chipset(drive, speed); -} - static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -347,6 +348,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * If the BIOS does not set the IO base addaress to XX00, 343 will fail. @@ -395,9 +397,11 @@ __restore_flags(flags); /* local CPU only */ #if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) - hpt34x_proc = 1; - bmide_dev = dev; - hpt34x_display_info = &hpt34x_get_info; + if (!hpt34x_proc) { + hpt34x_proc = 1; + bmide_dev = dev; + hpt34x_display_info = &hpt34x_get_info; + } #endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */ return dev->irq; @@ -406,6 +410,8 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif) { hwif->tuneproc = &hpt34x_tune_drive; + +#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { unsigned short pcicmd = 0; @@ -416,4 +422,9 @@ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } +#else /* !CONFIG_BLK_DEV_IDEDMA */ + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; +#endif /* CONFIG_BLK_DEV_IDEDMA */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c --- v2.3.99-pre2/linux/drivers/ide/hpt366.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/hpt366.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/hpt366.c Version 0.16 Feb. 10, 2000 + * linux/drivers/ide/hpt366.c Version 0.17 Mar. 18, 2000 * * Copyright (C) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -259,6 +259,64 @@ return(err); } +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; + +#if HPT366_DEBUG_DRIVE_INFO + printk("%s: config_chipset_for_pio\n", drive->name); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + + if (xfer_pio> 4) + 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 : + (drive->id->tPIO & 2) ? 0x02 : + (drive->id->tPIO & 1) ? 0x01 : 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; + } +#if HPT366_DEBUG_DRIVE_INFO + printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + (void) hpt366_tune_chipset(drive, speed); +} + +static void hpt366_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + 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) hpt366_tune_chipset(drive, speed); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities @@ -347,63 +405,6 @@ return rval; } -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; - -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: config_chipset_for_pio\n", drive->name); -#endif /* HPT366_DEBUG_DRIVE_INFO */ - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio> 4) - 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 : - (drive->id->tPIO & 2) ? 0x02 : - (drive->id->tPIO & 1) ? 0x01 : 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; - } -#if HPT366_DEBUG_DRIVE_INFO - printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed); -#endif /* HPT366_DEBUG_DRIVE_INFO */ - (void) hpt366_tune_chipset(drive, speed); -} - -static void hpt366_tune_drive (ide_drive_t *drive, byte pio) -{ - byte speed; - 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) hpt366_tune_chipset(drive, speed); -} - static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -478,6 +479,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) { @@ -532,13 +534,20 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif) { hwif->tuneproc = &hpt366_tune_drive; +#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &hpt366_dmaproc; + hwif->autodma = 1; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } +#else /* !CONFIG_BLK_DEV_IDEDMA */ + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; +#endif /* CONFIG_BLK_DEV_IDEDMA */ } void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ht6560b.c linux/drivers/ide/ht6560b.c --- v2.3.99-pre2/linux/drivers/ide/ht6560b.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ht6560b.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ht6560b.c Version 0.07 Feb 1, 2000 + * linux/drivers/ide/ht6560b.c Version 0.07 Feb 1, 2000 * * Copyright (C) 1995-2000 Linus Torvalds & author (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/icside.c linux/drivers/ide/icside.c --- v2.3.99-pre2/linux/drivers/ide/icside.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/icside.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/icside.c + * linux/drivers/ide/icside.c * * Copyright (c) 1996,1997 Russell King. * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- v2.3.99-pre2/linux/drivers/ide/ide-cd.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-cd.c Wed Mar 22 22:22:05 2000 @@ -1,5 +1,6 @@ /* - * linux/drivers/block/ide-cd.c + * linux/drivers/ide/ide-cd.c + * * Copyright (C) 1994, 1995, 1996 scott snyder * Copyright (C) 1996-1998 Erik Andersen * Copyright (C) 1998, 1999 Jens Axboe @@ -276,6 +277,7 @@ #define IDECD_VERSION "4.56" +#include #include #include #include @@ -2400,21 +2402,10 @@ printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size)); - if (drive->using_dma) { - if ((drive->id->field_valid & 4) && - (drive->id->hw_config & 0x2000) && - (HWIF(drive)->udma_four) && - (drive->id->dma_ultra & (drive->id->dma_ultra >> 11) & 3)) { - printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ - } else if ((drive->id->field_valid & 4) && - (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) { - printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ - } else if (drive->id->field_valid & 4) { - printk(", (U)DMA"); /* Can be BIOS-enabled! */ - } else { - printk(", DMA"); - } - } +#ifdef CONFIG_BLK_DEV_IDEDMA + if (drive->using_dma) + (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive); +#endif /* CONFIG_BLK_DEV_IDEDMA */ printk("\n"); return nslots; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h --- v2.3.99-pre2/linux/drivers/ide/ide-cd.h Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-cd.h Thu Mar 23 15:38:23 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide_cd.h + * linux/drivers/ide/ide_cd.h * * Copyright (C) 1996-98 Erik Andersen * Copyright (C) 1998-2000 Jens Axboe diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c --- v2.3.99-pre2/linux/drivers/ide/ide-disk.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-disk.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 + * linux/drivers/ide/ide-disk.c Version 1.09 April 23, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -821,21 +821,10 @@ drive->name, id->model, capacity/2048L, id->buf_size/2, drive->bios_cyl, drive->bios_head, drive->bios_sect); - - if (drive->using_dma) { - if ((id->field_valid & 4) && (id->hw_config & 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)) { - printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ - } else if (id->field_valid & 4) { - printk(", (U)DMA"); /* Can be BIOS-enabled! */ - } else { - printk(", DMA"); - } - } +#ifdef CONFIG_BLK_DEV_IDEDMA + if (drive->using_dma) + (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive); +#endif /* CONFIG_BLK_DEV_IDEDMA */ printk("\n"); drive->mult_count = 0; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c --- v2.3.99-pre2/linux/drivers/ide/ide-dma.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-dma.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * linux/drivers/ide/ide-dma.c Version 4.09 April 23, 1999 * * Copyright (c) 1999 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -354,6 +354,29 @@ return 0; } +int report_drive_dmaing (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + + if ((id->field_valid & 4) && (id->hw_config & 0x2000) && + (HWIF(drive)->udma_four) && + (id->dma_ultra & (id->dma_ultra >> 11) & 3)) { + if ((id->dma_ultra >> 12) & 1) { + printk(", UDMA(66)"); /* UDMA BIOS-enabled! */ + } else { + printk(", UDMA(44)"); /* UDMA BIOS-enabled! */ + } + } else if ((id->field_valid & 4) && + (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { + printk(", UDMA(33)"); /* UDMA BIOS-enabled! */ + } else if (id->field_valid & 4) { + printk(", (U)DMA"); /* Can be BIOS-enabled! */ + } else { + printk(", DMA"); + } + return 1; +} + static int config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -453,6 +476,9 @@ case ide_dma_bad_drive: case ide_dma_good_drive: return check_drive_lists(drive, (func == ide_dma_good_drive)); + case ide_dma_verbose: + return report_drive_dmaing(drive); + case ide_dma_retune: case ide_dma_lostirq: case ide_dma_timeout: printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c --- v2.3.99-pre2/linux/drivers/ide/ide-features.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-features.c Wed Mar 22 17:18:44 2000 @@ -100,6 +100,8 @@ case ide_dma_test_irq: return("ide_dma_test_irq"); case ide_dma_bad_drive: return("ide_dma_bad_drive"); case ide_dma_good_drive: return("ide_dma_good_drive"); + case ide_dma_verbose: return("ide_dma_verbose"); + case ide_dma_retune: return("ide_dma_retune"); case ide_dma_lostirq: return("ide_dma_lostirq"); case ide_dma_timeout: return("ide_dma_timeout"); default: return("unknown"); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c --- v2.3.99-pre2/linux/drivers/ide/ide-floppy.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-floppy.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 + * linux/drivers/ide/ide-floppy.c Version 0.9 Jul 4, 1999 * * Copyright (C) 1996 - 1999 Gadi Oxman */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-geometry.c linux/drivers/ide/ide-geometry.c --- v2.3.99-pre2/linux/drivers/ide/ide-geometry.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/ide/ide-geometry.c Wed Mar 22 17:18:44 2000 @@ -1,9 +1,9 @@ /* - * linux/drivers/block/ide-geometry.c + * linux/drivers/ide/ide-geometry.c */ #include -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +#ifdef CONFIG_IDE #include #include @@ -211,4 +211,4 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); return ret; } -#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */ +#endif /* CONFIG_IDE */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c --- v2.3.99-pre2/linux/drivers/ide/ide-pci.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-pci.c Wed Mar 22 17:18:44 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 + * linux/drivers/ide/ide-pci.c Version 1.04 July 27, 1999 * - * Copyright (c) 1998-1999 Andre Hedrick + * Copyright (c) 1998-2000 Andre Hedrick * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c --- v2.3.99-pre2/linux/drivers/ide/ide-pmac.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-pmac.c Wed Mar 22 17:18:44 2000 @@ -1,4 +1,6 @@ /* + * linux/drivers/ide/ide-pmac.c Version ?.?? Mar. 18, 2000 + * * Support for IDE interfaces on PowerMacs. * These IDE interfaces are memory-mapped and have a DBDMA channel * for doing DMA. @@ -10,7 +12,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Some code taken from drivers/block/ide-dma.c: + * Some code taken from drivers/ide/ide-dma.c: * * Copyright (c) 1995-1998 Mark Lord * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c --- v2.3.99-pre2/linux/drivers/ide/ide-pnp.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-pnp.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-pnp.c + * linux/drivers/ide/ide-pnp.c * * This file provides autodetection for ISA PnP IDE interfaces. * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface. diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c --- v2.3.99-pre2/linux/drivers/ide/ide-probe.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/ide/ide-probe.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 + * linux/drivers/ide/ide-probe.c Version 1.05 July 3, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c --- v2.3.99-pre2/linux/drivers/ide/ide-proc.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-proc.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 + * linux/drivers/ide/ide-proc.c Version 1.03 January 2, 1998 * * Copyright (C) 1997-1998 Mark Lord */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c --- v2.3.99-pre2/linux/drivers/ide/ide-tape.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide-tape.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 + * linux/drivers/ide/ide-tape.c Version 1.16f Dec 15, 1999 * * Copyright (C) 1995 - 1999 Gadi Oxman * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.3.99-pre2/linux/drivers/ide/ide.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.30 Dec 28, 1999 + * linux/drivers/ide/ide.c Version 6.30 Dec 28, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -1809,9 +1809,9 @@ static void ide_probe_module (void) { if (!ide_probe) { -#ifdef CONFIG_KMOD +#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE) (void) request_module("ide-probe-mod"); -#endif /* CONFIG_KMOD */ +#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */ } else { (void) ide_probe->init(); } @@ -2491,6 +2491,30 @@ return 0; } + case HDIO_GETGEO_BIG: + { + struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; + if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; + if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; + if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; + if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; + if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, + (unsigned long *) &loc->start)) return -EFAULT; + return 0; + } + + case HDIO_GETGEO_BIG_RAW: + { + struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; + if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; + if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT; + if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT; + if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; + if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, + (unsigned long *) &loc->start)) return -EFAULT; + return 0; + } + case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); @@ -2564,8 +2588,7 @@ } case HDIO_UNREGISTER_HWIF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - /* should I check here for arg > MAX_HWIFS, or - just let ide_unregister fail silently? -- shaver */ + /* (arg > MAX_HWIFS) checked in function */ ide_unregister(arg); return 0; case HDIO_SET_NICE: diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ide_modes.h linux/drivers/ide/ide_modes.h --- v2.3.99-pre2/linux/drivers/ide/ide_modes.h Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ide_modes.h Thu Mar 23 15:37:58 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide_modes.h + * linux/drivers/ide/ide_modes.h * * Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/ns87415.c linux/drivers/ide/ns87415.c --- v2.3.99-pre2/linux/drivers/ide/ns87415.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/ns87415.c Wed Mar 22 22:22:05 2000 @@ -1,12 +1,14 @@ /* - * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 + * linux/drivers/ide/ns87415.c Version 1.01 Mar. 18, 2000 * - * Copyright (C) 1997-1998 Mark Lord - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997-1998 Mark Lord + * Copyright (C) 1998 Eddie C. Dost + * Copyright (C) 1999-2000 Andre Hedrick * - * Inspired by an earlier effort from David S. Miller (davem@caipfs.rutgers.edu) + * Inspired by an earlier effort from David S. Miller */ +#include #include #include #include @@ -78,6 +80,7 @@ ns87415_prepare_drive (drive, drive->using_dma); } +#ifdef CONFIG_BLK_DEV_IDEDMA static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -106,6 +109,7 @@ return ide_dmaproc(func, drive); /* use standard DMA stuff */ } } +#endif /* CONFIG_BLK_DEV_IDEDMA */ void __init ide_init_ns87415 (ide_hwif_t *hwif) { @@ -179,7 +183,10 @@ else if (!hwif->irq && hwif->mate && hwif->mate->irq) hwif->irq = hwif->mate->irq; /* share IRQ with mate */ +#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) hwif->dmaproc = &ns87415_dmaproc; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + hwif->selectproc = &ns87415_selectproc; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/opti621.c linux/drivers/ide/opti621.c --- v2.3.99-pre2/linux/drivers/ide/opti621.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/opti621.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999 + * linux/drivers/ide/opti621.c Version 0.6 Jan 02, 1999 * * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c --- v2.3.99-pre2/linux/drivers/ide/pdc202xx.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/pdc202xx.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/pdc202xx.c Version 0.29 Feb. 10, 2000 + * linux/drivers/ide/pdc202xx.c Version 0.30 Mar. 18, 2000 * * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -9,6 +9,9 @@ * Note that BIOS v1.29 is reported to fix the problem. Since this is * safe chipset tuning, including this support is harmless * + * Promise Ultra66 cards with BIOS v1.11 this + * compiled into the kernel if you have more than one card installed. + * * The latest chipset code will support the following :: * Three Ultra33 controllers and 12 drives. * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. @@ -16,60 +19,6 @@ * * UNLESS you enable "CONFIG_PDC202XX_BURST" * - * There is only one BIOS in the three contollers. - * - * May 8 20:56:17 Orion kernel: - * Uniform Multi-Platform E-IDE driver Revision: 6.19 - * PDC20246: IDE controller on PCI bus 00 dev a0 - * PDC20246: not 100% native mode: will probe irqs later - * PDC20246: ROM enabled at 0xfebd0000 - * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode. - * ide0: BM-DMA at 0xef80-0xef87, BIOS settings: hda:DMA, hdb:DMA - * ide1: BM-DMA at 0xef88-0xef8f, BIOS settings: hdc:pio, hdd:pio - * PDC20246: IDE controller on PCI bus 00 dev 98 - * PDC20246: not 100% native mode: will probe irqs later - * PDC20246: ROM enabled at 0xfebc0000 - * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode. - * ide2: BM-DMA at 0xef40-0xef47, BIOS settings: hde:DMA, hdf:DMA - * ide3: BM-DMA at 0xef48-0xef4f, BIOS settings: hdg:DMA, hdh:DMA - * PDC20246: IDE controller on PCI bus 00 dev 90 - * PDC20246: not 100% native mode: will probe irqs later - * PDC20246: ROM enabled at 0xfebb0000 - * PDC20246: (U)DMA Burst Bit DISABLED Primary PCI Mode Secondary PCI Mode. - * PDC20246: FORCING BURST BIT 0x00 -> 0x01 ACTIVE - * ide4: BM-DMA at 0xef00-0xef07, BIOS settings: hdi:DMA, hdj:pio - * ide5: BM-DMA at 0xef08-0xef0f, BIOS settings: hdk:pio, hdl:pio - * PIIX3: IDE controller on PCI bus 00 dev 39 - * PIIX3: device not capable of full native PCI mode - * - * ide0 at 0xeff0-0xeff7,0xefe6 on irq 19 - * ide1 at 0xefa8-0xefaf,0xebe6 on irq 19 - * ide2 at 0xefa0-0xefa7,0xef7e on irq 18 - * ide3 at 0xef68-0xef6f,0xef66 on irq 18 - * ide4 at 0xef38-0xef3f,0xef62 on irq 17 - * hda: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=13328/15/63, UDMA(33) - * hdb: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=6256/16/63, UDMA(33) - * hde: Maxtor 72004 AP, 1916MB w/128kB Cache, CHS=3893/16/63, DMA - * hdf: Maxtor 71626 A, 1554MB w/64kB Cache, CHS=3158/16/63, DMA - * hdi: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33) - * hdj: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33) - * - * Promise Ultra66 cards with BIOS v1.11 this - * compiled into the kernel if you have more than one card installed. - * - * PDC20262: IDE controller on PCI bus 00 dev a0 - * PDC20262: not 100% native mode: will probe irqs later - * PDC20262: ROM enabled at 0xfebb0000 - * PDC20262: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode. - * ide0: BM-DMA at 0xef00-0xef07, BIOS settings: hda:pio, hdb:pio - * ide1: BM-DMA at 0xef08-0xef0f, BIOS settings: hdc:pio, hdd:pio - * - * UDMA 4/2 and UDMA 3/1 only differ by the testing bit 13 in word93. - * Chipset timing speeds must be identical - * - * drive_number - * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); */ /* @@ -100,7 +49,7 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 -#undef DISPLAY_PDC202XX_TIMINGS +#define DISPLAY_PDC202XX_TIMINGS #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) #include @@ -111,13 +60,56 @@ extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; +char *pdc202xx_pio_verbose (u32 drive_pci) +{ + if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET"); + if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4"); + if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3"); + if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2"); + if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1"); + if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0"); + return("PIO ?"); +} + +char *pdc202xx_dma_verbose (u32 drive_pci) +{ + if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2"); + if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1"); + if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0"); + if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2"); + if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1"); + if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0"); + return("PIO---"); +} + +char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable) +{ + if ((drive_pci & 0x000ff000) == 0x000ff000) + return("NOTSET"); + if ((drive_pci & 0x00012000) == 0x00012000) + return((slow_cable) ? "UDMA 2" : "UDMA 4"); + if ((drive_pci & 0x00024000) == 0x00024000) + return((slow_cable) ? "UDMA 1" : "UDMA 3"); + if ((drive_pci & 0x00036000) == 0x00036000) + return("UDMA 0"); + return(pdc202xx_dma_verbose(drive_pci)); +} + static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; u32 bibma = bmide_dev->resource[4].start; + u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; + u16 reg50h = 0, pmask = (1<<10), smask = (1<<11); u8 c0 = 0, c1 = 0; + pci_read_config_word(bmide_dev, 0x50, ®50h); + pci_read_config_dword(bmide_dev, 0x60, ®60h); + pci_read_config_dword(bmide_dev, 0x64, ®64h); + pci_read_config_dword(bmide_dev, 0x68, ®68h); + pci_read_config_dword(bmide_dev, 0x6c, ®6ch); + /* * at that point bibma+0x2 et bibma+0xa are byte registers * to investigate: @@ -131,6 +123,7 @@ break; case PCI_DEVICE_ID_PROMISE_20246: p += sprintf(p, "\n PDC20246 Chipset.\n"); + reg50h |= 0x0c00; break; default: p += sprintf(p, "\n PDC202XX Chipset.\n"); @@ -139,17 +132,18 @@ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); p += sprintf(p, " %sabled %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); + (c0&0x80)?"dis":" en",(c1&0x80)?"dis":" en"); p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); - - p += sprintf(p, "UDMA\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); - + (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no "); + p += sprintf(p, "DMA Mode: %s %s %s %s\n", + pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg68h, (reg50h & smask)), + pdc202xx_ultra_verbose(reg6ch, (reg50h & smask))); + p += sprintf(p, " PIO Mode: %s %s %s %s\n", + pdc202xx_pio_verbose(reg60h),pdc202xx_pio_verbose(reg64h), + pdc202xx_pio_verbose(reg68h),pdc202xx_pio_verbose(reg6ch)); return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ @@ -268,6 +262,90 @@ #endif /* PDC202XX_DECODE_REGISTER_INFO */ +/* 0 1 2 3 4 5 6 7 8 + * 960, 480, 390, 300, 240, 180, 120, 90, 60 + * 180, 150, 120, 90, 60 + * DMA_Speed + * 180, 120, 90, 90, 90, 60, 30 + * 11, 5, 4, 3, 2, 1, 0 + */ +static int config_chipset_for_pio (ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte drive_pci, speed; + byte AP, BP, TA, TB; + + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + int err; + + switch (drive_number) { + case 0: drive_pci = 0x60; break; + case 1: drive_pci = 0x64; break; + case 2: drive_pci = 0x68; break; + case 3: drive_pci = 0x6c; break; + default: return 1; + } + + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + + + if ((AP & 0x0F) || (BP & 0x07)) { + /* clear PIO modes of lower 8421 bits of A Register */ + pci_write_config_byte(dev, (drive_pci), AP & ~0x0F); + pci_read_config_byte(dev, (drive_pci), &AP); + + /* clear PIO modes of lower 421 bits of B Register */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + } + + pio = (pio == 5) ? 4 : pio; + switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) { + case 4:speed = XFER_PIO_4; TA=0x01; TB=0x04; break; + case 3:speed = XFER_PIO_3; TA=0x02; TB=0x06; break; + case 2:speed = XFER_PIO_2; TA=0x03; TB=0x08; break; + case 1:speed = XFER_PIO_1; TA=0x05; TB=0x0C; break; + case 0: + default:speed = XFER_PIO_0; TA=0x09; TB=0x13; break; + } + pci_write_config_byte(dev, (drive_pci), AP|TA); + pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); + +#if PDC202XX_DECODE_REGISTER_INFO + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + pci_read_config_byte(dev, (drive_pci)|0x03, &DP); + + decode_registers(REG_A, AP); + decode_registers(REG_B, BP); + decode_registers(REG_C, CP); + decode_registers(REG_D, DP); +#endif /* PDC202XX_DECODE_REGISTER_INFO */ + + err = ide_config_drive_speed(drive, speed); + +#if PDC202XX_DEBUG_DRIVE_INFO + printk("%s: %s drive%d 0x%08x ", + drive->name, ide_xfer_verbose(speed), + drive_number, drive_conf); + pci_read_config_dword(dev, drive_pci, &drive_conf); + printk("0x%08x\n", drive_conf); +#endif /* PDC202XX_DEBUG_DRIVE_INFO */ + return err; +} + +static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio) +{ + (void) config_chipset_for_pio(drive, pio); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) { struct hd_driveid *id = drive->id; @@ -476,91 +554,6 @@ ide_dma_off_quietly); } -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ - -static int config_chipset_for_pio (ide_drive_t *drive, byte pio) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - byte drive_pci, speed; - byte AP, BP, TA, TB; - - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - int err; - - switch (drive_number) { - case 0: drive_pci = 0x60; break; - case 1: drive_pci = 0x64; break; - case 2: drive_pci = 0x68; break; - case 3: drive_pci = 0x6c; break; - default: return 1; - } - - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - - - if ((AP & 0x0F) || (BP & 0x07)) { - /* clear PIO modes of lower 8421 bits of A Register */ - pci_write_config_byte(dev, (drive_pci), AP & ~0x0F); - pci_read_config_byte(dev, (drive_pci), &AP); - - /* clear PIO modes of lower 421 bits of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - } - - pio = (pio == 5) ? 4 : pio; - switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) { - case 4: speed = XFER_PIO_4; TA=0x01; TB=0x04; break; - case 3: speed = XFER_PIO_3; TA=0x02; TB=0x06; break; - case 2: speed = XFER_PIO_2; TA=0x03; TB=0x08; break; - case 1: speed = XFER_PIO_1; TA=0x05; TB=0x0C; break; - case 0: - default: speed = XFER_PIO_0; TA=0x09; TB=0x13; break; - } - pci_write_config_byte(dev, (drive_pci), AP|TA); - pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); - -#if PDC202XX_DECODE_REGISTER_INFO - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - pci_read_config_byte(dev, (drive_pci)|0x03, &DP); - - decode_registers(REG_A, AP); - decode_registers(REG_B, BP); - decode_registers(REG_C, CP); - decode_registers(REG_D, DP); -#endif /* PDC202XX_DECODE_REGISTER_INFO */ - - err = ide_config_drive_speed(drive, speed); - -#if PDC202XX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d 0x%08x ", - drive->name, ide_xfer_verbose(speed), - drive_number, drive_conf); - pci_read_config_dword(dev, drive_pci, &drive_conf); - printk("0x%08x\n", drive_conf); -#endif /* PDC202XX_DEBUG_DRIVE_INFO */ - - return err; -} - -static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio) -{ - (void) config_chipset_for_pio(drive, pio); -} - static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -625,6 +618,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) { @@ -701,11 +695,12 @@ #endif /* CONFIG_PDC202XX_MASTER */ #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) - pdc202xx_proc = 1; - bmide_dev = dev; - pdc202xx_display_info = &pdc202xx_get_info; + if (!pdc202xx_proc) { + pdc202xx_proc = 1; + bmide_dev = dev; + pdc202xx_display_info = &pdc202xx_get_info; + } #endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ - return dev->irq; } @@ -722,10 +717,18 @@ { hwif->tuneproc = &pdc202xx_tune_drive; +#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; + hwif->autodma = 1; } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; + hwif->autodma = 0; } +#else /* !CONFIG_BLK_DEV_IDEDMA */ + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; +#endif /* CONFIG_BLK_DEV_IDEDMA */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/piix.c linux/drivers/ide/piix.c --- v2.3.99-pre2/linux/drivers/ide/piix.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/ide/piix.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/piix.c Version 0.30 Feb. 26, 2000 + * linux/drivers/ide/piix.c Version 0.31 Mar. 18, 2000 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) @@ -51,31 +51,6 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); * - * 00:1f.1 IDE interface: Intel Corporation: - * Unknown device 2411 (rev 01) (prog-if 80 [Master]) - * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- - * ParErr- Stepping- SERR- FastB2B- - * Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- - * SERR- @@ -281,6 +256,7 @@ restore_flags(flags); } +#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING) static int piix_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -387,13 +363,16 @@ /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } +#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */ unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name) { #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) - piix_proc = 1; - bmide_dev = dev; - piix_display_info = &piix_get_info; + if (!piix_proc) { + piix_proc = 1; + bmide_dev = dev; + piix_display_info = &piix_get_info; + } #endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */ return 0; } @@ -427,12 +406,12 @@ if (!hwif->dma_base) return; +#ifndef CONFIG_BLK_DEV_IDEDMA + hwif->autodma = 0; +#else /* CONFIG_BLK_DEV_IDEDMA */ #ifdef CONFIG_PIIX_TUNING hwif->autodma = 1; hwif->dmaproc = &piix_dmaproc; -#else - if (hwif->autodma) - hwif->autodma = 0; - #endif /* CONFIG_PIIX_TUNING */ +#endif /* !CONFIG_BLK_DEV_IDEDMA */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/q40ide.c linux/drivers/ide/q40ide.c --- v2.3.99-pre2/linux/drivers/ide/q40ide.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/q40ide.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/q40ide.c -- Q40 I/O port IDE Driver + * linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver * * original file created 12 Jul 1997 by Geert Uytterhoeven * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/qd6580.c linux/drivers/ide/qd6580.c --- v2.3.99-pre2/linux/drivers/ide/qd6580.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/qd6580.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996 + * linux/drivers/ide/qd6580.c Version 0.02 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/rapide.c linux/drivers/ide/rapide.c --- v2.3.99-pre2/linux/drivers/ide/rapide.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/rapide.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/rapide.c + * linux/drivers/ide/rapide.c * * Copyright (c) 1996-1998 Russell King. * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c --- v2.3.99-pre2/linux/drivers/ide/rz1000.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/rz1000.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 + * linux/drivers/ide/rz1000.c Version 0.05 December 8, 1997 * * Copyright (C) 1995-1998 Linus Torvalds & author (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c --- v2.3.99-pre2/linux/drivers/ide/sis5513.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/sis5513.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/sis5513.c Version 0.09 Feb. 10, 2000 + * linux/drivers/ide/sis5513.c Version 0.10 Mar. 18, 2000 * * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License @@ -109,14 +109,14 @@ static int sis_get_info(char *, char **, off_t, int); extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -struct pci_dev *bmide_dev; +static struct pci_dev *bmide_dev; -static char *cable_type[] = { +static char *cable_type[] __initdata = { "80 pins", "40 pins" }; -static char *recovery_time [] ={ +static char *recovery_time [] __initdata ={ "12 PCICLK", "1 PCICLK", "2 PCICLK", "3 PCICLK", "4 PCICLK", "5 PCICLCK", @@ -127,14 +127,14 @@ "15 PCICLK", "15 PCICLK" }; -static char *cycle_time [] = { +static char * cycle_time [] __initdata = { "Undefined", "2 CLCK", "3 CLK", "4 CLK", "5 CLK", "6 CLK", "7 CLK", "8 CLK" }; -static char *active_time [] = { +static char * active_time [] __initdata = { "8 PCICLK", "1 PCICLCK", "2 PCICLK", "2 PCICLK", "4 PCICLK", "5 PCICLK", @@ -222,6 +222,123 @@ byte sis_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); +static void config_drive_art_rwp (ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + byte reg4bh = 0; + byte rw_prefetch = (0x11 << drive_number); + + pci_read_config_byte(dev, 0x4b, ®4bh); + if (drive->media != ide_disk) + return; + + if ((reg4bh & rw_prefetch) != rw_prefetch) + pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); +} + +static void config_art_rwp_pio (ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + byte timing, drive_pci, test1, test2; + + unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; + unsigned short xfer_pio = drive->id->eide_pio_modes; + int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + +#if 0 + config_drive_art_rwp(drive); +#endif + + pio = ide_get_best_pio_mode(drive, 255, pio, 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; + +/* + * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4 + * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns) + * 0x41 2:0 bits 000 110 100 011 011 + * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns) + * 0x40 3:0 bits 0000 0111 0100 0011 0001 + * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns) + */ + + switch(drive_number) { + case 0: drive_pci = 0x40; break; + case 1: drive_pci = 0x42; break; + case 2: drive_pci = 0x44; break; + case 3: drive_pci = 0x46; break; + default: return; + } + + pci_read_config_byte(dev, drive_pci, &test1); + pci_read_config_byte(dev, drive_pci|0x01, &test2); + + /* + * Do a blanket clear of active and recovery timings. + */ + + test1 &= ~0x07; + test2 &= ~0x0F; + + switch(timing) { + case 4: test1 |= 0x01; test2 |= 0x03; break; + case 3: test1 |= 0x03; test2 |= 0x03; break; + case 2: test1 |= 0x04; test2 |= 0x04; break; + case 1: test1 |= 0x07; test2 |= 0x06; break; + default: break; + } + + pci_write_config_byte(dev, drive_pci, test1); + pci_write_config_byte(dev, drive_pci|0x01, test2); +} + +static int config_chipset_for_pio (ide_drive_t *drive, byte pio) +{ + int err; + byte speed; + + 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; + } + + config_art_rwp_pio(drive, pio); + err = ide_config_drive_speed(drive, speed); + return err; +} + +#undef SIS5513_TUNEPROC + +#ifdef SIS5513_TUNEPROC +static void sis5513_tune_drive (ide_drive_t *drive, byte pio) +{ + (void) config_chipset_for_pio(drive, pio); +} +#endif /* SIS5513_TUNEPROC */ + +#ifdef CONFIG_BLK_DEV_IDEDMA /* * ((id->hw_config & 0x2000) && (HWIF(drive)->udma_four)) */ @@ -331,84 +448,6 @@ ide_dma_off_quietly); } -static void config_drive_art_rwp (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - byte timing, pio, drive_pci, test1, test2; - - unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; - unsigned short xfer_pio = drive->id->eide_pio_modes; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - - if (drive->media == ide_disk) { - struct pci_dev *dev = hwif->pci_dev; - byte reg4bh = 0; - byte rw_prefetch = (0x11 << drive_number); - - pci_read_config_byte(dev, 0x4b, ®4bh); - if ((reg4bh & rw_prefetch) != rw_prefetch) - pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); - } - - 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; - -/* - * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4 - * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns) - * 0x41 2:0 bits 000 110 100 011 011 - * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns) - * 0x40 3:0 bits 0000 0111 0100 0011 0001 - * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns) - */ - - switch(drive_number) { - case 0: drive_pci = 0x40;break; - case 1: drive_pci = 0x42;break; - case 2: drive_pci = 0x44;break; - case 3: drive_pci = 0x46;break; - default: return; - } - - pci_read_config_byte(dev, drive_pci, &test1); - pci_read_config_byte(dev, drive_pci|0x01, &test2); - - /* - * Do a blanket clear of active and recovery timings. - */ - - test1 &= ~0x07; - test2 &= ~0x0F; - - switch(timing) { - case 4: test1 |= 0x01;test2 |= 0x03;break; - case 3: test1 |= 0x03;test2 |= 0x03;break; - case 2: test1 |= 0x04;test2 |= 0x04;break; - case 1: test1 |= 0x07;test2 |= 0x06;break; - default: break; - } - - pci_write_config_byte(dev, drive_pci, test1); - pci_write_config_byte(dev, drive_pci|0x01, test2); -} - static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -417,9 +456,10 @@ if (id && (id->capability & 1) && HWIF(drive)->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { - return HWIF(drive)->dmaproc(ide_dma_off, 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 & 0x001F) { /* Force if Capable UltraDMA */ @@ -434,13 +474,25 @@ (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive, 0); + if (dma_func != ide_dma_on) + goto no_dma_set; } } else if ((ide_dmaproc(ide_dma_good_drive, drive)) && (id->eide_dma_time > 150)) { /* Consult the list of known "good" drives */ dma_func = config_chipset_for_dma(drive, 0); - } + 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: + (void) config_chipset_for_pio(drive, 5); } + return HWIF(drive)->dmaproc(dma_func, drive); } @@ -452,12 +504,14 @@ switch (func) { case ide_dma_check: config_drive_art_rwp(drive); + config_art_rwp_pio(drive, 5); return config_drive_xfer_rate(drive); default: break; } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) { @@ -492,9 +546,11 @@ pci_write_config_byte(dev, 0x52, reg52h|0x04); } #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) - sis_proc = 1; - bmide_dev = dev; - sis_display_info = &sis_get_info; + if (!sis_proc) { + sis_proc = 1; + bmide_dev = dev; + sis_display_info = &sis_get_info; + } #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ } return 0; @@ -525,11 +581,16 @@ hwif->irq = hwif->channel ? 15 : 14; +#ifdef SIS5513_TUNEPROC + hwif->tuneproc = &sis5513_tune_drive; +#endif /* SIS5513_TUNEPROC */ + if (!(hwif->dma_base)) return; if (host_dev) { switch(host_dev->device) { +#ifdef CONFIG_BLK_DEV_IDEDMA case PCI_DEVICE_ID_SI_530: case PCI_DEVICE_ID_SI_540: case PCI_DEVICE_ID_SI_620: @@ -540,6 +601,7 @@ hwif->autodma = 1; hwif->dmaproc = &sis5513_dmaproc; break; +#endif /* CONFIG_BLK_DEV_IDEDMA */ default: hwif->autodma = 0; break; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/sl82c105.c linux/drivers/ide/sl82c105.c --- v2.3.99-pre2/linux/drivers/ide/sl82c105.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/sl82c105.c Wed Mar 22 17:18:44 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/sl82c105.c + * linux/drivers/ide/sl82c105.c * * SL82C105/Winbond 553 IDE driver * diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/trm290.c linux/drivers/ide/trm290.c --- v2.3.99-pre2/linux/drivers/ide/trm290.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/trm290.c Wed Mar 22 22:22:05 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 + * linux/drivers/ide/trm290.c Version 1.02 Mar. 18, 2000 * * Copyright (c) 1997-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -124,6 +124,7 @@ * */ +#include #include #include #include @@ -171,6 +172,7 @@ trm290_prepare_drive(drive, drive->using_dma); } +#ifdef CONFIG_BLK_DEV_IDEDMA static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -209,6 +211,7 @@ trm290_prepare_drive(drive, 0); /* select PIO xfer */ return 1; } +#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Invoked from ide-dma.c at boot time. @@ -247,7 +250,11 @@ else if (!hwif->irq && hwif->mate && hwif->mate->irq) hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); + +#ifdef CONFIG_BLK_DEV_IDEDMA hwif->dmaproc = &trm290_dmaproc; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + hwif->selectproc = &trm290_selectproc; hwif->autodma = 0; /* play it safe for now */ #if 1 diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/umc8672.c linux/drivers/ide/umc8672.c --- v2.3.99-pre2/linux/drivers/ide/umc8672.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/ide/umc8672.c Wed Mar 22 17:18:45 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 + * linux/drivers/ide/umc8672.c Version 0.05 Jul 31, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c --- v2.3.99-pre2/linux/drivers/ide/via82cxxx.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/ide/via82cxxx.c Wed Mar 22 17:18:45 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/via82cxxx.c Version 0.07 Feb. 10, 2000 + * linux/drivers/ide/via82cxxx.c Version 0.08 Mar. 18, 2000 * * Copyright (C) 1998-99 Michel Aubry, Maintainer * Copyright (C) 1999 Jeff Garzik, MVP4 Support @@ -143,14 +143,14 @@ #include #include -static char *FIFO_str[] = { +static char *FIFO_str[] __initdata = { " 1 ", "3/4", "1/2", "1/4" }; -static char *control3_str[] = { +static char *control3_str[] __initdata = { "No limitation", "64", "128", @@ -516,6 +516,62 @@ #ifdef CONFIG_VIA82CXXX_TUNING +struct chipset_bus_clock_list_entry { + unsigned short bus_speed; + byte xfer_speed; + byte chipset_settings; +}; + +PCI_DEVICE_ID_VIA_82C586_1 +PCI_DEVICE_ID_VIA_82C596 +PCI_DEVICE_ID_VIA_82C686 +PCI_DEVICE_ID_VIA_8231 + +PCI_DEVICE_ID_VIA_82C586_1 TYPE_1 +PCI_DEVICE_ID_VIA_82C596 TYPE_2 +PCI_DEVICE_ID_VIA_82C686 TYPE_2 +PCI_DEVICE_ID_VIA_82C596 TYPE_3 +PCI_DEVICE_ID_VIA_82C686 TYPE_3 +PCI_DEVICE_ID_VIA_8231 TYPE_4 + +struct chipset_bus_clock_list_entry ultra_33_base [] = { +{ TYPE_1,25,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 }, +{ TYPE_1,33,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 }, +{ TYPE_1,37,0x00,0x00,0x60,0x61,0x62,0x03,0x21,0x32,0x76,0x76,0xA9 }, +{ TYPE_2,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, +{ TYPE_2,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, +{ TYPE_2,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB }, +{ TYPE_2,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE }, +{ TYPE_3,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, +{ TYPE_3,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 }, +{ TYPE_3,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB }, +{ TYPE_3,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE }, +{ TYPE_4,0,0,0,0,0,0,0,0,0,0,0,0 }, +{ 0,0,0,0,0,0,0,0,0,0,0,0,0 } +}; + +struct chipset_bus_clock_list_entry timing_66_base [] = { + { 37, XFER_PIO_4, 0x21 }, + { 37, XFER_PIO_3, 0x32 }, + { 37, XFER_PIO_2, 0x76 }, + { 37, XFER_PIO_1, 0x76 }, + { 37, XFER_PIO_0, 0xA9 }, + { ANY, XFER_PIO_4, 0x20 }, + { ANY, XFER_PIO_3, 0x31 }, + { ANY, XFER_PIO_2, 0x65 }, + { ANY, XFER_PIO_1, 0x65 }, + { ANY, XFER_PIO_0, 0xA8 }, +}; + +static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + return chipset_table->chipset_settings; + } + return 0x01208585; +} + static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed) { struct hd_driveid *id = drive->id; @@ -539,7 +595,7 @@ case 2: ata2_pci = 0x4a; ata3_pci = 0x52; break; case 3: ata2_pci = 0x4b; ata3_pci = 0x53; break; default: - return err; + return -1; } pci_read_config_byte(dev, ata2_pci, &timing); @@ -575,6 +631,57 @@ return(err); } +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 : + (drive->id->tPIO & 2) ? 0x02 : + (drive->id->tPIO & 1) ? 0x01 : 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) via82cxxx_tune_chipset(drive, speed); +} + +static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio) +{ + byte speed; + 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) via82cxxx_tune_chipset(drive, speed); +} + +#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -617,56 +724,6 @@ return rval; } -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 : - (drive->id->tPIO & 2) ? 0x02 : - (drive->id->tPIO & 1) ? 0x01 : 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) via82cxxx_tune_chipset(drive, speed); -} - -static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio) -{ - byte speed; - 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) via82cxxx_tune_chipset(drive, speed); -} - static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -726,6 +783,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_VIA82CXXX_TUNING */ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name) @@ -745,7 +803,7 @@ host_dev = host; printk(ApolloHostChipInfo[i].name); - + printk("\n"); for (j = 0; j < arraysize (ApolloISAChipInfo) && !isa_dev; j++) { if (ApolloISAChipInfo[j].host_id != ApolloHostChipInfo[i].host_id) @@ -777,9 +835,11 @@ } #if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) - via_proc = 1; - bmide_dev = dev; - via_display_info = &via_get_info; + if (!via_proc) { + via_proc = 1; + bmide_dev = dev; + via_display_info = &via_get_info; + } #endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ return 0; @@ -797,13 +857,15 @@ #ifdef CONFIG_VIA82CXXX_TUNING hwif->tuneproc = &via82cxxx_tune_drive; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; +#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &via82cxxx_dmaproc; - } else { - hwif->autodma = 0; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; + hwif->autodma = 1; } +#endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_VIA82CXXX_TUNING */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/Config.in linux/drivers/ieee1394/Config.in --- v2.3.99-pre2/linux/drivers/ieee1394/Config.in Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/Config.in Wed Mar 22 00:02:48 2000 @@ -14,11 +14,12 @@ fi dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394 - + dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 + bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG fi endmenu fi diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/csr.c linux/drivers/ieee1394/csr.c --- v2.3.99-pre2/linux/drivers/ieee1394/csr.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/csr.c Wed Mar 22 00:02:48 2000 @@ -14,6 +14,7 @@ #include "highlevel.h" +/* FIXME: this one won't work on little endian with big endian data */ static u16 csr_crc16(unsigned *data, int length) { int check=0, i; @@ -47,14 +48,18 @@ host->csr.state &= ~0x100; } - host->csr.topology_map[1]++; - host->csr.topology_map[2] = host->node_count << 16 | host->selfid_count; - host->csr.topology_map[0] = (host->selfid_count + 2) << 16 - | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2); - - /* FIXME - generate speed map */ - host->csr.speed_map[0] = 0x3f1 << 16 | csr_crc16(host->csr.speed_map+1, - 0x3f1); + host->csr.topology_map[1] = + cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1); + host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16 + | host->selfid_count); + host->csr.topology_map[0] = + cpu_to_be32((host->selfid_count + 2) << 16 + | csr_crc16(host->csr.topology_map + 1, + host->selfid_count + 2)); + + host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 + | csr_crc16(host->csr.speed_map+1, + 0x3f1)); } @@ -78,8 +83,8 @@ /* Read topology / speed maps and configuration ROM */ -static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr, - unsigned int length) +static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length) { int csraddr = addr - CSR_REGISTER_BASE; const char *src; @@ -100,43 +105,11 @@ return RCODE_COMPLETE; } -/* Read FCP register space */ -static int read_fcp(struct hpsb_host *host, quadlet_t *buffer, u64 addr, - unsigned int length) -{ - int csraddr = addr - CSR_REGISTER_BASE; - const char *src; - - if (csraddr + length > CSR_FCP_END) { - return RCODE_ADDRESS_ERROR; - } - src = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND; - - memcpy(buffer, src, length); - return RCODE_COMPLETE; -} - -/* Write FCP register space */ -static int write_fcp(struct hpsb_host *host, quadlet_t *data, u64 addr, - unsigned int length) -{ - int csraddr = addr - CSR_REGISTER_BASE; - char *dest; - - if (csraddr + length > CSR_FCP_END) { - return RCODE_ADDRESS_ERROR; - } - dest = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND; - - memcpy(dest, data, length); - return RCODE_COMPLETE; -} - #define out if (--length == 0) break -static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr, - unsigned int length) +static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf, + u64 addr, unsigned int length) { int csraddr = addr - CSR_REGISTER_BASE; int oldcycle; @@ -149,13 +122,13 @@ switch (csraddr) { case CSR_STATE_CLEAR: - *(buf++) = host->csr.state; + *(buf++) = cpu_to_be32(host->csr.state); out; case CSR_STATE_SET: - *(buf++) = host->csr.state; + *(buf++) = cpu_to_be32(host->csr.state); out; case CSR_NODE_IDS: - *(buf++) = host->csr.node_ids; + *(buf++) = cpu_to_be32(host->csr.node_ids); out; case CSR_RESET_START: @@ -164,10 +137,10 @@ /* address gap - handled by default below */ case CSR_SPLIT_TIMEOUT_HI: - *(buf++) = host->csr.split_timeout_hi; + *(buf++) = cpu_to_be32(host->csr.split_timeout_hi); out; case CSR_SPLIT_TIMEOUT_LO: - *(buf++) = host->csr.split_timeout_lo; + *(buf++) = cpu_to_be32(host->csr.split_timeout_lo); out; /* address gap */ @@ -182,7 +155,7 @@ /* cycle time wrapped around */ host->csr.bus_time += 1 << 7; } - *(buf++) = host->csr.cycle_time; + *(buf++) = cpu_to_be32(host->csr.cycle_time); out; case CSR_BUS_TIME: oldcycle = host->csr.cycle_time; @@ -193,7 +166,8 @@ /* cycle time wrapped around */ host->csr.bus_time += (1 << 7); } - *(buf++) = host->csr.bus_time | (host->csr.cycle_time >> 25); + *(buf++) = cpu_to_be32(host->csr.bus_time + | (host->csr.cycle_time >> 25)); out; /* address gap */ @@ -204,16 +178,16 @@ return RCODE_ADDRESS_ERROR; case CSR_BUS_MANAGER_ID: - *(buf++) = host->csr.bus_manager_id; + *(buf++) = cpu_to_be32(host->csr.bus_manager_id); out; case CSR_BANDWIDTH_AVAILABLE: - *(buf++) = host->csr.bandwidth_available; + *(buf++) = cpu_to_be32(host->csr.bandwidth_available); out; case CSR_CHANNELS_AVAILABLE_HI: - *(buf++) = host->csr.channels_available_hi; + *(buf++) = cpu_to_be32(host->csr.channels_available_hi); out; case CSR_CHANNELS_AVAILABLE_LO: - *(buf++) = host->csr.channels_available_lo; + *(buf++) = cpu_to_be32(host->csr.channels_available_lo); out; /* address gap to end - fall through to default */ @@ -224,8 +198,8 @@ return RCODE_COMPLETE; } -static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr, - unsigned int length) +static int write_regs(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) { int csraddr = addr - CSR_REGISTER_BASE; @@ -246,7 +220,7 @@ case CSR_NODE_IDS: host->csr.node_ids &= NODE_MASK << 16; - host->csr.node_ids |= *(data++) & (BUS_MASK << 16); + host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16); host->node_id = host->csr.node_ids >> 16; host->template->devctl(host, SET_BUS_ID, host->node_id >> 6); out; @@ -259,10 +233,12 @@ return RCODE_ADDRESS_ERROR; case CSR_SPLIT_TIMEOUT_HI: - host->csr.split_timeout_hi = *(data++) & 0x00000007; + host->csr.split_timeout_hi = + be32_to_cpu(*(data++)) & 0x00000007; out; case CSR_SPLIT_TIMEOUT_LO: - host->csr.split_timeout_lo = *(data++) & 0xfff80000; + host->csr.split_timeout_lo = + be32_to_cpu(*(data++)) & 0xfff80000; out; /* address gap */ @@ -270,11 +246,12 @@ case CSR_CYCLE_TIME: /* should only be set by cycle start packet, automatically */ - host->csr.cycle_time = *data; - host->template->devctl(host, SET_CYCLE_COUNTER, *(data++)); + host->csr.cycle_time = be32_to_cpu(*data); + host->template->devctl(host, SET_CYCLE_COUNTER, + be32_to_cpu(*(data++))); out; case CSR_BUS_TIME: - host->csr.bus_time = *(data++) & 0xffffff80; + host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80; out; /* address gap */ @@ -305,13 +282,13 @@ /* helper function for lock_regs */ inline static void compare_swap(quadlet_t *old, quadlet_t data, quadlet_t arg) { - if (*old == arg) { - *old = data; + if (*old == be32_to_cpu(arg)) { + *old = be32_to_cpu(data); } } -static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr, - quadlet_t data, quadlet_t arg, int extcode) +static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int extcode) { int csraddr = addr - CSR_REGISTER_BASE; unsigned long flags; @@ -327,25 +304,28 @@ switch (csraddr) { case CSR_BUS_MANAGER_ID: - *store = host->csr.bus_manager_id; + *store = cpu_to_be32(host->csr.bus_manager_id); compare_swap(&host->csr.bus_manager_id, data, arg); break; case CSR_BANDWIDTH_AVAILABLE: - *store = host->csr.bandwidth_available; + *store = cpu_to_be32(host-> + csr.bandwidth_available); compare_swap(&host->csr.bandwidth_available, data, arg); break; case CSR_CHANNELS_AVAILABLE_HI: - *store = host->csr.channels_available_hi; + *store = cpu_to_be32(host-> + csr.channels_available_hi); compare_swap(&host->csr.channels_available_hi, data, arg); break; case CSR_CHANNELS_AVAILABLE_LO: - *store = host->csr.channels_available_lo; + *store = cpu_to_be32(host-> + csr.channels_available_lo); compare_swap(&host->csr.channels_available_lo, data, arg); break; @@ -377,34 +357,48 @@ } } +static int write_fcp(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) +{ + int csraddr = addr - CSR_REGISTER_BASE; + + if (length > 512) { + return RCODE_TYPE_ERROR; + } + + switch (csraddr) { + case CSR_FCP_COMMAND: + highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length); + break; + case CSR_FCP_RESPONSE: + highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length); + break; + default: + return RCODE_TYPE_ERROR; + } + + return RCODE_COMPLETE; +} + struct hpsb_highlevel_ops csr_ops = { - add_host, - NULL, - host_reset, - NULL + add_host: add_host, + host_reset: host_reset, }; struct hpsb_address_ops map_ops = { - read_maps, - NULL, - NULL, - NULL + read: read_maps, }; struct hpsb_address_ops fcp_ops = { - read_fcp, - write_fcp, - NULL, - NULL + write: write_fcp, }; struct hpsb_address_ops reg_ops = { - read_regs, - write_regs, - lock_regs, - NULL + read: read_regs, + write: write_regs, + lock: lock_regs, }; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/csr.h linux/drivers/ieee1394/csr.h --- v2.3.99-pre2/linux/drivers/ieee1394/csr.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/csr.h Wed Mar 22 00:02:48 2000 @@ -46,7 +46,6 @@ quadlet_t topology_map[256]; quadlet_t speed_map[1024]; - quadlet_t fcp_data[1024]; }; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/highlevel.c linux/drivers/ieee1394/highlevel.c --- v2.3.99-pre2/linux/drivers/ieee1394/highlevel.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/highlevel.c Wed Mar 22 00:02:48 2000 @@ -192,23 +192,35 @@ read_unlock(&hl_drivers_lock); } +void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, + u8 *data, unsigned int length) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + int cts = data[0]; + + read_lock(&hl_drivers_lock); + entry = hl_drivers.next; + + while (entry != &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + if (hl->op->fcp_request) { + hl->op->fcp_request(host, nodeid, direction, cts, data, + length); + } + entry = entry->next; + } + read_unlock(&hl_drivers_lock); +} -int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr, - unsigned int length) +int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length) { struct hpsb_address_serve *as; struct list_head *entry; unsigned int partlength; int rcode = RCODE_ADDRESS_ERROR; - if ((addr | length) & 0x3) { - /* Addresses or lengths not a multiple of a quadlet pose a big - * problem on little endian machines because we always do this - * in arch endian and swapping would mess it all up. So we - * simply don't allow this at all. */ - return RCODE_TYPE_ERROR; - } - read_lock(&addr_space_lock); entry = addr_space.next; @@ -220,7 +232,7 @@ length); if (as->op->read != NULL) { - rcode = as->op->read(host, buffer, addr, + rcode = as->op->read(host, nodeid, buffer, addr, partlength); } else { rcode = RCODE_TYPE_ERROR; @@ -247,18 +259,14 @@ return rcode; } -int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr, - unsigned int length) +int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) { struct hpsb_address_serve *as; struct list_head *entry; unsigned int partlength; int rcode = RCODE_ADDRESS_ERROR; - if ((addr | length) & 0x3) { - return RCODE_TYPE_ERROR; - } - read_lock(&addr_space_lock); entry = addr_space.next; @@ -270,7 +278,7 @@ length); if (as->op->write != NULL) { - rcode = as->op->write(host, data, addr, + rcode = as->op->write(host, nodeid, data, addr, partlength); } else { rcode = RCODE_TYPE_ERROR; @@ -298,8 +306,8 @@ } -int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr, - quadlet_t data, quadlet_t arg, int ext_tcode) +int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode) { struct hpsb_address_serve *as; struct list_head *entry; @@ -313,8 +321,8 @@ while (as->start <= addr) { if (as->end > addr) { if (as->op->lock != NULL) { - rcode = as->op->lock(host, store, addr, data, - arg, ext_tcode); + rcode = as->op->lock(host, nodeid, store, addr, + data, arg, ext_tcode); } else { rcode = RCODE_TYPE_ERROR; } @@ -331,8 +339,8 @@ return rcode; } -int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr, - octlet_t data, octlet_t arg, int ext_tcode) +int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode) { struct hpsb_address_serve *as; struct list_head *entry; @@ -346,8 +354,9 @@ while (as->start <= addr) { if (as->end > addr) { if (as->op->lock64 != NULL) { - rcode = as->op->lock64(host, store, addr, data, - arg, ext_tcode); + rcode = as->op->lock64(host, nodeid, store, + addr, data, arg, + ext_tcode); } else { rcode = RCODE_TYPE_ERROR; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/highlevel.h linux/drivers/ieee1394/highlevel.h --- v2.3.99-pre2/linux/drivers/ieee1394/highlevel.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/highlevel.h Wed Mar 22 00:02:48 2000 @@ -55,6 +55,13 @@ * for channel/host combinations you did not request. */ void (*iso_receive) (struct hpsb_host *host, int channel, quadlet_t *data, unsigned int length); + + /* A write request was received on either the FCP_COMMAND (direction = + * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg + * contains the cts field (first byte of data). + */ + void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction, + int cts, u8 *data, unsigned int length); }; struct hpsb_address_ops { @@ -67,17 +74,17 @@ */ /* These functions have to implement block reads for themselves. */ - int (*read) (struct hpsb_host *host, quadlet_t *buffer, u64 addr, - unsigned int length); - int (*write) (struct hpsb_host *host, quadlet_t *data, u64 addr, - unsigned int length); + int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length); + int (*write) (struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length); /* Lock transactions: write results of ext_tcode operation into * *store. */ - int (*lock) (struct hpsb_host *host, quadlet_t *store, u64 addr, - quadlet_t data, quadlet_t arg, int ext_tcode); - int (*lock64) (struct hpsb_host *host, octlet_t *store, u64 addr, - octlet_t data, octlet_t arg, int ext_tcode); + int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode); + int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode); }; @@ -87,17 +94,19 @@ void highlevel_remove_host(struct hpsb_host *host); void highlevel_host_reset(struct hpsb_host *host); -int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr, - unsigned int length); -int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr, - unsigned int length); -int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr, - quadlet_t data, quadlet_t arg, int ext_tcode); -int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr, - octlet_t data, octlet_t arg, int ext_tcode); +int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length); +int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length); +int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode); +int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode); void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data, unsigned int length); +void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, + u8 *data, unsigned int length); /* diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/ieee1394.h linux/drivers/ieee1394/ieee1394.h --- v2.3.99-pre2/linux/drivers/ieee1394/ieee1394.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/ieee1394.h Wed Mar 22 00:02:48 2000 @@ -63,4 +63,103 @@ #define SELFID_PORT_NCONN 0x1 #define SELFID_PORT_NONE 0x0 + +#include + +#ifdef __BIG_ENDIAN_BITFIELD + +struct selfid { + u32 packet_identifier:2; /* always binary 10 */ + u32 phy_id:6; + /* byte */ + u32 extended:1; /* if true is struct ext_selfid */ + u32 link_active:1; + u32 gap_count:6; + /* byte */ + u32 speed:2; + u32 phy_delay:2; + u32 contender:1; + u32 power_class:3; + /* byte */ + u32 port0:2; + u32 port1:2; + u32 port2:2; + u32 initiated_reset:1; + u32 more_packets:1; +} __attribute__((packed)); + +struct ext_selfid { + u32 packet_identifier:2; /* always binary 10 */ + u32 phy_id:6; + /* byte */ + u32 extended:1; /* if false is struct selfid */ + u32 seq_nr:3; + u32 reserved:2; + u32 porta:2; + /* byte */ + u32 portb:2; + u32 portc:2; + u32 portd:2; + u32 porte:2; + /* byte */ + u32 portf:2; + u32 portg:2; + u32 porth:2; + u32 reserved2:1; + u32 more_packets:1; +} __attribute__((packed)); + +#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */ + +/* + * Note: these mean to be bit fields of a big endian SelfID as seen on a little + * endian machine. + */ + +struct selfid { + u32 phy_id:6; + u32 packet_identifier:2; /* always binary 10 */ + /* byte */ + u32 gap_count:6; + u32 link_active:1; + u32 extended:1; /* if true is struct ext_selfid */ + /* byte */ + u32 power_class:3; + u32 contender:1; + u32 phy_delay:2; + u32 speed:2; + /* byte */ + u32 more_packets:1; + u32 initiated_reset:1; + u32 port2:2; + u32 port1:2; + u32 port0:2; +} __attribute__((packed)); + +struct ext_selfid { + u32 phy_id:6; + u32 packet_identifier:2; /* always binary 10 */ + /* byte */ + u32 porta:2; + u32 reserved:2; + u32 seq_nr:3; + u32 extended:1; /* if false is struct selfid */ + /* byte */ + u32 porte:2; + u32 portd:2; + u32 portc:2; + u32 portb:2; + /* byte */ + u32 more_packets:1; + u32 reserved2:1; + u32 porth:2; + u32 portg:2; + u32 portf:2; +} __attribute__((packed)); + +#else +#error What? PDP endian? +#endif /* __BIG_ENDIAN_BITFIELD */ + + #endif /* _IEEE1394_IEEE1394_H */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c --- v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_core.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/ieee1394/ieee1394_core.c Wed Mar 22 00:02:48 2000 @@ -2,11 +2,12 @@ * IEEE 1394 for Linux * * Core support: hpsb_packet management, packet handling and forwarding to - * csr or lowlevel code + * highlevel or lowlevel code * * Copyright (C) 1999, 2000 Andreas E. Bombe */ +#include #include #include #include @@ -62,7 +63,7 @@ packet->header = header; if (data_size) { - data = kmalloc(data_size + 4, kmflags); + data = kmalloc(data_size + 8, kmflags); if (data == NULL) { kfree(header); kfree(packet); @@ -70,18 +71,14 @@ } packet->data = data; - packet->data_size = data_size - 4; + packet->data_size = data_size; } INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); packet->state = unused; packet->generation = get_hpsb_generation(); - -#ifdef __BIG_ENDIAN - /* set default */ packet->data_be = 1; -#endif return packet; } @@ -133,59 +130,55 @@ { int nodeid = -1; int rest_of_selfids = num_of_selfids; - quadlet_t *sidp = host->topology_map; - quadlet_t sid = *sidp; + struct selfid *sid = (struct selfid *)host->topology_map; + struct ext_selfid *esid; int esid_seq = 23; - int i; while (rest_of_selfids--) { - sid = *(sidp++); - - if (!(sid & 0x00800000) /* !extended */) { + if (!sid->extended) { nodeid++; esid_seq = 0; - - if (((sid >> 24) & NODE_MASK) != nodeid) { + + if (sid->phy_id != nodeid) { HPSB_INFO("SelfIDs failed monotony check with " - "%d", (sid >> 24) & NODE_MASK); + "%d", sid->phy_id); return 0; } - - /* "if is contender and link active" */ - if ((sid & (1<<11)) && (sid & (1<<22))) { - host->irm_id = LOCAL_BUS | ((sid >> 24) - & NODE_MASK); + + if (sid->contender && sid->link_active) { + host->irm_id = LOCAL_BUS | sid->phy_id; } } else { - if ((((sid >> 24) & NODE_MASK) != nodeid) - || (((sid >> 20) & 0x7) != esid_seq)) { + esid = (struct ext_selfid *)sid; + + if ((esid->phy_id != nodeid) + || (esid->seq_nr != esid_seq)) { HPSB_INFO("SelfIDs failed monotony check with " - "%d/%d", (sid >> 24) & NODE_MASK, - (sid >> 20) & 0x7); + "%d/%d", esid->phy_id, esid->seq_nr); return 0; } esid_seq++; } + sid++; } - - sidp--; - while (sid & 0x00800000 /* extended */) { - /* check that no ports go to a parent */ - for (i = 2; i < 18; i += 2) { - if ((sid & (0x3 << i)) == (0x2 << i)) { + + esid = (struct ext_selfid *)(sid - 1); + while (esid->extended) { + if ((esid->porta == 0x2) || (esid->portb == 0x2) + || (esid->portc == 0x2) || (esid->portd == 0x2) + || (esid->porte == 0x2) || (esid->portf == 0x2) + || (esid->portg == 0x2) || (esid->porth == 0x2)) { HPSB_INFO("SelfIDs failed root check on " "extended SelfID"); return 0; - } } - sid = *(sidp--); + esid--; } - for (i = 2; i < 8; i += 2) { - if ((sid & (0x3 << i)) == (0x2 << i)) { + sid = (struct selfid *)esid; + if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) { HPSB_INFO("SelfIDs failed root check"); return 0; - } } return nodeid + 1; @@ -196,7 +189,8 @@ char speedcap[nodecount]; char cldcnt[nodecount]; u8 *map = host->speed_map; - quadlet_t *sidp; + struct selfid *sid; + struct ext_selfid *esid; int i, j, n; for (i = 0; i < (nodecount * 64); i += 64) { @@ -210,22 +204,26 @@ } /* find direct children count and speed */ - for (sidp = &host->topology_map[host->selfid_count-1], + for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1], n = nodecount - 1; - sidp >= host->topology_map; sidp--) { - if (*sidp & 0x00800000 /* extended */) { - for (i = 2; i < 18; i += 2) { - if ((*sidp & (0x3 << i)) == (0x3 << i)) { - cldcnt[n]++; - } - } + (void *)sid >= (void *)host->topology_map; sid--) { + if (sid->extended) { + esid = (struct ext_selfid *)sid; + + if (esid->porta == 0x3) cldcnt[n]++; + if (esid->portb == 0x3) cldcnt[n]++; + if (esid->portc == 0x3) cldcnt[n]++; + if (esid->portd == 0x3) cldcnt[n]++; + if (esid->porte == 0x3) cldcnt[n]++; + if (esid->portf == 0x3) cldcnt[n]++; + if (esid->portg == 0x3) cldcnt[n]++; + if (esid->porth == 0x3) cldcnt[n]++; } else { - for (i = 2; i < 8; i += 2) { - if ((*sidp & (0x3 << i)) == (0x3 << i)) { - cldcnt[n]++; - } - } - speedcap[n] = (*sidp >> 14) & 0x3; + if (sid->port0 == 0x3) cldcnt[n]++; + if (sid->port1 == 0x3) cldcnt[n]++; + if (sid->port2 == 0x3) cldcnt[n]++; + + speedcap[n] = sid->speed; n--; } } @@ -262,7 +260,7 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) { if (host->in_bus_reset) { - printk("including selfid 0x%x\n", sid); + HPSB_DEBUG("including selfid 0x%x", sid); host->topology_map[host->selfid_count++] = sid; } else { /* FIXME - info on which host */ @@ -293,7 +291,12 @@ } /* irm_id is kept up to date by check_selfids() */ - host->is_irm = (host->irm_id == host->node_id); + if (host->irm_id == host->node_id) { + host->is_irm = 1; + host->is_busmgr = 1; + host->busmgr_id = host->node_id; + host->csr.bus_manager_id = host->node_id; + } host->reset_retries = 0; inc_hpsb_generation(); @@ -346,6 +349,7 @@ packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 + (packet->node_id & NODE_MASK)]; +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG switch (packet->speed_code) { case 2: dump_packet("send packet 400:", packet->header, @@ -359,6 +363,7 @@ dump_packet("send packet 100:", packet->header, packet->header_size); } +#endif return host->template->transmit_packet(host, packet); } @@ -459,12 +464,14 @@ { struct hpsb_packet *p; + dsize += (dsize % 4 ? 4 - (dsize % 4) : 0); + p = alloc_hpsb_packet(dsize); if (p == NULL) { /* FIXME - send data_error response */ return NULL; } - + p->type = async; p->state = unused; p->host = host; @@ -472,6 +479,10 @@ p->tlabel = (data[0] >> 10) & 0x3f; p->no_waiter = 1; + if (dsize % 4) { + p->data[dsize / 4] = 0; + } + return p; } @@ -479,21 +490,12 @@ packet = create_reply_packet(host, data, length); \ if (packet == NULL) break -inline void swap_quadlets_on_le(quadlet_t *q) -{ -#ifdef __LITTLE_ENDIAN - quadlet_t saved = q[0]; - q[0] = q[1]; - q[1] = saved; -#endif -} - - void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data, size_t size) { struct hpsb_packet *packet; int length, rcode, extcode; + int source = data[1] >> 16; u64 addr; /* big FIXME - no error checking is done for an out of bounds length */ @@ -501,7 +503,7 @@ switch (tcode) { case TCODE_WRITEQ: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, data+3, addr, 4); + rcode = highlevel_write(host, source, data+3, addr, 4); if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) { /* not a broadcast write, reply */ @@ -513,7 +515,8 @@ case TCODE_WRITEB: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, data+4, addr, data[3]>>16); + rcode = highlevel_write(host, source, data+4, addr, + data[3]>>16); if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) { /* not a broadcast write, reply */ @@ -527,7 +530,7 @@ PREP_REPLY_PACKET(0); addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_read(host, data, addr, 4); + rcode = highlevel_read(host, source, data, addr, 4); fill_async_readquad_resp(packet, rcode, *data); send_packet_nocare(packet); break; @@ -537,7 +540,8 @@ PREP_REPLY_PACKET(length); addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_read(host, packet->data, addr, length); + rcode = highlevel_read(host, source, packet->data, addr, + length); fill_async_readblock_resp(packet, rcode, length); send_packet_nocare(packet); break; @@ -556,35 +560,32 @@ switch (length) { case 4: - rcode = highlevel_lock(host, packet->data, addr, + rcode = highlevel_lock(host, source, packet->data, addr, data[4], 0, extcode); fill_async_lock_resp(packet, rcode, extcode, 4); break; case 8: if ((extcode != EXTCODE_FETCH_ADD) && (extcode != EXTCODE_LITTLE_ADD)) { - rcode = highlevel_lock(host, packet->data, addr, + rcode = highlevel_lock(host, source, + packet->data, addr, data[5], data[4], extcode); fill_async_lock_resp(packet, rcode, extcode, 4); } else { - swap_quadlets_on_le(data + 4); - rcode = highlevel_lock64(host, + rcode = highlevel_lock64(host, source, (octlet_t *)packet->data, addr, *(octlet_t *)(data + 4), 0ULL, extcode); - swap_quadlets_on_le(packet->data); fill_async_lock_resp(packet, rcode, extcode, 8); } break; case 16: - swap_quadlets_on_le(data + 4); - swap_quadlets_on_le(data + 6); - rcode = highlevel_lock64(host, (octlet_t *)packet->data, - addr, *(octlet_t *)(data + 6), + rcode = highlevel_lock64(host, source, + (octlet_t *)packet->data, addr, + *(octlet_t *)(data + 6), *(octlet_t *)(data + 4), extcode); - swap_quadlets_on_le(packet->data); fill_async_lock_resp(packet, rcode, extcode, 8); break; default: @@ -609,7 +610,9 @@ return; } +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG dump_packet("received packet:", data, size); +#endif tcode = (data[0] >> 4) & 0xf; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_core.h linux/drivers/ieee1394/ieee1394_core.h --- v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_core.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/ieee1394_core.h Wed Mar 22 00:02:48 2000 @@ -40,29 +40,26 @@ unsigned no_waiter:1; /* Data big endianness flag - may vary from request to request. The - * header is always in machine byte order. */ + * header is always in machine byte order. + * Not really used currently. */ unsigned data_be:1; /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */ unsigned speed_code:2; - /* --- 16 bytes (one cacheline) --- */ - - /* *header and *data are guaranteed to be 32-bit DMAable and may be + /* + * *header and *data are guaranteed to be 32-bit DMAable and may be * overwritten to allow in-place byte swapping. Neither of these is * CRCed (the sizes also don't include CRC), but contain space for at * least one additional quadlet to allow in-place CRCing. The memory is * also guaranteed to have physical mapping (virt_to_bus() is meaningful * on these pointers). - * NOTE: The 32-bit DMA guarantee is currently not enforced. - * That's a Linux 2.3 issue. */ quadlet_t *header; quadlet_t *data; size_t header_size; size_t data_size; - /* --- 32 bytes --- */ struct hpsb_host *host; unsigned int generation; @@ -139,12 +136,14 @@ * for other cases (internal errors that don't justify a panic). Safe to call * from within a transmit packet routine. */ -void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode); +void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, + int ackcode); /* * Hand over received packet to the core. The contents of data are expected to * be the full packet but with the CRCs left out (data block follows header - * immediately) and in machine byte order. *data can be safely overwritten + * immediately), with the header (i.e. the first four quadlets) in machine byte + * order and the data block in big endian. *data can be safely overwritten * after this call. */ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_transactions.c linux/drivers/ieee1394/ieee1394_transactions.c --- v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_transactions.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/ieee1394/ieee1394_transactions.c Wed Mar 22 00:02:49 2000 @@ -68,7 +68,7 @@ PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE); packet->header[3] = length << 16; packet->header_size = 16; - packet->data_size = length; + packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0); } void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data) @@ -85,8 +85,8 @@ PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB); packet->header[3] = length << 16; packet->header_size = 16; - packet->data_size = length; packet->expect_response = 1; + packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0); } void fill_async_write_resp(struct hpsb_packet *packet, int rcode) @@ -260,7 +260,7 @@ quadlet_t *buffer, size_t length) { if (host->node_id != node) return -1; - return highlevel_read(host, buffer, addr, length); + return highlevel_read(host, node, buffer, addr, length); } struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node, @@ -284,7 +284,7 @@ { struct hpsb_packet *p; - p = alloc_hpsb_packet(length); + p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); if (!p) return NULL; p->host = host; @@ -318,9 +318,13 @@ { struct hpsb_packet *p; - p = alloc_hpsb_packet(length); + p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); if (!p) return NULL; + if (length % 4) { + p->data[length / 4] = 0; + } + p->host = host; p->tlabel = get_tlabel(host, node, 1); p->node_id = node; @@ -370,7 +374,7 @@ } if (host->node_id == node) { - switch(highlevel_read(host, buffer, addr, length)) { + switch(highlevel_read(host, node, buffer, addr, length)) { case RCODE_COMPLETE: return 0; case RCODE_TYPE_ERROR: @@ -381,16 +385,6 @@ } } - if (length & 0x3) { - /* FIXME: Lengths not multiple of 4 are not implemented. Mainly - * there is the problem with little endian machines because we - * always swap to little endian on receive. If we read 5 bytes - * 12345 we receive them as 12345000 and swap them to 43210005. - * How should we copy that to the caller? Require *buffer to be - * a full quadlet multiple in length? */ - return -EACCES; - } - if (length == 4) { packet = hpsb_make_readqpacket(host, node, addr); } else { @@ -432,7 +426,7 @@ } if (host->node_id == node) { - switch(highlevel_write(host, buffer, addr, length)) { + switch(highlevel_write(host, node, buffer, addr, length)) { case RCODE_COMPLETE: return 0; case RCODE_TYPE_ERROR: @@ -443,12 +437,6 @@ } } - if (length & 0x3) { - /* FIXME: Lengths not multiple of 4 are not implemented. See function - * hpsb_read for explanation, same reason, different direction. */ - return -EACCES; - } - if (length == 4) { packet = hpsb_make_writeqpacket(host, node, addr, *buffer); } else { @@ -483,7 +471,8 @@ int retval = 0, length; if (host->node_id == node) { - switch(highlevel_lock(host, data, addr, *data, arg, extcode)) { + switch(highlevel_lock(host, node, data, addr, *data, arg, + extcode)) { case RCODE_COMPLETE: return 0; case RCODE_TYPE_ERROR: diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_types.h linux/drivers/ieee1394/ieee1394_types.h --- v2.3.99-pre2/linux/drivers/ieee1394/ieee1394_types.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/ieee1394_types.h Wed Mar 22 00:02:49 2000 @@ -6,6 +6,7 @@ #include #include #include +#include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) @@ -23,6 +24,8 @@ { __list_add(new, head->prev, head); } + +#define __constant_cpu_to_be32(x) __constant_htonl((x)) #endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c --- v2.3.99-pre2/linux/drivers/ieee1394/ohci1394.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/ieee1394/ohci1394.c Wed Mar 22 00:02:49 2000 @@ -35,9 +35,18 @@ * . Config ROM * * Known bugs: - * . Self-id are not received properly if card - * is initialized with no other nodes on the - * bus. + * . Self-id are sometimes not received properly + * if card is initialized with no other nodes + * on the bus + */ + +/* + * Acknowledgments: + * + * Emilie Chung + * .Tip on Async Request Filter + * Pascal Drolet + * .Various tips for optimization and functionnalities */ #include @@ -71,11 +80,15 @@ #include "ieee1394_core.h" #include "ohci1394.h" +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#define OHCI1394_DEBUG +#endif + #ifdef DBGMSG #undef DBGMSG #endif -#if OHCI1394_DEBUG +#ifdef OHCI1394_DEBUG #define DBGMSG(card, fmt, args...) \ printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args) #else @@ -97,10 +110,14 @@ return 1; int supported_chips[][2] = { - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 }, - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV22 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV23 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV26 }, { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 }, { PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 }, + { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 }, + { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 }, + { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 }, { -1, -1 } }; @@ -213,7 +230,7 @@ if (q[0] == ~q[1]) { PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd", q[0]); - hpsb_selfid_received(host, q[0]); + hpsb_selfid_received(host, cpu_to_be32(q[0])); if (((q[0]&0x3f000000)>>24)==phyid) { lsid=q[0]; PRINT(KERN_INFO, ohci->id, @@ -369,6 +386,23 @@ PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx); } +/* Count the number of available iso contexts */ +static int get_nb_iso_ctx(struct ti_ohci *ohci) +{ + int i,ctx=0; + u32 tmp; + + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0xffffffff); + tmp = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); + + /* Count the number of contexts */ + for(i=0; i<32; i++) { + if(tmp & 1) ctx++; + tmp >>= 1; + } + return ctx; +} + /* Global initialization */ static int ohci_initialize(struct hpsb_host *host) { @@ -411,15 +445,22 @@ virt_to_bus(ohci->csr_config_rom)); /* Write the config ROM header */ - reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->csr_config_rom[0]); + reg_write(ohci, OHCI1394_ConfigROMhdr, + cpu_to_be32(ohci->csr_config_rom[0])); /* Set bus options */ - reg_write(ohci, OHCI1394_BusOptions, ohci->csr_config_rom[2]); - - /* Write the GUID into the csr config rom */ - ohci->csr_config_rom[3] = reg_read(ohci, OHCI1394_GUIDHi); - ohci->csr_config_rom[4] = reg_read(ohci, OHCI1394_GUIDLo); + reg_write(ohci, OHCI1394_BusOptions, + cpu_to_be32(ohci->csr_config_rom[2])); + /* Write the GUID into the csr config rom */ + ohci->csr_config_rom[3] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi)); + ohci->csr_config_rom[4] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo)); + + ohci->max_packet_size = + 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); + PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes", + ohci->max_packet_size); + /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); @@ -427,7 +468,10 @@ reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); /* Initialize IR dma */ - for (i=0;i<4;i++) { /* FIXME : how many contexts are available ? */ + ohci->nb_iso_ctx = get_nb_iso_ctx(ohci); + PRINT(KERN_INFO, ohci->id, "%d iso contexts available", + ohci->nb_iso_ctx); + for (i=0;inb_iso_ctx;i++) { reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i, 0xffffffff); reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0); @@ -465,7 +509,6 @@ * Accept AT requests from all nodes. This probably * will have to be controlled from the subsystem * on a per node basis. - * (Tip by Emilie Chung ) */ reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000); @@ -578,8 +621,9 @@ unsigned char tcode; int i=50; - if (packet->data_size >= 4096) { - PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)", + if (packet->data_size >= ohci->max_packet_size) { + PRINT(KERN_ERR, ohci->id, + "transmit packet size = %d too big", packet->data_size); return 0; } @@ -587,24 +631,8 @@ /* Decide wether we have a request or a response packet */ tcode = (packet->header[0]>>4)&0xf; - if ((tcode==TCODE_READQ)|| - (tcode==TCODE_WRITEQ)|| - (tcode==TCODE_READB)|| - (tcode==TCODE_WRITEB)|| - (tcode==TCODE_LOCK_REQUEST)) - d = ohci->at_req_context; - - else if ((tcode==TCODE_WRITE_RESPONSE)|| - (tcode==TCODE_READQ_RESPONSE)|| - (tcode==TCODE_READB_RESPONSE)|| - (tcode==TCODE_LOCK_RESPONSE)) - d = ohci->at_resp_context; - - else { - PRINT(KERN_ERR, ohci->id, - "Unexpected packet tcode=%d in AT DMA", tcode); - return 0; - } + if (tcode & 0x02) d = ohci->at_resp_context; + else d = ohci->at_req_context; spin_lock(&d->lock); @@ -659,6 +687,7 @@ switch (cmd) { case RESET_BUS: + host->attempt_root=1; PRINT(KERN_INFO, ohci->id, "resetting bus on request%s", (host->attempt_root ? " and attempting to become root" : "")); @@ -679,15 +708,21 @@ break; case ACT_CYCLE_MASTER: -#if 0 if (arg) { - /* enable cycleTimer, cycleMaster, cycleSource */ - reg_write(ohci, OHCI1394_LinkControlSet, 0x00700000); + /* check if we are root and other nodes are present */ + u32 nodeId = reg_read(ohci, OHCI1394_NodeID); + if ((nodeId & (1<<30)) && (nodeId & 0x3f)) { + /* + * enable cycleTimer cycleMaster cycleSource + */ + DBGMSG(ohci->id, "Cycle master enabled"); + reg_write(ohci, OHCI1394_LinkControlSet, + 0x00700000); + } } else { /* disable cycleTimer, cycleMaster, cycleSource */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000); - }; -#endif + } break; case CANCEL_REQUESTS: @@ -811,8 +846,20 @@ struct hpsb_host *host = ohci->host; int phyid = -1, isroot = 0; + /* read the interrupt event register */ event=reg_read(ohci, OHCI1394_IntEventSet); +#if 0 + /* + * clear the interrupt event register, except for the + * bus reset event interrupt (if any). This is an + * attempt to comply with ohci spec 7.2.3.2 + */ + reg_write(ohci, OHCI1394_IntEventClear, event & (~OHCI1394_busReset)); +#else + /* The above attempt doesn't work */ + reg_write(ohci, OHCI1394_IntEventClear, event); +#endif if (event & OHCI1394_busReset) { if (!host->in_bus_reset) { PRINT(KERN_INFO, ohci->id, "Bus reset"); @@ -821,6 +868,11 @@ dma_trm_reset(ohci->at_req_context); dma_trm_reset(ohci->at_resp_context); +#if 0 + /* clear the bus reset event */ + reg_write(ohci, OHCI1394_IntEventClear, + OHCI1394_busReset); +#endif /* Subsystem call */ hpsb_bus_reset(ohci->host); @@ -891,7 +943,7 @@ if (event & OHCI1394_selfIDComplete) { if (host->in_bus_reset) { node_id = reg_read(ohci, OHCI1394_NodeID); - if (node_id & 0x8000000) { /* NodeID valid */ + if (node_id & 0x80000000) { /* NodeID valid */ phyid = node_id & 0x0000003f; isroot = (node_id & 0x40000000) != 0; @@ -924,8 +976,6 @@ #endif } - /* clear the interrupt event register */ - reg_write(ohci, OHCI1394_IntEventClear, event); } /* Put the buffer back into the dma context */ @@ -963,44 +1013,34 @@ return length; } -static int packet_length(struct dma_rcv_ctx *d, int idx, - quadlet_t *buf_ptr, int offset) +const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, + -1, 0, -1, 0, -1, -1, 16, -1}; + +/* + * Determine the length of a packet in the buffer + * Optimization suggested by Pascal Drolet + */ +static int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr, +int offset) { - unsigned char tcode; - int length; + unsigned char tcode; + int length = -1; /* Let's see what kind of packet is in there */ - tcode = (buf_ptr[0]>>4)&0xf; + tcode = (buf_ptr[0] >> 4) & 0xf; - if (d->ctx==0) { /* Async Receive Request */ - if (tcode==TCODE_READQ) return 16; - else if (tcode==TCODE_WRITEQ || - tcode==TCODE_READB) return 20; - else if (tcode==TCODE_WRITEB || - tcode==TCODE_LOCK_REQUEST) { - return block_length(d, idx, buf_ptr, offset) + 20; - } - else if (tcode==0xE) { /* Phy packet */ - return 16; - } - else return -1; - } - else if (d->ctx==1) { /* Async Receive Response */ - if (tcode==TCODE_WRITE_RESPONSE) return 16; - else if (tcode==TCODE_READQ_RESPONSE) return 20; - else if (tcode==TCODE_READB_RESPONSE || - tcode==TCODE_LOCK_RESPONSE) { - return block_length(d, idx, buf_ptr, offset) + 20; - } - else return -1; + if (d->ctx < 2) { /* Async Receive Response/Request */ + length = TCODE_SIZE[tcode]; + if (length == 0) + length = block_length(d, idx, buf_ptr, offset) + 20; } else if (d->ctx==2) { /* Iso receive */ /* Assumption: buffer fill mode with header/trailer */ length = (buf_ptr[0]>>16); if (length % 4) length += 4 - (length % 4); - return length+8; + length+=8; } - return -1; + return length; } /* Bottom half that processes dma receive buffers */ @@ -1336,6 +1376,7 @@ static int add_card(struct pci_dev *dev) { struct ti_ohci *ohci; /* shortcut to currently handled device */ + int i; if (num_of_cards == MAX_OHCI1394_CARDS) { PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " @@ -1344,6 +1385,10 @@ return 1; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + pci_enable_device(dev); +#endif + ohci = &cards[num_of_cards++]; ohci->id = num_of_cards-1; @@ -1363,7 +1408,11 @@ if (ohci->csr_config_rom == NULL) { FAIL("failed to allocate buffer config rom"); } - memcpy(ohci->csr_config_rom, ohci_csr_rom, sizeof(ohci_csr_rom)); + for (i=0;icsr_config_rom[i] = cpu_to_be32(ohci_csr_rom[i]); + + DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x", + *((char *)ohci->csr_config_rom+4)); /* self-id dma buffer allocation */ ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h --- v2.3.99-pre2/linux/drivers/ieee1394/ohci1394.h Sun Feb 20 21:12:39 2000 +++ linux/drivers/ieee1394/ohci1394.h Wed Mar 22 00:02:49 2000 @@ -4,16 +4,18 @@ #include "ieee1394_types.h" -#define OHCI1394_DEBUG 1 - #define OHCI1394_DRIVER_NAME "ohci1394" -#ifndef PCI_DEVICE_ID_TI_OHCI1394 -#define PCI_DEVICE_ID_TI_OHCI1394 0x8009 -#endif +#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV22 +#define PCI_DEVICE_ID_TI_OHCI1394_LV22 0x8009 +#endif + +#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV23 +#define PCI_DEVICE_ID_TI_OHCI1394_LV23 0x8019 +#endif -#ifndef PCI_DEVICE_ID_TI_OHCI1394_2 -#define PCI_DEVICE_ID_TI_OHCI1394_2 0x8019 +#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV26 +#define PCI_DEVICE_ID_TI_OHCI1394_LV26 0x8020 #endif #ifndef PCI_DEVICE_ID_VIA_OHCI1394 @@ -28,6 +30,22 @@ #define PCI_DEVICE_ID_SONY_CXD3222 0x8039 #endif +#ifndef PCI_DEVICE_ID_NEC_1394 +#define PCI_DEVICE_ID_NEC_1394 0x00cd +#endif + +#ifndef PCI_DEVICE_ID_NEC_UPD72862 +#define PCI_DEVICE_ID_NEC_UPD72862 0x0063 +#endif + +#ifndef PCI_DEVICE_ID_NEC_UPD72870 +#define PCI_DEVICE_ID_NEC_UPD72870 0x00cd +#endif + +#ifndef PCI_DEVICE_ID_NEC_UPD72871 +#define PCI_DEVICE_ID_NEC_UPD72871 0x00ce +#endif + #define MAX_OHCI1394_CARDS 4 #define OHCI1394_MAX_AT_REQ_RETRIES 0x2 @@ -113,6 +131,8 @@ quadlet_t *self_id_buffer; /* dma buffer for self-id packets */ quadlet_t *csr_config_rom; /* buffer for csr config rom */ + unsigned int max_packet_size; + /* async receive */ struct dma_rcv_ctx *ar_resp_context; struct dma_rcv_ctx *ar_req_context; @@ -125,6 +145,7 @@ struct dma_rcv_ctx *ir_context; u64 IR_channel_usage; spinlock_t IR_channel_lock; + int nb_iso_ctx; /* IEEE-1394 part follows */ struct hpsb_host *host; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c --- v2.3.99-pre2/linux/drivers/ieee1394/pcilynx.c Thu Feb 10 17:11:09 2000 +++ linux/drivers/ieee1394/pcilynx.c Wed Mar 22 00:02:49 2000 @@ -59,6 +59,13 @@ /* print card specific information */ #define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) +#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) +#else +#define PRINT_GD(level, fmt, args...) +#define PRINTD(level, card, fmt, args...) +#endif static struct ti_lynx cards[MAX_PCILYNX_CARDS]; static int num_of_cards = 0; @@ -313,7 +320,8 @@ } } - printk("-%d- generated own selfid 0x%x\n", lynx->id, lsid); + cpu_to_be32s(&lsid); + PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid); return lsid; } @@ -322,7 +330,14 @@ quadlet_t *q = lynx->rcv_page; int phyid, isroot; quadlet_t lsid = 0; + int i; + i = (size > 16 ? 16 : size) / 4 - 1; + while (i >= 0) { + cpu_to_be32s(&q[i]); + i--; + } + if (!lynx->phyic.reg_1394a) { lsid = generate_own_selfid(lynx, host); } @@ -339,17 +354,20 @@ } while (size > 0) { - if (!lynx->phyic.reg_1394a - && (q[0] & 0x3f800000) == ((phyid + 1) << 24)) { + struct selfid *sid = (struct selfid *)q; + + if (!lynx->phyic.reg_1394a && !sid->extended + && (sid->phy_id == (phyid + 1))) { hpsb_selfid_received(host, lsid); } if (q[0] == ~q[1]) { - printk("-%d- selfid packet 0x%x rcvd\n", lynx->id, q[0]); + PRINT(KERN_DEBUG, lynx->id, "selfid packet 0x%x rcvd", + q[0]); hpsb_selfid_received(host, q[0]); } else { - printk("-%d- inconsistent selfid 0x%x/0x%x\n", lynx->id, - q[0], q[1]); + PRINT(KERN_INFO, lynx->id, + "inconsistent selfid 0x%x/0x%x", q[0], q[1]); } q += 2; size -= 8; @@ -429,14 +447,14 @@ pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; #ifdef __BIG_ENDIAN - pcl.buffer[0].control = PCL_CMD_RCV | 2048; - pcl.buffer[1].control = PCL_LAST_BUFF | 2048; + pcl.buffer[0].control = PCL_CMD_RCV | 16; + pcl.buffer[1].control = PCL_LAST_BUFF | 4080; #else - pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 2048; - pcl.buffer[1].control = PCL_LAST_BUFF | PCL_BIGENDIAN | 2048; + pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16; + pcl.buffer[1].control = PCL_LAST_BUFF | 4080; #endif pcl.buffer[0].pointer = virt_to_bus(lynx->rcv_page); - pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 2048; + pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 16; put_pcl(lynx, lynx->rcv_pcl, &pcl); pcl.next = pcl_bus(lynx, lynx->async_pcl); @@ -445,10 +463,11 @@ pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; - pcl.buffer[0].control = PCL_CMD_RCV | PCL_LAST_BUFF | 2048; + pcl.buffer[0].control = PCL_CMD_RCV | 4; #ifndef __BIG_ENDIAN pcl.buffer[0].control |= PCL_BIGENDIAN; #endif + pcl.buffer[1].control = PCL_LAST_BUFF | 2044; for (i = 0; i < NUM_ISORCV_PCL; i++) { int page = i / ISORCV_PER_PAGE; @@ -456,6 +475,7 @@ pcl.buffer[0].pointer = virt_to_bus(lynx->iso_rcv.page[page]) + sec * MAX_ISORCV_SIZE; + pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4; put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl); } @@ -539,6 +559,10 @@ } packet->xnext = NULL; + if (packet->tcode == TCODE_WRITEQ + || packet->tcode == TCODE_READQ_RESPONSE) { + cpu_to_be32s(&packet->header[3]); + } spin_lock_irqsave(&lynx->async_queue_lock, flags); @@ -1054,8 +1078,8 @@ } if (linkint & LINK_INT_PHY_REG_RCVD) { if (!host->in_bus_reset) { - printk("-%d- phy reg received without reset\n", - lynx->id); + PRINT(KERN_INFO, lynx->id, + "phy reg received without reset"); } } if (linkint & LINK_INT_ISO_STUCK) { @@ -1082,7 +1106,7 @@ } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) { - PRINT(KERN_INFO, lynx->id, "iso receive"); + PRINTD(KERN_DEBUG, lynx->id, "iso receive"); spin_lock(&lynx->iso_rcv.lock); @@ -1094,7 +1118,7 @@ if ((lynx->iso_rcv.next == lynx->iso_rcv.last) || !lynx->iso_rcv.chan_count) { - printk("stopped\n"); + PRINTD(KERN_DEBUG, lynx->id, "stopped"); reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0); } @@ -1125,9 +1149,9 @@ spin_unlock(&lynx->async_queue_lock); if (ack & DMA_CHAN_STAT_SPECIALACK) { - printk("-%d- special ack %d\n", lynx->id, - (ack >> 15) & 0xf); - ack = ACKX_SEND_ERROR; + ack = (ack >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); } else { ack = (ack >> 15) & 0xf; } @@ -1139,7 +1163,7 @@ /* general receive DMA completed */ int stat = reg_read(lynx, DMA1_CHAN_STAT); - printk("-%d- received packet size %d\n", lynx->id, + PRINTD(KERN_DEBUG, lynx->id, "received packet size %d", stat & 0x1fff); if (stat & DMA_CHAN_STAT_SELFID) { @@ -1149,8 +1173,12 @@ | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN); } else { - hpsb_packet_received(host, lynx->rcv_page, - stat & 0x1fff); + quadlet_t *q_data = lynx->rcv_page; + if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE + || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) { + cpu_to_be32s(q_data + 3); + } + hpsb_packet_received(host, q_data, stat & 0x1fff); } run_pcl(lynx, lynx->rcv_pcl_start, 1); @@ -1411,7 +1439,7 @@ } if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) { - PRINT_G(KERN_ERR, "allocation of char major number %d failed\n", + PRINT_G(KERN_ERR, "allocation of char major number %d failed", PCILYNX_MAJOR); return -EBUSY; } @@ -1453,13 +1481,13 @@ void cleanup_module(void) { hpsb_unregister_lowlevel(get_lynx_template()); - PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module\n"); + PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module"); } int init_module(void) { if (hpsb_register_lowlevel(get_lynx_template())) { - PRINT_G(KERN_ERR, "registering failed\n"); + PRINT_G(KERN_ERR, "registering failed"); return -ENXIO; } else { return 0; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/pcilynx.h linux/drivers/ieee1394/pcilynx.h --- v2.3.99-pre2/linux/drivers/ieee1394/pcilynx.h Sun Feb 20 21:12:39 2000 +++ linux/drivers/ieee1394/pcilynx.h Wed Mar 22 22:22:05 2000 @@ -462,71 +462,75 @@ #define PCL_BIGENDIAN (1<<16) +#define _(x) (__constant_cpu_to_be32(x)) + quadlet_t lynx_csr_rom[] = { /* bus info block */ - 0x04040000, /* info/CRC length, CRC */ - 0x31333934, /* 1394 magic number */ - 0xf064a000, /* misc. settings */ - 0x08002850, /* vendor ID, chip ID high */ - 0x0000ffff, /* chip ID low */ + _(0x04040000), /* info/CRC length, CRC */ + _(0x31333934), /* 1394 magic number */ + _(0xf064a000), /* misc. settings */ + _(0x08002850), /* vendor ID, chip ID high */ + _(0x0000ffff), /* chip ID low */ /* root directory */ - 0x00090000, /* CRC length, CRC */ - 0x03080028, /* vendor ID (Texas Instr.) */ - 0x81000009, /* offset to textual ID */ - 0x0c000200, /* node capabilities */ - 0x8d00000e, /* offset to unique ID */ - 0xc7000010, /* offset to module independent info */ - 0x04000000, /* module hardware version */ - 0x81000026, /* offset to textual ID */ - 0x09000000, /* node hardware version */ - 0x81000026, /* offset to textual ID */ + _(0x00090000), /* CRC length, CRC */ + _(0x03080028), /* vendor ID (Texas Instr.) */ + _(0x81000009), /* offset to textual ID */ + _(0x0c000200), /* node capabilities */ + _(0x8d00000e), /* offset to unique ID */ + _(0xc7000010), /* offset to module independent info */ + _(0x04000000), /* module hardware version */ + _(0x81000026), /* offset to textual ID */ + _(0x09000000), /* node hardware version */ + _(0x81000026), /* offset to textual ID */ /* module vendor ID textual */ - 0x00080000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x54455841, /* "Texas Instruments" */ - 0x5320494e, - 0x53545255, - 0x4d454e54, - 0x53000000, + _(0x00080000), /* CRC length, CRC */ + _(0x00000000), + _(0x00000000), + _(0x54455841), /* "Texas Instruments" */ + _(0x5320494e), + _(0x53545255), + _(0x4d454e54), + _(0x53000000), /* node unique ID leaf */ - 0x00020000, /* CRC length, CRC */ - 0x08002850, /* vendor ID, chip ID high */ - 0x0000ffff, /* chip ID low */ + _(0x00020000), /* CRC length, CRC */ + _(0x08002850), /* vendor ID, chip ID high */ + _(0x0000ffff), /* chip ID low */ /* module dependent info */ - 0x00060000, /* CRC length, CRC */ - 0xb8000006, /* offset to module textual ID */ - 0x81000004, /* ??? textual descriptor */ - 0x39010000, /* SRAM size */ - 0x3a010000, /* AUXRAM size */ - 0x3b000000, /* AUX device */ + _(0x00060000), /* CRC length, CRC */ + _(0xb8000006), /* offset to module textual ID */ + _(0x81000004), /* ??? textual descriptor */ + _(0x39010000), /* SRAM size */ + _(0x3a010000), /* AUXRAM size */ + _(0x3b000000), /* AUX device */ /* module textual ID */ - 0x00050000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x54534231, /* "TSB12LV21" */ - 0x324c5632, - 0x31000000, + _(0x00050000), /* CRC length, CRC */ + _(0x00000000), + _(0x00000000), + _(0x54534231), /* "TSB12LV21" */ + _(0x324c5632), + _(0x31000000), /* part number */ - 0x00060000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x39383036, /* "9806000-0001" */ - 0x3030342d, - 0x30303431, - 0x20000001, + _(0x00060000), /* CRC length, CRC */ + _(0x00000000), + _(0x00000000), + _(0x39383036), /* "9806000-0001" */ + _(0x3030342d), + _(0x30303431), + _(0x20000001), /* module hardware version textual */ - 0x00050000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x5453424b, /* "TSBKPCITST" */ - 0x50434954, - 0x53540000, + _(0x00050000), /* CRC length, CRC */ + _(0x00000000), + _(0x00000000), + _(0x5453424b), /* "TSBKPCITST" */ + _(0x50434954), + _(0x53540000), /* node hardware version textual */ - 0x00050000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x54534232, /* "TSB21LV03" */ - 0x313c5630, - 0x33000000 + _(0x00050000), /* CRC length, CRC */ + _(0x00000000), + _(0x00000000), + _(0x54534232), /* "TSB21LV03" */ + _(0x313c5630), + _(0x33000000) }; + +#undef _ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c --- v2.3.99-pre2/linux/drivers/ieee1394/raw1394.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/ieee1394/raw1394.c Wed Mar 22 00:02:49 2000 @@ -59,7 +59,7 @@ { if (req->ibs) { if (atomic_dec_and_test(&req->ibs->refcount)) { - atomic_sub((req->data[0] >> 16) + 4, &iso_buffer_size); + atomic_sub(req->ibs->data_size, &iso_buffer_size); kfree(req->ibs); } } else if (req->free_data) { @@ -109,6 +109,7 @@ } free_tlabel(packet->host, packet->node_id, packet->tlabel); + queue_complete_req(req); } @@ -215,6 +216,7 @@ LIST_HEAD(reqs); if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { + HPSB_INFO("dropped iso packet"); return; } @@ -230,22 +232,23 @@ continue; } + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) break; + if (!ibs) { ibs = kmalloc(sizeof(struct iso_block_store) + length, SLAB_ATOMIC); - if (!ibs) break; + if (!ibs) { + kfree(req); + break; + } atomic_add(length, &iso_buffer_size); atomic_set(&ibs->refcount, 0); + ibs->data_size = length; memcpy(ibs->data, data, length); } - req = __alloc_pending_request(SLAB_ATOMIC); - if (!req) { - kfree(ibs); - break; - } - atomic_inc(&ibs->refcount); req->file_info = fi; @@ -270,6 +273,75 @@ } } +static void fcp_request(struct hpsb_host *host, int nodeid, int direction, + int cts, u8 *data, unsigned int length) +{ + unsigned long flags; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi; + struct pending_request *req; + struct iso_block_store *ibs = NULL; + LIST_HEAD(reqs); + + if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { + HPSB_INFO("dropped fcp request"); + return; + } + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(host); + + if (hi != NULL) { + for (lh = hi->file_info_list.next; lh != &hi->file_info_list; + lh = lh->next) { + fi = list_entry(lh, struct file_info, list); + + if (!fi->fcp_buffer) { + continue; + } + + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) break; + + if (!ibs) { + ibs = kmalloc(sizeof(struct iso_block_store) + + length, SLAB_ATOMIC); + if (!ibs) { + kfree(req); + break; + } + + atomic_add(length, &iso_buffer_size); + atomic_set(&ibs->refcount, 0); + ibs->data_size = length; + memcpy(ibs->data, data, length); + } + + atomic_inc(&ibs->refcount); + + req->file_info = fi; + req->ibs = ibs; + req->data = ibs->data; + req->req.type = RAW1394_REQ_FCP_REQUEST; + req->req.generation = get_hpsb_generation(); + req->req.misc = nodeid | (direction << 16); + req->req.recvb = (quadlet_t *)fi->fcp_buffer; + req->req.length = length; + + list_add_tail(&req->list, &reqs); + } + } + spin_unlock_irqrestore(&host_info_lock, flags); + + lh = reqs.next; + while (lh != &reqs) { + req = list_entry(lh, struct pending_request, list); + lh = lh->next; + queue_complete_req(req); + } +} + static int dev_read(struct file *file, char *buffer, size_t count, loff_t *offset_is_ignored) @@ -455,8 +527,28 @@ spin_unlock(&host_info_lock); } +static void handle_fcp_listen(struct file_info *fi, struct pending_request *req) +{ + if (req->req.misc) { + if (fi->fcp_buffer) { + req->req.error = RAW1394_ERROR_ALREADY; + } else { + fi->fcp_buffer = (u8 *)req->req.recvb; + } + } else { + if (!fi->fcp_buffer) { + req->req.error = RAW1394_ERROR_ALREADY; + } else { + fi->fcp_buffer = NULL; + } + } + + req->req.length = 0; + queue_complete_req(req); +} + static int handle_local_request(struct file_info *fi, - struct pending_request *req) + struct pending_request *req, int node) { u64 addr = req->req.address & 0xffffffffffffULL; @@ -466,7 +558,7 @@ switch (req->req.type) { case RAW1394_REQ_ASYNC_READ: - req->req.error = highlevel_read(fi->host, req->data, addr, + req->req.error = highlevel_read(fi->host, node, req->data, addr, req->req.length); break; @@ -477,8 +569,8 @@ break; } - req->req.error = highlevel_write(fi->host, req->data, addr, - req->req.length); + req->req.error = highlevel_write(fi->host, node, req->data, + addr, req->req.length); req->req.length = 0; break; @@ -503,14 +595,16 @@ } if (req->req.length == 8) { - req->req.error = highlevel_lock(fi->host, req->data, - addr, req->data[1], + req->req.error = highlevel_lock(fi->host, node, + req->data, addr, + req->data[1], req->data[0], req->req.misc); req->req.length = 4; } else { - req->req.error = highlevel_lock(fi->host, req->data, - addr, req->data[0], 0, + req->req.error = highlevel_lock(fi->host, node, + req->data, addr, + req->data[0], 0, req->req.misc); } break; @@ -539,28 +633,27 @@ if (!packet) return -ENOMEM; req->data = &packet->header[3]; - } else if ((req->req.length % 4) == 0) { + } else { packet = hpsb_make_readbpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; req->data = packet->data; - } else { - req->req.error = RAW1394_ERROR_UNTIDY_LEN; } break; case RAW1394_REQ_ASYNC_WRITE: if (req->req.length == 4) { - packet = hpsb_make_writeqpacket(fi->host, node, addr, - 0); - if (!packet) return -ENOMEM; + quadlet_t x; - if (copy_from_user(&packet->header[3], req->req.sendb, - 4)) { + if (copy_from_user(&x, req->req.sendb, 4)) { req->req.error = RAW1394_ERROR_MEMFAULT; } - } else if ((req->req.length % 4) == 0) { + + packet = hpsb_make_writeqpacket(fi->host, node, addr, + x); + if (!packet) return -ENOMEM; + } else { packet = hpsb_make_writebpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; @@ -569,8 +662,6 @@ req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; } - } else { - req->req.error = RAW1394_ERROR_UNTIDY_LEN; } req->req.length = 0; break; @@ -649,6 +740,11 @@ return sizeof(struct raw1394_request); } + if (req->req.type == RAW1394_REQ_FCP_LISTEN) { + handle_fcp_listen(fi, req); + return sizeof(struct raw1394_request); + } + if (req->req.length == 0) { req->req.error = RAW1394_ERROR_INVALID_ARG; queue_complete_req(req); @@ -656,7 +752,7 @@ } if (fi->host->node_id == node) { - return handle_local_request(fi, req); + return handle_local_request(fi, req, node); } return handle_remote_request(fi, req, node); @@ -806,10 +902,11 @@ } static struct hpsb_highlevel_ops hl_ops = { - add_host, - remove_host, - host_reset, - iso_receive + add_host: add_host, + remove_host: remove_host, + host_reset: host_reset, + iso_receive: iso_receive, + fcp_request: fcp_request, }; static struct file_operations file_ops = { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/ieee1394/raw1394.h linux/drivers/ieee1394/raw1394.h --- v2.3.99-pre2/linux/drivers/ieee1394/raw1394.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/raw1394.h Wed Mar 22 00:02:49 2000 @@ -5,7 +5,7 @@ #define RAW1394_DEVICE_MAJOR 171 #define RAW1394_DEVICE_NAME "raw1394" -#define RAW1394_KERNELAPI_VERSION 1 +#define RAW1394_KERNELAPI_VERSION 2 /* state: opened */ #define RAW1394_REQ_INITIALIZE 1 @@ -21,10 +21,12 @@ #define RAW1394_REQ_LOCK64 103 #define RAW1394_REQ_ISO_LISTEN 200 +#define RAW1394_REQ_FCP_LISTEN 201 /* kernel to user */ #define RAW1394_REQ_BUS_RESET 10000 #define RAW1394_REQ_ISO_RECEIVE 10001 +#define RAW1394_REQ_FCP_REQUEST 10002 /* error codes */ #define RAW1394_ERROR_NONE 0 @@ -67,6 +69,7 @@ struct iso_block_store { atomic_t refcount; + size_t data_size; quadlet_t data[0]; }; @@ -82,6 +85,8 @@ struct semaphore complete_sem; spinlock_t reqlists_lock; wait_queue_head_t poll_wait_complete; + + u8 *fcp_buffer; u64 listen_channels; quadlet_t *iso_buffer; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.3.99-pre2/linux/drivers/isdn/Config.in Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/Config.in Thu Mar 23 08:38:57 2000 @@ -85,8 +85,14 @@ if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA fi -dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN -if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then +dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then + bool 'CAPI2.0 Middleware support' CONFIG_ISDN_CAPI_MIDDLEWARE + if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" != "n" ]; then + bool 'CAPI2.0 filesystem support' CONFIG_ISDN_CAPIFS + fi +fi +if [ "$CONFIG_ISDN_CAPI" != "n" ]; then bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.3.99-pre2/linux/drivers/isdn/Makefile Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/Makefile Thu Mar 23 08:38:57 2000 @@ -97,12 +97,12 @@ endif endif -ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) +ifeq ($(CONFIG_ISDN_CAPI),y) L_OBJS += avmb1/avmb1.o SUB_DIRS += avmb1 MOD_SUB_DIRS += avmb1 else - ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) + ifeq ($(CONFIG_ISDN_CAPI),m) MOD_SUB_DIRS += avmb1 endif endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/Makefile linux/drivers/isdn/avmb1/Makefile --- v2.3.99-pre2/linux/drivers/isdn/avmb1/Makefile Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/Makefile Thu Mar 23 08:38:57 2000 @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $ +# $Id: Makefile,v 1.16 2000/03/17 12:15:44 calle Exp $ # # Makefile for the CAPI and AVM-B1 device drivers. # @@ -11,6 +11,49 @@ # parent makes.. # # $Log: Makefile,v $ +# Revision 1.16 2000/03/17 12:15:44 calle +# ALL_SUB_DIRS were wrong. +# +# Revision 1.15 2000/03/16 15:21:03 calle +# Bugfix in c4_remove: loop 5 times instead of 4 :-( +# +# Revision 1.14 2000/03/13 17:50:55 calle +# Added avm_cs.c for 2.3.x PCMCIA support. +# +# Revision 1.13 2000/03/08 17:06:33 calle +# - changes for devfs and 2.3.49 +# - capifs now configurable (no need with devfs) +# - New Middleware ioctl CAPI_NCCI_GETUNIT +# - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) +# +# Revision 1.12 2000/03/06 18:00:23 calle +# - Middleware extention now working with 2.3.49 (capifs). +# - Fixed typos in debug section of capi.c +# - Bugfix: Makefile corrected for b1pcmcia.c +# +# Revision 1.11 2000/03/06 09:17:07 calle +# - capifs: fileoperations now in inode (change for 2.3.49) +# - Config.in: Middleware extention not a tristate, uups. +# +# Revision 1.10 2000/03/03 16:48:38 calle +# - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) +# It is now possible to create a connection with a CAPI2.0 applikation +# and than to handle the data connection from /dev/capi/ (capifs) and also +# using async or sync PPP on this connection. +# The two major device number 190 and 191 are not confirmed yet, +# but I want to save the code in cvs, before I go on. +# +# Revision 1.9 2000/03/03 15:50:42 calle +# - kernel CAPI: +# - Changed parameter "param" in capi_signal from __u32 to void *. +# - rewrote notifier handling in kcapi.c +# - new notifier NCCI_UP and NCCI_DOWN +# - User CAPI: +# - /dev/capi20 is now a cloning device. +# - middleware extentions prepared. +# - capidrv.c +# - locking of list operations and module count updates. +# # Revision 1.8 2000/01/25 14:33:38 calle # - Added Support AVM B1 PCI V4.0 (tested with prototype) # - splitted up t1pci.c into b1dma.c for common function with b1pciv4 @@ -64,6 +107,9 @@ # # +SUB_DIRS := +MOD_SUB_DIRS := +ALL_SUB_DIRS := # fcpci fcclassic # # Objects that don't export a symtab # @@ -82,53 +128,78 @@ O_TARGET := # used for .o targets (from O and OX objects) L_TARGET := # used for .a targets (from L and LX objects) -ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) +ifeq ($(CONFIG_ISDN_CAPI),y) O_TARGET += avmb1.o OX_OBJS += kcapi.o O_OBJS += capi.o + ifdef CONFIG_ISDN_CAPIFS + OX_OBJS += capifs.o + endif ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA - O_OBJS += b1isa.o + O_OBJS += b1isa.o endif ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI - O_OBJS += b1pci.o + O_OBJS += b1pci.o endif ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA - O_OBJS += t1isa.o + O_OBJS += t1isa.o endif ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA - OX_OBJS += b1pcmcia.o + OX_OBJS += b1pcmcia.o endif ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI - O_OBJS += t1pci.o + O_OBJS += t1pci.o endif ifdef CONFIG_ISDN_DRV_AVMB1_C4 - O_OBJS += c4.o + O_OBJS += c4.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI + SUB_DIRS += fcpci + MOD_SUB_DIRS += fcpci + endif + ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC + SUB_DIRS += fcclassic + MOD_SUB_DIRS += fcclassic endif OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o else - ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) - O_TARGET += kernelcapi.o - OX_OBJS += kcapi.o - M_OBJS += capi.o kernelcapi.o - ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA - M_OBJS += b1isa.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI - M_OBJS += b1pci.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA - M_OBJS += t1isa.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA - MX_OBJS += b1pcmcia.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI - M_OBJS += t1pci.o - endif - ifdef CONFIG_ISDN_DRV_AVMB1_C4 - M_OBJS += c4.o - endif - MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o + ifeq ($(CONFIG_ISDN_CAPI),m) + O_TARGET += kernelcapi.o + OX_OBJS += kcapi.o + M_OBJS += capi.o kernelcapi.o + ifdef CONFIG_ISDN_CAPIFS + MX_OBJS += capifs.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA + M_OBJS += b1isa.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI + M_OBJS += b1pci.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA + M_OBJS += t1isa.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA + MX_OBJS += b1pcmcia.o + ifeq ($(CONFIG_HOTPLUG),y) + ifneq ($(CONFIG_PCMCIA),n) + M_OBJS += avm_cs.o + endif + endif + endif + ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI + M_OBJS += t1pci.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_C4 + M_OBJS += c4.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI + MOD_SUB_DIRS += fcpci + endif + ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC + MOD_SUB_DIRS += fcclassic + endif + MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o endif endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/avm_cs.c linux/drivers/isdn/avmb1/avm_cs.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/avm_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/avm_cs.c Thu Mar 23 08:38:57 2000 @@ -0,0 +1,528 @@ +/*====================================================================== + + A PCMCIA client driver for AVM B1/M1/M2 + + Written by Carsten Paeth, calle@calle.in-berlin.de + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* This means pick from 15, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static int default_irq_list[10] = { 15, 12, 11, 10, 9, 7, 5, 4, 3, -1 }; +static int irq_list[10] = { -1 }; + +MODULE_PARM(irq_list, "1-10i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card insertion + and ejection events. They are invoked from the skeleton event + handler. +*/ + +static void avmcs_config(dev_link_t *link); +static void avmcs_release(u_long arg); +static int avmcs_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *avmcs_attach(void); +static void avmcs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "avm_cs"; + +/* + A linked list of "instances" of the skeleton device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally can't be allocated dynamically. +*/ + +typedef struct local_info_t { + dev_node_t node; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + avmcs_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *avmcs_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &avmcs_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts2 = 16; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] != -1) { + for (i = 0; i < 10 && irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } else { + for (i = 0; i < 10 && default_irq_list[i] > 0; i++) + link->irq.IRQInfo2 |= 1 << default_irq_list[i]; + } + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &avmcs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + avmcs_detach(link); + return NULL; + } + + return link; +} /* avmcs_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void avmcs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + kfree_s(link->priv, sizeof(local_info_t)); + } + kfree_s(link, sizeof(struct dev_link_t)); + +} /* avmcs_detach */ + +/*====================================================================== + + avmcs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +======================================================================*/ + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, + cisparse_t *parse) +{ + int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) return i; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) return i; + return CardServices(ParseTuple, handle, tuple, parse); +} + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +static void avmcs_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + local_info_t *dev; + int i; + u_char buf[64]; + char devname[128]; + int cardtype; + int (*addcard)(unsigned int port, unsigned irq); + + handle = link->handle; + dev = link->priv; + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + do { + tuple.DesiredTuple = CISTPL_CONFIG; + i = CardServices(GetFirstTuple, handle, &tuple); + if (i != CS_SUCCESS) break; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + i = CardServices(GetTupleData, handle, &tuple); + if (i != CS_SUCCESS) break; + i = CardServices(ParseTuple, handle, &tuple, &parse); + if (i != CS_SUCCESS) break; + link->conf.ConfigBase = parse.config.base; + } while (0); + if (i != CS_SUCCESS) { + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; + return; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + + do { + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 254; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_VERS_1; + + devname[0] = 0; + if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { + strncpy(devname,parse.version_1.str + parse.version_1.ofs[1], + sizeof(devname)); + } + /* + * find IO port + */ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if (cf->io.nwin > 0) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; + printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", + link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1); + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) goto found_port; + } + i = next_tuple(handle, &tuple, &parse); + } + +found_port: + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + break; + } + + /* + * allocate an interrupt line + */ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + CardServices(ReleaseIO, link->handle, &link->io); + break; + } + + /* + * configure the PCMCIA socket + */ + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + break; + } + + } while (0); + + /* At this point, the dev_node_t structure(s) should be + initialized and arranged in a linked list at link->dev. */ + + if (devname[0]) { + char *s = strrchr(devname, ' '); + if (!s) + s = devname; + else s++; + strcpy(dev->node.dev_name, s); + if (strcmp("M1", s) == 0) { + cardtype = AVM_CARDTYPE_M1; + } else if (strcmp("M2", s) == 0) { + cardtype = AVM_CARDTYPE_M2; + } else { + cardtype = AVM_CARDTYPE_B1; + } + } else { + strcpy(dev->node.dev_name, "b1"); + cardtype = AVM_CARDTYPE_B1; + } + + dev->node.major = 64; + dev->node.minor = 0; + link->dev = &dev->node; + + link->state &= ~DEV_CONFIG_PENDING; + /* If any step failed, release any partially configured state */ + if (i != 0) { + avmcs_release((u_long)link); + return; + } + + + switch (cardtype) { + case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break; + case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break; + default: + case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break; + } + if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) { + printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n", + dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ); + avmcs_release((u_long)link); + return; + } + dev->node.minor = i; + +} /* avmcs_config */ + +/*====================================================================== + + After a card is removed, avmcs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void avmcs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + /* + If the device is currently in use, we won't release until it + is actually closed. + */ + if (link->open) { + link->state |= DEV_STALE_CONFIG; + return; + } + + b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); + + /* Unlink the device chain */ + link->dev = NULL; + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + avmcs_detach(link); + +} /* avmcs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ + +static int avmcs_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + (HZ/20); + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + avmcs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + return 0; +} /* avmcs_event */ + +/*====================================================================*/ + +int init_module(void) +{ + servinfo_t serv; + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "avm_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach); + return 0; +} + +void cleanup_module(void) +{ + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + avmcs_release((u_long)dev_list); + avmcs_detach(dev_list); + } +} diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/b1dma.c Tue Mar 7 14:32:25 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Thu Mar 23 08:38:57 2000 @@ -40,7 +40,7 @@ MODULE_AUTHOR("Carsten Paeth "); -static int suppress_pollack = 0; +int suppress_pollack = 0; MODULE_PARM(suppress_pollack, "0-1i"); /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/b1pcmcia.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/b1pcmcia.c Thu Mar 23 23:18:20 2000 @@ -1,11 +1,16 @@ /* - * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $ + * $Id: b1pcmcia.c,v 1.8 2000/03/06 18:00:23 calle Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.8 2000/03/06 18:00:23 calle + * - Middleware extention now working with 2.3.49 (capifs). + * - Fixed typos in debug section of capi.c + * - Bugfix: Makefile corrected for b1pcmcia.c + * * Revision 1.7 2000/02/02 18:36:03 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -70,7 +75,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.7 $"; +static char *revision = "$Revision: 1.8 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/c4.c Tue Mar 7 14:32:25 2000 +++ linux/drivers/isdn/avmb1/c4.c Thu Mar 23 08:38:57 2000 @@ -1,11 +1,17 @@ /* - * $Id: c4.c,v 1.4 2000/02/02 18:36:03 calle Exp $ + * $Id: c4.c,v 1.6 2000/03/17 12:21:08 calle Exp $ * * Module for AVM C4 card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: c4.c,v $ + * Revision 1.6 2000/03/17 12:21:08 calle + * send patchvalues now working. + * + * Revision 1.5 2000/03/16 15:21:03 calle + * Bugfix in c4_remove: loop 5 times instead of 4 :-( + * * Revision 1.4 2000/02/02 18:36:03 calle * - Modules are now locked while init_module is running * - fixed problem with memory mapping if address is not aligned @@ -40,7 +46,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.4 $"; +static char *revision = "$Revision: 1.6 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -65,7 +71,7 @@ /* ------------------------------------------------------------- */ -static int suppress_pollack = 0; +int suppress_pollack = 0; MODULE_AUTHOR("Carsten Paeth "); @@ -770,45 +776,78 @@ c4_dispatch_tx(card); } -static int c4_send_config(avmcard *card, capiloaddatapart * config) +static int queue_sendconfigword(avmcard *card, __u32 val) { struct sk_buff *skb; - __u8 val[sizeof(__u32)]; void *p; - unsigned char *dp; - int left, retval; - - skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC); + + skb = alloc_skb(3+4, GFP_ATOMIC); if (!skb) { - printk(KERN_CRIT "%s: no memory, can't send config.\n", + printk(KERN_CRIT "%s: no memory, send config\n", card->name); - return -ENOMEM; + return -ENOMEM; } p = skb->data; _put_byte(&p, 0); _put_byte(&p, 0); _put_byte(&p, SEND_CONFIG); - _put_word(&p, 1); + _put_word(&p, val); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + return 0; +} + +static int queue_sendconfig(avmcard *card, char cval[4]) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(3+4, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, send config\n", + card->name); + return -ENOMEM; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); _put_byte(&p, SEND_CONFIG); - _put_word(&p, config->len); /* 12 */ + _put_byte(&p, cval[0]); + _put_byte(&p, cval[1]); + _put_byte(&p, cval[2]); + _put_byte(&p, cval[3]); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + return 0; +} + +static int c4_send_config(avmcard *card, capiloaddatapart * config) +{ + __u8 val[4]; + unsigned char *dp; + int left, retval; + + if ((retval = queue_sendconfigword(card, 1)) != 0) + return retval; + if ((retval = queue_sendconfigword(card, config->len)) != 0) + return retval; dp = config->data; left = config->len; while (left >= sizeof(__u32)) { if (config->user) { retval = copy_from_user(val, dp, sizeof(val)); - if (retval) { - dev_kfree_skb(skb); + if (retval) return -EFAULT; - } } else { memcpy(val, dp, sizeof(val)); } - _put_byte(&p, SEND_CONFIG); - _put_byte(&p, val[0]); - _put_byte(&p, val[1]); - _put_byte(&p, val[2]); - _put_byte(&p, val[3]); + if ((retval = queue_sendconfig(card, val)) != 0) + return retval; left -= sizeof(val); dp += sizeof(val); } @@ -816,25 +855,15 @@ memset(val, 0, sizeof(val)); if (config->user) { retval = copy_from_user(&val, dp, left); - if (retval) { - dev_kfree_skb(skb); + if (retval) return -EFAULT; - } } else { memcpy(&val, dp, left); } - _put_byte(&p, SEND_CONFIG); - _put_byte(&p, val[0]); - _put_byte(&p, val[1]); - _put_byte(&p, val[2]); - _put_byte(&p, val[3]); + if ((retval = queue_sendconfig(card, val)) != 0) + return retval; } - skb_put(skb, (__u8 *)p - (__u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - c4_dispatch_tx(card); - return 0; } @@ -871,8 +900,15 @@ c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); restore_flags(flags); - if (data->configuration.len > 0 && data->configuration.data) - c4_send_config(card, &data->configuration); + if (data->configuration.len > 0 && data->configuration.data) { + retval = c4_send_config(card, &data->configuration); + if (retval) { + printk(KERN_ERR "%s: failed to set config!!\n", + card->name); + c4_reset(card); + return retval; + } + } c4_send_init(card); @@ -904,7 +940,7 @@ c4_reset(card); - for (i=0; i <= 4; i++) { + for (i=0; i < 4; i++) { cinfo = &card->ctrlinfo[i]; if (cinfo->capi_ctrl) di->detach_ctr(cinfo->capi_ctrl); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capi.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/isdn/avmb1/capi.c Thu Mar 23 23:18:20 2000 @@ -1,11 +1,51 @@ /* - * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $ + * $Id: capi.c,v 1.30 2000/03/19 12:31:36 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.30 2000/03/19 12:31:36 calle + * PPP over CAPI raw driver disabled for now, ppp_generic has been changed. + * + * Revision 1.29 2000/03/13 17:48:13 calle + * removed unused variable. + * + * Revision 1.28 2000/03/08 17:06:33 calle + * - changes for devfs and 2.3.49 + * - capifs now configurable (no need with devfs) + * - New Middleware ioctl CAPI_NCCI_GETUNIT + * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) + * + * Revision 1.27 2000/03/06 18:00:23 calle + * - Middleware extention now working with 2.3.49 (capifs). + * - Fixed typos in debug section of capi.c + * - Bugfix: Makefile corrected for b1pcmcia.c + * + * Revision 1.26 2000/03/03 16:48:38 calle + * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) + * It is now possible to create a connection with a CAPI2.0 applikation + * and than to handle the data connection from /dev/capi/ (capifs) and also + * using async or sync PPP on this connection. + * The two major device number 190 and 191 are not confirmed yet, + * but I want to save the code in cvs, before I go on. + * + * Revision 1.25 2000/03/03 16:37:11 kai + * incorporated some cosmetic changes from the official kernel tree back + * into CVS + * + * Revision 1.24 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.23 2000/02/26 01:00:53 keil * changes from 2.3.47 * @@ -114,6 +154,7 @@ * */ +#include #include #include #include @@ -126,52 +167,686 @@ #include #include #include +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +#include +#ifdef CONFIG_PPP +#include +#include +#include +#undef CAPI_PPP_ON_RAW_DEVICE +#endif /* CONFIG_PPP */ +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include #include #include #include #include #include - #include "capiutil.h" #include "capicmd.h" -#include "capidev.h" +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +#include "capifs.h" +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +#include + +static char *revision = "$Revision: 1.30 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); +#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */ +#undef _DEBUG_TTYFUNCS /* call to tty_driver */ +#undef _DEBUG_DATAFLOW /* data flow */ + /* -------- driver information -------------------------------------- */ int capi_major = 68; /* allocated */ +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +int capi_rawmajor = 190; +int capi_ttymajor = 191; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ MODULE_PARM(capi_major, "i"); +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +MODULE_PARM(capi_rawmajor, "i"); +MODULE_PARM(capi_ttymajor, "i"); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +/* -------- defines ------------------------------------------------- */ + +#define CAPINC_MAX_RECVQUEUE 10 +#define CAPINC_MAX_SENDQUEUE 10 +#define CAPI_MAX_BLKSIZE 2048 + +/* -------- data structures ----------------------------------------- */ + +struct capidev; +struct capincci; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +struct capiminor; + +struct capiminor { + struct capiminor *next; + struct capincci *nccip; + unsigned int minor; + + __u16 applid; + __u32 ncci; + __u16 datahandle; + __u16 msgid; + + struct file *file; + struct tty_struct *tty; + int ttyinstop; + int ttyoutstop; + struct sk_buff *ttyskb; + atomic_t ttyopencount; + + struct sk_buff_head inqueue; + int inbytes; + struct sk_buff_head outqueue; + int outbytes; + + /* for raw device */ + struct sk_buff_head recvqueue; + wait_queue_head_t recvwait; + wait_queue_head_t sendwait; + + /* transmit path */ + struct datahandle_queue { + struct datahandle_queue *next; + __u16 datahandle; + } *ackqueue; + int nack; + +}; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +struct capincci { + struct capincci *next; + __u32 ncci; + struct capidev *cdev; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *minorp; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +}; + +struct capidev { + struct capidev *next; + struct file *file; + __u16 applid; + __u16 errcode; + unsigned int minor; + unsigned userflags; + + struct sk_buff_head recvqueue; + wait_queue_head_t recvwait; + + /* Statistic */ + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; + + struct capincci *nccis; +}; /* -------- global variables ---------------------------------------- */ -static struct capidev capidevs[CAPI_MAXMINOR + 1]; -struct capi_interface *capifuncs; +static struct capi_interface *capifuncs = 0; +static struct capidev *capidev_openlist = 0; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +static struct capiminor *minors = 0; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +static kmem_cache_t *capidev_cachep = 0; +static kmem_cache_t *capincci_cachep = 0; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +static kmem_cache_t *capiminor_cachep = 0; +static kmem_cache_t *capidh_cachep = 0; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -/* -------- function called by lower level -------------------------- */ +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +/* -------- datahandles --------------------------------------------- */ + +int capincci_add_ack(struct capiminor *mp, __u16 datahandle) +{ + struct datahandle_queue *n, **pp; + + n = (struct datahandle_queue *) + kmem_cache_alloc(capidh_cachep, GFP_ATOMIC); + if (!n) { + printk(KERN_ERR "capi: alloc datahandle failed\n"); + return -1; + } + n->next = 0; + n->datahandle = datahandle; + for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ; + *pp = n; + mp->nack++; + return 0; +} + +int capiminor_del_ack(struct capiminor *mp, __u16 datahandle) +{ + struct datahandle_queue **pp, *p; + + for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) { + if ((*pp)->datahandle == datahandle) { + p = *pp; + *pp = (*pp)->next; + kmem_cache_free(capidh_cachep, p); + mp->nack--; + return 0; + } + } + return -1; +} + +void capiminor_del_all_ack(struct capiminor *mp) +{ + struct datahandle_queue **pp, *p; + + for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) { + p = *pp; + *pp = (*pp)->next; + kmem_cache_free(capidh_cachep, p); + mp->nack--; + } +} + + +/* -------- struct capiminor ---------------------------------------- */ + +struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci) +{ + struct capiminor *mp, **pp; + unsigned int minor = 0; + + mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC); + if (!mp) { + printk(KERN_ERR "capi: can't alloc capiminor\n"); + return 0; + } + MOD_INC_USE_COUNT; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(THIS_MODULE)); +#endif + memset(mp, 0, sizeof(struct capiminor)); + mp->applid = applid; + mp->ncci = ncci; + mp->msgid = 0; + atomic_set(&mp->ttyopencount,0); + + skb_queue_head_init(&mp->inqueue); + skb_queue_head_init(&mp->outqueue); + + skb_queue_head_init(&mp->recvqueue); + init_waitqueue_head(&mp->recvwait); + init_waitqueue_head(&mp->sendwait); + + for (pp = &minors; *pp; pp = &(*pp)->next) { + if ((*pp)->minor < minor) + continue; + if ((*pp)->minor > minor) + break; + minor++; + } + mp->minor = minor; + mp->next = *pp; + *pp = mp; + return mp; +} + +void capiminor_free(struct capiminor *mp) +{ + struct capiminor **pp; + struct sk_buff *skb; + + pp = &minors; + while (*pp) { + if (*pp == mp) { + *pp = (*pp)->next; + if (mp->ttyskb) kfree_skb(mp->ttyskb); + mp->ttyskb = 0; + while ((skb = skb_dequeue(&mp->recvqueue)) != 0) + kfree_skb(skb); + while ((skb = skb_dequeue(&mp->inqueue)) != 0) + kfree_skb(skb); + while ((skb = skb_dequeue(&mp->outqueue)) != 0) + kfree_skb(skb); + capiminor_del_all_ack(mp); + kmem_cache_free(capiminor_cachep, mp); + MOD_DEC_USE_COUNT; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE)); +#endif + return; + } else { + pp = &(*pp)->next; + } + } +} + +struct capiminor *capiminor_find(unsigned int minor) +{ + struct capiminor *p; + for (p = minors; p && p->minor != minor; p = p->next) + ; + return p; +} +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +/* -------- struct capincci ----------------------------------------- */ + +static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci) +{ + struct capincci *np, **pp; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp = 0; + kdev_t kdev; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + np = (struct capincci *)kmem_cache_alloc(capincci_cachep, GFP_ATOMIC); + if (!np) + return 0; + memset(np, 0, sizeof(struct capincci)); + np->ncci = ncci; + np->cdev = cdev; + for (pp=&cdev->nccis; *pp; pp = &(*pp)->next) + ; + *pp = np; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + mp = 0; + if (cdev->userflags & CAPIFLAG_HIGHJACKING) + mp = np->minorp = capiminor_alloc(cdev->applid, ncci); + if (mp) { + mp->nccip = np; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "set mp->nccip\n"); +#endif +#ifdef CONFIG_ISDN_CAPIFS + kdev = MKDEV(capi_rawmajor, mp->minor); + capifs_new_ncci('r', mp->minor, kdev); + kdev = MKDEV(capi_ttymajor, mp->minor); + capifs_new_ncci(0, mp->minor, kdev); +#endif + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + return np; +} + +static void capincci_free(struct capidev *cdev, __u32 ncci) +{ + struct capincci *np, **pp; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + + pp=&cdev->nccis; + while (*pp) { + np = *pp; + if (ncci == 0xffffffff || np->ncci == ncci) { + *pp = (*pp)->next; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if ((mp = np->minorp) != 0) { +#ifdef CONFIG_ISDN_CAPIFS + capifs_free_ncci('r', mp->minor); + capifs_free_ncci(0, mp->minor); +#endif + if (mp->tty) { + mp->nccip = 0; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "reset mp->nccip\n"); +#endif + tty_hangup(mp->tty); + } else if (mp->file) { + mp->nccip = 0; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "reset mp->nccip\n"); +#endif + wake_up_interruptible(&mp->recvwait); + wake_up_interruptible(&mp->sendwait); + } else { + capiminor_free(mp); + } + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + kmem_cache_free(capincci_cachep, np); + if (*pp == 0) return; + } else { + pp = &(*pp)->next; + } + } +} -static void capi_signal(__u16 applid, __u32 minor) +struct capincci *capincci_find(struct capidev *cdev, __u32 ncci) +{ + struct capincci *p; + + for (p=cdev->nccis; p ; p = p->next) { + if (p->ncci == ncci) + break; + } + return p; +} + +/* -------- struct capidev ------------------------------------------ */ + +static struct capidev *capidev_alloc(struct file *file) { struct capidev *cdev; + struct capidev **pp; + + cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL); + if (!cdev) + return 0; + memset(cdev, 0, sizeof(struct capidev)); + cdev->file = file; + cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev); + + skb_queue_head_init(&cdev->recvqueue); + init_waitqueue_head(&cdev->recvwait); + pp=&capidev_openlist; + while (*pp) pp = &(*pp)->next; + *pp = cdev; + return cdev; +} + +static void capidev_free(struct capidev *cdev) +{ + struct capidev **pp; + struct sk_buff *skb; + + if (cdev->applid) + (*capifuncs->capi_release) (cdev->applid); + cdev->applid = 0; + + while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) { + kfree_skb(skb); + } + + pp=&capidev_openlist; + while (*pp && *pp != cdev) pp = &(*pp)->next; + if (*pp) + *pp = cdev->next; + + kmem_cache_free(capidev_cachep, cdev); +} + +static struct capidev *capidev_find(__u16 applid) +{ + struct capidev *p; + for (p=capidev_openlist; p; p = p->next) { + if (p->applid == applid) + break; + } + return p; +} + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +/* -------- handle data queue --------------------------------------- */ + +struct sk_buff * +gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) +{ + struct sk_buff *nskb; + nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC); + if (nskb) { + __u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2); + unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN); + capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN); + capimsg_setu16(s, 2, mp->applid); + capimsg_setu8 (s, 4, CAPI_DATA_B3); + capimsg_setu8 (s, 5, CAPI_RESP); + capimsg_setu16(s, 6, mp->msgid++); + capimsg_setu32(s, 8, mp->ncci); + capimsg_setu16(s, 12, datahandle); + } + return nskb; +} + +int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) +{ + struct sk_buff *nskb; + unsigned int datalen; + __u16 errcode, datahandle; + + datalen = skb->len - CAPIMSG_LEN(skb->data); + if (mp->tty) { + if (mp->tty->ldisc.receive_buf == 0) { + printk(KERN_ERR "capi: ldisc has no receive_buf function\n"); + return -1; + } + if (mp->ttyinstop) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: recv tty throttled\n"); +#endif + return -1; + } + if (mp->tty->ldisc.receive_room && + mp->tty->ldisc.receive_room(mp->tty) < datalen) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: no room in tty\n"); +#endif + return -1; + } + if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); + return -1; + } + datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); + errcode = (*capifuncs->capi_put_message)(mp->applid, nskb); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", + errcode); + kfree_skb(nskb); + return -1; + } + (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", + datahandle, skb->len); +#endif + mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len); + return 0; + + } else if (mp->file) { + if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: no room in raw queue\n"); +#endif + return -1; + } + if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); + return -1; + } + datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); + errcode = (*capifuncs->capi_put_message)(mp->applid, nskb); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", + errcode); + kfree_skb(nskb); + return -1; + } + (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => raw\n", + datahandle, skb->len); +#endif + skb_queue_tail(&mp->recvqueue, skb); + wake_up_interruptible(&mp->recvwait); + return 0; + } +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: currently no receiver\n"); +#endif + return -1; +} + +void handle_minor_recv(struct capiminor *mp) +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(&mp->inqueue)) != 0) { + unsigned int len = skb->len; + mp->inbytes -= len; + if (handle_recv_skb(mp, skb) < 0) { + skb_queue_head(&mp->inqueue, skb); + mp->inbytes += len; + return; + } + } +} + +int handle_minor_send(struct capiminor *mp) +{ + struct sk_buff *skb; + __u16 len; + int count = 0; + __u16 errcode; + __u16 datahandle; + + if (mp->tty && mp->ttyoutstop) { +#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) + printk(KERN_DEBUG "capi: send: tty stopped\n"); +#endif + return 0; + } + + while ((skb = skb_dequeue(&mp->outqueue)) != 0) { + datahandle = mp->datahandle; + len = (__u16)skb->len; + skb_push(skb, CAPI_DATA_B3_REQ_LEN); + memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN); + capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN); + capimsg_setu16(skb->data, 2, mp->applid); + capimsg_setu8 (skb->data, 4, CAPI_DATA_B3); + capimsg_setu8 (skb->data, 5, CAPI_REQ); + capimsg_setu16(skb->data, 6, mp->msgid++); + capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */ + capimsg_setu32(skb->data, 12, (__u32) skb->data); /* Data32 */ + capimsg_setu16(skb->data, 16, len); /* Data length */ + capimsg_setu16(skb->data, 18, datahandle); + capimsg_setu16(skb->data, 20, 0); /* Flags */ + + if (capincci_add_ack(mp, datahandle) < 0) { + skb_pull(skb, CAPI_DATA_B3_REQ_LEN); + skb_queue_head(&mp->outqueue, skb); + return count; + } + errcode = (*capifuncs->capi_put_message) (mp->applid, skb); + if (errcode == CAPI_NOERROR) { + mp->datahandle++; + count++; + mp->outbytes -= len; +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n", + datahandle, len); +#endif + continue; + } + capiminor_del_ack(mp, datahandle); + + if (errcode == CAPI_SENDQUEUEFULL) { + skb_pull(skb, CAPI_DATA_B3_REQ_LEN); + skb_queue_head(&mp->outqueue, skb); + break; + } + + /* ups, drop packet */ + printk(KERN_ERR "capi: put_message = %x\n", errcode); + mp->outbytes -= len; + kfree_skb(skb); + } + if (count) + wake_up_interruptible(&mp->sendwait); + return count; +} + +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +/* -------- function called by lower level -------------------------- */ + +static void capi_signal(__u16 applid, void *param) +{ + struct capidev *cdev = (struct capidev *)param; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp; + __u16 datahandle; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + struct capincci *np; struct sk_buff *skb = 0; + __u32 ncci; - if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) { - printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor); + (void) (*capifuncs->capi_get_message) (applid, &skb); + if (!skb) { + printk(KERN_ERR "BUG: capi_signal: no skb\n"); return; } - cdev = &capidevs[minor]; - (void) (*capifuncs->capi_get_message) (applid, &skb); - if (skb) { - skb_queue_tail(&cdev->recv_queue, skb); - wake_up_interruptible(&cdev->recv_wait); + + if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + return; + } + ncci = CAPIMSG_CONTROL(skb->data); + for (np = cdev->nccis; np && np->ncci != ncci; np = np->next) + ; + if (!np) { + printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + return; + } +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + mp = np->minorp; + if (!mp) { + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + return; + } + + + if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { + + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", + datahandle, skb->len-CAPIMSG_LEN(skb->data)); +#endif + skb_queue_tail(&mp->inqueue, skb); + mp->inbytes += skb->len; + handle_minor_recv(mp); + + } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) { + + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4); +#ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n", + datahandle, + CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2)); +#endif + kfree_skb(skb); + (void)capiminor_del_ack(mp, datahandle); + if (mp->tty) { + if (mp->tty->ldisc.write_wakeup) + mp->tty->ldisc.write_wakeup(mp->tty); + } else { + wake_up_interruptible(&mp->sendwait); + } + (void)handle_minor_send(mp); + } else { - printk(KERN_ERR "BUG: capi_signal: no skb\n"); + /* ups, let capi application handle it :-) */ + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ } -/* -------- file_operations ----------------------------------------- */ +/* -------- file_operations for capidev ----------------------------- */ static long long capi_llseek(struct file *file, long long offset, int origin) @@ -182,29 +857,25 @@ static ssize_t capi_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; + struct capidev *cdev = (struct capidev *)file->private_data; struct sk_buff *skb; int retval; size_t copied; - if (ppos != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; - if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + if (!cdev->applid) return -ENODEV; - cdev = &capidevs[minor]; - - if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) { + if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; for (;;) { - interruptible_sleep_on(&cdev->recv_wait); - if ((skb = skb_dequeue(&cdev->recv_queue)) != 0) + interruptible_sleep_on(&cdev->recvwait); + if ((skb = skb_dequeue(&cdev->recvqueue)) != 0) break; if (signal_pending(current)) break; @@ -213,20 +884,22 @@ return -ERESTARTNOHAND; } if (skb->len > count) { - skb_queue_head(&cdev->recv_queue, skb); + skb_queue_head(&cdev->recvqueue, skb); return -EMSGSIZE; } retval = copy_to_user(buf, skb->data, skb->len); if (retval) { - skb_queue_head(&cdev->recv_queue, skb); + skb_queue_head(&cdev->recvqueue, skb); return retval; } copied = skb->len; - if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 - && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) { cdev->nrecvdatapkt++; - else cdev->nrecvctlpkt++; + } else { + cdev->nrecvctlpkt++; + } + kfree_skb(skb); return copied; @@ -235,41 +908,34 @@ static ssize_t capi_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct inode *inode = file->f_dentry->d_inode; - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; + struct capidev *cdev = (struct capidev *)file->private_data; struct sk_buff *skb; int retval; - __u8 cmd; - __u8 subcmd; __u16 mlen; - if (ppos != &file->f_pos) + if (ppos != &file->f_pos) return -ESPIPE; - if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + if (!cdev->applid) return -ENODEV; - cdev = &capidevs[minor]; - skb = alloc_skb(count, GFP_USER); if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb); return retval; } - cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); mlen = CAPIMSG_LEN(skb->data); - if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { - __u16 dlen = CAPIMSG_DATALEN(skb->data); - if (mlen + dlen != count) { + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { + if (mlen + CAPIMSG_DATALEN(skb->data) != count) { + kfree_skb(skb); + return -EINVAL; + } + } else { + if (mlen != count) { kfree_skb(skb); return -EINVAL; } - } else if (mlen != count) { - kfree_skb(skb); - return -EINVAL; } CAPIMSG_SETAPPID(skb->data, cdev->applid); @@ -279,26 +945,26 @@ kfree_skb(skb); return -EIO; } - if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { cdev->nsentdatapkt++; - else cdev->nsentctlpkt++; + } else { + cdev->nsentctlpkt++; + } return count; } static unsigned int capi_poll(struct file *file, poll_table * wait) { + struct capidev *cdev = (struct capidev *)file->private_data; unsigned int mask = 0; - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); - struct capidev *cdev; - if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + if (!cdev->applid) return POLLERR; - cdev = &capidevs[minor]; - poll_wait(file, &(cdev->recv_wait), wait); + poll_wait(file, &(cdev->recvwait), wait); mask = POLLOUT | POLLWRNORM; - if (!skb_queue_empty(&cdev->recv_queue)) + if (!skb_queue_empty(&cdev->recvqueue)) mask |= POLLIN | POLLRDNORM; return mask; } @@ -306,36 +972,28 @@ static int capi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; + struct capidev *cdev = (struct capidev *)file->private_data; capi_ioctl_struct data; - int retval; - - - if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) - return -ENODEV; - - cdev = &capidevs[minor]; + int retval = -EINVAL; switch (cmd) { case CAPI_REGISTER: { - if (!minor) - return -EINVAL; retval = copy_from_user((void *) &data.rparams, (void *) arg, sizeof(struct capi_register_params)); if (retval) return -EFAULT; - if (cdev->is_registered) + if (cdev->applid) return -EEXIST; cdev->errcode = (*capifuncs->capi_register) (&data.rparams, &cdev->applid); - if (cdev->errcode) + if (cdev->errcode) { + cdev->applid = 0; return -EIO; - (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor); - cdev->is_registered = 1; + } + (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, cdev); } - return 0; + return (int)cdev->applid; case CAPI_GET_VERSION: { @@ -441,8 +1099,6 @@ case CAPI_MANUFACTURER_CMD: { struct capi_manufacturer_cmd mcmd; - if (minor) - return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = copy_from_user((void *) &mcmd, (void *) arg, @@ -452,112 +1108,770 @@ return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data); } return 0; + + case CAPI_SET_FLAGS: + case CAPI_CLR_FLAGS: + { + unsigned userflags; + retval = copy_from_user((void *) &userflags, + (void *) arg, + sizeof(userflags)); + if (retval) + return -EFAULT; + if (cmd == CAPI_SET_FLAGS) + cdev->userflags |= userflags; + else + cdev->userflags &= ~userflags; + } + return 0; + + case CAPI_GET_FLAGS: + { + retval = copy_to_user((void *) arg, + (void *) &cdev->userflags, + sizeof(cdev->userflags)); + if (retval) + return -EFAULT; + } + return 0; + + case CAPI_NCCI_OPENCOUNT: + { + struct capincci *nccip; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + struct capiminor *mp; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + unsigned ncci; + int count = 0; + retval = copy_from_user((void *) &ncci, + (void *) arg, + sizeof(ncci)); + if (retval) + return -EFAULT; + nccip = capincci_find(cdev, (__u32) ncci); + if (!nccip) + return 0; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if ((mp = nccip->minorp) != 0) { + count += atomic_read(&mp->ttyopencount); + if (mp->file) + count++; + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + return count; + } + return 0; + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + case CAPI_NCCI_GETUNIT: + { + struct capincci *nccip; + struct capiminor *mp; + unsigned ncci; + retval = copy_from_user((void *) &ncci, + (void *) arg, + sizeof(ncci)); + if (retval) + return -EFAULT; + nccip = capincci_find(cdev, (__u32) ncci); + if (!nccip || (mp = nccip->minorp) == 0) + return -ESRCH; + return mp->minor; + } + return 0; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ } return -EINVAL; } static int capi_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); - - if (minor >= CAPI_MAXMINOR) - return -ENXIO; - - if (minor) { - if (capidevs[minor].is_open) - return -EEXIST; - - capidevs[minor].is_open = 1; - skb_queue_head_init(&capidevs[minor].recv_queue); - MOD_INC_USE_COUNT; - capidevs[minor].nopen++; + if (file->private_data) + return -EEXIST; - } else { - capidevs[minor].is_open++; - MOD_INC_USE_COUNT; - } + if ((file->private_data = capidev_alloc(file)) == 0) + return -ENOMEM; + MOD_INC_USE_COUNT; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE)); +#endif return 0; } -static int -capi_release(struct inode *inode, struct file *file) +static int capi_release(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); - struct capidev *cdev; - struct sk_buff *skb; - - if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) { - printk(KERN_ERR "capi20: release minor %d ???\n", minor); - return 0; - } - cdev = &capidevs[minor]; + struct capidev *cdev = (struct capidev *)file->private_data; - if (minor) { - - if (cdev->is_registered) - (*capifuncs->capi_release) (cdev->applid); - - cdev->is_registered = 0; - cdev->applid = 0; - - while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) { - kfree_skb(skb); - } - cdev->is_open = 0; - } else { - cdev->is_open--; - } + capincci_free(cdev, 0xffffffff); + capidev_free(cdev); MOD_DEC_USE_COUNT; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); +#endif return 0; } static struct file_operations capi_fops = { - llseek: capi_llseek, - read: capi_read, - write: capi_write, - poll: capi_poll, - ioctl: capi_ioctl, - open: capi_open, - release: capi_release, + llseek: capi_llseek, + read: capi_read, + write: capi_write, + poll: capi_poll, + ioctl: capi_ioctl, + open: capi_open, + release: capi_release, }; -/* -------- /proc functions ----------------------------------- */ +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE +/* -------- file_operations for capincci ---------------------------- */ -/* - * /proc/capi/capi20: - * minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt - */ -static int proc_capidev_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +int capinc_raw_open(struct inode *inode, struct file *file) { - struct capidev *cp; - int i; - int len = 0; - off_t begin = 0; + struct capiminor *mp; - for (i=0; i < CAPI_MAXMINOR; i++) { - cp = &capidevs[i+1]; - if (cp->nopen == 0) continue; - len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n", - i+1, - cp->nopen, - cp->nrecvctlpkt, - cp->nrecvdatapkt, - cp->nsentctlpkt, - cp->nsentdatapkt); - if (len+begin > off+count) - goto endloop; - if (len+begin < off) { - begin += len; - len = 0; - } - } -endloop: - if (i >= CAPI_MAXMINOR) - *eof = 1; + if (file->private_data) + return -EEXIST; + if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) + return -ENXIO; + if (mp->nccip == 0) + return -ENXIO; + if (mp->file) + return -EBUSY; + +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE)); +#endif + + mp->datahandle = 0; + mp->file = file; + file->private_data = (void *)mp; + handle_minor_recv(mp); + return 0; +} + +long long capinc_raw_llseek(struct file *file, + long long offset, int origin) +{ + return -ESPIPE; +} + +ssize_t capinc_raw_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + struct sk_buff *skb; + int retval; + size_t copied = 0; + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!mp || !mp->nccip) + return -EINVAL; + + if ((skb = skb_dequeue(&mp->recvqueue)) == 0) { + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + for (;;) { + interruptible_sleep_on(&mp->recvwait); + if (mp->nccip == 0) + return 0; + if ((skb = skb_dequeue(&mp->recvqueue)) != 0) + break; + if (signal_pending(current)) + break; + } + if (skb == 0) + return -ERESTARTNOHAND; + } + do { + if (count < skb->len) { + retval = copy_to_user(buf, skb->data, count); + if (retval) { + skb_queue_head(&mp->recvqueue, skb); + return retval; + } + skb_pull(skb, count); + skb_queue_head(&mp->recvqueue, skb); + copied += count; + return copied; + } else { + retval = copy_to_user(buf, skb->data, skb->len); + if (retval) { + skb_queue_head(&mp->recvqueue, skb); + return copied; + } + copied += skb->len; + count -= skb->len; + buf += skb->len; + kfree_skb(skb); + } + } while ((skb = skb_dequeue(&mp->recvqueue)) != 0); + + return copied; +} + +ssize_t capinc_raw_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + struct sk_buff *skb; + int retval; + + if (ppos != &file->f_pos) + return -ESPIPE; + + if (!mp || !mp->nccip) + return -EINVAL; + + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER); + + skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); + if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { + kfree_skb(skb); + return retval; + } + + while (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&mp->sendwait); + if (mp->nccip == 0) { + kfree_skb(skb); + return -EIO; + } + if (signal_pending(current)) + return -ERESTARTNOHAND; + } + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + return count; +} + +unsigned int +capinc_raw_poll(struct file *file, poll_table * wait) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + unsigned int mask = 0; + + if (!mp || !mp->nccip) + return POLLERR|POLLHUP; + + poll_wait(file, &(mp->recvwait), wait); + if (!skb_queue_empty(&mp->recvqueue)) + mask |= POLLIN | POLLRDNORM; + poll_wait(file, &(mp->sendwait), wait); + if (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) + mask = POLLOUT | POLLWRNORM; + return mask; +} + +int capinc_raw_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + if (!mp || !mp->nccip) + return -EINVAL; + + switch (cmd) { + } + return -EINVAL; +} + +int +capinc_raw_release(struct inode *inode, struct file *file) +{ + struct capiminor *mp = (struct capiminor *)file->private_data; + + if (mp) { + mp->file = 0; + if (mp->nccip == 0) + capiminor_free(mp); + } + +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(THIS_MODULE)); +#endif + return 0; +} + +struct file_operations capinc_raw_fops = +{ + capinc_raw_llseek, + capinc_raw_read, + capinc_raw_write, + NULL, /* capi_readdir */ + capinc_raw_poll, + capinc_raw_ioctl, + NULL, /* capi_mmap */ + capinc_raw_open, + NULL, /* capi_flush */ + capinc_raw_release, + NULL, /* capi_fsync */ + NULL, /* capi_fasync */ +}; + +/* -------- tty_operations for capincci ----------------------------- */ + +int capinc_tty_open(struct tty_struct * tty, struct file * file) +{ + struct capiminor *mp; + + if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) + return -ENXIO; + if (mp->nccip == 0) + return -ENXIO; + if (mp->file) + return -EBUSY; + + skb_queue_head_init(&mp->recvqueue); + init_waitqueue_head(&mp->recvwait); + init_waitqueue_head(&mp->sendwait); + tty->driver_data = (void *)mp; +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(THIS_MODULE)); +#endif + if (atomic_read(&mp->ttyopencount) == 0) + mp->tty = tty; + atomic_inc(&mp->ttyopencount); +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); +#endif + handle_minor_recv(mp); + return 0; +} + +void capinc_tty_close(struct tty_struct * tty, struct file * file) +{ + struct capiminor *mp; + + mp = (struct capiminor *)tty->driver_data; + if (mp) { + if (atomic_dec_and_test(&mp->ttyopencount)) { +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_close lastclose\n"); +#endif + tty->driver_data = (void *)0; + mp->tty = 0; + } +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); +#endif + if (mp->nccip == 0) + capiminor_free(mp); + } + +#ifdef _DEBUG_REFCOUNT + printk(KERN_DEBUG "capinc_tty_close\n"); +#endif +} + +int capinc_tty_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct sk_buff *skb; + int retval; + +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n", + from_user, count); +#endif + + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n"); +#endif + return 0; + } + + skb = mp->ttyskb; + if (skb) { + mp->ttyskb = 0; + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + } + + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n"); + return -ENOMEM; + } + + skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); + if (from_user) { + if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { + kfree_skb(skb); +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval); +#endif + return retval; + } + } else { + memcpy(skb_put(skb, count), buf, count); + } + + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + (void)handle_minor_recv(mp); + return count; +} + +void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct sk_buff *skb; + +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_put_char(%u)\n", ch); +#endif + + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n"); +#endif + return; + } + + skb = mp->ttyskb; + if (skb) { + if (skb_tailroom(skb) > 0) { + *(skb_put(skb, 1)) = ch; + return; + } + mp->ttyskb = 0; + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + } + skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC); + if (skb) { + skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); + *(skb_put(skb, 1)) = ch; + mp->ttyskb = skb; + } else { + printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); + } +} + +void capinc_tty_flush_chars(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + struct sk_buff *skb; + +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_flush_chars\n"); +#endif + + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n"); +#endif + return; + } + + skb = mp->ttyskb; + if (skb) { + mp->ttyskb = 0; + skb_queue_tail(&mp->outqueue, skb); + mp->outbytes += skb->len; + (void)handle_minor_send(mp); + } + (void)handle_minor_recv(mp); +} + +int capinc_tty_write_room(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + int room; + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n"); +#endif + return 0; + } + room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue); + room *= CAPI_MAX_BLKSIZE; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room); +#endif + return room; +} + +int capinc_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; + if (!mp || !mp->nccip) { +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n"); +#endif + return 0; + } +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", + mp->outbytes, mp->nack, + skb_queue_len(&mp->outqueue), + skb_queue_len(&mp->inqueue)); +#endif + return mp->outbytes; +} + +int capinc_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_set_termios\n"); +#endif +} + +void capinc_tty_throttle(struct tty_struct * tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_throttle\n"); +#endif + if (mp) + mp->ttyinstop = 1; +} + +void capinc_tty_unthrottle(struct tty_struct * tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_unthrottle\n"); +#endif + if (mp) { + mp->ttyinstop = 0; + handle_minor_recv(mp); + } +} + +void capinc_tty_stop(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_stop\n"); +#endif + if (mp) { + mp->ttyoutstop = 1; + } +} + +void capinc_tty_start(struct tty_struct *tty) +{ + struct capiminor *mp = (struct capiminor *)tty->driver_data; +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_start\n"); +#endif + if (mp) { + mp->ttyoutstop = 0; + (void)handle_minor_send(mp); + } +} + +void capinc_tty_hangup(struct tty_struct *tty) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_hangup\n"); +#endif +} + +void capinc_tty_break_ctl(struct tty_struct *tty, int state) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state); +#endif +} + +void capinc_tty_flush_buffer(struct tty_struct *tty) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_flush_buffer\n"); +#endif +} + +void capinc_tty_set_ldisc(struct tty_struct *tty) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_set_ldisc\n"); +#endif +} + +void capinc_tty_send_xchar(struct tty_struct *tty, char ch) +{ +#ifdef _DEBUG_TTYFUNCS + printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch); +#endif +} + +int capinc_tty_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return 0; +} + +int capinc_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + return 0; +} + +#define CAPINC_NR_PORTS 256 +static struct tty_driver capinc_tty_driver; +static int capinc_tty_refcount; +static struct tty_struct *capinc_tty_table[CAPINC_NR_PORTS]; +static struct termios *capinc_tty_termios[CAPINC_NR_PORTS]; +static struct termios *capinc_tty_termios_locked[CAPINC_NR_PORTS]; + +int capinc_tty_init(void) +{ + struct tty_driver *drv = &capinc_tty_driver; + + /* Initialize the tty_driver structure */ + + memset(drv, 0, sizeof(struct tty_driver)); + drv->magic = TTY_DRIVER_MAGIC; +#if (LINUX_VERSION_CODE > 0x20100) + drv->driver_name = "capi_nc"; +#endif + drv->name = "capi/%d"; + drv->major = capi_ttymajor; + drv->minor_start = 0; + drv->num = CAPINC_NR_PORTS; + drv->type = TTY_DRIVER_TYPE_SERIAL; + drv->subtype = SERIAL_TYPE_NORMAL; + drv->init_termios = tty_std_termios; + drv->init_termios.c_iflag = ICRNL; + drv->init_termios.c_oflag = OPOST | ONLCR; + drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + drv->init_termios.c_lflag = 0; + drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS; + drv->refcount = &capinc_tty_refcount; + drv->table = capinc_tty_table; + drv->termios = capinc_tty_termios; + drv->termios_locked = capinc_tty_termios_locked; + + drv->open = capinc_tty_open; + drv->close = capinc_tty_close; + drv->write = capinc_tty_write; + drv->put_char = capinc_tty_put_char; + drv->flush_chars = capinc_tty_flush_chars; + drv->write_room = capinc_tty_write_room; + drv->chars_in_buffer = capinc_tty_chars_in_buffer; + drv->ioctl = capinc_tty_ioctl; + drv->set_termios = capinc_tty_set_termios; + drv->throttle = capinc_tty_throttle; + drv->unthrottle = capinc_tty_unthrottle; + drv->stop = capinc_tty_stop; + drv->start = capinc_tty_start; + drv->hangup = capinc_tty_hangup; +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + drv->break_ctl = capinc_tty_break_ctl; +#endif + drv->flush_buffer = capinc_tty_flush_buffer; + drv->set_ldisc = capinc_tty_set_ldisc; +#if (LINUX_VERSION_CODE >= 131343) + drv->send_xchar = capinc_tty_send_xchar; + drv->read_proc = capinc_tty_read_proc; +#endif + if (tty_register_driver(drv)) { + printk(KERN_ERR "Couldn't register capi_nc driver\n"); + return -1; + } + return 0; +} + +void capinc_tty_exit(void) +{ + struct tty_driver *drv = &capinc_tty_driver; + int retval; + if ((retval = tty_unregister_driver(drv))) + printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval); +} + +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + +/* -------- /proc functions ----------------------------------------- */ + +/* + * /proc/capi/capi20: + * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt + */ +static int proc_capidev_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capidev *cdev; + int len = 0; + off_t begin = 0; + + for (cdev=capidev_openlist; cdev; cdev = cdev->next) { + len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n", + cdev->minor, + cdev->applid, + cdev->nrecvctlpkt, + cdev->nrecvdatapkt, + cdev->nsentctlpkt, + cdev->nsentdatapkt); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (cdev == 0) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * /proc/capi/capi20ncci: + * applid ncci + */ +static int proc_capincci_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capidev *cdev; + struct capincci *np; + int len = 0; + off_t begin = 0; + + for (cdev=capidev_openlist; cdev; cdev = cdev->next) { + for (np=cdev->nccis; np; np = np->next) { + len += sprintf(page+len, "%d 0x%x%s\n", + cdev->applid, + np->ncci, +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE + ""); +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + np->minorp && np->minorp->file ? " open" : ""); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } + } +endloop: + if (cdev == 0) + *eof = 1; if (off >= len+begin) return 0; *start = page + (begin-off); @@ -573,6 +1887,7 @@ } procfsentries[] = { /* { "capi", S_IFDIR, 0 }, */ { "capi/capi20", 0 , proc_capidev_read_proc }, + { "capi/capi20ncci", 0 , proc_capincci_read_proc }, }; static void proc_init(void) @@ -600,78 +1915,226 @@ } } } + /* -------- init function and module interface ---------------------- */ + +static void alloc_exit(void) +{ + if (capidev_cachep) { + (void)kmem_cache_destroy(capidev_cachep); + capidev_cachep = 0; + } + if (capincci_cachep) { + (void)kmem_cache_destroy(capincci_cachep); + capincci_cachep = 0; + } +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if (capidh_cachep) { + (void)kmem_cache_destroy(capidh_cachep); + capidh_cachep = 0; + } + if (capiminor_cachep) { + (void)kmem_cache_destroy(capiminor_cachep); + capiminor_cachep = 0; + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +} + +static int alloc_init(void) +{ + capidev_cachep = kmem_cache_create("capi20_dev", + sizeof(struct capidev), + 0, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!capidev_cachep) { + alloc_exit(); + return -ENOMEM; + } + + capincci_cachep = kmem_cache_create("capi20_ncci", + sizeof(struct capincci), + 0, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!capincci_cachep) { + alloc_exit(); + return -ENOMEM; + } +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + capidh_cachep = kmem_cache_create("capi20_dh", + sizeof(struct datahandle_queue), + 0, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!capidh_cachep) { + alloc_exit(); + return -ENOMEM; + } + capiminor_cachep = kmem_cache_create("capi20_minor", + sizeof(struct capiminor), + 0, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!capiminor_cachep) { + alloc_exit(); + return -ENOMEM; + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + return 0; +} + +static void lower_callback(unsigned int cmd, __u32 contr, void *data) +{ + struct capi_ncciinfo *np; + struct capidev *cdev; + + switch (cmd) { + case KCI_CONTRUP: + printk(KERN_INFO "capi: controller %hu up\n", contr); + break; + case KCI_CONTRDOWN: + printk(KERN_INFO "capi: controller %hu down\n", contr); + break; + case KCI_NCCIUP: + np = (struct capi_ncciinfo *)data; + if ((cdev = capidev_find(np->applid)) == 0) + return; + (void)capincci_alloc(cdev, np->ncci); + break; + case KCI_NCCIDOWN: + np = (struct capi_ncciinfo *)data; + if ((cdev = capidev_find(np->applid)) == 0) + return; + (void)capincci_free(cdev, np->ncci); + break; + } +} + #ifdef MODULE #define capi_init init_module #endif static struct capi_interface_user cuser = { "capi20", - 0, + lower_callback, }; +static char rev[10]; + int capi_init(void) { - int j; - - memset(capidevs, 0, sizeof(capidevs)); - for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) { - init_waitqueue_head(&capidevs[j].recv_wait); - } + char *p; + + MOD_INC_USE_COUNT; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 2); + p = strchr(rev, '$'); + *(p-1) = 0; + } else + strcpy(rev, "???"); if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); + MOD_DEC_USE_COUNT; return -EIO; } + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if (devfs_register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) { + devfs_unregister_chrdev(capi_major, "capi20"); + printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor); + MOD_DEC_USE_COUNT; + return -EIO; + } + devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS, + DEVFS_FL_DEFAULT, + capi_rawmajor, 0, + S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + &capinc_raw_fops, NULL); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT, capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &capi_fops, NULL); - devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT, - capi_major, 1, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, - &capi_fops, NULL); - devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT, - capi_major, 11, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, - &capi_fops, NULL); printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major); if ((capifuncs = attach_capi_interface(&cuser)) == 0) { + + MOD_DEC_USE_COUNT; devfs_unregister_chrdev(capi_major, "capi20"); +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ devfs_unregister(devfs_find_handle(NULL, "capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0)); - for (j = 0; j < 10; j++) { - char devname[32]; + return -EIO; + } + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + if (capinc_tty_init() < 0) { + (void) detach_capi_interface(&cuser); + devfs_unregister_chrdev(capi_major, "capi20"); + devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); + MOD_DEC_USE_COUNT; + return -ENOMEM; + } +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - sprintf(devname, "isdn/capi20.0%i", j); - devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0)); - sprintf (devname, "isdn/capi20.1%i", j); - devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0)); + if (alloc_init() < 0) { +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + unsigned int j; + devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); + for (j = 0; j < CAPINC_NR_PORTS; j++) { + char devname[32]; + sprintf(devname, "capi/r%u", j); + devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0)); } - return -EIO; + capinc_tty_exit(); +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + (void) detach_capi_interface(&cuser); + devfs_unregister_chrdev(capi_major, "capi20"); + devfs_unregister(devfs_find_handle(NULL, "capi20", 0, + capi_major, 0, + DEVFS_SPECIAL_CHR, 0)); + MOD_DEC_USE_COUNT; + return -ENOMEM; } + (void)proc_init(); + + printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n", + rev, capi_major); + + MOD_DEC_USE_COUNT; return 0; } #ifdef MODULE void cleanup_module(void) { - int i; - char devname[32]; - +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + unsigned int j; +#endif + alloc_exit(); (void)proc_exit(); + devfs_unregister_chrdev(capi_major, "capi20"); devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0)); - for (i = 0; i < 10; i++) { - sprintf (devname, "isdn/capi20.0%i", i); - devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 1, DEVFS_SPECIAL_CHR, 0)); - sprintf (devname, "isdn/capi20.1%i", i); - devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 11, DEVFS_SPECIAL_CHR, 0)); + +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + capinc_tty_exit(); + devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); + for (j = 0; j < CAPINC_NR_PORTS; j++) { + char devname[32]; + sprintf(devname, "capi/r%u", j); + devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0)); } +#endif (void) detach_capi_interface(&cuser); + printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev); } #endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capicmd.h linux/drivers/isdn/avmb1/capicmd.h --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capicmd.h Thu May 29 21:53:05 1997 +++ linux/drivers/isdn/avmb1/capicmd.h Thu Mar 23 08:38:57 2000 @@ -1,11 +1,22 @@ /* - * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $ + * $Id: capicmd.h,v 1.2 2000/03/03 15:50:42 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capicmd.h,v $ + * Revision 1.2 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.1 1997/03/04 21:50:30 calle * Frirst version in isdn4linux * @@ -19,6 +30,10 @@ */ #ifndef __CAPICMD_H__ #define __CAPICMD_H__ + +#define CAPI_MSG_BASELEN 8 +#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2) +#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2) /*----- CAPI commands -----*/ #define CAPI_ALERT 0x01 diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capidev.h Thu Nov 11 20:11:36 1999 +++ linux/drivers/isdn/avmb1/capidev.h Thu Mar 23 08:38:57 2000 @@ -1,11 +1,22 @@ /* - * $Id: capidev.h,v 1.4 1999/07/01 15:26:32 calle Exp $ + * $Id: capidev.h,v 1.5 2000/03/03 15:50:42 calle Exp $ * * CAPI 2.0 Interface for Linux * * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidev.h,v $ + * Revision 1.5 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.4 1999/07/01 15:26:32 calle * complete new version (I love it): * + new hardware independed "capi_driver" interface that will make it easy to: @@ -40,18 +51,18 @@ */ struct capidev { - int is_open; - int is_registered; - __u16 applid; + struct capidev *next; + struct file *file; + __u16 applid; + __u16 errcode; + unsigned int minor; + struct sk_buff_head recv_queue; wait_queue_head_t recv_wait; - __u16 errcode; + /* Statistic */ - unsigned long nopen; - unsigned long nrecvctlpkt; - unsigned long nrecvdatapkt; - unsigned long nsentctlpkt; - unsigned long nsentdatapkt; + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; }; - -#define CAPI_MAXMINOR CAPI_MAXAPPL diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capidrv.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/capidrv.c Thu Mar 23 08:38:57 2000 @@ -1,11 +1,22 @@ /* - * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $ + * $Id: capidrv.c,v 1.30 2000/03/03 15:50:42 calle Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.30 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.29 1999/12/06 17:13:06 calle * Added controller watchdog. * @@ -171,7 +182,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.29 $"; +static char *revision = "$Revision: 1.30 $"; int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); @@ -440,25 +451,33 @@ static inline capidrv_contr *findcontrbydriverid(int driverid) { capidrv_contr *p = global.contr_list; + long flags; + save_flags(flags); + cli(); while (p) { if (p->myid == driverid) - return p; + break; p = p->next; } - return (capidrv_contr *) 0; + restore_flags(flags); + return p; } static capidrv_contr *findcontrbynumber(__u32 contr) { capidrv_contr *p = global.contr_list; + long flags; + save_flags(flags); + cli(); while (p) { if (p->contrnr == contr) - return p; + break; p = p->next; } - return (capidrv_contr *) 0; + restore_flags(flags); + return p; } @@ -1501,7 +1520,7 @@ static _cmsg s_cmsg; -static void capidrv_signal(__u16 applid, __u32 dummy) +static void capidrv_signal(__u16 applid, void *dummy) { struct sk_buff *skb = 0; @@ -2218,14 +2237,18 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) { capidrv_contr *card; + long flags; isdn_ctrl cmd; char id[20]; int i; + MOD_INC_USE_COUNT; + sprintf(id, "capidrv-%d", contr); if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) { printk(KERN_WARNING "capidrv: (%s) Could not allocate contr-struct.\n", id); + MOD_DEC_USE_COUNT; return -1; } memset(card, 0, sizeof(capidrv_contr)); @@ -2238,6 +2261,7 @@ printk(KERN_WARNING "capidrv: (%s) Could not allocate bchan-structs.\n", id); kfree(card); + MOD_DEC_USE_COUNT; return -1; } card->interface.channels = profp->nbchannel; @@ -2258,29 +2282,35 @@ ISDN_FEATURE_P_UNKNOWN; card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); - card->next = global.contr_list; - global.contr_list = card; - global.ncontr++; + + card->q931_read = card->q931_buf; card->q931_write = card->q931_buf; card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1; if (!register_isdn(&card->interface)) { - global.contr_list = global.contr_list->next; printk(KERN_ERR "capidrv: Unable to register contr %s\n", id); kfree(card->bchans); kfree(card); + MOD_DEC_USE_COUNT; return -1; } card->myid = card->interface.channels; + save_flags(flags); + cli(); + card->next = global.contr_list; + global.contr_list = card; + global.ncontr++; + restore_flags(flags); + memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan); for (i = 0; i < card->nbchan; i++) { card->bchans[i].contr = card; } - cmd.driver = card->myid; cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; card->interface.statcallb(&cmd); card->cipmask = 0x1FFF03FF; /* any */ @@ -2304,30 +2334,41 @@ { capidrv_contr **pp, *card; isdn_ctrl cmd; + long flags; int i; + save_flags(flags); + cli(); for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { if ((*pp)->contrnr == contr) break; } if (!*pp) { + restore_flags(flags); printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); return -1; } card = *pp; + *pp = (*pp)->next; + global.ncontr--; + restore_flags(flags); if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", card->contrnr, card->myid); - cmd.command = ISDN_STAT_UNLOAD; + cmd.command = ISDN_STAT_STOP; cmd.driver = card->myid; card->interface.statcallb(&cmd); - *pp = (*pp)->next; - global.ncontr--; - for (i = 0; i < card->nbchan; i++) { + + cmd.command = ISDN_STAT_DISCH; + cmd.driver = card->myid; + cmd.arg = i; + cmd.parm.num[0] = 0; + card->interface.statcallb(&cmd); + if (card->bchans[i].nccip) free_ncci(card, card->bchans[i].nccip); if (card->bchans[i].plcip) @@ -2338,10 +2379,16 @@ kfree(card->bchans); del_timer(&card->listentimer); - printk(KERN_INFO "%s: now down.\n", card->name); + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); kfree(card); + printk(KERN_INFO "%s: now down.\n", card->name); + + MOD_DEC_USE_COUNT; + return 0; } @@ -2438,10 +2485,14 @@ __u32 ncontr, contr; __u16 errcode; + MOD_INC_USE_COUNT; + capifuncs = attach_capi_interface(&cuser); - if (!capifuncs) + if (!capifuncs) { + MOD_DEC_USE_COUNT; return -EIO; + } if ((p = strchr(revision, ':'))) { strcpy(rev, p + 1); @@ -2456,6 +2507,7 @@ errcode = (*capifuncs->capi_register) (&rparam, &global.appid); if (errcode) { detach_capi_interface(&cuser); + MOD_DEC_USE_COUNT; return -EIO; } @@ -2463,6 +2515,7 @@ if (errcode != CAPI_NOERROR) { (void) (*capifuncs->capi_release) (global.appid); detach_capi_interface(&cuser); + MOD_DEC_USE_COUNT; return -EIO; } @@ -2477,6 +2530,9 @@ } proc_init(); + printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev); + MOD_DEC_USE_COUNT; + return 0; } @@ -2484,6 +2540,7 @@ void cleanup_module(void) { capidrv_contr *card, *next; + long flags; char rev[10]; char *p; @@ -2498,8 +2555,15 @@ for (card = global.contr_list; card; card = next) { next = card->next; disable_dchannel_trace(card); + } + + save_flags(flags); + cli(); + for (card = global.contr_list; card; card = next) { + next = card->next; capidrv_delcontr(card->contrnr); } + restore_flags(flags); (void) (*capifuncs->capi_release) (global.appid); detach_capi_interface(&cuser); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capifs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capifs.c Thu Mar 23 23:18:20 2000 @@ -0,0 +1,595 @@ +/* + * $Id: capifs.c,v 1.5 2000/03/13 17:49:52 calle Exp $ + * + * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) + * + * Heavily based on devpts filesystem from H. Peter Anvin + * + * $Log: capifs.c,v $ + * Revision 1.5 2000/03/13 17:49:52 calle + * make it running with 2.3.51. + * + * Revision 1.4 2000/03/08 17:06:33 calle + * - changes for devfs and 2.3.49 + * - capifs now configurable (no need with devfs) + * - New Middleware ioctl CAPI_NCCI_GETUNIT + * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) + * + * Revision 1.3 2000/03/06 18:00:23 calle + * - Middleware extention now working with 2.3.49 (capifs). + * - Fixed typos in debug section of capi.c + * - Bugfix: Makefile corrected for b1pcmcia.c + * + * Revision 1.2 2000/03/06 09:17:07 calle + * - capifs: fileoperations now in inode (change for 2.3.49) + * - Config.in: Middleware extention not a tristate, uups. + * + * Revision 1.1 2000/03/03 16:48:38 calle + * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) + * It is now possible to create a connection with a CAPI2.0 applikation + * and than to handle the data connection from /dev/capi/ (capifs) and also + * using async or sync PPP on this connection. + * The two major device number 190 and 191 are not confirmed yet, + * but I want to save the code in cvs, before I go on. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Carsten Paeth "); + +static char *revision = "$Revision: 1.5 $"; + +struct capifs_ncci { + struct inode *inode; + char used; + char type; + unsigned int num; + kdev_t kdev; +}; + +struct capifs_sb_info { + u32 magic; + struct super_block *next; + struct super_block **back; + int setuid; + int setgid; + uid_t uid; + gid_t gid; + umode_t mode; + + unsigned int max_ncci; + struct capifs_ncci *nccis; +}; + +#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') +#define CAPIFS_SBI_MAGIC (('C'<<24)|('A'<<16)|('P'<<8)|'I') + +static inline struct capifs_sb_info *SBI(struct super_block *sb) +{ + return (struct capifs_sb_info *)(sb->u.generic_sbp); +} + +/* ------------------------------------------------------------------ */ + +static int capifs_root_readdir(struct file *,void *,filldir_t); +static struct dentry *capifs_root_lookup(struct inode *,struct dentry *); +static int capifs_revalidate(struct dentry *, int); + +static struct file_operations capifs_root_operations = { + read: generic_read_dir, + readdir: capifs_root_readdir, +}; + +struct inode_operations capifs_root_inode_operations = { + lookup: capifs_root_lookup, +}; + +struct inode_operations capifs_inode_operations; + +static struct dentry_operations capifs_dentry_operations = { + d_revalidate: capifs_revalidate, +}; + +/* + * /dev/capi/%d + * /dev/capi/r%d + */ + +static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct inode * inode = filp->f_dentry->d_inode; + struct capifs_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb); + off_t nr; + char numbuf[32]; + + nr = filp->f_pos; + + switch(nr) + { + case 0: + if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + default: + while (nr < sbi->max_ncci) { + int n = nr - 2; + struct capifs_ncci *np = &sbi->nccis[n]; + if (np->inode && np->used) { + char *p = numbuf; + if (np->type) *p++ = np->type; + sprintf(p, "%u", np->num); + if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 ) + return 0; + } + filp->f_pos = ++nr; + } + break; + } + + return 0; +} + +/* + * Revalidate is called on every cache lookup. We use it to check that + * the ncci really does still exist. Never revalidate negative dentries; + * for simplicity (fix later?) + */ +static int capifs_revalidate(struct dentry * dentry, int flags) +{ + struct capifs_sb_info *sbi; + + if ( !dentry->d_inode ) + return 0; + + sbi = SBI(dentry->d_inode->i_sb); + + return ( sbi->nccis[dentry->d_inode->i_ino - 2].inode == dentry->d_inode ); +} + +static struct dentry *capifs_root_lookup(struct inode * dir, struct dentry * dentry) +{ + struct capifs_sb_info *sbi = SBI(dir->i_sb); + struct capifs_ncci *np; + unsigned int i; + char numbuf[32]; + char *p, *tmp; + unsigned int num; + char type = 0; + + dentry->d_inode = NULL; /* Assume failure */ + dentry->d_op = &capifs_dentry_operations; + + if (dentry->d_name.len >= sizeof(numbuf) ) + return NULL; + strncpy(numbuf, dentry->d_name.name, dentry->d_name.len); + numbuf[dentry->d_name.len] = 0; + p = numbuf; + if (!isdigit(*p)) type = *p++; + tmp = p; + num = (unsigned int)simple_strtoul(p, &tmp, 10); + if (tmp == p || *tmp) + return NULL; + + for (i = 0, np = sbi->nccis ; i < sbi->max_ncci; i++, np++) { + if (np->used && np->num == num && np->type == type) + break; + } + + if ( i >= sbi->max_ncci ) + return NULL; + + dentry->d_inode = np->inode; + if ( dentry->d_inode ) + dentry->d_inode->i_count++; + + d_add(dentry, dentry->d_inode); + + return NULL; +} + +/* ------------------------------------------------------------------ */ + +static struct super_block *mounts = NULL; + +static void capifs_put_super(struct super_block *sb) +{ + struct capifs_sb_info *sbi = SBI(sb); + struct inode *inode; + int i; + + for ( i = 0 ; i < sbi->max_ncci ; i++ ) { + if ( (inode = sbi->nccis[i].inode) ) { + if ( inode->i_count != 1 ) + printk("capifs_put_super: badness: entry %d count %d\n", + i, inode->i_count); + inode->i_nlink--; + iput(inode); + } + } + + *sbi->back = sbi->next; + if ( sbi->next ) + SBI(sbi->next)->back = sbi->back; + + kfree(sbi->nccis); + kfree(sbi); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + MOD_DEC_USE_COUNT; +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) +static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); +static void capifs_write_inode(struct inode *inode) { }; +#else +static int capifs_statfs(struct super_block *sb, struct statfs *buf); +#endif +static void capifs_read_inode(struct inode *inode); + +static struct super_operations capifs_sops = { + read_inode: capifs_read_inode, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + write_inode: capifs_write_inode, +#endif + put_super: capifs_put_super, + statfs: capifs_statfs, +}; + +static int capifs_parse_options(char *options, struct capifs_sb_info *sbi) +{ + int setuid = 0; + int setgid = 0; + uid_t uid = 0; + gid_t gid = 0; + umode_t mode = 0600; + unsigned int maxncci = 512; + char *this_char, *value; + + this_char = NULL; + if ( options ) + this_char = strtok(options,","); + for ( ; this_char; this_char = strtok(NULL,",")) { + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"uid")) { + if (!value || !*value) + return 1; + uid = simple_strtoul(value,&value,0); + if (*value) + return 1; + setuid = 1; + } + else if (!strcmp(this_char,"gid")) { + if (!value || !*value) + return 1; + gid = simple_strtoul(value,&value,0); + if (*value) + return 1; + setgid = 1; + } + else if (!strcmp(this_char,"mode")) { + if (!value || !*value) + return 1; + mode = simple_strtoul(value,&value,8); + if (*value) + return 1; + } + else if (!strcmp(this_char,"maxncci")) { + if (!value || !*value) + return 1; + maxncci = simple_strtoul(value,&value,8); + if (*value) + return 1; + } + else + return 1; + } + sbi->setuid = setuid; + sbi->setgid = setgid; + sbi->uid = uid; + sbi->gid = gid; + sbi->mode = mode & ~S_IFMT; + sbi->max_ncci = maxncci; + + return 0; +} + +struct super_block *capifs_read_super(struct super_block *s, void *data, + int silent) +{ + struct inode * root_inode; + struct dentry * root; + struct capifs_sb_info *sbi; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + MOD_INC_USE_COUNT; + lock_super(s); +#endif + /* Super block already completed? */ + if (s->s_root) + goto out; + + sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL); + if ( !sbi ) + goto fail; + + memset(sbi, 0, sizeof(struct capifs_sb_info)); + sbi->magic = CAPIFS_SBI_MAGIC; + + if ( capifs_parse_options(data,sbi) ) { + kfree(sbi); + printk("capifs: called with bogus options\n"); + goto fail; + } + + sbi->nccis = kmalloc(sizeof(struct capifs_ncci) * sbi->max_ncci, GFP_KERNEL); + if ( !sbi->nccis ) { + kfree(sbi); + goto fail; + } + memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci); + + s->u.generic_sbp = (void *) sbi; + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = CAPIFS_SUPER_MAGIC; + s->s_op = &capifs_sops; + s->s_root = NULL; + + /* + * Get the root inode and dentry, but defer checking for errors. + */ + root_inode = iget(s, 1); /* inode 1 == root directory */ + root = d_alloc_root(root_inode); + + /* + * Check whether somebody else completed the super block. + */ + if (s->s_root) { + if (root) dput(root); + else iput(root_inode); + goto out; + } + + if (!root) { + printk("capifs: get root dentry failed\n"); + /* + * iput() can block, so we clear the super block first. + */ + iput(root_inode); + kfree(sbi->nccis); + kfree(sbi); + goto fail; + } + + /* + * Check whether somebody else completed the super block. + */ + if (s->s_root) + goto out; + + /* + * Success! Install the root dentry now to indicate completion. + */ + s->s_root = root; + + sbi->next = mounts; + if ( sbi->next ) + SBI(sbi->next)->back = &(sbi->next); + sbi->back = &mounts; + mounts = s; + +out: /* Success ... somebody else completed the super block for us. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + unlock_super(s); +#endif + return s; +fail: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) + unlock_super(s); + MOD_DEC_USE_COUNT; +#endif + return NULL; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) +static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + struct statfs tmp; + + tmp.f_type = CAPIFS_SUPER_MAGIC; + tmp.f_bsize = 1024; + tmp.f_blocks = 0; + tmp.f_bfree = 0; + tmp.f_bavail = 0; + tmp.f_files = 0; + tmp.f_ffree = 0; + tmp.f_namelen = NAME_MAX; + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; +} +#else +static int capifs_statfs(struct super_block *sb, struct statfs *buf) +{ + buf->f_type = CAPIFS_SUPER_MAGIC; + buf->f_bsize = 1024; + buf->f_blocks = 0; + buf->f_bfree = 0; + buf->f_bavail = 0; + buf->f_files = 0; + buf->f_ffree = 0; + buf->f_namelen = NAME_MAX; + return 0; +} +#endif + +static void capifs_read_inode(struct inode *inode) +{ + ino_t ino = inode->i_ino; + struct capifs_sb_info *sbi = SBI(inode->i_sb); + + inode->i_op = NULL; + inode->i_mode = 0; + inode->i_nlink = 0; + inode->i_size = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blocks = 0; + inode->i_blksize = 1024; + inode->i_uid = inode->i_gid = 0; + + if ( ino == 1 ) { + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; + inode->i_op = &capifs_root_inode_operations; + inode->i_fop = &capifs_root_operations; + inode->i_nlink = 2; + return; + } + + /* need dummy inode operations .... */ + inode->i_op = &capifs_inode_operations; + + ino -= 2; + if ( ino >= sbi->max_ncci ) + return; /* Bogus */ + + init_special_inode(inode, S_IFCHR, 0); + + return; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51) +static struct file_system_type capifs_fs_type = { + "capifs", + 0, + capifs_read_super, + NULL +}; +#else +static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0); +#endif + +void capifs_new_ncci(char type, unsigned int num, kdev_t device) +{ + struct super_block *sb; + struct capifs_sb_info *sbi; + struct capifs_ncci *np; + ino_t ino; + + for ( sb = mounts ; sb ; sb = sbi->next ) { + sbi = SBI(sb); + + for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) { + if (np->used == 0) { + np->used = 1; + np->type = type; + np->num = num; + np->kdev = device; + break; + } + } + + if ((np->inode = iget(sb, ino+2)) != 0) { + struct inode *inode = np->inode; + inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid; + inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid; + inode->i_mode = sbi->mode | S_IFCHR; + inode->i_rdev = np->kdev; + inode->i_nlink++; + } + } +} + +void capifs_free_ncci(char type, unsigned int num) +{ + struct super_block *sb; + struct capifs_sb_info *sbi; + struct inode *inode; + struct capifs_ncci *np; + ino_t ino; + + for ( sb = mounts ; sb ; sb = sbi->next ) { + sbi = SBI(sb); + + for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) { + if (!np->used || np->type != type || np->num != num) + continue; + if (np->inode) { + inode = np->inode; + np->used = 0; + inode->i_nlink--; + iput(inode); + break; + } + } + } +} + +int __init capifs_init(void) +{ + char rev[10]; + char *p; + int err; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, "1.0"); + + err = register_filesystem(&capifs_fs_type); + if (err) + return err; +#ifdef MODULE + printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev); +#else + printk(KERN_NOTICE "capifs: Rev%s: started\n", rev); +#endif + return 0; +} + +void capifs_exit(void) +{ + unregister_filesystem(&capifs_fs_type); +} + +EXPORT_SYMBOL(capifs_new_ncci); +EXPORT_SYMBOL(capifs_free_ncci); + +#ifdef MODULE + +int init_module(void) +{ + return capifs_init(); +} + +void cleanup_module(void) +{ + capifs_exit(); +} + +#endif diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capifs.h linux/drivers/isdn/avmb1/capifs.h --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capifs.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capifs.h Thu Mar 23 08:38:57 2000 @@ -0,0 +1,25 @@ +/* + * $Id: capifs.h,v 1.2 2000/03/08 17:06:33 calle Exp $ + * + * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) + * + * $Log: capifs.h,v $ + * Revision 1.2 2000/03/08 17:06:33 calle + * - changes for devfs and 2.3.49 + * - capifs now configurable (no need with devfs) + * - New Middleware ioctl CAPI_NCCI_GETUNIT + * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) + * + * Revision 1.1 2000/03/03 16:48:38 calle + * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) + * It is now possible to create a connection with a CAPI2.0 applikation + * and than to handle the data connection from /dev/capi/ (capifs) and also + * using async or sync PPP on this connection. + * The two major device number 190 and 191 are not confirmed yet, + * but I want to save the code in cvs, before I go on. + * + * + */ + +void capifs_new_ncci(char type, unsigned int num, kdev_t device); +void capifs_free_ncci(char type, unsigned int num); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capiutil.c Thu Nov 11 20:11:36 1999 +++ linux/drivers/isdn/avmb1/capiutil.c Thu Mar 23 08:38:57 2000 @@ -1,5 +1,5 @@ /* - * $Id: capiutil.c,v 1.10 1999/08/31 11:19:54 paul Exp $ + * $Id: capiutil.c,v 1.11 2000/03/03 15:50:42 calle Exp $ * * CAPI 2.0 convert capi message to capi message struct * @@ -7,6 +7,17 @@ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capiutil.c,v $ + * Revision 1.11 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.10 1999/08/31 11:19:54 paul * various spelling corrections (new checksums may be needed, Karsten!) * @@ -794,7 +805,7 @@ /*15 */ "Class", /*16 */ "ConnectedNumber", /*17 */ "ConnectedSubaddress", - /*18 */ "Data", + /*18 */ "Data32", /*19 */ "DataHandle", /*1a */ "DataLength", /*1b */ "FacilityConfirmationParameter", @@ -892,13 +903,7 @@ cmsg->l += 2; break; case _CDWORD: - if (strcmp(NAME, "Data") == 0) { - bufprint("%-*s = ", slen, NAME); - printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l), - *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32))); - bufprint("\n"); - } else - bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l)); + bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l)); cmsg->l += 4; break; case _CSTRUCT: diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/capiutil.h linux/drivers/isdn/avmb1/capiutil.h --- v2.3.99-pre2/linux/drivers/isdn/avmb1/capiutil.h Thu Nov 11 20:11:36 1999 +++ linux/drivers/isdn/avmb1/capiutil.h Thu Mar 23 08:38:57 2000 @@ -1,5 +1,5 @@ /* - * $Id: capiutil.h,v 1.4 1999/09/15 08:16:03 calle Exp $ + * $Id: capiutil.h,v 1.5 2000/03/03 15:50:42 calle Exp $ * * CAPI 2.0 defines & types * @@ -7,6 +7,17 @@ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capiutil.h,v $ + * Revision 1.5 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.4 1999/09/15 08:16:03 calle * Implementation of 64Bit extention complete. * @@ -36,28 +47,47 @@ #include -#define CAPIMSG_LEN(m) (m[0] | (m[1] << 8)) -#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8)) -#define CAPIMSG_COMMAND(m) (m[4]) -#define CAPIMSG_SUBCOMMAND(m) (m[5]) -#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8)) +#define CAPIMSG_BASELEN 8 +#define CAPIMSG_U8(m, off) (m[off]) +#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8)) +#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24)) +#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0) +#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2) +#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4) +#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5) +#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5])) +#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6) #define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f) -#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24)) +#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8) #define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m) -#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24)) -#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8)) +#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */ + +static inline void capimsg_setu8(void *m, int off, __u8 val) +{ + ((__u8 *)m)[off] = val; +} + +static inline void capimsg_setu16(void *m, int off, __u16 val) +{ + ((__u8 *)m)[off] = val & 0xff; + ((__u8 *)m)[off+1] = (val >> 8) & 0xff; +} + +static inline void capimsg_setu32(void *m, int off, __u32 val) +{ + ((__u8 *)m)[off] = val & 0xff; + ((__u8 *)m)[off+1] = (val >> 8) & 0xff; + ((__u8 *)m)[off+2] = (val >> 16) & 0xff; + ((__u8 *)m)[off+3] = (val >> 24) & 0xff; +} -#define CAPIMSG_SETAPPID(m, applid) \ - do { \ - ((__u8 *)m)[2] = (__u16)(applid) & 0xff; \ - ((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \ - } while (0) - -#define CAPIMSG_SETLEN(m, len) \ - do { \ - ((__u8 *)m)[0] = (__u16)(len) & 0xff; \ - ((__u8 *)m)[1] = ((__u16)(len) >> 8) & 0xff; \ - } while (0) +#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len) +#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid) +#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd) +#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd) +#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid) +#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr) +#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len) /*----- basic-type definitions -----*/ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c --- v2.3.99-pre2/linux/drivers/isdn/avmb1/kcapi.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/kcapi.c Thu Mar 23 08:38:57 2000 @@ -1,11 +1,22 @@ /* - * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $ + * $Id: kcapi.c,v 1.13 2000/03/03 15:50:42 calle Exp $ * * Kernel CAPI 2.0 Module * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kcapi.c,v $ + * Revision 1.13 2000/03/03 15:50:42 calle + * - kernel CAPI: + * - Changed parameter "param" in capi_signal from __u32 to void *. + * - rewrote notifier handling in kcapi.c + * - new notifier NCCI_UP and NCCI_DOWN + * - User CAPI: + * - /dev/capi20 is now a cloning device. + * - middleware extentions prepared. + * - capidrv.c + * - locking of list operations and module count updates. + * * Revision 1.12 2000/01/28 16:45:39 calle * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), * will search named driver and call the add_card function if one exist. @@ -78,6 +89,7 @@ #include #include #include +#include #include #include "capicmd.h" #include "capiutil.h" @@ -86,7 +98,7 @@ #include #endif -static char *revision = "$Revision: 1.12 $"; +static char *revision = "$Revision: 1.13 $"; /* ------------------------------------------------------------- */ @@ -125,8 +137,8 @@ __u16 applid; capi_register_params rparam; int releasing; - __u32 param; - void (*signal) (__u16 applid, __u32 param); + void *param; + void (*signal) (__u16 applid, void *param); struct sk_buff_head recv_queue; int nncci; struct capi_ncci *nccilist; @@ -137,6 +149,14 @@ unsigned long nsentdatapkt; }; +struct capi_notifier { + struct capi_notifier *next; + unsigned int cmd; + __u32 controller; + __u16 applid; + __u32 ncci; +}; + /* ------------------------------------------------------------- */ static struct capi_version driver_version = {2, 0, 1, 1<<4}; @@ -160,9 +180,9 @@ static int ncards = 0; static struct sk_buff_head recv_queue; static struct capi_interface_user *capi_users = 0; +static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED; static struct capi_driver *drivers; -static long notify_up_set = 0; -static long notify_down_set = 0; +static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; static struct tq_struct tq_state_notify; static struct tq_struct tq_recv_notify; @@ -304,6 +324,7 @@ int len = 0; off_t begin = 0; + spin_lock(&drivers_lock); for (driver = drivers; driver; driver = driver->next) { len += sprintf(page+len, "%-32s %d %s\n", driver->name, @@ -317,6 +338,7 @@ } } endloop: + spin_unlock(&drivers_lock); if (!driver) *eof = 1; if (off >= len+begin) @@ -336,6 +358,7 @@ int len = 0; off_t begin = 0; + spin_lock(&capi_users_lock); for (cp = capi_users; cp ; cp = cp->next) { len += sprintf(page+len, "%s\n", cp->name); if (len+begin > off+count) @@ -346,6 +369,7 @@ } } endloop: + spin_unlock(&capi_users_lock); if (cp == 0) *eof = 1; if (off >= len+begin) @@ -510,6 +534,161 @@ } } +/* -------- Notifier handling --------------------------------- */ + +static struct capi_notifier_list{ + struct capi_notifier *head; + struct capi_notifier *tail; +} notifier_list; + +static inline void notify_enqueue(struct capi_notifier *np) +{ + struct capi_notifier_list *q = ¬ifier_list; + unsigned long flags; + + save_flags(flags); + cli(); + if (q->tail) { + q->tail->next = np; + q->tail = np; + } else { + q->head = q->tail = np; + } + restore_flags(flags); +} + +static inline struct capi_notifier *notify_dequeue(void) +{ + struct capi_notifier_list *q = ¬ifier_list; + struct capi_notifier *np = 0; + unsigned long flags; + + save_flags(flags); + cli(); + if (q->head) { + np = q->head; + if ((q->head = np->next) == 0) + q->tail = 0; + np->next = 0; + } + restore_flags(flags); + return np; +} + +static int notify_push(unsigned int cmd, __u32 controller, + __u16 applid, __u32 ncci) +{ + struct capi_notifier *np; + + np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC); + if (!np) + return -1; + memset(np, 0, sizeof(struct capi_notifier)); + np->cmd = cmd; + np->controller = controller; + np->applid = applid; + np->ncci = ncci; + notify_enqueue(np); + MOD_INC_USE_COUNT; + queue_task(&tq_state_notify, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return 0; +} + +/* -------- KCI_CONTRUP --------------------------------------- */ + +static void notify_up(__u32 contr) +{ + struct capi_interface_user *p; + + printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile); + } + spin_unlock(&capi_users_lock); +} + +/* -------- KCI_CONTRDOWN ------------------------------------- */ + +static void notify_down(__u32 contr) +{ + struct capi_interface_user *p; + printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr); + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_CONTRDOWN, contr, 0); + } + spin_unlock(&capi_users_lock); +} + +/* -------- KCI_NCCIUP ---------------------------------------- */ + +static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci) +{ + struct capi_interface_user *p; + struct capi_ncciinfo n; + n.applid = applid; + n.ncci = ncci; + /*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/ + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_NCCIUP, contr, &n); + } + spin_unlock(&capi_users_lock); +}; + +/* -------- KCI_NCCIDOWN -------------------------------------- */ + +static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci) +{ + struct capi_interface_user *p; + struct capi_ncciinfo n; + n.applid = applid; + n.ncci = ncci; + /*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/ + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_NCCIDOWN, contr, &n); + } + spin_unlock(&capi_users_lock); +}; + +/* ------------------------------------------------------------ */ + +static void inline notify_doit(struct capi_notifier *np) +{ + switch (np->cmd) { + case KCI_CONTRUP: + notify_up(np->controller); + break; + case KCI_CONTRDOWN: + notify_down(np->controller); + break; + case KCI_NCCIUP: + notify_ncciup(np->controller, np->applid, np->ncci); + break; + case KCI_NCCIDOWN: + notify_nccidown(np->controller, np->applid, np->ncci); + break; + } +} + +static void notify_handler(void *dummy) +{ + struct capi_notifier *np; + + while ((np = notify_dequeue()) != 0) { + notify_doit(np); + kfree(np); + MOD_DEC_USE_COUNT; + } +} + /* -------- NCCI Handling ------------------------------------- */ static inline void mq_init(struct capi_ncci * np) @@ -617,6 +796,7 @@ APPL(appl)->nncci++; printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci); + notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci); } static void controllercb_free_ncci(struct capi_ctr * card, @@ -634,6 +814,7 @@ kfree(np); APPL(appl)->nncci--; printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci); + notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci); return; } } @@ -734,42 +915,6 @@ kfree_skb(skb); } -/* -------- Notifier ------------------------------------------ */ - -static void notify_up(__u32 contr) -{ - struct capi_interface_user *p; - - printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); - for (p = capi_users; p; p = p->next) { - if (!p->callback) continue; - (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile); - } -} - -static void notify_down(__u32 contr) -{ - struct capi_interface_user *p; - printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr); - for (p = capi_users; p; p = p->next) { - if (!p->callback) continue; - (*p->callback) (KCI_CONTRDOWN, contr, 0); - } -} - -static void notify_handler(void *dummy) -{ - __u32 contr; - - for (contr=1; VALID_CARD(contr); contr++) - if (test_and_clear_bit(contr, ¬ify_up_set)) - notify_up(contr); - for (contr=1; VALID_CARD(contr); contr++) - if (test_and_clear_bit(contr, ¬ify_down_set)) - notify_down(contr); -} - - static void controllercb_ready(struct capi_ctr * card) { __u16 appl; @@ -782,11 +927,10 @@ card->driver->register_appl(card, appl, &APPL(appl)->rparam); } - set_bit(CARDNR(card), ¬ify_up_set); - queue_task(&tq_state_notify, &tq_scheduler); - printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", CARDNR(card), card->name); + + notify_push(KCI_CONTRUP, CARDNR(card), 0, 0); } static void controllercb_reseted(struct capi_ctr * card) @@ -812,6 +956,7 @@ struct capi_ncci *np = *pp; *pp = np->next; printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci); + notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci); kfree(np); nextpp = pp; } else { @@ -819,9 +964,10 @@ } } } - set_bit(CARDNR(card), ¬ify_down_set); - queue_task(&tq_state_notify, &tq_scheduler); + printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card)); + + notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0); } static void controllercb_suspend_output(struct capi_ctr *card) @@ -952,9 +1098,12 @@ { struct capi_driver **pp; + MOD_INC_USE_COUNT; + spin_lock(&drivers_lock); for (pp = &drivers; *pp; pp = &(*pp)->next) ; driver->next = 0; *pp = driver; + spin_unlock(&drivers_lock); printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name); sprintf(driver->procfn, "capi/drivers/%s", driver->name); driver->procent = create_proc_entry(driver->procfn, 0, 0); @@ -974,6 +1123,7 @@ void detach_capi_driver(struct capi_driver *driver) { struct capi_driver **pp; + spin_lock(&drivers_lock); for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ; if (*pp) { *pp = (*pp)->next; @@ -981,10 +1131,12 @@ } else { printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name); } + spin_unlock(&drivers_lock); if (driver->procent) { remove_proc_entry(driver->procfn, 0); driver->procent = 0; } + MOD_DEC_USE_COUNT; } /* ------------------------------------------------------------- */ @@ -1041,6 +1193,7 @@ if (!VALID_APPLID(applid) || APPL(applid)->releasing) return CAPI_ILLAPPNR; + APPL(applid)->releasing++; while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0) kfree_skb(skb); for (i = 0; i < CAPI_MAXCONTR; i++) { @@ -1049,6 +1202,7 @@ APPL(applid)->releasing++; cards[i].driver->release_appl(&cards[i], applid); } + APPL(applid)->releasing--; if (APPL(applid)->releasing <= 0) { APPL(applid)->signal = 0; APPL_MARK_FREE(applid); @@ -1128,8 +1282,8 @@ } static __u16 capi_set_signal(__u16 applid, - void (*signal) (__u16 applid, __u32 param), - __u32 param) + void (*signal) (__u16 applid, void *param), + void *param) { if (!VALID_APPLID(applid)) return CAPI_ILLAPPNR; @@ -1194,10 +1348,12 @@ static struct capi_driver *find_driver(char *name) { struct capi_driver *dp; + spin_lock(&drivers_lock); for (dp = drivers; dp; dp = dp->next) if (strcmp(dp->name, name) == 0) - return dp; - return 0; + break; + spin_unlock(&drivers_lock); + return dp; } #ifdef CONFIG_AVMB1_COMPAT @@ -1272,6 +1428,10 @@ card = CARD(ldef.contr); if (card->cardstate == CARD_FREE) return -ESRCH; + if (card->driver->load_firmware == 0) { + printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name); + return -ESRCH; + } if (ldef.t4file.len <= 0) { printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); @@ -1490,16 +1650,20 @@ { struct capi_interface_user *p; + MOD_INC_USE_COUNT; + spin_lock(&capi_users_lock); for (p = capi_users; p; p = p->next) { if (p == userp) { + spin_unlock(&capi_users_lock); printk(KERN_ERR "kcapi: double attach from %s\n", userp->name); + MOD_DEC_USE_COUNT; return 0; } } userp->next = capi_users; capi_users = userp; - MOD_INC_USE_COUNT; + spin_unlock(&capi_users_lock); printk(KERN_NOTICE "kcapi: %s attached\n", userp->name); return &avmb1_interface; @@ -1509,15 +1673,18 @@ { struct capi_interface_user **pp; + spin_lock(&capi_users_lock); for (pp = &capi_users; *pp; pp = &(*pp)->next) { if (*pp == userp) { *pp = userp->next; + spin_unlock(&capi_users_lock); userp->next = 0; - MOD_DEC_USE_COUNT; printk(KERN_NOTICE "kcapi: %s detached\n", userp->name); + MOD_DEC_USE_COUNT; return 0; } } + spin_unlock(&capi_users_lock); printk(KERN_ERR "kcapi: double detach from %s\n", userp->name); return -1; } @@ -1623,7 +1790,6 @@ strcpy(rev, "1.0"); } - schedule(); /* execute queued tasks .... */ proc_capi_exit(); printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev); } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c --- v2.3.99-pre2/linux/drivers/isdn/divert/divert_procfs.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/isdn/divert/divert_procfs.c Thu Mar 23 08:38:57 2000 @@ -1,5 +1,5 @@ /* - * $Id: divert_procfs.c,v 1.6 2000/02/14 19:23:03 werner Exp $ + * $Id: divert_procfs.c,v 1.8 2000/03/03 16:37:11 kai Exp $ * * Filesystem handling for the diversion supplementary services. * @@ -20,6 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divert_procfs.c,v $ + * Revision 1.8 2000/03/03 16:37:11 kai + * incorporated some cosmetic changes from the official kernel tree back + * into CVS + * + * Revision 1.7 2000/03/02 00:11:06 werner + * + * Changes related to procfs for 2.3.48 + * * Revision 1.6 2000/02/14 19:23:03 werner * * Changed handling of proc filesystem tables to a more portable version @@ -302,13 +310,13 @@ static struct file_operations isdn_fops = { - llseek: isdn_divert_lseek, - read: isdn_divert_read, - write: isdn_divert_write, - poll: isdn_divert_poll, - ioctl: isdn_divert_ioctl, - open: isdn_divert_open, - release: isdn_divert_close, + llseek: isdn_divert_lseek, + read: isdn_divert_read, + write: isdn_divert_write, + poll: isdn_divert_poll, + ioctl: isdn_divert_ioctl, + open: isdn_divert_open, + release: isdn_divert_close, }; /****************************/ @@ -336,7 +344,7 @@ remove_proc_entry("isdn", proc_net); return (-1); } - isdn_divert_entry->proc_fops = &isdn_fops; + isdn_divert_entry->proc_fops = &isdn_fops; #endif /* CONFIG_PROC_FS */ return (0); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.3.99-pre2/linux/drivers/isdn/eicon/eicon_idi.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/isdn/eicon/eicon_idi.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.31 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -26,6 +26,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.33 2000/03/06 15:45:17 armin + * Fixed incomplete number handling with BRI PtP connection. + * + * Revision 1.32 2000/03/04 17:04:21 armin + * Fix of statemachine, B-connect before D-connect, + * thanks to Helmut Adams + * Minor change in send-data packet handling. + * * Revision 1.31 2000/02/22 16:26:40 armin * Fixed membase error message. * Fixed missing log buffer struct. @@ -156,7 +164,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.31 $"; +char *eicon_idi_revision = "$Revision: 1.33 $"; eicon_manifbuf *manbuf; @@ -2515,15 +2523,7 @@ break; case 3: /* incomplete number */ eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No); - switch(ccard->type) { - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - /* TODO (other protocols) */ - chan->fsm_state = EICON_STATE_ICALLW; - break; - default: - idi_do_req(ccard, chan, HANGUP, 0); - } + chan->fsm_state = EICON_STATE_ICALLW; break; } break; @@ -2560,8 +2560,10 @@ /* On most incoming calls we use automatic connect */ /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ } - } else - idi_hangup(ccard, chan); + } else { + if (chan->fsm_state != EICON_STATE_ACTIVE) + idi_hangup(ccard, chan); + } break; case CALL_CON: eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No); @@ -3012,11 +3014,13 @@ reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); if (((len - offset) > 270) && + (chan->l2prot != ISDN_PROTO_L2_MODEM) && + (chan->l2prot != ISDN_PROTO_L2_FAX) && (chan->l2prot != ISDN_PROTO_L2_TRANS)) { reqbuf->Req = IDI_N_MDATA; } else { reqbuf->Req = IDI_N_DATA; - if (ack) reqbuf->Req |= N_D_BIT; + /* if (ack) reqbuf->Req |= N_D_BIT; */ } reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.3.99-pre2/linux/drivers/isdn/hisax/callc.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/callc.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $ +/* $Id: callc.c,v 2.41 2000/03/17 07:07:42 kai Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,9 @@ * Fritz Elfert * * $Log: callc.c,v $ + * Revision 2.41 2000/03/17 07:07:42 kai + * fixed oops when dialing out without l3 protocol selected + * * Revision 2.40 1999/12/19 12:59:56 keil * fix leased line handling * and cosmetics @@ -167,7 +170,7 @@ #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module)) #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.40 $"; +const char *lli_revision = "$Revision: 2.41 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -349,6 +352,8 @@ { isdn_ctrl ic; + if (!chanp->proc) + return; if (chanp->proc->para.cause == NO_CAUSE) return; ic.driver = chanp->cs->myid; @@ -641,7 +646,8 @@ lli_leased_hup(fi, chanp); } else { FsmChangeState(fi, ST_WAIT_DRELEASE); - chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ + if (chanp->proc) + chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); } @@ -656,7 +662,8 @@ lli_leased_hup(fi, chanp); } else { FsmChangeState(fi, ST_WAIT_DRELEASE); - chanp->proc->para.cause = 0x15; /* Call Rejected */ + if (chanp->proc) + chanp->proc->para.cause = 0x15; /* Call Rejected */ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); } @@ -688,7 +695,8 @@ return; } #ifndef ALERT_REJECT - chanp->proc->para.cause = 0x15; /* Call Rejected */ + if (chanp->proc) + chanp->proc->para.cause = 0x15; /* Call Rejected */ chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); lli_dhup_close(fi, event, arg); #else diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.3.99-pre2/linux/drivers/isdn/hisax/l3dss1.c Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/hisax/l3dss1.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $ +/* $Id: l3dss1.c,v 2.24 2000/03/19 15:26:35 kai Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,9 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.24 2000/03/19 15:26:35 kai + * changed keypad to use specified bearer, instead of always a-law + * * Revision 2.23 2000/02/26 01:38:14 keil * Fixes for V.110 encoding LLC from Jens Jakobsen * @@ -107,7 +110,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.23 $"; +const char *dss1_revision = "$Revision: 2.24 $"; #define EXT_BEARER_CAPS 1 @@ -1313,39 +1316,31 @@ /* * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 */ - if (!send_keypad) - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = 0x4; /* BC-IE-code */ - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = 0x4; /* BC-IE-code */ - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - else { *p++ = 0x4; /* assumptions for bearer services with keypad */ - *p++ = 0x3; - *p++ = 0x80; - *p++ = 0x90; - *p++ = 0xa3; - *p++ = 0x18; /* no specific channel */ - *p++ = 0x01; - *p++ = 0x83; - *p++ = 0x2C; /* IE keypad */ + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_BEARER; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_BEARER; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + + if (send_keypad) { + *p++ = IE_KEYPAD; *p++ = strlen(teln); while (*teln) - *p++ = (*teln++) & 0x7F; - } + *p++ = (*teln++) & 0x7F; + } - /* * What about info2? Mapping to High-Layer-Compatibility? */ @@ -1394,7 +1389,7 @@ sp++; } if (*msn) { - *p++ = 0x6c; + *p++ = IE_CALLING_PN; *p++ = strlen(msn) + (screen ? 2 : 1); /* Classify as AnyPref. */ if (screen) { @@ -1407,7 +1402,7 @@ } if (sub) { *sub++ = '.'; - *p++ = 0x6d; /* Calling party subaddress */ + *p++ = IE_CALLING_SUB; *p++ = strlen(sub) + 2; *p++ = 0x80; /* NSAP coded */ *p++ = 0x50; /* local IDI format */ @@ -1425,33 +1420,27 @@ } if (!send_keypad) { - *p++ = 0x70; - *p++ = strlen(teln) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - if (sub) { - *sub++ = '.'; - *p++ = 0x71; /* Called party subaddress */ - *p++ = strlen(sub) + 2; - *p++ = 0x80; /* NSAP coded */ - *p++ = 0x50; /* local IDI format */ - while (*sub) - *p++ = *sub++ & 0x7f; - } + *p++ = IE_CALLED_PN; + *p++ = strlen(teln) + 1; + /* Classify as AnyPref. */ + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + while (*teln) + *p++ = *teln++ & 0x7f; + + if (sub) { + *sub++ = '.'; + *p++ = IE_CALLED_SUB; + *p++ = strlen(sub) + 2; + *p++ = 0x80; /* NSAP coded */ + *p++ = 0x50; /* local IDI format */ + while (*sub) + *p++ = *sub++ & 0x7f; + } } #if EXT_BEARER_CAPS - if (send_keypad) { /* special handling independant of si2 */ - *p++ = 0x7c; - *p++ = 0x03; - *p++ = 0x80; - *p++ = 0x90; - *p++ = 0xa3; - } else if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 - *p++ = 0x7c; + *p++ = IE_LLC; *p++ = 0x04; *p++ = 0x88; *p++ = 0x90; @@ -1459,7 +1448,7 @@ *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 - *p++ = 0x7c; + *p++ = IE_LLC; *p++ = 0x05; *p++ = 0x88; *p++ = 0x90; @@ -1468,7 +1457,7 @@ *p++ = 0x82; } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 - *p++ = 0x7c; + *p++ = IE_LLC; *p++ = 0x06; *p++ = 0x88; *p++ = 0x90; @@ -1477,18 +1466,18 @@ #ifndef CONFIG_HISAX_NO_LLC } else { switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = 0x7c; /* BC-IE-code */ - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ + case 1: /* Telephony */ + *p++ = IE_LLC; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ default: - *p++ = 0x7c; /* BC-IE-code */ - *p++ = 0x2; /* Length */ + *p++ = IE_LLC; + *p++ = 0x2; /* Length */ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ *p++ = 0x90; /* Circuit-Mode 64kbps */ break; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc --- v2.3.99-pre2/linux/drivers/isdn/hisax/md5sums.asc Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/hisax/md5sums.asc Thu Mar 23 08:38:57 2000 @@ -11,9 +11,9 @@ bb51bd223040b511c18f091da5ab6456 isdnl2.c b7aa7f97b2374967a4aca7c52991142c isdnl3.c a23fbf8879c1432b04640b8b04bdf419 tei.c -ce248e56c2e1326012d0b25f92bbf99b callc.c +838791b14269ec94c74ba4ae89c022e6 callc.c bf9605b36429898f7be6630034e83230 cert.c -6ce0a184127be1a44747e2017ed24ad9 l3dss1.c +a30e6253837739f6f54d9dadcd42d9f2 l3dss1.c a3a570781f828b6d59e6b231653133de l3_1tr6.c 4aeba32c4c3480d2a6b9af34600b974f elsa.c a296edc459b508bf0346c3132815a4db diva.c @@ -23,9 +23,9 @@ Version: 2.6.3i Charset: noconv -iQCVAwUBOLcvXDpxHvX/mS9tAQGPWAP9Fg14RXcAwjCy4VeFoDBMOFpxllvG7xZR -HQKENCYIzXKPb6I/IBUv3+BhL8Lnhjw8a2DXz6c6u+0nmUIFnzyt1BfzT70P9rKd -BBN7f1KdIiQEmv0fZwd79Rz5PYvRDbY520bNTJZhorwqGI/qc3gGgHVtSR8OHhuS -ZMQ1pb9W6jE= -=CA5N +iQCVAwUBONlcejpxHvX/mS9tAQFWYAP/WmxgwQ7W6gVnsMkUlwzE1TKGWVJdGUTC +7WrKEtdweuzW3/7WEzjBoZgUEcpugJYK3JENby1xjh3yIHfws4HqLme1yXAmkYUK +6LmW96HC2g4wj7PH0hvLnzTOtXDGTppU7KJibbB+ziyhBbs6SGXOD4zHrCWmT9ld +CURhfNgftIs= +=AA+Q -----END PGP SIGNATURE----- diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c --- v2.3.99-pre2/linux/drivers/isdn/hisax/q931.c Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/hisax/q931.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $ +/* $Id: q931.c,v 1.8 2000/03/21 23:53:22 kai Exp $ * q931.c code to decode ITU Q.931 call control messages * @@ -14,6 +14,9 @@ * * * $Log: q931.c,v $ + * Revision 1.8 2000/03/21 23:53:22 kai + * fix backwards compatibility + * * Revision 1.7 1998/11/15 23:55:17 keil * changes from 2.0 * @@ -201,29 +204,6 @@ #define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) -static struct MessageType fac_1tr6[] = -{ - {FAC_Sperre, "Sperre"}, - {FAC_Forward1, "Forward 1"}, - {FAC_Forward2, "Forward 2"}, - {FAC_Konferenz, "Konferenz"}, - {FAC_GrabBchan, "Grab Bchannel"}, - {FAC_Reactivate, "Reactivate"}, - {FAC_Konferenz3, "Dreier Konferenz"}, - {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"}, - {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"}, - {FAC_NummernIdent, "Rufnummer-Identifizierung"}, - {FAC_GBG, "GBG"}, - {FAC_DisplayUebergeben, "Display Uebergeben"}, - {FAC_DisplayUmgeleitet, "Display Umgeleitet"}, - {FAC_Unterdruecke, "Unterdruecke Rufnummer"}, - {FAC_Deactivate, "Deactivate"}, - {FAC_Activate, "Activate"}, - {FAC_SPV, "SPV"}, - {FAC_Rueckwechsel, "Rueckwechsel"}, - {FAC_Umleitung, "Umleitung"} -}; -#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType)) static int prbits(char *dest, u_char b, int start, int len) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c --- v2.3.99-pre2/linux/drivers/isdn/hisax/w6692.c Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/hisax/w6692.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.2 2000/02/26 00:35:13 keil Exp $ +/* $Id: w6692.c,v 1.4 2000/03/16 23:24:11 werner Exp $ * w6692.c Winbond W6692 specific routines * @@ -8,6 +8,14 @@ * This file is (c) under GNU PUBLIC LICENSE * * $Log: w6692.c,v $ + * Revision 1.4 2000/03/16 23:24:11 werner + * + * Fixed an additional location + * + * Revision 1.3 2000/03/16 22:41:36 werner + * + * Tried to fix second B-channel problem (still not tested) + * * Revision 1.2 2000/02/26 00:35:13 keil * Fix skb freeing in interrupt context * @@ -50,7 +58,7 @@ extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.2 $"; +const char *w6692_revision = "$Revision: 1.4 $"; #define DBUSY_TIMER_VALUE 80 @@ -317,10 +325,13 @@ { u_char val; u_char r; - struct BCState *bcs = cs->bcs + bchan; + struct BCState *bcs = cs->bcs; struct sk_buff *skb; int count; + if (bcs->channel != bchan) + bcs++; /* hardware bchan must match ! */ + val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); @@ -724,7 +735,9 @@ W6692Bmode(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - int bchan = bcs->hw.w6692.bchan; + int bchan = bc; + + bcs->hw.w6692.bchan = bc; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "w6692 %c mode %d ichan %d", diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c --- v2.3.99-pre2/linux/drivers/isdn/hysdn/hysdn_procconf.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/isdn/hysdn/hysdn_procconf.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_procconf.c,v 1.2 2000/02/14 19:23:03 werner Exp $ +/* $Id: hysdn_procconf.c,v 1.4 2000/03/03 16:37:12 kai Exp $ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_procconf.c,v $ + * Revision 1.4 2000/03/03 16:37:12 kai + * incorporated some cosmetic changes from the official kernel tree back + * into CVS + * + * Revision 1.3 2000/03/02 00:11:07 werner + * + * Changes related to procfs for 2.3.48 + * * Revision 1.2 2000/02/14 19:23:03 werner * * Changed handling of proc filesystem tables to a more portable version @@ -40,7 +48,7 @@ #include "hysdn_defs.h" -static char *hysdn_procconf_revision = "$Revision: 1.2 $"; +static char *hysdn_procconf_revision = "$Revision: 1.4 $"; #define INFO_OUT_LEN 80 /* length of info line including lf */ @@ -403,11 +411,11 @@ /******************************************************/ static struct file_operations conf_fops = { - llseek: hysdn_dummy_lseek, - read: hysdn_conf_read, - write: hysdn_conf_write, - open: hysdn_conf_open, - release: hysdn_conf_close, + llseek: hysdn_dummy_lseek, + read: hysdn_conf_read, + write: hysdn_conf_write, + open: hysdn_conf_open, + release: hysdn_conf_close, }; /*****************************/ @@ -438,7 +446,6 @@ if ((card->procconf = (void *) create_proc_entry(conf_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; hysdn_proclog_init(card); /* init the log file entry */ } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/hysdn/hysdn_proclog.c linux/drivers/isdn/hysdn/hysdn_proclog.c --- v2.3.99-pre2/linux/drivers/isdn/hysdn/hysdn_proclog.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/isdn/hysdn/hysdn_proclog.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_proclog.c,v 1.2 2000/02/14 19:23:03 werner Exp $ +/* $Id: hysdn_proclog.c,v 1.4 2000/03/03 16:37:12 kai Exp $ * Linux driver for HYSDN cards, /proc/net filesystem log functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_proclog.c,v $ + * Revision 1.4 2000/03/03 16:37:12 kai + * incorporated some cosmetic changes from the official kernel tree back + * into CVS + * + * Revision 1.3 2000/03/02 00:11:07 werner + * + * Changes related to procfs for 2.3.48 + * * Revision 1.2 2000/02/14 19:23:03 werner * * Changed handling of proc filesystem tables to a more portable version @@ -40,7 +48,7 @@ #include "hysdn_defs.h" -static char *hysdn_proclog_revision = "$Revision: 1.2 $"; +static char *hysdn_proclog_revision = "$Revision: 1.4 $"; /* the proc subdir for the interface is defined in the procconf module */ extern struct proc_dir_entry *hysdn_proc_entry; @@ -420,14 +428,15 @@ /**************************************************/ static struct file_operations log_fops = { - llseek: hysdn_dummy_lseek, - read: hysdn_log_read, - write: hysdn_log_write, - poll: hysdn_log_poll, - open: hysdn_log_open, - release: hysdn_log_close, + llseek: hysdn_dummy_lseek, + read: hysdn_log_read, + write: hysdn_log_write, + poll: hysdn_log_poll, + open: hysdn_log_open, + release: hysdn_log_close, }; + /***********************************************************************************/ /* hysdn_proclog_init is called when the module is loaded after creating the cards */ /* conf files. */ @@ -441,10 +450,9 @@ if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { memset(pd, 0, sizeof(struct procdata)); - sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) - pd->log->proc_fops = &log_fops; /* set new operations table */ + pd->log->proc_fops = &log_fops; init_waitqueue_head(&(pd->rd_queue)); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c --- v2.3.99-pre2/linux/drivers/isdn/isdn_audio.c Thu Aug 26 13:05:37 1999 +++ linux/drivers/isdn/isdn_audio.c Wed Mar 22 22:23:55 2000 @@ -292,38 +292,25 @@ {'*', '0', '#', 'D'} }; - -/* - * egcs 2.95 complain about invalid asm statement: - * "fixed or forbidden register 2 (cx) was spilled for class CREG." - */ -#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__) -#if __GNUC__ == 2 && __GNUC_MINOR__ < 95 -#define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT -#endif -#endif - -#ifdef ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT static inline void isdn_audio_tlookup(const void *table, void *buff, unsigned long n) { - __asm__("cld\n" +#ifdef __i386__ + unsigned long d0, d1, d2, d3; + __asm__ __volatile__( + "cld\n" "1:\tlodsb\n\t" "xlatb\n\t" "stosb\n\t" "loop 1b\n\t" - : : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff) - : "bx", "cx", "di", "si", "ax"); -} - + : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3) + : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) + : "memory", "ax"); #else -static inline void -isdn_audio_tlookup(const char *table, char *buff, unsigned long n) -{ while (n--) *buff++ = table[*(unsigned char *)buff]; -} #endif +} void isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.3.99-pre2/linux/drivers/isdn/isdn_common.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/isdn/isdn_common.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.99 2000/02/26 01:00:52 keil Exp $ +/* $Id: isdn_common.c,v 1.100 2000/03/03 16:37:11 kai Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.100 2000/03/03 16:37:11 kai + * incorporated some cosmetic changes from the official kernel tree back + * into CVS + * * Revision 1.99 2000/02/26 01:00:52 keil * changes from 2.3.47 * @@ -449,7 +453,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.99 $"; +static char *isdn_revision = "$Revision: 1.100 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_concap.c linux/drivers/isdn/isdn_concap.c --- v2.3.99-pre2/linux/drivers/isdn/isdn_concap.c Thu Aug 26 13:05:37 1999 +++ linux/drivers/isdn/isdn_concap.c Thu Mar 23 08:38:57 2000 @@ -1,10 +1,13 @@ -/* $Id: isdn_concap.c,v 1.6 1999/08/22 20:26:01 calle Exp $ +/* $Id: isdn_concap.c,v 1.7 2000/03/21 23:53:22 kai Exp $ * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific * stuff goes here. Stuff that depends only on the concap protocol goes to * another -- protocol specific -- source file. * * $Log: isdn_concap.c,v $ + * Revision 1.7 2000/03/21 23:53:22 kai + * fix backwards compatibility + * * Revision 1.6 1999/08/22 20:26:01 calle * backported changes from kernel 2.3.14: * - several #include "config.h" gone, others come. @@ -58,15 +61,20 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) { - int tmp; struct net_device *ndev = concap -> net_dev; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev; + isdn_net_local *lp = isdn_net_get_locked_lp(nd); IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name); + if (!lp) { + IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 1); + return 1; + } lp->huptimer = 0; - tmp=isdn_net_send_skb(ndev, lp, skb); - IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp); - return tmp; + isdn_net_writebuf_skb(lp, skb); + spin_unlock_bh(&lp->xmit_lock); + IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 0); + return 0; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.3.99-pre2/linux/drivers/isdn/isdn_net.c Sat Feb 26 22:31:46 2000 +++ linux/drivers/isdn/isdn_net.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.110 2000/02/26 01:00:53 keil Exp $ +/* $Id: isdn_net.c,v 1.122 2000/03/20 22:37:46 detabc Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,50 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.122 2000/03/20 22:37:46 detabc + * modify abc-extension to work together with the new LL. + * remove abc frame-counter (is obsolete now). + * use the new lp->super_tx_queue for internal queueing (bsd-rawip-compress). + * modify isdn_net_xmit() and isdn_net_write_super(). + * -- Kai, please have a look to this two function's. Thank's. + * + * Revision 1.121 2000/03/19 15:27:53 kai + * no known bugs left... + * + * Revision 1.120 2000/03/18 16:20:25 kai + * cosmetics / renaming + * + * Revision 1.118 2000/03/17 18:20:46 kai + * moved to frame_cnt based flow control + * some races still need to be fixed + * + * Revision 1.117 2000/03/17 17:01:00 kai + * cleanup + * + * Revision 1.116 2000/03/17 16:22:55 kai + * we keep track of outstanding packets (given to HL, but not confirmed yet) + * now, but we don't use it for flow control yet. + * + * Revision 1.115 2000/03/17 12:49:42 kai + * calling statcallb with ISDN_STAT_BSENT in hard-IRQ context is now + * officially allowed. writebuf_skb() will never be called in hard-IRQ context + * anymore. + * + * Revision 1.114 2000/03/16 16:37:41 kai + * Allow phone numbers starting with "*" as outgoing numbers for + * networking interface. Some PBX's need this to allow dialing internal + * numbers (mine, for example ;-) + * + * Revision 1.113 2000/03/16 15:46:37 kai + * a little bugfix and cosmetic changes + * + * Revision 1.112 2000/03/04 16:20:42 detabc + * copy frames before rewriting frame's saddr + * + * Revision 1.111 2000/02/28 22:28:24 he + * moved tx_timeout warning messages in old (2.2.x) branch where it really only + * indicates problems. + * * Revision 1.110 2000/02/26 01:00:53 keil * changes from 2.3.47 * @@ -487,19 +531,6 @@ * the network layer, and therefore, it only makes sense to call netif_* * functions on them. * - * The old code abused the slaves dev->start to remember the corresponding - * master's interface state (ifup'ed or not). This does not work with SOFTNET - * any more, because there's now dev->start anymore. - * Instead I chose to add isdn_net_started() which gives the state of the - * master in case of slaves. - * I'm still not sure if this is how it's supposed to be done this way - * because it uses netif_running(dev) which might be - * considered private to the network layer. However, it works for now. - * Alternative: set a flag in _open() and clear it in _close() - * - * I left some dead code around in #if 0 which I'm not absolutely sure about. - * If no problems turn up, it should be removed later - * * --KG */ @@ -507,7 +538,7 @@ * Find out if the netdevice has been ifup-ed yet. * For slaves, look at the corresponding master. */ -static int __inline__ isdn_net_started(isdn_net_dev *n) +static __inline__ int isdn_net_device_started(isdn_net_dev *n) { isdn_net_local *lp = n->local; struct net_device *dev; @@ -523,7 +554,7 @@ * wake up the network -> net_device queue. * For slaves, wake the corresponding master interface. */ -static void __inline__ isdn_net_lp_xon(isdn_net_local * lp) +static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) { if (lp->master) netif_wake_queue(lp->master); @@ -531,6 +562,75 @@ netif_wake_queue(&lp->netdev->dev); } +/* + * stop the network -> net_device queue. + * For slaves, stop the corresponding master interface. + */ +static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) +{ + if (lp->master) + netif_stop_queue(lp->master); + else + netif_stop_queue(&lp->netdev->dev); +} + +/* + * find out if the net_device which this lp belongs to (lp can be + * master or slave) is busy. It's busy iff all (master and slave) + * queues are busy + */ +static __inline__ int isdn_net_device_busy(isdn_net_local *lp) +{ + isdn_net_local *nlp; + isdn_net_dev *nd; + unsigned long flags; + + if (!isdn_net_lp_busy(lp)) + return 0; + + if (lp->master) + nd = ((isdn_net_local *) lp->master->priv)->netdev; + else + nd = lp->netdev; + + spin_lock_irqsave(&nd->queue_lock, flags); + nlp = lp->next; + while (nlp != lp) { + if (!isdn_net_lp_busy(nlp)) { + spin_unlock_irqrestore(&nd->queue_lock, flags); + return 0; + } + nlp = nlp->next; + } + spin_unlock_irqrestore(&nd->queue_lock, flags); + return 1; +} + +static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp) +{ + atomic_inc(&lp->frame_cnt); + if (isdn_net_device_busy(lp)) + isdn_net_device_stop_queue(lp); +} + +static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp) +{ + atomic_dec(&lp->frame_cnt); + + if (!(isdn_net_device_busy(lp))) { + if (!skb_queue_empty(&lp->super_tx_queue)) { + queue_task(&lp->tqueue, &tq_immediate); + } else { + isdn_net_device_wake_queue(lp); + } + } +} + +static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) +{ + atomic_set(&lp->frame_cnt, 0); +} + /* For 2.2.x we leave the transmitter busy timeout at 2 secs, just * to be safe. * For 2.3.x we push it up to 20 secs, because call establishment @@ -546,9 +646,8 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); -static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.110 $"; +char *isdn_net_revision = "$Revision: 1.122 $"; /* * Code for raw-networking over ISDN @@ -660,16 +759,12 @@ isdn_net_unbind_channel(isdn_net_local * lp) { ulong flags; + struct sk_buff *skb; save_flags(flags); cli(); - if (lp->first_skb) { - dev_kfree_skb(lp->first_skb); - lp->first_skb = NULL; - } - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - lp->sav_skb = NULL; + while ((skb = skb_dequeue(&lp->super_tx_queue))) { + kfree_skb(skb); } if (!lp->master) { /* reset only master device */ /* Moral equivalent of dev_purge_queues(): @@ -766,6 +861,11 @@ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore); } +static void isdn_net_lp_disconnected(isdn_net_local *lp) +{ + isdn_net_rm_from_bundle(lp); +} + /* * Handle status-messages from ISDN-interfacecard. * This function is called from within the main-status-dispatcher @@ -789,28 +889,9 @@ /* A packet has successfully been sent out */ if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { + isdn_net_dec_frame_cnt(lp); lp->stats.tx_packets++; lp->stats.tx_bytes += c->parm.length; - /* some HL drivers deliver - ISDN_STAT_BSENT from hw interrupt. - Output routines in isdn_ppp are now - called with irq disabled such that - dequeueing the sav_skb while another - frame is sent will not occur. - */ - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) { - struct net_device *mdev; - if (lp->master) - mdev = lp->master; - else - mdev = &lp->netdev->dev; - if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) { - lp->sav_skb = NULL; - } else { - return 1; - } - } - isdn_net_lp_xon(lp); } return 1; case ISDN_STAT_DCONN: @@ -842,6 +923,7 @@ #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); #endif + isdn_net_lp_disconnected(lp); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); printk(KERN_INFO "%s: remote hangup\n", lp->name); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, @@ -864,6 +946,7 @@ #endif /* CONFIG_ISDN_X25 */ case ISDN_STAT_BCONN: /* B-Channel is up */ + isdn_net_zero_frame_cnt(lp); switch (lp->dialstate) { case 5: case 6: @@ -881,13 +964,17 @@ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1); + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { + if (lp->master) { /* is lp a slave? */ + isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; + isdn_net_add_to_bundle(nd, lp); + } + } printk(KERN_INFO "isdn_net: %s connected\n", lp->name); /* If first Chargeinfo comes before B-Channel connect, * we correct the timestamp here. */ lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n", - lp->name, lp->chargetime); /* reset dial-timeout */ lp->dialstarted = 0; @@ -903,13 +990,9 @@ if( pops->connect_ind) pops->connect_ind(cprot); #endif /* CONFIG_ISDN_X25 */ - /* Immediately send first skb to speed up arp */ - if (lp->first_skb) { - - if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb))) - lp->first_skb = NULL; - } - if(! lp->first_skb) isdn_net_lp_xon(lp); + /* ppp needs to do negotiations first */ + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) + isdn_net_device_wake_queue(lp); return 1; } break; @@ -942,20 +1025,6 @@ } /* - * Check, if a number contains wildcard-characters, in which case it - * is for incoming purposes only. - */ -static int -isdn_net_checkwild(char *num) -{ - return ((strchr(num, '?')) || - (strchr(num, '*')) || - (strchr(num, '[')) || - (strchr(num, ']')) || - (strchr(num, '^'))); -} - -/* * Perform dialout for net-interfaces and timeout-handling for * D-Channel-up and B-Channel-up Messages. * This function is initially called from within isdn_net_start_xmit() or @@ -1033,7 +1102,7 @@ s = "dial suppressed: isdn system stopped"; else s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(&p->dev, lp->first_skb, s); + isdn_net_unreachable(&p->dev, 0, s); isdn_net_hangup(&p->dev); break; } @@ -1066,7 +1135,7 @@ restore_flags(flags); lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out"); + isdn_net_unreachable(&p->dev, 0, "dial: timed out"); isdn_net_hangup(&p->dev); break; } @@ -1084,7 +1153,7 @@ if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times"); + isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times"); } isdn_net_hangup(&p->dev); break; @@ -1248,6 +1317,7 @@ #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); #endif + isdn_net_lp_disconnected(lp); #ifdef CONFIG_ISDN_X25 /* try if there are generic encap protocol receiver routines and signal the closure of @@ -1360,31 +1430,83 @@ } /* - * Generic routine to send out an skbuf. - * If lowlevel-device does not support support skbufs, use - * standard send-routine, else send directly. - * - * Return: 0 on success, !0 on failure. + * this function is used to send supervisory data, i.e. data which was + * not received from the network layer, but e.g. frames from ipppd, CCP + * reset frames etc. + */ +void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) +{ + if (in_interrupt()) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + return; + } + + spin_lock_bh(&lp->xmit_lock); + if (!isdn_net_lp_busy(lp)) { + isdn_net_writebuf_skb(lp, skb); + } else { + skb_queue_tail(&lp->super_tx_queue, skb); + } + spin_unlock_bh(&lp->xmit_lock); +} + +/* + * called from tq_immediate */ -int isdn_net_send_skb - (struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb) +static void +isdn_net_softint(void *private) +{ + isdn_net_local *lp = private; + struct sk_buff *skb; + + spin_lock_bh(&lp->xmit_lock); + while (!isdn_net_lp_busy(lp)) { + skb = skb_dequeue(&lp->super_tx_queue); + if (!skb) + break; + isdn_net_writebuf_skb(lp, skb); + } + spin_unlock_bh(&lp->xmit_lock); +} + +/* + * all frames sent from the (net) LL to a HL driver should go via this function + * it's serialized by the caller holding the lp->xmit_lock spinlock + */ +void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb) { int ret; int len = skb->len; /* save len */ - ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); - if (ret == len) { - lp->transcount += len; - return 0; + /* before obtaining the lock the caller should have checked that + the lp isn't busy */ + if (isdn_net_lp_busy(lp)) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + goto error; } - if (ret < 0) { - dev_kfree_skb(skb); - lp->stats.tx_errors++; - return 0; + + if (!(lp->flags & ISDN_NET_CONNECTED)) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + goto error; } - return 1; + ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); + if (ret != len) { + /* we should never get here */ + printk(KERN_WARNING "%s: HL driver queue full\n", lp->name); + goto error; + } + + lp->transcount += len; + isdn_net_inc_frame_cnt(lp); + return; + + error: + dev_kfree_skb(skb); + lp->stats.tx_errors++; + } + /* * Helper function for isdn_net_start_xmit. * When called, the connection is already established. @@ -1397,9 +1519,18 @@ */ static int -isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb) +isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) { - int ret; + isdn_net_dev *nd; + isdn_net_local *slp; + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + int retv = 0; + + if (((isdn_net_local *) (ndev->priv))->master) { + printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); + dev_kfree_skb(skb); + return 0; + } /* For the other encaps the header has already been built */ #ifdef CONFIG_ISDN_PPP @@ -1407,31 +1538,27 @@ return isdn_ppp_xmit(skb, ndev); } #endif + + nd = ((isdn_net_local *) ndev->priv)->netdev; + + lp = isdn_net_get_locked_lp(nd); + if (!lp) { + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name); + return 1; + } + /* we have our lp locked from now on */ + /* Reset hangup-timeout */ - lp->huptimer = 0; + lp->huptimer = 0; // FIXME? + isdn_net_writebuf_skb(lp, skb); + spin_unlock_bh(&lp->xmit_lock); + + /* the following stuff is here for backwards compatibility. + * in future, start-up and hangup of slaves (based on current load) + * should move to userspace and get based on an overall cps + * calculation + */ if (lp->cps > lp->triggercps) { - /* Device overloaded */ - - /* - * Packet-delivery via round-robin over master - * and all connected slaves. - */ - if (lp->master) - /* Slaves always deliver themselves */ - ret = isdn_net_send_skb(ndev, lp, skb); - else { - isdn_net_local *slp = (isdn_net_local *) (lp->srobin->priv); - /* Master delivers via srobin and maintains srobin */ - if (lp->srobin == ndev) - ret = isdn_net_send_skb(ndev, lp, skb); - else - ret = isdn_net_start_xmit(skb, lp->srobin); - lp->srobin = (slp->slave) ? slp->slave : ndev; - slp = (isdn_net_local *) (lp->srobin->priv); - if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0))) - lp->srobin = ndev; - } - /* Slave-startup using delay-variable */ if (lp->slave) { if (!lp->sqfull) { /* First time overload: set timestamp only */ @@ -1439,17 +1566,24 @@ lp->sqfull_stamp = jiffies; } else { /* subsequent overload: if slavedelay exceeded, start dialing */ - if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) - isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); + if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) { + slp = lp->slave->priv; + if (!(slp->flags & ISDN_NET_CONNECTED)) { + isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); + } + } } } } else { - /* Not overloaded, deliver locally */ - ret = isdn_net_send_skb(ndev, lp, skb); - if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) + if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) { lp->sqfull = 0; + } + /* this is a hack to allow auto-hangup for slaves on moderate loads */ + nd->queue = nd->local; } - return ret; + + return retv; + } static void @@ -1489,7 +1623,7 @@ * actually, this may not matter at all, because ISDN hardware * should not see transmitter hangs at all IMO * changed KERN_DEBUG to KERN_WARNING to find out if this is - * ever called + * ever called --KG */ } ndev->trans_start = jiffies; @@ -1608,19 +1742,11 @@ return 1; /* let upper layer requeue skb packet */ } #endif - /* remember first skb to speed up arp - * when using encap ETHER - */ - if (lp->first_skb) { - printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n"); - dev_kfree_skb(lp->first_skb); - lp->first_skb = NULL; - } - lp->first_skb = skb; /* Initiate dialing */ restore_flags(flags); isdn_net_dial(); - return 0; + isdn_net_device_stop_queue(lp); + return 1; } else { isdn_net_unreachable(ndev, skb, "No phone number"); @@ -1633,14 +1759,7 @@ if (!lp->dialstate) { /* ISDN connection is established, try sending */ int ret; - if (lp->first_skb) { - if (isdn_net_xmit(ndev, lp, lp->first_skb)){ - netif_stop_queue(ndev); - return 1; -} - lp->first_skb = NULL; - } - ret = (isdn_net_xmit(ndev, lp, skb)); + ret = (isdn_net_xmit(ndev, skb)); if(ret) netif_stop_queue(ndev); return ret; } else @@ -1754,7 +1873,6 @@ unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC); unsigned long t = (jiffies / HZ * 1000000); - int len; cisco_hdr *ch; cisco_slarp *s; @@ -1782,9 +1900,7 @@ s->rel = 0xffff; s->t1 = t >> 16; s->t0 = t & 0xffff; - len = skb->len; - if (isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 0, skb) != len) - dev_kfree_skb(skb); + isdn_net_write_super(lp, skb); } static void @@ -2417,7 +2533,7 @@ * Is the interface up? * If not, reject the call actively. */ - if (!isdn_net_started(p)) { + if (!isdn_net_device_started(p)) { restore_flags(flags); printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", lp->name); @@ -2508,6 +2624,7 @@ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_free(lp); #endif + isdn_net_lp_disconnected(lp); isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); } @@ -2707,10 +2824,17 @@ netdev->ib.last = NULL; #endif netdev->queue = netdev->local; + spin_lock_init(&netdev->queue_lock); + netdev->local->last = netdev->local; netdev->local->netdev = netdev; netdev->local->next = netdev->local; + memset(&netdev->local->tqueue, 0, sizeof(struct tq_struct)); + netdev->local->tqueue.routine = isdn_net_softint; + netdev->local->tqueue.data = netdev->local; + spin_lock_init(&netdev->local->xmit_lock); + netdev->local->isdn_device = -1; netdev->local->isdn_channel = -1; netdev->local->pre_device = -1; @@ -2718,13 +2842,11 @@ netdev->local->exclusive = -1; netdev->local->ppp_slot = -1; netdev->local->pppbind = -1; - netdev->local->sav_skb = NULL; - netdev->local->first_skb = NULL; + skb_queue_head_init(&netdev->local->super_tx_queue); netdev->local->l2_proto = ISDN_PROTO_L2_X75I; netdev->local->l3_proto = ISDN_PROTO_L3_TRANS; netdev->local->triggercps = 6000; netdev->local->slavedelay = 10 * HZ; - netdev->local->srobin = &netdev->dev; netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ netdev->local->onhtime = 10; /* Default hangup-time for saving costs of those who forget configuring this */ @@ -2762,7 +2884,7 @@ if (n->local->master) return NULL; /* Master must not be started yet */ - if (isdn_net_started(n)) + if (isdn_net_device_started(n)) return NULL; return (isdn_net_new(newname, &(n->dev))); } @@ -2805,7 +2927,7 @@ #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = p -> cprot; #endif - if (isdn_net_started(p)) { + if (isdn_net_device_started(p)) { printk(KERN_WARNING "%s: cannot change encap when if is up\n", lp->name); return -EBUSY; @@ -3066,8 +3188,6 @@ isdn_net_dev *p = isdn_net_findif(phone->name); isdn_net_phone *n; - if (isdn_net_checkwild(phone->phone) && (phone->outgoing & 1)) - return -EINVAL; if (p) { if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL))) return -ENOMEM; @@ -3240,7 +3360,7 @@ save_flags(flags); cli(); - if (isdn_net_started(p)) { + if (isdn_net_device_started(p)) { restore_flags(flags); return -EBUSY; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v2.3.99-pre2/linux/drivers/isdn/isdn_net.h Thu Aug 26 13:05:37 1999 +++ linux/drivers/isdn/isdn_net.h Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.h,v 1.10 1999/08/22 20:26:06 calle Exp $ +/* $Id: isdn_net.h,v 1.16 2000/03/21 23:53:22 kai Exp $ * header for Linux ISDN subsystem, network related functions (linklevel). * @@ -21,6 +21,26 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.h,v $ + * Revision 1.16 2000/03/21 23:53:22 kai + * fix backwards compatibility + * + * Revision 1.15 2000/03/19 15:27:53 kai + * no known bugs left... + * + * Revision 1.14 2000/03/18 16:20:25 kai + * cosmetics / renaming + * + * Revision 1.13 2000/03/17 18:20:46 kai + * moved to frame_cnt based flow control + * some races still need to be fixed + * + * Revision 1.12 2000/03/17 17:01:00 kai + * cleanup + * + * Revision 1.11 2000/03/17 16:22:55 kai + * we keep track of outstanding packets (given to HL, but not confirmed yet) + * now, but we don't use it for flow control yet. + * * Revision 1.10 1999/08/22 20:26:06 calle * backported changes from kernel 2.3.14: * - several #include "config.h" gone, others come. @@ -124,8 +144,88 @@ extern int isdn_net_force_hangup(char *); extern int isdn_net_force_dial(char *); extern isdn_net_dev *isdn_net_findif(char *); -extern int isdn_net_send_skb(struct net_device *, isdn_net_local *, - struct sk_buff *); extern int isdn_net_rcv_skb(int, struct sk_buff *); extern void isdn_net_slarp_out(void); extern int isdn_net_dial_req(isdn_net_local *); +extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb); +extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); + +#define ISDN_NET_MAX_QUEUE_LENGTH 2 + +/* + * is this particular channel busy? + */ +static __inline__ int isdn_net_lp_busy(isdn_net_local *lp) +{ + if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH) + return 0; + else + return 1; +} + +/* + * For the given net device, this will get a non-busy channel out of the + * corresponding bundle. The returned channel is locked. + */ +static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd) +{ + unsigned long flags; + isdn_net_local *lp; + + spin_lock_irqsave(&nd->queue_lock, flags); + lp = nd->queue; /* get lp on top of queue */ + spin_lock_bh(&nd->queue->xmit_lock); + while (isdn_net_lp_busy(nd->queue)) { + spin_unlock_bh(&nd->queue->xmit_lock); + nd->queue = nd->queue->next; + if (nd->queue == lp) /* not found -- should never happen */ + return 0; + spin_lock_bh(&nd->queue->xmit_lock); + } + lp = nd->queue; + + nd->queue = nd->queue->next; + spin_unlock_irqrestore(&nd->queue_lock, flags); + return lp; +} + +/* + * add a channel to a bundle + */ +static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp) +{ + isdn_net_local *lp; + unsigned long flags; + + spin_lock_irqsave(&nd->queue_lock, flags); + + lp = nd->queue; + nlp->last = lp->last; + lp->last->next = nlp; + lp->last = nlp; + nlp->next = lp; + nd->queue = nlp; + + spin_unlock_irqrestore(&nd->queue_lock, flags); +} +/* + * remove a channel from the bundle it belongs to + */ +static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) +{ + isdn_net_local *master_lp = lp; + unsigned long flags; + + if (lp->master) + master_lp = (isdn_net_local *) lp->master->priv; + + spin_lock_irqsave(&master_lp->netdev->queue_lock, flags); + lp->last->next = lp->next; + lp->next->last = lp->last; + if (master_lp->netdev->queue == lp) + master_lp->netdev->queue = lp->next; + lp->next = lp->last = lp; /* (re)set own pointers */ + spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); +} + + diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.3.99-pre2/linux/drivers/isdn/isdn_ppp.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/isdn_ppp.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.62 2000/02/12 19:26:55 kai Exp $ +/* $Id: isdn_ppp.c,v 1.69 2000/03/19 15:27:53 kai Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.69 2000/03/19 15:27:53 kai + * no known bugs left... + * + * Revision 1.67 2000/03/17 18:20:46 kai + * moved to frame_cnt based flow control + * some races still need to be fixed + * + * Revision 1.66 2000/03/17 17:01:00 kai + * cleanup + * + * Revision 1.65 2000/03/17 16:22:55 kai + * we keep track of outstanding packets (given to HL, but not confirmed yet) + * now, but we don't use it for flow control yet. + * + * Revision 1.64 2000/03/17 10:43:56 kai + * 2.3.99 contains MPPP constants which cause a warning because we + * redefine them in include/linux/isdn_ppp.h + * + * So from now on we use the generic PPP constants, change is backwards + * compatible, though + * + * Revision 1.63 2000/03/16 15:46:37 kai + * a little bugfix and cosmetic changes + * * Revision 1.62 2000/02/12 19:26:55 kai * adopted to latest 2.3 softnet changes. * @@ -263,10 +287,6 @@ * */ -/* TODO: right tbusy handling when using MP */ - -#define CONFIG_ISDN_CCP 1 - #include #define __NO_VERSION__ #include @@ -331,7 +351,7 @@ static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.62 $"; +char *isdn_ppp_revision = "$Revision: 1.69 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; @@ -366,36 +386,28 @@ int isdn_ppp_free(isdn_net_local * lp) { -#ifdef CONFIG_ISDN_MPP isdn_net_local *master_lp = lp; -#endif unsigned long flags; struct ippp_struct *is; if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) return 0; - is = ippp_table[lp->ppp_slot]; - save_flags(flags); cli(); -#ifdef CONFIG_ISDN_MPP - if (lp->master) - master_lp = (isdn_net_local *) lp->master->priv; - lp->last->next = lp->next; - lp->next->last = lp->last; - if (master_lp->netdev->queue == lp) { - master_lp->netdev->queue = lp->next; - if (lp->next == lp) { /* last link in queue? */ - master_lp->netdev->ib.bundled = 0; - isdn_ppp_free_mpqueue(master_lp->netdev); - isdn_ppp_free_sqqueue(master_lp->netdev); - } +#ifdef CONFIG_ISDN_MPP + if (lp->next == lp) { /* last link in queue? */ + master_lp->netdev->ib.bundled = 0; + isdn_ppp_free_mpqueue(master_lp->netdev); + isdn_ppp_free_sqqueue(master_lp->netdev); } - lp->next = lp->last = lp; /* (re)set own pointers */ #endif + isdn_net_rm_from_bundle(lp); + + is = ippp_table[lp->ppp_slot]; + if ((is->state & IPPP_CONNECT)) isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ else if (is->state & IPPP_ASSIGNED) @@ -406,6 +418,7 @@ is->lp = NULL; /* link is down .. set lp to NULL */ lp->ppp_slot = -1; /* is this OK ?? */ + restore_flags(flags); return 0; @@ -422,9 +435,6 @@ long flags; struct ippp_struct *is; - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) - return -1; - save_flags(flags); cli(); @@ -1030,8 +1040,6 @@ lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { unsigned short hl; - unsigned long flags; - int cnt; struct sk_buff *skb; /* * we need to reserve enought space in front of @@ -1054,17 +1062,7 @@ isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */ - save_flags(flags); - cli(); - if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) { - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count); - } else - printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count); - lp->sav_skb = skb; - } - restore_flags(flags); + isdn_net_write_super(lp, skb); } } return count; @@ -1162,7 +1160,7 @@ int sqno_end; if(is->compflags & SC_LINK_DECOMP_ON) { - if(proto == PPP_LINK_COMP) { + if(proto == PPP_COMPFRAG) { if(is->debug & 0x10) printk(KERN_DEBUG "received single link compressed frame\n"); skb = isdn_ppp_decompress(skb,is,NULL,proto); @@ -1425,7 +1423,7 @@ #endif break; case PPP_CCP: - case PPP_LINK_CCP: + case PPP_CCPFRAG: isdn_ppp_receive_ccp(net_dev,lp,skb,proto); /* Dont pop up ResetReq/Ack stuff to the daemon any longer - the job is done already */ @@ -1484,19 +1482,13 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct net_device *mdev = ((isdn_net_local *) (netdev->priv))->master; /* get master (for redundancy) */ isdn_net_local *lp,*mlp; isdn_net_dev *nd; unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt,*ipts; - unsigned long flags; - if (mdev) - mlp = (isdn_net_local *) (mdev->priv); - else { - mdev = netdev; - mlp = (isdn_net_local *) (netdev->priv); - } + mlp = (isdn_net_local *) (netdev->priv); + nd = mlp->netdev; /* get master lp */ ipts = ippp_table[mlp->ppp_slot]; @@ -1515,21 +1507,18 @@ break; default: dev_kfree_skb(skb); - printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol); + printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", + skb->protocol); return 0; } - lp = nd->queue; /* get lp on top of queue */ - - if (lp->sav_skb) { /* find a non-busy device */ - isdn_net_local *nlp = lp->next; - while (lp->sav_skb) { - if (lp == nlp) - return 1; - nlp = nd->queue = nd->queue->next; - } - lp = nlp; + lp = isdn_net_get_locked_lp(nd); + if (!lp) { + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name); + return 1; } + /* we have our lp locked from now on */ + ipt = ippp_table[lp->ppp_slot]; lp->huptimer = 0; @@ -1538,8 +1527,8 @@ */ /* Pull off the fake header we stuck on earlier to keep - * the fragemntation code happy. - */ + * the fragmentation code happy. + */ skb_pull(skb,IPPP_MAX_HEADER); if (ipt->debug & 0x4) @@ -1612,11 +1601,10 @@ /* we get mp_seqno from static isdn_net_local */ long mp_seqno = ipts->mp_seqno; ipts->mp_seqno++; - nd->queue = nd->queue->next; if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) { unsigned char *data = isdn_ppp_skb_push(&skb, 3); if(!data) - return 0; + goto unlock; mp_seqno &= 0xfff; data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */ data[1] = mp_seqno & 0xff; @@ -1624,7 +1612,7 @@ } else { unsigned char *data = isdn_ppp_skb_push(&skb, 5); if(!data) - return 0; + goto unlock; data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ data[2] = (mp_seqno >> 8) & 0xff; @@ -1644,20 +1632,20 @@ if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { unsigned char *data = isdn_ppp_skb_push(&skb,1); if(!data) - return 0; + goto unlock; data[0] = proto & 0xff; } else { unsigned char *data = isdn_ppp_skb_push(&skb,2); if(!data) - return 0; + goto unlock; data[0] = (proto >> 8) & 0xff; data[1] = proto & 0xff; } if(!(ipt->pppcfg & SC_COMP_AC)) { unsigned char *data = isdn_ppp_skb_push(&skb,2); if(!data) - return 0; + goto unlock; data[0] = 0xff; /* All Stations */ data[1] = 0x03; /* Unnumbered information */ } @@ -1668,16 +1656,11 @@ printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot); } - save_flags(flags); - cli(); - if (isdn_net_send_skb(netdev, lp, skb)) { - if (lp->sav_skb) { /* should never happen as sav_skb are sent with disabled IRQs) */ - printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name); - dev_kfree_skb(skb); - } else - lp->sav_skb = skb; - } - restore_flags(flags); + + isdn_net_writebuf_skb(lp, skb); + + unlock: + spin_unlock_bh(&lp->xmit_lock); return 0; } @@ -1731,28 +1714,21 @@ char ifn[IFNAMSIZ + 1]; long flags; isdn_net_dev *p; - isdn_net_local *lp, - *nlp; + isdn_net_local *lp, *nlp; sprintf(ifn, "ippp%d", unit); p = isdn_net_findif(ifn); if (!p) return -1; - isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */ - save_flags(flags); cli(); + isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */ nlp = is->lp; - lp = p->queue; + isdn_net_add_to_bundle(p, nlp); p->ib.bundled = 1; - nlp->last = lp->last; - lp->last->next = nlp; - lp->last = nlp; - nlp->next = lp; - p->queue = nlp; ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; /* maybe also SC_CCP stuff */ @@ -1761,7 +1737,6 @@ ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); - restore_flags(flags); return 0; } @@ -1949,12 +1924,14 @@ #ifdef CONFIG_ISDN_PPP_VJ int toss = 0; #endif -/* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft: - eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen - wenn sqno min_sqno: Larger than mp_mrru: If sum of all pktlen of pending + packets large than mrru: discard - packets need to be consecutive, though, if not + there could be an B and an E-packet in between. + */ struct mpqueue *ql, *q = dev->mp_last; @@ -2249,8 +2226,7 @@ { struct sk_buff *skb; unsigned char *p; - int count, hl; - unsigned long flags; + int hl; int cnt = 0; isdn_net_local *lp = is->lp; @@ -2291,26 +2267,7 @@ printk(KERN_DEBUG "Sending CCP Frame:\n"); isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); - /* Just ripped from isdn_ppp_write. Dunno whether it makes sense, - especially dunno what the sav_skb stuff is good for. */ - - count = skb->len; - save_flags(flags); - cli(); - if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, - 1, skb)) != count) { - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - printk(KERN_INFO - "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", - cnt, count); - } else - printk(KERN_INFO - "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", - cnt, count); - lp->sav_skb = skb; - } - restore_flags(flags); + isdn_net_write_super(lp, skb); } /* Allocate the reset state vector */ @@ -2560,14 +2517,6 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master, int proto) { -#ifndef CONFIG_ISDN_CCP - if(proto == PPP_COMP || proto == PPP_LINK_COMP) { - printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n"); - dev_kfree_skb(skb); - return NULL; - } - return skb; -#else void *stat = NULL; struct isdn_ppp_compressor *ipc = NULL; struct sk_buff *skb_out; @@ -2617,7 +2566,7 @@ printk(KERN_DEBUG "ippp: Decompress valid!\n"); */ - if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) { + if((master && proto == PPP_COMP) || (!master && proto == PPP_COMPFRAG) ) { /* Set up reset params for the decompressor */ memset(&rsparm, 0, sizeof(rsparm)); rsparm.data = rsdata; @@ -2657,7 +2606,6 @@ ipc->incomp(stat,skb,proto); return skb; } -#endif } /* @@ -2676,13 +2624,9 @@ void *stat; struct sk_buff *skb_out; -#ifdef CONFIG_ISDN_CCP /* we do not compress control protocols */ if(*proto < 0 || *proto > 0x3fff) { -#else - { -#endif - return skb_in; + return skb_in; } if(type) { /* type=1 => Link compression */ @@ -2883,7 +2827,7 @@ } proto = ((int)data[0]<<8)+data[1]; - if(proto != PPP_CCP && proto != PPP_LINK_CCP) + if(proto != PPP_CCP && proto != PPP_CCPFRAG) return; printk(KERN_DEBUG "Received CCP frame from daemon:\n"); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_v110.c linux/drivers/isdn/isdn_v110.c --- v2.3.99-pre2/linux/drivers/isdn/isdn_v110.c Thu Nov 11 20:11:39 1999 +++ linux/drivers/isdn/isdn_v110.c Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_v110.c,v 1.3 1999/10/30 09:49:28 keil Exp $ +/* $Id: isdn_v110.c,v 1.4 2000/03/16 16:34:12 kai Exp $ * Linux ISDN subsystem, V.110 related functions (linklevel). * @@ -19,6 +19,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_v110.c,v $ + * Revision 1.4 2000/03/16 16:34:12 kai + * some translation work + * + * there shouldn't be any German comments lurking around anymore ;-) + * * Revision 1.3 1999/10/30 09:49:28 keil * Reinit of v110 structs * @@ -39,14 +44,15 @@ #undef ISDN_V110_DEBUG -char *isdn_v110_revision = "$Revision: 1.3 $"; +char *isdn_v110_revision = "$Revision: 1.4 $"; #define V110_38400 255 #define V110_19200 15 #define V110_9600 3 -/* Die folgenden Daten sind fertig kodierte Matrizen, jeweils - als online und offline matrix für 9600, 19200 und 38400 +/* + * The following data are precoded matrices, online and offline matrix + * for 9600, 19200 und 38400, respectively */ static unsigned char V110_OnMatrix_9600[] = {0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, @@ -74,13 +80,12 @@ static unsigned char V110_OffMatrix_38400[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff}; - -/* FlipBits dreht die Reihenfolge von jeweils keylen bits in einem byte um. - Aus der Bitreihenfolge 76543210 werden bei keylen=4 die bits 45670123, - bei keylen=2 die bits 67452301. Dies ist notwendig, weil die reihenfolge - auf der isdn-leitung falsch herum ist. +/* + * FlipBits reorders sequences of keylen bits in one byte. + * E.g. source order 7654321 will be converted to 45670123 when keylen = 4, + * and to 67452301 when keylen = 2. This is necessary because ordering on + * the isdn line is the the other way. */ - static __inline unsigned char FlipBits(unsigned char c, int keylen) { @@ -164,8 +169,9 @@ } -/* ValidHeaderBytes prüft, wieviele bytes in v->decodebuf gültig sind */ - +/* + * ValidHeaderBytes return the number of valid bytes in v->decodebuf + */ static int ValidHeaderBytes(isdn_v110_stream * v) { @@ -176,8 +182,9 @@ return i; } -/* SyncHeader schiebt den decodebuf pointer auf den nächsten gültigen header */ - +/* + * SyncHeader moves the decodebuf ptr to the next valid header + */ static void SyncHeader(isdn_v110_stream * v) { @@ -214,68 +221,60 @@ int dbit = v->dbit; unsigned char b = v->b; - while (line < len) { /* sind schon alle matrizenzeilen abgearbeitet? */ - if ((line % 10) == 0) { /* die 0. zeile der matrix ist immer null ! */ - if (m[line] != 0x00) { /* nicht 0 ? dann fehler! */ + while (line < len) { /* Are we done with all lines of the matrix? */ + if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */ + if (m[line] != 0x00) { /* not 0 ? -> error! */ #ifdef ISDN_V110_DEBUG printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n"); + /* returning now is not the right thing, though :-( */ #endif - -/* - dann einen return zu machen, ist auch irgendwie nicht das richtige! :-( - v->introducer = 0; v->dbit = 1; v->b = 0; - return buflen; anzahl schon erzeugter daten zurückgeben! - */ - } - line++; /* sonst die nächste matrixzeile nehmen */ + } + line++; /* next line of matrix */ continue; - } else if ((line % 10) == 5) { /* in zeile 5 stehen nur e-bits ! */ - if ((m[line] & 0x70) != 0x30) { /* 011 muß am anfang stehen! */ + } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */ + if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */ #ifdef ISDN_V110_DEBUG printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n"); + /* returning now is not the right thing, though :-( */ #endif -/* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-( - v->introducer = 0; v->dbit = 1; v->b = 0; - return buflen; - */ } - line++; /* alles klar, nächste zeile */ + line++; /* next line */ continue; } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */ - introducer = (m[line] & mbit) ? 0 : 1; /* aktuelles bit der matrix */ + introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */ next_byte: - if (mbit > 2) { /* war es das letzte bit dieser matrixzeile ? */ - mbit >>= 1; /* nein, nimm das nächste in dieser zeile */ + if (mbit > 2) { /* was it the last bit in this line ? */ + mbit >>= 1; /* no -> take next */ continue; - } /* sonst links in der nächsten zeile anfangen */ + } /* otherwise start with leftmost bit in the next line */ mbit = 64; line++; continue; - } else { /* sonst müssen wir ein datenbit setzen */ - if (m[line] & mbit) /* war das bit in der matrix gesetzt ? */ - b |= dbit; /* ja, dann setz es auch im datenbyte */ + } else { /* otherwise we need to set a data bit */ + if (m[line] & mbit) /* was that bit set in the matrix ? */ + b |= dbit; /* yes -> set it in the data byte */ else - b &= dbit - 1; /* nein, lösch bit im datenbyte */ - if (dbit < 128) /* haben wir schon ein ganzes byte voll ? */ - dbit <<= 1; /* nein, auf zum nächsten datenbit */ - else { /* ein ganzes datenbyte ist voll */ - buf[buflen++] = b; /* byte in den output buffer kopieren */ - introducer = b = 0; /* Init der Introsequenz und des datenbytes */ - dbit = 1; /* als nächstes suchen wir das nullte bit */ + b &= dbit - 1; /* no -> clear it in the data byte */ + if (dbit < 128) /* is that data byte done ? */ + dbit <<= 1; /* no, got the next bit */ + else { /* data byte is done */ + buf[buflen++] = b; /* copy byte into the output buffer */ + introducer = b = 0; /* init of the intro sequence and of the data byte */ + dbit = 1; /* next we look for the 0th bit */ } - goto next_byte; /* suche das nächste bit in der matrix */ + goto next_byte; /* look for next bit in the matrix */ } } v->introducer = introducer; v->dbit = dbit; v->b = b; - return buflen; /* return anzahl der bytes im output buffer */ + return buflen; /* return number of bytes in the output buffer */ } -/* DecodeStream erhält vom input stream V110 kodierte Daten, die zu den - V110 frames zusammengepackt werden müssen. Die Daten können an diese - Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne - darauf achten zu müssen, das frames usw. eingehalten werden. +/* + * DecodeStream receives V.110 coded data from the input stream. It recovers the + * original frames. + * The input stream doesn't need to be framed */ struct sk_buff * isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb) @@ -314,8 +313,8 @@ dev_kfree_skb(skb); return NULL; /* no, try later */ } - if (ValidHeaderBytes(v) != v->nbytes) { /* ist es ein ungültiger header ? */ - SyncHeader(v); /* nein, such einen header */ + if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */ + SyncHeader(v); /* no -> look for header */ goto ReSync; } len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes; @@ -357,15 +356,15 @@ int introducer = 3; int ibit[] = {0, 1, 1}; - while ((i < len) && (line < mlen)) { /* solange noch input da ist */ - switch (line % 10) { /* in welcher matrixzeile sind wir ? */ + while ((i < len) && (line < mlen)) { /* while we still have input data */ + switch (line % 10) { /* in which line of the matrix are we? */ case 0: - m[line++] = 0x00; /* zeile 0 ist immer 0 */ - mbit = 128; /* und es geht mit dem 7. bit weiter */ + m[line++] = 0x00; /* line 0 is always 0 */ + mbit = 128; /* go on with the 7th bit */ break; case 5: - m[line++] = 0xbf; /* zeile 5 ist immer 10111111 */ - mbit = 128; /* und es geht mit dem 7. bit weiter */ + m[line++] = 0xbf; /* line 5 is always 10111111 */ + mbit = 128; /* go on with the 7th bit */ break; } if (line >= mlen) { @@ -373,41 +372,41 @@ return line; } next_bit: - switch (mbit) { /* ganz linkes oder rechtes bit ? */ + switch (mbit) { /* leftmost or rightmost bit ? */ case 1: - line++; /* ganz rechts ! dann in die nächste */ + line++; /* rightmost -> go to next line */ if (line >= mlen) { printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n"); return line; } case 128: - m[line] = 128; /* ganz links byte auf 1000000 setzen */ - mbit = 64; /* aktuelles bit in der matrixzeile */ + m[line] = 128; /* leftmost -> set byte to 1000000 */ + mbit = 64; /* current bit in the matrix line */ continue; } - if (introducer) { /* 110 sequenz setzen ? */ - introducer--; /* ein digit weniger setzen */ - m[line] |= ibit[introducer] ? mbit : 0; /* entsprechendes bit setzen */ - mbit >>= 1; /* bit der matrixzeile >> 1 */ - goto next_bit; /* und dort weiter machen */ - } /* else datenbits in die matrix packen! */ - m[line] |= (buf[i] & dbit) ? mbit : 0; /* datenbit in matrix setzen */ - if (dbit == 128) { /* war es das letzte datenbit ? */ - dbit = 1; /* dann mach beim nächsten weiter */ - i++; /* nächste datenbyte des input buffers */ - if (i < len) /* war es schon das letzte ? */ - introducer = 3; /* nein, schreib den introducer 110 */ - else { /* war das letzte datenbyte ! */ - m[line] |= (mbit - 1) & 0xfe; /* setz restliche bits der zeile auf 1 */ + if (introducer) { /* set 110 sequence ? */ + introducer--; /* set on digit less */ + m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */ + mbit >>= 1; /* bit of matrix line >> 1 */ + goto next_bit; /* and go on there */ + } /* else push data bits into the matrix! */ + m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */ + if (dbit == 128) { /* was it the last one? */ + dbit = 1; /* then go on with first bit of */ + i++; /* next byte in input buffer */ + if (i < len) /* input buffer done ? */ + introducer = 3; /* no, write introducer 110 */ + else { /* input buffer done ! */ + m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */ break; } - } else /* nicht das letzte datenbit */ - dbit <<= 1; /* dann gehe zum nächsten datenbit */ - mbit >>= 1; /* und setz bit der matrix weiter */ + } else /* not the last data bit */ + dbit <<= 1; /* then go to next data bit */ + mbit >>= 1; /* go to next bit of matrix */ goto next_bit; } - /* evtl. noch restliche zeilen in der matrix generieren... */ + /* if necessary, generate remaining lines of the matrix... */ if ((line) && ((line + 10) < mlen)) switch (++line % 10) { case 1: @@ -429,7 +428,7 @@ case 9: m[line++] = 0xfe; } - return line; /* soviele matrixzeilen sind es */ + return line; /* that's how many lines we have */ } /* @@ -517,7 +516,7 @@ return nskb; } mlen = EncodeMatrix(skb->data, rlen, v110buf, size); - /* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */ + /* now distribute 2 or 4 bits each to the output stream! */ rbuf = skb_put(nskb, size); olen = 0; sval1 = 8 - v->nbits; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/isdn/isdn_v110.h linux/drivers/isdn/isdn_v110.h --- v2.3.99-pre2/linux/drivers/isdn/isdn_v110.h Thu Nov 11 20:11:39 1999 +++ linux/drivers/isdn/isdn_v110.h Thu Mar 23 08:38:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_v110.h,v 1.2 1999/10/30 09:49:28 keil Exp $ +/* $Id: isdn_v110.h,v 1.3 2000/03/16 16:34:12 kai Exp $ * Linux ISDN subsystem, V.110 related functions (linklevel). * @@ -19,6 +19,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_v110.h,v $ + * Revision 1.3 2000/03/16 16:34:12 kai + * some translation work + * + * there shouldn't be any German comments lurking around anymore ;-) + * * Revision 1.2 1999/10/30 09:49:28 keil * Reinit of v110 structs * @@ -29,17 +34,14 @@ #ifndef _isdn_v110_h_ #define _isdn_v110_h_ -/* isdn_v110_encode erhält len Nettodaten in buf, kodiert diese und liefert - das Ergebnis wieder in buf. Wieviele Bytes kodiert wurden wird als - return zurück gegeben. Diese Daten können dann 1:1 auf die Leitung - gegeben werden. -*/ +/* + * isdn_v110_encode will take raw data and encode it using V.110 + */ extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *); -/* isdn_v110_decode erhält vom input stream V110 kodierte Daten, die zu den - V110 frames zusammengepackt werden müssen. Die Daten können an diese - Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne - darauf achten zu müssen, das frames usw. eingehalten werden. +/* + * isdn_v110_decode receives V.110 coded data from the stream and rebuilds + * frames from them. The source stream doesn't need to be framed. */ extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.3.99-pre2/linux/drivers/net/3c509.c Fri Mar 10 16:40:42 2000 +++ linux/drivers/net/3c509.c Tue Mar 21 14:43:39 2000 @@ -310,9 +310,11 @@ with "nopnp=1" before, does not harm if not. */ idev->deactivate(idev); idev->activate(idev); - if (!idev->resource[0].start || check_region(idev->resource[0].start,16)) + if (!idev->resource[0].start || check_region(idev->resource[0].start, EL3_IO_EXTENT)) continue; ioaddr = idev->resource[0].start; + if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509 PnP")) + return -EBUSY; irq = idev->irq_resource[0].start; if (el3_debug > 3) printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n", diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.3.99-pre2/linux/drivers/net/3c515.c Tue Mar 7 14:32:25 2000 +++ linux/drivers/net/3c515.c Tue Mar 21 14:43:39 2000 @@ -490,7 +490,7 @@ if (inw(ioaddr + Wn0EepromData) != 0x6d50) continue; } - printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n", + printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr; @@ -533,7 +533,7 @@ if (inw(ioaddr + Wn0EepromData) != 0x6d50) continue; } - printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n", + printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); irq = inw(ioaddr + 0x2002) & 15; corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.3.99-pre2/linux/drivers/net/3c59x.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/3c59x.c Tue Mar 21 11:18:37 2000 @@ -21,8 +21,6 @@ */ -static char *version = -"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -84,6 +82,9 @@ #define PCI_SUPPORT_VER2 #define DEV_FREE_SKB(skb) dev_kfree_skb(skb); + +static char *version __initdata = +"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.3.99-pre2/linux/drivers/net/8139too.c Sat Feb 26 22:31:46 2000 +++ linux/drivers/net/8139too.c Mon Mar 20 07:53:51 2000 @@ -1838,7 +1838,7 @@ void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; - unsigned long flags; + unsigned long flags=0; DPRINTK ("ENTER\n"); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.3.99-pre2/linux/drivers/net/8390.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/8390.c Tue Mar 21 11:03:00 2000 @@ -114,8 +114,8 @@ static void set_multicast_list(struct net_device *dev); static void do_set_multicast_list(struct net_device *dev); -/* - * SMP and the 8390 setup. +/** + * DOC: SMP and the 8390 setup. * * The 8390 isnt exactly designed to be multithreaded on RX/TX. There is * a page register that controls bank and packet buffer access. We guard @@ -142,10 +142,14 @@ -/* Open/initialize the board. This routine goes all-out, setting everything - up anew at each open, even though many of these registers should only - need to be set once at boot. - */ +/** + * ei_open - Open/initialize the board. + * @dev: network device to initialize + * + * This routine goes all-out, setting everything + * up anew at each open, even though many of these registers should only + * need to be set once at boot. + */ int ei_open(struct net_device *dev) { unsigned long flags; @@ -173,7 +177,12 @@ return 0; } -/* Opposite of above. Only used when "ifconfig down" is done. */ +/** + * ei_close - shut down network device + * @dev: network device to close + * + * Opposite of ei_open. Only used when "ifconfig down" is done. + */ int ei_close(struct net_device *dev) { struct ei_device *ei_local = (struct ei_device *) dev->priv; @@ -190,6 +199,14 @@ return 0; } +/** + * ei_start_xmit - begin packet transmission + * @skb: packet to be sent + * @dev: network device to which packet is sent + * + * Sends a packet to an 8390 network device. + */ + static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; @@ -389,8 +406,15 @@ return 0; } -/* The typical workload of the driver: - Handle the ether interface interrupts. */ +/** + * ei_interrupt - + * @irq: + * @dev_id: + * @regs: + * + * The typical workload of the driver: + * Handle the ether interface interrupts. + */ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) { @@ -492,7 +516,10 @@ return; } -/* +/** + * ei_tx_err - handle transmitter error + * @dev: network device which threw the exception + * * A transmitter error has happened. Most likely excess collisions (which * is a fairly normal condition). If the error is one where the Tx will * have been aborted, we try and send another one right away, instead of @@ -538,8 +565,13 @@ } } -/* We have finished a transmit: check for errors and then trigger the next - packet to be sent. Called with lock held */ +/** + * ei_tx_intr - transmit interrupt handler + * @dev: network device for which tx intr is handled + * + * We have finished a transmit: check for errors and then trigger the next + * packet to be sent. Called with lock held + */ static void ei_tx_intr(struct net_device *dev) { @@ -625,8 +657,13 @@ netif_wake_queue(dev); } -/* We have a good packet(s), get it/them out of the buffers. - Called with lock held */ +/** + * ei_receive - receive some packets + * @dev: network device with which receive will be run + * + * We have a good packet(s), get it/them out of the buffers. + * Called with lock held + */ static void ei_receive(struct net_device *dev) { @@ -751,7 +788,10 @@ return; } -/* +/** + * ei_rx_overrun - handle receiver overrun + * @dev: network device which threw exception + * * We have a receiver overrun: we have to kick the 8390 to get it started * again. Problem is that you have to kick it exactly as NS prescribes in * the updated datasheets, or "the NIC may act in an unpredictable manner." @@ -900,7 +940,10 @@ } } -/* +/** + * do_set_multicast_list - set/clear multicast filter + * @dev: net device for which multicast filter is adjusted + * * Set or clear the multicast filter for this adaptor. May be called * from a BH in 2.1.x. Must be called with lock held. */ @@ -970,7 +1013,10 @@ spin_unlock_irqrestore(&ei_local->page_lock, flags); } -/* +/** + * ethdev_init - init rest of 8390 device struct + * @dev: network device structure to init + * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ @@ -1006,7 +1052,11 @@ /* This page of functions should be 8390 generic */ /* Follow National Semi's recommendations for initializing the "NIC". */ -/* +/** + * NS8390_init - initialize 8390 hardware + * @dev: network device to initialize + * @startp: boolean. non-zero value to initiate chip processing + * * Must be called with lock held. */ @@ -1066,7 +1116,6 @@ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ do_set_multicast_list(dev); /* (re)load the mcast table */ } - return; } /* Trigger a transmit start, assuming the length is valid. diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.99-pre2/linux/drivers/net/Config.in Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/Config.in Tue Mar 21 14:43:39 2000 @@ -124,9 +124,7 @@ bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI if [ "$CONFIG_NET_PCI" = "y" ]; then tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE - fi + dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -134,12 +132,12 @@ tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT tristate ' CS89x0 support' CONFIG_CS89x0 tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 - tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP + dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 fi - tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 + dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM @@ -147,7 +145,7 @@ tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi - tristate ' PCI NE2000 support' CONFIG_NE2K_PCI + dep_tristate ' PCI NE2000 support' CONFIG_NE2K_PCI $CONFIG_PCI # tristate ' Sundance Alta support' CONFIG_ALTA if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129 @@ -166,7 +164,9 @@ fi bool ' Pocket and portable adapters' CONFIG_NET_POCKET if [ "$CONFIG_NET_POCKET" = "y" ]; then - tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP + if [ "$CONFIG_X86" = "y" ]; then + tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP + fi tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600 tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620 fi diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.3.99-pre2/linux/drivers/net/defxx.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/defxx.c Wed Mar 22 22:23:55 2000 @@ -3495,6 +3495,6 @@ /* * Local variables: - * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 -c defxx.c" + * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c" * End: */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.3.99-pre2/linux/drivers/net/epic100.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/epic100.c Mon Mar 20 07:53:51 2000 @@ -1099,6 +1099,12 @@ struct net_device *dev; long ioaddr; static int card_idx = -1; + static int printed_version = 0; + + if (!printed_version) { + printk (KERN_INFO "%s", version); + printed_version = 1; + } chip_idx = ent->driver_data; @@ -1280,13 +1286,7 @@ static int __init epic100_init (void) { - printk (KERN_INFO "%s", version); - - if (pci_register_driver (&epic100_driver) > 0) - return 0; - - pci_unregister_driver (&epic100_driver); - return -ENODEV; + return pci_module_init (&epic100_driver); } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c --- v2.3.99-pre2/linux/drivers/net/irda/irport.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/irda/irport.c Tue Mar 21 11:17:28 2000 @@ -941,10 +941,14 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_task_execute(self, __irport_change_speed, NULL, NULL, (void *) irq->ifr_baudrate); break; case SIOCSDONGLE: /* Set dongle */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* Initialize dongle */ dongle = irda_device_dongle_init(dev, irq->ifr_dongle); if (!dongle) @@ -965,12 +969,16 @@ NULL); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = irport_is_receiving(self); break; case SIOCSDTRRTS: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); break; default: diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c --- v2.3.99-pre2/linux/drivers/net/irda/irtty.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/irda/irtty.c Tue Mar 21 11:17:28 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Fri Jan 14 21:02:27 2000 + * Modified at: Sat Mar 11 07:43:30 2000 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, @@ -962,10 +962,14 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_task_execute(self, irtty_change_speed, NULL, NULL, (void *) irq->ifr_baudrate); break; case SIOCSDONGLE: /* Set dongle */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* Initialize dongle */ dongle = irda_device_dongle_init(dev, irq->ifr_dongle); if (!dongle) @@ -986,15 +990,21 @@ NULL); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = irtty_is_receiving(self); break; case SIOCSDTRRTS: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); break; case SIOCSMODE: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irtty_set_mode(dev, irq->ifr_mode); break; default: diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c --- v2.3.99-pre2/linux/drivers/net/irda/nsc-ircc.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/irda/nsc-ircc.c Tue Mar 21 11:17:28 2000 @@ -1947,9 +1947,13 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; nsc_ircc_change_speed(self, irq->ifr_baudrate); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.3.99-pre2/linux/drivers/net/irda/toshoboe.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/irda/toshoboe.c Tue Mar 21 11:17:28 2000 @@ -603,11 +603,15 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* toshoboe_setbaud(self, irq->ifr_baudrate); */ /* Just change speed once - inserted by Paul Bristow */ self->new_speed = irq->ifr_baudrate; break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c --- v2.3.99-pre2/linux/drivers/net/irda/w83977af_ir.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/irda/w83977af_ir.c Tue Mar 21 11:17:28 2000 @@ -1332,9 +1332,13 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; w83977af_change_speed(self, irq->ifr_baudrate); break; case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.3.99-pre2/linux/drivers/net/ne2k-pci.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/ne2k-pci.c Tue Mar 21 11:02:09 2000 @@ -71,28 +71,55 @@ STOP_PG_0x60=0x100, }; -/* This will eventually be converted to the standard PCI probe table. */ + +enum ne2k_pci_chipsets { + CH_RealTek_RTL_8029 = 0, + CH_Winbond_89C940, + CH_Compex_RL2000, + CH_KTI_ET32P2, + CH_NetVin_NV5000SC, + CH_Via_86C926, + CH_SureCom_NE34, + CH_Winbond_W89C940F, + CH_Holtek_HT80232, + CH_Holtek_HT80229, +}; + static struct { - unsigned short vendor, dev_id; char *name; int flags; -} -pci_clone_list[] __initdata = { - {0x10ec, 0x8029, "RealTek RTL-8029", 0}, - {0x1050, 0x0940, "Winbond 89C940", 0}, - {0x11f6, 0x1401, "Compex RL2000", 0}, - {0x8e2e, 0x3000, "KTI ET32P2", 0}, - {0x4a14, 0x5000, "NetVin NV5000SC", 0}, - {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO}, - {0x10bd, 0x0e34, "SureCom NE34", 0}, - {0x1050, 0x5a5a, "Winbond W89C940F", 0}, - {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, - {0x12c3, 0x5598, "Holtek HT80229", - ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, +} pci_clone_list[] __devinitdata = { + {"RealTek RTL-8029", 0}, + {"Winbond 89C940", 0}, + {"Compex RL2000", 0}, + {"KTI ET32P2", 0}, + {"NetVin NV5000SC", 0}, + {"Via 86C926", ONLY_16BIT_IO}, + {"SureCom NE34", 0}, + {"Winbond W89C940F", 0}, + {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, + {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, {0,} }; + +static struct pci_device_id ne2k_pci_tbl[] __devinitdata = { + { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 }, + { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 }, + { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 }, + { 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 }, + { 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC }, + { 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 }, + { 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 }, + { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F }, + { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 }, + { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl); + + /* ---- No user-serviceable parts below ---- */ #define NE_BASE (dev->base_addr) @@ -104,8 +131,6 @@ #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -static int ne2k_pci_probe(void); -static struct net_device *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx); static int ne2k_pci_open(struct net_device *dev); static int ne2k_pci_close(struct net_device *dev); @@ -122,47 +147,11 @@ /* No room in the standard 8390 structure for extra info we need. */ struct ne2k_pci_card { - struct ne2k_pci_card *next; struct net_device *dev; struct pci_dev *pci_dev; }; -/* A list of all installed devices, for removing the driver module. */ -static struct ne2k_pci_card *ne2k_card_list = NULL; -static int __init ne2k_pci_init_module(void) -{ - /* We must emit version information. */ - if (debug) - printk(KERN_INFO "%s", version); - if (ne2k_pci_probe()) { - printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n"); - return -ENODEV; - } - lock_8390_module(); - return 0; -} - -static void __exit ne2k_pci_cleanup_module(void) -{ - struct net_device *dev; - struct ne2k_pci_card *this_card; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (ne2k_card_list) { - dev = ne2k_card_list->dev; - unregister_netdev(dev); - release_region(dev->base_addr, NE_IO_EXTENT); - kfree(dev); - this_card = ne2k_card_list; - ne2k_card_list = ne2k_card_list->next; - kfree(this_card); - } - unlock_8390_module(); -} - -module_init(ne2k_pci_init_module); -module_exit(ne2k_pci_cleanup_module); /* NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet @@ -177,96 +166,42 @@ in the 'dev' and 'ei_status' structures. */ -#ifdef HAVE_DEVLIST -struct netdev_entry netcard_drv = -{"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0}; -#endif -static int __init ne2k_pci_probe(void) +static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { - struct pci_dev *pdev = NULL; - int cards_found = 0; - int i; struct net_device *dev; + int i, irq, reg0, start_page, stop_page; + unsigned char SA_prom[32]; + int chip_idx = ent->driver_data; + static unsigned version_printed = 0; + long ioaddr; + + if (version_printed++ == 0) + printk(KERN_INFO "%s", version); - if ( ! pci_present()) + ioaddr = pci_resource_start (pdev, 0); + irq = pdev->irq; + + if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) { + printk (KERN_ERR "ne2k-pci: no I/O resource at PCI BAR #0\n"); return -ENODEV; - - while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)) != NULL) { - int pci_irq_line; - u16 pci_command, new_command; - unsigned long pci_ioaddr; - - /* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */ - for (i = 0; pci_clone_list[i].vendor != 0; i++) - if (pci_clone_list[i].vendor == pdev->vendor - && pci_clone_list[i].dev_id == pdev->device) - break; - if (pci_clone_list[i].vendor == 0) - continue; - - pci_ioaddr = pdev->resource[0].start; - pci_irq_line = pdev->irq; - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - - /* Avoid already found cards from previous calls */ - if (check_region(pci_ioaddr, NE_IO_EXTENT)) - continue; - - { - static unsigned version_printed = 0; - if (version_printed++ == 0) - printk(KERN_INFO "%s", version); - } - - /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - new_command = pci_command | PCI_COMMAND_IO; - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled this" - " NE2k clone! Updating PCI command %4.4x->%4.4x.\n", - pci_command, new_command); - pci_write_config_word(pdev, PCI_COMMAND, new_command); - } -#ifndef __sparc__ - if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS) - printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k" - " card to IRQ %d, which is unlikely to work!.\n" - KERN_WARNING " You should use the PCI BIOS setup to assign" - " a valid IRQ line.\n", pci_irq_line); -#endif - printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#lx, IRQ %d.\n", - pci_clone_list[i].name, pci_ioaddr, pci_irq_line); - dev = ne2k_pci_probe1(pci_ioaddr, pci_irq_line, i); - if (dev == 0) { - /* Should not happen. */ - printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#lx failed.\n", - pci_ioaddr); - continue; - } else { - struct ne2k_pci_card *ne2k_card = - kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL); - ne2k_card->next = ne2k_card_list; - ne2k_card_list = ne2k_card; - ne2k_card->dev = dev; - ne2k_card->pci_dev = pdev; - } - - cards_found++; } - - return cards_found ? 0 : -ENODEV; -} - -static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx) -{ - struct net_device *dev; - int i; - unsigned char SA_prom[32]; - int start_page, stop_page; - int reg0 = inb(ioaddr); - + + if (pci_enable_device (pdev)) { + printk (KERN_ERR "ne2k-pci: cannot enable device\n"); + return -EIO; + } + + if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) { + printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n", + NE_IO_EXTENT, ioaddr); + return -EBUSY; + } + + reg0 = inb(ioaddr); if (reg0 == 0xFF) - return 0; + goto err_out_free_res; /* Do a preliminary verification that we have a 8390. */ { @@ -279,12 +214,16 @@ if (inb(ioaddr + EN0_COUNTER0) != 0) { outb(reg0, ioaddr); outb(regd, ioaddr + 0x0d); /* Restore the old values. */ - return 0; + goto err_out_free_res; } } dev = init_etherdev(NULL, 0); - + if (!dev) { + printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n"); + goto err_out_free_res; + } + /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; @@ -298,14 +237,15 @@ /* Limit wait: '2' avoids jiffy roll-over. */ if (jiffies - reset_start_time > 2) { printk("ne2k-pci: Card failure (no reset ack).\n"); - return 0; + goto err_out_free_netdev; } outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ } if (load_8390_module("ne2k-pci.c")) { - return 0; + printk (KERN_ERR "ne2k-pci: cannot load 8390 module\n"); + goto err_out_free_netdev; } /* Read the 16 bytes of station address PROM. @@ -355,12 +295,10 @@ /* 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); - return 0; + printk (KERN_ERR "%s: unable to get memory for dev->priv.\n", dev->name); + goto err_out_free_netdev; } - request_region(ioaddr, NE_IO_EXTENT, dev->name); - printk("%s: %s found at %#lx, IRQ %d, ", dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); for(i = 0; i < 6; i++) { @@ -387,16 +325,26 @@ dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; NS8390_init(dev, 0); - return dev; + return 0; + +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); +err_out_free_res: + release_region (ioaddr, NE_IO_EXTENT); + return -ENODEV; + } static int ne2k_pci_open(struct net_device *dev) { - if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) + MOD_INC_USE_COUNT; + if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; return -EAGAIN; + } ei_open(dev); - MOD_INC_USE_COUNT; return 0; } @@ -588,6 +536,58 @@ ei_status.dmaing &= ~0x01; return; } + + +static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (!dev) { + printk (KERN_ERR "bug! ne2k_pci_remove_one called w/o net_device\n"); + return; + } + + unregister_netdev (dev); + release_region (dev->base_addr, NE_IO_EXTENT); + kfree (dev); +} + + +static struct pci_driver ne2k_driver = { + name: "ne2k-pci", + probe: ne2k_pci_init_one, + remove: ne2k_pci_remove_one, + id_table: ne2k_pci_tbl, +}; + + +static int __init ne2k_pci_init(void) +{ + int rc; + + MOD_INC_USE_COUNT; + lock_8390_module(); + + rc = pci_module_init (&ne2k_driver); + + /* XXX should this test CONFIG_HOTPLUG like pci_module_init? */ + if (rc <= 0) + unlock_8390_module(); + + MOD_DEC_USE_COUNT; + + return rc; +} + + +static void __exit ne2k_pci_cleanup(void) +{ + pci_unregister_driver (&ne2k_driver); + unlock_8390_module(); +} + +module_init(ne2k_pci_init); +module_exit(ne2k_pci_cleanup); /* diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.3.99-pre2/linux/drivers/net/net_init.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/net_init.c Mon Mar 20 08:01:14 2000 @@ -1,4 +1,4 @@ -/* netdrv_init.c: Initialization for network devices. */ +/* net_init.c: Initialization for network devices. */ /* Written 1993,1994,1995 by Donald Becker. @@ -27,6 +27,8 @@ 08/11/99 - Alan Cox: Got fed up of the mess in this file and cleaned it up. We now share common code and have regularised name allocation setups. Abolished the 16 card limits. + 03/19/2000 - jgarzik and Urban Widmark: init_etherdev 32-byte align + */ #include @@ -139,14 +141,22 @@ return dev; } -/* Fill in the fields of the device structure with ethernet-generic values. - - If no device structure is passed, a new one is constructed, complete with - a SIZEOF_PRIVATE private data area. - - If an empty string area is passed as dev->name, or a new structure is made, - a new name string is constructed. The passed string area should be 8 bytes - long. +/** + * init_etherdev - Register ethernet device + * @dev: An ethernet device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with ethernet-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. The passed string area should be 8 bytes + * long. */ struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/pcmcia/3c575_cb.c linux/drivers/net/pcmcia/3c575_cb.c --- v2.3.99-pre2/linux/drivers/net/pcmcia/3c575_cb.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/pcmcia/3c575_cb.c Mon Mar 20 07:53:51 2000 @@ -12,10 +12,16 @@ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Linux Kernel Additions: + + LK1.1.2 (March 19, 2000) + * New PCI interface (jgarzik) + */ static char *version = -"3c59x.c:v0.99L 5/28/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; +"3c575_cb.c:v0.99L+LK1.1.2 3/19/2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -64,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -85,9 +92,6 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(compaq_ioaddr, "i"); -MODULE_PARM(compaq_irq, "i"); -MODULE_PARM(compaq_device_id, "i"); /* Operational parameter that usually are not changed. */ @@ -103,6 +107,10 @@ code size of a per-interface flag is not worthwhile. */ static char mii_preamble_required = 0; +#define PFX "3c575_cb: " + + + /* Theory of Operation @@ -186,76 +194,134 @@ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int drv_flags, io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, struct net_device *dev, - long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; -static struct net_device *vortex_probe1(struct pci_dev *pdev, - struct net_device *dev, long ioaddr, - int irq, int dev_id, int card_idx); -static struct pci_id_info pci_tbl[] = { - {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, - {"3Com Vortex", 0x10B7, 0x5900, 0xff00, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, - {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, - {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, - {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c905C Tornado", 0x10B7, 0x9200, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, - {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3CCFE575CT Cyclone CardBus", 0x10B7, 0x5257, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3CCFEM656 Cyclone CardBus", 0x10B7, 0x6562, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, - 128, vortex_probe1}, - {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, - {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00, - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, + + +enum vortex_chips { + CH_3C590 = 0, + CH_3C595_1, + CH_3C595_2, + CH_3C595_3, + CH_VORTEX, + CH_3C900_1, + CH_3C900_2, + CH_3C900_3, + CH_3C900B_FL, + CH_3C905_1, + CH_3C905_2, + CH_3C905B_1, + CH_3C905B_2, + CH_3C905B_FX, + CH_3C905C, + CH_3C980, + CH_3CSOHO100_TX, + CH_3C555, + CH_3C575_1, + CH_3CCFE575, + CH_3CCFE575CT, + CH_3CCFE656, + CH_3CCFEM656, + CH_3C575_2, + CH_BOOMERANG, +}; + + +/* note: this array directly indexed by above enums, and MUST + * be kept in sync with both the enums above, and the PCI device + * table below + */ +static struct vortex_chip_info { + const char *name; + int flags; + int drv_flags; + int io_size; +} vortex_info_tbl[] = { + {"3c590 Vortex 10Mbps", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100baseTx", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100baseT4", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3c595 Vortex 100base-MII", + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, + {"3Com Vortex", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Boomerang 10baseT", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Boomerang 10Mbps Combo", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {"3c900 Cyclone 10Mbps Combo", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c900B-FL Cyclone 10base-FL", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c905 Boomerang 100baseTx", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + {"3c905 Boomerang 100baseT4", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + {"3c905B Cyclone 100baseTx", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3c905B Cyclone 10/100/BNC", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + {"3c905B-FX Cyclone 100baseFx", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c905C Tornado", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c980 Cyclone", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3cSOHO100-TX Hurricane", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c555 Laptop Hurricane", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c575 Boomerang CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + {"3CCFE575 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3CCFE575CT Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3CCFE656 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3CCFEM656 Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, }, + {"3c575 series CardBus (unknown version)", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + {"3Com Boomerang (unknown version)", + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + {0,}, /* 0 terminated list. */ +}; + + +static struct pci_device_id vortex_pci_tbl[] __devinit = { + { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 }, + { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 }, + { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 }, + { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 }, + { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX }, + { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 }, + { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 }, + { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 }, + { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL }, + { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 }, + { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 }, + { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 }, + { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 }, + { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX }, + { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C }, + { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 }, + { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, + { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, + { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, + { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, + { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, + { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, + { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, + { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_2 }, + { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_BOOMERANG }, {0,}, /* 0 terminated list. */ }; +MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); + /* Operational definitions. These are not used by other compilation units and thus are not @@ -400,7 +466,7 @@ /* The addresses of transmit- and receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct net_device *next_module; + struct net_device *next_module; /* NULL if PCI device */ void *priv_addr; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ @@ -463,9 +529,8 @@ { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifndef CARDBUS -static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[]); -#endif +static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, + int chip_idx, int card_idx); static void vortex_up(struct net_device *dev); static void vortex_down(struct net_device *dev); static int vortex_open(struct net_device *dev); @@ -484,7 +549,6 @@ static void set_rx_mode(struct net_device *dev); static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void vortex_tx_timeout(struct net_device *dev); -static void acpi_wake(struct pci_dev *pdev); static void acpi_set_WOL(struct net_device *dev); /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ @@ -492,280 +556,181 @@ #define MAX_UNITS 8 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -/* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_vortex_dev = NULL; -#ifdef MODULE -#ifndef CARDBUS -/* Variables to work-around the Compaq PCI BIOS32 problem. */ -static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900; -#endif -#ifdef CARDBUS +/* A list of all installed Vortex EISA devices, for removing the driver module. */ +static struct net_device *root_vortex_eisa_dev = NULL; -#include +static int vortex_cards_found = 0; -static void vortex_reap(void) -{ - struct net_device **devp, **next; - printk(KERN_DEBUG "vortex_reap()\n"); - for (devp = &root_vortex_dev; *devp; devp = next) { - struct vortex_private *vp = (*devp)->priv; - next = &vp->next_module; - if (vp->open || !vp->reap) continue; - unregister_netdev(*devp); - if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - kfree(*devp); - kfree(vp->priv_addr); - *devp = *next; next = devp; - } -} -static dev_node_t *vortex_attach(dev_locator_t *loc) -{ - u16 dev_id, vendor_id; - u32 io; - u8 irq; - struct net_device *dev; - int chip_idx; - struct pci_dev *pdev; - vortex_reap(); - if (loc->bus != LOC_PCI) return NULL; - pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); - if (!pdev) return NULL; - io = pci_resource_start (pdev, 0); - irq = pdev->irq; - vendor_id = pdev->vendor; - dev_id = pdev->device; - printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", - pdev->bus->number, pdev->devfn, dev_id); - if (io == 0 || irq == 0) { - printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " - "assigned an %s.\n" KERN_ERR " It will not be activated.\n", - io == 0 ? "I/O address" : "IRQ"); - return NULL; - } - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor_id == pci_tbl[chip_idx].vendor_id - && (dev_id & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */ - printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in " - "vortex_attach().\n", vendor_id, dev_id); - return NULL; - } - dev = vortex_probe1(pdev, NULL, io, irq, chip_idx, MAX_UNITS+1); - if (dev) { - dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - strcpy(node->dev_name, dev->name); - node->major = node->minor = 0; - node->next = NULL; - MOD_INC_USE_COUNT; - return node; - } - return NULL; -} - -static void vortex_detach(dev_node_t *node) -{ - struct net_device *dev, *next; - printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name); - for (dev = root_vortex_dev; dev; dev = next) { - next = ((struct vortex_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } - if (dev && dev->priv) { - struct vortex_private *vp = dev->priv; - if (vp->open) vortex_down(dev); - vp->reap = 1; - kfree(node); - MOD_DEC_USE_COUNT; - } -} -static void vortex_suspend(dev_node_t *node) +static void vortex_suspend (struct pci_dev *pdev) { - struct net_device *dev, *next; - printk(KERN_DEBUG "vortex_suspend(%s)\n", node->dev_name); - for (dev = root_vortex_dev; dev; dev = next) { - next = ((struct vortex_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } + struct net_device *dev = pdev->driver_data; + + printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name); + if (dev && dev->priv) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - if (vp->open) vortex_down(dev); + if (vp->open) { + netif_device_detach(dev); + vortex_down(dev); + } } } -static void vortex_resume(dev_node_t *node) + +static void vortex_resume (struct pci_dev *pdev) { - struct net_device *dev, *next; - printk(KERN_DEBUG "vortex_resume(%s)\n", node->dev_name); - for (dev = root_vortex_dev; dev; dev = next) { - next = ((struct vortex_private *)dev->priv)->next_module; - if (strcmp(dev->name, node->dev_name) == 0) break; - } + struct net_device *dev = pdev->driver_data; + + printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name); + if (dev && dev->priv) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - if (vp->open) vortex_up(dev); + if (vp->open) { + vortex_up(dev); + netif_device_attach(dev); + } } } -struct driver_operations vortex_ops = { - "3c575_cb", vortex_attach, vortex_suspend, vortex_resume, vortex_detach -}; - -#endif /* Cardbus support */ -int init_module(void) -{ - if (vortex_debug) - printk(KERN_INFO "%s", version); -#ifdef CARDBUS - register_driver(&vortex_ops); - return 0; -#else - return vortex_scan(0, pci_tbl); -#endif -} - -#else -int tc59x_probe(struct net_device *dev) +/* returns count found (>= 0), or negative on error */ +static int __init vortex_eisa_init (void) { - static int did_version = -1; - if (++did_version <= 0) - printk(KERN_INFO "%s", version); - return vortex_scan(dev, pci_tbl); -} -#endif /* not MODULE */ - -#ifndef CARDBUS -static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[]) -{ - int cards_found = 0; - - /* Allow an EISA-only driver. */ - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->base_address[0] & ~3; - irq = pdev->irq; - } + long ioaddr; + int rc; + int orig_cards_found = vortex_cards_found; - if (ioaddr == 0) { - printk(KERN_WARNING " A 3Com network adapter has been found, " - "however it has not been assigned an I/O address.\n" - " You may need to power-cycle the machine for this " - "device to work!\n"); - continue; - } + /* Now check all slots of the EISA bus. */ + if (!EISA_bus) + return 0; - /* Activate the card. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the device " - "at %d/%d. Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + int device_id; - dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq, - chip_idx, cards_found); + if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL) + continue; - if (dev) { - /* Get and check the latency values. On the 3c590 series - the latency timer must be set to the maximum value to avoid - data corruption that occurs when the timer expires during - a transfer -- a bug in the Vortex chip only. */ - u8 pci_latency; - u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32; - - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", - dev->name, pci_latency, new_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, new_latency); - } - dev = 0; - cards_found++; - } + /* Check the standard EISA ID register for an encoded '3Com'. */ + if (inw(ioaddr + 0xC80) != 0x6d50) { + release_region (ioaddr, VORTEX_TOTAL_SIZE); + continue; } - } - /* Now check all slots of the EISA bus. */ - if (EISA_bus) { - static long ioaddr = 0x1000; - for ( ; ioaddr < 0x9000; ioaddr += 0x1000) { - int device_id; - if (check_region(ioaddr, VORTEX_TOTAL_SIZE)) - continue; - /* Check the standard EISA ID register for an encoded '3Com'. */ - if (inw(ioaddr + 0xC80) != 0x6d50) - continue; - /* Check for a product that we support, 3c59{2,7} any rev. */ - device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); - if ((device_id & 0xFF00) != 0x5900) - continue; - vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12, - 4, cards_found); - dev = 0; - cards_found++; + /* Check for a product that we support, 3c59{2,7} any rev. */ + device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); + if ((device_id & 0xFF00) != 0x5900) { + release_region (ioaddr, VORTEX_TOTAL_SIZE); + continue; } - } -#ifdef MODULE - /* Special code to work-around the Compaq PCI BIOS32 problem. */ - if (compaq_ioaddr) { - vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq, - compaq_device_id, cards_found++); - dev = 0; + rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, + 4, /* XXX is 4 correct eisa idx? */ + vortex_cards_found); + if (rc == 0) + vortex_cards_found++; + else + release_region (ioaddr, VORTEX_TOTAL_SIZE); } -#endif - return cards_found ? 0 : -ENODEV; + return vortex_cards_found - orig_cards_found; } -#endif /* ! Cardbus */ -static struct net_device *vortex_probe1(struct pci_dev *pdev, - struct net_device *dev, long ioaddr, - int irq, int chip_idx, int card_idx) + +/* returns count (>= 0), or negative on error */ +static int __devinit vortex_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rc; + + rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq, + ent->driver_data, vortex_cards_found); + if (rc == 0) + vortex_cards_found++; + + return rc; +} + + +/* NOTE: pdev can be NULL, for the case of an EISA driver */ +static int __devinit vortex_probe1(struct pci_dev *pdev, + long ioaddr, int irq, + int chip_idx, int card_idx) { struct vortex_private *vp; int option; unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; + struct net_device *dev; + static int printed_version = 0; + + if (!printed_version) { + printk (KERN_INFO "%s", version); + printed_version = 1; + } - dev = init_etherdev(dev, 0); - - printk(KERN_INFO "%s: 3Com %s at 0x%lx, ", - dev->name, pci_tbl[chip_idx].name, ioaddr); - + dev = init_etherdev(NULL, sizeof(*vp)); + if (!dev) { + printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); + return -ENOMEM; + } + + printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ", + dev->name, + pdev ? "PCI" : "EISA", + vortex_info_tbl[chip_idx].name, + ioaddr); + + /* private struct aligned and zeroed by init_etherdev */ + vp = dev->priv; + vp->priv_addr = vp; dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; - /* Make certain the descriptor lists are aligned. */ - { - void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL); - vp = (void *)(((long)mem + 15) & ~15); - memset(vp, 0, sizeof(*vp)); - vp->priv_addr = mem; + /* module list only for EISA devices */ + if (pdev == NULL) { + vp->next_module = root_vortex_eisa_dev; + root_vortex_eisa_dev = dev; + } + + /* PCI-only startup logic */ + if (pdev) { + /* EISA resources already marked, so only PCI needs to do this here */ + if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size, + dev->name)) { + printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", + dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr); + kfree (dev); + return -EBUSY; + } + + /* wake up and enable device */ + if (pci_enable_device (pdev)) { + printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name); + release_region (ioaddr, vortex_info_tbl[chip_idx].io_size); + kfree (dev); + return -EIO; + } + + /* enable bus-mastering if necessary */ + if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER) + pci_set_master (pdev); } - dev->priv = vp; - - vp->next_module = root_vortex_dev; - root_vortex_dev = dev; vp->lock = SPIN_LOCK_UNLOCKED; vp->chip_id = chip_idx; vp->pdev = pdev; + /* if we are a PCI driver, we store info in pdev->driver_data + * instead of a module list */ + if (pdev) + pdev->driver_data = dev; + /* The lower four bits are the media type. */ if (dev->mem_start) option = dev->mem_start; @@ -793,7 +758,7 @@ EL3WINDOW(0); for (i = 0; i < 0x40; i++) { int timer; -#ifdef CARDBUS +#if 1 /* ifdef CARDBUS */ outw(0x230 + i, ioaddr + Wn0EepromCmd); #else outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); @@ -835,7 +800,7 @@ dev->irq); #endif - if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { + if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) @@ -922,9 +887,6 @@ vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; } - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); - /* The 3c59x-specific entries in the device structure. */ dev->open = &vortex_open; dev->hard_start_xmit = &vortex_start_xmit; @@ -932,10 +894,10 @@ dev->get_stats = &vortex_get_stats; dev->do_ioctl = &vortex_ioctl; dev->set_multicast_list = &set_rx_mode; - dev->tx_timeout = vortex_tx_timeout; + dev->tx_timeout = &vortex_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - return dev; + return 0; } static void wait_for_completion(struct net_device *dev, int cmd) @@ -956,11 +918,13 @@ long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; union wn3_config config; - int i; - - /* Should be if(HAS_ACPI) */ - acpi_wake(vp->pdev); + int i, device_id; + if (vp->pdev) + device_id = vp->pdev->device; + else + device_id = 0x5900; /* EISA */ + /* Before initializing select the active media port. */ EL3WINDOW(3); config.i = inl(ioaddr + Wn3_Config); @@ -972,7 +936,7 @@ media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { - if (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) + if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY) dev->if_port = XCVR_NWAY; else { /* Find first available media type, starting with 100baseTx. */ @@ -995,7 +959,7 @@ vp->full_duplex = vp->force_fd; config.u.xcvr = dev->if_port; - if ( ! (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY)) + if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)) outl(config.i, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { @@ -1045,12 +1009,11 @@ if (vp->cb_fn_base) { u_short n = inw(ioaddr + Wn2_ResetOptions); /* Inverted LED polarity */ - if (pci_tbl[vp->chip_id].device_id != 0x5257) + if (device_id != 0x5257) n |= 0x0010; /* Inverted polarity of MII power bit */ - if ((pci_tbl[vp->chip_id].device_id == 0x6560) || - (pci_tbl[vp->chip_id].device_id == 0x6562) || - (pci_tbl[vp->chip_id].device_id == 0x5257)) + if ((device_id == 0x6560) || (device_id == 0x6562) || + (device_id == 0x5257)) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); } @@ -2088,66 +2051,107 @@ /* Change the power state to D3; RxEnable doesn't take effect. */ pci_write_config_word(vp->pdev, 0xe0, 0x8103); } -/* Change from D3 (sleep) to D0 (active). - Problem: The Cyclone forgets all PCI config info during the transition! */ -static void acpi_wake(struct pci_dev *pdev) -{ - u32 base0, base1, romaddr; - u16 pci_command, pwr_command; - u8 pci_latency, pci_cacheline, irq; - pci_read_config_word(pdev, 0xe0, &pwr_command); - if ((pwr_command & 3) == 0) + +static void __devexit vortex_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct vortex_private *vp; + + if (!dev) return; - pci_read_config_word( pdev, PCI_COMMAND, &pci_command); - pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base0); - pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &base1); - pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr); - pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency); - pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); - pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq); - - pci_write_config_word( pdev, 0xe0, 0x0000); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, base0); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base1); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr); - pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq); - pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency); - pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline); - pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5); + + vp = (void *)(dev->priv); + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + unregister_netdev(dev); + outw(TotalReset, dev->base_addr + EL3_CMD); + release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size); + kfree(dev); } -#ifdef MODULE -void cleanup_module(void) + +static struct pci_driver vortex_driver = { + name: "3c575_cb", + probe: vortex_init_one, + remove: vortex_remove_one, + suspend: vortex_suspend, + resume: vortex_resume, + id_table: vortex_pci_tbl, +}; + + +static int vortex_have_pci = 0; +static int vortex_have_eisa = 0; + + +static int __init vortex_init (void) { - struct net_device *next_dev; + int rc; + + MOD_INC_USE_COUNT; + + rc = pci_module_init (&vortex_driver); + if (rc < 0) + goto out; + if (rc > 0) + vortex_have_pci = 1; + + rc = vortex_eisa_init (); + if (rc < 0) + goto out; + if (rc > 0) + vortex_have_eisa = 1; -#ifdef CARDBUS - unregister_driver(&vortex_ops); - vortex_reap(); -#endif +out: + MOD_DEC_USE_COUNT; + return rc; +} - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_vortex_dev) { - struct vortex_private *vp=(void *)(root_vortex_dev->priv); - next_dev = vp->next_module; - unregister_netdev(root_vortex_dev); - outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); - release_region(root_vortex_dev->base_addr, - pci_tbl[vp->chip_id].io_size); - kfree(root_vortex_dev); - kfree(vp->priv_addr); - root_vortex_dev = next_dev; + +static void __exit vortex_eisa_cleanup (void) +{ + struct net_device *dev, *tmp; + struct vortex_private *vp; + long ioaddr; + + dev = root_vortex_eisa_dev; + + while (dev) { + vp = dev->priv; + ioaddr = dev->base_addr; + + unregister_netdev (dev); + outw (TotalReset, ioaddr + EL3_CMD); + release_region (ioaddr, VORTEX_TOTAL_SIZE); + + tmp = dev; + dev = vp->next_module; + + kfree (tmp); } } -#endif /* MODULE */ + +static void __exit vortex_cleanup (void) +{ + if (vortex_have_pci) + pci_unregister_driver (&vortex_driver); + if (vortex_have_eisa) + vortex_eisa_cleanup (); +} + + +module_init(vortex_init); +module_exit(vortex_cleanup); + + /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c" + * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.3.99-pre2/linux/drivers/net/pcmcia/Config.in Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/pcmcia/Config.in Tue Mar 21 12:39:17 2000 @@ -18,6 +18,7 @@ if [ "$CONFIG_CARDBUS" = "y" ]; then dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m + tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP fi bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile --- v2.3.99-pre2/linux/drivers/net/pcmcia/Makefile Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/pcmcia/Makefile Mon Mar 20 07:56:33 2000 @@ -19,8 +19,6 @@ # Things that need to export symbols export-objs := ray_cs.o -CFLAGS_3c575_cb.o = -DCARDBUS -DMODULE - # 16-bit client drivers obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o @@ -39,6 +37,7 @@ # Cardbus client drivers obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o +obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c --- v2.3.99-pre2/linux/drivers/net/pcmcia/xircom_tulip_cb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/xircom_tulip_cb.c Tue Mar 21 12:39:17 2000 @@ -0,0 +1,3153 @@ +/* tulip.c: A DEC 21040-family ethernet driver for Linux. */ +/* + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + This driver is for the Digital "Tulip" Ethernet adapter interface. + It should work with most DEC 21*4*-based chips/ethercards, as well as + with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Support and updates available at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html +*/ + +#define SMP_CHECK +#define CARDBUS 1 +static const char version[] = "xircom_tulip_cb.c:v0.91 4/14/99 becker@cesdis.gsfc.nasa.gov (modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford)\n"; + +/* A few user-configurable values. */ + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 25; + +#define MAX_UNITS 8 +/* Used to pass the full-duplex flag, etc. */ +static int full_duplex[MAX_UNITS] = {0, }; +static int options[MAX_UNITS] = {0, }; +static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ + +/* The possible media types that can be set in options[] are: */ +static const char * const medianame[] = { + "10baseT", "10base2", "AUI", "100baseTx", + "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", + "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", +}; + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 + +/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ +#ifdef __alpha__ +static int rx_copybreak = 1518; +#else +static int rx_copybreak = 100; +#endif + +/* + Set the bus performance register. + Typical: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 No alignment 0x00000000 unlimited 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Warning: many older 486 systems are broken and require setting 0x00A04800 + 8 longword cache alignment, 8 longword burst. + ToDo: Non-Intel setting could be better. +*/ + +#if defined(__alpha__) +static int csr0 = 0x01A00000 | 0xE000; +#elif defined(__powerpc__) +static int csr0 = 0x01B00000 | 0x8000; +#elif defined(__sparc__) +static int csr0 = 0x01B00080 | 0x8000; +#elif defined(__i386__) +static int csr0 = 0x01A00000 | 0x8000; +#else +#warning Processor architecture undefined! +static int csr0 = 0x00A00000 | 0x4800; +#endif + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +/* This is a mysterious value that can be written to CSR11 in the 21040 (only) + to support a pre-NWay full-duplex signaling mechanism using short frames. + No one knows what it should be, but if left at its default value some + 10base2(!) packets trigger a full-duplex-request interrupt. */ +#define FULL_DUPLEX_MAGIC 0x6969 + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. + This is only in the support-all-kernels source code. */ + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(reverse_probe, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(csr0, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#define RUN_AT(x) (jiffies + (x)) + +#define tulip_debug debug +#ifdef TULIP_DEBUG +static int tulip_debug = TULIP_DEBUG; +#else +static int tulip_debug = 1; +#endif + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the DECchip "Tulip", Digital's +single-chip ethernet controllers for PCI. Supported members of the family +are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike +chips from Lite-On, Macronics, ASIX, Compex and other listed below are also +supported. + +These chips are used on at least 140 unique PCI board designs. The great +number of chips and board designs supported is the reason for the +driver size and complexity. Almost of the increasing complexity is in the +board configuration and media selection code. There is very little +increasing in the operational critical path length. + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS preferably should assign the +PCI INTA signal to an otherwise unused system IRQ line. + +Some boards have EEPROMs tables with default media entry. The factory default +is usually "autoselect". This should only be overridden when using +transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) +for forcing full-duplex when used with old link partners that do not do +autonegotiation. + +III. Driver operation + +IIIa. Ring buffers + +The Tulip can use either ring buffers or lists of Tx and Rx descriptors. +This driver uses statically allocated rings of Rx and Tx descriptors, set at +compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs +for the Rx ring buffers at open() time and passes the skb->data field to the +Tulip as receive data buffers. When an incoming frame is less than +RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is +copied to the new skbuff. When the incoming frame is larger, the skbuff is +passed directly up the protocol stack and replaced by a newly allocated +skbuff. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. For small frames the copying cost is negligible (esp. considering +that we are pre-loading the cache with immediately useful header +information). For large frames the copying cost is non-trivial, and the +larger copy might flush the cache of useful data. A subtle aspect of this +choice is that the Tulip only receives into longword aligned buffers, thus +the IP header at offset 14 isn't longword aligned for further processing. +Copied frames are put into the new skbuff at an offset of "+2", thus copying +has the beneficial effect of aligning the IP header and preloading the +cache. + +IIIC. Synchronization +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'tp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so +we can't avoid the interrupt overhead by having the Tx routine reap the Tx +stats.) After reaping the stats, it marks the queue entry as empty by setting +the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the +tx_full and tbusy flags. + +IV. Notes + +Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. +Greg LaPolla at Linksys provided PNIC and other Linksys boards. +Znyx provided a four-port card for testing. + +IVb. References + +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") +http://www.national.com/pf/DP/DP83840A.html +http://www.asix.com.tw/pmac.htm +http://www.admtek.com.tw/ + +IVc. Errata + +The old DEC databooks were light on details. +The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last +register of the set CSR12-15 written. Hmmm, now how is that possible? + +The DEC SROM format is very badly designed not precisely defined, leading to +part of the media selection junkheap below. Some boards do not have EEPROM +media tables and need to be patched up. Worse, other boards use the DEC +design kit media table when it isn't correct for their board. + +We cannot use MII interrupts because there is no defined GPIO pin to attach +them. The MII transceiver status is polled using an kernel timer. + +*/ + +/* This table use during operation for capabilities and media timer. */ + +static void tulip_timer(unsigned long data); +static void t21142_timer(unsigned long data); +static void mxic_timer(unsigned long data); +static void pnic_timer(unsigned long data); +static void comet_timer(unsigned long data); + +enum tbl_flag { + HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, + HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ + HAS_NWAY143=0x40, /* Uses 21143-like internal NWay. */ +}; +static struct tulip_chip_table { + char *chip_name; + int io_size; + int valid_intrs; /* CSR7 interrupt enable settings */ + int flags; + void (*media_timer)(unsigned long data); +} tulip_tbl[] = { + { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, + { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer }, + { "Digital DS21140 Tulip", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + { "Digital DS21143 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, t21142_timer }, + { "Lite-On 82c168 PNIC", 256, 0x0001ebef, + HAS_MII, pnic_timer }, + { "Macronix 98713 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Macronix 98715 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "Macronix 98725 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "ASIX AX88140", 128, 0x0001fbff, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, + { "Lite-On PNIC-II", 256, 0x0001ebef, + HAS_MII | HAS_NWAY143, pnic_timer }, + { "ADMtek Comet", 256, 0x0001abef, + MC_HASH_ONLY, comet_timer }, + { "Compex 9881 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Xircom Cardbus Adapter (DEC 21143 compatible mode)", 128, 0x0801fbff, + HAS_MII | HAS_ACPI, tulip_timer }, + {0}, +}; +/* This matches the table above. Note 21142 == 21143. */ +enum chips { + DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, + LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881, + X3201_3, +}; + +/* A full-duplex map for media types. */ +enum MediaIs { + MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, + MediaIs100=16}; +static const char media_cap[] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; +static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; +/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ +static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; +static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + +static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; +static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + +/* Offsets to the Command and Status Registers, "CSRs". All accesses + must be longword instructions and quadword aligned. */ +enum tulip_offsets { + CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, + CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, + CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10, + NormalIntr=0x10000, AbnormalIntr=0x8000, + RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, + TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, +}; + +/* The Tulip Rx and Tx buffer descriptors. */ +struct tulip_rx_desc { + s32 status; + s32 length; + u32 buffer1, buffer2; +}; + +struct tulip_tx_desc { + s32 status; + s32 length; + u32 buffer1, buffer2; /* We use only buffer 1. */ +}; + +enum desc_status_bits { + DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, +}; + +/* Ring-wrap flag in length field, use for last ring entry. + 0x01000000 means chain on buffer2 address, + 0x02000000 means use the ring start address in CSR2/3. + Note: Some work-alike chips do not function correctly in chained mode. + The ASIX chip works only in chained mode. + Thus we indicates ring mode, but always write the 'next' field for + chained mode as well. +*/ +#define DESC_RING_WRAP 0x02000000 + +#ifdef CARDBUS +#define EEPROM_ADDRLEN (chip_rev == 65 ? 8 : 6) +#else +#define EEPROM_ADDRLEN 6 +#endif +#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ + +struct medialeaf { + u8 type; + u8 media; + unsigned char *leafdata; +}; + +struct mediatable { + u16 defaultmedia; + u8 leafcount, csr12dir; /* General purpose pin directions. */ + unsigned has_mii:1, has_nonmii:1, has_reset:6; + u32 csr15dir, csr15val; /* 21143 NWay setting. */ + struct medialeaf mleaf[0]; +}; + +struct mediainfo { + struct mediainfo *next; + int info_type; + int index; + unsigned char *info; +}; + +struct tulip_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct tulip_rx_desc rx_ring[RX_RING_SIZE]; + struct tulip_tx_desc tx_ring[TX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; +#ifdef CARDBUS + /* The X3201-3 requires double word aligned tx bufs */ + struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE]; +#endif + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + char *rx_buffs; /* Address of temporary Rx buffers. */ + u8 setup_buf[96*sizeof(u16) + 7]; + u16 *setup_frame; /* Pseudo-Tx frame to init address table. */ + int chip_id; + int revision; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + int interrupt; /* In-interrupt flag. */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int full_duplex_lock:1; + unsigned int fake_addr:1; /* Multiport board faked address. */ + 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. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ + unsigned int open:1; + unsigned int csr0; /* CSR0 setting. */ + unsigned int csr6; /* Current CSR6 control settings. */ + unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ + u16 to_advertise; /* NWay capabilities advertised. */ + u16 lpar; /* 21143 Link partner ability. */ + u16 advertising[4]; + signed char phys[4], mii_cnt; /* MII device addresses. */ + struct mediatable *mtable; + int cur_index; /* Current media index. */ + int saved_if_port; + struct pci_dev *pdev; + spinlock_t lock; + int pad0, pad1; /* Used for 8-byte alignment */ +}; + +static void parse_eeprom(struct net_device *dev); +static int read_eeprom(long ioaddr, int location, int addr_len); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static void select_media(struct net_device *dev, int startup); +static void tulip_up(struct net_device *dev); +static void tulip_down(struct net_device *dev); +static int tulip_open(struct net_device *dev); +static void tulip_timer(unsigned long data); +static void t21142_start_nway(struct net_device *dev); +static void tulip_tx_timeout(struct net_device *dev); +static void tulip_init_ring(struct net_device *dev); +static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int tulip_rx(struct net_device *dev); +static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int tulip_close(struct net_device *dev); +static struct net_device_stats *tulip_get_stats(struct net_device *dev); +#ifdef HAVE_PRIVATE_IOCTL +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#endif +static void set_rx_mode(struct net_device *dev); + +/* The Xircom cards are picky about when certain bits in CSR6 can be + manipulated. Keith Owens . */ + +static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx) +{ + const int strict_bits = 0x0060e202; + int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; + long flags; + save_flags(flags); + cli(); + if (chip_idx != X3201_3) { + outl(newcsr6, ioaddr + CSR6); + restore_flags(flags); + return; + } + newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ + /* read 0 on the Xircom cards */ + newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ + currcsr6 = inl(ioaddr + CSR6); + if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || + ((currcsr6 & ~0x2002) == 0)) { + outl(newcsr6, ioaddr + CSR6); /* safe */ + restore_flags(flags); + return; + } + /* make sure the transmitter and receiver are stopped first */ + currcsr6 &= ~0x2002; + while (1) { + csr5 = inl(ioaddr + CSR5); + if (csr5 == 0xffffffff) + break; /* cannot read csr5, card removed? */ + csr5_22_20 = csr5 & 0x700000; + csr5_19_17 = csr5 & 0x0e0000; + if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && + (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) + break; /* both are stopped or suspended */ + if (!--attempts) { + printk(KERN_INFO "tulip.c: outl_CSR6 too many attempts," + "csr5=0x%08x\n", csr5); + outl(newcsr6, ioaddr + CSR6); /* unsafe but do it anyway */ + restore_flags(flags); + return; + } + outl(currcsr6, ioaddr + CSR6); + udelay(1); + } + /* now it is safe to change csr6 */ + outl(newcsr6, ioaddr + CSR6); + restore_flags(flags); +} + +static struct net_device *tulip_probe1(struct pci_dev *pdev, + struct net_device *dev, long ioaddr, int irq, + int chip_idx, int board_idx) +{ + static int did_version = 0; /* Already printed version info. */ + struct tulip_private *tp; + /* See note below on the multiport cards. */ + static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; + static int last_irq = 0; + static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ + u8 chip_rev; + int i; + unsigned short sum; + + if (tulip_debug > 0 && did_version++ == 0) + printk(KERN_INFO "%s", version); + + dev = init_etherdev(dev, 0); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev); + /* Bring the 21143 out of sleep mode. + Caution: Snooze mode does not work with some boards! */ + if (tulip_tbl[chip_idx].flags & HAS_ACPI) + pci_write_config_dword(pdev, 0x40, 0x00000000); + + printk(KERN_INFO "%s: %s rev %d at %#3lx,", + dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + + /* Stop the chip's Tx and Rx processes. */ + outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, chip_idx); + /* Clear the missed-packet counter. */ + (volatile int)inl(ioaddr + CSR8); + + if (chip_idx == DC21041) { + if (inl(ioaddr + CSR9) & 0x8000) { + printk(" 21040 compatible mode,"); + chip_idx = DC21040; + } else { + printk(" 21041 mode,"); + } + } + + /* The station address ROM is read byte serially. The register must + be polled, waiting for the value to be read bit serially from the + EEPROM. + */ + sum = 0; + if (chip_idx == DC21040) { + outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ + for (i = 0; i < 6; i++) { + int value, boguscnt = 100000; + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + dev->dev_addr[i] = value; + sum += value & 0xff; + } + } else if (chip_idx == LC82C168) { + for (i = 0; i < 3; i++) { + int value, boguscnt = 100000; + outl(0x600 | i, ioaddr + 0x98); + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); + sum += value & 0xffff; + } + } else if (chip_idx == COMET) { + /* No need to read the EEPROM. */ + put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); + put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); + for (i = 0; i < 6; i ++) + sum += dev->dev_addr[i]; + } else if (chip_idx == X3201_3) { + /* Xircom has its address stored in the CIS + * we access it through the boot rom interface for now + * this might not work, as the CIS is not parsed but I + * (danilo) use the offset I found on my card's CIS !!! + * + * Doug Ledford: I changed this routine around so that it + * walks the CIS memory space, parsing the config items, and + * finds the proper lan_node_id tuple and uses the data + * stored there. + */ + unsigned char j, tuple, link, data_id, data_count; + outl(1<<12, ioaddr + CSR9); /* enable boot rom access */ + for (i = 0x100; i < 0x1f7; i += link+2) { + outl(i, ioaddr + CSR10); + tuple = inl(ioaddr + CSR9) & 0xff; + outl(i + 1, ioaddr + CSR10); + link = inl(ioaddr + CSR9) & 0xff; + outl(i + 2, ioaddr + CSR10); + data_id = inl(ioaddr + CSR9) & 0xff; + outl(i + 3, ioaddr + CSR10); + data_count = inl(ioaddr + CSR9) & 0xff; + if ( (tuple == 0x22) && + (data_id == 0x04) && (data_count == 0x06) ) { + /* + * This is it. We have the data we want. + */ + for (j = 0; j < 6; j++) { + outl(i + j + 4, ioaddr + CSR10); + dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff; + } + break; + } else if (link == 0) { + break; + } + } + sum = 1; // to make check below fail! + } else { /* Must be a new chip, with a serial EEPROM interface. */ + /* We read the whole EEPROM, and sort it out later. DEC has a + specification _Digital Semiconductor 21X4 Serial ROM Format_ + but early vendor boards just put the address in the first six + EEPROM locations. */ + unsigned char ee_data[EEPROM_SIZE]; + int sa_offset = 0; + + for (i = 0; i < sizeof(ee_data)/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); + + /* Detect the simple EEPROM format by the duplicated station addr. */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + sa_offset = 20; + if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { + sa_offset = 2; /* Grrr, damn Matrox boards. */ + multiport_cnt = 4; + } + for (i = 0; i < 6; i ++) { + dev->dev_addr[i] = ee_data[i + sa_offset]; + sum += ee_data[i + sa_offset]; + } + } + /* Lite-On boards have the address byte-swapped. */ + if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) + && dev->dev_addr[1] == 0x00) + for (i = 0; i < 6; i+=2) { + char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[i+1]; + dev->dev_addr[i+1] = tmp; + } + /* On the Zynx 315 Etherarray and other multiport boards only the + first Tulip has an EEPROM. + The addresses of the subsequent ports are derived from the first. + Many PCI BIOSes also incorrectly report the IRQ line, so we correct + that here as well. */ + if (sum == 0 || sum == 6*0xff) { + printk(" EEPROM not present,"); + for (i = 0; i < 5; i++) + dev->dev_addr[i] = last_phys_addr[i]; + dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__i386__) /* Patch up x86 BIOS bug. */ + if (last_irq) + irq = last_irq; +#endif + } + + for (i = 0; i < 6; i++) + printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); + printk(", IRQ %d.\n", irq); + last_irq = irq; + + /* We do a request_region() only to register /proc/ioports info. */ + /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ + request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Make certain the data structures are quadword aligned. */ + tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7); + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + + tp->lock = SPIN_LOCK_UNLOCKED; + tp->pdev = pdev; + tp->chip_id = chip_idx; + tp->revision = chip_rev; + tp->csr0 = csr0; + tp->setup_frame = (u16 *)(((unsigned long)tp->setup_buf + 7) & ~7); + + /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. + And the ASIX must have a burst limit or horrible things happen. */ + if ( (chip_idx == DC21143 && chip_rev == 65) || + (chip_idx == X3201_3) ) + tp->csr0 &= ~0x01000000; + else if (chip_idx == AX88140) + tp->csr0 |= 0x2000; + +#ifdef TULIP_FULL_DUPLEX + tp->full_duplex = 1; + tp->full_duplex_lock = 1; +#endif +#ifdef TULIP_DEFAULT_MEDIA + tp->default_port = TULIP_DEFAULT_MEDIA; +#endif +#ifdef TULIP_NO_MEDIA_SWITCH + tp->medialock = 1; +#endif + + /* The lower four bits are the media type. */ + if (board_idx >= 0 && board_idx < MAX_UNITS) { + tp->default_port = options[board_idx] & 15; + if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) + tp->full_duplex = 1; + if (mtu[board_idx] > 0) + dev->mtu = mtu[board_idx]; + } + if (dev->mem_start) + tp->default_port = dev->mem_start; + if (tp->default_port) { + tp->medialock = 1; + if (media_cap[tp->default_port] & MediaAlwaysFD) + tp->full_duplex = 1; + } + if (tp->full_duplex) + tp->full_duplex_lock = 1; + + /* This is logically part of probe1(), but too complex to write inline. */ + if (tulip_tbl[chip_idx].flags & HAS_MEDIA_TABLE) + parse_eeprom(dev); + + if (media_cap[tp->default_port] & MediaIsMII) { + u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; + tp->to_advertise = media2advert[tp->default_port - 9]; + } else + tp->to_advertise = 0x03e1; + + if ((tulip_tbl[chip_idx].flags & ALWAYS_CHECK_MII) || + (tp->mtable && tp->mtable->has_mii) || + ( ! tp->mtable && (tulip_tbl[chip_idx].flags & HAS_MII))) { + int phy, phy_idx; + if (tp->mtable && tp->mtable->has_mii) { + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == 11) { + tp->cur_index = i; + tp->saved_if_port = dev->if_port; + select_media(dev, 1); + dev->if_port = tp->saved_if_port; + break; + } + } + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = mdio_read(dev, phy, 1); + if ((mii_status & 0x8301) == 0x8001 || + ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { + int mii_reg0 = mdio_read(dev, phy, 0); + int mii_advert = mdio_read(dev, phy, 4); + int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; + tp->phys[phy_idx] = phy; + tp->advertising[phy_idx++] = reg4; + printk(KERN_INFO "%s: MII transceiver #%d " + "config %4.4x status %4.4x advertising %4.4x.\n", + dev->name, phy, mii_reg0, mii_status, mii_advert); + /* Fixup for DLink with miswired PHY. */ + if (mii_advert != reg4) { + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," + " previously advertising %4.4x.\n", + dev->name, reg4, phy, mii_advert); + mdio_write(dev, phy, 4, reg4); + } + /* Enable autonegotiation: some boards default to off. */ + mdio_write(dev, phy, 0, mii_reg0 | + (tp->full_duplex ? 0x1100 : 0x1000) | + (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); + } + } + tp->mii_cnt = phy_idx; + if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { + printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + tp->phys[0] = 1; + } + } + + /* The Tulip-specific entries in the device structure. */ + dev->open = &tulip_open; + dev->hard_start_xmit = &tulip_start_xmit; + dev->stop = &tulip_close; + dev->get_stats = &tulip_get_stats; +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = &private_ioctl; +#endif +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &set_rx_mode; +#endif + dev->tx_timeout = tulip_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + /* Reset the xcvr interface and turn on heartbeat. */ + switch (chip_idx) { + case DC21041: + outl(0x00000000, ioaddr + CSR13); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ + outl_CSR6(inl(ioaddr + CSR6) | 0x0200, ioaddr, chip_idx); + outl(0x0000EF05, ioaddr + CSR13); + break; + case DC21040: + outl(0x00000000, ioaddr + CSR13); + outl(0x00000004, ioaddr + CSR13); + break; + case DC21140: default: + if (tp->mtable) + outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); + break; + case DC21142: + case PNIC2: + if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) { + outl_CSR6(0x82020000, ioaddr, chip_idx); + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl_CSR6(0x820E0000, ioaddr, chip_idx); + } else { + outl_CSR6(0x82420200, ioaddr, chip_idx); + outl(0x0001, ioaddr + CSR13); + outl(0x0003FFFF, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + outl(0x0001, ioaddr + CSR13); + outl(0x1301, ioaddr + CSR12); /* Start NWay. */ + } + break; + case X3201_3: + outl(0x0008, ioaddr + CSR15); + udelay(5); /* The delays are Xircom recommended to give the + * chipset time to reset the actual hardware + * on the PCMCIA card + */ + outl(0xa8050000, ioaddr + CSR15); + udelay(5); + outl(0xa00f0000, ioaddr + CSR15); + udelay(5); + outl_CSR6(0x32000200, ioaddr, chip_idx); + break; + case LC82C168: + if ( ! tp->mii_cnt) { + outl_CSR6(0x00420000, ioaddr, chip_idx); + outl(0x30, ioaddr + CSR12); + outl(0x0001F078, ioaddr + 0xB8); + outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ + } + break; + case MX98713: case COMPEX9881: + outl_CSR6(0x00000000, ioaddr, chip_idx); + outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ + outl(0x00000001, ioaddr + CSR13); + break; + case MX98715: case MX98725: + outl_CSR6(0x01a80000, ioaddr, chip_idx); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00001000, ioaddr + CSR12); + break; + case COMET: + /* No initialization necessary. */ + break; + } + + return dev; +} + +/* Serial EEPROM section. */ +/* The main routine to parse the very complicated SROM structure. + Search www.digital.com for "21X4 SROM" to get details. + This code is very complex, and will require changes to support + additional cards, so I'll be verbose about what is going on. + */ + +/* Known cards that have old-style EEPROMs. */ +static struct fixups { + char *name; + unsigned char addr0, addr1, addr2; + u16 newtable[32]; /* Max length below. */ +} eeprom_fixups[] = { + {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f, + 0x0000, 0x009E, /* 10baseT */ + 0x0903, 0x006D, /* 100baseTx */ }}, + {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0103, 0x006D, /* 100baseTx */ }}, + {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }}, + {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F, + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + }}, + {0, 0, 0, 0, {}}}; + +static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", + "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; + +#if defined(__i386__) /* AKA get_unaligned() */ +#define get_u16(ptr) (*(u16 *)(ptr)) +#else +#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) +#endif + +static void parse_eeprom(struct net_device *dev) +{ + /* The last media info list parsed, for multiport boards. */ + static struct mediatable *last_mediatable = NULL; + static unsigned char *last_ee_data = NULL; + static int controller_index = 0; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + unsigned char *ee_data = tp->eeprom; + int i; +#ifdef CARDBUS + int chip_rev = tp->revision; +#endif + + tp->mtable = 0; + for (i = 0; i < EEPROM_SIZE/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); + + /* Detect an old-style (SA only) EEPROM layout: + memcmp(eedata, eedata+16, 8). */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + break; + if (i >= 8) { + if (ee_data[0] == 0xff) { + if (last_mediatable) { + controller_index++; + printk(KERN_INFO "%s: Controller %d of multiport board.\n", + dev->name, controller_index); + tp->mtable = last_mediatable; + ee_data = last_ee_data; + goto subsequent_board; + } else + printk(KERN_INFO "%s: Missing EEPROM, this interface may " + "not work correctly!\n", + dev->name); + return; + } + /* Do a fix-up based on the vendor half of the station address prefix. */ + for (i = 0; eeprom_fixups[i].name; i++) { + if (dev->dev_addr[0] == eeprom_fixups[i].addr0 + && dev->dev_addr[1] == eeprom_fixups[i].addr1 + && dev->dev_addr[2] == eeprom_fixups[i].addr2) { + if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + i++; /* An Accton EN1207, not an outlaw Maxtech. */ + memcpy(ee_data + 26, eeprom_fixups[i].newtable, + sizeof(eeprom_fixups[i].newtable)); + printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" + " substitute media control info.\n", + dev->name, eeprom_fixups[i].name); + break; + } + } + if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ + printk(KERN_INFO "%s: Old style EEPROM with no media selection " + "information.\n", + dev->name); + return; + } + } + + controller_index = 0; + if (ee_data[19] > 1) { /* Multiport board. */ + last_ee_data = ee_data; + } +subsequent_board: + + if (ee_data[27] == 0) { /* No valid media table. */ + } else if (tp->chip_id == DC21041) { + unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; + short media; + int count; + + media = get_u16(p); + p += 2; + count = *p++; + + printk(KERN_INFO "%s:21041 Media information at %d, default media " + "%4.4x (%s).\n", dev->name, ee_data[27], media, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + unsigned char media_code = *p++; + u16 csrvals[3]; + int idx; + for (idx = 0; idx < 3; idx++) { + csrvals[idx] = get_u16(p); + p += 2; + } + if (media_code & 0x40) { + printk(KERN_INFO "%s: 21041 media %2.2x (%s)," + " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n", + dev->name, media_code & 15, medianame[media_code & 15], + csrvals[0], csrvals[1], csrvals[2]); + } else + printk(KERN_INFO "%s: 21041 media #%d, %s.\n", + dev->name, media_code & 15, medianame[media_code & 15]); + } + } else { + unsigned char *p = (void *)ee_data + ee_data[27]; + unsigned char csr12dir = 0; + int count; + struct mediatable *mtable; + u16 media = get_u16(p); + + p += 2; + if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM) + csr12dir = *p++; + count = *p++; + mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), + GFP_KERNEL); + if (mtable == NULL) + return; /* Horrible, impossible failure. */ + last_mediatable = tp->mtable = mtable; + mtable->defaultmedia = media; + mtable->leafcount = count; + mtable->csr12dir = csr12dir; + mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; + mtable->csr15dir = mtable->csr15val = 0; + + printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + struct medialeaf *leaf = &mtable->mleaf[i]; + + if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ + leaf->type = 0; + leaf->media = p[0] & 0x3f; + leaf->leafdata = p; + if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ + mtable->has_mii = 1; + p += 4; + } else { + leaf->type = p[1]; + if (p[1] == 0x05) { + mtable->has_reset = i; + leaf->media = p[2] & 0x0f; + } else if (p[1] & 1) { + mtable->has_mii = 1; + leaf->media = 11; + } else { + mtable->has_nonmii = 1; + leaf->media = p[2] & 0x0f; + if (p[1] == 2) { + if (leaf->media == 0) { + mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; + mtable->csr15val = get_unaligned((u16*)&p[5])<<16; + } else if (leaf->media == 0x40) { + u32 base15 = get_unaligned((u16*)&p[7]); + mtable->csr15dir = + (get_unaligned((u16*)&p[9])<<16) + base15; + mtable->csr15val = + (get_unaligned((u16*)&p[11])<<16) + base15; + } + } + } + leaf->leafdata = p + 2; + p += (p[0] & 0x3f) + 1; + } + if (tulip_debug > 1 && leaf->media == 11) { + unsigned char *bp = leaf->leafdata; + printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " + "sequences %d/%d long, capabilities %2.2x %2.2x.\n", + dev->name, bp[0], bp[1], bp[1 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + } + printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", + dev->name, i, medianame[leaf->media], leaf->media, + block_name[leaf->type], leaf->type); + } + } +} +/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. + We add a bus turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << addr_len) +#define EE_READ_CMD (6 << addr_len) +#define EE_ERASE_CMD (7 << addr_len) + +static int read_eeprom(long ioaddr, int location, int addr_len) +{ + int i; + unsigned short retval = 0; + long ee_addr = ioaddr + CSR9; + int read_cmd = location | EE_READ_CMD; + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ + +/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); + inl(ioaddr + 0xA0); + inl(ioaddr + 0xA0); + while (--i > 0) + if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) + return retval & 0xffff; + return 0xffff; + } + + if (tp->chip_id == COMET) { + if (phy_id == 1) { + if (location < 7) + return inl(ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + return inl(ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + return inl(ioaddr + 0xD4 + ((location-29)<<2)); + } + return 0xffff; + } + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(cmd, ioaddr + 0xA0); + do + if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) + break; + while (--i > 0); + return; + } + + if (tp->chip_id == COMET) { + if (phy_id != 1) + return; + if (location < 7) + outl(value, ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + outl(value, ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + return; + } + + /* Establish sync by sending 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return; +} + +static void +tulip_up(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* On some chip revs we must set the MII/SYM port before the reset!? */ + if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) + outl_CSR6(0x00040000, ioaddr, tp->chip_id); + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + outl(0x00000001, ioaddr + CSR0); + + /* Deassert reset. */ + outl(tp->csr0, ioaddr + CSR0); + udelay(2); + + if (tulip_tbl[tp->chip_id].flags & HAS_ACPI) + pci_write_config_dword(tp->pdev, 0x40, 0x00000000); + + /* Clear the tx ring */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + } + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); + + if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) { + u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); + u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); + if (tp->chip_id == AX88140) { + outl(0, ioaddr + CSR13); + outl(addr_low, ioaddr + CSR14); + outl(1, ioaddr + CSR13); + outl(addr_high, ioaddr + CSR14); + } else if (tp->chip_id == COMET) { + outl(addr_low, ioaddr + 0xA4); + outl(addr_high, ioaddr + 0xA8); + outl(0, ioaddr + 0xAC); + outl(0, ioaddr + 0xB0); + } + } else if (tp->chip_id != X3201_3) { + /* This is set_rx_mode(), but without starting the transmitter. */ + u16 *eaddrs = (u16 *)dev->dev_addr; + u16 *setup_frm = &tp->setup_frame[15*6]; + + /* 21140 bug: you must add the broadcast address. */ + memset(tp->setup_frame, 0xff, 96*sizeof(u16)); + /* Fill the final entry of the table with our physical address. */ + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].length = 0x08000000 | 192; + tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[0].status = DescOwned; + + tp->cur_tx++; + } else { /* X3201_3 */ + u16 *eaddrs = (u16 *)dev->dev_addr; + u16 *setup_frm = &tp->setup_frame[0*6]; + + /* fill the table with the broadcast address */ + memset(tp->setup_frame, 0xff, 96*sizeof(u16)); + /* re-fill the first 14 table entries with our address */ + for(i=0; i<14; i++) { + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].length = 0x08000000 | 192; + /* Lie about the address of our setup frame to make the */ + /* chip happy */ + tp->tx_ring[0].buffer1 = (virt_to_bus(tp->setup_frame) + 4); + tp->tx_ring[0].status = DescOwned; + + tp->cur_tx++; + } + outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); + outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); + + tp->saved_if_port = dev->if_port; + if (dev->if_port == 0) + dev->if_port = tp->default_port; + if (tp->chip_id == DC21041 && dev->if_port > 4) + /* Invalid: Select initial TP, autosense, autonegotiate. */ + dev->if_port = 4; + + /* Allow selecting a default media. */ + i = 0; + if (tp->mtable == NULL) + goto media_picked; + if (dev->if_port) { + int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 : + (dev->if_port == 12 ? 0 : dev->if_port); + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using user-specified media %s.\n", + dev->name, medianame[dev->if_port]); + goto media_picked; + } + } + if ((tp->mtable->defaultmedia & 0x0800) == 0) { + int looking_for = tp->mtable->defaultmedia & 15; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", + dev->name, medianame[looking_for]); + goto media_picked; + } + } + /* Start sensing first non-full-duplex media. */ + for (i = tp->mtable->leafcount - 1; + (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) + ; +media_picked: + + tp->csr6 = 0; + tp->cur_index = i; + if (dev->if_port == 0 && tp->chip_id == DC21142) { + if (tp->mii_cnt) { + select_media(dev, 1); + if (tulip_debug > 1) + printk(KERN_INFO "%s: Using MII transceiver %d, status " + "%4.4x.\n", + dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1)); + outl_CSR6(0x82020000, ioaddr, tp->chip_id); + tp->csr6 = 0x820E0000; + dev->if_port = 11; + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + } else + t21142_start_nway(dev); + } else if ((tp->chip_id == LC82C168 || tp->chip_id == PNIC2) + && tp->mii_cnt && ! tp->medialock) { + dev->if_port = 11; + tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0001, ioaddr + CSR15); + } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) + && ! tp->medialock) { + dev->if_port = 0; + tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { + /* Provided by BOLO, Macronix - 12/10/1998. */ + dev->if_port = 0; + tp->csr6 = 0x01880200; + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); + } else if (tp->chip_id == DC21143 && + media_cap[dev->if_port] & MediaIsMII) { + /* We must reset the media CSRs when we force-select MII mode. */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + } else if (tp->chip_id == X3201_3) { + outl(0x0008, ioaddr + CSR15); + udelay(5); + outl(0xa8050000, ioaddr + CSR15); + udelay(5); + outl(0xa00f0000, ioaddr + CSR15); + udelay(5); + tp->csr6 = 0x32400000; + } else if (tp->chip_id == COMET) { + dev->if_port = 0; + tp->csr6 = 0x00040000; + } else + select_media(dev, 1); + + /* Start the chip's Tx to process setup frame. */ + outl_CSR6(tp->csr6, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id); + + /* Enable interrupts by setting the interrupt mask. */ + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + outl(0, ioaddr + CSR2); /* Rx poll demand */ + + netif_start_queue (dev); + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", + dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), + inl(ioaddr + CSR6)); + } + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT(5*HZ); + tp->timer.data = (unsigned long)dev; + tp->timer.function = tulip_tbl[tp->chip_id].media_timer; + add_timer(&tp->timer); +} + +static int +tulip_open(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) + return -EAGAIN; + + tulip_init_ring(dev); + + tulip_up(dev); + tp->open = 1; + MOD_INC_USE_COUNT; + + return 0; +} + +/* Set up the transceiver control registers for the selected media type. */ +static void select_media(struct net_device *dev, int startup) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct mediatable *mtable = tp->mtable; + u32 new_csr6; + int i; + + if (mtable) { + struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; + unsigned char *p = mleaf->leafdata; + switch (mleaf->type) { + case 0: /* 21140 non-MII xcvr. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" + " with control setting %2.2x.\n", + dev->name, p[1]); + dev->if_port = p[0]; + if (startup) + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + outl(p[1], ioaddr + CSR12); + new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); + break; + case 2: case 4: { + u16 setup[5]; + u32 csr13val, csr14val, csr15dir, csr15val; + for (i = 0; i < 5; i++) + setup[i] = get_u16(&p[i*2 + 1]); + + dev->if_port = p[0] & 15; + if (media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + + if (startup && mtable->has_reset) { + struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; + unsigned char *rst = rleaf->leafdata; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Resetting the transceiver.\n", + dev->name); + for (i = 0; i < rst[0]; i++) + outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " + "%4.4x/%4.4x.\n", + dev->name, medianame[dev->if_port], setup[0], setup[1]); + if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ + csr13val = setup[0]; + csr14val = setup[1]; + csr15dir = (setup[3]<<16) | setup[2]; + csr15val = (setup[4]<<16) | setup[2]; + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + outl(csr13val, ioaddr + CSR13); + } else { + csr13val = 1; + csr14val = 0x0003FF7F; + csr15dir = (setup[0]<<16) | 0x0008; + csr15val = (setup[1]<<16) | 0x0008; + if (dev->if_port <= 4) + csr14val = t21142_csr14[dev->if_port]; + if (startup) { + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + } + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + if (startup) outl(csr13val, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", + dev->name, csr15dir, csr15val); + if (mleaf->type == 4) + new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); + else + new_csr6 = 0x82420000; + break; + } + case 1: case 3: { + int phy_num = p[0]; + int init_length = p[1]; + u16 *misc_info; + u16 to_advertise; + + dev->if_port = 11; + new_csr6 = 0x020E0000; + if (mleaf->type == 3) { /* 21142 */ + u16 *init_sequence = (u16*)(p+2); + u16 *reset_sequence = &((u16*)(p+3))[init_length]; + int reset_length = p[2 + init_length*2]; + misc_info = reset_sequence + reset_length; + if (startup) + for (i = 0; i < reset_length; i++) + outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); + for (i = 0; i < init_length; i++) + outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); + } else { + u8 *init_sequence = p + 2; + u8 *reset_sequence = p + 3 + init_length; + int reset_length = p[2 + init_length]; + misc_info = (u16*)(reset_sequence + reset_length); + if (startup) { + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + for (i = 0; i < reset_length; i++) + outl(reset_sequence[i], ioaddr + CSR12); + } + for (i = 0; i < init_length; i++) + outl(init_sequence[i], ioaddr + CSR12); + } + to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; + tp->advertising[phy_num] = to_advertise; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", + dev->name, to_advertise, phy_num, tp->phys[phy_num]); + /* Bogus: put in by a committee? */ + mdio_write(dev, tp->phys[phy_num], 4, to_advertise); + break; + } + default: + printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", + dev->name, mleaf->type); + new_csr6 = 0x020E0000; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12) & 0xff); + } else if (tp->chip_id == DC21041) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", + dev->name, medianame[dev->if_port & 15], + inl(ioaddr + CSR12) & 0xffff); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + new_csr6 = 0x80020000; + } else if (tp->chip_id == LC82C168 || tp->chip_id == PNIC2) { + if (startup && ! tp->medialock) + dev->if_port = tp->mii_cnt ? 11 : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x," + " media %s.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12), + medianame[dev->if_port]); + if (tp->mii_cnt) { + new_csr6 = 0x810C0000; + outl(0x0001, ioaddr + CSR15); + outl(0x0201B07A, ioaddr + 0xB8); + } else if (startup) { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + } else if (dev->if_port == 3 || dev->if_port == 5) { + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + if (startup) + outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */ + else + outl(0x1F868, ioaddr + 0xB8); + } else { + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + } else if (tp->chip_id == DC21040) { /* 21040 */ + /* Turn on the xcvr interface. */ + int csr12 = inl(ioaddr + CSR12); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], csr12); + if (media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + new_csr6 = 0x20000; + /* Set the full duplux match frame. */ + outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + if (t21040_csr13[dev->if_port] & 8) { + outl(0x0705, ioaddr + CSR14); + outl(0x0006, ioaddr + CSR15); + } else { + outl(0xffff, ioaddr + CSR14); + outl(0x0000, ioaddr + CSR15); + } + outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); + } else if (tp->chip_id == X3201_3) { /* Xircom */ + if (tp->default_port == 0) + dev->if_port = tp->mii_cnt ? 11 : 3; +/* Someone is on crack, the Xircom only does MII, no Fx */ +/* if (media_cap[dev->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (media_cap[dev->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000;*/ + new_csr6 = 0x324c0000; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Xircom CardBus Adapter: " + "%s transceiver, CSR12 %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12)); + } else { /* Unknown chip type with no media table. */ + if (tp->default_port == 0) + dev->if_port = tp->mii_cnt ? 11 : 3; + if (media_cap[dev->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (media_cap[dev->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No media description table, assuming " + "%s transceiver, CSR12 %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12)); + } + + tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); + return; +} + +/* + Check the MII negotiated duplex, and change the CSR6 setting if + required. + Return 0 if everything is OK. + Return < 0 if the transceiver is missing or has no link beat. + */ +static int check_duplex(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int mii_reg1, mii_reg5, negotiated, duplex; + + if (tp->full_duplex_lock) + return 0; + mii_reg1 = mdio_read(dev, tp->phys[0], 1); + mii_reg5 = mdio_read(dev, tp->phys[0], 5); + if (tulip_debug > 1) + printk(KERN_INFO "%s: MII status %4.4x, Link partner report " + "%4.4x.\n", dev->name, mii_reg1, mii_reg5); + if (mii_reg1 == 0xffff) + return -2; + if ((mii_reg1 & 0x0004) == 0) { + int new_reg1 = mdio_read(dev, tp->phys[0], 1); + if ((new_reg1 & 0x0004) == 0) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: No link beat on the MII interface," + " status %4.4x.\n", dev->name, new_reg1); + return -1; + } + } + negotiated = mii_reg5 & tp->advertising[0]; + duplex = ((negotiated & 0x0300) == 0x0100 + || (negotiated & 0x00C0) == 0x0040); + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + if (tp->full_duplex) tp->csr6 |= 0x0200; + else tp->csr6 &= ~0x0200; + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + if (tulip_debug > 0) + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + "#%d link partner capability of %4.4x.\n", + dev->name, tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + } + return 0; +} + +static void tulip_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 csr12 = inl(ioaddr + CSR12); + int next_tick = 2*HZ; + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x " + "SIA %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6), + csr12, inl(ioaddr + CSR13), + inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + } + switch (tp->chip_id) { + case DC21040: + if (!tp->medialock && csr12 & 0x0002) { /* Network error */ + printk(KERN_INFO "%s: No link beat found.\n", + dev->name); + dev->if_port = (dev->if_port == 2 ? 0 : 2); + select_media(dev, 0); + dev->trans_start = jiffies; + } + break; + case DC21041: + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", + dev->name, csr12); + switch (dev->if_port) { + case 0: case 3: case 4: + if (csr12 & 0x0004) { /*LnkFail */ + /* 10baseT is dead. Check for activity on alternate port. */ + tp->mediasense = 1; + if (csr12 & 0x0200) + dev->if_port = 2; + else + dev->if_port = 1; + printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", + dev->name, medianame[dev->if_port]); + outl(0, ioaddr + CSR13); /* Reset */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + next_tick = 10*HZ; /* 2.4 sec. */ + } else + next_tick = 30*HZ; + break; + case 1: /* 10base2 */ + case 2: /* AUI */ + if (csr12 & 0x0100) { + next_tick = (30*HZ); /* 30 sec. */ + tp->mediasense = 0; + } else if ((csr12 & 0x0004) == 0) { + printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", + dev->name); + dev->if_port = 0; + select_media(dev, 0); + next_tick = (24*HZ)/10; /* 2.4 sec. */ + } else if (tp->mediasense || (csr12 & 0x0002)) { + dev->if_port = 3 - dev->if_port; /* Swap ports. */ + select_media(dev, 0); + next_tick = 20*HZ; + } else { + next_tick = 20*HZ; + } + break; + } + break; + case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { + struct medialeaf *mleaf; + unsigned char *p; + if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ + /* Not much that can be done. + Assume this a generic MII or SYM transceiver. */ + next_tick = 60*HZ; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " + "CSR12 0x%2.2x.\n", + dev->name, inl(ioaddr + CSR6), csr12 & 0xff); + break; + } + mleaf = &tp->mtable->mleaf[tp->cur_index]; + p = mleaf->leafdata; + switch (mleaf->type) { + case 0: case 4: { + /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ + int offset = mleaf->type == 4 ? 5 : 2; + s8 bitnum = p[offset]; + if (p[offset+1] & 0x80) { + if (tulip_debug > 1) + printk(KERN_DEBUG"%s: Transceiver monitor tick " + "CSR12=%#2.2x, no media sense.\n", + dev->name, csr12); + if (mleaf->type == 4) { + if (mleaf->media == 3 && (csr12 & 0x02)) + goto select_next_media; + } + break; + } + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" + " bit %d is %d, expecting %d.\n", + dev->name, csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); + /* Check that the specified bit has the proper value. */ + if ((bitnum < 0) != + ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, + medianame[mleaf->media]); + if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ + goto actually_mii; + break; + } + if (tp->medialock) + break; + select_next_media: + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + dev->if_port = tp->mtable->mleaf[tp->cur_index].media; + if (media_cap[dev->if_port] & MediaIsFD) + goto select_next_media; /* Skip FD entries. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No link beat on media %s," + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & 15], + medianame[tp->mtable->mleaf[tp->cur_index].media]); + select_media(dev, 0); + /* Restart the transmit process. */ + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + next_tick = (24*HZ)/10; + break; + } + case 1: case 3: /* 21140, 21142 MII */ + actually_mii: + check_duplex(dev); + next_tick = 60*HZ; + break; + case 2: /* 21142 serial block has no link beat. */ + default: + break; + } + } + break; + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list + of available transceivers. */ +static void t21142_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + int next_tick = 60*HZ; + int new_csr6 = 0; + + if ((tulip_debug > 2) && !(media_cap[dev->if_port] & MediaIsMII)) + printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", + dev->name, csr12, medianame[dev->if_port]); + if (media_cap[dev->if_port] & MediaIsMII) { + check_duplex(dev); + next_tick = 60*HZ; + } else if (tp->nwayset) { + /* Don't screw up a negotiated session! */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", + dev->name, medianame[dev->if_port], csr12); + } else if (tp->medialock) { + ; + } else if (dev->if_port == 3) { + if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " + "trying NWay.\n", dev->name, csr12); + t21142_start_nway(dev); + next_tick = 3*HZ; + } + } else if (((csr12 & 0x7000) != 0x5000) + && tp->chip_id != X3201_3) { + /* Negotiation failed. Search media types. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", + dev->name, csr12); + if (!(csr12 & 4)) { /* 10mbps link beat good. */ + new_csr6 = 0x82420000; + dev->if_port = 0; + outl(0, ioaddr + CSR13); + outl(0x0003FFFF, ioaddr + CSR14); + outw(t21142_csr15[dev->if_port], ioaddr + CSR15); + outl(t21142_csr13[dev->if_port], ioaddr + CSR13); + } else { + /* Select 100mbps port to check for link beat. */ + new_csr6 = 0x83860000; + dev->if_port = 3; + outl(0, ioaddr + CSR13); + outl(0x0003FF7F, ioaddr + CSR14); + outw(8, ioaddr + CSR15); + outl(1, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_INFO"%s: Testing new 21143 media %s.\n", + dev->name, medianame[dev->if_port]); + if (new_csr6 != (tp->csr6 & ~0x00D5)) { + tp->csr6 &= 0x00D5; + tp->csr6 |= new_csr6; + outl(0x0301, ioaddr + CSR12); + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + next_tick = 3*HZ; + } + if (tp->cur_tx - tp->dirty_tx > 0 && + jiffies - dev->trans_start > TX_TIMEOUT) { + printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n", + dev->name, tp->cur_tx, tp->dirty_tx); + tulip_tx_timeout(dev); + } + + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +static void t21142_start_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14 = ((tp->to_advertise & 0x0180) << 9) | + ((tp->to_advertise&0x0020)<<1) | 0xffbf; + + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + if (debug > 1) + printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", + dev->name, csr14); + outl(0x0001, ioaddr + CSR13); + outl(csr14, ioaddr + CSR14); + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + outl_CSR6(tp->csr6, ioaddr, tp->chip_id); + if (tp->mtable && tp->mtable->csr15dir) { + outl(tp->mtable->csr15dir, ioaddr + CSR15); + outl(tp->mtable->csr15val, ioaddr + CSR15); + } else + outw(0x0008, ioaddr + CSR15); + outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ +} + +static void t21142_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " + "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); + + /* If NWay finished and we have a negotiated partner capability. */ + if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { + int setup_done = 0; + tp->lpar = csr12 >> 16; + tp->nwayset = 1; + if (csr12 & 0x01000000) dev->if_port = 5; + else if (csr12 & 0x00800000) dev->if_port = 3; + else if (csr12 & 0x00400000) dev->if_port = 4; + else if (csr12 & 0x00200000) dev->if_port = 0; + else { + tp->nwayset = 0; + if ( ! (csr12 & 2)) dev->if_port = 3; + else if ( ! (csr12 & 4)) dev->if_port = 0; + } + tp->full_duplex = (media_cap[tp->default_port] & MediaAlwaysFD) ? 1:0; + + if (tulip_debug > 1) { + if (tp->nwayset) + printk(KERN_INFO "%s: Switching to %s based on link partner " + "advertisement %4.4x.\n", + dev->name, medianame[dev->if_port], tp->lpar); + else + printk(KERN_INFO "%s: Switching to %s based on link beat " + "status of %4.4x.\n", + dev->name, medianame[dev->if_port], csr12); + } + + if (tp->mtable) { + int i; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == dev->if_port) { + tp->cur_index = i; + select_media(dev, 0); + setup_done = 1; + break; + } + } + if ( ! setup_done) { + tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; + if (tp->full_duplex) + tp->csr6 |= 0x0200; + outw(0x0000, ioaddr + CSR13); + outw(0x0000, ioaddr + CSR14); + } + outl_CSR6(tp->csr6 | 0x0000, ioaddr, tp->chip_id); + if (debug > 2) + printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", + dev->name, inl(ioaddr + CSR5)); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } else if ((tp->nwayset && (csr5 & 0x08000000) + && (dev->if_port == 3 || dev->if_port == 5) + && (csr12 & 2) == 2) || + (tp->nway && (csr5 & (TPLnkFail)))) { + /* Link blew? Maybe restart NWay. */ + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } else if (dev->if_port == 3 || dev->if_port == 5) { + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); + if ((csr12 & 2) && ! tp->medialock) { + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + } else if (dev->if_port == 0 || dev->if_port == 4) { + if ((csr12 & 4) == 0) + printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", + dev->name); + } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", + dev->name); + dev->if_port = 0; + } else if (tp->nwayset) { + if (tulip_debug) + printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", + dev->name, medianame[dev->if_port], tp->csr6); + } else { /* 100mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", + dev->name); + dev->if_port = 3; + tp->csr6 = 0x83860000; + outl(0x0003FF7F, ioaddr + CSR14); + outl(0x0301, ioaddr + CSR12); + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } +} + +static void mxic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 3) { + printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, + inl(ioaddr + CSR12)); + } + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + +static void pnic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + int next_tick = 60*HZ; + int new_csr6 = tp->csr6 & ~0x40C40200; + + if (media_cap[dev->if_port] & MediaIsMII) { + int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0]; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC negotiated capability %8.8x, " + "CSR5 %8.8x.\n", + dev->name, negotiated, inl(ioaddr + CSR5)); + + if (negotiated & 0x0380) /* 10 vs 100mbps */ + new_csr6 |= 0x810E0000; + else + new_csr6 |= 0x814E0000; + if (((negotiated & 0x0300) == 0x0100) /* Duplex */ + || (negotiated & 0x00C0) == 0x0040 + || tp->full_duplex_lock) { + tp->full_duplex = 1; + new_csr6 |= 0x0200; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC MII PHY status %4.4x, Link " + "partner report %4.4x, csr6 %8.8x/%8.8x.\n", + dev->name, mdio_read(dev, tp->phys[0], 1), negotiated, + tp->csr6, inl(ioaddr + CSR6)); + } else { + int phy_reg = inl(ioaddr + 0xB8); + int csr5 = inl(ioaddr + CSR5); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC PHY status %8.8x, CSR5 %8.8x.\n", + dev->name, phy_reg, csr5); + + if (phy_reg & 0x04000000) { /* Remote link fault */ + /*outl(0x0201F078, ioaddr + 0xB8);*/ + next_tick = 3*HZ; + } + if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " + "CSR5 %8.8x, PHY %3.3x.\n", + dev->name, medianame[dev->if_port], csr12, + inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); + if (tp->medialock) { + } else if (dev->if_port == 0) { + dev->if_port = 3; + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + outl(0x1F868, ioaddr + 0xB8); + } else { + dev->if_port = 0; + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + new_csr6 |= (tp->csr6 & 0xfdff); + next_tick = 3*HZ; + } else + new_csr6 = tp->csr6; + if (tp->full_duplex_lock || (phy_reg & 0x30000000) != 0) { + tp->full_duplex = 1; + new_csr6 |= 0x00000200; + } + } + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); /* Restart Tx */ + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + dev->trans_start = jiffies; + if (tulip_debug > 1) + printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, " + "CSR6 %8.8x.\n", + dev->name, tp->full_duplex ? "full" : "half", new_csr6); + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +static void comet_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " + "%4.4x.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +static void tulip_tx_timeout(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (media_cap[dev->if_port] & MediaIsMII) { + /* Do nothing -- the media monitor should handle this. */ + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", + dev->name); + } else if (tp->chip_id == DC21040) { + if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { + dev->if_port = (dev->if_port == 2 ? 0 : 2); + printk(KERN_INFO "%s: transmit timed out, switching to " + "%s.\n", + dev->name, medianame[dev->if_port]); + select_media(dev, 0); + } + dev->trans_start = jiffies; + return; + } else if (tp->chip_id == DC21041) { + int csr12 = inl(ioaddr + CSR12); + + printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " + "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), csr12, + inl(ioaddr + CSR13), inl(ioaddr + CSR14)); + tp->mediasense = 1; + if ( ! tp->medialock) { + if (dev->if_port == 1 || dev->if_port == 2) + if (csr12 & 0x0004) { + dev->if_port = 2 - dev->if_port; + } else + dev->if_port = 0; + else + dev->if_port = 1; + select_media(dev, 0); + } + } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 + || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { + printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " + "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), + inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + if ( ! tp->medialock && tp->mtable) { + do + --tp->cur_index; + while (tp->cur_index >= 0 + && (media_cap[tp->mtable->mleaf[tp->cur_index].media] + & MediaIsFD)); + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + select_media(dev, 0); + printk(KERN_WARNING "%s: transmit timed out, switching to %s " + "media.\n", dev->name, medianame[dev->if_port]); + } + } else { + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " + "%8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); + dev->if_port = 0; + } + +#if defined(way_too_many_messages) + if (tulip_debug > 3) { + int i; + for (i = 0; i < RX_RING_SIZE; i++) { + u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); + int j; + printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " + "%2.2x %2.2x %2.2x.\n", + i, (unsigned int)tp->rx_ring[i].status, + (unsigned int)tp->rx_ring[i].length, + (unsigned int)tp->rx_ring[i].buffer1, + (unsigned int)tp->rx_ring[i].buffer2, + buf[0], buf[1], buf[2]); + for (j = 0; buf[j] != 0xee && j < 1600; j++) + if (j < 100) printk(" %2.2x", buf[j]); + printk(" j=%d.\n", j); + } + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); + printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Stop and restart the chip's Tx processes . */ + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + dev->trans_start = jiffies; + netif_wake_queue (dev); + tp->stats.tx_errors++; +} + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void tulip_init_ring(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x00000000; + tp->rx_ring[i].length = PKT_BUF_SZ; + tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]); + tp->rx_skbuff[i] = NULL; + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].length = PKT_BUF_SZ | DESC_RING_WRAP; + tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]); + + for (i = 0; i < RX_RING_SIZE; i++) { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[i].status = DescOwned; /* Owned by Tulip chip */ + tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail); + } + tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]); +#ifdef CARDBUS + if (tp->chip_id == X3201_3) + tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ); +#endif CARDBUS + } + tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]); +} + +static int +tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + u32 flag; + + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_skbuff[entry] = skb; +#ifdef CARDBUS + if (tp->chip_id == X3201_3) { + memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len); + tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data); + } else +#endif + tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data); + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x60000000; /* No interrupt */ + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0xe0000000; /* Tx-done intr. */ + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x60000000; /* No Tx-done intr. */ + } else { + /* Leave room for set_rx_mode() to fill entries. */ + flag = 0xe0000000; /* Tx-done intr. */ + tp->tx_full = 1; + } + if (entry == TX_RING_SIZE-1) + flag |= 0xe0000000 | DESC_RING_WRAP; + + tp->tx_ring[entry].length = skb->len | flag; + tp->tx_ring[entry].status = DescOwned; /* Pass ownership to the chip. */ + tp->cur_tx++; + if (tp->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); + + /* Trigger an immediate transmit demand. */ + outl(0, dev->base_addr + CSR1); + + dev->trans_start = jiffies; + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr5, work_budget = max_interrupt_work; + + spin_lock (&tp->lock); + + do { + csr5 = inl(ioaddr + CSR5); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(csr5 & 0x0001ffff, ioaddr + CSR5); + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if (csr5 == 0xffffffff) + break; /* all bits set, assume PCMCIA card removed */ + + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) + break; + + if (csr5 & (RxIntr | RxNoBuf)) + work_budget -= tulip_rx(dev); + + if (csr5 & (TxNoBuf | TxDied | TxIntr)) { + unsigned int dirty_tx; + + for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; + dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int status = tp->tx_ring[entry].status; + + if (status < 0) + break; /* It still hasn't been Txed */ + /* Check for Rx filter setup frames. */ + if (tp->tx_skbuff[entry] == NULL) + continue; + + if (status & 0x8000) { + /* There was an major error, log it. */ +#ifndef final_version + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + tp->stats.tx_errors++; + if (status & 0x4104) tp->stats.tx_aborted_errors++; + if (status & 0x0C00) tp->stats.tx_carrier_errors++; + if (status & 0x0200) tp->stats.tx_window_errors++; + if (status & 0x0002) tp->stats.tx_fifo_errors++; + if ((status & 0x0080) && tp->full_duplex == 0) + tp->stats.tx_heartbeat_errors++; +#ifdef ETHER_STATS + if (status & 0x0100) tp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (status & 0x0001) tp->stats.tx_deferred++; +#endif + tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff; + tp->stats.collisions += (status >> 3) & 15; + tp->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_skbuff[entry]); + tp->tx_skbuff[entry] = 0; + } + +#ifndef final_version + if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, tp->cur_tx, tp->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (tp->tx_full && + tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) + /* The ring is no longer full */ + tp->tx_full = 0; + + if (tp->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); + + tp->dirty_tx = dirty_tx; + if (csr5 & TxDied) { + if (tulip_debug > 2) + printk(KERN_WARNING "%s: The transmitter stopped." + " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", + dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + } + + /* Log errors. */ + if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ + if (csr5 == 0xffffffff) + break; + if (csr5 & TxJabber) tp->stats.tx_errors++; + if (csr5 & TxFIFOUnderflow) { + if ((tp->csr6 & 0xC000) != 0xC000) + tp->csr6 += 0x4000; /* Bump up the Tx threshold */ + else + tp->csr6 |= 0x00200000; /* Store-n-forward. */ + /* Restart the transmit process. */ + outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + if (csr5 & RxDied) { /* Missed a Rx frame. */ + tp->stats.rx_errors++; + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); + } + if (csr5 & TimerInt) { + if (tulip_debug > 2) + printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", + dev->name, csr5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + } + if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { + if ( tp->chip_id == DC21142) + t21142_lnk_change(dev, csr5); + } + /* Clear all error sources, included undocumented ones! */ + outl(0x0800f7ba, ioaddr + CSR5); + } + if (--work_budget < 0) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Too much work during an interrupt, " + "csr5=0x%8.8x.\n", dev->name, csr5); + /* Acknowledge all interrupt sources. */ + outl(0x8001ffff, ioaddr + CSR5); +#ifdef notdef + /* Clear all but standard interrupt sources. */ + outl((~csr5) & 0x0001ebef, ioaddr + CSR7); +#endif + break; + } + } while (1); + + if (tulip_debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", + dev->name, inl(ioaddr + CSR5)); + + spin_unlock (&tp->lock); +} + +static int +tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int work_done = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); + /* If we own the next entry, it's a new packet. Send it up. */ + while (tp->rx_ring[entry].status >= 0) { + s32 status = tp->rx_ring[entry].status; + + if (tulip_debug > 5) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); + if (--rx_work_limit < 0) + break; + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if ! defined(__alpha__) + eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1), + pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), + bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len); +#endif + work_done++; + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); + tp->rx_skbuff[entry] = NULL; +#ifndef final_version + if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in tulip_rx: %p vs. %p / %p.\n", + dev->name, bus_to_virt(tp->rx_ring[entry].buffer1), + skb->head, temp); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + entry = (++tp->cur_rx) % RX_RING_SIZE; + } + + /* Refill the Rx ring buffers. */ + for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + struct sk_buff *skb; + skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail); + work_done++; + } + tp->rx_ring[entry].status = DescOwned; + } + + return work_done; +} + +static void +tulip_down(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x00000000, ioaddr + CSR7); + /* Stop the chip's Tx and Rx processes. */ + outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, tp->chip_id); + /* 21040 -- Leave the card in 10baseT state. */ + if (tp->chip_id == DC21040) + outl(0x00000004, ioaddr + CSR13); + + if (inl(ioaddr + CSR6) != 0xffffffff) + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + + dev->if_port = tp->saved_if_port; +} + +static int +tulip_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl(ioaddr + CSR5)); + + netif_stop_queue(dev); + + if (netif_device_present(dev)) + tulip_down(dev); + + del_timer(&tp->timer); + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].length = 0; + tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ + if (skb) { + dev_kfree_skb(skb); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb(tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + tp->open = 0; + return 0; +} + +static struct net_device_stats *tulip_get_stats(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (netif_device_present(dev)) + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + + return &tp->stats; +} + +#ifdef HAVE_PRIVATE_IOCTL +/* Provide ioctl() calls to examine the MII xcvr state. */ +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + int phy = tp->phys[0] & 0x1f; + long flags; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + if (tp->mii_cnt) + data[0] = phy; + else if (tp->chip_id == DC21142) /* 21142 pseudo-MII */ + data[0] = 32; + else if (tp->chip_id == PNIC2) + data[0] = 32; + else if (tp->chip_id == COMET) + data[0] = 1; + else + return -ENODEV; + return 0; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + if (data[0] == 32 && + (tp->chip_id == DC21142 || tp->chip_id == PNIC2)) { + int csr12 = inl(ioaddr + CSR12); + int csr14 = inl(ioaddr + CSR14); + switch (data[1]) { + case 0: { + data[3] = (csr14<<5) & 0x1000; + break; } + case 1: + data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + + (csr12&0x06 ? 0x04 : 0); + break; + case 4: { + data[3] = ((csr14>>9)&0x0380) + + ((inl(ioaddr + CSR6)>>3)&0x0040) +((csr14>>1)&0x20) + 1; + break; + } + case 5: data[3] = csr12 >> 16; break; + default: data[3] = 0; break; + } + } else { + save_flags(flags); + cli(); + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + restore_flags(flags); + } + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ +#if defined(CAP_NET_ADMIN) + if (!capable(CAP_NET_ADMIN)) + return -EPERM; +#else + if (!suser()) + return -EPERM; +#endif + if (data[0] == 32 && tp->chip_id == DC21142) { + if (data[1] == 5) + tp->to_advertise = data[2]; + } else { + save_flags(flags); + cli(); + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + restore_flags(flags); + } + return 0; + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} +#endif /* HAVE_PRIVATE_IOCTL */ + +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN32 ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline u32 ether_crc_le(int length, unsigned char *data) +{ + u32 crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + int csr6 = inl(ioaddr + CSR6) & ~0x00D5; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + tp->csr6 &= ~0x00D5; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + tp->csr6 |= 0x00C0; + csr6 |= 0x00C0; + /* Unconditionally log net taps. */ + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter well -- accept all multicasts. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) { + /* Some work-alikes have only a 64-entry hash filter table. */ + /* Should verify correctness on big-endian/__powerpc__ */ + struct dev_mc_list *mclist; + int i; + u32 mc_filter[2]; /* Multicast hash filter */ + if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else { + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); + if (tp->chip_id == AX88140) { + outl(2, ioaddr + CSR13); + outl(mc_filter[0], ioaddr + CSR14); + outl(3, ioaddr + CSR13); + outl(mc_filter[1], ioaddr + CSR14); + } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + outl(mc_filter[0], ioaddr + 0xAC); + outl(mc_filter[1], ioaddr + 0xB0); + } + } + } else { + u16 *eaddrs, *setup_frm = tp->setup_frame; + struct dev_mc_list *mclist; + u32 tx_flags = 0x08000000 | 192; + int i; + + /* Note that only the low-address shortword of setup_frame is valid! + The values are doubled for big-endian architectures. */ + if ((dev->mc_count > 14) || ((dev->mc_count > 6) && (tp->chip_id == X3201_3))) { /* Must use a multicast hash table. */ + u16 hash_table[32]; + tx_flags = 0x08400000 | 192; /* Use hash filter. */ + memset(hash_table, 0, sizeof(hash_table)); + set_bit(255, hash_table); /* Broadcast entry */ + /* This should work on big-endian machines as well. */ + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + hash_table); + for (i = 0; i < 32; i++) { + *setup_frm++ = hash_table[i]; + *setup_frm++ = hash_table[i]; + } + setup_frm = &tp->setup_frame[13*6]; + } else if(tp->chip_id != X3201_3) { + /* We have <= 14 addresses so we can use the wonderful + 16 address perfect filtering of the Tulip. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + /* Fill the unused entries with the broadcast address. */ + memset(setup_frm, 0xff, (15-i)*12); + setup_frm = &tp->setup_frame[15*6]; + } else { + /* fill the first two table entries with our address */ + eaddrs = (u16 *)dev->dev_addr; + for(i=0; i<2; i++) { + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + /* Double fill each entry to accomodate chips that */ + /* don't like to parse these correctly */ + for (i=0, mclist=dev->mc_list; imc_count; + i++, mclist=mclist->next) { + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + } + i=((i+1)*2); + /* Fill the unused entries with the broadcast address. */ + memset(setup_frm, 0xff, (15-i)*12); + setup_frm = &tp->setup_frame[15*6]; + } + + /* Fill the final entry with our physical address. */ + eaddrs = (u16 *)dev->dev_addr; + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + /* Now add this frame to the Tx list. */ + if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { + /* Same setup recently queued, we need not add it. */ + } else { + unsigned long flags; + unsigned int entry, dummy = -1; + + save_flags(flags); cli(); + entry = tp->cur_tx++ % TX_RING_SIZE; + + if (entry != 0) { + /* Avoid a chip errata by prefixing a dummy entry. */ + tp->tx_skbuff[entry] = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? DESC_RING_WRAP : 0; + tp->tx_ring[entry].buffer1 = 0; + /* race with chip, set DescOwned later */ + dummy = entry; + entry = tp->cur_tx++ % TX_RING_SIZE; + } + + tp->tx_skbuff[entry] = 0; + /* Put the setup frame on the Tx list. */ + if (entry == TX_RING_SIZE-1) + tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ + tp->tx_ring[entry].length = tx_flags; + if(tp->chip_id == X3201_3) + tp->tx_ring[entry].buffer1 = (virt_to_bus(tp->setup_frame) + 4); + else + tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[entry].status = DescOwned; + if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { + tp->tx_full = 1; + netif_stop_queue (dev); + } + if (dummy >= 0) + tp->tx_ring[dummy].status = DescOwned; + restore_flags(flags); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + } + } + outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id); +} + +static struct pci_device_id tulip_pci_table[] __devinitdata = { +#if 0 /* these entries conflict with regular tulip driver */ + { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, + { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, + { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 }, + { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, + { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, + { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, + { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, + { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, +#endif + { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + {0}, +}; + +MODULE_DEVICE_TABLE(pci, tulip_pci_table); + +static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *dev; + static int board_idx = 0; + + printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name); + + pci_enable_device (pdev); + pci_set_master (pdev); + dev = tulip_probe1(pdev, NULL, + pci_resource_start (pdev, 0), pdev->irq, + id->driver_data, board_idx++); + if (dev) { + pdev->driver_data = dev; + return 0; + } + return -ENODEV; +} + +static void tulip_suspend(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + printk(KERN_INFO "tulip_suspend(%s)\n", dev->name); + if (tp->open) tulip_down(dev); +} + +static void tulip_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + printk(KERN_INFO "tulip_resume(%s)\n", dev->name); + if (tp->open) tulip_up(dev); +} + +static void __devexit tulip_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + + printk(KERN_INFO "tulip_detach(%s)\n", dev->name); + unregister_netdev(dev); + kfree(dev); + kfree(tp); +} + +static struct pci_driver tulip_ops = { + name: "tulip_cb", + id_table: tulip_pci_table, + probe: tulip_pci_probe, + remove: tulip_remove, + suspend: tulip_suspend, + resume: tulip_resume +}; + +static int __init tulip_init(void) +{ + pci_register_driver(&tulip_ops); + return 0; +} + +static __exit void tulip_exit(void) +{ + pci_unregister_driver(&tulip_ops); +} + +module_init(tulip_init) +module_exit(tulip_exit) + + +/* + * Local variables: + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.3.99-pre2/linux/drivers/net/plip.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/plip.c Wed Mar 22 09:55:33 2000 @@ -1325,7 +1325,7 @@ static int parport_ptr = 0; -static void __init plip_setup(char *str) +static int __init plip_setup(char *str) { int ints[4]; @@ -1350,6 +1350,7 @@ ints[1]); } } + return 1; } __setup("plip=", plip_setup); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c --- v2.3.99-pre2/linux/drivers/net/rrunner.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/rrunner.c Wed Mar 22 22:23:55 2000 @@ -1650,6 +1650,6 @@ /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" + * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.3.99-pre2/linux/drivers/net/shaper.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/shaper.c Tue Mar 21 14:43:39 2000 @@ -485,20 +485,24 @@ static int shaper_neigh_setup(struct neighbour *n) { +#ifdef CONFIG_INET if (n->nud_state == NUD_NONE) { n->ops = &arp_broken_ops; n->output = n->ops->output; } +#endif return 0; } static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) { +#ifdef CONFIG_INET if (p->tbl->family == AF_INET) { p->neigh_setup = shaper_neigh_setup; p->ucast_probes = 0; p->mcast_probes = 0; } +#endif return 0; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.3.99-pre2/linux/drivers/net/starfire.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/starfire.c Mon Mar 20 07:53:52 2000 @@ -12,10 +12,16 @@ Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html + + LK1.1.1 (jgarzik): + - Use PCI driver interface + - Fix MOD_xxx races + - softnet fixups + */ static const char *versionA = -"starfire.c:v0.12 5/28/99 Written by Donald Becker\n", +"starfire.c:v0.12+LK1.1.1 3/19/2000 Written by Donald Becker and others\n", *versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n"; /* A few user-configurable values. These may be modified when a driver @@ -26,7 +32,6 @@ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; -static int min_pci_latency = 64; static int mtu = 0; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Starfire has a 512 element hash table based on the Ethernet CRC. */ @@ -62,6 +67,9 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +#define PFX "starfire: " + + #if !defined(__OPTIMIZE__) || !defined(__KERNEL__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. @@ -94,7 +102,6 @@ MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(min_pci_latency, "i"); MODULE_PARM(mtu, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); @@ -196,38 +203,33 @@ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; - -static struct net_device *starfire_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chp_idx, int fnd_cnt); #if 0 #define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */ #endif #define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ -static struct pci_id_info pci_tbl[] = { - { "Adaptec Starfire 6915", - 0x9004, 0x6915, 0xffff, PCI_USES_MASTER, 128, starfire_probe1}, - {0,}, /* 0 terminated list. */ + +enum chipset { + CH_6915 = 0, +}; + + +static struct pci_device_id starfire_pci_tbl[] __devinitdata = { + { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 }, + { 0, }, }; +MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); -/* A chip capabilities table, matching the entries in pci_tbl[] above. */ +/* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */ enum chip_capability_flags {CanHaveMII=1, }; -struct chip_info { +static struct chip_info { char *chip_name; int io_size; int flags; - void (*media_timer)(unsigned long data); -} static skel_netdrv_tbl[] = { - {"Adaptec Starfire 6915", 128, CanHaveMII, 0, }, +} netdrv_tbl[] = { + { "Adaptec Starfire 6915", 128, CanHaveMII }, }; @@ -322,8 +324,6 @@ struct starfire_tx_desc *tx_ring; dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; - struct net_device *next_module; /* Link for devices of this type. */ - const char *product_name; /* The addresses of rx/tx-in-place skbuffs. */ struct ring_info rx_info[RX_RING_SIZE]; struct ring_info tx_info[TX_RING_SIZE]; @@ -340,7 +340,6 @@ /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; struct pci_dev *pdev; - unsigned char pci_bus, pci_devfn; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ @@ -378,107 +377,62 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); - - -/* A list of our installed devices, for removing the driver module. */ -static struct net_device *root_net_dev = NULL; -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - cards we know about in slot order. */ - -static int pci_etherdev_probe(struct pci_id_info pci_tbl[]) +static int __devinit starfire_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; + struct netdev_private *np; + int i, irq, option, chip_id = ent->driver_data; struct net_device *dev; - - for (;pci_index < 0xff; pci_index++) { - struct pci_dev *pdev; - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long pciaddr; - long ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pdev = pci_find_slot (pci_bus, pci_device_fn); - if (!pdev) continue; - vendor = pdev->vendor; - device = pdev->device; - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - pciaddr = pdev->resource[0].start; -#if defined(ADDR_64BITS) && defined(__alpha__) - pciaddr |= ((long)pdev->base_address[1]) << 32; -#endif - irq = pdev->irq; - - if (debug > 2) - printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", - pci_tbl[chip_idx].name, pciaddr, irq); - - if ((pci_tbl[chip_idx].flags & PCI_USES_IO)) { - if (check_region(pciaddr, pci_tbl[chip_idx].io_size)) - continue; - ioaddr = pciaddr; - } else if ((ioaddr = (long)ioremap(pciaddr&~0xf, MEM_ADDR_SZ)) == 0) { - printk(KERN_INFO "Failed to map PCI address %#lx.\n", - pciaddr); - continue; - } - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pci_write_config_word(pdev, PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, - irq, chip_idx, cards_found); - - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < min_pci_latency) { - printk(KERN_INFO " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to %d clocks.\n", - pci_latency, min_pci_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); - } - } - cards_found++; + static int card_idx = 0; + static int printed_version = 0; + long ioaddr; + int io_size = netdrv_tbl[chip_id].io_size; + + ioaddr = pci_resource_start (pdev, 0); + if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { + printk (KERN_ERR PFX "no PCI MEM resources, aborting\n"); + return -ENODEV; + } + + dev = init_etherdev(NULL, sizeof(*np)); + if (!dev) { + printk (KERN_ERR PFX "cannot alloc etherdev, aborting\n"); + return -ENOMEM; + } + + irq = pdev->irq; + + if (request_mem_region (ioaddr, io_size, dev->name) == NULL) { + printk (KERN_ERR PFX "resource 0x%x @ 0x%lx busy, aborting\n", + io_size, ioaddr); + goto err_out_free_netdev; + } + + if (pci_enable_device (pdev)) { + printk (KERN_ERR PFX "cannot enable PCI device, aborting\n"); + goto err_out_free_res; + } + + ioaddr = (long) ioremap (ioaddr, io_size); + if (!ioaddr) { + printk (KERN_ERR PFX "cannot remap 0x%x @ 0x%lx, aborting\n", + io_size, ioaddr); + goto err_out_free_res; + } + + pci_set_master (pdev); + + option = card_idx < MAX_UNITS ? options[card_idx] : 0; + card_idx++; + + if (!printed_version) { + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); + printed_version = 1; } - return cards_found ? 0 : -ENODEV; -} - -static struct net_device * -starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_id, int card_idx) -{ - struct netdev_private *np; - int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - struct net_device *dev = init_etherdev(NULL, 0); - - if (!dev) - return NULL; - - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); + printk (KERN_INFO "%s: %s at 0x%lx, ", + dev->name, netdrv_tbl[chip_id].chip_name, ioaddr); /* Serial EEPROM reads are hidden by the hardware. */ for (i = 0; i < 6; i++) @@ -500,18 +454,13 @@ dev->base_addr = ioaddr; dev->irq = irq; - /* Make certain the descriptor lists are aligned. */ - np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 15) & ~15); - memset(np, 0, sizeof(*np)); - dev->priv = np; - - np->next_module = root_net_dev; - root_net_dev = dev; + /* private struct aligned and zeroed by init_etherdev */ + np = dev->priv; np->pdev = pdev; - np->pci_bus = pci_bus; - np->pci_devfn = pci_devfn; np->chip_id = chip_id; + + pdev->driver_data = dev; if (dev->mem_start) option = dev->mem_start; @@ -533,7 +482,7 @@ /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; - dev->tx_timeout = tx_timeout; + dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &netdev_close; dev->get_stats = &get_stats; @@ -543,7 +492,7 @@ if (mtu) dev->mtu = mtu; - if (skel_netdrv_tbl[np->chip_id].flags & CanHaveMII) { + if (netdrv_tbl[np->chip_id].flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); @@ -558,7 +507,14 @@ np->mii_cnt = phy_idx; } - return dev; + return 0; + +err_out_free_res: + release_mem_region (ioaddr, io_size); +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; } @@ -590,10 +546,13 @@ long ioaddr = dev->base_addr; int i; + MOD_INC_USE_COUNT; /* Do we need to reset the chip??? */ - if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) - return -EAGAIN; + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } /* Disable the Rx and Tx, and reset the chip. */ writel(0, ioaddr + GenCtrl); @@ -624,11 +583,10 @@ if (np->rx_ring) pci_free_consistent(np->pdev, PAGE_SIZE, np->rx_ring, np->rx_ring_dma); + MOD_DEC_USE_COUNT; return -ENOMEM; } - MOD_INC_USE_COUNT; - init_ring(dev); /* Set the size of the Rx buffers. */ writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl); @@ -691,6 +649,8 @@ /* Enable the Rx and Tx units. */ writel(0x000F, ioaddr + GenCtrl); + netif_start_queue(dev); + if (debug > 2) printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); @@ -762,6 +722,7 @@ add_timer(&np->timer); } + static void tx_timeout(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -783,15 +744,16 @@ } #endif - /* Perhaps we should reinitialize the hardware here. */ - dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - - /* Trigger an immediate transmit demand. */ - - netif_wake_queue(dev); - np->stats.tx_errors++; - return; + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + + /* Stop and restart the chip's Tx processes . */ + /* XXX todo */ + + /* Trigger an immediate transmit demand. */ + /* XXX todo */ + + np->stats.tx_errors++; } @@ -849,8 +811,6 @@ struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; - netif_stop_queue(dev); - /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -883,10 +843,10 @@ /* Update the producer index. */ writel(++entry, dev->base_addr + TxProducerIdx); - if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) + if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) { np->tx_full = 1; - if (! np->tx_full) - netif_start_queue(dev); + netif_stop_queue(dev); + } dev->trans_start = jiffies; if (debug > 4) { @@ -1347,56 +1307,69 @@ return 0; } -static int __init starfire_init_module (void) + +static void __devexit starfire_remove_one (struct pci_dev *pdev) { - if (debug) /* Emit version even if no cards detected. */ - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); -#ifdef CARDBUS - register_driver(ðerdev_ops); - return 0; -#else - if (pci_etherdev_probe(pci_tbl)) { - printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n"); - return -ENODEV; + struct net_device *dev = pdev->driver_data; + struct netdev_private *np; + + if (!dev) { + printk (KERN_WARNING "bug: removing starfire pci dev without driver\n"); + return; } - return 0; -#endif + + np = dev->priv; + + unregister_netdev(dev); + iounmap((char *)dev->base_addr); + + if (np->tx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_done_q, np->tx_done_q_dma); + if (np->rx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_done_q, np->rx_done_q_dma); + if (np->tx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_ring, np->tx_ring_dma); + if (np->rx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_ring, np->rx_ring_dma); + + kfree(dev); } -static void __exit starfire_cleanup_module (void) + +static struct pci_driver starfire_driver = { + name: "starfire", + probe: starfire_init_one, + remove: starfire_remove_one, + id_table: starfire_pci_tbl, +}; + + +static int __init starfire_init (void) { - struct net_device *next_dev; + int rc; + + MOD_INC_USE_COUNT; + + rc = pci_module_init (&starfire_driver); + + MOD_DEC_USE_COUNT; + + return rc; +} -#ifdef CARDBUS - unregister_driver(ðerdev_ops); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_net_dev) { - struct netdev_private *np = - (struct netdev_private *)root_net_dev->priv; - next_dev = np->next_module; - unregister_netdev(root_net_dev); - iounmap((char *)root_net_dev->base_addr); - if (np->tx_done_q) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->tx_done_q, np->tx_done_q_dma); - if (np->rx_done_q) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->rx_done_q, np->rx_done_q_dma); - if (np->tx_ring) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->tx_ring, np->tx_ring_dma); - if (np->rx_ring) - pci_free_consistent(np->pdev, PAGE_SIZE, - np->rx_ring, np->rx_ring_dma); - kfree(root_net_dev); - root_net_dev = next_dev; - } +static void __exit starfire_cleanup (void) +{ + pci_unregister_driver (&starfire_driver); } -module_init(starfire_init_module); -module_exit(starfire_cleanup_module); + +module_init(starfire_init); +module_exit(starfire_cleanup); /* diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.3.99-pre2/linux/drivers/net/tlan.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/tlan.c Wed Mar 22 09:38:14 2000 @@ -66,6 +66,12 @@ * network cleanup in 2.3.43pre7 (Tigran & myself) * - Minor stuff. * + * v1.5 March 22, 2000 - Fixed another timer bug that would hang the driver + * if no cable/link were present. + * - Cosmetic changes. + * - TODO: Port completely to new PCI/DMA API + * Auto-Neg fallback. + * *******************************************************************************/ @@ -106,7 +112,7 @@ static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; static int TLanVersionMajor = 1; -static int TLanVersionMinor = 4; +static int TLanVersionMinor = 5; static TLanAdapterEntry TLanAdapterList[] __initdata = { @@ -430,7 +436,8 @@ } - printk(KERN_INFO "TLAN: %d device(s) installed\n", TLanDevicesInstalled); + printk(KERN_INFO "TLAN: %d device%s installed\n", + TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s"); return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV); } @@ -839,8 +846,10 @@ TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); - if ( priv->timer.function != NULL ) + if ( priv->timer.function != NULL ) { del_timer( &priv->timer ); + priv->timer.function = NULL; + } free_irq( dev->irq, dev ); TLan_FreeLists( dev ); TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name ); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c --- v2.3.99-pre2/linux/drivers/net/tokenring/lanstreamer.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/tokenring/lanstreamer.c Tue Mar 21 14:43:39 2000 @@ -58,6 +58,7 @@ * First release to the public * 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing * malloc free checks, reviewed code. + * 03/13/00 - Added spinlocks for smp * * To Do: * @@ -105,6 +106,7 @@ #include #include #include +#include #include #include @@ -121,7 +123,7 @@ * Official releases will only have an a.b.c version number format. */ -static char *version = "LanStreamer.c v0.1.0 12/10/99 - Mike Sullivan"; +static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan"; static char *open_maj_error[] = { "No error", "Lobe Media Test", "Physical Insertion", @@ -210,7 +212,7 @@ /* Check to see if io has been allocated, if so, we've already done this card, so continue on the card discovery loop */ - if (check_region(pci_device->resource[0].start, STREAMER_IO_SPACE)) + if (check_region(pci_device->resource[0].start & (~3), STREAMER_IO_SPACE)) { card_no++; continue; @@ -223,6 +225,8 @@ break; } memset(streamer_priv, 0, sizeof(struct streamer_private)); + init_waitqueue_head(&streamer_priv->srb_wait); + init_waitqueue_head(&streamer_priv->trb_wait); #ifndef MODULE dev = init_trdev(dev, 0); if(dev==NULL) @@ -238,11 +242,11 @@ pci_device, dev, dev->priv); #endif dev->irq = pci_device->irq; - dev->base_addr = pci_device->resource[0].start; + dev->base_addr = pci_device->resource[0].start & (~3); dev->init = &streamer_init; + streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name; streamer_priv->streamer_mmio = ioremap(pci_device->resource[1].start, 256); - init_waitqueue_head(&streamer_priv->srb_wait); - init_waitqueue_head(&streamer_priv->trb_wait); + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) streamer_priv->pkt_buf_sz = PKT_BUF_SZ; else @@ -250,7 +254,6 @@ streamer_priv->streamer_ring_speed = ringspeed[card_no]; streamer_priv->streamer_message_level = message_level[card_no]; - streamer_priv->streamer_multicast_set = 0; if (streamer_init(dev) == -1) { unregister_netdevice(dev); @@ -274,7 +277,7 @@ } -static int __init streamer_init(struct net_device *dev) +static int streamer_reset(struct net_device *dev) { struct streamer_private *streamer_priv; __u8 *streamer_mmio; @@ -286,12 +289,6 @@ streamer_priv = (struct streamer_private *) dev->priv; streamer_mmio = streamer_priv->streamer_mmio; - printk("%s \n", version); - printk(KERN_INFO "%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, using irq %d\n", - dev->name, (unsigned int) dev->base_addr, - streamer_priv->streamer_mmio, dev->irq); - - request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer"); writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL); t = jiffies; /* Hold soft reset bit for a while */ @@ -330,11 +327,16 @@ printk(KERN_INFO "%s: skb allocation for diagnostics failed...proceeding\n", dev->name); } else { - streamer_priv->streamer_rx_ring[0].forward = 0; - streamer_priv->streamer_rx_ring[0].status = 0; - streamer_priv->streamer_rx_ring[0].buffer = virt_to_bus(skb->data); - streamer_priv->streamer_rx_ring[0].framelen_buflen = 512; /* streamer_priv->pkt_buf_sz; */ - writel(virt_to_bus(&streamer_priv->streamer_rx_ring[0]), streamer_mmio + RXBDA); + struct streamer_rx_desc *rx_ring; + u8 *data; + + rx_ring=(struct streamer_rx_desc *)skb->data; + data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc); + rx_ring->forward=0; + rx_ring->status=0; + rx_ring->buffer=virt_to_bus(data); + rx_ring->framelen_buflen=512; + writel(virt_to_bus(rx_ring),streamer_mmio+RXBDA); } #if STREAMER_DEBUG @@ -382,7 +384,7 @@ writew(readw(streamer_mmio + LAPWWO) + 6, streamer_mmio + LAPA); if (readw(streamer_mmio + LAPD)) { printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n", - readw(streamer_mmio + LAPD)); + ntohs(readw(streamer_mmio + LAPD))); release_region(dev->base_addr, STREAMER_IO_SPACE); return -1; } @@ -398,17 +400,14 @@ #endif /* setup uaa area for access with LAPD */ - writew(uaa_addr, streamer_mmio + LAPA); - - /* setup uaa area for access with LAPD */ { int i; __u16 addr; writew(uaa_addr, streamer_mmio + LAPA); for (i = 0; i < 6; i += 2) { - addr = readw(streamer_mmio + LAPDINC); - dev->dev_addr[i] = addr & 0xff; - dev->dev_addr[i + 1] = (addr >> 8) & 0xff; + addr=ntohs(readw(streamer_mmio+LAPDINC)); + dev->dev_addr[i]= (addr >> 8) & 0xff; + dev->dev_addr[i+1]= addr & 0xff; } #if STREAMER_DEBUG printk("Adapter address: "); @@ -421,6 +420,32 @@ return 0; } +static int __init streamer_init(struct net_device *dev) +{ + struct streamer_private *streamer_priv; + __u8 *streamer_mmio; + int rc; + + streamer_priv=(struct streamer_private *)dev->priv; + streamer_mmio=streamer_priv->streamer_mmio; + + spin_lock_init(&streamer_priv->streamer_lock); + + printk("%s \n", version); + printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, + streamer_priv->streamer_card_name, + (unsigned int) dev->base_addr, + streamer_priv->streamer_mmio, + dev->irq); + + request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer"); + + rc=streamer_reset(dev); + return rc; +} + + + static int streamer_open(struct net_device *dev) { struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; @@ -430,7 +455,11 @@ int i, open_finished = 1; __u16 srb_word; __u16 srb_open; + int rc; + if (readw(streamer_mmio+BMCTL_SUM) & BMCTL_RX_ENABLED) { + rc=streamer_reset(dev); + } if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "streamer", dev)) { return -EAGAIN; @@ -461,23 +490,27 @@ writew(0, streamer_mmio + LAPDINC); } - writew(readw(streamer_mmio + LAPWWO), streamer_mmio + LAPA); - writew(SRB_OPEN_ADAPTER, streamer_mmio + LAPDINC); /* open */ + writew(readw(streamer_mmio+LAPWWO),streamer_mmio+LAPA); + writew(htons(SRB_OPEN_ADAPTER<<8),streamer_mmio+LAPDINC) ; /* open */ + writew(htons(STREAMER_CLEAR_RET_CODE<<8),streamer_mmio+LAPDINC); writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); writew(readw(streamer_mmio + LAPWWO) + 8, streamer_mmio + LAPA); #if STREAMER_NETWORK_MONITOR /* If Network Monitor, instruct card to copy MAC frames through the ARB */ - writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */ + writew(htons(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */ #else - writew(ntohs(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */ + writew(htons(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */ #endif if (streamer_priv->streamer_laa[0]) { writew(readw(streamer_mmio + LAPWWO) + 12, streamer_mmio + LAPA); - writew(((__u16 *) (streamer_priv->streamer_laa))[0], streamer_mmio + LAPDINC); /* offset 12 word */ - writew(((__u16 *) (streamer_priv->streamer_laa))[2], streamer_mmio + LAPDINC); /* offset 14 word */ - writew(((__u16 *) (streamer_priv->streamer_laa))[4], streamer_mmio + LAPDINC); /* offset 16 word */ + writew(htons((streamer_priv->streamer_laa[0] << 8) | + streamer_priv->streamer_laa[1]),streamer_mmio+LAPDINC); + writew(htons((streamer_priv->streamer_laa[2] << 8) | + streamer_priv->streamer_laa[3]),streamer_mmio+LAPDINC); + writew(htons((streamer_priv->streamer_laa[4] << 8) | + streamer_priv->streamer_laa[5]),streamer_mmio+LAPDINC); memcpy(dev->dev_addr, streamer_priv->streamer_laa, dev->addr_len); } @@ -526,7 +559,7 @@ * timed out. */ writew(srb_open + 2, streamer_mmio + LAPA); - srb_word = readw(streamer_mmio + LAPD) & 0xFF; + srb_word = ntohs(readw(streamer_mmio + LAPD)) & 0xFF; if (srb_word == STREAMER_CLEAR_RET_CODE) { printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name); @@ -574,7 +607,7 @@ } while (!(open_finished)); /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ writew(srb_open + 18, streamer_mmio + LAPA); - srb_word = readw(streamer_mmio + LAPD) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8; if (srb_word & (1 << 3)) if (streamer_priv->streamer_message_level) printk(KERN_INFO "%s: Opened in FDX Mode\n", dev->name); @@ -604,6 +637,14 @@ writew(~BMCTL_RX_DIS, streamer_mmio + BMCTL_RUM); /* setup rx descriptors */ + streamer_priv->streamer_rx_ring= + kmalloc( sizeof(struct streamer_rx_desc)* + STREAMER_RX_RING_SIZE,GFP_KERNEL); + if (!streamer_priv->streamer_rx_ring) { + printk(KERN_WARNING "%s ALLOC of streamer rx ring FAILED!!\n",dev->name); + return -EIO; + } + for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { struct sk_buff *skb; @@ -638,6 +679,13 @@ /* setup tx ring */ + streamer_priv->streamer_tx_ring=kmalloc(sizeof(struct streamer_tx_desc)* + STREAMER_TX_RING_SIZE,GFP_KERNEL); + if (!streamer_priv->streamer_tx_ring) { + printk(KERN_WARNING "%s ALLOC of streamer_tx_ring FAILED\n",dev->name); + return -EIO; + } + writew(~BMCTL_TX2_DIS, streamer_mmio + BMCTL_RUM); /* Enables TX channel 2 */ for (i = 0; i < STREAMER_TX_RING_SIZE; i++) { streamer_priv->streamer_tx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_tx_ring[i + 1]); @@ -776,7 +824,7 @@ memcpy(skb_put(skb, length),bus_to_virt(rx_desc->buffer), length); /* copy this fragment */ streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0; streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz; - streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = virt_to_bus(skb->data); + /* give descriptor back to the adapter */ writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]), streamer_mmio + RXLBDA); @@ -828,10 +876,14 @@ misr = readw(streamer_mmio + MISR_RUM); writew(~misr, streamer_mmio + MISR_RUM); - if (!sisr) { /* Interrupt isn't for us */ + if (!sisr) + { /* Interrupt isn't for us */ + writew(~misr,streamer_mmio+MISR_RUM); return; } + spin_lock(&streamer_priv->streamer_lock); + if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY)) || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) { if (sisr & SISR_SRB_REPLY) { @@ -868,9 +920,9 @@ writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA); printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n", dev->name, readw(streamer_mmio + LAPDINC), - readw(streamer_mmio + LAPDINC), - readw(streamer_mmio + LAPDINC), - readw(streamer_mmio + LAPDINC)); + ntohs(readw(streamer_mmio + LAPDINC)), + ntohs(readw(streamer_mmio + LAPDINC)), + ntohs(readw(streamer_mmio + LAPDINC))); free_irq(dev->irq, dev); } @@ -907,17 +959,19 @@ } /* One if the interrupts we want */ writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); + spin_unlock(&streamer_priv->streamer_lock) ; } - static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) { struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; __u8 *streamer_mmio = streamer_priv->streamer_mmio; + unsigned long flags ; + spin_lock_irqsave(&streamer_priv->streamer_lock, flags); netif_stop_queue(dev); - + if (streamer_priv->free_tx_ring_entries) { streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len; @@ -941,9 +995,11 @@ writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA); streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); - netif_start_queue(dev); + netif_wake_queue(dev); + spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 0; } else { + spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 1; } } @@ -957,9 +1013,10 @@ unsigned long flags; int i; + netif_stop_queue(dev); writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(SRB_CLOSE_ADAPTER, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); + writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); save_flags(flags); cli(); @@ -987,7 +1044,9 @@ streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { - dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]); + if (streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]) { + dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]); + } streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); } @@ -1003,11 +1062,10 @@ writew(streamer_priv->srb, streamer_mmio + LAPA); printk("srb): "); for (i = 0; i < 2; i++) { - printk("%x ", htons(readw(streamer_mmio + LAPDINC))); + printk("%x ", ntohs(readw(streamer_mmio + LAPDINC))); } printk("\n"); #endif - netif_stop_queue(dev); free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; @@ -1019,9 +1077,10 @@ struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; __u8 *streamer_mmio = streamer_priv->streamer_mmio; - __u8 options = 0, set_mc_list = 0; - __u16 ata1, ata2; + __u8 options = 0; struct dev_mc_list *dmi; + unsigned char dev_mc_address[5]; + int i; writel(streamer_priv->srb, streamer_mmio + LAPA); options = streamer_priv->streamer_copy_all_options; @@ -1031,23 +1090,17 @@ 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 ^ streamer_priv->streamer_copy_all_options)) { /* Now to issue the srb command to alter the copy.all.options */ - - writew(SRB_MODIFY_RECEIVE_OPTIONS, - streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); - writew(streamer_priv->streamer_receive_options | (options << 8), streamer_mmio + LAPDINC); - writew(0x414a, streamer_mmio + LAPDINC); - writew(0x454d, streamer_mmio + LAPDINC); - writew(0x2053, streamer_mmio + LAPDINC); + writew(htons(SRB_MODIFY_RECEIVE_OPTIONS << 8), streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); + writew(htons((streamer_priv->streamer_receive_options << 8) | options),streamer_mmio+LAPDINC); + writew(htons(0x4a41),streamer_mmio+LAPDINC); + writew(htons(0x4d45),streamer_mmio+LAPDINC); + writew(htons(0x5320),streamer_mmio+LAPDINC); writew(0x2020, streamer_mmio + LAPDINC); streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ @@ -1058,54 +1111,25 @@ return; } - if (set_mc_list ^ streamer_priv->streamer_multicast_set) - { /* Multicast options have changed */ - dmi = dev->mc_list; - - writel(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); - ata1 = readw(streamer_mmio + LAPDINC); - ata2 = readw(streamer_mmio + LAPD); - - writel(streamer_priv->srb, streamer_mmio + LAPA); - - 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. - */ - - if (!(ata1 & 0x0400)) { /* need to set functional mask */ - writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); - writew(0, streamer_mmio + LAPDINC); - writew(ata1 | 0x0400, streamer_mmio + LAPDINC); - writew(ata2, streamer_mmio + LAPD); - - streamer_priv->srb_queued = 2; - writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - - streamer_priv->streamer_multicast_set = 1; - } - - } else { /* Turn multicast off */ - - if ((ata1 & 0x0400)) { /* Hmmm, need to reset the functional mask */ - writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); - writew(0, streamer_mmio + LAPDINC); - writew(ata1 & ~0x0400, streamer_mmio + LAPDINC); - writew(ata2, streamer_mmio + LAPD); - - streamer_priv->srb_queued = 2; - writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - - streamer_priv->streamer_multicast_set = 0; - } - } - - } + /* Set the functional addresses we need for multicast */ + writel(streamer_priv->srb,streamer_mmio+LAPA); + dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; + + for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) + { + dev_mc_address[0] |= dmi->dmi_addr[2] ; + dev_mc_address[1] |= dmi->dmi_addr[3] ; + dev_mc_address[2] |= dmi->dmi_addr[4] ; + dev_mc_address[3] |= dmi->dmi_addr[5] ; + } + + writew(htons(SRB_SET_FUNC_ADDRESS << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); + writew(0,streamer_mmio+LAPDINC); + writew(htons( (dev_mc_address[0] << 8) | dev_mc_address[1]),streamer_mmio+LAPDINC); + writew(htons( (dev_mc_address[2] << 8) | dev_mc_address[3]),streamer_mmio+LAPDINC); + streamer_priv->srb_queued = 2 ; + writel(LISR_SRB_CMD,streamer_mmio+LISR_SUM); } static void streamer_srb_bh(struct net_device *dev) @@ -1115,7 +1139,7 @@ __u16 srb_word; writew(streamer_priv->srb, streamer_mmio + LAPA); - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { @@ -1125,7 +1149,8 @@ */ case SRB_MODIFY_RECEIVE_OPTIONS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; + switch (srb_word) { case 0x01: printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name); @@ -1147,11 +1172,10 @@ /* SRB_SET_GROUP_ADDRESS - Multicast group setting */ case SRB_SET_GROUP_ADDRESS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: - streamer_priv->streamer_multicast_set = 1; - break; + break; case 0x01: printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name); break; @@ -1176,11 +1200,10 @@ /* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list */ case SRB_RESET_GROUP_ADDRESS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: - streamer_priv->streamer_multicast_set = 0; - break; + break; case 0x01: printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name); break; @@ -1200,7 +1223,7 @@ */ case SRB_SET_FUNC_ADDRESS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: if (streamer_priv->streamer_message_level) @@ -1221,7 +1244,7 @@ */ case SRB_READ_LOG: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: { @@ -1250,7 +1273,7 @@ /* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */ case SRB_READ_SR_COUNTERS: - srb_word = readw(streamer_mmio + LAPDINC) & 0xFF; + srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; switch (srb_word) { case 0x00: if (streamer_priv->streamer_message_level) @@ -1285,9 +1308,10 @@ struct sockaddr *saddr = addr; struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; - if (netif_running(dev)) { + if (netif_running(dev)) + { printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name); - return -EBUSY; + return -EIO; } memcpy(streamer_priv->streamer_laa, saddr->sa_data, dev->addr_len); @@ -1324,12 +1348,12 @@ #endif writew(streamer_priv->arb, streamer_mmio + LAPA); - arb_word = readw(streamer_mmio + LAPD) & 0xFF; - + arb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8; + if (arb_word == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ writew(streamer_priv->arb + 6, streamer_mmio + LAPA); streamer_priv->mac_rx_buffer = buff_off = ntohs(readw(streamer_mmio + LAPDINC)); - header_len = readw(streamer_mmio + LAPDINC) & 0xff; /* 802.5 Token-Ring Header Length */ + header_len=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; /* 802.5 Token-Ring Header Length */ frame_len = ntohs(readw(streamer_mmio + LAPDINC)); #if STREAMER_DEBUG @@ -1340,7 +1364,7 @@ __u16 len; writew(ntohs(buff_off), streamer_mmio + LAPA); /*setup window to frame data */ - next = ntohs(readw(streamer_mmio + LAPDINC)); + next = htons(readw(streamer_mmio + LAPDINC)); status = ntohs(readw(streamer_mmio + LAPDINC)) & 0xff; len = ntohs(readw(streamer_mmio + LAPDINC)); @@ -1364,7 +1388,7 @@ int i; __u16 rx_word; - writew(ntohs(buff_off), streamer_mmio + LAPA); /* setup window to frame data */ + writew(htons(buff_off), streamer_mmio + LAPA); /* setup window to frame data */ next_ptr = ntohs(readw(streamer_mmio + LAPDINC)); readw(streamer_mmio + LAPDINC); /* read thru status word */ buffer_len = ntohs(readw(streamer_mmio + LAPDINC)); @@ -1374,9 +1398,9 @@ i = 0; while (i < buffer_len) { - rx_word = readw(streamer_mmio + LAPDINC); - frame_data[i] = rx_word & 0xff; - frame_data[i + 1] = (rx_word >> 8) & 0xff; + rx_word=ntohs(readw(streamer_mmio+LAPDINC)); + frame_data[i]=rx_word >> 8; + frame_data[i+1]=rx_word & 0xff; i += 2; } @@ -1420,10 +1444,10 @@ writew(streamer_priv->asb, streamer_mmio + LAPA); - writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */ - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */ + writew(htons(ASB_RECEIVE_DATA << 8), streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); writew(0, streamer_mmio + LAPDINC); - writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); + writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM); @@ -1433,12 +1457,13 @@ } else if (arb_word == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */ writew(streamer_priv->arb + 6, streamer_mmio + LAPA); lan_status = ntohs(readw(streamer_mmio + LAPDINC)); - fdx_prot_error = readw(streamer_mmio + LAPD) & 0xFF; - + fdx_prot_error = ntohs(readw(streamer_mmio+LAPD)) >> 8; + /* Issue ARB Free */ writew(LISR_ARB_FREE, streamer_priv->streamer_mmio + LISR_SUM); - lan_status_diff = streamer_priv->streamer_lan_status ^ lan_status; + lan_status_diff = (streamer_priv->streamer_lan_status ^ lan_status) & + lan_status; if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR)) { @@ -1489,8 +1514,8 @@ /* Issue READ.LOG command */ writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(SRB_READ_LOG, streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); + writew(htons(SRB_READ_LOG << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); writew(0, streamer_mmio + LAPDINC); streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ @@ -1503,10 +1528,10 @@ /* Issue a READ.SR.COUNTERS */ writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(SRB_READ_SR_COUNTERS, - streamer_mmio + LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, - streamer_mmio + LAPDINC); + writew(htons(SRB_READ_SR_COUNTERS << 8), + streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), + streamer_mmio+LAPDINC); streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); @@ -1528,10 +1553,10 @@ /* Dropped through the first time */ writew(streamer_priv->asb, streamer_mmio + LAPA); - writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */ - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */ + writew(htons(ASB_RECEIVE_DATA << 8),streamer_mmio+LAPDINC); + writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); writew(0, streamer_mmio + LAPDINC); - writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); + writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM); streamer_priv->asb_queued = 2; @@ -1542,7 +1567,7 @@ if (streamer_priv->asb_queued == 2) { __u8 rc; writew(streamer_priv->asb + 2, streamer_mmio + LAPA); - rc = readw(streamer_mmio + LAPD) & 0xff; + rc=ntohs(readw(streamer_mmio+LAPD)) >> 8; switch (rc) { case 0x01: printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name); @@ -1594,7 +1619,7 @@ off_t pos = 0; int size; - struct net_device *dev; + struct device *dev; size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n"); @@ -1607,8 +1632,8 @@ for (dev = dev_base; dev != NULL; dev = dev->next) { - if (dev->base_addr == (pci_device->base_address[0] & (~3))) - { /* Yep, a Streamer device */ + if (dev->base_addr == pci_device->resource[0].start) + { /* Yep, a Streamer device */ size = sprintf_info(buffer + len, dev); len += size; pos = begin + len; @@ -1644,17 +1669,17 @@ for (i = 0; i < 14; i += 2) { __u16 io_word; __u8 *datap = (__u8 *) & sat; - io_word = readw(streamer_mmio + LAPDINC); - datap[size] = io_word & 0xff; - datap[size + 1] = (io_word >> 8) & 0xff; + io_word=ntohs(readw(streamer_mmio+LAPDINC)); + datap[size]=io_word >> 8; + datap[size+1]=io_word & 0xff; } writew(streamer_priv->streamer_parms_addr, streamer_mmio + LAPA); for (i = 0; i < 68; i += 2) { __u16 io_word; __u8 *datap = (__u8 *) & spt; - io_word = readw(streamer_mmio + LAPDINC); - datap[size] = io_word & 0xff; - datap[size + 1] = (io_word >> 8) & 0xff; + io_word=ntohs(readw(streamer_mmio+LAPDINC)); + datap[size]=io_word >> 8; + datap[size+1]=io_word & 0xff; } @@ -1723,10 +1748,7 @@ #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent; - - ent = create_proc_entry("net/streamer_tr", 0, 0); - ent->read_proc = &streamer_proc_info; + create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); #endif #endif for (i = 0; (i < STREAMER_MAX_ADAPTERS); i++) @@ -1758,11 +1780,17 @@ void cleanup_module(void) { int i; + struct streamer_private *streamer_priv; for (i = 0; i < STREAMER_MAX_ADAPTERS; i++) if (dev_streamer[i]) { unregister_trdev(dev_streamer[i]); release_region(dev_streamer[i]->base_addr, STREAMER_IO_SPACE); + streamer_priv=(struct streamer_private *)dev_streamer[i]->priv; + kfree_s(streamer_priv->streamer_rx_ring, + sizeof(struct streamer_rx_desc)*STREAMER_RX_RING_SIZE); + kfree_s(streamer_priv->streamer_tx_ring, + sizeof(struct streamer_tx_desc)*STREAMER_TX_RING_SIZE); kfree_s(dev_streamer[i]->priv, sizeof(struct streamer_private)); kfree_s(dev_streamer[i], sizeof(struct net_device)); dev_streamer[i] = NULL; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tokenring/lanstreamer.h linux/drivers/net/tokenring/lanstreamer.h --- v2.3.99-pre2/linux/drivers/net/tokenring/lanstreamer.h Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/tokenring/lanstreamer.h Tue Mar 21 14:43:39 2000 @@ -132,6 +132,7 @@ #define BMCTL_TX1_DIS (1<<14) #define BMCTL_TX2_DIS (1<<10) #define BMCTL_RX_DIS (1<<6) +#define BMCTL_RX_ENABLED (1<<5) #define RXLBDA 0x90 #define RXBDA 0x94 @@ -257,6 +258,9 @@ __u16 asb; __u8 *streamer_mmio; + char *streamer_card_name; + + spinlock_t streamer_lock; volatile int srb_queued; /* True if an SRB is still posted */ wait_queue_head_t srb_wait; @@ -264,10 +268,10 @@ 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; + wait_queue_head_t trb_wait; - struct streamer_rx_desc streamer_rx_ring[STREAMER_RX_RING_SIZE]; - struct streamer_tx_desc streamer_tx_ring[STREAMER_TX_RING_SIZE]; + struct streamer_rx_desc *streamer_rx_ring; + struct streamer_tx_desc *streamer_tx_ring; struct sk_buff *tx_ring_skb[STREAMER_TX_RING_SIZE], *rx_ring_skb[STREAMER_RX_RING_SIZE]; int tx_ring_free, tx_ring_last_status, rx_ring_last_received, @@ -279,7 +283,6 @@ __u16 pkt_buf_sz; __u8 streamer_receive_options, streamer_copy_all_options, streamer_message_level; - __u8 streamer_multicast_set; __u16 streamer_addr_table_addr, streamer_parms_addr; __u16 mac_rx_buffer; __u8 streamer_laa[6]; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.3.99-pre2/linux/drivers/net/tulip/21142.c Sat Feb 26 22:31:47 2000 +++ linux/drivers/net/tulip/21142.c Tue Mar 21 12:39:17 2000 @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/eeprom.c linux/drivers/net/tulip/eeprom.c --- v2.3.99-pre2/linux/drivers/net/tulip/eeprom.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/tulip/eeprom.c Tue Mar 21 12:39:17 2000 @@ -15,7 +15,6 @@ #include "tulip.h" #include -#include #include @@ -30,31 +29,31 @@ /* Known cards that have old-style EEPROMs. */ static struct eeprom_fixup eeprom_fixups[] __devinitdata = { {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, - 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0903, 0x006D, /* 100baseTx */ - 0x0905, 0x006D, /* 100baseTx-FD */ }}, + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0903, 0x006D, /* 100baseTx */ + 0x0905, 0x006D, /* 100baseTx-FD */ }}, {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, - 0x0107, 0x8021, /* 100baseFx */ - 0x0108, 0x8021, /* 100baseFx-FD */ - 0x0100, 0x009E, /* 10baseT */ - 0x0104, 0x009E, /* 10baseT-FD */ - 0x0103, 0x006D, /* 100baseTx */ - 0x0105, 0x006D, /* 100baseTx-FD */ }}, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0100, 0x009E, /* 10baseT */ + 0x0104, 0x009E, /* 10baseT-FD */ + 0x0103, 0x006D, /* 100baseTx */ + 0x0105, 0x006D, /* 100baseTx-FD */ }}, {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, - 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ - 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ + 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, - 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ - 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ - 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ - 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ - 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ }}, {"NetWinder", 0x00, 0x10, 0x57, /* Default media = MII diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c --- v2.3.99-pre2/linux/drivers/net/tulip/interrupt.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/tulip/interrupt.c Tue Mar 21 12:39:17 2000 @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include #include #include @@ -211,9 +210,12 @@ if (status < 0) break; /* It still has not been Txed */ + /* Check for Rx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { - pci_unmap_single(tp->pdev, + /* test because dummy frames not mapped */ + if (tp->tx_buffers[entry].mapping) + pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c --- v2.3.99-pre2/linux/drivers/net/tulip/media.c Sat Feb 26 22:31:47 2000 +++ linux/drivers/net/tulip/media.c Tue Mar 21 12:39:17 2000 @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include /* This is a mysterious value that can be written to CSR11 in the 21040 (only) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c --- v2.3.99-pre2/linux/drivers/net/tulip/pnic.c Sat Feb 26 22:31:47 2000 +++ linux/drivers/net/tulip/pnic.c Tue Mar 21 12:39:17 2000 @@ -15,7 +15,6 @@ #include #include "tulip.h" -#include void pnic_do_nway(struct net_device *dev) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c --- v2.3.99-pre2/linux/drivers/net/tulip/timer.c Sat Feb 26 22:31:47 2000 +++ linux/drivers/net/tulip/timer.c Tue Mar 21 12:39:17 2000 @@ -14,7 +14,6 @@ */ #include "tulip.h" -#include void tulip_timer(unsigned long data) @@ -87,7 +86,11 @@ break; } break; - case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { + case DC21140: + case DC21142: + case MX98713: + case COMPEX9881: + default: { struct medialeaf *mleaf; unsigned char *p; if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.3.99-pre2/linux/drivers/net/tulip/tulip.h Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/tulip/tulip.h Tue Mar 21 12:39:17 2000 @@ -17,7 +17,7 @@ #include #include #include - +#include struct tulip_chip_table { char *chip_name; @@ -36,8 +36,10 @@ HAS_ACPI = 0x10, MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */ HAS_PNICNWAY = 0x80, - HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */ - HAS_8023X = 0x100, + HAS_NWAY = 0x40, /* Uses internal NWay xcvr. */ + HAS_INTR_MITIGATION = 0x100, + IS_ASIX = 0x200, + HAS_8023X = 0x400, }; @@ -58,7 +60,6 @@ COMET, COMPEX9881, I21145, - X3201_3, }; @@ -137,6 +138,17 @@ }; +enum t21041_csr13_bits { + csr13_eng = (0xEF0<<4), /* for eng. purposes only, hardcode at EF0h */ + csr13_aui = (1<<3), /* clear to force 10bT, set to force AUI/BNC */ + csr13_cac = (1<<2), /* CSR13/14/15 autoconfiguration */ + csr13_srl = (1<<0), /* When reset, resets all SIA functions, machines */ + + csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_cac | csr13_srl), + csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl), +}; + + /* Keep the ring sizes a power of two for efficiency. Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. @@ -334,7 +346,14 @@ extern u16 t21041_csr13[]; extern u16 t21041_csr14[]; extern u16 t21041_csr15[]; -void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6); + + +extern inline void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) +{ + long ioaddr = tp->base_addr; + + outl (newcsr6, ioaddr + CSR6); +} #endif /* __NET_TULIP_H__ */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.3.99-pre2/linux/drivers/net/tulip/tulip_core.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/tulip/tulip_core.c Tue Mar 21 12:39:17 2000 @@ -19,7 +19,7 @@ */ -static const char version[] = "Linux Tulip driver version 0.9.4 (Feb 28, 2000)\n"; +static const char version[] = "Linux Tulip driver version 0.9.4.2 (Mar 21, 2000)\n"; #include #include "tulip.h" @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -92,9 +91,6 @@ #define TX_TIMEOUT (4*HZ) -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - MODULE_AUTHOR("The Linux Kernel Team"); MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); MODULE_PARM(tulip_debug, "i"); @@ -123,12 +119,13 @@ struct tulip_chip_table tulip_tbl[] = { { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, - { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, + { "Digital DC21041 Tulip", 128, 0x0001ebef, + HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer }, { "Digital DS21140 Tulip", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, { "Digital DS21143 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY + | HAS_INTR_MITIGATION, t21142_timer }, { "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII | HAS_PNICNWAY, pnic_timer }, { "Macronix 98713 PMAC", 128, 0x0001ebef, @@ -138,18 +135,15 @@ { "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, { "ASIX AX88140", 128, 0x0001fbff, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer }, { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, + HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer }, { "ADMtek Comet", 256, 0x0001abef, MC_HASH_ONLY, comet_timer }, { "Compex 9881 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, { "Intel DS21145 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, - t21142_timer }, - { "Xircom tulip work-alike", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY, t21142_timer }, {0}, }; @@ -163,16 +157,20 @@ { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, +/* { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },*/ { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, - { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, {0}, }; -MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); +MODULE_DEVICE_TABLE(pci, tulip_pci_tbl); /* A full-duplex map for media types. */ @@ -181,7 +179,13 @@ u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ -u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +u16 t21041_csr13[] = { + csr13_mask_10bt, /* 10-T */ + csr13_mask_auibnc, /* 10-2 */ + csr13_mask_auibnc, /* AUI */ + csr13_mask_10bt, /* 10-T */ + csr13_mask_10bt, /* 10T-FD */ +}; u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; @@ -198,54 +202,6 @@ static void set_rx_mode(struct net_device *dev); -/* The Xircom cards are picky about when certain bits in CSR6 can be - manipulated. Keith Owens . */ - -void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) -{ - long ioaddr = tp->base_addr; - const int strict_bits = 0x0060e202; - int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; - - /* common path */ - if (tp->chip_id != X3201_3) { - outl (newcsr6, ioaddr + CSR6); - return; - } - - newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ - /* read 0 on the Xircom cards */ - newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ - currcsr6 = inl (ioaddr + CSR6); - if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || - ((currcsr6 & ~0x2002) == 0)) - goto out_write; - - /* make sure the transmitter and receiver are stopped first */ - currcsr6 &= ~0x2002; - while (1) { - csr5 = inl (ioaddr + CSR5); - if (csr5 == 0xffffffff) - break; /* cannot read csr5, card removed? */ - csr5_22_20 = csr5 & 0x700000; - csr5_19_17 = csr5 & 0x0e0000; - if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && - (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) - break; /* both are stopped or suspended */ - if (!--attempts) { - printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts," - "csr5=0x%08x\n", csr5); - goto out_write; - } - outl (currcsr6, ioaddr + CSR6); - udelay (1); - } - -out_write: - /* now it is safe to change csr6 */ - outl (newcsr6, ioaddr + CSR6); -} - static void tulip_up(struct net_device *dev) { @@ -264,11 +220,13 @@ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ outl(0x00000001, ioaddr + CSR0); + udelay(100); /* Deassert reset. Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. */ outl(tp->csr0, ioaddr + CSR0); + udelay(100); if (tulip_debug > 1) printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); @@ -561,7 +519,6 @@ out: dev->trans_start = jiffies; - netif_start_queue (dev); spin_unlock_irqrestore (&tp->lock, flags); } @@ -786,14 +743,14 @@ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ if (tp->mii_cnt) data[0] = phy; - else if (tp->flags & HAS_NWAY143) + else if (tp->flags & HAS_NWAY) data[0] = 32; else if (tp->chip_id == COMET) data[0] = 1; else return -ENODEV; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { int csr12 = inl(ioaddr + CSR12); int csr14 = inl(ioaddr + CSR14); switch (data[1]) { @@ -821,7 +778,7 @@ case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + if (data[0] == 32 && (tp->flags & HAS_NWAY)) { if (data[1] == 5) tp->to_advertise = data[2]; } else { @@ -1108,9 +1065,13 @@ /* Clear the missed-packet counter. */ (volatile int)inl(ioaddr + CSR8); - if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { - printk(" 21040 compatible mode,"); - chip_idx = DC21040; + if (chip_idx == DC21041) { + if (inl(ioaddr + CSR9) & 0x8000) { + printk(" 21040 compatible mode,"); + chip_idx = DC21040; + } else { + printk(" 21041 mode,"); + } } /* The station address ROM is read byte serially. The register must @@ -1307,7 +1268,7 @@ dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; - if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) + if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041) tp->link_change = t21142_lnk_change; else if (tp->flags & HAS_PNICNWAY) tp->link_change = pnic_lnk_change; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.99-pre2/linux/drivers/net/via-rhine.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/net/via-rhine.c Thu Mar 23 23:35:35 2000 @@ -27,16 +27,19 @@ LK1.1.1: - Justin Guyett: softnet and locking fixes - Jeff Garzik: use PCI interface - -*/ -static const char *versionA = -"via-rhine.c:v1.01-LK1.1.1 3/2/2000 Written by Donald Becker\n"; -static const char *versionB = -" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; + LK1.1.2: + - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions + + LK1.1.3: + - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c code) + update "Theory of Operation" with softnet/locking changes + - Dave Miller: PCI DMA and endian fixups + - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation +*/ /* A few user-configurable values. These may be modified when a driver - module is loaded.*/ + module is loaded. */ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; @@ -58,6 +61,7 @@ The Rhine has a 64 element 8390-like hash table. */ static const int multicast_filter_limit = 32; + /* Operational parameters that are set at compile time. */ /* Keep the ring sizes a power of two for compile efficiency. @@ -68,12 +72,21 @@ #define TX_RING_SIZE 8 #define RX_RING_SIZE 16 + /* Operational parameters that usually are not changed. */ + /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error See the last lines of the source file for the proper compile-command. +#endif + #include #include #include @@ -91,15 +104,20 @@ #include #include -/* This driver was written to use PCI memory space, however some x86 - motherboards only configure I/O space accesses correctly. */ -#if defined(__i386__) && !defined(VIA_USE_MEMORY) -#define VIA_USE_IO -#endif -#if defined(__alpha__) -#define VIA_USE_IO -#endif -#ifdef VIA_USE_IO +static const char *versionA __devinitdata = +"via-rhine.c:v1.03a-LK1.1.3 3/23/2000 Written by Donald Becker\n"; +static const char *versionB __devinitdata = +" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; + + + +/* This driver was written to use PCI memory space, however most versions + of the Rhine only work correctly with I/O space accesses. */ +#if defined(VIA_USE_MEMORY) +#warning Many adapters using the VIA Rhine chip are not configured to work +#warning with PCI memory space accesses. +#else +#define USE_IO #undef readb #undef readw #undef readl @@ -114,9 +132,6 @@ #define writel outl #endif -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - #define RUN_AT(x) (jiffies + (x)) MODULE_AUTHOR("Donald Becker "); @@ -186,18 +201,17 @@ The driver runs as two independent, single-threaded flows of control. One is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and interrupt handling software. +dev->priv->lock spinlock. The other thread is the interrupt handler, which +is single threaded by the hardware and interrupt handling software. -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'lp->tx_full' flag. +The send packet thread has partial control over the Tx ring. It locks the +dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring +is not available it stops the transmit queue by calling netif_stop_queue. The interrupt handler has exclusive control over the Rx ring and records stats from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it -clears both the tx_full and tbusy flags. +empty by incrementing the dirty_tx mark. If at least half of the entries in +the Rx ring are available the transmit queue is woken up if it was stopped. IV. Notes @@ -231,57 +245,49 @@ }; enum via_rhine_chips { - vt86c100a = 0, - vt3043, + VT86C100A = 0, + VT3043, }; struct via_rhine_chip_info { const char *name; - u16 flags; + u16 pci_flags; int io_size; + int drv_flags; }; +enum chip_capability_flags {CanHaveMII=1, }; + +#if defined(VIA_USE_MEMORY) +#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) +#else +#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) +#endif + /* directly indexed by enum via_rhine_chips, above */ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { - {"VIA VT86C100A Rhine-II", - PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, - 128,}, - {"VIA VT3043 Rhine", - PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, - 128,}, + { "VIA VT86C100A Rhine-II", RHINE_IOTYPE, 128, CanHaveMII }, + { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII } }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = { - {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a}, - {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043}, + {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, + {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043}, {0,}, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); - -/* A chip capabilities table, matching the entries in pci_tbl[] above. */ -enum chip_capability_flags {CanHaveMII=1, }; -struct chip_info { - int io_size; - int flags; -} static cap_tbl[] = { - {128, CanHaveMII, }, - {128, CanHaveMII, }, -}; - - -/* Offsets to the device registers. -*/ +/* Offsets to the device registers. */ enum register_offsets { StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, IntrStatus=0x0C, IntrEnable=0x0E, MulticastFilter0=0x10, MulticastFilter1=0x14, RxRingPtr=0x18, TxRingPtr=0x1C, - MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E, + MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E, }; @@ -295,21 +301,19 @@ IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, IntrTxAborted=0x2000, IntrLinkChange=0x4000, IntrRxWakeUp=0x8000, - IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260, + IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, }; /* The Rx and Tx buffer descriptors. */ struct rx_desc { - u16 rx_status; - u16 rx_length; + s32 rx_status; u32 desc_length; u32 addr; u32 next_desc; }; struct tx_desc { - u16 tx_status; - u16 tx_own; + s32 tx_status; u32 desc_length; u32 addr; u32 next_desc; @@ -317,9 +321,11 @@ /* Bits in *_desc.status */ enum rx_status_bits { - RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F}; + RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F +}; + enum desc_status_bits { - DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000, + DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000, }; /* Bits in ChipCmd. */ @@ -331,32 +337,42 @@ }; struct netdev_private { - /* Descriptor rings first for alignment. */ - struct rx_desc rx_ring[RX_RING_SIZE]; - struct tx_desc tx_ring[TX_RING_SIZE]; + /* Descriptor rings */ + struct rx_desc *rx_ring; + struct tx_desc *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + dma_addr_t rx_skbuff_dma[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */ - unsigned char *tx_bufs; /* Tx bounce buffer region. */ + + struct pci_dev *pdev; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; + /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; struct rx_desc *rx_head_desc; - unsigned short int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned short int cur_tx, dirty_tx; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ u16 chip_cmd; /* Current setting for ChipCmd */ unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port:4; /* Last dev->if_port value. */ u8 tx_thresh, rx_thresh; + /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ @@ -393,6 +409,9 @@ static int did_version = 0; long ioaddr; int io_size; + int pci_flags; + void *ring; + dma_addr_t ring_dma; /* print version once and once only */ if (! did_version++) { @@ -403,44 +422,67 @@ card_idx++; option = card_idx < MAX_UNITS ? options[card_idx] : 0; io_size = via_rhine_chip_info[chip_id].io_size; + pci_flags = via_rhine_chip_info[chip_id].pci_flags; + /* this should always be supported */ + if (!pci_dma_supported(pdev, 0xffffffff)) { + printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n"); + goto err_out; + } + + /* sanity check */ + if ((pci_resource_len (pdev, 0) < io_size) || + (pci_resource_len (pdev, 1) < io_size)) { + printk (KERN_ERR "Insufficient PCI resources, aborting\n"); + goto err_out; + } -#ifdef VIA_USE_IO - ioaddr = pci_resource_start (pdev, 0); -#else - ioaddr = pci_resource_start (pdev, 1); -#endif + /* allocate pci dma space for rx and tx descriptor rings */ + ring = pci_alloc_consistent(pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + &ring_dma); + if (!ring) { + printk(KERN_ERR "Could not allocate DMA memory.\n"); + goto err_out; + } + + ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1); if (pci_enable_device (pdev)) { printk (KERN_ERR "unable to init PCI device (card #%d)\n", card_idx); - goto err_out; + goto err_out_free_dma; } - if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER) + if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); dev = init_etherdev(NULL, sizeof(*np)); if (dev == NULL) { printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx); - goto err_out; + goto err_out_free_dma; } - if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) { + /* request all PIO and MMIO regions just to make sure + * noone else attempts to use any portion of our I/O space */ + if (!request_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0), dev->name)) { printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n", dev->name, io_size, pci_resource_start (pdev, 0)); goto err_out_free_netdev; } - if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) { + if (!request_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1), dev->name)) { printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n", dev->name, io_size, pci_resource_start (pdev, 1)); goto err_out_free_pio; } -#ifndef VIA_USE_IO +#ifndef USE_IO ioaddr = (long) ioremap (ioaddr, io_size); if (!ioaddr) { printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", @@ -469,6 +511,11 @@ np = dev->priv; spin_lock_init (&np->lock); np->chip_id = chip_id; + np->pdev = pdev; + np->rx_ring = ring; + np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); + np->rx_ring_dma = ring_dma; + np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); if (dev->mem_start) option = dev->mem_start; @@ -499,7 +546,7 @@ pdev->driver_data = dev; - if (cap_tbl[np->chip_id].flags & CanHaveMII) { + if (via_rhine_chip_info[chip_id].drv_flags & CanHaveMII) { int phy, phy_idx = 0; np->phys[0] = 1; /* Standard for this chip. */ for (phy = 1; phy < 32 && phy_idx < 4; phy++) { @@ -518,18 +565,25 @@ return 0; -#ifndef VIA_USE_IO +#ifndef USE_IO /* note this is ifdef'd because the ioremap is ifdef'd... * so additional exit conditions above this must move * release_mem_region outside of the ifdef */ err_out_free_mmio: - release_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)); + release_mem_region(pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); #endif err_out_free_pio: - release_region(pci_resource_start (pdev, 0), io_size); + release_region(pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); err_out_free_netdev: unregister_netdev (dev); kfree (dev); +err_out_free_dma: + pci_free_consistent(pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + ring, ring_dma); err_out: return -ENODEV; } @@ -557,9 +611,12 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) { + struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int boguscnt = 1024; + if (phy_id == np->phys[0] && regnum == 4) + np->advertising = value; /* Wait for a previous command to complete. */ while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; @@ -578,32 +635,34 @@ long ioaddr = dev->base_addr; int i; + MOD_INC_USE_COUNT; + /* Reset the chip. */ writew(CmdReset, ioaddr + ChipCmd); - if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) - return -EAGAIN; + if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } if (debug > 1) printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n", dev->name, dev->irq); - MOD_INC_USE_COUNT; - via_rhine_init_ring(dev); - writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); - writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + writel(np->rx_ring_dma, ioaddr + RxRingPtr); + writel(np->tx_ring_dma, ioaddr + TxRingPtr); for (i = 0; i < 6; i++) writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ - writew(0x0006, ioaddr + PCIConfig); /* Tune configuration??? */ + writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ /* Configure the FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ np->tx_thresh = 0x20; - np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ + np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ if (dev->if_port == 0) dev->if_port = np->default_port; @@ -666,6 +725,7 @@ } } + static void via_rhine_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; @@ -677,12 +737,14 @@ printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); } + via_rhine_check_duplex(dev); np->timer.expires = RUN_AT(next_tick); add_timer(&np->timer); } + static void via_rhine_tx_timeout (struct net_device *dev) { struct netdev_private *np = (struct netdev_private *) dev->priv; @@ -693,16 +755,17 @@ dev->name, readw (ioaddr + IntrStatus), mdio_read (dev, np->phys[0], 1)); - /* Perhaps we should reinitialize the hardware here. */ + /* XXX Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + /* XXX to do */ /* Trigger an immediate transmit demand. */ + /* XXX to do */ dev->trans_start = jiffies; np->stats.tx_errors++; - - netif_start_queue (dev); } @@ -720,13 +783,13 @@ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rx_status = 0; - np->rx_ring[i].rx_length = 0; - np->rx_ring[i].desc_length = np->rx_buf_sz; - np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]); + np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); + np->rx_ring[i].next_desc = + cpu_to_le32(np->rx_ring_dma + sizeof(struct rx_desc)*(i+1)); np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]); + np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); /* Fill in the Rx buffers. */ for (i = 0; i < RX_RING_SIZE; i++) { @@ -734,20 +797,25 @@ np->rx_skbuff[i] = skb; if (skb == NULL) break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[i].addr = virt_to_bus(skb->tail); - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].rx_length = DescOwn; + skb->dev = dev; /* Mark as being used by this device. */ + + np->rx_skbuff_dma[i] = + pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); + np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); } for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; - np->tx_ring[i].tx_own = 0; - np->tx_ring[i].desc_length = 0x00e08000; - np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]); + np->tx_ring[i].tx_status = 0; + np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].next_desc = + cpu_to_le32(np->tx_ring_dma + sizeof(struct tx_desc)*(i+1)); np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL); } - np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]); + np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); return; } @@ -771,16 +839,24 @@ if ((long)skb->data & 3) { /* Must use alignment buffer. */ if (np->tx_buf[entry] == NULL && - (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) + (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) { + spin_unlock_irqrestore (&np->lock, flags); return 1; + } memcpy(np->tx_buf[entry], skb->data, skb->len); - np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]); - } else - np->tx_ring[entry].addr = virt_to_bus(skb->data); - - np->tx_ring[entry].desc_length = 0x00E08000 | - (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); - np->tx_ring[entry].tx_own = DescOwn; + np->tx_skbuff_dma[entry] = + pci_map_single(np->pdev, np->tx_buf[entry], skb->len, + PCI_DMA_TODEVICE); + } else { + np->tx_skbuff_dma[entry] = + pci_map_single(np->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + } + np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]); + + np->tx_ring[entry].desc_length = + cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); np->cur_tx++; @@ -848,7 +924,7 @@ } /* This routine is logically part of the interrupt handler, but isolated - for clarity and better register allocation. */ + for clarity. */ static void via_rhine_tx(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -858,15 +934,15 @@ /* if tx_full is set, they're all dirty, not clean */ while (np->dirty_tx != np->cur_tx) { - if (np->tx_ring[entry].tx_own) /* transmit request pending */ + txstatus = le32_to_cpu(np->tx_ring[entry].tx_status); + if (txstatus & DescOwn) break; - txstatus = np->tx_ring[entry].tx_status; if (debug > 6) - printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n", + printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n", entry, txstatus); if (txstatus & 0x8000) { if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); np->stats.tx_errors++; if (txstatus & 0x0400) np->stats.tx_carrier_errors++; @@ -877,12 +953,15 @@ /* Transmitter restarted in 'abnormal' handler. */ } else { np->stats.collisions += (txstatus >> 3) & 15; - np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; + np->stats.tx_bytes += le32_to_cpu(np->tx_ring[entry].desc_length) & 0x7ff; np->stats.tx_packets++; - } - /* Free the original skb. */ - dev_kfree_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = NULL; + } + /* Free the original skb. */ + pci_unmap_single(np->pdev, + le32_to_cpu(np->tx_ring[entry].addr), + np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = NULL; entry = (++np->dirty_tx) % TX_RING_SIZE; } if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2) @@ -896,33 +975,32 @@ static void via_rhine_rx(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; - int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE; - int boguscnt = RX_RING_SIZE; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; if (debug > 4) { - printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n", - entry, np->rx_head_desc->rx_length); + printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %8.8x.\n", + entry, le32_to_cpu(np->rx_head_desc->rx_status)); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while ( ! (np->rx_head_desc->rx_length & DescOwn)) { + while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) { struct rx_desc *desc = np->rx_head_desc; - int data_size = desc->rx_length; - u16 desc_status = desc->rx_status; + u32 desc_status = le32_to_cpu(desc->rx_status); + int data_size = desc_status >> 16; if (debug > 4) - printk(KERN_DEBUG " via_rhine_rx() status is %4.4x.\n", + printk(KERN_DEBUG " via_rhine_rx() status is %8.8x.\n", desc_status); if (--boguscnt < 0) break; if ( (desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " - "multiple buffers, entry %#x length %d status %4.4x!\n", + "multiple buffers, entry %#x length %d status %8.8x!\n", dev->name, entry, data_size, desc_status); printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", - dev->name, np->rx_head_desc, - &np->rx_ring[entry]); + dev->name, np->rx_head_desc, &np->rx_ring[entry]); np->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ @@ -942,25 +1020,35 @@ /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) || USE_IP_COPYSUM /* Avoid misaligned on Alpha */ - eth_copy_and_sum(skb, bus_to_virt(desc->addr), - pkt_len, 0); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len); + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); #endif } else { - skb_put(skb = np->rx_skbuff[entry], pkt_len); + skb = np->rx_skbuff[entry]; + if (skb == NULL) { + printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", + dev->name); + break; + } np->rx_skbuff[entry] = NULL; + skb_put(skb, pkt_len); + pci_unmap_single(np->pdev, np->rx_skbuff_dma[entry], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); - np->stats.rx_bytes+=skb->len; netif_rx(skb); dev->last_rx = jiffies; + np->stats.rx_bytes += skb->len; np->stats.rx_packets++; } entry = (++np->cur_rx) % RX_RING_SIZE; @@ -968,19 +1056,21 @@ } /* Refill the Rx ring buffers. */ - while (np->dirty_rx != np->cur_rx) { + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { struct sk_buff *skb; - entry = np->dirty_rx++ % RX_RING_SIZE; + entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[entry].addr = virt_to_bus(skb->tail); + np->rx_skbuff_dma[entry] = + pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]); } - np->rx_ring[entry].rx_status = 0; - np->rx_ring[entry].rx_length = DescOwn; + np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } /* Pre-emptively restart Rx engine. */ @@ -1020,7 +1110,8 @@ printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } - if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) { + if ((intr_status & ~( IntrLinkChange | IntrStatsMax | + IntrTxAbort | IntrTxAborted)) && debug > 1) { printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Recovery for other fault sources not known. */ @@ -1076,6 +1167,8 @@ } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ + writel(0xffffffff, ioaddr + MulticastFilter0); + writel(0xffffffff, ioaddr + MulticastFilter1); rx_mode = 0x0C; } else { struct dev_mc_list *mclist; @@ -1083,12 +1176,11 @@ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, - mc_filter); + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); - rx_mode = 0x08; + rx_mode = 0x0C; } writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig); } @@ -1138,13 +1230,17 @@ /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_length = 0; - np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + np->rx_ring[i].rx_status = 0; + np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->rx_skbuff[i]) { + pci_unmap_single(np->pdev, + np->rx_skbuff_dma[i], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skbuff[i]); } np->rx_skbuff[i] = 0; } + for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) dev_kfree_skb(np->tx_skbuff[i]); @@ -1165,14 +1261,19 @@ unregister_netdev(dev); release_region(pci_resource_start (pdev, 0), - via_rhine_chip_info[np->chip_id].io_size); + pci_resource_len (pdev, 0)); release_mem_region(pci_resource_start (pdev, 1), - via_rhine_chip_info[np->chip_id].io_size); + pci_resource_len (pdev, 1)); -#ifndef VIA_USE_IO +#ifndef USE_IO iounmap((char *)(dev->base_addr)); #endif + pci_free_consistent(pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + np->rx_ring, np->rx_ring_dma); + kfree(dev); } @@ -1187,7 +1288,15 @@ static int __init via_rhine_init (void) { - return pci_module_init (&via_rhine_driver); + int rc; + + MOD_INC_USE_COUNT; + + rc = pci_module_init (&via_rhine_driver); + + MOD_DEC_USE_COUNT; + + return rc; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.3.99-pre2/linux/drivers/net/wan/Config.in Tue Mar 14 19:10:39 2000 +++ linux/drivers/net/wan/Config.in Mon Mar 20 07:53:52 2000 @@ -55,9 +55,11 @@ if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC - bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR + bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 + fi bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP - bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.3.99-pre2/linux/drivers/parport/ChangeLog Sun Mar 19 18:35:30 2000 +++ linux/drivers/parport/ChangeLog Wed Mar 22 09:37:22 2000 @@ -1,3 +1,12 @@ +2000-03-22 Tim Waugh + + * init.c (parport_setup): Fix return value. + +2000-03-21 Tim Waugh + + * parport_pc.c (parport_pc_pci_probe): Fix return value; call + pci_enable_device. + 2000-03-16 Tim Waugh * parport_pc.c (parport_ECP_supported): This seems to trigger on diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/parport/init.c linux/drivers/parport/init.c --- v2.3.99-pre2/linux/drivers/parport/init.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/parport/init.c Wed Mar 22 09:37:22 2000 @@ -49,13 +49,13 @@ if (!str || !*str || (*str == '0' && !*(str+1))) { /* Disable parport if "parport=0" in cmdline */ io[0] = PARPORT_DISABLE; - return 0; + return 1; } if (!strncmp (str, "auto", 4)) { irq[0] = PARPORT_IRQ_AUTO; dma[0] = PARPORT_DMA_AUTO; - return 0; + return 1; } val = simple_strtoul (str, &endptr, 0); @@ -108,7 +108,7 @@ } parport_setup_ptr++; - return 0; + return 1; } __setup ("parport=", parport_setup); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.99-pre2/linux/drivers/parport/parport_pc.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/parport/parport_pc.c Wed Mar 22 09:37:22 2000 @@ -2348,7 +2348,7 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) { - int count, n, i = id->driver_data; + int err, count, n, i = id->driver_data; if (i < last_sio) /* This is an onboard Super-IO and has already been probed */ return 0; @@ -2356,6 +2356,9 @@ /* This is a PCI card */ i -= last_sio; count = 0; + if ((err = pci_enable_device (dev)) != 0) + return err; + for (n = 0; n < cards[i].numports; n++) { int lo = cards[i].addr[n].lo; int hi = cards[i].addr[n].hi; @@ -2370,7 +2373,7 @@ count++; } - return count; + return count == 0 ? -ENODEV : 0; } static struct pci_driver parport_pc_pci_driver = { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.99-pre2/linux/drivers/pci/pci.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/pci/pci.c Tue Mar 21 11:02:09 2000 @@ -33,6 +33,16 @@ LIST_HEAD(pci_root_buses); LIST_HEAD(pci_devices); +/** + * pci_find_slot - locate PCI device from a given PCI slot + * @bus: number of PCI bus on which desired PCI device resides + * @devfn: number of PCI slot in which desired PCI device resides + * + * Given a PCI bus and slot number, the desired PCI device is + * located in system global list of PCI devices. If the device + * is found, a pointer to its data structure is returned. If no + * device is found, %NULL is returned. + */ struct pci_dev * pci_find_slot(unsigned int bus, unsigned int devfn) { @@ -66,6 +76,19 @@ } +/** + * pci_find_device - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all vendor ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor and @device, a pointer to its device structure is + * returned. Otherwise, %NULL is returned. + * + * A new search is initiated by passing %NULL to the @from argument. + * Otherwise if @from is not null, searches continue from that point. + */ struct pci_dev * pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) { @@ -73,6 +96,18 @@ } +/** + * pci_find_class - begin or continue searching for a PCI device by class + * @class: search for a PCI device with this class designation + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @class, a pointer to its device structure is + * returned. Otherwise, %NULL is returned. + * + * A new search is initiated by passing %NULL to the @from argument. + * Otherwise if @from is not null, searches continue from that point. + */ struct pci_dev * pci_find_class(unsigned int class, const struct pci_dev *from) { @@ -122,7 +157,11 @@ } -/* +/** + * pci_find_parent_resource - return resource region of parent bus of given region + * @dev: PCI device structure contains resources to be searched + * @res: child resource record for which parent is sought + * * For given resource region of given device, return the resource * region of parent bus the given region is contained in or where * it should be allocated from. @@ -150,7 +189,11 @@ return best; } -/* +/** + * pci_set_power_state - Set power management state of a device. + * @dev: PCI device for which PM is set + * @new_state: new power management statement (0 == D0, 3 == D3, etc.) + * * Set power management state of a device. For transitions from state D3 * it isn't as straightforward as one could assume since many devices forget * their configuration space during wakeup. Returns old power state. @@ -192,7 +235,10 @@ return old_state; } -/* +/** + * pci_enable_device - Initialize device before it's used by a driver. + * @dev: PCI device to be initialized + * * Initialize device before it's used by a driver. Ask low-level code * to enable I/O and memory. Wake up the device if it was suspended. * Beware, this function can fail. diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/pcmcia/ti113x.h linux/drivers/pcmcia/ti113x.h --- v2.3.99-pre2/linux/drivers/pcmcia/ti113x.h Sun Mar 19 18:35:30 2000 +++ linux/drivers/pcmcia/ti113x.h Thu Mar 23 15:37:27 2000 @@ -137,16 +137,32 @@ #ifdef CONFIG_CARDBUS /* - * Generic TI open - TI has an extension for the + * Generic TI init - TI has an extension for the * INTCTL register that sets the PCI CSC interrupt. * Make sure we set it correctly at open and init - * time. + * time + * - open: disable the PCI CSC interrupt. This makes + * it possible to use the CSC interrupt to probe the + * ISA interrupts. + * - init: set the interrupt to match our PCI state. + * This makes us correctly get PCI CSC interrupt + * events. */ static int ti_open(pci_socket_t *socket) { u8 new, reg = exca_readb(socket, I365_INTCTL); new = reg & ~I365_INTR_ENA; + if (new != reg) + exca_writeb(socket, I365_INTCTL, new); + return 0; +} + +static int ti_intctl(pci_socket_t *socket) +{ + u8 new, reg = exca_readb(socket, I365_INTCTL); + + new = reg & ~I365_INTR_ENA; if (socket->cb_irq) new |= I365_INTR_ENA; if (new != reg) @@ -157,7 +173,7 @@ static int ti_init(pci_socket_t *socket) { yenta_init(socket); - ti_open(socket); + ti_intctl(socket); return 0; } @@ -200,7 +216,7 @@ config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket)); config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket)); config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket)); - ti_open(socket); + ti_intctl(socket); return 0; } @@ -237,7 +253,7 @@ yenta_init(socket); config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); - ti_open(socket); + ti_intctl(socket); return 0; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.3.99-pre2/linux/drivers/pcmcia/yenta.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/pcmcia/yenta.c Sun Mar 19 20:59:38 2000 @@ -851,22 +851,3 @@ yenta_proc_setup }; EXPORT_SYMBOL(yenta_operations); - -/* - * Ricoh cardbus bridge: standard cardbus, except it needs - * some extra init code to set timings etc. - */ -struct pci_socket_ops ricoh_operations = { - yenta_open, - yenta_close, - ricoh_init, - yenta_suspend, - yenta_get_status, - yenta_get_socket, - yenta_set_socket, - yenta_get_io_map, - yenta_set_io_map, - yenta_get_mem_map, - yenta_set_mem_map, - yenta_proc_setup -}; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.3.99-pre2/linux/drivers/pnp/isapnp.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/pnp/isapnp.c Sun Mar 19 18:19:22 2000 @@ -1208,6 +1208,50 @@ return NULL; } +static const struct isapnp_card_id * +isapnp_match_card(const struct isapnp_card_id *ids, struct pci_bus *card) +{ + int idx; + + while (ids->vendor || ids->device) { + if ((ids->vendor == ISAPNP_ANY_ID || ids->vendor == card->vendor) && + (ids->device == ISAPNP_ANY_ID || ids->device == card->device)) { + for (idx = 0; idx < ISAPNP_CARD_DEVS; idx++) { + if (ids->devs[idx].vendor == 0 && + ids->devs[idx].function == 0) + return ids; + if (isapnp_find_dev(card, + ids->devs[idx].vendor, + ids->devs[idx].function, + NULL) == NULL) + goto __next; + } + return ids; + } + __next: + ids++; + } + return NULL; +} + +int isapnp_probe_cards(const struct isapnp_card_id *ids, + int (*probe)(struct pci_bus *_card, + const struct isapnp_card_id *_id)) +{ + struct pci_bus *card; + const struct isapnp_card_id *id; + int count = 0; + + if (ids == NULL || probe == NULL) + return -EINVAL; + isapnp_for_each_card(card) { + id = isapnp_match_card(ids, card); + if (id != NULL && probe(card, id) >= 0) + count++; + } + return count; +} + static unsigned int isapnp_dma_resource_flags(struct isapnp_dma *dma) { return dma->flags | IORESOURCE_DMA | IORESOURCE_AUTO; @@ -2065,6 +2109,8 @@ #endif /* CONFIG_PCI */ +EXPORT_SYMBOL(isapnp_cards); +EXPORT_SYMBOL(isapnp_devices); EXPORT_SYMBOL(isapnp_present); EXPORT_SYMBOL(isapnp_cfg_begin); EXPORT_SYMBOL(isapnp_cfg_end); @@ -2080,6 +2126,7 @@ EXPORT_SYMBOL(isapnp_deactivate); EXPORT_SYMBOL(isapnp_find_card); EXPORT_SYMBOL(isapnp_find_dev); +EXPORT_SYMBOL(isapnp_probe_cards); EXPORT_SYMBOL(isapnp_resource_change); int __init isapnp_init(void) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c --- v2.3.99-pre2/linux/drivers/sbus/char/envctrl.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/sbus/char/envctrl.c Wed Mar 22 21:50:29 2000 @@ -1,4 +1,4 @@ -/* $Id: envctrl.c,v 1.15 2000/02/09 22:33:23 davem Exp $ +/* $Id: envctrl.c,v 1.16 2000/03/22 21:29:23 ecd Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -1002,7 +1002,6 @@ return 0; out: - envctrl_stop(); return -ENODEV; } @@ -1381,7 +1380,7 @@ } else { err = prom_getproperty(node, "cpu-temp-factors", envctrl.cpu_temp_table, 256); - if (err) { + if (err < 0) { printk("envctrl: can't read `cpu-temp-factors'\n"); goto out; } @@ -1398,7 +1397,7 @@ } else { err = prom_getproperty(node, "cpu-fan-speeds", envctrl.cpu_fan_speeds, 112); - if (err) { + if (err < 0) { printk("envctrl: can't read `cpu-fan-speeds'\n"); goto out; } @@ -1415,7 +1414,7 @@ } else { err = prom_getproperty(node, "ps-temp-factors", envctrl.ps_temp_table, 256); - if (err) { + if (err < 0) { printk("envctrl: can't read `ps-temp-factors'\n"); goto out; } @@ -1432,7 +1431,7 @@ } else { err = prom_getproperty(node, "ps-fan-speeds", envctrl.ps_fan_speeds, 112); - if (err) { + if (err < 0) { printk("envctrl: can't read `ps-fan-speeds'\n"); goto out; } @@ -1449,8 +1448,6 @@ out: if (tmp) kfree(tmp); - - envctrl_stop(); return err; } #endif /* U450_SUPPORT */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.3.99-pre2/linux/drivers/sbus/char/sunmouse.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/sbus/char/sunmouse.c Tue Mar 21 23:38:25 2000 @@ -69,7 +69,6 @@ unsigned char prev_state; /* Previous button state */ int delta_x; /* Current delta-x */ int delta_y; /* Current delta-y */ - int present; int ready; /* set if there if data is available */ int active; /* set if device is open */ int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */ @@ -382,8 +381,6 @@ { if(sunmouse.active++) return 0; - if(!sunmouse.present) - return -EINVAL; sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; sunmouse.vuid_mode = VUID_NATIVE; @@ -555,11 +552,8 @@ SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops }; -int __init sun_mouse_init(void) +void sun_mouse_zsinit(void) { - if (!sunmouse.present) - return -ENODEV; - printk("Sun Mouse-Systems mouse driver version 1.00\n"); sunmouse.ready = sunmouse.active = 0; @@ -568,11 +562,4 @@ sunmouse.button_state = 0x80; init_waitqueue_head(&sunmouse.proc_list); sunmouse.byte = 69; - return 0; -} - -void -sun_mouse_zsinit(void) -{ - sunmouse.present = 1; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.3.99-pre2/linux/drivers/sbus/char/sunserial.c Wed Dec 29 13:13:18 1999 +++ linux/drivers/sbus/char/sunserial.c Tue Mar 21 23:38:25 2000 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.74 1999/12/15 22:30:23 davem Exp $ +/* $Id: sunserial.c,v 1.75 2000/03/22 02:45:36 davem Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -66,6 +66,8 @@ } return err; } + +__initcall(rs_init); void __init rs_kgdb_hook(int channel) { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.3.99-pre2/linux/drivers/scsi/Makefile Sun Mar 19 18:35:30 2000 +++ linux/drivers/scsi/Makefile Wed Mar 22 09:39:11 2000 @@ -738,17 +738,11 @@ sim710.o : sim710_d.h -initio.o: ini9100u.c i91uscsi.c - $(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o - $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o +initio.o: ini9100u.o i91uscsi.o $(LD) -r -o initio.o ini9100u.o i91uscsi.o - rm -f ini9100u.o i91uscsi.o a100u2w.o: inia100.o i60uscsi.o $(LD) -r -o a100u2w.o inia100.o i60uscsi.o - -megaraid.o: megaraid.c - $(CC) $(CFLAGS) -c megaraid.c scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o \ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.3.99-pre2/linux/drivers/scsi/advansys.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/advansys.c Sun Mar 19 18:19:35 2000 @@ -4186,7 +4186,7 @@ #endif /* ADVANSYS_DEBUG */ #ifdef ADVANSYS_ASSERT -STATIC int interrupts_enabled(void); +STATIC int advansys_interrupts_enabled(void); #endif /* ADVANSYS_ASSERT */ @@ -7053,7 +7053,7 @@ Scsi_Device *device; int ret; - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %lx, done %lx\n", (ulong) scp, (ulong) scp->scsi_done); @@ -7182,7 +7182,7 @@ } ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); return ret; } @@ -7602,7 +7602,7 @@ struct Scsi_Host *shp; int i; - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %lx, qdonep %lx\n", (ulong) asc_dvc_varp, (ulong) qdonep); ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); @@ -7773,7 +7773,7 @@ struct Scsi_Host *shp; int i; - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %lx, scsiqp %lx\n", (ulong) adv_dvc_varp, (ulong) scsiqp); ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); @@ -8422,7 +8422,7 @@ ASC_DBG3(3, "asc_enqueue: ascq %lx, reqp %lx, flag %d\n", (ulong) ascq, (ulong) reqp, flag); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); tid = REQPTID(reqp); @@ -8475,7 +8475,7 @@ REQP reqp; ASC_DBG2(3, "asc_dequeue: ascq %lx, tid %d\n", (ulong) ascq, tid); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if ((reqp = ascq->q_first[tid]) != NULL) { ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); @@ -8524,7 +8524,7 @@ int i; ASC_DBG2(3, "asc_dequeue_list: ascq %lx, tid %d\n", (ulong) ascq, tid); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID)); /* @@ -8607,7 +8607,7 @@ ASC_DBG2(3, "asc_rmqueue: ascq %lx, reqp %lx\n", (ulong) ascq, (ulong) reqp); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); @@ -8675,7 +8675,7 @@ ASC_DBG2(3, "asc_isqueued: ascq %lx, reqp %lx\n", (ulong) ascq, (ulong) reqp); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); @@ -8705,7 +8705,7 @@ int i; ASC_DBG1(1, "asc_execute_queue: ascq %lx\n", (ulong) ascq); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE); /* * Execute queued commands for devices attached to * the current board in round-robin fashion. @@ -10919,12 +10919,12 @@ #ifdef ADVANSYS_ASSERT /* - * interrupts_enabled() + * advansys_interrupts_enabled() * * Return 1 if interrupts are enabled, otherwise return 0. */ STATIC int -interrupts_enabled(void) +advansys_interrupts_enabled(void) { int flags; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.3.99-pre2/linux/drivers/scsi/eata.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/scsi/eata.c Tue Mar 21 14:43:39 2000 @@ -1212,7 +1212,7 @@ ints[0] = i - 1; internal_setup(cur, ints); - return 0; + return 1; } static void add_pci_ports(void) { diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.3.99-pre2/linux/drivers/scsi/qlogicisp.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/qlogicisp.c Wed Mar 22 00:05:02 2000 @@ -6,6 +6,9 @@ * Copyright 2000, Jayson C. Vantuyl * and Bryon W. Roche * + * 64-bit addressing added by Kanoj Sarcar + * and Leo Dagum + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any @@ -18,6 +21,7 @@ */ #include +#include #include #include #include @@ -160,6 +164,8 @@ #define MBOX3 0x76 /* mailbox 3 */ #define MBOX4 0x78 /* mailbox 4 */ #define MBOX5 0x7a /* mailbox 5 */ +#define MBOX6 0x7c /* mailbox 6 */ +#define MBOX7 0x7e /* mailbox 7 */ /* mailbox command complete status codes */ #define MBOX_COMMAND_COMPLETE 0x4000 @@ -177,6 +183,15 @@ #define REQUEST_QUEUE_WAKEUP 0x8005 #define EXECUTION_TIMEOUT_RESET 0x8006 +#ifdef CONFIG_QL_ISP_A64 +#define IOCB_SEGS 2 +#define CONTINUATION_SEGS 5 +#define MAX_CONTINUATION_ENTRIES 254 +#else +#define IOCB_SEGS 4 +#define CONTINUATION_SEGS 7 +#endif /* CONFIG_QL_ISP_A64 */ + struct Entry_header { u_char entry_type; u_char entry_cnt; @@ -185,8 +200,14 @@ }; /* entry header type commands */ +#ifdef CONFIG_QL_ISP_A64 +#define ENTRY_COMMAND 9 +#define ENTRY_CONTINUATION 0xa +#else #define ENTRY_COMMAND 1 #define ENTRY_CONTINUATION 2 +#endif /* CONFIG_QL_ISP_A64 */ + #define ENTRY_STATUS 3 #define ENTRY_MARKER 4 #define ENTRY_EXTENDED_COMMAND 5 @@ -199,6 +220,9 @@ struct dataseg { u_int d_base; +#ifdef CONFIG_QL_ISP_A64 + u_int d_base_hi; +#endif u_int d_count; }; @@ -213,7 +237,11 @@ u_short time_out; u_short segment_cnt; u_char cdb[12]; - struct dataseg dataseg[4]; +#ifdef CONFIG_QL_ISP_A64 + u_int rsvd1; + u_int rsvd2; +#endif + struct dataseg dataseg[IOCB_SEGS]; }; /* command entry control flag definitions */ @@ -240,8 +268,10 @@ struct Continuation_Entry { struct Entry_header hdr; +#ifndef CONFIG_QL_ISP_A64 u_int reserved; - struct dataseg dataseg[7]; +#endif + struct dataseg dataseg[CONTINUATION_SEGS]; }; struct Marker_Entry { @@ -385,6 +415,11 @@ #define MBOX_WRITE_FOUR_RAM_WORDS 0x0041 #define MBOX_EXEC_BIOS_IOCB 0x0042 +#ifdef CONFIG_QL_ISP_A64 +#define MBOX_CMD_INIT_REQUEST_QUEUE_64 0x0052 +#define MBOX_CMD_INIT_RESPONSE_QUEUE_64 0x0053 +#endif /* CONFIG_QL_ISP_A64 */ + #include "qlogicisp_asm.c" #define PACKB(a, b) (((a)<<4)|(b)) @@ -457,6 +492,25 @@ PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */ PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */ PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */ +#ifdef CONFIG_QL_ISP_A64 + ,PACKB(0, 0), /* 0x0043 */ + PACKB(0, 0), /* 0x0044 */ + PACKB(0, 0), /* 0x0045 */ + PACKB(0, 0), /* 0x0046 */ + PACKB(0, 0), /* 0x0047 */ + PACKB(0, 0), /* 0x0048 */ + PACKB(0, 0), /* 0x0049 */ + PACKB(0, 0), /* 0x004a */ + PACKB(0, 0), /* 0x004b */ + PACKB(0, 0), /* 0x004c */ + PACKB(0, 0), /* 0x004d */ + PACKB(0, 0), /* 0x004e */ + PACKB(0, 0), /* 0x004f */ + PACKB(0, 0), /* 0x0050 */ + PACKB(0, 0), /* 0x0051 */ + PACKB(8, 8), /* MBOX_CMD_INIT_REQUEST_QUEUE_64 (0x0052) */ + PACKB(8, 8) /* MBOX_CMD_INIT_RESPONSE_QUEUE_64 (0x0053) */ +#endif /* CONFIG_QL_ISP_A64 */ }; #define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) @@ -742,6 +796,7 @@ struct Continuation_Entry *cont; struct Scsi_Host *host; struct isp1020_hostdata *hostdata; + dma_addr_t dma_addr; ENTER("isp1020_queuecommand"); @@ -817,14 +872,18 @@ /* fill in first four sg entries: */ n = sg_count; - if (n > 4) - n = 4; + if (n > IOCB_SEGS) + n = IOCB_SEGS; for (i = 0; i < n; i++) { - ds[i].d_base = cpu_to_le32(sg_dma_address(sg)); + dma_addr = sg_dma_address(sg); + ds[i].d_base = cpu_to_le32((u32) dma_addr); +#ifdef CONFIG_QL_ISP_A64 + ds[i].d_base_hi = cpu_to_le32((u32) (dma_addr>>32)); +#endif /* CONFIG_QL_ISP_A64 */ ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); ++sg; } - sg_count -= 4; + sg_count -= IOCB_SEGS; while (sg_count > 0) { ++cmd->hdr.entry_cnt; @@ -841,32 +900,46 @@ cont->hdr.entry_cnt = 0; cont->hdr.sys_def_1 = 0; cont->hdr.flags = 0; +#ifndef CONFIG_QL_ISP_A64 cont->reserved = 0; +#endif ds = cont->dataseg; n = sg_count; - if (n > 7) - n = 7; + if (n > CONTINUATION_SEGS) + n = CONTINUATION_SEGS; for (i = 0; i < n; ++i) { - ds[i].d_base = cpu_to_le32(sg_dma_address(sg)); + dma_addr = sg_dma_address(sg); + ds[i].d_base = cpu_to_le32((u32) dma_addr); +#ifdef CONFIG_QL_ISP_A64 + ds[i].d_base_hi = cpu_to_le32((u32)(dma_addr>>32)); +#endif /* CONFIG_QL_ISP_A64 */ ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); ++sg; } sg_count -= n; } } else if (Cmnd->request_bufflen) { - Cmnd->SCp.ptr = (char *)(unsigned long) - pci_map_single(hostdata->pci_dev, + /*Cmnd->SCp.ptr = (char *)(unsigned long)*/ + dma_addr = pci_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + Cmnd->SCp.ptr = (char *)(unsigned long) dma_addr; cmd->dataseg[0].d_base = - cpu_to_le32((u32)(long)Cmnd->SCp.ptr); + cpu_to_le32((u32) dma_addr); +#ifdef CONFIG_QL_ISP_A64 + cmd->dataseg[0].d_base_hi = + cpu_to_le32((u32) (dma_addr>>32)); +#endif /* CONFIG_QL_ISP_A64 */ cmd->dataseg[0].d_count = cpu_to_le32((u32)Cmnd->request_bufflen); cmd->segment_cnt = cpu_to_le16(1); } else { cmd->dataseg[0].d_base = 0; +#ifdef CONFIG_QL_ISP_A64 + cmd->dataseg[0].d_base_hi = 0; +#endif /* CONFIG_QL_ISP_A64 */ cmd->dataseg[0].d_count = 0; cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } @@ -983,7 +1056,11 @@ scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); else if (Cmnd->request_bufflen) pci_unmap_single(hostdata->pci_dev, +#ifdef CONFIG_QL_ISP_A64 + (dma_addr_t)((long)Cmnd->SCp.ptr), +#else (u32)((long)Cmnd->SCp.ptr), +#endif Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); @@ -1612,8 +1689,13 @@ static int isp1020_load_parameters(struct Scsi_Host *host) { int i, k; +#ifdef CONFIG_QL_ISP_A64 + u_long queue_addr; + u_short param[8]; +#else u_int queue_addr; u_short param[6]; +#endif u_short isp_cfg1, hwrev; unsigned long flags; struct isp1020_hostdata *hostdata = @@ -1753,13 +1835,20 @@ } queue_addr = hostdata->res_dma; - +#ifdef CONFIG_QL_ISP_A64 + param[0] = MBOX_CMD_INIT_RESPONSE_QUEUE_64; +#else param[0] = MBOX_INIT_RES_QUEUE; +#endif param[1] = RES_QUEUE_LEN + 1; param[2] = (u_short) (queue_addr >> 16); param[3] = (u_short) (queue_addr & 0xffff); param[4] = 0; param[5] = 0; +#ifdef CONFIG_QL_ISP_A64 + param[6] = (u_short) (queue_addr >> 48); + param[7] = (u_short) (queue_addr >> 32); +#endif isp1020_mbox_command(host, param); @@ -1770,13 +1859,22 @@ } queue_addr = hostdata->req_dma; - +#ifdef CONFIG_QL_ISP_A64 + param[0] = MBOX_CMD_INIT_REQUEST_QUEUE_64; +#else param[0] = MBOX_INIT_REQ_QUEUE; +#endif param[1] = QLOGICISP_REQ_QUEUE_LEN + 1; param[2] = (u_short) (queue_addr >> 16); param[3] = (u_short) (queue_addr & 0xffff); param[4] = 0; +#ifdef CONFIG_QL_ISP_A64 + param[5] = 0; + param[6] = (u_short) (queue_addr >> 48); + param[7] = (u_short) (queue_addr >> 32); +#endif + isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { @@ -1811,6 +1909,8 @@ printk("qlogicisp: mbox_command loop timeout #1\n"); switch(mbox_param[param[0]] >> 4) { + case 8: isp_outw(param[7], host, MBOX7); + case 7: isp_outw(param[6], host, MBOX6); case 6: isp_outw(param[5], host, MBOX5); case 5: isp_outw(param[4], host, MBOX4); case 4: isp_outw(param[3], host, MBOX3); @@ -1836,6 +1936,8 @@ printk("qlogicisp: mbox_command loop timeout #3\n"); switch(mbox_param[param[0]] & 0xf) { + case 8: param[7] = isp_inw(host, MBOX7); + case 7: param[6] = isp_inw(host, MBOX6); case 6: param[5] = isp_inw(host, MBOX5); case 5: param[4] = isp_inw(host, MBOX4); case 4: param[3] = isp_inw(host, MBOX3); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.3.99-pre2/linux/drivers/scsi/scsi.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/scsi.c Thu Mar 23 11:03:45 2000 @@ -1377,12 +1377,12 @@ */ void scsi_release_commandblocks(Scsi_Device * SDpnt) { - Scsi_Cmnd *SCpnt; + Scsi_Cmnd *SCpnt, *SCnext; unsigned long flags; - spin_lock_irqsave(&device_request_lock, flags); - for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { - SDpnt->device_queue = SCpnt->next; + spin_lock_irqsave(&device_request_lock, flags); + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) { + SDpnt->device_queue = SCnext = SCpnt->next; kfree((char *) SCpnt); } SDpnt->has_cmdblocks = 0; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.99-pre2/linux/drivers/scsi/st.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/scsi/st.c Wed Mar 22 15:37:46 2000 @@ -5,14 +5,14 @@ History: Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. Contribution and ideas from several people including (in alphabetical - order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, - Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and - Eric Youngdale. + order) Klaus Ehrenfried, Eric Lee Green, Wolfgang Denk, Steve Hirsch, + Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, + J"org Weule, and Eric Youngdale. Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Mon Mar 13 21:15:29 2000 by makisara@kai.makisara.local + Last modified: Sun Mar 19 22:06:54 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support @@ -2621,8 +2621,7 @@ return set_location(STp, STps->last_block_visited, STp->new_partition, 1); } -/* Functions for reading and writing the medium partition mode page. These - seem to work with Wangtek 6200HS and HP C1533A. */ +/* Functions for reading and writing the medium partition mode page. */ #define PART_PAGE 0x11 #define PART_PAGE_FIXED_LENGTH 8 @@ -2675,6 +2674,11 @@ The following algorithm is used to accomodate both drives: if the number of partition size fields is greater than the maximum number of additional partitions in the mode page, the second field is used. Otherwise the first field is used. + + For Seagate DDS drives the page length must be 8 when no partitions is defined + and 10 when 1 partition is defined (information from Eric Lee Green). This is + is acceptable also to some other old drives and enforced if the first partition + size field is used for the first additional partition size. */ static int partition_tape(Scsi_Tape *STp, int size) { @@ -2707,12 +2711,16 @@ if (size <= 0) { bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0; + if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS]) + bp[pgo + MP_OFF_PAGE_LENGTH] = 6; DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev)); } else { bp[psdo] = (size >> 8) & 0xff; bp[psdo + 1] = size & 0xff; bp[pgo + 3] = 1; + if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8) + bp[pgo + MP_OFF_PAGE_LENGTH] = 8; DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with two partitions (1 = %d MB).\n", dev, size)); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.3.99-pre2/linux/drivers/scsi/u14-34f.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/scsi/u14-34f.c Tue Mar 21 14:43:39 2000 @@ -943,7 +943,7 @@ ints[0] = i - 1; internal_setup(cur, ints); - return 0; + return 1; } int u14_34f_detect(Scsi_Host_Template *tpnt) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.3.99-pre2/linux/drivers/sound/ac97_codec.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/sound/ac97_codec.c Mon Mar 20 07:53:51 2000 @@ -25,7 +25,7 @@ * v0.3 Feb 22 2000 Ollie Lho * bug fix for record mask setting * v0.2 Feb 10 2000 Ollie Lho - * add ac97_read_proc for /proc/driver/vnedor/ac97 + * add ac97_read_proc for /proc/driver/{vendor}/ac97 * v0.1 Jan 14 2000 Ollie Lho * Isolated from trident.c to support multiple ac97 codec */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/awe_hw.h linux/drivers/sound/awe_hw.h --- v2.3.99-pre2/linux/drivers/sound/awe_hw.h Fri Mar 10 16:40:44 2000 +++ linux/drivers/sound/awe_hw.h Tue Mar 21 11:10:45 2000 @@ -3,9 +3,9 @@ * * Access routines and definitions for the low level driver for the * Creative AWE32/SB32/AWE64 wave table synth. - * version 0.4.3; Mar. 1, 1998 + * version 0.4.4; Jan. 4, 2000 * - * Copyright (C) 1996-1998 Takashi Iwai + * Copyright (C) 1996-2000 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/awe_wave.c linux/drivers/sound/awe_wave.c --- v2.3.99-pre2/linux/drivers/sound/awe_wave.c Fri Mar 10 16:40:44 2000 +++ linux/drivers/sound/awe_wave.c Wed Mar 22 15:37:11 2000 @@ -2,9 +2,9 @@ * sound/awe_wave.c * * The low level driver for the AWE32/SB32/AWE64 wave table synth. - * version 0.4.3; Feb. 1, 1999 + * version 0.4.4; Jan. 4, 2000 * - * Copyright (C) 1996-1999 Takashi Iwai + * Copyright (C) 1996-2000 Takashi Iwai * * 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 @@ -26,6 +26,9 @@ #include #include #include +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +#include +#endif #include "sound_config.h" #include "soundmodule.h" @@ -42,9 +45,6 @@ * debug message */ -/* do not allocate buffer at beginning */ -#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} - #ifdef AWE_DEBUG_ON #define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }} #define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }} @@ -59,56 +59,56 @@ * bank and voice record */ +typedef struct _sf_list sf_list; +typedef struct _awe_voice_list awe_voice_list; +typedef struct _awe_sample_list awe_sample_list; + /* soundfont record */ -typedef struct _sf_list { - unsigned short sf_id; - unsigned short type; +struct _sf_list { + unsigned short sf_id; /* id number */ + unsigned short type; /* lock & shared flags */ int num_info; /* current info table index */ int num_sample; /* current sample table index */ int mem_ptr; /* current word byte pointer */ - int infos; - int samples; + awe_voice_list *infos, *last_infos; /* instruments */ + awe_sample_list *samples, *last_samples; /* samples */ #ifdef AWE_ALLOW_SAMPLE_SHARING - int shared; /* shared index */ - unsigned char name[AWE_PATCH_NAME_LEN]; + sf_list *shared; /* shared list */ + unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */ #endif -} sf_list; + sf_list *next, *prev; +}; -/* bank record */ -typedef struct _awe_voice_list { - int next; /* linked list with same sf_id */ +/* instrument list */ +struct _awe_voice_list { + awe_voice_info v; /* instrument information */ + sf_list *holder; /* parent sf_list of this record */ unsigned char bank, instr; /* preset number information */ char type, disabled; /* type=normal/mapped, disabled=boolean */ - awe_voice_info v; /* voice information */ - int next_instr; /* preset table list */ - int next_bank; /* preset table list */ -} awe_voice_list; + awe_voice_list *next; /* linked list with same sf_id */ + awe_voice_list *next_instr; /* instrument list */ + awe_voice_list *next_bank; /* hash table list */ +}; /* voice list type */ #define V_ST_NORMAL 0 #define V_ST_MAPPED 1 -typedef struct _awe_sample_list { - int next; /* linked list with same sf_id */ +/* sample list */ +struct _awe_sample_list { awe_sample_info v; /* sample information */ -} awe_sample_list; + sf_list *holder; /* parent sf_list of this record */ + awe_sample_list *next; /* linked list with same sf_id */ +}; /* sample and information table */ -static int current_sf_id = 0; -static int locked_sf_id = 0; -static int max_sfs; -static sf_list *sflists = NULL; - -#define awe_free_mem_ptr() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].mem_ptr) -#define awe_free_info() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_info) -#define awe_free_sample() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_sample) - -static int max_samples; -static awe_sample_list *samples = NULL; - -static int max_infos; -static awe_voice_list *infos = NULL; - +static int current_sf_id = 0; /* current number of fonts */ +static int locked_sf_id = 0; /* locked position */ +static sf_list *sfhead = NULL, *sftail = NULL; /* linked-lists */ + +#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0) +#define awe_free_info() (sftail ? sftail->num_info : 0) +#define awe_free_sample() (sftail ? sftail->num_sample : 0) #define AWE_MAX_PRESETS 256 #define AWE_DEFAULT_PRESET 0 @@ -119,7 +119,7 @@ #define MAX_LAYERS AWE_MAX_VOICES /* preset table index */ -static int preset_table[AWE_MAX_PRESETS]; +static awe_voice_list *preset_table[AWE_MAX_PRESETS]; /* * voice table @@ -143,8 +143,6 @@ int main_vol; /* channel volume (0-127) */ int expression_vol; /* midi expression (0-127) */ int chan_press; /* channel pressure */ - int vrec; /* instrument list */ - int def_vrec; /* default instrument list */ int sustained; /* sustain status in MIDI */ FX_Rec fx; /* effects */ FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */ @@ -194,9 +192,9 @@ static awe_chan_info channels[AWE_MAX_CHANNELS]; -/*---------------------------------------------------------------- +/* * global variables - *----------------------------------------------------------------*/ + */ #ifndef AWE_DEFAULT_BASE_ADDR #define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */ @@ -206,10 +204,13 @@ #define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */ #endif -#define awe_port io -#define awe_mem_size memsize int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */ int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */ +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static int isapnp = 1; +#else +static int isapnp = 0; +#endif MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver"); @@ -217,6 +218,8 @@ MODULE_PARM_DESC(io, "base i/o port of Emu8000"); MODULE_PARM(memsize, "i"); MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes"); +MODULE_PARM(isapnp, "i"); +MODULE_PARM_DESC(isapnp, "use ISAPnP detection"); EXPORT_NO_SYMBOLS; /* DRAM start offset */ @@ -255,7 +258,7 @@ 0, /* perc_mode (obsolete) */ AWE_MAX_VOICES, /* nr_voices */ 0, /* nr_drums (obsolete) */ - AWE_MAX_INFOS /* instr_bank_size */ + 400 /* instr_bank_size */ }; @@ -362,8 +365,9 @@ static void awe_terminate_and_init(int voice, int forced); /* voice search */ -static int awe_search_instr(int bank, int preset); -static int awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist); +static int awe_search_key(int bank, int preset, int note); +static awe_voice_list *awe_search_instr(int bank, int preset, int note); +static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist); static void awe_alloc_multi_voices(int ch, int note, int velocity, int key); static void awe_alloc_one_voice(int voice, int note, int velocity); static int awe_clear_voice(void); @@ -373,6 +377,7 @@ static int awe_close_patch(awe_patch_info *patch, const char *addr, int count); static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count); static int awe_load_info(awe_patch_info *patch, const char *addr, int count); +static int awe_remove_info(awe_patch_info *patch, const char *addr, int count); static int awe_load_data(awe_patch_info *patch, const char *addr, int count); static int awe_replace_data(awe_patch_info *patch, const char *addr, int count); static int awe_load_map(awe_patch_info *patch, const char *addr, int count); @@ -381,22 +386,24 @@ #endif /*static int awe_probe_info(awe_patch_info *patch, const char *addr, int count);*/ static int awe_probe_data(awe_patch_info *patch, const char *addr, int count); -static int check_patch_opened(int type, char *name); -static int awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels); -static void add_sf_info(int rec); -static void add_sf_sample(int rec); -static void purge_old_list(int rec, int next); -static void add_info_list(int rec); +static sf_list *check_patch_opened(int type, char *name); +static int awe_write_wave_data(const char *addr, int offset, awe_sample_list *sp, int channels); +static int awe_create_sf(int type, char *name); +static void awe_free_sf(sf_list *sf); +static void add_sf_info(sf_list *sf, awe_voice_list *rec); +static void add_sf_sample(sf_list *sf, awe_sample_list *smp); +static void purge_old_list(awe_voice_list *rec, awe_voice_list *next); +static void add_info_list(awe_voice_list *rec); static void awe_remove_samples(int sf_id); static void rebuild_preset_list(void); -static short awe_set_sample(awe_voice_info *vp); -static int search_sample_index(int sf, int sample, int level); +static short awe_set_sample(awe_voice_list *rec); +static awe_sample_list *search_sample_index(sf_list *sf, int sample); +static int is_identical_holder(sf_list *sf1, sf_list *sf2); #ifdef AWE_ALLOW_SAMPLE_SHARING -static int is_identical_id(int id1, int id2); -static int is_identical_name(unsigned char *name, int id); +static int is_identical_name(unsigned char *name, sf_list *p); static int is_shared_sf(unsigned char *name); -static int info_duplicated(awe_voice_list *rec); +static int info_duplicated(sf_list *sf, awe_voice_list *rec); #endif /* allow sharing */ /* lowlevel functions */ @@ -410,7 +417,7 @@ static int awe_open_dram_for_write(int offset, int channels); static void awe_open_dram_for_check(void); static void awe_close_dram(void); -static void awe_write_dram(unsigned short c); +/*static void awe_write_dram(unsigned short c);*/ static int awe_detect_base(int addr); static int awe_detect(void); static void awe_check_dram(void); @@ -483,9 +490,9 @@ static int ctrls[AWE_MD_END]; -/*---------------------------------------------------------------- +/* * synth operation table - *----------------------------------------------------------------*/ + */ static struct synth_operations awe_operations = { @@ -513,39 +520,32 @@ }; -/*================================================================ +/* * General attach / unload interface - *================================================================*/ + */ -static int _attach_awe(void) +static int __init _attach_awe(void) { if (awe_present) return 0; /* for OSS38.. called twice? */ /* check presence of AWE32 card */ if (! awe_detect()) { - printk(KERN_WARNING "AWE32: not detected\n"); + printk(KERN_ERR "AWE32: not detected\n"); return 0; } /* check AWE32 ports are available */ if (awe_check_port()) { - printk(KERN_WARNING "AWE32: I/O area already used.\n"); + printk(KERN_ERR "AWE32: I/O area already used.\n"); return 0; } /* set buffers to NULL */ - sflists = NULL; - samples = NULL; - infos = NULL; - - /* allocate sample tables */ - INIT_TABLE(sflists, max_sfs, AWE_MAX_SF_LISTS, sf_list); - INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list); - INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list); + sfhead = sftail = NULL; my_dev = sound_alloc_synthdev(); if (my_dev == -1) { - printk(KERN_WARNING "AWE32 Error: too many synthesizers\n"); + printk(KERN_ERR "AWE32 Error: too many synthesizers\n"); return 0; } @@ -570,8 +570,8 @@ awe_initialize(); sprintf(awe_info.name, "AWE32-%s (RAM%dk)", - AWEDRV_VERSION, awe_mem_size/1024); - printk("\n", awe_mem_size/1024); + AWEDRV_VERSION, memsize/1024); + printk(KERN_INFO "\n", memsize/1024); awe_present = TRUE; @@ -583,33 +583,18 @@ static void free_tables(void) { - if(sflists) - vfree(sflists); - sflists = NULL; max_sfs = 0; - if (samples) - vfree(samples); - samples = NULL; max_samples = 0; - if (infos) - vfree(infos); - infos = NULL; max_infos = 0; -} - -static void *realloc_block(void *buf, int oldsize, int size) -{ - void *ptr; - if (oldsize == size) - return buf; - if ((ptr = vmalloc(size)) == NULL) - return NULL; - if (oldsize && size) - memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) ); - if (buf) - vfree(buf); - return ptr; + if (sftail) { + sf_list *p, *prev; + for (p = sftail; p; p = prev) { + prev = p->prev; + awe_free_sf(p); + } + } + sfhead = sftail = NULL; } -static void _unload_awe(void) +static void __exit _unload_awe(void) { if (awe_present) { awe_reset_samples(); @@ -627,96 +612,6 @@ } } -/* - * Linux PnP driver support - */ - -#ifdef CONFIG_PNP_DRV - -#include - -static int pnp = 1; /* use PnP as default */ - -#define AWE_NUM_CHIPS 3 -static unsigned int pnp_ids[AWE_NUM_CHIPS] = { - PNP_EISAID('C','T','L',0x0021), - PNP_EISAID('C','T','L',0x0022), - PNP_EISAID('C','T','L',0x0023), -}; -static struct pnp_driver pnp_awe[AWE_NUM_CHIPS]; -static int awe_pnp_ok = 0; - -static void awe_pnp_config(struct pnp_device *d) -{ - struct pnp_resource *r; - int port[3]; - int nio = 0; - - port[0] = port[1] = port[2] = 0; - for (r = d->res; r != NULL; r = r->next) { - if (r->type == PNP_RES_IO) { - if (nio >= 0 && nio < 3) - port[nio] = r->start; - nio++; - } - } - setup_ports(port[0], port[1], port[2]); - DEBUG(0,printk("AWE32: PnP setup ports: %x:%x:%x\n", port[0], port[1], port[2])); -} - -static int awe_pnp_event (struct pnp_device *d, struct pnp_drv_event *e) -{ - struct pnp_driver *drv = d->l.k.driver; - - switch (e->type) { - case PNP_DRV_ALLOC: - drv->flags |= PNP_DRV_INUSE; - awe_pnp_ok = 1; - awe_pnp_config(d); - _attach_awe(); - break; - - case PNP_DRV_DISABLE: - case PNP_DRV_EMERGSTOP: - drv->flags &= ~PNP_DRV_INUSE; - awe_pnp_ok = 0; - _unload_awe(); - break; - - case PNP_DRV_CONFIG: - if (awe_busy) return 1; /* used now */ - awe_release_region(); - awe_pnp_config(d); - awe_request_region(); - break; - - case PNP_DRV_RECONFIG: - break; - } - return 0; -} - -static int awe_initpnp (void) -{ - int i; - for (i = 0; i < AWE_NUM_CHIPS; i++) { - pnp_awe[i].id.type = PNP_HDL_ISA; - pnp_awe[i].id.t.isa.id = pnp_ids[i]; - pnp_awe[i].id.next = NULL; - pnp_awe[i].name = "Soundblaster AWE32/AWE64 PnP"; - pnp_awe[i].event = awe_pnp_event; - pnp_register_driver(&pnp_awe[i], 1); - } - return 0; -} - -static void awe_unload_pnp (void) -{ - int i; - for (i = 0; i < AWE_NUM_CHIPS; i++) - pnp_unregister_driver(&pnp_awe[i]); -} -#endif /* PnP support */ /* * clear sample tables @@ -725,12 +620,8 @@ static void awe_reset_samples(void) { - int i; - /* free all bank tables */ - for (i = 0; i < AWE_MAX_PRESETS; i++) - preset_table[i] = -1; - + memset(preset_table, 0, sizeof(preset_table)); free_tables(); current_sf_id = 0; @@ -767,7 +658,7 @@ } /* write 16bit data */ -static inline void +static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data) { awe_set_cmd(cmd); @@ -775,7 +666,7 @@ } /* write 32bit data */ -static inline void +static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data) { unsigned short addr = awe_ports[port]; @@ -785,7 +676,7 @@ } /* read 16bit data */ -static inline unsigned short +static unsigned short awe_peek(unsigned short cmd, unsigned short port) { unsigned short k; @@ -795,7 +686,7 @@ } /* read 32bit data */ -static inline unsigned int +static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port) { unsigned int k1, k2; @@ -837,14 +728,16 @@ current->state = TASK_INTERRUPTIBLE; schedule_timeout((HZ*(unsigned long)delay + 44099)/44100); } +/* +static void awe_wait(unsigned short delay) +{ + udelay(((unsigned long)delay * 1000000L + 44099) / 44100); +} +*/ #endif /* wait by loop */ /* write a word data */ -static inline void -awe_write_dram(unsigned short c) -{ - awe_poke(AWE_SMLD, c); -} +#define awe_write_dram(c) awe_poke(AWE_SMLD, c) /* @@ -852,7 +745,7 @@ * 0x620-623, 0xA20-A23, 0xE20-E23 */ -static int +static int __init awe_check_port(void) { if (! port_setuped) return 0; @@ -861,7 +754,7 @@ check_region(awe_ports[3], 4)); } -static void +static void __init awe_request_region(void) { if (! port_setuped) return; @@ -870,7 +763,7 @@ request_region(awe_ports[3], 4, "sound driver (AWE32)"); } -static void +static void __exit awe_release_region(void) { if (! port_setuped) return; @@ -879,9 +772,11 @@ release_region(awe_ports[3], 4); } + /* - * AWE32 initialization + * initialization of AWE driver */ + static void awe_initialize(void) { @@ -935,7 +830,6 @@ static void awe_init_voice_info(awe_voice_info *vp) { - vp->sf_id = 0; /* normal mode */ vp->sample = 0; vp->rate_offset = 0; @@ -1338,7 +1232,7 @@ fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; /* A voice sample must assigned before calling */ - if ((vp = voices[voice].sample) == NULL || vp->index < 0) + if ((vp = voices[voice].sample) == NULL || vp->index == 0) return; parm = (awe_voice_parm_block*)&vp->parm; @@ -1457,15 +1351,15 @@ awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget); awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget); - /* turn on envelope */ - awe_poke(AWE_DCYSUSV(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY, - vp->parm.voldcysus)); /* set reverb */ temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb); temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux; awe_poke_dw(AWE_PTRX(voice), temp); awe_poke_dw(AWE_CPF(voice), ptarget << 16); + /* turn on envelope */ + awe_poke(AWE_DCYSUSV(voice), + FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY, + vp->parm.voldcysus)); voices[voice].state = AWE_ST_ON; @@ -1568,7 +1462,7 @@ fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; if (!IS_PLAYING(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index < 0) + if ((vp = voices[voice].sample) == NULL || vp->index == 0) return; tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF, @@ -1603,7 +1497,7 @@ fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index < 0) + if ((vp = voices[voice].sample) == NULL || vp->index == 0) return; /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */ @@ -1622,14 +1516,16 @@ } if (forced || temp != voices[voice].apan) { voices[voice].apan = temp; + if (temp == 0) + voices[voice].aaux = 0xff; + else + voices[voice].aaux = (-temp) & 0xff; addr = vp->loopstart - 1; addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START, AWE_FX_COARSE_LOOP_START, vp->mode); temp = (temp<<24) | (unsigned int)addr; awe_poke_dw(AWE_PSST(voice), temp); DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr)); - if (temp == 0) voices[voice].aaux = 0xff; - else voices[voice].aaux = (-temp)&0xff; } } @@ -1644,7 +1540,7 @@ fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index < 0) + if ((vp = voices[voice].sample) == NULL || vp->index == 0) return; awe_poke(AWE_FMMOD(voice), FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF, @@ -1662,7 +1558,7 @@ fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index < 0) + if ((vp = voices[voice].sample) == NULL || vp->index == 0) return; awe_poke(AWE_TREMFRQ(voice), FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ, @@ -1680,7 +1576,7 @@ fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index < 0) + if ((vp = voices[voice].sample) == NULL || vp->index == 0) return; awe_poke(AWE_FM2FRQ2(voice), FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ, @@ -1700,7 +1596,7 @@ fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; if (IS_NO_EFFECT(voice) && !forced) return; - if ((vp = voices[voice].sample) == NULL || vp->index < 0) + if ((vp = voices[voice].sample) == NULL || vp->index == 0) return; addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff; @@ -1708,12 +1604,12 @@ awe_poke_dw(AWE_CCCA(voice), addr); } -/*================================================================ +/* * calculate pitch offset - *---------------------------------------------------------------- + * * 0xE000 is no pitch offset at 44100Hz sample. * Every 4096 is one octave. - *================================================================*/ + */ static void awe_calc_pitch(int voice) @@ -1726,9 +1622,9 @@ /* search voice information */ if ((ap = vp->sample) == NULL) return; - if (ap->index < 0) { + if (ap->index == 0) { DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); - if (awe_set_sample(ap) < 0) + if (awe_set_sample((awe_voice_list*)ap) == 0) return; } @@ -1785,9 +1681,9 @@ /* search voice information */ if ((ap = vp->sample) == NULL) return; - if (ap->index < 0) { + if (ap->index == 0) { DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); - if (awe_set_sample(ap) < 0) + if (awe_set_sample((awe_voice_list*)ap) == 0) return; } note = freq_to_note(freq); @@ -1806,13 +1702,13 @@ #endif /* AWE_HAS_GUS_COMPATIBILITY */ -/*================================================================ +/* * calculate volume attenuation - *---------------------------------------------------------------- + * * Voice volume is controlled by volume attenuation parameter. * So volume becomes maximum when avol is 0 (no attenuation), and * minimum when 255 (-96dB or silence). - *================================================================*/ + */ static int vol_table[128] = { 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49, @@ -1887,9 +1783,9 @@ return; ap = vp->sample; - if (ap->index < 0) { + if (ap->index == 0) { DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample)); - if (awe_set_sample(ap) < 0) + if (awe_set_sample((awe_voice_list*)ap) == 0) return; } @@ -2054,8 +1950,6 @@ cp->instr = ctrls[AWE_MD_DEF_PRESET]; cp->bank = ctrls[AWE_MD_DEF_BANK]; } - cp->vrec = -1; - cp->def_vrec = -1; } cp->bender = 0; /* zero tune skew */ @@ -2092,9 +1986,9 @@ } -/*---------------------------------------------------------------- +/* * device open / close - *----------------------------------------------------------------*/ + */ /* open device: * reset status of all voices, and clear sample position flag @@ -2158,13 +2052,13 @@ awe_info.nr_voices = awe_max_voices; else awe_info.nr_voices = AWE_MAX_CHANNELS; - memcpy((char*)arg, &awe_info + 0, sizeof(awe_info)); + memcpy((char*)arg, &awe_info, sizeof(awe_info)); return 0; break; case SNDCTL_SEQ_RESETSAMPLES: - awe_reset_samples(); awe_reset(dev); + awe_reset_samples(); return 0; break; @@ -2174,10 +2068,10 @@ break; case SNDCTL_SYNTH_MEMAVL: - return awe_mem_size - awe_free_mem_ptr() * 2; + return memsize - awe_free_mem_ptr() * 2; default: - printk("AWE32: unsupported ioctl %d\n", cmd); + printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd); return -EINVAL; } } @@ -2358,18 +2252,46 @@ } -/* search instrument from preset table with the specified bank */ +/* calculate hash key */ static int -awe_search_instr(int bank, int preset) +awe_search_key(int bank, int preset, int note) { - int i; + unsigned int key; - limitvalue(preset, 0, AWE_MAX_PRESETS-1); - for (i = preset_table[preset]; i >= 0; i = infos[i].next_bank) { - if (infos[i].bank == bank) - return i; +#if 1 /* new hash table */ + if (bank == AWE_DRUM_BANK) + key = preset + note + 128; + else + key = bank + preset; +#else + key = preset; +#endif + key %= AWE_MAX_PRESETS; + + return (int)key; +} + + +/* search instrument from hash table */ +static awe_voice_list * +awe_search_instr(int bank, int preset, int note) +{ + awe_voice_list *p; + int key, key2; + + key = awe_search_key(bank, preset, note); + for (p = preset_table[key]; p; p = p->next_bank) { + if (p->instr == preset && p->bank == bank) + return p; } - return -1; + key2 = awe_search_key(bank, preset, 0); /* search default */ + if (key == key2) + return NULL; + for (p = preset_table[key2]; p; p = p->next_bank) { + if (p->instr == preset && p->bank == bank) + return p; + } + return NULL; } @@ -2390,7 +2312,6 @@ awe_set_instr(int dev, int voice, int instr_no) { awe_chan_info *cinfo; - int def_bank; if (! voice_in_range(voice)) return -EINVAL; @@ -2399,26 +2320,8 @@ return -EINVAL; cinfo = &channels[voice]; - - if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice)) - def_bank = AWE_DRUM_BANK; /* always search drumset */ - else - def_bank = cinfo->bank; - - cinfo->vrec = -1; - cinfo->def_vrec = -1; - cinfo->vrec = awe_search_instr(def_bank, instr_no); - if (def_bank == AWE_DRUM_BANK) /* search default drumset */ - cinfo->def_vrec = awe_search_instr(def_bank, ctrls[AWE_MD_DEF_DRUM]); - else /* search default preset */ - cinfo->def_vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr_no); - - if (cinfo->vrec < 0 && cinfo->def_vrec < 0) { - DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no)); - } - cinfo->instr = instr_no; - DEBUG(2,printk("AWE32: [program(%d) %d/%d]\n", voice, instr_no, def_bank)); + DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no)); return 0; } @@ -2576,7 +2479,7 @@ switch (cmd) { case _AWE_DEBUG_MODE: ctrls[AWE_MD_DEBUG_MODE] = p1; - printk("AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]); + printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]); break; case _AWE_REVERB_MODE: ctrls[AWE_MD_REVERB_MODE] = p1; @@ -2590,6 +2493,7 @@ case _AWE_REMOVE_LAST_SAMPLES: DEBUG(0,printk("AWE32: remove last samples\n")); + awe_reset(0); if (locked_sf_id > 0) awe_remove_samples(locked_sf_id); break; @@ -2772,6 +2676,8 @@ if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) && !ctrls[AWE_MD_TOGGLE_DRUM_BANK]) break; + if (value < 0 || value > 255) + break; cinfo->bank = value; if (cinfo->bank == AWE_DRUM_BANK) DRUM_CHANNEL_ON(cinfo->channel); @@ -2920,10 +2826,10 @@ } -/*---------------------------------------------------------------- +/* * load a sound patch: * three types of patches are accepted: AWE, GUS, and SYSEX. - *----------------------------------------------------------------*/ + */ static int awe_load_patch(int dev, int format, const char *addr, @@ -2941,20 +2847,21 @@ /* no system exclusive message supported yet */ return 0; } else if (format != AWE_PATCH) { - printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format); + printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format); return -EINVAL; } if (count < AWE_PATCH_INFO_SIZE) { - printk("AWE32 Error: Patch header too short\n"); + printk(KERN_WARNING "AWE32 Error: Patch header too short\n"); return -EINVAL; } - copy_from_user(((char*)&patch) + offs, addr + offs, - AWE_PATCH_INFO_SIZE - offs); + if (copy_from_user(((char*)&patch) + offs, addr + offs, + AWE_PATCH_INFO_SIZE - offs)) + return -EFAULT; count -= AWE_PATCH_INFO_SIZE; if (count < patch.len) { - printk("AWE32: sample: Patch record too short (%d<%d)\n", + printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n", count, patch.len); return -EINVAL; } @@ -2987,6 +2894,9 @@ case AWE_PROBE_DATA: rc = awe_probe_data(&patch, addr, count); break; + case AWE_REMOVE_INFO: + rc = awe_remove_info(&patch, addr, count); + break; case AWE_LOAD_CHORUS_FX: rc = awe_load_chorus_fx(&patch, addr, count); break; @@ -2995,7 +2905,7 @@ break; default: - printk("AWE32 Error: unknown patch format type %d\n", + printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n", patch.type); rc = -EINVAL; } @@ -3004,7 +2914,7 @@ } -/* create an sflist record */ +/* create an sf list record */ static int awe_create_sf(int type, char *name) { @@ -3012,40 +2922,43 @@ /* terminate sounds */ awe_reset(0); - if (current_sf_id >= max_sfs) { - int newsize = max_sfs + AWE_MAX_SF_LISTS; - sf_list *newlist = realloc_block(sflists, sizeof(sf_list)*max_sfs, - sizeof(sf_list)*newsize); - if (newlist == NULL) - return 1; - sflists = newlist; - max_sfs = newsize; - } - rec = &sflists[current_sf_id]; + rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL); + if (rec == NULL) + return 1; /* no memory */ rec->sf_id = current_sf_id + 1; rec->type = type; - if (current_sf_id == 0 || (type & AWE_PAT_LOCKED) != 0) + if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0) locked_sf_id = current_sf_id + 1; rec->num_info = awe_free_info(); rec->num_sample = awe_free_sample(); rec->mem_ptr = awe_free_mem_ptr(); - rec->infos = -1; - rec->samples = -1; + rec->infos = rec->last_infos = NULL; + rec->samples = rec->last_samples = NULL; + + /* add to linked-list */ + rec->next = NULL; + rec->prev = sftail; + if (sftail) + sftail->next = rec; + else + sfhead = rec; + sftail = rec; + current_sf_id++; #ifdef AWE_ALLOW_SAMPLE_SHARING - rec->shared = 0; + rec->shared = NULL; if (name) memcpy(rec->name, name, AWE_PATCH_NAME_LEN); else strcpy(rec->name, "*TEMPORARY*"); - if (current_sf_id > 0 && name && (type & AWE_PAT_SHARED) != 0) { + if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) { /* is the current font really a shared font? */ if (is_shared_sf(rec->name)) { /* check if the shared font is already installed */ - int i; - for (i = current_sf_id; i > 0; i--) { - if (is_identical_name(rec->name, i)) { - rec->shared = i; + sf_list *p; + for (p = rec->prev; p; p = p->prev) { + if (is_identical_name(rec->name, p)) { + rec->shared = p; break; } } @@ -3053,8 +2966,6 @@ } #endif /* allow sharing */ - current_sf_id++; - return 0; } @@ -3065,37 +2976,31 @@ #define ASC_TO_KEY(c) ((c) - 'A' + 1) static int is_shared_sf(unsigned char *name) { - static unsigned char id_head[6] = { + static unsigned char id_head[4] = { ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'), AWE_MAJOR_VERSION, - AWE_MINOR_VERSION, - AWE_TINY_VERSION, }; - if (memcmp(name, id_head, 6) == 0) + if (memcmp(name, id_head, 4) == 0) return TRUE; return FALSE; } /* check if the given name matches to the existing list */ -static int is_identical_name(unsigned char *name, int sf) +static int is_identical_name(unsigned char *name, sf_list *p) { - char *id = sflists[sf-1].name; + char *id = p->name; if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0) return TRUE; return FALSE; } /* check if the given voice info exists */ -static int info_duplicated(awe_voice_list *rec) +static int info_duplicated(sf_list *sf, awe_voice_list *rec) { - int j, sf_id; - sf_list *sf; - /* search for all sharing lists */ - for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) { - sf = &sflists[sf_id - 1]; - for (j = sf->infos; j >= 0; j = infos[j].next) { - awe_voice_list *p = &infos[j]; + for (; sf; sf = sf->shared) { + awe_voice_list *p; + for (p = sf->infos; p; p = p->next) { if (p->type == V_ST_NORMAL && p->bank == rec->bank && p->instr == rec->instr && @@ -3111,6 +3016,29 @@ #endif /* AWE_ALLOW_SAMPLE_SHARING */ +/* free sf_list record */ +/* linked-list in this function is not cared */ +static void +awe_free_sf(sf_list *sf) +{ + if (sf->infos) { + awe_voice_list *p, *next; + for (p = sf->infos; p; p = next) { + next = p->next; + kfree(p); + } + } + if (sf->samples) { + awe_sample_list *p, *next; + for (p = sf->samples; p; p = next) { + next = p->next; + kfree(p); + } + } + kfree(sf); +} + + /* open patch; create sf list and set opened flag */ static int awe_open_patch(awe_patch_info *patch, const char *addr, int count) @@ -3118,13 +3046,14 @@ awe_open_parm parm; int shared; - copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm)); + if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm))) + return -EFAULT; shared = FALSE; #ifdef AWE_ALLOW_SAMPLE_SHARING - if (current_sf_id > 0 && (parm.type & AWE_PAT_SHARED) != 0) { + if (sftail && (parm.type & AWE_PAT_SHARED) != 0) { /* is the previous font the same font? */ - if (is_identical_name(parm.name, current_sf_id)) { + if (is_identical_name(parm.name, sftail)) { /* then append to the previous */ shared = TRUE; awe_reset(0); @@ -3135,8 +3064,8 @@ #endif /* allow sharing */ if (! shared) { if (awe_create_sf(parm.type, parm.name)) { - printk("AWE32: can't open: failed to alloc new list\n"); - return -ENOSPC; + printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n"); + return -ENOMEM; } } patch_opened = TRUE; @@ -3144,28 +3073,30 @@ } /* check if the patch is already opened */ -static int +static sf_list * check_patch_opened(int type, char *name) { if (! patch_opened) { if (awe_create_sf(type, name)) { - printk("AWE32: failed to alloc new list\n"); - return -ENOSPC; + printk(KERN_ERR "AWE32: failed to alloc new list\n"); + return NULL; } patch_opened = TRUE; - return current_sf_id; + return sftail; } - return current_sf_id; + return sftail; } /* close the patch; if no voice is loaded, remove the patch */ static int awe_close_patch(awe_patch_info *patch, const char *addr, int count) { - if (patch_opened && current_sf_id > 0) { + if (patch_opened && sftail) { /* if no voice is loaded, release the current patch */ - if (sflists[current_sf_id-1].infos == -1) + if (sftail->infos == NULL) { + awe_reset(0); awe_remove_samples(current_sf_id - 1); + } } patch_opened = 0; return 0; @@ -3176,52 +3107,39 @@ static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count) { - if (current_sf_id > 0 && current_sf_id > locked_sf_id) + if (current_sf_id > 0 && current_sf_id > locked_sf_id) { + awe_reset(0); awe_remove_samples(current_sf_id - 1); + } return 0; } /* allocate voice info list records */ -static int alloc_new_info(int nvoices) +static awe_voice_list * +alloc_new_info(void) { - int newsize, free_info; awe_voice_list *newlist; - free_info = awe_free_info(); - if (free_info + nvoices >= max_infos) { - do { - newsize = max_infos + AWE_MAX_INFOS; - } while (free_info + nvoices >= newsize); - newlist = realloc_block(infos, sizeof(awe_voice_list)*max_infos, - sizeof(awe_voice_list)*newsize); - if (newlist == NULL) { - printk("AWE32: can't alloc info table\n"); - return -ENOSPC; - } - infos = newlist; - max_infos = newsize; + + newlist = (awe_voice_list *)kmalloc(sizeof(*newlist), GFP_KERNEL); + if (newlist == NULL) { + printk(KERN_ERR "AWE32: can't alloc info table\n"); + return NULL; } - return 0; + return newlist; } /* allocate sample info list records */ -static int alloc_new_sample(void) +static awe_sample_list * +alloc_new_sample(void) { - int newsize, free_sample; awe_sample_list *newlist; - free_sample = awe_free_sample(); - if (free_sample >= max_samples) { - newsize = max_samples + AWE_MAX_SAMPLES; - newlist = realloc_block(samples, - sizeof(awe_sample_list)*max_samples, - sizeof(awe_sample_list)*newsize); - if (newlist == NULL) { - printk("AWE32: can't alloc sample table\n"); - return -ENOSPC; - } - samples = newlist; - max_samples = newsize; + + newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL); + if (newlist == NULL) { + printk(KERN_ERR "AWE32: can't alloc sample table\n"); + return NULL; } - return 0; + return newlist; } /* load voice map */ @@ -3229,35 +3147,33 @@ awe_load_map(awe_patch_info *patch, const char *addr, int count) { awe_voice_map map; - awe_voice_list *rec; - int p, free_info; + awe_voice_list *rec, *p; + sf_list *sf; /* get the link info */ if (count < sizeof(map)) { - printk("AWE32 Error: invalid patch info length\n"); + printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); return -EINVAL; } - copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)); + if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map))) + return -EFAULT; /* check if the identical mapping already exists */ - p = awe_search_instr(map.map_bank, map.map_instr); - for (; p >= 0; p = infos[p].next_instr) { - if (p >= 0 && infos[p].type == V_ST_MAPPED && - infos[p].v.low == map.map_key && - infos[p].v.start == map.src_instr && - infos[p].v.end == map.src_bank && - infos[p].v.fixkey == map.src_key) + p = awe_search_instr(map.map_bank, map.map_instr, map.map_key); + for (; p; p = p->next_instr) { + if (p->type == V_ST_MAPPED && + p->v.start == map.src_instr && + p->v.end == map.src_bank && + p->v.fixkey == map.src_key) return 0; /* already present! */ } - if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0) - return -ENOSPC; + if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL) + return -ENOMEM; - if (alloc_new_info(1) < 0) - return -ENOSPC; + if ((rec = alloc_new_info()) == NULL) + return -ENOMEM; - free_info = awe_free_info(); - rec = &infos[free_info]; rec->bank = map.map_bank; rec->instr = map.map_instr; rec->type = V_ST_MAPPED; @@ -3270,9 +3186,8 @@ rec->v.start = map.src_instr; rec->v.end = map.src_bank; rec->v.fixkey = map.src_key; - rec->v.sf_id = current_sf_id; - add_info_list(free_info); - add_sf_info(free_info); + add_sf_info(sf, rec); + add_info_list(rec); return 0; } @@ -3284,25 +3199,28 @@ { #ifdef AWE_ALLOW_SAMPLE_SHARING awe_voice_map map; - int p; + awe_voice_list *p; if (! patch_opened) return -EINVAL; /* get the link info */ if (count < sizeof(map)) { - printk("AWE32 Error: invalid patch info length\n"); + printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); return -EINVAL; } - copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)); + if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map))) + return -EFAULT; /* check if the identical mapping already exists */ - p = awe_search_instr(map.src_bank, map.src_instr); - for (; p >= 0; p = infos[p].next_instr) { - if (p >= 0 && infos[p].type == V_ST_NORMAL && - is_identical_id(infos[p].v.sf_id, current_sf_id) && - infos[p].v.low <= map.src_key && - infos[p].v.high >= map.src_key) + if (sftail == NULL) + return -EINVAL; + p = awe_search_instr(map.src_bank, map.src_instr, map.src_key); + for (; p; p = p->next_instr) { + if (p->type == V_ST_NORMAL && + is_identical_holder(p->holder, sftail) && + p->v.low <= map.src_key && + p->v.high >= map.src_key) return 0; /* already present! */ } #endif /* allow sharing */ @@ -3319,12 +3237,40 @@ return -EINVAL; /* search the specified sample by optarg */ - if (search_sample_index(current_sf_id, patch->optarg, 0) >= 0) + if (search_sample_index(sftail, patch->optarg) != NULL) return 0; #endif /* allow sharing */ return -EINVAL; } + +/* remove the present instrument layers */ +static int +remove_info(sf_list *sf, int bank, int instr) +{ + awe_voice_list *prev, *next, *p; + int removed = 0; + + prev = NULL; + for (p = sf->infos; p; prev = p, p = next) { + next = p->next; + if (p->type == V_ST_NORMAL && + p->bank == bank && p->instr == instr) { + /* remove this layer */ + if (prev) + prev->next = next; + else + sf->infos = next; + if (p == sf->last_infos) + sf->last_infos = prev; + sf->num_info--; + removed++; + kfree(p); + } + } + return removed; +} + /* load voice information data */ static int awe_load_info(awe_patch_info *patch, const char *addr, int count) @@ -3333,125 +3279,154 @@ awe_voice_rec_hdr hdr; int i; int total_size; + sf_list *sf; + awe_voice_list *rec; if (count < AWE_VOICE_REC_SIZE) { - printk("AWE32 Error: invalid patch info length\n"); + printk(KERN_WARNING "AWE32 Error: invalid patch info length\n"); return -EINVAL; } offset = AWE_PATCH_INFO_SIZE; - copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE); + if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE)) + return -EFAULT; offset += AWE_VOICE_REC_SIZE; if (hdr.nvoices <= 0 || hdr.nvoices >= 100) { - printk("AWE32 Error: Illegal voice number %d\n", hdr.nvoices); + printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices); return -EINVAL; } total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices; if (count < total_size) { - printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n", + printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n", count, hdr.nvoices); return -EINVAL; } - if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0) - return -ENOSPC; + if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL) + return -ENOMEM; -#if 0 /* it looks like not so useful.. */ - /* check if the same preset already exists in the info list */ - for (i = sflists[current_sf_id-1].infos; i >= 0; i = infos[i].next) { - if (infos[i].disabled) continue; - if (infos[i].bank == hdr.bank && infos[i].instr == hdr.instr) { - /* in exclusive mode, do skip loading this */ - if (hdr.write_mode == AWE_WR_EXCLUSIVE) - return 0; - /* in replace mode, disable the old data */ - else if (hdr.write_mode == AWE_WR_REPLACE) - infos[i].disabled = TRUE; + switch (hdr.write_mode) { + case AWE_WR_EXCLUSIVE: + /* exclusive mode - if the instrument already exists, + return error */ + for (rec = sf->infos; rec; rec = rec->next) { + if (rec->type == V_ST_NORMAL && + rec->bank == hdr.bank && + rec->instr == hdr.instr) + return -EINVAL; } + break; + case AWE_WR_REPLACE: + /* replace mode - remoe the instrument if it already exists */ + remove_info(sf, hdr.bank, hdr.instr); + break; } - if (hdr.write_mode == AWE_WR_REPLACE) - rebuild_preset_list(); -#endif - - if (alloc_new_info(hdr.nvoices) < 0) - return -ENOSPC; + /* append new layers */ for (i = 0; i < hdr.nvoices; i++) { - int rec = awe_free_info(); - - infos[rec].bank = hdr.bank; - infos[rec].instr = hdr.instr; - infos[rec].type = V_ST_NORMAL; - infos[rec].disabled = FALSE; + rec = alloc_new_info(); + if (rec == NULL) + return -ENOMEM; + + rec->bank = hdr.bank; + rec->instr = hdr.instr; + rec->type = V_ST_NORMAL; + rec->disabled = FALSE; /* copy awe_voice_info parameters */ - copy_from_user(&infos[rec].v, addr + offset, AWE_VOICE_INFO_SIZE); + if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) { + kfree(rec); + return -EFAULT; + } offset += AWE_VOICE_INFO_SIZE; - infos[rec].v.sf_id = current_sf_id; #ifdef AWE_ALLOW_SAMPLE_SHARING - if (sflists[current_sf_id-1].shared) { - if (info_duplicated(&infos[rec])) + if (sf && sf->shared) { + if (info_duplicated(sf, rec)) { + kfree(rec); continue; + } } #endif /* allow sharing */ - if (infos[rec].v.mode & AWE_MODE_INIT_PARM) - awe_init_voice_parm(&infos[rec].v.parm); - awe_set_sample(&infos[rec].v); + if (rec->v.mode & AWE_MODE_INIT_PARM) + awe_init_voice_parm(&rec->v.parm); + add_sf_info(sf, rec); + awe_set_sample(rec); add_info_list(rec); - add_sf_info(rec); } return 0; } +/* remove instrument layers */ +static int +awe_remove_info(awe_patch_info *patch, const char *addr, int count) +{ + unsigned char bank, instr; + sf_list *sf; + + if (! patch_opened || (sf = sftail) == NULL) { + printk(KERN_WARNING "AWE32: remove_info: patch not opened\n"); + return -EINVAL; + } + + bank = ((unsigned short)patch->optarg >> 8) & 0xff; + instr = (unsigned short)patch->optarg & 0xff; + if (! remove_info(sf, bank, instr)) + return -EINVAL; + return 0; +} + + /* load wave sample data */ static int awe_load_data(awe_patch_info *patch, const char *addr, int count) { int offset, size; - int rc, free_sample; - awe_sample_info tmprec, *rec; + int rc; + awe_sample_info tmprec; + awe_sample_list *rec; + sf_list *sf; - if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0) - return -ENOSPC; + if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL) + return -ENOMEM; size = (count - AWE_SAMPLE_INFO_SIZE) / 2; offset = AWE_PATCH_INFO_SIZE; - copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE); + if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE)) + return -EFAULT; offset += AWE_SAMPLE_INFO_SIZE; if (size != tmprec.size) { - printk("AWE32: load: sample size differed (%d != %d)\n", + printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n", tmprec.size, size); return -EINVAL; } - if (search_sample_index(current_sf_id, tmprec.sample, 0) >= 0) { + if (search_sample_index(sf, tmprec.sample) != NULL) { #ifdef AWE_ALLOW_SAMPLE_SHARING /* if shared sample, skip this data */ - if (sflists[current_sf_id-1].type & AWE_PAT_SHARED) + if (sf->type & AWE_PAT_SHARED) return 0; #endif /* allow sharing */ DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample)); return -EINVAL; } - if (alloc_new_sample() < 0) - return -ENOSPC; + if ((rec = alloc_new_sample()) == NULL) + return -ENOMEM; - free_sample = awe_free_sample(); - rec = &samples[free_sample].v; - *rec = tmprec; + memcpy(&rec->v, &tmprec, sizeof(tmprec)); - if (rec->size > 0) - if ((rc = awe_write_wave_data(addr, offset, rec, -1)) != 0) + if (rec->v.size > 0) { + if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) { + kfree(rec); return rc; + } + sf->mem_ptr += rc; + } - rec->sf_id = current_sf_id; - - add_sf_sample(free_sample); - + add_sf_sample(sf, rec); return 0; } @@ -3462,55 +3437,57 @@ { int offset; int size; - int rc, i; + int rc; int channels; awe_sample_info cursmp; int save_mem_ptr; + sf_list *sf; + awe_sample_list *rec; - if (! patch_opened) { - printk("AWE32: replace: patch not opened\n"); + if (! patch_opened || (sf = sftail) == NULL) { + printk(KERN_WARNING "AWE32: replace: patch not opened\n"); return -EINVAL; } size = (count - AWE_SAMPLE_INFO_SIZE) / 2; offset = AWE_PATCH_INFO_SIZE; - copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE); + if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE)) + return -EFAULT; offset += AWE_SAMPLE_INFO_SIZE; if (cursmp.size == 0 || size != cursmp.size) { - printk("AWE32: replace: illegal sample size (%d!=%d)\n", + printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n", cursmp.size, size); return -EINVAL; } channels = patch->optarg; if (channels <= 0 || channels > AWE_NORMAL_VOICES) { - printk("AWE32: replace: illegal channels %d\n", channels); + printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels); return -EINVAL; } - for (i = sflists[current_sf_id-1].samples; - i >= 0; i = samples[i].next) { - if (samples[i].v.sample == cursmp.sample) + for (rec = sf->samples; rec; rec = rec->next) { + if (rec->v.sample == cursmp.sample) break; } - if (i < 0) { - printk("AWE32: replace: cannot find existing sample data %d\n", + if (rec == NULL) { + printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n", cursmp.sample); return -EINVAL; } - if (samples[i].v.size != cursmp.size) { - printk("AWE32: replace: exiting size differed (%d!=%d)\n", - samples[i].v.size, cursmp.size); + if (rec->v.size != cursmp.size) { + printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n", + rec->v.size, cursmp.size); return -EINVAL; } save_mem_ptr = awe_free_mem_ptr(); - sflists[current_sf_id-1].mem_ptr = samples[i].v.start - awe_mem_start; - memcpy(&samples[i].v, &cursmp, sizeof(cursmp)); - if ((rc = awe_write_wave_data(addr, offset, &samples[i].v, channels)) != 0) + sftail->mem_ptr = rec->v.start - awe_mem_start; + memcpy(&rec->v, &cursmp, sizeof(cursmp)); + rec->v.sf_id = current_sf_id; + if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0) return rc; - sflists[current_sf_id-1].mem_ptr = save_mem_ptr; - samples[i].v.sf_id = current_sf_id; + sftail->mem_ptr = save_mem_ptr; return 0; } @@ -3521,28 +3498,11 @@ static const char *readbuf_addr; static int readbuf_offs; static int readbuf_flags; -#ifdef MALLOC_LOOP_DATA -static unsigned short *readbuf_loop; -static int readbuf_loopstart, readbuf_loopend; -#endif /* initialize read buffer */ static int readbuf_init(const char *addr, int offset, awe_sample_info *sp) { -#ifdef MALLOC_LOOP_DATA - readbuf_loop = NULL; - readbuf_loopstart = sp->loopstart; - readbuf_loopend = sp->loopend; - if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) { - int looplen = sp->loopend - sp->loopstart; - readbuf_loop = vmalloc(looplen * 2); - if (readbuf_loop == NULL) { - printk("AWE32: can't malloc temp buffer\n"); - return -ENOSPC; - } - } -#endif readbuf_addr = addr; readbuf_offs = offset; readbuf_flags = sp->mode_flags; @@ -3557,59 +3517,31 @@ /* read from user buffer */ if (readbuf_flags & AWE_SAMPLE_8BITS) { unsigned char cc; - get_user(cc, (unsigned char*)&(readbuf_addr)[readbuf_offs + pos]); - c = cc << 8; /* convert 8bit -> 16bit */ + get_user(cc, (unsigned char*)(readbuf_addr + readbuf_offs + pos)); + c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */ } else { - get_user(c, (unsigned short*)&(readbuf_addr)[readbuf_offs + pos * 2]); + get_user(c, (unsigned short*)(readbuf_addr + readbuf_offs + pos * 2)); } if (readbuf_flags & AWE_SAMPLE_UNSIGNED) c ^= 0x8000; /* unsigned -> signed */ -#ifdef MALLOC_LOOP_DATA - /* write on cache for reverse loop */ - if (readbuf_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) { - if (pos >= readbuf_loopstart && pos < readbuf_loopend) - readbuf_loop[pos - readbuf_loopstart] = c; - } -#endif return c; } -#ifdef MALLOC_LOOP_DATA -/* read from cache */ -static unsigned short -readbuf_word_cache(int pos) -{ - if (pos >= readbuf_loopstart && pos < readbuf_loopend) - return readbuf_loop[pos - readbuf_loopstart]; - return 0; -} - -static void -readbuf_end(void) -{ - if (readbuf_loop) - vfree(readbuf_loop); - readbuf_loop = NULL; -} - -#else - #define readbuf_word_cache readbuf_word #define readbuf_end() /**/ -#endif - /*----------------------------------------------------------------*/ #define BLANK_LOOP_START 8 #define BLANK_LOOP_END 40 #define BLANK_LOOP_SIZE 48 -/* loading onto memory */ +/* loading onto memory - return the actual written size */ static int -awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels) +awe_write_wave_data(const char *addr, int offset, awe_sample_list *list, int channels) { int i, truesize, dram_offset; + awe_sample_info *sp = &list->v; int rc; /* be sure loop points start < end */ @@ -3621,11 +3553,11 @@ /* compute true data size to be loaded */ truesize = sp->size; - if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) + if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) truesize += sp->loopend - sp->loopstart; if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) truesize += BLANK_LOOP_SIZE; - if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) { + if (awe_free_mem_ptr() + truesize >= memsize/2) { DEBUG(-1,printk("AWE32 Error: Sample memory full\n")); return -ENOSPC; } @@ -3686,13 +3618,12 @@ } } - sflists[current_sf_id-1].mem_ptr += truesize; awe_close_dram(); /* initialize FM */ awe_init_fm(); - return 0; + return truesize; } @@ -3728,33 +3659,36 @@ struct patch_info patch; awe_voice_info *rec; awe_sample_info *smp; + awe_voice_list *vrec; + awe_sample_list *smprec; int sizeof_patch; - int note, free_sample, free_info; - int rc; + int note, rc; + sf_list *sf; sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */ if (size < sizeof_patch) { - printk("AWE32 Error: Patch header too short\n"); + printk(KERN_WARNING "AWE32 Error: Patch header too short\n"); return -EINVAL; } - copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs); + if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs)) + return -EFAULT; size -= sizeof_patch; if (size < patch.len) { - printk("AWE32 Warning: Patch record too short (%d<%d)\n", + printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n", size, patch.len); return -EINVAL; } - if (check_patch_opened(AWE_PAT_TYPE_GUS, NULL) < 0) - return -ENOSPC; - if (alloc_new_sample() < 0) - return -ENOSPC; - if (alloc_new_info(1)) - return -ENOSPC; - - free_sample = awe_free_sample(); - smp = &samples[free_sample].v; + if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL) + return -ENOMEM; + if ((smprec = alloc_new_sample()) == NULL) + return -ENOMEM; + if ((vrec = alloc_new_info()) == NULL) { + kfree(smprec); + return -ENOMEM; + } - smp->sample = free_sample; + smp = &smprec->v; + smp->sample = sf->num_sample; smp->start = 0; smp->end = patch.len; smp->loopstart = patch.loop_start; @@ -3786,17 +3720,15 @@ smp->checksum_flag = 0; smp->checksum = 0; - if ((rc = awe_write_wave_data(addr, sizeof_patch, smp, -1)) != 0) + if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) return rc; - - smp->sf_id = current_sf_id; - add_sf_sample(free_sample); + sf->mem_ptr += rc; + add_sf_sample(sf, smprec); /* set up voice info */ - free_info = awe_free_info(); - rec = &infos[free_info].v; + rec = &vrec->v; awe_init_voice_info(rec); - rec->sample = free_sample; /* the last sample */ + rec->sample = sf->num_info; /* the last sample */ rec->rate_offset = calc_rate_offset(patch.base_freq); note = freq_to_note(patch.base_note); rec->root = note / 100; @@ -3831,8 +3763,8 @@ release += calc_gus_envelope_time (patch.env_rate[5], patch.env_offset[4], patch.env_offset[5]); - rec->parm.volatkhld = (calc_parm_attack(attack) << 8) | - calc_parm_hold(hold); + rec->parm.volatkhld = (calc_parm_hold(hold) << 8) | + calc_parm_attack(attack); rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) | calc_parm_decay(decay); rec->parm.volrelease = 0x8000 | calc_parm_decay(release); @@ -3860,17 +3792,16 @@ /* scale_freq, scale_factor, volume, and fractions not implemented */ /* append to the tail of the list */ - infos[free_info].bank = ctrls[AWE_MD_GUS_BANK]; - infos[free_info].instr = patch.instr_no; - infos[free_info].disabled = FALSE; - infos[free_info].type = V_ST_NORMAL; - infos[free_info].v.sf_id = current_sf_id; + vrec->bank = ctrls[AWE_MD_GUS_BANK]; + vrec->instr = patch.instr_no; + vrec->disabled = FALSE; + vrec->type = V_ST_NORMAL; - add_info_list(free_info); - add_sf_info(free_info); + add_sf_info(sf, vrec); + add_info_list(vrec); /* set the voice index */ - awe_set_sample(rec); + awe_set_sample(vrec); return 0; } @@ -3881,96 +3812,100 @@ * sample and voice list handlers */ -/* append this to the sf list */ -static void add_sf_info(int rec) +/* append this to the current sf list */ +static void add_sf_info(sf_list *sf, awe_voice_list *rec) { - int sf_id = infos[rec].v.sf_id; - if (sf_id <= 0) return; - sf_id--; - if (sflists[sf_id].infos < 0) - sflists[sf_id].infos = rec; - else { - int i, prev; - prev = sflists[sf_id].infos; - while ((i = infos[prev].next) >= 0) - prev = i; - infos[prev].next = rec; - } - infos[rec].next = -1; - sflists[sf_id].num_info++; + if (sf == NULL) + return; + rec->holder = sf; + rec->v.sf_id = sf->sf_id; + if (sf->last_infos) + sf->last_infos->next = rec; + else + sf->infos = rec; + sf->last_infos = rec; + rec->next = NULL; + sf->num_info++; } /* prepend this sample to sf list */ -static void add_sf_sample(int rec) +static void add_sf_sample(sf_list *sf, awe_sample_list *rec) { - int sf_id = samples[rec].v.sf_id; - if (sf_id <= 0) return; - sf_id--; - samples[rec].next = sflists[sf_id].samples; - sflists[sf_id].samples = rec; - sflists[sf_id].num_sample++; + if (sf == NULL) + return; + rec->holder = sf; + rec->v.sf_id = sf->sf_id; + if (sf->last_samples) + sf->last_samples->next = rec; + else + sf->samples = rec; + sf->last_samples = rec; + rec->next = NULL; + sf->num_sample++; } /* purge the old records which don't belong with the same file id */ -static void purge_old_list(int rec, int next) +static void purge_old_list(awe_voice_list *rec, awe_voice_list *next) { - infos[rec].next_instr = next; - if (infos[rec].bank == AWE_DRUM_BANK) { + rec->next_instr = next; + if (rec->bank == AWE_DRUM_BANK) { /* remove samples with the same note range */ - int cur, *prevp = &infos[rec].next_instr; - int low = infos[rec].v.low; - int high = infos[rec].v.high; - for (cur = next; cur >= 0; cur = infos[cur].next_instr) { - if (infos[cur].v.low == low && - infos[cur].v.high == high && - ! is_identical_id(infos[cur].v.sf_id, infos[rec].v.sf_id)) - *prevp = infos[cur].next_instr; - prevp = &infos[cur].next_instr; + awe_voice_list *cur, *prev = rec; + int low = rec->v.low; + int high = rec->v.high; + for (cur = next; cur; cur = cur->next_instr) { + if (cur->v.low == low && + cur->v.high == high && + ! is_identical_holder(cur->holder, rec->holder)) + prev->next_instr = cur->next_instr; + else + prev = cur; } } else { - if (! is_identical_id(infos[next].v.sf_id, infos[rec].v.sf_id)) - infos[rec].next_instr = -1; + if (! is_identical_holder(next->holder, rec->holder)) + /* remove all samples */ + rec->next_instr = NULL; } } /* prepend to top of the preset table */ -static void add_info_list(int rec) +static void add_info_list(awe_voice_list *rec) { - int *prevp, cur; - int instr; - int bank; + awe_voice_list *prev, *cur; + int key; - if (infos[rec].disabled) + if (rec->disabled) return; - instr = infos[rec].instr; - bank = infos[rec].bank; - limitvalue(instr, 0, AWE_MAX_PRESETS-1); - prevp = &preset_table[instr]; - cur = *prevp; - while (cur >= 0) { + key = awe_search_key(rec->bank, rec->instr, rec->v.low); + prev = NULL; + for (cur = preset_table[key]; cur; cur = cur->next_bank) { /* search the first record with the same bank number */ - if (infos[cur].bank == bank) { + if (cur->instr == rec->instr && cur->bank == rec->bank) { /* replace the list with the new record */ - infos[rec].next_bank = infos[cur].next_bank; - *prevp = rec; + rec->next_bank = cur->next_bank; + if (prev) + prev->next_bank = rec; + else + preset_table[key] = rec; purge_old_list(rec, cur); return; } - prevp = &infos[cur].next_bank; - cur = infos[cur].next_bank; + prev = cur; } /* this is the first bank record.. just add this */ - infos[rec].next_instr = -1; - infos[rec].next_bank = preset_table[instr]; - preset_table[instr] = rec; + rec->next_instr = NULL; + rec->next_bank = preset_table[key]; + preset_table[key] = rec; } /* remove samples later than the specified sf_id */ static void awe_remove_samples(int sf_id) { + sf_list *p, *prev; + if (sf_id <= 0) { awe_reset_samples(); return; @@ -3979,6 +3914,20 @@ if (current_sf_id <= sf_id) return; + for (p = sftail; p; p = prev) { + if (p->sf_id <= sf_id) + break; + prev = p->prev; + awe_free_sf(p); + } + sftail = p; + if (sftail) { + sf_id = sftail->sf_id; + sftail->next = NULL; + } else { + sf_id = 0; + sfhead = NULL; + } current_sf_id = sf_id; if (locked_sf_id > sf_id) locked_sf_id = sf_id; @@ -3989,33 +3938,36 @@ /* rebuild preset search list */ static void rebuild_preset_list(void) { - int i, j; + sf_list *p; + awe_voice_list *rec; - for (i = 0; i < AWE_MAX_PRESETS; i++) - preset_table[i] = -1; + memset(preset_table, 0, sizeof(preset_table)); - for (i = 0; i < current_sf_id; i++) { - for (j = sflists[i].infos; j >= 0; j = infos[j].next) - add_info_list(j); + for (p = sfhead; p; p = p->next) { + for (rec = p->infos; rec; rec = rec->next) + add_info_list(rec); } } /* compare the given sf_id pair */ -static int is_identical_id(int id1, int id2) +static int is_identical_holder(sf_list *sf1, sf_list *sf2) { - if (id1 == id2) - return TRUE; - if (id1 <= 0 || id2 <= 0) /* this must not happen.. */ + if (sf1 == NULL || sf2 == NULL) return FALSE; + if (sf1 == sf2) + return TRUE; #ifdef AWE_ALLOW_SAMPLE_SHARING { /* compare with the sharing id */ - int i; - if (id1 < id2) { /* make sure id1 > id2 */ - int tmp; tmp = id1; id1 = id2; id2 = tmp; - } - for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) { - if (i == id2) + sf_list *p; + int counter = 0; + if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */ + sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp; + } + for (p = sf1->shared; p; p = p->shared) { + if (counter++ > current_sf_id) + break; /* strange sharing loop.. quit */ + if (p == sf2) return TRUE; } } @@ -4024,73 +3976,81 @@ } /* search the sample index matching with the given sample id */ -static int search_sample_index(int sf, int sample, int level) +static awe_sample_list * +search_sample_index(sf_list *sf, int sample) { - int i; - - if (sf <= 0 || sf > current_sf_id) - return -1; /* this must not happen */ - - for (i = sflists[sf-1].samples; i >= 0; i = samples[i].next) { - if (samples[i].v.sample == sample) - return i; - } + awe_sample_list *p; #ifdef AWE_ALLOW_SAMPLE_SHARING - if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */ - if (level > current_sf_id) - return -1; /* strange sharing loop.. quit */ - return search_sample_index(i, sample, level + 1); + int counter = 0; + while (sf) { + for (p = sf->samples; p; p = p->next) { + if (p->v.sample == sample) + return p; + } + sf = sf->shared; + if (counter++ > current_sf_id) + break; /* strange sharing loop.. quit */ + } +#else + if (sf) { + for (p = sf->samples; p; p = p->next) { + if (p->v.sample == sample) + return p; + } } #endif - return -1; + return NULL; } /* search the specified sample */ +/* non-zero = found */ static short -awe_set_sample(awe_voice_info *vp) +awe_set_sample(awe_voice_list *rec) { - int i; + awe_sample_list *smp; + awe_voice_info *vp = &rec->v; - vp->index = -1; - if ((i = search_sample_index(vp->sf_id, vp->sample, 0)) < 0) - return -1; + vp->index = 0; + if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL) + return 0; /* set the actual sample offsets */ - vp->start += samples[i].v.start; - vp->end += samples[i].v.end; - vp->loopstart += samples[i].v.loopstart; - vp->loopend += samples[i].v.loopend; + vp->start += smp->v.start; + vp->end += smp->v.end; + vp->loopstart += smp->v.loopstart; + vp->loopend += smp->v.loopend; /* copy mode flags */ - vp->mode = samples[i].v.mode_flags; - /* set index */ - vp->index = i; + vp->mode = smp->v.mode_flags; + /* set flag */ + vp->index = 1; - return i; + return 1; } -/*---------------------------------------------------------------- +/* * voice allocation - *----------------------------------------------------------------*/ + */ /* look for all voices associated with the specified note & velocity */ static int -awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist) +awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, + awe_voice_info **vlist) { int nvoices; nvoices = 0; - for (; rec >= 0; rec = infos[rec].next_instr) { - if (note >= infos[rec].v.low && - note <= infos[rec].v.high && - velocity >= infos[rec].v.vellow && - velocity <= infos[rec].v.velhigh) { - if (infos[rec].type == V_ST_MAPPED) { + for (; rec; rec = rec->next_instr) { + if (note >= rec->v.low && + note <= rec->v.high && + velocity >= rec->v.vellow && + velocity <= rec->v.velhigh) { + if (rec->type == V_ST_MAPPED) { /* mapper */ - vlist[0] = &infos[rec].v; + vlist[0] = &rec->v; return -1; } - vlist[nvoices++] = &infos[rec].v; + vlist[nvoices++] = &rec->v; if (nvoices >= AWE_MAX_VOICES) break; } @@ -4103,29 +4063,45 @@ the note number if necessary. */ static int -really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_info **vlist, int level) +really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist) { int nvoices; + awe_voice_list *vrec; + int level = 0; - nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); - if (nvoices == 0) - nvoices = awe_search_multi_voices(def_vrec, *note, velocity, vlist); - if (nvoices < 0) { /* mapping */ - int preset = vlist[0]->start; - int bank = vlist[0]->end; - int key = vlist[0]->fixkey; - if (level > 5) { - printk("AWE32: too deep mapping level\n"); - return 0; - } - vrec = awe_search_instr(bank, preset); - if (bank == AWE_DRUM_BANK) - def_vrec = awe_search_instr(bank, 0); - else - def_vrec = awe_search_instr(0, preset); - if (key >= 0) - *note = key; - return really_alloc_voices(vrec, def_vrec, note, velocity, vlist, level+1); + for (;;) { + vrec = awe_search_instr(bank, instr, *note); + nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); + if (nvoices == 0) { + if (bank == AWE_DRUM_BANK) + /* search default drumset */ + vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note); + else + /* search default preset */ + vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note); + nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); + } + if (nvoices == 0) { + if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0) + /* search default drumset */ + vrec = awe_search_instr(bank, 0, *note); + else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0) + /* search default preset */ + vrec = awe_search_instr(0, instr, *note); + nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist); + } + if (nvoices < 0) { /* mapping */ + int key = vlist[0]->fixkey; + instr = vlist[0]->start; + bank = vlist[0]->end; + if (level++ > 5) { + printk(KERN_ERR "AWE32: too deep mapping level\n"); + return 0; + } + if (key >= 0) + *note = key; + } else + break; } return nvoices; @@ -4135,15 +4111,17 @@ static void awe_alloc_multi_voices(int ch, int note, int velocity, int key) { - int i, v, nvoices; + int i, v, nvoices, bank; awe_voice_info *vlist[AWE_MAX_VOICES]; - if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0) - awe_set_instr(0, ch, channels[ch].instr); + if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) + bank = AWE_DRUM_BANK; /* always search drumset */ + else + bank = channels[ch].bank; /* check the possible voices; note may be changeable if mapped */ - nvoices = really_alloc_voices(channels[ch].vrec, channels[ch].def_vrec, - ¬e, velocity, vlist, 0); + nvoices = really_alloc_voices(bank, channels[ch].instr, + ¬e, velocity, vlist); /* set the voices */ current_alloc_time++; @@ -4169,78 +4147,62 @@ } -/* search the best voice from the specified status condition */ +/* search an empty voice. + if no empty voice is found, at least terminate a voice + */ static int -search_best_voice(int condition) +awe_clear_voice(void) { - int i, time, best; - int vtarget = 0xffff, min_vtarget = 0xffff; + enum { + OFF=0, RELEASED, SUSTAINED, PLAYING, END + }; + struct voice_candidate_t { + int best; + int time; + int vtarget; + } candidate[END]; + int i, type, vtarget; + + vtarget = 0xffff; + for (type = OFF; type < END; type++) { + candidate[type].best = -1; + candidate[type].time = current_alloc_time + 1; + candidate[type].vtarget = vtarget; + } - best = -1; - time = current_alloc_time + 1; for (i = 0; i < awe_max_voices; i++) { - if (! (voices[i].state & condition)) + if (voices[i].state & AWE_ST_OFF) + type = OFF; + else if (voices[i].state & AWE_ST_RELEASED) + type = RELEASED; + else if (voices[i].state & AWE_ST_SUSTAINED) + type = SUSTAINED; + else if (voices[i].state & ~AWE_ST_MARK) + type = PLAYING; + else continue; #ifdef AWE_CHECK_VTARGET /* get current volume */ vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff; #endif - if (best < 0 || vtarget < min_vtarget || - (vtarget == min_vtarget && voices[i].time < time)) { - best = i; - time = voices[i].time; - min_vtarget = vtarget; + if (candidate[type].best < 0 || + vtarget < candidate[type].vtarget || + (vtarget == candidate[type].vtarget && + voices[i].time < candidate[type].time)) { + candidate[type].best = i; + candidate[type].time = voices[i].time; + candidate[type].vtarget = vtarget; } } - /* clear voice */ - if (best >= 0) { - if (voices[best].state != AWE_ST_OFF) - awe_terminate(best); - awe_voice_init(best, TRUE); - } - - return best; -} - -/* search an empty voice. - if no empty voice is found, at least terminate a voice - */ -static int -awe_clear_voice(void) -{ - int best; - /* looking for the oldest empty voice */ - if ((best = search_best_voice(AWE_ST_OFF)) >= 0) - return best; - if ((best = search_best_voice(AWE_ST_RELEASED)) >= 0) - return best; - /* looking for the oldest sustained voice */ - if ((best = search_best_voice(AWE_ST_SUSTAINED)) >= 0) - return best; - - if (MULTI_LAYER_MODE() && ctrls[AWE_MD_CHN_PRIOR]) { - int ch = -1; - int time = current_alloc_time + 1; - int i; - /* looking for the voices from high channel (except drum ch) */ - for (i = 0; i < awe_max_voices; i++) { - if (IS_DRUM_CHANNEL(voices[i].ch)) continue; - if (voices[i].ch < ch) continue; - if (voices[i].state != AWE_ST_MARK && - (voices[i].ch > ch || voices[i].time < time)) { - best = i; - time = voices[i].time; - ch = voices[i].ch; - } + for (type = OFF; type < END; type++) { + if ((i = candidate[type].best) >= 0) { + if (voices[i].state != AWE_ST_OFF) + awe_terminate(i); + awe_voice_init(i, TRUE); + return i; } } - if (best < 0) - best = search_best_voice(~AWE_ST_MARK); - - if (best >= 0) - return best; - return 0; } @@ -4251,16 +4213,17 @@ static void awe_alloc_one_voice(int voice, int note, int velocity) { - int ch, nvoices; + int ch, nvoices, bank; awe_voice_info *vlist[AWE_MAX_VOICES]; ch = voices[voice].ch; - if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0) - awe_set_instr(0, ch, channels[ch].instr); + if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice)) + bank = AWE_DRUM_BANK; /* always search drumset */ + else + bank = voices[voice].cinfo->bank; - nvoices = really_alloc_voices(voices[voice].cinfo->vrec, - voices[voice].cinfo->def_vrec, - ¬e, velocity, vlist, 0); + nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr, + ¬e, velocity, vlist); if (nvoices > 0) { voices[voice].time = ++current_alloc_time; voices[voice].sample = vlist[0]; /* use the first one */ @@ -4271,9 +4234,9 @@ } -/*---------------------------------------------------------------- +/* * sequencer2 functions - *----------------------------------------------------------------*/ + */ /* search an empty voice; used by sequencer2 */ static int @@ -4331,14 +4294,14 @@ awe_mixer_ioctl, }; -static void attach_mixer(void) +static void __init attach_mixer(void) { if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) { mixer_devs[my_mixerdev] = &awe_mixer_operations; } } -static void unload_mixer(void) +static void __exit unload_mixer(void) { if (my_mixerdev >= 0) sound_unload_mixerdev(my_mixerdev); @@ -4352,7 +4315,7 @@ if (((cmd >> 8) & 0xff) != 'M') return -EINVAL; - level = (int) *(int *)arg; + level = *(int*)arg; level = ((level & 0xff) + (level >> 8)) / 2; DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level)); @@ -4408,13 +4371,13 @@ level = 0; break; } - return *(int *)arg = level; + return *(int*)arg = level; } #endif /* CONFIG_AWE32_MIXER */ /* - * initialization of AWE32 + * initialization of Emu8000 */ /* intiailize audio channels */ @@ -4636,7 +4599,7 @@ { #ifndef AWE_ALWAYS_INIT_FM /* if no extended memory is on board.. */ - if (awe_mem_size <= 0) + if (memsize <= 0) return; #endif DEBUG(3,printk("AWE32: initializing FM\n")); @@ -4731,7 +4694,8 @@ awe_poke_dw(AWE_CCCA(vidx[i]), 0); voices[vidx[i]].state = AWE_ST_OFF; } - return -ENOSPC; + printk("awe: not ready to write..\n"); + return -EPERM; } /* set address to write */ @@ -4784,13 +4748,13 @@ } -/*================================================================ +/* * detect presence of AWE32 and check memory size - *================================================================*/ + */ /* detect emu8000 chip on the specified address; from VV's guide */ -static int +static int __init awe_detect_base(int addr) { setup_ports(addr, 0, 0); @@ -4804,16 +4768,79 @@ return 1; } -static int +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static struct { + unsigned short vendor; + unsigned short function; + char *name; +} isapnp_awe_list[] __initdata = { + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), "AWE32 WaveTable"}, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), "AWE64 WaveTable"}, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), "AWE64 Gold WaveTable"}, + {0,} +}; + +static struct pci_dev *idev = NULL; + +static int __init awe_probe_isapnp(int *port) +{ + int i; + + for (i = 0; isapnp_awe_list[i].vendor != 0; i++) { + while ((idev = isapnp_find_dev(NULL, + isapnp_awe_list[i].vendor, + isapnp_awe_list[i].function, + idev))) { + if (idev->prepare(idev) < 0) + continue; + if (idev->activate(idev) < 0 || + !idev->resource[0].start) { + idev->deactivate(idev); + idev->deactivate(idev); + continue; + } + *port = idev->resource[0].start; + break; + } + if (!idev) + continue; + printk(KERN_INFO "ISAPnP reports %s at i/o %#x\n", + isapnp_awe_list[i].name, *port); + return 0; + } + return -ENODEV; +} + +static void __exit awe_deactivate_isapnp(void) +{ +#if 1 + if (idev) { + idev->deactivate(idev); + idev = NULL; + } +#endif +} + +#endif + +static int __init awe_detect(void) { int base; - if (port_setuped) /* already initialized by PnP */ +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (isapnp) { + if (awe_probe_isapnp(&io) < 0) { + printk(KERN_ERR "AWE32: No ISAPnP cards found\n"); + return 0; + } + setup_ports(io, 0, 0); return 1; + } +#endif /* isapnp */ - if (awe_port) /* use default i/o port value */ - setup_ports(awe_port, 0, 0); + if (io) /* use default i/o port value */ + setup_ports(io, 0, 0); else { /* probe it */ for (base = 0x620; base <= 0x680; base += 0x20) if (awe_detect_base(base)) @@ -4826,36 +4853,36 @@ } -/*================================================================ +/* * check dram size on AWE board - *================================================================*/ + */ /* any three numbers you like */ #define UNIQUE_ID1 0x1234 #define UNIQUE_ID2 0x4321 #define UNIQUE_ID3 0xFFFF -static void +static void __init awe_check_dram(void) { if (awe_present) /* already initialized */ return; - if (awe_mem_size >= 0) { /* given by config file or module option */ - awe_mem_size *= 1024; /* convert to Kbytes */ + if (memsize >= 0) { /* given by config file or module option */ + memsize *= 1024; /* convert to Kbytes */ return; } awe_open_dram_for_check(); - awe_mem_size = 0; + memsize = 0; /* set up unique two id numbers */ awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET); awe_poke(AWE_SMLD, UNIQUE_ID1); awe_poke(AWE_SMLD, UNIQUE_ID2); - while (awe_mem_size < AWE_MAX_DRAM_SIZE) { + while (memsize < AWE_MAX_DRAM_SIZE) { awe_wait(5); /* read a data on the DRAM start address */ awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET); @@ -4864,33 +4891,35 @@ break; if (awe_peek(AWE_SMLD) != UNIQUE_ID2) break; - awe_mem_size += 512; /* increment 512kbytes */ + memsize += 512; /* increment 512kbytes */ /* Write a unique data on the test address; * if the address is out of range, the data is written on * 0x200000(=AWE_DRAM_OFFSET). Then the two id words are * broken by this data. */ - awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + awe_mem_size*512L); + awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L); awe_poke(AWE_SMLD, UNIQUE_ID3); awe_wait(5); /* read a data on the just written DRAM address */ - awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + awe_mem_size*512L); + awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L); awe_peek(AWE_SMLD); /* discard stale data */ if (awe_peek(AWE_SMLD) != UNIQUE_ID3) break; } awe_close_dram(); - DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", awe_mem_size)); + DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize)); /* convert to Kbytes */ - awe_mem_size *= 1024; + memsize *= 1024; } -/*================================================================ +/*----------------------------------------------------------------*/ + +/* * chorus and reverb controls; from VV's guide - *================================================================*/ + */ /* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */ static char chorus_defined[AWE_CHORUS_NUMBERS]; @@ -4909,15 +4938,16 @@ awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count) { if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) { - printk("AWE32 Error: illegal chorus mode %d for uploading\n", patch->optarg); + printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg); return -EINVAL; } if (count < sizeof(awe_chorus_fx_rec)) { - printk("AWE32 Error: too short chorus fx parameters\n"); + printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n"); return -EINVAL; } - copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, - sizeof(awe_chorus_fx_rec)); + if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, + sizeof(awe_chorus_fx_rec))) + return -EFAULT; chorus_defined[patch->optarg] = TRUE; return 0; } @@ -5016,15 +5046,16 @@ awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count) { if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) { - printk("AWE32 Error: illegal reverb mode %d for uploading\n", patch->optarg); + printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg); return -EINVAL; } if (count < sizeof(awe_reverb_fx_rec)) { - printk("AWE32 Error: too short reverb fx parameters\n"); + printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n"); return -EINVAL; } - copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, - sizeof(awe_reverb_fx_rec)); + if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE, + sizeof(awe_reverb_fx_rec))) + return -EFAULT; reverb_defined[patch->optarg] = TRUE; return 0; } @@ -5047,9 +5078,9 @@ awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]); } -/*================================================================ +/* * treble/bass equalizer control - *================================================================*/ + */ static unsigned short bass_parm[12][3] = { {0xD26A, 0xD36A, 0x0000}, /* -12 dB */ @@ -5113,15 +5144,17 @@ } +/*----------------------------------------------------------------*/ + #ifdef CONFIG_AWE32_MIDIEMU -/*================================================================ +/* * Emu8000 MIDI Emulation - *================================================================*/ + */ -/*================================================================ +/* * midi queue record - *================================================================*/ + */ /* queue type */ enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, }; @@ -5149,9 +5182,9 @@ } ConvTable; -/*================================================================ +/* * prototypes - *================================================================*/ + */ static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int)); static void awe_midi_close(int dev); @@ -5183,9 +5216,9 @@ #define numberof(ary) (sizeof(ary)/sizeof(ary[0])) -/*================================================================ +/* * OSS Midi device record - *================================================================*/ + */ static struct midi_operations awe_midi_operations = { @@ -5204,7 +5237,7 @@ static int my_mididev = -1; -static void attach_midiemu(void) +static void __init attach_midiemu(void) { if ((my_mididev = sound_alloc_mididev()) < 0) printk ("Sound: Too many midi devices detected\n"); @@ -5212,7 +5245,7 @@ midi_devs[my_mididev] = &awe_midi_operations; } -static void unload_midiemu(void) +static void __exit unload_midiemu(void) { if (my_mididev >= 0) sound_unload_mididev(my_mididev); @@ -5632,9 +5665,9 @@ } -/*================================================================ +/* * RPN events - *================================================================*/ + */ static void midi_rpn_event(MidiStatus *st) { @@ -5686,10 +5719,10 @@ } -/*================================================================ +/* * system exclusive message * GM/GS/XG macros are accepted - *================================================================*/ + */ static void midi_system_exclusive(MidiStatus *st) { @@ -5784,6 +5817,8 @@ } +/*----------------------------------------------------------------*/ + /* * convert NRPN/control values */ @@ -6006,9 +6041,9 @@ static int num_gs_effects = numberof(gs_effects); -/*================================================================ +/* * NRPN events: accept as AWE32/SC88 specific controls - *================================================================*/ + */ static void midi_nrpn_event(MidiStatus *st) { @@ -6026,9 +6061,9 @@ } -/*---------------------------------------------------------------- +/* * XG control effects; still experimental - *----------------------------------------------------------------*/ + */ /* cutoff: quarter semitone step, max=255 */ static unsigned short xg_cutoff(int val) @@ -6071,45 +6106,42 @@ #endif /* CONFIG_AWE32_MIDIEMU */ -/* new type interface */ -static int __init attach_awe(void) + +/*----------------------------------------------------------------*/ + +/* + * device / lowlevel (module) interface + */ + +int __init attach_awe(void) { -#ifdef CONFIG_PNP_DRV - if (pnp) { - awe_initpnp(); - if (awe_pnp_ok) - return 0; - } -#endif /* pnp */ - - _attach_awe(); - - return 0; -} + return _attach_awe() ? 0 : -ENODEV; +} -static void __exit unload_awe(void) +void __exit unload_awe(void) { -#ifdef CONFIG_PNP_DRV - if (pnp) - awe_unload_pnp(); -#endif - _unload_awe(); +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if (isapnp) + awe_deactivate_isapnp(); +#endif /* isapnp */ } + module_init(attach_awe); module_exit(unload_awe); #ifndef MODULE static int __init setup_awe(char *str) { - /* io, memsize */ - int ints[3]; + /* io, memsize, isapnp */ + int ints[4]; str = get_options(str, ARRAY_SIZE(ints), ints); io = ints[1]; memsize = ints[2]; + isapnp = ints[3]; return 1; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/awe_wave.h linux/drivers/sound/awe_wave.h --- v2.3.99-pre2/linux/drivers/sound/awe_wave.h Fri Mar 10 16:40:44 2000 +++ linux/drivers/sound/awe_wave.h Tue Mar 21 11:10:45 2000 @@ -2,7 +2,7 @@ * sound/awe_config.h * * Configuration of AWE32/SB32/AWE64 wave table synth driver. - * version 0.4.3; Mar. 1, 1998 + * version 0.4.4; Jan. 4, 2000 * * Copyright (C) 1996-1998 Takashi Iwai * @@ -68,20 +68,10 @@ /*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */ /* - * maximum size of soundfont list table + * AWE driver version number */ - -#define AWE_MAX_SF_LISTS 16 - -/* - * chunk size of sample and voice tables - */ - -#define AWE_MAX_SAMPLES 400 -#define AWE_MAX_INFOS 800 - #define AWE_MAJOR_VERSION 0 #define AWE_MINOR_VERSION 4 -#define AWE_TINY_VERSION 3 +#define AWE_TINY_VERSION 4 #define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION) -#define AWEDRV_VERSION "0.4.3" +#define AWEDRV_VERSION "0.4.4" diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.3.99-pre2/linux/drivers/sound/sb.h Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/sb.h Mon Mar 20 07:40:59 2000 @@ -151,6 +151,7 @@ int sb_dsp_init (struct address_info *hw_config); void sb_dsp_unload(struct address_info *hw_config, int sbmpu); int sb_mixer_init(sb_devc *devc); +void sb_mixer_unload(sb_devc *devc); void sb_mixer_set_stereo (sb_devc *devc, int mode); void smw_mixer_init(sb_devc *devc); void sb_dsp_midi_init (sb_devc *devc); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.3.99-pre2/linux/drivers/sound/sb_card.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sound/sb_card.c Wed Mar 22 15:37:02 2000 @@ -29,6 +29,10 @@ * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup * Alessandro Zummo * + * 13-03-2000 Added some more cards, thanks to Torsten Werner. + * Removed joystick and wavetable code, there are better places for them. + * Code cleanup plus some fixes. + * */ #include @@ -145,10 +149,7 @@ static struct address_info cfg_mpu; struct pci_dev *sb_dev = NULL, - *wss_dev = NULL, - *jp_dev = NULL, - *mpu_dev = NULL, - *wt_dev = NULL; + *mpu_dev = NULL; /* * Note DMA2 of -1 has the right meaning in the SB16 driver as well * as here. It will cause either an error if it is needed or a fallback @@ -166,10 +167,9 @@ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE static int isapnp = 1; static int isapnpjump = 0; -static int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be - in the kernel tree */ +static int activated = 1; #else -int isapnp = 0; +static int isapnp = 0; #endif MODULE_DESCRIPTION("Soundblaster driver"); @@ -187,10 +187,8 @@ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE MODULE_PARM(isapnp, "i"); MODULE_PARM(isapnpjump, "i"); -MODULE_PARM(nosbwave, "i"); MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); -MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver."); #endif MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); @@ -213,12 +211,13 @@ { int err; + /* Device already active? Let's use it */ + if(dev->active) { - printk(KERN_INFO "sb: %s %s already in use\n", devname, resname); - return(NULL); + activated = 0; + return(dev); } - if((err = dev->activate(dev)) < 0) { printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err); @@ -324,42 +323,6 @@ else printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n"); - - /* @P@:Gameport - */ - - if((jp_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - jp_dev->prepare(jp_dev); - - if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev))) - show_base("CMI8330", "gameport", &jp_dev->resource[0]); - } - else - printk(KERN_ERR "sb: CMI8330 panic: gameport not found\n"); - - /* @@@0001:OPL3 - */ - -#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) - if((wss_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - wss_dev->prepare(wss_dev); - - /* Let's disable IRQ and DMA for WSS device */ - - wss_dev->irq_resource[0].flags = 0; - wss_dev->dma_resource[0].flags = 0; - - if((wss_dev = activate_dev("CMI8330", "opl3", wss_dev))) - show_base("CMI8330", "opl3", &wss_dev->resource[1]); - } - else - printk(KERN_ERR "sb: CMI8330 panic: opl3 not found\n"); -#endif - printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo \n"); return(sb_dev); @@ -391,7 +354,6 @@ } if(!sb_dev) return(NULL); - } else printk(KERN_ERR "sb: DT0197H panic: sb base not found\n"); @@ -413,169 +375,100 @@ else printk(KERN_ERR "sb: DT0197H panic: mpu not found\n"); - - /* @P@:Gameport - */ - - if((jp_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - jp_dev->prepare(jp_dev); - - if((jp_dev = activate_dev("DT0197H", "gameport", jp_dev))) - show_base("DT0197H", "gameport", &jp_dev->resource[0]); - } - else - printk(KERN_ERR "sb: DT0197H panic: gameport not found\n"); - - /* @H@0001:OPL3 - */ - -#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) - if((wss_dev = isapnp_find_dev(bus, - ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) - { - wss_dev->prepare(wss_dev); - - /* Let's disable IRQ and DMA for WSS device */ - - wss_dev->irq_resource[0].flags = 0; - wss_dev->dma_resource[0].flags = 0; - - if((wss_dev = activate_dev("DT0197H", "opl3", wss_dev))) - show_base("DT0197H", "opl3", &wss_dev->resource[0]); - } - else - printk(KERN_ERR "sb: DT0197H panic: opl3 not found\n"); -#endif - printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner \n"); return(sb_dev); } -/* Specific support for awe will be dropped when: - * a) The new awe_wawe driver with PnP support will be introduced in the kernel - * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-) - */ - -static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init_als(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) { - /* CTL0042:Audio SB64 - * CTL0031:Audio SB32 - * CTL0045:Audio SB64 + /* + * ALS100 + * very similar to both ones above above + */ + + /* @@@0001:Soundblaster. */ - if( (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) || - (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) || - (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL)) ) + if((sb_dev = isapnp_find_dev(bus, + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) { sb_dev->prepare(sb_dev); - if((sb_dev = activate_dev("AWE", "sb", sb_dev))) + if((sb_dev = activate_dev("ALS100", "sb", sb_dev))) { hw_config->io_base = sb_dev->resource[0].start; hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - - mpu_config->io_base = sb_dev->resource[1].start; + hw_config->dma = sb_dev->dma_resource[1].start; + hw_config->dma2 = sb_dev->dma_resource[0].start; - show_base("AWE", "sb", &sb_dev->resource[0]); - show_base("AWE", "mpu", &sb_dev->resource[1]); - show_base("AWE", "opl3", &sb_dev->resource[2]); + show_base("ALS100", "sb", &sb_dev->resource[0]); } - else - return(NULL); - } - else - printk(KERN_ERR "sb: AWE panic: sb base not found\n"); - - - /* CTL7002:Game SB64 - * CTL7001:Game SB32 - */ - if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) || - (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) ) - { - jp_dev->prepare(jp_dev); - - if((jp_dev = activate_dev("AWE", "gameport", jp_dev))) - show_base("AWE", "gameport", &jp_dev->resource[0]); + if(!sb_dev) return(NULL); } else - printk(KERN_ERR "sb: AWE panic: gameport not found\n"); + printk(KERN_ERR "sb: ALS100 panic: sb base not found\n"); - - /* CTL0022:WaveTable SB64 - * CTL0021:WaveTable SB32 - * CTL0023:WaveTable Sb64 + /* @X@0001:mpu */ - if( nosbwave == 0 && - ( ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) || - ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) || - ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) )) + if((mpu_dev = isapnp_find_dev(bus, + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) { - wt_dev->prepare(wt_dev); - - if((wt_dev = activate_dev("AWE", "wavetable", wt_dev))) + mpu_dev->prepare(mpu_dev); + + if((mpu_dev = activate_dev("ALS100", "mpu", mpu_dev))) { - show_base("AWE", "wavetable", &wt_dev->resource[0]); - show_base("AWE", "wavetable", &wt_dev->resource[1]); - show_base("AWE", "wavetable", &wt_dev->resource[2]); + show_base("ALS100", "mpu", &mpu_dev->resource[0]); + mpu_config->io_base = mpu_dev->resource[0].start; } } else - printk(KERN_ERR "sb: AWE panic: wavetable not found\n"); + printk(KERN_ERR "sb: ALS100 panic: mpu not found\n"); - printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo \n"); + printk(KERN_INFO "sb: ALS100 mail reports to Torsten Werner \n"); return(sb_dev); } -#define SBF_DEV 0x01 +#define SBF_DEV 0x01 /* Please notice that cards without this flag are on the top in the list */ static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; } -isapnp_sb_list[] __initdata = { +sb_isapnp_list[] __initdata = { + {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, + {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" }, + {ISAPNP_VENDOR('A','L','S'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_als, "ALS 100" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV, &sb_init_ess, "ESS 1688" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, - {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, - {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" }, {0} }; -static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot) +static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot) { struct pci_dev *idev = NULL; /* You missed the init func? That's bad. */ - if(isapnp_sb_list[slot].initfunc) + if(sb_isapnp_list[slot].initfunc) { - char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name; + char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name; printk(KERN_INFO "sb: %s detected\n", busname); /* Initialize this baby. */ - if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config))) + if((idev = sb_isapnp_list[slot].initfunc(bus, card, hw_config, mpu_config))) { /* We got it. */ @@ -600,12 +493,12 @@ Should this be fixed? - azummo */ -int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) +int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config) { int i; - /* Count entries in isapnp_sb_list */ - for (i = 0; isapnp_sb_list[i].vendor != 0; i++); + /* Count entries in sb_isapnp_list */ + for (i = 0; sb_isapnp_list[i].vendor != 0; i++); /* Check and adjust isapnpjump */ if( isapnpjump < 0 || isapnpjump > ( i - 1 ) ) @@ -614,18 +507,18 @@ isapnpjump = 0; } - for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) { + for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) { - if(!(isapnp_sb_list[i].flags & SBF_DEV)) + if(!(sb_isapnp_list[i].flags & SBF_DEV)) { struct pci_bus *bus = NULL; while ((bus = isapnp_find_card( - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, + sb_isapnp_list[i].vendor, + sb_isapnp_list[i].function, bus))) { - if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i)) + if(sb_isapnp_init(hw_config, mpu_config, bus, NULL, i)) return 0; } } @@ -635,18 +528,18 @@ * that matches any entry marked with SBF_DEV in the table. */ - for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) { + for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) { - if(isapnp_sb_list[i].flags & SBF_DEV) + if(sb_isapnp_list[i].flags & SBF_DEV) { struct pci_dev *card = NULL; while ((card = isapnp_find_dev(NULL, - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, + sb_isapnp_list[i].vendor, + sb_isapnp_list[i].function, card))) { - if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i)) + if(sb_isapnp_init(hw_config, mpu_config, card->bus, card, i)) return 0; } } @@ -665,7 +558,7 @@ */ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE - if(isapnp && (sb_probe_isapnp(&cfg, &cfg_mpu) < 0) ) { + if(isapnp && (sb_isapnp_probe(&cfg, &cfg_mpu) < 0) ) { printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); isapnp = 0; } @@ -707,11 +600,13 @@ unload_sbmpu(&cfg_mpu); SOUND_LOCK_END; - if(sb_dev) sb_dev->deactivate(sb_dev); - if(jp_dev) jp_dev->deactivate(jp_dev); - if(wt_dev) wt_dev->deactivate(wt_dev); - if(mpu_dev) mpu_dev->deactivate(mpu_dev); - if(wss_dev) wss_dev->deactivate(wss_dev); +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + if(activated) + { + if(sb_dev) sb_dev->deactivate(sb_dev); + if(mpu_dev) mpu_dev->deactivate(mpu_dev); + } +#endif } module_init(init_sb); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.3.99-pre2/linux/drivers/sound/sb_common.c Sun Mar 19 18:35:30 2000 +++ linux/drivers/sound/sb_common.c Mon Mar 20 07:40:59 2000 @@ -908,13 +908,10 @@ } if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI)) { - extern int sbmixnum; - if (devc->irq > 0) free_irq(devc->irq, devc); - sound_unload_mixerdev(devc->my_mixerdev); - sbmixnum--; + sb_mixer_unload(devc); /* We don't have to do this bit any more the UART401 is its own master -- Krzysztof Halasa */ /* But we have to do it, if UART401 is not detected */ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.3.99-pre2/linux/drivers/sound/sb_mixer.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/sb_mixer.c Mon Mar 20 07:40:59 2000 @@ -740,3 +740,9 @@ sb_mixer_reset(devc); return 1; } + +void sb_mixer_unload(sb_devc *devc) +{ + sound_unload_mixerdev(devc->my_mixerdev); + sbmixnum--; +} diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.99-pre2/linux/drivers/usb/Config.in Sun Mar 19 18:35:30 2000 +++ linux/drivers/usb/Config.in Tue Mar 21 12:31:12 2000 @@ -43,6 +43,7 @@ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB m if [ "$CONFIG_USB_STORAGE" != "n" ]; then bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.99-pre2/linux/drivers/usb/Makefile Sun Mar 19 18:35:30 2000 +++ linux/drivers/usb/Makefile Tue Mar 21 12:31:12 2000 @@ -74,6 +74,7 @@ obj-$(CONFIG_USB_CPIA) += cpia.o obj-$(CONFIG_USB_IBMCAM) += ibmcam.o obj-$(CONFIG_USB_DC2XX) += dc2xx.o +obj-$(CONFIG_USB_MDC800) += mdc800.o obj-$(CONFIG_USB_STORAGE) += usb-storage.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_DABUSB) += dabusb.o diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/hid-debug.h linux/drivers/usb/hid-debug.h --- v2.3.99-pre2/linux/drivers/usb/hid-debug.h Sat Feb 12 11:22:11 2000 +++ linux/drivers/usb/hid-debug.h Sun Mar 19 18:29:40 2000 @@ -105,6 +105,7 @@ {0, 0x35, "Tap"}, {0, 0x39, "TabletFunctionKey"}, {0, 0x3a, "ProgramChangeKey"}, + {0, 0x3c, "Invert"}, {0, 0x42, "TipSwitch"}, {0, 0x43, "SecondaryTipSwitch"}, {0, 0x44, "BarrelSwitch"}, diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.3.99-pre2/linux/drivers/usb/hid.c Fri Mar 10 16:40:44 2000 +++ linux/drivers/usb/hid.c Sun Mar 19 18:29:40 2000 @@ -802,6 +802,11 @@ case 0x30: /* TipPressure */ + if (!test_bit(BTN_TOUCH, input->keybit)) { + device->quirks |= HID_QUIRK_NOTOUCH; + set_bit(EV_KEY, input->evbit); + set_bit(BTN_TOUCH, input->keybit); + } usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; usage->code = ABS_PRESSURE; clear_bit(usage->code, bit); @@ -817,10 +822,18 @@ } break; + case 0x3c: /* Invert */ + + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + usage->code = BTN_TOOL_RUBBER; + clear_bit(usage->code, bit); + break; + case 0x33: /* Touch */ case 0x42: /* TipSwitch */ case 0x43: /* TipSwitch2 */ + device->quirks &= ~HID_QUIRK_NOTOUCH; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; usage->code = BTN_TOUCH; clear_bit(usage->code, bit); @@ -930,7 +943,7 @@ } } -static void hid_process_event(struct input_dev *input, int flags, struct hid_usage *usage, __s32 value) +static void hid_process_event(struct input_dev *input, int *quirks, struct hid_field *field, struct hid_usage *usage, __s32 value) { hid_dump_input(usage, value); @@ -941,9 +954,30 @@ return; } + if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ + *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); + return; + } + + if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ + if (value) { + input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); + return; + } + input_event(input, usage->type, usage->code, 0); + input_event(input, usage->type, BTN_TOOL_RUBBER, 0); + return; + } + + if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ + int a = field->logical_minimum; + int b = field->logical_maximum; + input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); + } + input_event(input, usage->type, usage->code, value); - if ((flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) + if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) input_event(input, usage->type, usage->code, 0); } @@ -986,19 +1020,21 @@ } else { if (value[n] == field->value[n]) continue; } - hid_process_event(&dev->input, field->flags, &field->usage[n], value[n]); + hid_process_event(&dev->input, &dev->quirks, field, &field->usage[n], value[n]); } else { if (field->value[n] >= min && field->value[n] <= max /* non-NULL value */ && field->usage[field->value[n] - min].hid /* nonzero usage */ && search(value, field->value[n], count)) - hid_process_event(&dev->input, field->flags, &field->usage[field->value[n] - min], 0); + hid_process_event(&dev->input, &dev->quirks, field, + &field->usage[field->value[n] - min], 0); if (value[n] >= min && value[n] <= max /* non-NULL value */ && field->usage[value[n] - min].hid /* nonzero usage */ && search(field->value, value[n], count)) - hid_process_event(&dev->input, field->flags, &field->usage[value[n] - min], 1); + hid_process_event(&dev->input, &dev->quirks, + field, &field->usage[value[n] - min], 1); } } @@ -1261,14 +1297,18 @@ #define USB_VENDOR_ID_WACOM 0x056a #define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 -#define USB_DEVICE_ID_WACOM_INTUOS 0x0021 +#define USB_DEVICE_ID_WACOM_INTUOS 0x0020 struct hid_blacklist { __u16 idVendor; __u16 idProduct; } hid_blacklist[] = { - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1}, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2}, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3}, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4}, { 0, 0 } }; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/hid.h linux/drivers/usb/hid.h --- v2.3.99-pre2/linux/drivers/usb/hid.h Thu Mar 2 14:36:23 2000 +++ linux/drivers/usb/hid.h Sun Mar 19 18:29:40 2000 @@ -179,6 +179,13 @@ #define HID_FEATURE_REPORT 2 /* + * HID device quirks. + */ + +#define HID_QUIRK_INVERT 0x01 +#define HID_QUIRK_NOTOUCH 0x02 + +/* * This is the global enviroment of the parser. This information is * persistent for main-items. The global enviroment can be saved and * restored with PUSH/POP statements. @@ -285,6 +292,7 @@ struct urb urb; /* USB URB structure */ struct urb urbout; /* Output URB */ struct input_dev input; /* input device structure */ + int quirks; /* Various nasty tricks the device can pull on us */ }; #define HID_GLOBAL_STACK_SIZE 4 diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.3.99-pre2/linux/drivers/usb/keybdev.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/usb/keybdev.c Sun Mar 19 18:29:40 2000 @@ -58,7 +58,8 @@ #endif -struct input_handler keybdev_handler; +static struct input_handler keybdev_handler; +static int keybdev_alt = 0; void keybdev_ledfunc(unsigned int led) { @@ -93,14 +94,22 @@ handle_scancode(0x1d, down); handle_scancode(0x45, down); } else if (code >= 96) { - handle_scancode(0xe0, 1); - handle_scancode(keybdev_x86_e0s[code - 96], down); - if (code == 99) { + if (code == 99 && keybdev_alt) { + handle_scancode(84, down); + } else { handle_scancode(0xe0, 1); - handle_scancode(0x37, down); + handle_scancode(keybdev_x86_e0s[code - 96], down); + if (code == 99) { + handle_scancode(0xe0, 1); + handle_scancode(0x37, down); + } } + } else if (code == 84) { + handle_scancode(43, down); } else handle_scancode(code, down); + if (code == 56 || code == 100) keybdev_alt = down; + #elif CONFIG_ADB_KEYBOARD if (code < 128 && keybdev_mac_codes[code]) @@ -152,7 +161,7 @@ kfree(handle); } -struct input_handler keybdev_handler = { +static struct input_handler keybdev_handler = { event: keybdev_event, connect: keybdev_connect, disconnect: keybdev_disconnect, diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c --- v2.3.99-pre2/linux/drivers/usb/mdc800.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/mdc800.c Tue Mar 21 12:31:12 2000 @@ -0,0 +1,931 @@ +/* + * copyright (C) 1999/2000 by Henning Zabel + * + * 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. + */ + + +/* + * USB-Kernel Driver for the Mustek MDC800 Digital Camera + * (c) 1999/2000 Henning Zabel + * + * + * The driver brings the USB functions of the MDC800 to Linux. + * To use the Camera you must support the USB Protocoll of the camera + * to the Kernel Node. + * The Driver uses a misc device Node. Create it with : + * mknod /dev/mustek c 10 171 + * + * The driver supports only one camera. + * + * version 0.7.1 + * The Init und Exit Module Function are updated. + * (01/03/2000) + * + * version 0.7.0 + * Rewrite of the driver : The driver now uses URB's. The old stuff + * has been removed. + * + * version 0.6.0 + * Rewrite of this driver: The Emulation of the rs232 protocoll + * has been removed from the driver. A special executeCommand function + * for this driver is included to gphoto. + * The driver supports two kind of communication to bulk endpoints. + * Either with the dev->bus->ops->bulk... or with callback function. + * (09/11/1999) + * + * version 0.5.0: + * first Version that gets a version number. Most of the needed + * functions work. + * (20/10/1999) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VERSION "0.7.1" +#define RELEASE_DATE "(01/03/2000)" + +/* Vendor and Product Information */ +#define MDC800_VENDOR_ID 0x055f +#define MDC800_PRODUCT_ID 0xa800 + +/* Timeouts (msec) */ +#define TO_READ_FROM_IRQ 4000 +#define TO_GET_READY 2000 +#define TO_DOWNLOAD_GET_READY 1500 +#define TO_DOWNLOAD_GET_BUSY 1500 +#define TO_WRITE_GET_READY 3000 +#define TO_DEFAULT_COMMAND 5000 + +/* Minor Number of the device (create with mknod /dev/mustek c 10 171) */ +#define MDC800_DEVICE_MINOR 171 + + +/************************************************************************** + Data and structs +***************************************************************************/ + + +typedef enum { + NOT_CONNECTED, READY, WORKING, DOWNLOAD +} mdc800_state; + + +/* Data for the driver */ +struct mdc800_data +{ + struct usb_device * dev; // Device Data + mdc800_state state; + + unsigned int endpoint [4]; + + purb_t irq_urb; + wait_queue_head_t irq_wait; + char* irq_urb_buffer; + + int camera_busy; // is camera busy ? + int camera_request_ready; // Status to synchronize with irq + char camera_response [8]; // last Bytes send after busy + + purb_t write_urb; + char* write_urb_buffer; + wait_queue_head_t write_wait; + + + purb_t download_urb; + char* download_urb_buffer; + wait_queue_head_t download_wait; + int download_left; // Bytes left to download ? + + + /* Device Data */ + char out [64]; // Answer Buffer + int out_ptr; // Index to the first not readen byte + int out_count; // Bytes in the buffer + + int open; // Camera device open ? + int rw_lock; // Block read <-> write + + char in [8]; // Command Input Buffer + int in_count; + + int pic_index; // Cache for the Imagesize (-1 for nothing cached ) + int pic_len; +}; + + +/* Specification of the Endpoints */ +static struct usb_endpoint_descriptor mdc800_ed [4] = +{ + { 0,0, 0x01, 0x02, 8, 0,0,0 }, + { 0,0, 0x82, 0x03, 8, 0,0,0 }, + { 0,0, 0x03, 0x02, 64, 0,0,0 }, + { 0,0, 0x84, 0x02, 64, 0,0,0 } +}; + + +/* The Variable used by the driver */ +static struct mdc800_data* mdc800=0; + + +/*************************************************************************** + The USB Part of the driver +****************************************************************************/ + +static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b) +{ + return ( + ( a->bEndpointAddress == b->bEndpointAddress ) + && ( a->bmAttributes == b->bmAttributes ) + && ( a->wMaxPacketSize == b->wMaxPacketSize ) + ); +} + + +/* + * Checks wether the camera responds busy + */ +static int mdc800_isBusy (char* ch) +{ + int i=0; + while (i<8) + { + if (ch [i] != (char)0x99) + return 0; + i++; + } + return 1; +} + + +/* + * Checks wether the Camera is ready + */ +static int mdc800_isReady (char *ch) +{ + int i=0; + while (i<8) + { + if (ch [i] != (char)0xbb) + return 0; + i++; + } + return 1; +} + + + +/* + * USB IRQ Handler for InputLine + */ +static void mdc800_usb_irq (struct urb *urb) +{ + int data_received=0, wake_up; + unsigned char* b=urb->transfer_buffer; + struct mdc800_data* mdc800=urb->context; + + if (urb->status >= 0) + { + + //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); + + if (mdc800_isBusy (b)) + { + if (!mdc800->camera_busy) + { + mdc800->camera_busy=1; + dbg ("gets busy"); + } + } + else + { + if (mdc800->camera_busy && mdc800_isReady (b)) + { + mdc800->camera_busy=0; + dbg ("gets ready"); + } + } + if (!(mdc800_isBusy (b) || mdc800_isReady (b))) + { + /* Store Data in camera_answer field */ + dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); + + memcpy (mdc800->camera_response,b,8); + data_received=1; + } + } + wake_up= ( mdc800->camera_request_ready > 0 ) + && + ( + ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy)) + || + ((mdc800->camera_request_ready == 2) && data_received) + || + ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy)) + || + (urb->status < 0) + ); + + if (wake_up) + { + mdc800->camera_request_ready=0; + wake_up_interruptible (&mdc800->irq_wait); + } +} + + +/* + * Waits a while until the irq responds that camera is ready + * + * mode : 0: Wait for camera gets ready + * 1: Wait for receiving data + * 2: Wait for camera gets busy + * + * msec: Time to wait + */ +static int mdc800_usb_waitForIRQ (int mode, int msec) +{ + mdc800->camera_request_ready=1+mode; + + interruptible_sleep_on_timeout (&mdc800->irq_wait, msec*HZ/1000); + + if (mdc800->camera_request_ready>0) + { + mdc800->camera_request_ready=0; + err ("timeout waiting for camera."); + return 0; + } + return 1; +} + + +/* + * The write_urb callback function + */ +static void mdc800_usb_write_notify (struct urb *urb) +{ + struct mdc800_data* mdc800=urb->context; + + if (urb->status != 0) + { + err ("writing command fails (status=%i)", urb->status); + } + mdc800->state=READY; + wake_up_interruptible (&mdc800->write_wait); +} + + +/* + * The download_urb callback function + */ +static void mdc800_usb_download_notify (struct urb *urb) +{ + struct mdc800_data* mdc800=urb->context; + + if (urb->status == 0) + { + /* Fill output buffer with these data */ + memcpy (mdc800->out, urb->transfer_buffer, 64); + mdc800->out_count=64; + mdc800->out_ptr=0; + mdc800->download_left-=64; + if (mdc800->download_left == 0) + { + mdc800->state=READY; + } + } + else + { + err ("request bytes fails (status:%i)", urb->status); + mdc800->state=READY; + } + wake_up_interruptible (&mdc800->download_wait); +} + + +/*************************************************************************** + Probing for the Camera + ***************************************************************************/ + +static struct usb_driver mdc800_usb_driver; + +/* + * Callback to search the Mustek MDC800 on the USB Bus + */ +static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum ) +{ + int i,j; + struct usb_interface_descriptor *intf_desc; + int irq_interval=0; + + dbg ("(mdc800_usb_probe) called."); + + if (mdc800->dev != 0) + { + warn ("only one Mustek MDC800 is supported."); + return 0; + } + + if (dev->descriptor.idVendor != MDC800_VENDOR_ID) + return 0; + if (dev->descriptor.idProduct != MDC800_PRODUCT_ID) + return 0; + + if (dev->descriptor.bNumConfigurations != 1) + { + err ("probe fails -> wrong Number of Configuration"); + return 0; + } + intf_desc=&dev->actconfig->interface[ifnum].altsetting[0]; + + if ( + ( intf_desc->bInterfaceClass != 0xff ) + || ( intf_desc->bInterfaceSubClass != 0 ) + || ( intf_desc->bInterfaceProtocol != 0 ) + || ( intf_desc->bNumEndpoints != 4) + ) + { + err ("probe fails -> wrong Interface"); + return 0; + } + + /* Check the Endpoints */ + for (i=0; i<4; i++) + { + mdc800->endpoint[i]=-1; + for (j=0; j<4; j++) + { + if (mdc800_endpoint_equals (&intf_desc->endpoint [j],&mdc800_ed [i])) + { + mdc800->endpoint[i]=intf_desc->endpoint [j].bEndpointAddress ; + if (i==1) + { + irq_interval=intf_desc->endpoint [j].bInterval; + } + + continue; + } + } + if (mdc800->endpoint[i] == -1) + { + err ("probe fails -> Wrong Endpoints."); + return 0; + } + } + + + usb_driver_claim_interface (&mdc800_usb_driver, &dev->actconfig->interface[ifnum], mdc800); + if (usb_set_interface (dev, ifnum, 0) < 0) + { + err ("MDC800 Configuration fails."); + return 0; + } + + info ("Found Mustek MDC800 on USB."); + + mdc800->dev=dev; + mdc800->state=READY; + + /* Setup URB Structs */ + FILL_INT_URB ( + mdc800->irq_urb, + mdc800->dev, + usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]), + mdc800->irq_urb_buffer, + 8, + mdc800_usb_irq, + mdc800, + irq_interval + ); + + FILL_BULK_URB ( + mdc800->write_urb, + mdc800->dev, + usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]), + mdc800->write_urb_buffer, + 8, + mdc800_usb_write_notify, + mdc800 + ); + + FILL_BULK_URB ( + mdc800->download_urb, + mdc800->dev, + usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]), + mdc800->download_urb_buffer, + 64, + mdc800_usb_download_notify, + mdc800 + ); + + return mdc800; +} + + +/* + * Disconnect USB device (maybe the MDC800) + */ +static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr) +{ + struct mdc800_data* mdc800=(struct mdc800_data*) ptr; + + dbg ("(mdc800_usb_disconnect) called"); + + if (mdc800->state == NOT_CONNECTED) + return; + + mdc800->state=NOT_CONNECTED; + mdc800->open=0; + mdc800->rw_lock=0; + + usb_unlink_urb (mdc800->irq_urb); + usb_unlink_urb (mdc800->write_urb); + usb_unlink_urb (mdc800->download_urb); + + usb_driver_release_interface (&mdc800_usb_driver, &dev->actconfig->interface[1]); + + mdc800->dev=0; + info ("Mustek MDC800 disconnected from USB."); +} + + +/*************************************************************************** + The Misc device Part (file_operations) +****************************************************************************/ + +/* + * This Function calc the Answersize for a command. + */ +static int mdc800_getAnswerSize (char command) +{ + switch ((unsigned char) command) + { + case 0x2a: + case 0x49: + case 0x51: + case 0x0d: + case 0x20: + case 0x07: + case 0x01: + case 0x25: + case 0x00: + return 8; + + case 0x05: + case 0x3e: + return mdc800->pic_len; + + case 0x09: + return 4096; + + default: + return 0; + } +} + + +/* + * Init the device: (1) alloc mem (2) Increase MOD Count .. + */ +static int mdc800_device_open (struct inode* inode, struct file *file) +{ + int retval=0; + if (mdc800->state == NOT_CONNECTED) + return -EBUSY; + + if (mdc800->open) + return -EBUSY; + + mdc800->rw_lock=0; + mdc800->in_count=0; + mdc800->out_count=0; + mdc800->out_ptr=0; + mdc800->pic_index=0; + mdc800->pic_len=-1; + mdc800->download_left=0; + + mdc800->camera_busy=0; + mdc800->camera_request_ready=0; + + retval=0; + if (usb_submit_urb (mdc800->irq_urb)) + { + err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status); + return -EIO; + } + + MOD_INC_USE_COUNT; + mdc800->open=1; + + dbg ("Mustek MDC800 device opened."); + return 0; +} + + +/* + * Close the Camera and release Memory + */ +static int mdc800_device_release (struct inode* inode, struct file *file) +{ + int retval=0; + dbg ("Mustek MDC800 device closed."); + + if (mdc800->open && (mdc800->state != NOT_CONNECTED)) + { + mdc800->open=0; + usb_unlink_urb (mdc800->irq_urb); + usb_unlink_urb (mdc800->write_urb); + usb_unlink_urb (mdc800->download_urb); + } + else + { + retval=-EIO; + } + + MOD_DEC_USE_COUNT; + + return retval; +} + + +/* + * The Device read callback Function + */ +static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos) +{ + int left=len, sts=len; /* single transfer size */ + char* ptr=buf; + + if (mdc800->state == NOT_CONNECTED) + return -EBUSY; + + if (!mdc800->open || mdc800->rw_lock) + return -EBUSY; + mdc800->rw_lock=1; + + while (left) + { + if (signal_pending (current)) { + mdc800->rw_lock=0; + return -EINTR; + } + + sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left; + + if (sts <= 0) + { + /* Too less Data in buffer */ + if (mdc800->state == DOWNLOAD) + { + mdc800->out_count=0; + mdc800->out_ptr=0; + + /* Download -> Request new bytes */ + if (usb_submit_urb (mdc800->download_urb)) + { + err ("Can't submit download urb (status=%i)",mdc800->download_urb->status); + mdc800->state=READY; + mdc800->rw_lock=0; + return len-left; + } + interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000); + if (mdc800->download_urb->status != 0) + { + err ("requesting bytes fails (status=%i)",mdc800->download_urb->status); + mdc800->state=READY; + mdc800->rw_lock=0; + return len-left; + } + } + else + { + /* No more bytes -> that's an error*/ + mdc800->rw_lock=0; + return -EIO; + } + } + else + { + /* memcpy Bytes */ + memcpy (ptr, &mdc800->out [mdc800->out_ptr], sts); + ptr+=sts; + left-=sts; + mdc800->out_ptr+=sts; + } + } + + mdc800->rw_lock=0; + return len-left; +} + + +/* + * The Device write callback Function + * If a 8Byte Command is received, it will be send to the camera. + * After this the driver initiates the request for the answer or + * just waits until the camera becomes ready. + */ +static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos) +{ + int i=0; + + if (mdc800->state != READY) + return -EBUSY; + + if (!mdc800->open || mdc800->rw_lock) + return -EBUSY; + mdc800->rw_lock=1; + + while (irw_lock=0; + return -EINTR; + } + + /* check for command start */ + if (buf [i] == (char) 0x55) + { + mdc800->in_count=0; + mdc800->out_count=0; + mdc800->out_ptr=0; + mdc800->download_left=0; + } + + /* save command byte */ + if (mdc800->in_count < 8) + { + mdc800->in[mdc800->in_count]=buf[i]; + mdc800->in_count++; + } + else + { + err ("Command is to long !\n"); + mdc800->rw_lock=0; + return -EIO; + } + + /* Command Buffer full ? -> send it to camera */ + if (mdc800->in_count == 8) + { + int answersize; + + mdc800_usb_waitForIRQ (0,TO_GET_READY); + + answersize=mdc800_getAnswerSize (mdc800->in[1]); + + mdc800->state=WORKING; + memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8); + if (usb_submit_urb (mdc800->write_urb)) + { + err ("submitting write urb fails (status=%i)", mdc800->write_urb->status); + mdc800->rw_lock=0; + mdc800->state=READY; + return -EIO; + } + interruptible_sleep_on_timeout (&mdc800->write_wait, TO_DEFAULT_COMMAND*HZ/1000); + if (mdc800->state == WORKING) + { + usb_unlink_urb (mdc800->write_urb); + mdc800->state=READY; + mdc800->rw_lock=0; + return -EIO; + } + + switch ((unsigned char) mdc800->in[1]) + { + case 0x05: /* Download Image */ + case 0x3e: /* Take shot in Fine Mode (WCam Mode) */ + if (mdc800->pic_len < 0) + { + err ("call 0x07 before 0x05,0x3e"); + mdc800->state=READY; + mdc800->rw_lock=0; + return -EIO; + } + mdc800->pic_len=-1; + + case 0x09: /* Download Thumbnail */ + mdc800->download_left=answersize+64; + mdc800->state=DOWNLOAD; + mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY); + break; + + + default: + if (answersize) + { + + if (!mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ)) + { + err ("requesting answer from irq fails"); + mdc800->state=READY; + mdc800->rw_lock=0; + return -EIO; + } + + /* Write dummy data, (this is ugly but part of the USB Protokoll */ + /* if you use endpoint 1 as bulk and not as irq */ + memcpy (mdc800->out, mdc800->camera_response,8); + + /* This is the interpreted answer */ + memcpy (&mdc800->out[8], mdc800->camera_response,8); + + mdc800->out_ptr=0; + mdc800->out_count=16; + + /* Cache the Imagesize, if command was getImageSize */ + if (mdc800->in [1] == (char) 0x07) + { + mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2]; + + dbg ("cached imagesize = %i",mdc800->pic_len); + } + + } + else + { + if (!mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND)) + { + err ("Command Timeout."); + mdc800->rw_lock=0; + mdc800->state=READY; + return -EIO; + } + } + mdc800->state=READY; + break; + } + } + i++; + } + mdc800->rw_lock=0; + return i; +} + + +/*************************************************************************** + Init and Cleanup this driver (Structs and types) +****************************************************************************/ + + +/* + * USB Driver Struct for this device + */ +static struct usb_driver mdc800_usb_driver = +{ + "mdc800", + mdc800_usb_probe, + mdc800_usb_disconnect, + { 0,0 }, + 0, + 0 +}; + + +/* File Operations of this drivers */ +static struct file_operations mdc800_device_ops = +{ + 0, /* llseek */ + mdc800_device_read, + mdc800_device_write, + 0, /* readdir */ + 0, /* poll */ + 0, /* ioctl, this can be used to detect USB ! */ + 0, /* mmap */ + mdc800_device_open, + 0, /* flush */ + mdc800_device_release, + 0, /* async */ + 0, /* fasync */ + 0, /* check_media_change */ +// 0, /* revalidate */ +// 0 /* lock */ +}; + + +/* + * The Misc Device Configuration Struct + */ +static struct miscdevice mdc800_device = +{ + MDC800_DEVICE_MINOR, + "USB Mustek MDC800 Camera", + &mdc800_device_ops +}; + + +/************************************************************************ + Init and Cleanup this driver (Main Functions) +*************************************************************************/ + +#define try(A) if ((A) == 0) goto cleanup_on_fail; +#define try_free_mem(A) if (A != 0) { kfree (A); A=0; } +#define try_free_urb(A) if (A != 0) { usb_free_urb (A); A=0; } + +int __init usb_mdc800_init (void) +{ + /* Allocate Memory */ + try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL)); + + mdc800->dev=0; + mdc800->open=0; + mdc800->state=NOT_CONNECTED; + memset(mdc800, 0, sizeof(struct mdc800_data)); + + init_waitqueue_head (&mdc800->irq_wait); + init_waitqueue_head (&mdc800->write_wait); + init_waitqueue_head (&mdc800->download_wait); + + try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL)); + try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL)); + try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL)); + + try (mdc800->irq_urb=usb_alloc_urb (0)); + try (mdc800->download_urb=usb_alloc_urb (0)); + try (mdc800->write_urb=usb_alloc_urb (0)); + + /* Register the driver */ + if (usb_register (&mdc800_usb_driver) < 0) + goto cleanup_on_fail; + if (misc_register (&mdc800_device) < 0) + goto cleanup_on_misc_register_fail; + + info ("Mustek Digital Camera Driver " VERSION " (MDC800)"); + info (RELEASE_DATE " Henning Zabel "); + + return 0; + + /* Clean driver up, when something fails */ + +cleanup_on_misc_register_fail: + usb_deregister (&mdc800_usb_driver); + +cleanup_on_fail: + + if (mdc800 != 0) + { + err ("can't alloc memory!"); + + try_free_mem (mdc800->download_urb_buffer); + try_free_mem (mdc800->write_urb_buffer); + try_free_mem (mdc800->irq_urb_buffer); + + try_free_urb (mdc800->write_urb); + try_free_urb (mdc800->download_urb); + try_free_urb (mdc800->irq_urb); + + kfree (mdc800); + } + mdc800=0; + return -1; +} + + +void __exit usb_mdc800_cleanup (void) +{ + usb_deregister (&mdc800_usb_driver); + misc_deregister (&mdc800_device); + + usb_free_urb (mdc800->irq_urb); + usb_free_urb (mdc800->download_urb); + usb_free_urb (mdc800->write_urb); + + kfree (mdc800->irq_urb_buffer); + kfree (mdc800->write_urb_buffer); + kfree (mdc800->download_urb_buffer); + + kfree (mdc800); + mdc800=0; +} + + +MODULE_AUTHOR ("Henning Zabel "); +MODULE_DESCRIPTION ("USB Driver for Mustek MDC800 Digital Camera"); + +module_init (usb_mdc800_init); +module_exit (usb_mdc800_cleanup); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c --- v2.3.99-pre2/linux/drivers/usb/mousedev.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/mousedev.c Sun Mar 19 18:29:40 2000 @@ -95,8 +95,8 @@ break; case ABS_Y: size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - list->dy += (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size; - list->oldy += list->dy * size; + list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size; + list->oldy -= list->dy * size; break; } break; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c --- v2.3.99-pre2/linux/drivers/usb/pegasus.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/usb/pegasus.c Tue Mar 21 12:30:20 2000 @@ -16,12 +16,9 @@ #include -static const char *version = __FILE__ ": v0.3.3 2000/03/13 Written by Petko Manolov (petkan@spct.net)\n"; +static const char *version = __FILE__ ": v0.3.5 2000/03/21 Written by Petko Manolov (petkan@spct.net)\n"; -#define ADMTEK_VENDOR_ID 0x07a6 -#define ADMTEK_DEVICE_ID_PEGASUS 0x0986 - #define PEGASUS_MTU 1500 #define PEGASUS_MAX_MTU 1536 #define PEGASUS_TX_TIMEOUT (HZ*5) @@ -38,6 +35,13 @@ unsigned char ALIGN(intr_buff[8]); }; +struct usb_eth_dev { + char *name; + __u16 vendor; + __u16 device; + void *private; +}; + static int loopback = 0; static int multicast_filter_limit = 32; @@ -46,6 +50,16 @@ MODULE_PARM(loopback, "i"); +static struct usb_eth_dev usb_dev_id[] = { + { "D-Link DSB-650TX", 0x2001, 0x4001, NULL }, + { "Linksys USB100TX", 0x066b, 0x2203, NULL }, + { "SMC 202 USB Ethernet", 0x0707, 0x0200, NULL }, + { "ADMtek AN986 (Pegasus) USB Ethernet", 0x07a6, 0x0986, NULL }, + { "Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL }, + { NULL, 0, 0, NULL } +}; + + #define pegasus_get_registers(dev, indx, size, data)\ usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ); #define pegasus_set_registers(dev, indx, size, data)\ @@ -164,8 +178,8 @@ return 4; if ((partmedia & 0x1f) != 1) { - err("party FAIL %x", partmedia); - return 5; + warn("party FAIL %x", partmedia); + /* return 5; FIXME */ } data[0] = 0xc9; @@ -374,13 +388,25 @@ netif_wake_queue(net); } +static int check_device_ids( __u16 vendor, __u16 product ) +{ + int i=0; + + while ( usb_dev_id[i].name ) { + if ( (usb_dev_id[i].vendor == vendor) && + (usb_dev_id[i].device == product) ) + return 0; + i++; + } + return 1; +} + static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum) { struct net_device *net; struct pegasus *pegasus; - if (dev->descriptor.idVendor != ADMTEK_VENDOR_ID || - dev->descriptor.idProduct != ADMTEK_DEVICE_ID_PEGASUS) { + if ( check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct) ) { return NULL; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/serial/Makefile-keyspan_pda_fw linux/drivers/usb/serial/Makefile-keyspan_pda_fw --- v2.3.99-pre2/linux/drivers/usb/serial/Makefile-keyspan_pda_fw Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/serial/Makefile-keyspan_pda_fw Mon Mar 20 08:28:25 2000 @@ -5,7 +5,7 @@ all: keyspan_pda_fw.h -%.asm: %.s +%.asm: %.S gcc -x assembler-with-cpp -P -E -o $@ $< %.hex: %.asm diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/serial/keyspan_pda.S linux/drivers/usb/serial/keyspan_pda.S --- v2.3.99-pre2/linux/drivers/usb/serial/keyspan_pda.S Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/keyspan_pda.S Mon Mar 20 08:28:25 2000 @@ -0,0 +1,1124 @@ +/* $Id: loop.s,v 1.23 2000/03/20 09:49:06 warner Exp $ + * + * Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on + * the EzUSB microcontroller. + * + * (C) Copyright 2000 Brian Warner + * + * 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. + * + * "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the + * company. + * + * This serial adapter is basically an EzUSB chip and an RS-232 line driver + * in a little widget that has a DB-9 on one end and a USB plug on the other. + * It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2 + * as a baud-rate generator. The wiring is: + * PC0/RxD0 <- rxd (DB9 pin 2) PC4 <- dsr pin 6 + * PC1/TxD0 -> txd pin 3 PC5 <- ri pin 9 + * PC2 -> rts pin 7 PC6 <- dcd pin 1 + * PC3 <- cts pin 8 PC7 -> dtr pin 4 + * PB1 -> line driver standby + * + * The EzUSB register constants below come from their excellent documentation + * and sample code (which used to be available at www.anchorchips.com, but + * that has now been absorbed into Cypress' site and the CD-ROM contents + * don't appear to be available online anymore). If we get multiple + * EzUSB-based drivers into the kernel, it might be useful to pull them out + * into a separate .h file. + * + * THEORY OF OPERATION: + * + * There are two 256-byte ring buffers, one for tx, one for rx. + * + * EP2out is pure tx data. When it appears, the data is copied into the tx + * ring and serial transmission is started if it wasn't already running. The + * "tx buffer empty" interrupt may kick off another character if the ring + * still has data. If the host is tx-blocked because the ring filled up, + * it will request a "tx unthrottle" interrupt. If sending a serial character + * empties the ring below the desired threshold, we set a bit that will send + * up the tx unthrottle message as soon as the rx buffer becomes free. + * + * EP2in (interrupt) is used to send both rx chars and rx status messages + * (only "tx unthrottle" at this time) back up to the host. The first byte + * of the rx message indicates data (0) or status msg (1). Status messages + * are sent before any data. + * + * Incoming serial characters are put into the rx ring by the serial + * interrupt, and the EP2in buffer sent if it wasn't already in transit. + * When the EP2in buffer returns, the interrupt prompts us to send more + * rx chars (or status messages) if they are pending. + * + * Device control happens through "vendor specific" control messages on EP0. + * All messages are destined for the "Interface" (with the index always 0, + * so that if their two-port device might someday use similar firmware, we + * can use index=1 to refer to the second port). The messages defined are: + * + * bRequest = 0 : set baud/bits/parity + * 1 : unused + * 2 : reserved for setting HW flow control (CTSRTS) + * 3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc) + * 4 : set break (on/off) + * 5 : reserved for requesting interrupts on pin state change + * 6 : query buffer room or chars in tx buffer + * 7 : request tx unthrottle interrupt + * + * The host-side driver is set to recognize the device ID values stashed in + * serial EEPROM (0x06cd, 0x0103), program this firmware into place, then + * start it running. This firmware will use EzUSB's "renumeration" trick by + * simulating a bus disconnect, then reconnect with a different device ID + * (encoded in the desc_device descriptor below). The host driver then + * recognizes the new device ID and glues it to the real serial driver code. + * + * USEFUL DOCS: + * EzUSB Technical Reference Manual: + * 8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is + * basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports + * use totally different registers! + * USB 1.1 spec: www.usb.org + * + * HOW TO BUILD: + * gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s + * as31 -l keyspan_pda.asm + * mv keyspan_pda.obj keyspan_pda.hex + * perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h + * Get as31 from , and hack on it + * a bit to make it build. + * + * THANKS: + * Greg Kroah-Hartman, for coordinating the whole usb-serial thing. + * AnchorChips, for making such an incredibly useful little microcontroller. + * KeySpan, for making a handy, cheap ($40) widget that was so easy to take + * apart and trace with an ohmmeter. + * + * TODO: + * lots. grep for TODO. Interrupt safety needs stress-testing. Better flow + * control. Interrupting host upon change in DCD, etc, counting transitions. + * Need to find a safe device id to use (the one used by the Keyspan firmware + * under Windows would be ideal.. can anyone figure out what it is?). Parity. + * More baud rates. Oh, and the string-descriptor-length silicon bug + * workaround should be implemented, but I'm lazy, and the consequence is + * that the device name strings that show up in your kernel log will have + * lots of trailing binary garbage in them (appears as ????). Device strings + * should be made more accurate. + * + * Questions, bugs, patches to Brian. + * + * -Brian Warner + * + */ + +#define HIGH(x) (((x) & 0xff00) / 256) +#define LOW(x) ((x) & 0xff) + +#define dpl1 0x84 +#define dph1 0x85 +#define dps 0x86 + +;;; our bit assignments +#define TX_RUNNING 0 +#define DO_TX_UNTHROTTLE 1 + + ;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60 +#define STACK #0x60-1 + +#define EXIF 0x91 +#define EIE 0xe8 + .flag EUSB, EIE.0 + .flag ES0, IE.4 + +#define EP0CS #0x7fb4 +#define EP0STALLbit #0x01 +#define IN0BUF #0x7f00 +#define IN0BC #0x7fb5 +#define OUT0BUF #0x7ec0 +#define OUT0BC #0x7fc5 +#define IN2BUF #0x7e00 +#define IN2BC #0x7fb9 +#define IN2CS #0x7fb8 +#define OUT2BC #0x7fc9 +#define OUT2CS #0x7fc8 +#define OUT2BUF #0x7dc0 +#define IN4BUF #0x7d00 +#define IN4BC #0x7fbd +#define IN4CS #0x7fbc +#define OEB #0x7f9d +#define OUTB #0x7f97 +#define OEC #0x7f9e +#define OUTC #0x7f98 +#define PINSC #0x7f9b +#define PORTCCFG #0x7f95 +#define IN07IRQ #0x7fa9 +#define OUT07IRQ #0x7faa +#define IN07IEN #0x7fac +#define OUT07IEN #0x7fad +#define USBIRQ #0x7fab +#define USBIEN #0x7fae +#define USBBAV #0x7faf +#define USBCS #0x7fd6 +#define SUDPTRH #0x7fd4 +#define SUDPTRL #0x7fd5 +#define SETUPDAT #0x7fe8 + + ;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91) + + .org 0 + ljmp start + ;; interrupt vectors + .org 23H + ljmp serial_int + .byte 0 + + .org 43H + ljmp USB_Jump_Table + .byte 0 ; filled in by the USB core + +;;; local variables. These are not initialized properly: do it by hand. + .org 30H +rx_ring_in: .byte 0 +rx_ring_out: .byte 0 +tx_ring_in: .byte 0 +tx_ring_out: .byte 0 +tx_unthrottle_threshold: .byte 0 + + .org 0x100H ; wants to be on a page boundary +USB_Jump_Table: + ljmp ISR_Sudav ; Setup Data Available + .byte 0 + ljmp 0 ; Start of Frame + .byte 0 + ljmp 0 ; Setup Data Loading + .byte 0 + ljmp 0 ; Global Suspend + .byte 0 + ljmp 0 ; USB Reset + .byte 0 + ljmp 0 ; Reserved + .byte 0 + ljmp 0 ; End Point 0 In + .byte 0 + ljmp 0 ; End Point 0 Out + .byte 0 + ljmp 0 ; End Point 1 In + .byte 0 + ljmp 0 ; End Point 1 Out + .byte 0 + ljmp ISR_Ep2in + .byte 0 + ljmp ISR_Ep2out + .byte 0 + + + .org 0x200 + +start: mov SP,STACK-1 ; set stack + ;; clear local variables + clr a + mov tx_ring_in, a + mov tx_ring_out, a + mov rx_ring_in, a + mov rx_ring_out, a + mov tx_unthrottle_threshold, a + clr TX_RUNNING + clr DO_TX_UNTHROTTLE + + ;; clear fifo with "fe" + mov r1, 0 + mov a, #0xfe + mov dptr, #tx_ring +clear_tx_ring_loop: + movx @dptr, a + inc dptr + djnz r1, clear_tx_ring_loop + + mov a, #0xfd + mov dptr, #rx_ring +clear_rx_ring_loop: + movx @dptr, a + inc dptr + djnz r1, clear_rx_ring_loop + +;;; turn on the RS-232 driver chip (bring the STANDBY pin low) + ;; set OEB.1 + mov a, #02H + mov dptr,OEB + movx @dptr,a + ;; clear PB1 + mov a, #00H + mov dptr,OUTB + movx @dptr,a + ;; set OEC.[127] + mov a, #0x86 + mov dptr,OEC + movx @dptr,a + ;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port + mov dptr, PORTCCFG + mov a, #0x03 + movx @dptr, a + + ;; set up interrupts, autovectoring + mov dptr, USBBAV + movx a,@dptr + setb acc.0 ; AVEN bit to 0 + movx @dptr, a + + mov a,#0x01 ; enable SUDAV: setup data available (for ep0) + mov dptr, USBIRQ + movx @dptr, a ; clear SUDAVI + mov dptr, USBIEN + movx @dptr, a + + mov dptr, IN07IEN + mov a,#0x04 ; enable IN2 int + movx @dptr, a + + mov dptr, OUT07IEN + mov a,#0x04 ; enable OUT2 int + movx @dptr, a + mov dptr, OUT2BC + movx @dptr, a ; arm OUT2 + + mov a, #0x84 ; turn on RTS, DTR + mov dptr,OUTC + movx @dptr, a + ;; setup the serial port. 9600 8N1. + mov a,#01010011 ; mode 1, enable rx, clear int + mov SCON, a + ;; using timer2, in 16-bit baud-rate-generator mode + ;; (xtal 12MHz, internal fosc 24MHz) + ;; RCAP2H,RCAP2L = 65536 - fosc/(32*baud) + ;; 57600: 0xFFF2.F, say 0xFFF3 + ;; 9600: 0xFFB1.E, say 0xFFB2 + ;; 300: 0xF63C +#define BAUD 9600 +#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate)) +#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate)) +#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate)) + + mov T2CON, #030h ; rclk=1,tclk=1,cp=0,tr2=0(enable later) + mov r3, #5 + acall set_baud + setb TR2 + mov SCON, #050h + +#if 0 + mov r1, #0x40 + mov a, #0x41 +send: + mov SBUF, a + inc a + anl a, #0x3F + orl a, #0x40 +; xrl a, #0x02 +wait1: + jnb TI, wait1 + clr TI + djnz r1, send +;done: sjmp done + +#endif + + setb EUSB + setb EA + setb ES0 + ;acall dump_stat + + ;; hey, what say we RENUMERATE! (TRM p.62) + mov a, #0 + mov dps, a + mov dptr, USBCS + mov a, #0x02 ; DISCON=0, DISCOE=0, RENUM=1 + movx @dptr, a + ;; now presence pin is floating, simulating disconnect. wait 0.5s + mov r1, #46 +renum_wait1: + mov r2, #0 +renum_wait2: + mov r3, #0 +renum_wait3: + djnz r3, renum_wait3 + djnz r2, renum_wait2 + djnz r1, renum_wait1 ; wait about n*(256^2) 6MHz clocks + mov a, #0x06 ; DISCON=0, DISCOE=1, RENUM=1 + movx @dptr, a + ;; we are back online. the host device will now re-query us + + +main: sjmp main + + + +ISR_Sudav: + push dps + push dpl + push dph + push dpl1 + push dph1 + push acc + mov a,EXIF + clr acc.4 + mov EXIF,a ; clear INT2 first + mov dptr, USBIRQ ; clear USB int + mov a,#01h + movx @dptr,a + + ;; get request type + mov dptr, SETUPDAT + movx a, @dptr + mov r1, a ; r1 = bmRequestType + inc dptr + movx a, @dptr + mov r2, a ; r2 = bRequest + inc dptr + movx a, @dptr + mov r3, a ; r3 = wValueL + inc dptr + movx a, @dptr + mov r4, a ; r4 = wValueH + + ;; main switch on bmRequest.type: standard or vendor + mov a, r1 + anl a, #0x60 + cjne a, #0x00, setup_bmreq_type_not_standard + ;; standard request: now main switch is on bRequest + ljmp setup_bmreq_is_standard + +setup_bmreq_type_not_standard: + ;; a still has bmreq&0x60 + cjne a, #0x40, setup_bmreq_type_not_vendor + ;; Anchor reserves bRequest 0xa0-0xaf, we use small ones + ;; switch on bRequest. bmRequest will always be 0x41 or 0xc1 + cjne r2, #0x00, setup_ctrl_not_00 + ;; 00 is set baud, wValue[0] has baud rate index + lcall set_baud ; index in r3, carry set if error + jc setup_bmreq_type_not_standard__do_stall + ljmp setup_done_ack +setup_bmreq_type_not_standard__do_stall: + ljmp setup_stall +setup_ctrl_not_00: + cjne r2, #0x01, setup_ctrl_not_01 + ;; 01 is reserved for set bits (parity). TODO + ljmp setup_stall +setup_ctrl_not_01: + cjne r2, #0x02, setup_ctrl_not_02 + ;; 02 is set HW flow control. TODO + ljmp setup_stall +setup_ctrl_not_02: + cjne r2, #0x03, setup_ctrl_not_03 + ;; 03 is control pins (RTS, DTR). + ljmp control_pins ; will jump to setup_done_ack, + ; or setup_return_one_byte +setup_ctrl_not_03: + cjne r2, #0x04, setup_ctrl_not_04 + ;; 04 is send break (really "turn break on/off"). TODO + cjne r3, #0x00, setup_ctrl_do_break_on + ;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port + mov dptr, PORTCCFG + movx a, @dptr + orl a, #0x02 + movx @dptr, a + ljmp setup_done_ack +setup_ctrl_do_break_on: + ;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low) + mov dptr, OUTC + movx a, @dptr + anl a, #0xfd ; ~0x02 + movx @dptr, a + mov dptr, PORTCCFG + movx a, @dptr + anl a, #0xfd ; ~0x02 + movx @dptr, a + ljmp setup_done_ack +setup_ctrl_not_04: + cjne r2, #0x05, setup_ctrl_not_05 + ;; 05 is set desired interrupt bitmap. TODO + ljmp setup_stall +setup_ctrl_not_05: + cjne r2, #0x06, setup_ctrl_not_06 + ;; 06 is query room + cjne r3, #0x00, setup_ctrl_06_not_00 + ;; 06, wValue[0]=0 is query write_room + mov a, tx_ring_out + setb c + subb a, tx_ring_in ; out-1-in = 255 - (in-out) + ljmp setup_return_one_byte +setup_ctrl_06_not_00: + cjne r3, #0x01, setup_ctrl_06_not_01 + ;; 06, wValue[0]=1 is query chars_in_buffer + mov a, tx_ring_in + clr c + subb a, tx_ring_out ; in-out + ljmp setup_return_one_byte +setup_ctrl_06_not_01: + ljmp setup_stall +setup_ctrl_not_06: + cjne r2, #0x07, setup_ctrl_not_07 + ;; 07 is request tx unthrottle interrupt + mov tx_unthrottle_threshold, r3; wValue[0] is threshold value + ljmp setup_done_ack +setup_ctrl_not_07: + ljmp setup_stall + +setup_bmreq_type_not_vendor: + ljmp setup_stall + + +setup_bmreq_is_standard: + cjne r2, #0x00, setup_breq_not_00 + ;; 00: Get_Status (sub-switch on bmRequestType: device, ep, int) + cjne r1, #0x80, setup_Get_Status_not_device + ;; Get_Status(device) + ;; are we self-powered? no. can we do remote wakeup? no + ;; so return two zero bytes. This is reusable +setup_return_two_zero_bytes: + mov dptr, IN0BUF + clr a + movx @dptr, a + inc dptr + movx @dptr, a + mov dptr, IN0BC + mov a, #2 + movx @dptr, a + ljmp setup_done_ack +setup_Get_Status_not_device: + cjne r1, #0x82, setup_Get_Status_not_endpoint + ;; Get_Status(endpoint) + ;; must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0 + ;; for now: cheat. TODO + sjmp setup_return_two_zero_bytes +setup_Get_Status_not_endpoint: + cjne r1, #0x81, setup_Get_Status_not_interface + ;; Get_Status(interface): return two zeros + sjmp setup_return_two_zero_bytes +setup_Get_Status_not_interface: + ljmp setup_stall + +setup_breq_not_00: + cjne r2, #0x01, setup_breq_not_01 + ;; 01: Clear_Feature (sub-switch on wValueL: stall, remote wakeup) + cjne r3, #0x00, setup_Clear_Feature_not_stall + ;; Clear_Feature(stall). should clear a stall bit. TODO + ljmp setup_stall +setup_Clear_Feature_not_stall: + cjne r3, #0x01, setup_Clear_Feature_not_rwake + ;; Clear_Feature(remote wakeup). ignored. + ljmp setup_done_ack +setup_Clear_Feature_not_rwake: + ljmp setup_stall + +setup_breq_not_01: + cjne r2, #0x03, setup_breq_not_03 + ;; 03: Set_Feature (sub-switch on wValueL: stall, remote wakeup) + cjne r3, #0x00, setup_Set_Feature_not_stall + ;; Set_Feature(stall). Should set a stall bit. TODO + ljmp setup_stall +setup_Set_Feature_not_stall: + cjne r3, #0x01, setup_Set_Feature_not_rwake + ;; Set_Feature(remote wakeup). ignored. + ljmp setup_done_ack +setup_Set_Feature_not_rwake: + ljmp setup_stall + +setup_breq_not_03: + cjne r2, #0x06, setup_breq_not_06 + ;; 06: Get_Descriptor (s-switch on wValueH: dev, config[n], string[n]) + cjne r4, #0x01, setup_Get_Descriptor_not_device + ;; Get_Descriptor(device) + mov dptr, SUDPTRH + mov a, #HIGH(desc_device) + movx @dptr, a + mov dptr, SUDPTRL + mov a, #LOW(desc_device) + movx @dptr, a + ljmp setup_done_ack +setup_Get_Descriptor_not_device: + cjne r4, #0x02, setup_Get_Descriptor_not_config + ;; Get_Descriptor(config[n]) + cjne r3, #0x00, setup_stall; only handle n==0 + ;; Get_Descriptor(config[0]) + mov dptr, SUDPTRH + mov a, #HIGH(desc_config1) + movx @dptr, a + mov dptr, SUDPTRL + mov a, #LOW(desc_config1) + movx @dptr, a + ljmp setup_done_ack +setup_Get_Descriptor_not_config: + cjne r4, #0x03, setup_Get_Descriptor_not_string + ;; Get_Descriptor(string[wValueL]) + ;; if (wValueL >= maxstrings) stall + mov a, #((desc_strings_end-desc_strings)/2) + clr c + subb a,r3 ; a=4, r3 = 0..3 . if a<=0 then stall + jc setup_stall + jz setup_stall + mov a, r3 + add a, r3 ; a = 2*wValueL + mov dptr, #desc_strings + add a, dpl + mov dpl, a + mov a, #0 + addc a, dph + mov dph, a ; dph = desc_strings[a]. big endian! (handy) + ;; it looks like my adapter uses a revision of the EZUSB that + ;; contains "rev D errata number 8", as hinted in the EzUSB example + ;; code. I cannot find an actual errata description on the Cypress + ;; web site, but from the example code it looks like this bug causes + ;; the length of string descriptors to be read incorrectly, possibly + ;; sending back more characters than the descriptor has. The workaround + ;; is to manually send out all of the data. The consequence of not + ;; using the workaround is that the strings gathered by the kernel + ;; driver are too long and are filled with trailing garbage (including + ;; leftover strings). Writing this out by hand is a nuisance, so for + ;; now I will just live with the bug. + movx a, @dptr + mov r1, a + inc dptr + movx a, @dptr + mov r2, a + mov dptr, SUDPTRH + mov a, r1 + movx @dptr, a + mov dptr, SUDPTRL + mov a, r2 + movx @dptr, a + ;; done + ljmp setup_done_ack + +setup_Get_Descriptor_not_string: + ljmp setup_stall + +setup_breq_not_06: + cjne r2, #0x08, setup_breq_not_08 + ;; Get_Configuration. always 1. return one byte. + ;; this is reusable + mov a, #1 +setup_return_one_byte: + mov dptr, IN0BUF + movx @dptr, a + mov a, #1 + mov dptr, IN0BC + movx @dptr, a + ljmp setup_done_ack +setup_breq_not_08: + cjne r2, #0x09, setup_breq_not_09 + ;; 09: Set_Configuration. ignored. + ljmp setup_done_ack +setup_breq_not_09: + cjne r2, #0x0a, setup_breq_not_0a + ;; 0a: Get_Interface. get the current altsetting for int[wIndexL] + ;; since we only have one interface, ignore wIndexL, return a 0 + mov a, #0 + ljmp setup_return_one_byte +setup_breq_not_0a: + cjne r2, #0x0b, setup_breq_not_0b + ;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored + ljmp setup_done_ack +setup_breq_not_0b: + ljmp setup_stall + + +setup_done_ack: + ;; now clear HSNAK + mov dptr, EP0CS + mov a, #0x02 + movx @dptr, a + sjmp setup_done +setup_stall: + ;; unhandled. STALL + ;EP0CS |= bmEPSTALL + mov dptr, EP0CS + movx a, @dptr + orl a, EP0STALLbit + movx @dptr, a + sjmp setup_done + +setup_done: + pop acc + pop dph1 + pop dpl1 + pop dph + pop dpl + pop dps + reti + +;;; ============================================================== + +set_baud: ; baud index in r3 + ;; verify a < 10 + mov a, r3 + jb ACC.7, set_baud__badbaud + clr c + subb a, #10 + jnc set_baud__badbaud + mov a, r3 + rl a ; a = index*2 + add a, #LOW(baud_table) + mov dpl, a + mov a, #HIGH(baud_table) + addc a, #0 + mov dph, a + ;; TODO: shut down xmit/receive + ;; TODO: wait for current xmit char to leave + ;; TODO: shut down timer to avoid partial-char glitch + movx a,@dptr ; BAUD_HIGH + mov RCAP2H, a + mov TH2, a + inc dptr + movx a,@dptr ; BAUD_LOW + mov RCAP2L, a + mov TL2, a + ;; TODO: restart xmit/receive + ;; TODO: reenable interrupts, resume tx if pending + clr c ; c=0: success + ret +set_baud__badbaud: + setb c ; c=1: failure + ret + +;;; ================================================== +control_pins: + cjne r1, #0x41, control_pins_in +control_pins_out: + mov a, r3 ; wValue[0] holds new bits: b7 is new DTR, b2 is new RTS + xrl a, #0xff ; 1 means active, 0V, +12V ? + anl a, #0x84 + mov r3, a + mov dptr, OUTC + movx a, @dptr ; only change bits 7 and 2 + anl a, #0x7b ; ~0x84 + orl a, r3 + movx @dptr, a ; other pins are inputs, bits ignored + ljmp setup_done_ack +control_pins_in: + mov dptr, PINSC + movx a, @dptr + xrl a, #0xff + ljmp setup_return_one_byte + +;;; ======================================== + +ISR_Ep2in: + push dps + push dpl + push dph + push dpl1 + push dph1 + push acc + mov a,EXIF + clr acc.4 + mov EXIF,a ; clear INT2 first + mov dptr, IN07IRQ ; clear USB int + mov a,#04h + movx @dptr,a + + ;; do stuff + lcall start_in + + pop acc + pop dph1 + pop dpl1 + pop dph + pop dpl + pop dps + reti + +ISR_Ep2out: + push dps + push dpl + push dph + push dpl1 + push dph1 + push acc + mov a,EXIF + clr acc.4 + mov EXIF,a ; clear INT2 first + mov dptr, OUT07IRQ ; clear USB int + mov a,#04h + movx @dptr,a + + ;; do stuff + + ;; copy data into buffer. for now, assume we will have enough space + mov dptr, OUT2BC ; get byte count + movx a,@dptr + mov r1, a + clr a + mov dps, a + mov dptr, OUT2BUF ; load DPTR0 with source + mov dph1, #HIGH(tx_ring) ; load DPTR1 with target + mov dpl1, tx_ring_in +OUT_loop: + movx a,@dptr ; read + inc dps ; switch to DPTR1: target + inc dpl1 ; target = tx_ring_in+1 + movx @dptr,a ; store + mov a,dpl1 + cjne a, tx_ring_out, OUT_no_overflow + sjmp OUT_overflow +OUT_no_overflow: + inc tx_ring_in ; tx_ring_in++ + inc dps ; switch to DPTR0: source + inc dptr + djnz r1, OUT_loop + sjmp OUT_done +OUT_overflow: + ;; signal overflow + ;; fall through +OUT_done: + ;; ack + mov dptr,OUT2BC + movx @dptr,a + + ;; start tx + acall maybe_start_tx + ;acall dump_stat + + pop acc + pop dph1 + pop dpl1 + pop dph + pop dpl + pop dps + reti + +dump_stat: + ;; fill in EP4in with a debugging message: + ;; tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out + ;; tx_active + ;; tx_ring[0..15] + ;; 0xfc + ;; rx_ring[0..15] + clr a + mov dps, a + + mov dptr, IN4CS + movx a, @dptr + jb acc.1, dump_stat__done; busy: cannot dump, old one still pending + mov dptr, IN4BUF + + mov a, tx_ring_in + movx @dptr, a + inc dptr + mov a, tx_ring_out + movx @dptr, a + inc dptr + + mov a, rx_ring_in + movx @dptr, a + inc dptr + mov a, rx_ring_out + movx @dptr, a + inc dptr + + clr a + jnb TX_RUNNING, dump_stat__no_tx_running + inc a +dump_stat__no_tx_running: + movx @dptr, a + inc dptr + ;; tx_ring[0..15] + inc dps + mov dptr, #tx_ring ; DPTR1: source + mov r1, #16 +dump_stat__tx_ring_loop: + movx a, @dptr + inc dptr + inc dps + movx @dptr, a + inc dptr + inc dps + djnz r1, dump_stat__tx_ring_loop + inc dps + + mov a, #0xfc + movx @dptr, a + inc dptr + + ;; rx_ring[0..15] + inc dps + mov dptr, #rx_ring ; DPTR1: source + mov r1, #16 +dump_stat__rx_ring_loop: + movx a, @dptr + inc dptr + inc dps + movx @dptr, a + inc dptr + inc dps + djnz r1, dump_stat__rx_ring_loop + + ;; now send it + clr a + mov dps, a + mov dptr, IN4BC + mov a, #38 + movx @dptr, a +dump_stat__done: + ret + +;;; ============================================================ + +maybe_start_tx: + ;; make sure the tx process is running. + jb TX_RUNNING, start_tx_done +start_tx: + ;; is there work to be done? + mov a, tx_ring_in + cjne a,tx_ring_out, start_tx__work + ret ; no work +start_tx__work: + ;; tx was not running. send the first character, setup the TI int + inc tx_ring_out ; [++tx_ring_out] + mov dph, #HIGH(tx_ring) + mov dpl, tx_ring_out + movx a, @dptr + mov sbuf, a + setb TX_RUNNING +start_tx_done: + ;; can we unthrottle the host tx process? + ;; step 1: do we care? + mov a, #0 + cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx + ;; nope +start_tx_really_done: + ret +start_tx__maybe_unthrottle_tx: + ;; step 2: is there now room? + mov a, tx_ring_out + setb c + subb a, tx_ring_in + ;; a is now write_room. If thresh >= a, we can unthrottle + clr c + subb a, tx_unthrottle_threshold + jc start_tx_really_done ; nope + ;; yes, we can unthrottle. remove the threshold and mark a request + mov tx_unthrottle_threshold, #0 + setb DO_TX_UNTHROTTLE + ;; prod rx, which will actually send the message when in2 becomes free + ljmp start_in + + +serial_int: + push dps + push dpl + push dph + push dpl1 + push dph1 + push acc + jnb TI, serial_int__not_tx + ;; tx finished. send another character if we have one + clr TI ; clear int + clr TX_RUNNING + lcall start_tx +serial_int__not_tx: + jnb RI, serial_int__not_rx + lcall get_rx_char + clr RI ; clear int +serial_int__not_rx: + ;; return + pop acc + pop dph1 + pop dpl1 + pop dph + pop dpl + pop dps + reti + +get_rx_char: + mov dph, #HIGH(rx_ring) + mov dpl, rx_ring_in + inc dpl ; target = rx_ring_in+1 + mov a, sbuf + movx @dptr, a + ;; check for overflow before incrementing rx_ring_in + mov a, dpl + cjne a, rx_ring_out, get_rx_char__no_overflow + ;; signal overflow + ret +get_rx_char__no_overflow: + inc rx_ring_in + ;; kick off USB INpipe + acall start_in + ret + +start_in: + ;; check if the inpipe is already running. + mov dptr, IN2CS + movx a, @dptr + jb acc.1, start_in__done; int will handle it + jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle + ;; see if there is any work to do. a serial interrupt might occur + ;; during this sequence? + mov a, rx_ring_in + cjne a, rx_ring_out, start_in__have_work + ret ; nope +start_in__have_work: + ;; now copy as much data as possible into the pipe. 63 bytes max. + clr a + mov dps, a + mov dph, #HIGH(rx_ring) ; load DPTR0 with source + inc dps + mov dptr, IN2BUF ; load DPTR1 with target + movx @dptr, a ; in[0] signals that rest of IN is rx data + inc dptr + inc dps + ;; loop until we run out of data, or we have copied 64 bytes + mov r1, #1 ; INbuf size counter +start_in__loop: + mov a, rx_ring_in + cjne a, rx_ring_out, start_in__still_copying + sjmp start_in__kick +start_in__still_copying: + inc rx_ring_out + mov dpl, rx_ring_out + movx a, @dptr + inc dps + movx @dptr, a ; write into IN buffer + inc dptr + inc dps + inc r1 + cjne r1, #64, start_in__loop; loop +start_in__kick: + ;; either we ran out of data, or we copied 64 bytes. r1 has byte count + ;; kick off IN + mov dptr, IN2BC + mov a, r1 + jz start_in__done + movx @dptr, a + ;; done +start_in__done: + ;acall dump_stat + ret +start_in__do_tx_unthrottle: + ;; special sequence: send a tx unthrottle message + clr DO_TX_UNTHROTTLE + clr a + mov dps, a + mov dptr, IN2BUF + mov a, #1 + movx @dptr, a + inc dptr + mov a, #2 + movx @dptr, a + mov dptr, IN2BC + movx @dptr, a + ret + +putchar: + clr TI + mov SBUF, a +putchar_wait: + jnb TI, putchar_wait + clr TI + ret + + +baud_table: ; baud_high, then baud_low + ;; baud[0]: 110 + .byte BAUD_HIGH(110) + .byte BAUD_LOW(110) + ;; baud[1]: 300 + .byte BAUD_HIGH(300) + .byte BAUD_LOW(300) + ;; baud[2]: 1200 + .byte BAUD_HIGH(1200) + .byte BAUD_LOW(1200) + ;; baud[3]: 2400 + .byte BAUD_HIGH(2400) + .byte BAUD_LOW(2400) + ;; baud[4]: 4800 + .byte BAUD_HIGH(4800) + .byte BAUD_LOW(4800) + ;; baud[5]: 9600 + .byte BAUD_HIGH(9600) + .byte BAUD_LOW(9600) + ;; baud[6]: 19200 + .byte BAUD_HIGH(19200) + .byte BAUD_LOW(19200) + ;; baud[7]: 38400 + .byte BAUD_HIGH(38400) + .byte BAUD_LOW(38400) + ;; baud[8]: 57600 + .byte BAUD_HIGH(57600) + .byte BAUD_LOW(57600) + ;; baud[9]: 115200 + .byte BAUD_HIGH(115200) + .byte BAUD_LOW(115200) + +desc_device: + .byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40 + .byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01 +;;; The "real" device id, which must match the host driver, is that +;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104 + +desc_config1: + .byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32 + .byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00 + .byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01 + .byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00 + +desc_strings: + .word string_langids, string_mfg, string_product, string_serial +desc_strings_end: + +string_langids: .byte string_langids_end-string_langids + .byte 3 + .word 0 +string_langids_end: + + ;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now + ;; *that* is a pain in the ass to encode. And they are little-endian + ;; too. Use this perl snippet to get the bytecodes: + /* while (<>) { + @c = split(//); + foreach $c (@c) { + printf("0x%02x, 0x00, ", ord($c)); + } + } + */ + +string_mfg: .byte string_mfg_end-string_mfg + .byte 3 +; .byte "ACME usb widgets" + .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00 +string_mfg_end: + +string_product: .byte string_product_end-string_product + .byte 3 +; .byte "ACME USB serial widget" + .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00 +string_product_end: + +string_serial: .byte string_serial_end-string_serial + .byte 3 +; .byte "47" + .byte 0x34, 0x00, 0x37, 0x00 +string_serial_end: + +;;; ring buffer memory + ;; tx_ring_in+1 is where the next input byte will go + ;; [tx_ring_out] has been sent + ;; if tx_ring_in == tx_ring_out, theres no work to do + ;; there are (tx_ring_in - tx_ring_out) chars to be written + ;; dont let _in lap _out + ;; cannot inc if tx_ring_in+1 == tx_ring_out + ;; write [tx_ring_in+1] then tx_ring_in++ + ;; if (tx_ring_in+1 == tx_ring_out), overflow + ;; else tx_ring_in++ + ;; read/send [tx_ring_out+1], then tx_ring_out++ + + ;; rx_ring_in works the same way + + .org 0x1000 +tx_ring: + .skip 0x100 ; 256 bytes +rx_ring: + .skip 0x100 ; 256 bytes + + + .END + diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/serial/usb-serial.c linux/drivers/usb/serial/usb-serial.c --- v2.3.99-pre2/linux/drivers/usb/serial/usb-serial.c Sun Mar 19 18:35:31 2000 +++ linux/drivers/usb/serial/usb-serial.c Sun Mar 19 18:15:06 2000 @@ -14,6 +14,16 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (03/19/2000) gkh + * Fixed oops that could happen when device was removed while a program + * was talking to the device. + * Removed the static urbs and now all urbs are created and destroyed + * dynamically. + * Reworked the internal interface. Now everything is based on the + * usb_serial_port structure instead of the larger usb_serial structure. + * This fixes the bug that a multiport device could not have more than + * one port open at one time. + * * (03/17/2000) gkh * Added config option for debugging messages. * Added patch for keyspan pda from Brian Warner. @@ -220,10 +230,9 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr); static struct usb_driver usb_serial_driver = { - "serial", - usb_serial_probe, - usb_serial_disconnect, - { NULL, NULL } + name: "serial", + probe: usb_serial_probe, + disconnect: usb_serial_disconnect, }; static int serial_refcount; @@ -233,11 +242,50 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, }; +static inline int serial_paranoia_check (struct usb_serial *serial, const char *function) +{ + if (!serial) { + dbg("%s - serial == NULL", function); + return -1; + } + if (serial->magic != USB_SERIAL_MAGIC) { + dbg("%s - bad magic number for serial", function); + return -1; + } + if (!serial->type) { + dbg("%s - serial->type == NULL!", function); + return -1; + } -static struct usb_serial *get_serial_by_minor (int minor) + return 0; +} + + +static inline int port_paranoia_check (struct usb_serial_port *port, const char *function) { - dbg("get_serial_by_minor %d", minor); + if (!port) { + dbg("%s - port == NULL", function); + return -1; + } + if (port->magic != USB_SERIAL_PORT_MAGIC) { + dbg("%s - bad magic number for port", function); + return -1; + } + if (!port->serial) { + dbg("%s - port->serial == NULL", function); + return -1; + } + if (!port->tty) { + dbg("%s - port->tty == NULL", function); + return -1; + } + return 0; +} + + +static struct usb_serial *get_serial_by_minor (int minor) +{ return serial_table[minor]; } @@ -267,6 +315,7 @@ return NULL; } memset(serial, 0, sizeof(struct usb_serial)); + serial->magic = USB_SERIAL_MAGIC; serial_table[i] = serial; *minor = i; dbg("minor base = %d", *minor); @@ -337,6 +386,8 @@ static int serial_open (struct tty_struct *tty, struct file * filp) { struct usb_serial *serial; + struct usb_serial_port *port; + int portNumber; dbg("serial_open"); @@ -346,180 +397,182 @@ /* get the serial object associated with this tty pointer */ serial = get_serial_by_minor (MINOR(tty->device)); - /* do some sanity checking that we really have a device present */ - if (!serial) { - dbg("serial == NULL!"); - return (-ENODEV); - } - if (!serial->type) { - dbg("serial->type == NULL!"); - return (-ENODEV); + if (serial_paranoia_check (serial, "serial_open")) { + return -ENODEV; } - /* make the tty driver remember our serial object, and us it */ - tty->driver_data = serial; - serial->tty = tty; + /* set up our port structure */ + portNumber = MINOR(tty->device) - serial->minor; + port = &serial->port[portNumber]; + port->number = portNumber; + port->serial = serial; + port->magic = USB_SERIAL_PORT_MAGIC; + + /* make the tty driver remember our port object, and us it */ + tty->driver_data = port; + port->tty = tty; /* pass on to the driver specific version of this function if it is available */ if (serial->type->open) { - return (serial->type->open(tty, filp)); + return (serial->type->open(port, filp)); } else { - return (generic_serial_open(tty, filp)); + return (generic_open(port, filp)); } } static void serial_close(struct tty_struct *tty, struct file * filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port; + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; dbg("serial_close"); - if (!serial) { - dbg("serial == NULL!"); + if (port_paranoia_check (port, "serial_close")) { return; } - port = MINOR(tty->device) - serial->minor; - - dbg("serial_close port %d", port); - - /* do some sanity checking that we really have a device present */ - if (!serial->type) { - dbg("serial->type == NULL!"); + serial = port->serial; + if (serial_paranoia_check (serial, "serial_close")) { return; } - if (!serial->port[port].active) { - dbg ("device not opened"); + + dbg("serial_close port %d", port->number); + + if (!port->active) { + dbg ("port not opened"); return; } /* pass on to the driver specific version of this function if it is available */ if (serial->type->close) { - serial->type->close(tty, filp); + serial->type->close(port, filp); } else { - generic_serial_close(tty, filp); + generic_close(port, filp); } } static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; - dbg("serial_write port %d, %d byte(s)", port, count); - - /* do some sanity checking that we really have a device present */ - if (!serial) { - dbg("serial == NULL!"); - return (-ENODEV); + dbg("serial_write"); + + if (port_paranoia_check (port, "serial_write")) { + return -ENODEV; } - if (!serial->type) { - dbg("serial->type == NULL!"); - return (-ENODEV); + + serial = port->serial; + if (serial_paranoia_check (serial, "serial_write")) { + return -ENODEV; } - if (!serial->port[port].active) { - dbg ("device not opened"); - return (-EINVAL); + + dbg("serial_write port %d, %d byte(s)", port->number, count); + + if (!port->active) { + dbg ("port not opened"); + return -EINVAL; } /* pass on to the driver specific version of this function if it is available */ if (serial->type->write) { - return (serial->type->write(tty, from_user, buf, count)); + return (serial->type->write(port, from_user, buf, count)); } else { - return (generic_serial_write(tty, from_user, buf, count)); + return (generic_write(port, from_user, buf, count)); } } static int serial_write_room (struct tty_struct *tty) { - struct usb_serial *serial = (struct usb_serial *)tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("serial_write_room port %d", port); + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; - /* do some sanity checking that we really have a device present */ - if (!serial) { - dbg("serial == NULL!"); - return (-ENODEV); + dbg("serial_write_room"); + + if (port_paranoia_check (port, "serial_write")) { + return -ENODEV; } - if (!serial->type) { - dbg("serial->type == NULL!"); - return (-ENODEV); + + serial = port->serial; + if (serial_paranoia_check (serial, "serial_write")) { + return -ENODEV; } - if (!serial->port[port].active) { - dbg ("device not open"); - return (-EINVAL); + + dbg("serial_write_room port %d", port->number); + + if (!port->active) { + dbg ("port not open"); + return -EINVAL; } /* pass on to the driver specific version of this function if it is available */ if (serial->type->write_room) { - return (serial->type->write_room(tty)); + return (serial->type->write_room(port)); } else { - return (generic_write_room(tty)); + return (generic_write_room(port)); } } static int serial_chars_in_buffer (struct tty_struct *tty) { - struct usb_serial *serial = (struct usb_serial *)tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("serial_chars_in_buffer port %d", port); + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; - /* do some sanity checking that we really have a device present */ - if (!serial) { - dbg("serial == NULL!"); - return (-ENODEV); + dbg("serial_chars_in_buffer"); + + if (port_paranoia_check (port, "serial_chars_in_buffer")) { + return -ENODEV; } - if (!serial->type) { - dbg("serial->type == NULL!"); - return (-ENODEV); + + serial = port->serial; + if (serial_paranoia_check (serial, "serial_chars_in_buffer")) { + return -ENODEV; } - if (!serial->port[port].active) { - dbg ("device not open"); - return (-EINVAL); + + if (!port->active) { + dbg ("port not open"); + return -EINVAL; } /* pass on to the driver specific version of this function if it is available */ if (serial->type->chars_in_buffer) { - return (serial->type->chars_in_buffer(tty)); + return (serial->type->chars_in_buffer(port)); } else { - return (generic_chars_in_buffer(tty)); + return (generic_chars_in_buffer(port)); } } static void serial_throttle (struct tty_struct * tty) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("serial_throttle port %d", port); + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; - /* do some sanity checking that we really have a device present */ - if (!serial) { - dbg("serial == NULL!"); + dbg("serial_throttle"); + + if (port_paranoia_check (port, "serial_throttle")) { return; } - if (!serial->type) { - dbg("serial->type == NULL!"); + + serial = port->serial; + if (serial_paranoia_check (serial, "serial_throttle")) { return; } - if (!serial->port[port].active) { - dbg ("device not open"); + + dbg("serial_throttle port %d", port->number); + + if (!port->active) { + dbg ("port not open"); return; } /* pass on to the driver specific version of this function */ if (serial->type->throttle) { - serial->type->throttle(tty); - } else { - generic_throttle(tty); + serial->type->throttle(port); } return; @@ -528,30 +581,30 @@ static void serial_unthrottle (struct tty_struct * tty) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("serial_unthrottle port %d", port); + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; - /* do some sanity checking that we really have a device present */ - if (!serial) { - dbg("serial == NULL!"); + dbg("serial_unthrottle"); + + if (port_paranoia_check (port, "serial_unthrottle")) { return; } - if (!serial->type) { - dbg("serial->type == NULL!"); + + serial = port->serial; + if (serial_paranoia_check (serial, "serial_unthrottle")) { return; } - if (!serial->port[port].active) { - dbg ("device not open"); + + dbg("serial_unthrottle port %d", port->number); + + if (!port->active) { + dbg ("port not open"); return; } /* pass on to the driver specific version of this function */ if (serial->type->unthrottle) { - serial->type->unthrottle(tty); - } else { - generic_unthrottle(tty); + serial->type->unthrottle(port); } return; @@ -560,70 +613,62 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port; - + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; + dbg("serial_ioctl"); - - if (!serial) { - dbg("serial == NULL!"); + + if (port_paranoia_check (port, "serial_ioctl")) { return -ENODEV; } - port = MINOR(tty->device) - serial->minor; - - dbg("serial_ioctl port %d", port); - - /* do some sanity checking that we really have a device present */ - if (!serial->type) { - dbg("serial->type == NULL!"); + serial = port->serial; + if (serial_paranoia_check (serial, "serial_ioctl")) { return -ENODEV; } - if (!serial->port[port].active) { - dbg ("device not open"); + + dbg("serial_ioctl port %d", port->number); + + if (!port->active) { + dbg ("port not open"); return -ENODEV; } /* pass on to the driver specific version of this function if it is available */ if (serial->type->ioctl) { - return (serial->type->ioctl(tty, file, cmd, arg)); + return (serial->type->ioctl(port, file, cmd, arg)); } else { - return (generic_ioctl (tty, file, cmd, arg)); + return -ENOIOCTLCMD; } } static void serial_set_termios (struct tty_struct *tty, struct termios * old) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port; - + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; + dbg("serial_set_termios"); - - if (!serial) { - dbg("serial == NULL!"); + + if (port_paranoia_check (port, "serial_set_termios")) { return; } - port = MINOR(tty->device) - serial->minor; - - dbg("serial_set_termios port %d", port); - - /* do some sanity checking that we really have a device present */ - if (!serial->type) { - dbg("serial->type == NULL!"); + serial = port->serial; + if (serial_paranoia_check (serial, "serial_set_termios")) { return; } - if (!serial->port[port].active) { - dbg ("device not open"); + + dbg("serial_set_termios port %d", port->number); + + if (!port->active) { + dbg ("port not open"); return; } /* pass on to the driver specific version of this function if it is available */ if (serial->type->set_termios) { - serial->type->set_termios(tty, old); - } else { - generic_set_termios (tty, old); + serial->type->set_termios(port, old); } return; @@ -632,32 +677,31 @@ static void serial_break (struct tty_struct *tty, int break_state) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port; - - if (!serial) { - dbg("serial == NULL!"); + struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; + struct usb_serial *serial; + + dbg("serial_break"); + + if (port_paranoia_check (port, "serial_break")) { return; } - port = MINOR(tty->device) - serial->minor; - - dbg("serial_break port %d", port); - - /* do some sanity checking that we really have a device present */ - if (!serial->type) { - dbg("serial->type == NULL!"); + serial = port->serial; + if (serial_paranoia_check (serial, "serial_break")) { return; } - if (!serial->port[port].active) { - dbg ("device not open"); + + dbg("serial_break port %d", port->number); + + if (!port->active) { + dbg ("port not open"); return; } /* pass on to the driver specific version of this function if it is available */ if (serial->type->break_ctl) { - serial->type->break_ctl(tty, break_state); + serial->type->break_ctl(port, break_state); } } @@ -666,13 +710,9 @@ /***************************************************************************** * Connect Tech's White Heat specific driver functions *****************************************************************************/ -static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp) +static int whiteheat_open (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; - - dbg("whiteheat_serial_open port %d", portNumber); + dbg("whiteheat_open port %d", port->number); if (port->active) { dbg ("device already open"); @@ -681,7 +721,7 @@ port->active = 1; /*Start reading from the device*/ - if (usb_submit_urb(&port->read_urb)) + if (usb_submit_urb(port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ @@ -691,36 +731,30 @@ } -static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp) +static void whiteheat_close(struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; - - dbg("whiteheat_serial_close port %d", portNumber); + dbg("whiteheat_close port %d", port->number); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - usb_unlink_urb (&port->write_urb); - usb_unlink_urb (&port->read_urb); + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); port->active = 0; } -static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_termios) +static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = port->tty->termios->c_cflag; - dbg("whiteheat_set_termios port %d", port); + dbg("whiteheat_set_termios port %d", port->number); /* check that they really want us to change something */ if (old_termios) { if ((cflag == old_termios->c_cflag) && - (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { + (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { dbg("nothing to change..."); return; } @@ -732,12 +766,9 @@ return; } -static void whiteheat_throttle (struct tty_struct * tty) +static void whiteheat_throttle (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("whiteheat_throttle port %d", port); + dbg("whiteheat_throttle port %d", port->number); /* Change the control signals */ /* FIXME!!! */ @@ -746,12 +777,9 @@ } -static void whiteheat_unthrottle (struct tty_struct * tty) +static void whiteheat_unthrottle (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("whiteheat_unthrottle port %d", port); + dbg("whiteheat_unthrottle port %d", port->number); /* Change the control signals */ /* FIXME!!! */ @@ -837,13 +865,9 @@ /****************************************************************************** * Handspring Visor specific driver functions ******************************************************************************/ -static int visor_serial_open (struct tty_struct *tty, struct file *filp) +static int visor_open (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; - - dbg("visor_serial_open port %d", portNumber); + dbg("visor_open port %d", port->number); if (port->active) { dbg ("device already open"); @@ -853,23 +877,22 @@ port->active = 1; /*Start reading from the device*/ - if (usb_submit_urb(&port->read_urb)) + if (usb_submit_urb(port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); return (0); } -static void visor_serial_close(struct tty_struct *tty, struct file * filp) + +static void visor_close (struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL); - dbg("visor_serial_close port %d", portNumber); + dbg("visor_close port %d", port->number); if (!transfer_buffer) { - err("visor_serial_close: kmalloc(%d) failed.", 0x12); + err("visor_close: kmalloc(%d) failed.", 0x12); } else { /* send a shutdown message to the device */ usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, @@ -877,33 +900,27 @@ } /* shutdown our bulk reads and writes */ - usb_unlink_urb (&port->write_urb); - usb_unlink_urb (&port->read_urb); + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); port->active = 0; } -static void visor_throttle (struct tty_struct * tty) +static void visor_throttle (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("visor_throttle port %d", port); + dbg("visor_throttle port %d", port->number); - usb_unlink_urb (&serial->port[port].read_urb); + usb_unlink_urb (port->read_urb); return; } -static void visor_unthrottle (struct tty_struct * tty) +static void visor_unthrottle (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + dbg("visor_unthrottle port %d", port->number); - dbg("visor_unthrottle port %d", port); - - if (usb_unlink_urb (&serial->port[port].read_urb)) + if (usb_unlink_urb (port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); return; @@ -988,17 +1005,15 @@ #include "ftdi_sio.h" -static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp) +static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; char buf[1]; /* Needed for the usb_control_msg I think */ - dbg("ftdi_sio_serial_open port %d", portNumber); + dbg("ftdi_sio_open port %d", port->number); if (port->active) { - dbg ("device already open"); + dbg ("port already open"); return -EINVAL; } port->active = 1; @@ -1069,21 +1084,19 @@ } /*Start reading from the device*/ - if (usb_submit_urb(&port->read_urb)) + if (usb_submit_urb(port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); return (0); } -static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp) +static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; char buf[1]; - dbg("ftdi_sio_serial_close port %d", portNumber); + dbg("ftdi_sio_close port %d", port->number); /* FIXME - might be able to do both simultaneously */ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -1104,8 +1117,8 @@ /* FIXME Should I flush the device here? - not doing it for now */ /* shutdown our bulk reads and writes */ - usb_unlink_urb (&port->write_urb); - usb_unlink_urb (&port->read_urb); + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); port->active = 0; } @@ -1116,15 +1129,13 @@ B1 0 B2..7 length of message excluding byte 0 */ -static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) +static int ftdi_sio_write (struct usb_serial_port *port, int from_user, + const unsigned char *buf, int count) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; const int data_offset = 1; - dbg("ftdi_sio_serial_write port %d, %d bytes", portNumber, count); + dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count); if (count == 0) { dbg("write request of 0 bytes"); @@ -1133,9 +1144,9 @@ /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { - unsigned char *first_byte = port->write_urb.transfer_buffer; + unsigned char *first_byte = port->write_urb->transfer_buffer; - if (port->write_urb.status == -EINPROGRESS) { + if (port->write_urb->status == -EINPROGRESS) { dbg ("already writing"); return 0; } @@ -1148,16 +1159,16 @@ /* Copy in the data to send */ if (from_user) { - copy_from_user(port->write_urb.transfer_buffer + data_offset , + copy_from_user(port->write_urb->transfer_buffer + data_offset , buf, count - data_offset ); } else { - memcpy(port->write_urb.transfer_buffer + data_offset, + memcpy(port->write_urb->transfer_buffer + data_offset, buf, count - data_offset ); } /* Write the control byte at the front of the packet*/ - first_byte = port->write_urb.transfer_buffer; + first_byte = port->write_urb->transfer_buffer; *first_byte = 1 | ((count-data_offset) << 2) ; #ifdef DEBUG @@ -1181,9 +1192,9 @@ #endif /* send the data out the bulk port */ - port->write_urb.transfer_buffer_length = count; + port->write_urb->transfer_buffer_length = count; - if (usb_submit_urb(&port->write_urb)) + if (usb_submit_urb(port->write_urb)) dbg("usb_submit_urb(write bulk) failed"); dbg("write returning: %d", count - data_offset); @@ -1197,14 +1208,24 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) { /* ftdi_sio_serial_buld_callback */ - struct usb_serial *serial = (struct usb_serial *)urb->context; - struct tty_struct *tty = serial->tty; + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial; + struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; const int data_offset = 2; int i; dbg("ftdi_sio_read_bulk_callback"); + if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) { + return; + } + + serial = port->serial; + if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) { + return; + } + if (urb->status) { dbg("nonzero read bulk status received: %d", urb->status); return; @@ -1227,6 +1248,7 @@ if (urb->actual_length > data_offset) { + tty = port->tty; for (i = data_offset ; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); } @@ -1241,14 +1263,14 @@ } /* ftdi_sio_serial_read_bulk_callback */ -static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios) +static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - unsigned int cflag = tty->termios->c_cflag; + struct usb_serial *serial = port->serial; + unsigned int cflag = port->tty->termios->c_cflag; __u16 urb_value; /* Will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ - dbg("ftdi_sio_set_termios port %d", port); + + dbg("ftdi_sio_set_termios port %d", port->number); /* FIXME - we should keep the old termios really */ /* FIXME -For this cut I don't care if the line is really changing or @@ -1312,14 +1334,14 @@ /*FIXME - the beginnings of this implementation - not even hooked into the driver yet */ -static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + struct usb_serial *serial = port->serial; __u16 urb_value=0; /* Will hold the new flags */ char buf[1]; int ret, mask; - dbg("ftdi_sio_ioctl port %d", port); + + dbg("ftdi_sio_ioctl port %d", port->number); /* Based on code from acm.c */ switch (cmd) { @@ -1408,8 +1430,9 @@ static void keyspan_pda_rx_interrupt (struct urb *urb) { - struct usb_serial *serial = (struct usb_serial *) urb->context; - struct tty_struct *tty = serial->tty; + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial; + struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; @@ -1417,11 +1440,21 @@ if (urb->status) return; - /* see if the message is data or a status interrupt */ + if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) { + return; + } + + serial = port->serial; + if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) { + return; + } + + /* see if the message is data or a status interrupt */ switch (data[0]) { case 0: /* rest of message is rx data */ if (urb->actual_length) { + tty = serial->port[0].tty; for (i = 1; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); } @@ -1435,6 +1468,7 @@ case 1: /* modemline change */ break; case 2: /* tx unthrottle interrupt */ + tty = serial->port[0].tty; serial->tx_throttled = 0; wake_up(&serial->write_wait); /* wake up writer */ wake_up(&tty->write_wait); /* them too */ @@ -1451,11 +1485,8 @@ } -static void keyspan_pda_rx_throttle (struct tty_struct *tty) +static void keyspan_pda_rx_throttle (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - /* stop receiving characters. We just turn off the URB request, and let chars pile up in the device. If we're doing hardware flowcontrol, the device will signal the other end when its buffer @@ -1463,19 +1494,16 @@ send an XOFF, although it might make sense to foist that off upon the device too. */ - dbg("keyspan_pda_rx_throttle port %d", port); - usb_unlink_urb(&serial->port[port].read_urb); + dbg("keyspan_pda_rx_throttle port %d", port->number); + usb_unlink_urb(port->read_urb); } -static void keyspan_pda_rx_unthrottle (struct tty_struct *tty) +static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - /* just restart the receive interrupt URB */ - dbg("keyspan_pda_rx_unthrottle port %d", port); - if (usb_submit_urb(&serial->port[port].read_urb)) + dbg("keyspan_pda_rx_unthrottle port %d", port->number); + if (usb_submit_urb(port->read_urb)) dbg(" usb_submit_urb(read urb) failed"); return; } @@ -1516,9 +1544,9 @@ } -static void keyspan_pda_break_ctl (struct tty_struct *tty, int break_state) +static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + struct usb_serial *serial = port->serial; int value; if (break_state == -1) value = 1; /* start break */ @@ -1535,11 +1563,11 @@ } -static void keyspan_pda_set_termios (struct tty_struct *tty, +static void keyspan_pda_set_termios (struct usb_serial_port *port, struct termios *old_termios) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - unsigned int cflag = tty->termios->c_cflag; + struct usb_serial *serial = port->serial; + unsigned int cflag = port->tty->termios->c_cflag; /* cflag specifies lots of stuff: number of stop bits, parity, number of data bits, baud. What can the device actually handle?: @@ -1611,10 +1639,10 @@ } -static int keyspan_pda_ioctl(struct tty_struct *tty, struct file *file, +static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + struct usb_serial *serial = port->serial; int rc; unsigned int value; unsigned char status, mask; @@ -1677,11 +1705,10 @@ return -ENOIOCTLCMD; } -static int keyspan_pda_write(struct tty_struct * tty, int from_user, +static int keyspan_pda_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + struct usb_serial *serial = port->serial; int request_unthrottle = 0; int rc = 0; DECLARE_WAITQUEUE(wait, current); @@ -1704,7 +1731,7 @@ the TX urb is in-flight (wait until it completes) the device is full (wait until it says there is room) */ - while (serial->port[port].write_urb.status == -EINPROGRESS) { + while (port->write_urb->status == -EINPROGRESS) { if (0 /* file->f_flags & O_NONBLOCK */) { rc = -EAGAIN; goto err; @@ -1746,8 +1773,7 @@ remove_wait_queue(&serial->write_wait, &wait); set_current_state(TASK_RUNNING); - count = (count > serial->port[port].bulk_out_size) ? - serial->port[port].bulk_out_size : count; + count = (count > port->bulk_out_size) ? port->bulk_out_size : count; if (count > serial->tx_room) { unsigned char room; /* Looks like we might overrun the Tx buffer. Ask the device @@ -1784,17 +1810,15 @@ if (count) { /* now transfer data */ if (from_user) { - copy_from_user(serial->port[port].write_urb.transfer_buffer, - buf, count); + copy_from_user(port->write_urb->transfer_buffer, buf, count); } else { - memcpy (serial->port[port].write_urb.transfer_buffer, - buf, count); + memcpy (port->write_urb->transfer_buffer, buf, count); } /* send the data out the bulk port */ - serial->port[port].write_urb.transfer_buffer_length = count; + port->write_urb->transfer_buffer_length = count; - if (usb_submit_urb(&serial->port[port].write_urb)) + if (usb_submit_urb(port->write_urb)) dbg(" usb_submit_urb(write bulk) failed"); } else { @@ -1828,11 +1852,22 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb) { - struct usb_serial *serial = (struct usb_serial *) urb->context; - struct tty_struct *tty = serial->tty; + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial; + struct tty_struct *tty; + + if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) { + return; + } + serial = port->serial; + if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) { + return; + } + wake_up_interruptible(&serial->write_wait); + tty = port->tty; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -1841,9 +1876,9 @@ } -static int keyspan_pda_write_room (struct tty_struct *tty) +static int keyspan_pda_write_room (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + struct usb_serial *serial = port->serial; /* used by n_tty.c for processing of tabs and such. Giving it our conservative guess is probably good enough, but needs testing by @@ -1853,9 +1888,9 @@ } -static int keyspan_pda_chars_in_buffer (struct tty_struct *tty) +static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + struct usb_serial *serial = port->serial; /* when throttled, return at least WAKEUP_CHARS to tell select() (via n_tty.c:normal_poll() ) that we're not writeable. */ @@ -1865,11 +1900,9 @@ } -static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp) +static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; unsigned char room; int rc; @@ -1901,33 +1934,30 @@ /* the normal serial device seems to always turn on DTR and RTS here, so do the same */ - if (tty->termios->c_cflag & CBAUD) + if (port->tty->termios->c_cflag & CBAUD) keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) ); else keyspan_pda_set_modem_info(serial, 0); /*Start reading from the device*/ - if (usb_submit_urb(&port->read_urb)) + if (usb_submit_urb(port->read_urb)) dbg(" usb_submit_urb(read int) failed"); return (0); } -static void keyspan_pda_serial_close(struct tty_struct *tty, - struct file *filp) +static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; /* the normal serial device seems to always shut off DTR and RTS now */ - if (tty->termios->c_cflag & HUPCL) + if (port->tty->termios->c_cflag & HUPCL) keyspan_pda_set_modem_info(serial, 0); /* shutdown our bulk reads and writes */ - usb_unlink_urb (&port->write_urb); - usb_unlink_urb (&port->read_urb); + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); port->active = 0; } @@ -1971,7 +2001,7 @@ intin = serial->port[0].interrupt_in_endpoint; /* set up the receive interrupt urb */ - FILL_INT_URB(&serial->port[0].read_urb, serial->dev, + FILL_INT_URB(serial->port[0].read_urb, serial->dev, usb_rcvintpipe(serial->dev, intin->bEndpointAddress), serial->port[0].interrupt_in_buffer, intin->wMaxPacketSize, @@ -1990,13 +2020,11 @@ /***************************************************************************** * generic devices specific driver functions *****************************************************************************/ -static int generic_serial_open (struct tty_struct *tty, struct file *filp) +static int generic_open (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; - dbg("generic_serial_open port %d", portNumber); + dbg("generic_open port %d", port->number); if (port->active) { dbg ("device already open"); @@ -2007,7 +2035,7 @@ /* if we have a bulk interrupt, start reading from it */ if (serial->num_bulk_in) { /*Start reading from the device*/ - if (usb_submit_urb(&port->read_urb)) + if (usb_submit_urb(port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); } @@ -2015,33 +2043,29 @@ } -static void generic_serial_close(struct tty_struct *tty, struct file * filp) +static void generic_close (struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; - dbg("generic_serial_close port %d", portNumber); + dbg("generic_close port %d", port->number); /* shutdown any bulk reads that might be going on */ if (serial->num_bulk_out) { - usb_unlink_urb (&port->write_urb); + usb_unlink_urb (port->write_urb); } if (serial->num_bulk_in) { - usb_unlink_urb (&port->read_urb); + usb_unlink_urb (port->read_urb); } port->active = 0; } -static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) +static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; - dbg("generic_serial_write port %d", portNumber); + dbg("generic_serial_write port %d", port->number); if (count == 0) { dbg("write request of 0 bytes"); @@ -2050,7 +2074,7 @@ /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { - if (port->write_urb.status == -EINPROGRESS) { + if (port->write_urb->status == -EINPROGRESS) { dbg ("already writing"); return (0); } @@ -2058,16 +2082,16 @@ count = (count > port->bulk_out_size) ? port->bulk_out_size : count; if (from_user) { - copy_from_user(port->write_urb.transfer_buffer, buf, count); + copy_from_user(port->write_urb->transfer_buffer, buf, count); } else { - memcpy (port->write_urb.transfer_buffer, buf, count); + memcpy (port->write_urb->transfer_buffer, buf, count); } /* send the data out the bulk port */ - port->write_urb.transfer_buffer_length = count; + port->write_urb->transfer_buffer_length = count; - if (usb_submit_urb(&port->write_urb)) + if (usb_submit_urb(port->write_urb)) dbg("usb_submit_urb(write bulk) failed"); return (count); @@ -2078,17 +2102,15 @@ } -static int generic_write_room (struct tty_struct *tty) +static int generic_write_room (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *)tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; int room; - dbg("generic_write_room port %d", portNumber); + dbg("generic_write_room port %d", port->number); if (serial->num_bulk_out) { - if (port->write_urb.status == -EINPROGRESS) + if (port->write_urb->status == -EINPROGRESS) room = 0; else room = port->bulk_out_size; @@ -2100,16 +2122,14 @@ } -static int generic_chars_in_buffer (struct tty_struct *tty) +static int generic_chars_in_buffer (struct usb_serial_port *port) { - struct usb_serial *serial = (struct usb_serial *)tty->driver_data; - int portNumber = MINOR(tty->device) - serial->minor; - struct usb_serial_port *port = &serial->port[portNumber]; + struct usb_serial *serial = port->serial; - dbg("generic_chars_in_buffer port %d", portNumber); + dbg("generic_chars_in_buffer port %d", port->number); if (serial->num_bulk_out) { - if (port->write_urb.status == -EINPROGRESS) { + if (port->write_urb->status == -EINPROGRESS) { return (port->bulk_out_size); } } @@ -2118,43 +2138,25 @@ } -static void generic_throttle (struct tty_struct *tty) -{ - /* do nothing for the generic device */ - return; -} - - -static void generic_unthrottle (struct tty_struct *tty) -{ - /* do nothing for the generic device */ - return; -} - - -static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) -{ - /* generic driver doesn't support any ioctls yet */ - return -ENOIOCTLCMD; -} - - -static void generic_set_termios (struct tty_struct *tty, struct termios * old) -{ - /* generic driver doesn't really care about setting any line settings */ - return; -} - - static void generic_read_bulk_callback (struct urb *urb) { - struct usb_serial *serial = (struct usb_serial *)urb->context; - struct tty_struct *tty = serial->tty; + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial; + struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; dbg("generic_read_bulk_callback"); + if (port_paranoia_check (port, "generic_read_bulk_callback")) { + return; + } + + serial = port->serial; + if (serial_paranoia_check (serial, "generic_read_bulk_callback")) { + return; + } + if (urb->status) { dbg("nonzero read bulk status received: %d", urb->status); return; @@ -2169,7 +2171,8 @@ printk ("\n"); } #endif - + + tty = port->tty; if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); @@ -2187,16 +2190,27 @@ static void generic_write_bulk_callback (struct urb *urb) { - struct usb_serial *serial = (struct usb_serial *) urb->context; - struct tty_struct *tty = serial->tty; + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial; + struct tty_struct *tty; dbg("generic_write_bulk_callback"); + if (port_paranoia_check (port, "generic_write_bulk_callback")) { + return; + } + + serial = port->serial; + if (serial_paranoia_check (serial, "generic_write_bulk_callback")) { + return; + } + if (urb->status) { dbg("nonzero write bulk status received: %d", urb->status); return; } + tty = port->tty; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -2206,7 +2220,6 @@ } - static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_serial *serial = NULL; @@ -2331,6 +2344,11 @@ /* set up the endpoint information */ for (i = 0; i < num_bulk_in; ++i) { port = &serial->port[i]; + port->read_urb = usb_alloc_urb (0); + if (!port->read_urb) { + err("No free urbs available"); + goto probe_error; + } buffer_size = bulk_in_endpoint[i]->wMaxPacketSize; port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); if (!port->bulk_in_buffer) { @@ -2338,16 +2356,21 @@ goto probe_error; } if (serial->type->read_bulk_callback) { - FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), - port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, serial); + FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), + port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port); } else { - FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), - port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, serial); + FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), + port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port); } } for (i = 0; i < num_bulk_out; ++i) { port = &serial->port[i]; + port->write_urb = usb_alloc_urb(0); + if (!port->write_urb) { + err("No free urbs available"); + goto probe_error; + } port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize; port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL); if (!port->bulk_out_buffer) { @@ -2355,25 +2378,31 @@ goto probe_error; } if (serial->type->write_bulk_callback) { - FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), - port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, serial); + FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), + port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port); } else { - FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), - port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, serial); + FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), + port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port); } } #if 0 /* use this code when WhiteHEAT is up and running */ for (i = 0; i < num_interrupt_in; ++i) { + port = &serial->port[i]; + port->control_urb = usb_alloc_urb(0); + if (!port->control_urb) { + err("No free urbs available"); + goto probe_error; + } buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize; - serial->interrupt_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL); - if (!serial->interrupt_in_buffer[i]) { + port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!port->interrupt_in_buffer) { err("Couldn't allocate interrupt_in_buffer"); goto probe_error; } - FILL_INT_URB(&serial->control_urb[i], dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress), - serial->interrupt_in_buffer[i], buffer_size, serial_control_irq, - serial, interrupt_in_endpoint[i]->bInterval); + FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress), + port->interrupt_in_buffer, buffer_size, serial_control_irq, + port, interrupt_in_endpoint[i]->bInterval); } #endif @@ -2395,15 +2424,27 @@ probe_error: if (serial) { - for (i = 0; i < num_bulk_in; ++i) + for (i = 0; i < num_bulk_in; ++i) { + port = &serial->port[i]; + if (port->read_urb) + usb_free_urb (port->read_urb); if (serial->port[i].bulk_in_buffer[i]) kfree (serial->port[i].bulk_in_buffer); - for (i = 0; i < num_bulk_out; ++i) + } + for (i = 0; i < num_bulk_out; ++i) { + port = &serial->port[i]; + if (port->write_urb) + usb_free_urb (port->write_urb); if (serial->port[i].bulk_out_buffer) kfree (serial->port[i].bulk_out_buffer); - for (i = 0; i < num_interrupt_in; ++i) + } + for (i = 0; i < num_interrupt_in; ++i) { + port = &serial->port[i]; + if (port->control_urb) + usb_free_urb (port->control_urb); if (serial->port[i].interrupt_in_buffer) kfree (serial->port[i].interrupt_in_buffer); + } /* return the minor range that this device had */ return_serial (serial); @@ -2422,27 +2463,33 @@ int i; if (serial) { - /* need to stop any transfers...*/ - for (i = 0; i < serial->num_ports; ++i) { - port = &serial->port[i]; - usb_unlink_urb (&port->write_urb); - usb_unlink_urb (&port->read_urb); - port->active = 0; - } + for (i = 0; i < serial->num_ports; ++i) + serial->port[i].active = 0; - /* free up any memory that we allocated */ for (i = 0; i < serial->num_bulk_in; ++i) { port = &serial->port[i]; + if (port->read_urb) { + usb_unlink_urb (port->read_urb); + usb_free_urb (port->read_urb); + } if (port->bulk_in_buffer) kfree (port->bulk_in_buffer); } for (i = 0; i < serial->num_bulk_out; ++i) { port = &serial->port[i]; + if (port->write_urb) { + usb_unlink_urb (port->write_urb); + usb_free_urb (port->write_urb); + } if (port->bulk_out_buffer) kfree (port->bulk_out_buffer); } for (i = 0; i < serial->num_interrupt_in; ++i) { port = &serial->port[i]; + if (port->control_urb) { + usb_unlink_urb (port->control_urb); + usb_free_urb (port->control_urb); + } if (port->interrupt_in_buffer) kfree (port->interrupt_in_buffer); } @@ -2468,7 +2515,7 @@ static struct tty_driver serial_tty_driver = { magic: TTY_DRIVER_MAGIC, driver_name: "usb", - name: "ttyUSB", + name: "ttyUSB%d", major: SERIAL_TTY_MAJOR, minor_start: 0, num: SERIAL_TTY_MINORS, diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h --- v2.3.99-pre2/linux/drivers/usb/serial/usb-serial.h Sun Mar 19 18:35:31 2000 +++ linux/drivers/usb/serial/usb-serial.h Sun Mar 19 18:15:06 2000 @@ -52,8 +52,12 @@ #define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ +#define USB_SERIAL_MAGIC 0x6702 /* magic number for usb_serial struct */ +#define USB_SERIAL_PORT_MAGIC 0x7301 /* magic number for usb_serial_port struct */ + struct usb_serial_port { + int magic; struct usb_serial *serial; /* pointer back to the owner of this port */ struct tty_struct * tty; /* the coresponding tty for this device */ unsigned char minor; @@ -63,21 +67,21 @@ struct usb_endpoint_descriptor * interrupt_in_endpoint; __u8 interrupt_in_interval; unsigned char * interrupt_in_buffer; - struct urb control_urb; + struct urb * control_urb; unsigned char * bulk_in_buffer; - struct urb read_urb; + struct urb * read_urb; unsigned char * bulk_out_buffer; int bulk_out_size; - struct urb write_urb; + struct urb * write_urb; void * private; /* data private to the specific driver */ }; struct usb_serial { + int magic; struct usb_device * dev; struct usb_serial_device_type * type; - struct tty_struct * tty; /* the coresponding tty for this device */ unsigned char minor; unsigned char num_ports; /* the number of ports this device has */ char num_interrupt_in; /* number of interrupt in endpoints we have */ @@ -121,16 +125,16 @@ int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ /* serial function calls */ - int (*open)(struct tty_struct * tty, struct file * filp); - void (*close)(struct tty_struct * tty, struct file * filp); - int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); - int (*write_room)(struct tty_struct *tty); - int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct termios * old); - void (*break_ctl)(struct tty_struct *tty, int break_state); - int (*chars_in_buffer)(struct tty_struct *tty); - void (*throttle)(struct tty_struct * tty); - void (*unthrottle)(struct tty_struct * tty); + int (*open) (struct usb_serial_port *port, struct file * filp); + void (*close) (struct usb_serial_port *port, struct file * filp); + int (*write) (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); + int (*write_room) (struct usb_serial_port *port); + int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); + void (*set_termios) (struct usb_serial_port *port, struct termios * old); + void (*break_ctl) (struct usb_serial_port *port, int break_state); + int (*chars_in_buffer) (struct usb_serial_port *port); + void (*throttle) (struct usb_serial_port *port); + void (*unthrottle) (struct usb_serial_port *port); void (*read_bulk_callback)(struct urb *urb); void (*write_bulk_callback)(struct urb *urb); @@ -140,15 +144,11 @@ /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ /* need to always compile these in, as some of the other devices use these functions as their own. */ /* if a driver does not provide a function pointer, the generic function will be called. */ -static int generic_serial_open (struct tty_struct *tty, struct file *filp); -static void generic_serial_close (struct tty_struct *tty, struct file *filp); -static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static int generic_write_room (struct tty_struct *tty); -static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); -static void generic_set_termios (struct tty_struct *tty, struct termios * old); -static int generic_chars_in_buffer (struct tty_struct *tty); -static void generic_throttle (struct tty_struct *tty); -static void generic_unthrottle (struct tty_struct *tty); +static int generic_open (struct usb_serial_port *port, struct file *filp); +static void generic_close (struct usb_serial_port *port, struct file *filp); +static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static int generic_write_room (struct usb_serial_port *port); +static int generic_chars_in_buffer (struct usb_serial_port *port); static void generic_read_bulk_callback (struct urb *urb); static void generic_write_bulk_callback (struct urb *urb); @@ -172,11 +172,11 @@ #ifdef CONFIG_USB_SERIAL_WHITEHEAT /* function prototypes for the Connect Tech WhiteHEAT serial converter */ -static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); -static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); -static void whiteheat_set_termios (struct tty_struct *tty, struct termios * old); -static void whiteheat_throttle (struct tty_struct *tty); -static void whiteheat_unthrottle (struct tty_struct *tty); +static int whiteheat_open (struct usb_serial_port *port, struct file *filp); +static void whiteheat_close (struct usb_serial_port *port, struct file *filp); +static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old); +static void whiteheat_throttle (struct usb_serial_port *port); +static void whiteheat_unthrottle (struct usb_serial_port *port); static int whiteheat_startup (struct usb_serial *serial); /* All of the device info needed for the Connect Tech WhiteHEAT */ @@ -193,6 +193,7 @@ num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, + num_ports: 1, startup: whiteheat_startup }; static struct usb_serial_device_type whiteheat_device = { @@ -206,8 +207,8 @@ num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 4, - open: whiteheat_serial_open, - close: whiteheat_serial_close, + open: whiteheat_open, + close: whiteheat_close, throttle: whiteheat_throttle, unthrottle: whiteheat_unthrottle, set_termios: whiteheat_set_termios, @@ -269,11 +270,11 @@ /* function prototypes for a handspring visor */ -static int visor_serial_open (struct tty_struct *tty, struct file *filp); -static void visor_serial_close (struct tty_struct *tty, struct file *filp); -static void visor_throttle (struct tty_struct *tty); -static void visor_unthrottle (struct tty_struct *tty); -static int visor_startup (struct usb_serial *serial); +static int visor_open (struct usb_serial_port *port, struct file *filp); +static void visor_close (struct usb_serial_port *port, struct file *filp); +static void visor_throttle (struct usb_serial_port *port); +static void visor_unthrottle (struct usb_serial_port *port); +static int visor_startup (struct usb_serial *serial); /* All of the device info needed for the Handspring Visor */ static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; @@ -289,8 +290,8 @@ num_bulk_in: 2, num_bulk_out: 2, num_ports: 2, - open: visor_serial_open, - close: visor_serial_close, + open: visor_open, + close: visor_close, throttle: visor_throttle, unthrottle: visor_unthrottle, startup: visor_startup, @@ -300,12 +301,12 @@ #ifdef CONFIG_USB_SERIAL_FTDI_SIO /* function prototypes for a FTDI serial converter */ -static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp); -static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp); -static int ftdi_sio_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp); +static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp); +static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); static void ftdi_sio_read_bulk_callback (struct urb *urb); -static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios * old); -static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); +static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old); +static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); /* All of the device info needed for the FTDI SIO serial converter */ static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; @@ -321,9 +322,10 @@ num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, - open: ftdi_sio_serial_open, - close: ftdi_sio_serial_close, - write: ftdi_sio_serial_write, + open: ftdi_sio_open, + close: ftdi_sio_close, + write: ftdi_sio_write, + ioctl: ftdi_sio_ioctl, read_bulk_callback: ftdi_sio_read_bulk_callback, set_termios: ftdi_sio_set_termios }; @@ -332,28 +334,28 @@ #ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA /* function prototypes for a Keyspan PDA serial converter */ -static int keyspan_pda_serial_open (struct tty_struct *tty, +static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp); -static void keyspan_pda_serial_close (struct tty_struct *tty, +static void keyspan_pda_close (struct usb_serial_port *port, struct file *filp); static int keyspan_pda_startup (struct usb_serial *serial); -static void keyspan_pda_rx_throttle (struct tty_struct *tty); -static void keyspan_pda_rx_unthrottle (struct tty_struct *tty); +static void keyspan_pda_rx_throttle (struct usb_serial_port *port); +static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port); static int keyspan_pda_setbaud (struct usb_serial *serial, int baud); -static int keyspan_pda_write_room (struct tty_struct *tty); -static int keyspan_pda_write (struct tty_struct *tty, +static int keyspan_pda_write_room (struct usb_serial_port *port); +static int keyspan_pda_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); static void keyspan_pda_write_bulk_callback (struct urb *urb); -static int keyspan_pda_chars_in_buffer (struct tty_struct *tty); -static int keyspan_pda_ioctl (struct tty_struct *tty, +static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port); +static int keyspan_pda_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); -static void keyspan_pda_set_termios (struct tty_struct *tty, +static void keyspan_pda_set_termios (struct usb_serial_port *port, struct termios *old); -static void keyspan_pda_break_ctl (struct tty_struct *tty, +static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state); static int keyspan_pda_fake_startup (struct usb_serial *serial); @@ -385,8 +387,8 @@ num_bulk_in: 0, num_bulk_out: 1, num_ports: 1, - open: keyspan_pda_serial_open, - close: keyspan_pda_serial_close, + open: keyspan_pda_open, + close: keyspan_pda_close, write: keyspan_pda_write, write_room: keyspan_pda_write_room, write_bulk_callback: keyspan_pda_write_bulk_callback, diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.99-pre2/linux/drivers/usb/uhci.c Sun Mar 19 18:35:31 2000 +++ linux/drivers/usb/uhci.c Thu Mar 23 14:59:08 2000 @@ -1315,8 +1315,8 @@ 0x00, /* __u16 bcdDevice; */ 0x00, 0x00, /* __u8 iManufacturer; */ - 0x00, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ 0x01 /* __u8 bNumConfigurations; */ }; @@ -1617,7 +1617,13 @@ memcpy (data, root_hub_config_des, len); OK(len); case 0x03: /* string descriptors */ - stat = -EPIPE; + len = usb_root_hub_string (wValue & 0xff, + uhci->io_addr, "UHCI", + data, wLength); + if (len > 0) { + OK (min (leni, len)); + } else + stat = -EPIPE; } break; case RH_GET_DESCRIPTOR | RH_CLASS: @@ -1985,6 +1991,15 @@ { int retval; struct uhci *uhci; + char buf[8], *bufp = buf; + +#ifndef __sparc__ + sprintf(buf, "%d", irq); +#else + bufp = __irq_itoa(irq); +#endif + printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n", + io_addr, bufp); uhci = alloc_uhci(io_addr, io_size); if (!uhci) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.3.99-pre2/linux/drivers/usb/usb-ohci.c Sun Mar 19 18:35:31 2000 +++ linux/drivers/usb/usb-ohci.c Thu Mar 23 15:02:18 2000 @@ -262,8 +262,14 @@ urb_print (urb, "SUB", usb_pipein (pipe)); #endif + /* a request to the virtual root hub */ if (usb_pipedevice (pipe) == ohci->rh.devnum) - return rh_submit_urb (urb); /* a request to the virtual root hub */ + return rh_submit_urb (urb); + + /* when controller's hung, permit only hub cleanup attempts + * such as powering down ports */ + if (ohci->disabled) + return -ESHUTDOWN; /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) { @@ -333,10 +339,11 @@ (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff; } - td_submit_urb (urb); /* fill the TDs and link it to the ed */ - if (ed->state != ED_OPER) /* link the ed into a chain if is not already */ ep_link (ohci, ed); + + td_submit_urb (urb); /* fill the TDs and link it to the ed */ + spin_unlock_irqrestore (&usb_ed_lock, flags); urb->status = USB_ST_URB_PENDING; @@ -1122,8 +1129,8 @@ 0x00, /* __u16 bcdDevice; */ 0x00, 0x00, /* __u8 iManufacturer; */ - 0x00, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ 0x01 /* __u8 bNumConfigurations; */ }; @@ -1222,13 +1229,16 @@ urb_t * urb = (urb_t *) ptr; ohci_t * ohci = urb->dev->bus->hcpriv; + + if (ohci->disabled) + return; if(ohci->rh.send) { len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length); if (len > 0) { urb->actual_length = len; #ifdef DEBUG - urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe)); + urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe)); #endif if (urb->complete) urb->complete (urb); } @@ -1379,27 +1389,49 @@ len = min (leni, min (sizeof (root_hub_config_des), wLength)); data_buf = root_hub_config_des; OK(len); case (0x03): /* string descriptors */ + len = usb_root_hub_string (wValue & 0xff, + (int) ohci->regs, "OHCI", + data, wLength); + if (len > 0) { + data_buf = data; + OK (min (leni, len)); + } + // else fallthrough default: status = TD_CC_STALL; } break; case RH_GET_DESCRIPTOR | RH_CLASS: - *(__u8 *) (data_buf+1) = 0x29; - put_unaligned(cpu_to_le32 (readl (&ohci->regs->roothub.a)), - (__u32 *) (data_buf + 2)); - *(__u8 *) data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */ - - len = min (leni, min(*(__u8 *) data_buf, wLength)); - *(__u8 *) (data_buf+6) = 0; /* Root Hub needs no current from bus */ - if (*(__u8 *) (data_buf+2) < 8) { /* less than 8 Ports */ - *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff; - *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16; - } else { - put_unaligned(cpu_to_le32 (readl(&ohci->regs->roothub.b)), - (__u32 *) (data_buf + 7)); + { + __u32 temp = readl (&ohci->regs->roothub.a); + + data_buf [0] = 9; // min length; + data_buf [1] = 0x29; + data_buf [2] = temp & RH_A_NDP; + data_buf [3] = 0; + if (temp & RH_A_PSM) /* per-port power switching? */ + data_buf [3] |= 0x1; + if (temp & RH_A_NOCP) /* no overcurrent reporting? */ + data_buf [3] |= 0x10; + else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */ + data_buf [3] |= 0x8; + + datab [1] = 0; + data_buf [5] = (temp & RH_A_POTPGT) >> 24; + temp = readl (&ohci->regs->roothub.b); + data_buf [7] = temp & RH_B_DR; + if (data_buf [2] < 7) { + data_buf [8] = 0xff; + } else { + data_buf [0] += 2; + data_buf [8] = (temp & RH_B_DR) >> 8; + data_buf [10] = data_buf [9] = 0xff; + } + + len = min (leni, min (data_buf [0], wLength)); + OK (len); } - OK (len); case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1); @@ -1413,7 +1445,8 @@ dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) )); len = min(len, leni); - memcpy (data, data_buf, len); + if (data != data_buf) + memcpy (data, data_buf, len); urb->actual_length = len; urb->status = cc_to_error [status]; @@ -1472,6 +1505,7 @@ } udelay (1); } + ohci->disabled = 0; } /*-------------------------------------------------------------------------*/ @@ -1502,7 +1536,7 @@ writel (0x628, &ohci->regs->lsthresh); /* Choose the interrupts we care about now, others later on demand */ - mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO; + mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */ writel (mask, &ohci->regs->intrenable); @@ -1550,6 +1584,11 @@ dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no)); + if (ints & OHCI_INTR_UE) { + ohci->disabled++; + err ("OHCI Unrecoverable Error, controller disabled"); + } + if (ints & OHCI_INTR_WDH) { writel (OHCI_INTR_WDH, ®s->intrdisable); dl_done_list (ohci, dl_reverse_done_list (ohci)); @@ -1650,16 +1689,24 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) { ohci_t * ohci; - dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base); + char buf[8], *bufp = buf; + +#ifndef __sparc__ + sprintf(buf, "%d", irq); +#else + bufp = __irq_itoa(irq); +#endif + printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n", + (unsigned long) mem_base, bufp); ohci = hc_alloc_ohci (mem_base); if (!ohci) { return -ENOMEM; } - + INIT_LIST_HEAD (&ohci->ohci_hcd_list); list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); - + hc_reset (ohci); writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control); wait_ms (10); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h --- v2.3.99-pre2/linux/drivers/usb/usb-ohci.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/usb-ohci.h Tue Mar 21 12:37:01 2000 @@ -212,31 +212,53 @@ } roothub; } __attribute((aligned(32))); + +/* OHCI CONTROL AND STATUS REGISTER MASKS */ + /* - * cmdstatus register */ -#define OHCI_CLF 0x02 -#define OHCI_BLF 0x04 + * HcControl (control) register masks + */ +#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ +#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ +#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ +#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ +#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ +#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ +#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ + +/* pre-shifted values for HCFS */ +# define OHCI_USB_RESET (0 << 6) +# define OHCI_USB_RESUME (1 << 6) +# define OHCI_USB_OPER (2 << 6) +# define OHCI_USB_SUSPEND (3 << 6) /* - * Interrupt register masks + * HcCommandStatus (cmdstatus) register masks */ -#define OHCI_INTR_SO (1) -#define OHCI_INTR_WDH (1 << 1) -#define OHCI_INTR_SF (1 << 2) -#define OHCI_INTR_RD (1 << 3) -#define OHCI_INTR_UE (1 << 4) -#define OHCI_INTR_FNO (1 << 5) -#define OHCI_INTR_RHSC (1 << 6) -#define OHCI_INTR_OC (1 << 30) -#define OHCI_INTR_MIE (1 << 31) +#define OHCI_HCR (1 << 0) /* host controller reset */ +#define OHCI_CLF (1 << 1) /* control list filled */ +#define OHCI_BLF (1 << 2) /* bulk list filled */ +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_SOC (3 << 16) /* scheduling overrun count */ /* - * Control register masks + * masks used with interrupt registers: + * HcInterruptStatus (intrstatus) + * HcInterruptEnable (intrenable) + * HcInterruptDisable (intrdisable) */ -#define OHCI_USB_RESET 0 -#define OHCI_USB_RESUME (1 << 6) -#define OHCI_USB_OPER (2 << 6) -#define OHCI_USB_SUSPEND (3 << 6) +#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ +#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ +#define OHCI_INTR_SF (1 << 2) /* start frame */ +#define OHCI_INTR_RD (1 << 3) /* resume detect */ +#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ +#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ +#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ +#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ + /* Virtual Root HUB */ @@ -248,6 +270,9 @@ int interval; struct timer_list rh_int_timer; }; + + +/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ /* destination of request */ #define RH_INTERFACE 0x01 @@ -261,8 +286,8 @@ #define RH_GET_STATUS 0x0080 #define RH_CLEAR_FEATURE 0x0100 #define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 #define RH_SET_DESCRIPTOR 0x0700 #define RH_GET_CONFIGURATION 0x0880 #define RH_SET_CONFIGURATION 0x0900 @@ -282,6 +307,7 @@ #define RH_PORT_RESET 0x04 #define RH_PORT_POWER 0x08 #define RH_PORT_LOW_SPEED 0x09 + #define RH_C_PORT_CONNECTION 0x10 #define RH_C_PORT_ENABLE 0x11 #define RH_C_PORT_SUSPEND 0x12 @@ -298,29 +324,44 @@ #define RH_ACK 0x01 #define RH_REQ_ERR -1 #define RH_NACK 0x00 - -/* Root-Hub Register info */ -#define RH_PS_CCS 0x00000001 -#define RH_PS_PES 0x00000002 -#define RH_PS_PSS 0x00000004 -#define RH_PS_POCI 0x00000008 -#define RH_PS_PRS 0x00000010 -#define RH_PS_PPS 0x00000100 -#define RH_PS_LSDA 0x00000200 -#define RH_PS_CSC 0x00010000 -#define RH_PS_PESC 0x00020000 -#define RH_PS_PSSC 0x00040000 -#define RH_PS_OCIC 0x00080000 -#define RH_PS_PRSC 0x00100000 - -/* Root hub status bits */ -#define RH_HS_LPS 0x00000001 -#define RH_HS_OCI 0x00000002 -#define RH_HS_DRWE 0x00008000 -#define RH_HS_LPSC 0x00010000 -#define RH_HS_OCIC 0x00020000 -#define RH_HS_CRWE 0x80000000 + +/* OHCI ROOT HUB REGISTER MASKS */ + +/* roothub.portstatus [i] bits */ +#define RH_PS_CCS 0x00000001 /* current connect status */ +#define RH_PS_PES 0x00000002 /* port enable status*/ +#define RH_PS_PSS 0x00000004 /* port suspend status */ +#define RH_PS_POCI 0x00000008 /* port over current indicator */ +#define RH_PS_PRS 0x00000010 /* port reset status */ +#define RH_PS_PPS 0x00000100 /* port power status */ +#define RH_PS_LSDA 0x00000200 /* low speed device attached */ +#define RH_PS_CSC 0x00010000 /* connect status change */ +#define RH_PS_PESC 0x00020000 /* port enable status change */ +#define RH_PS_PSSC 0x00040000 /* port suspend status change */ +#define RH_PS_OCIC 0x00080000 /* over current indicator change */ +#define RH_PS_PRSC 0x00100000 /* port reset status change */ + +/* roothub.status bits */ +#define RH_HS_LPS 0x00000001 /* local power status */ +#define RH_HS_OCI 0x00000002 /* over current indicator */ +#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ +#define RH_HS_LPSC 0x00010000 /* local power status change */ +#define RH_HS_OCIC 0x00020000 /* over current indicator change */ +#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ + +/* roothub.b masks */ +#define RH_B_DR 0x0000ffff /* device removable flags */ +#define RH_B_PPCM 0xffff0000 /* port power control mask */ + +/* roothub.a masks */ +#define RH_A_NDP (0xff << 0) /* number of downstream ports */ +#define RH_A_PSM (1 << 8) /* power switching mode */ +#define RH_A_NPS (1 << 9) /* no power switching */ +#define RH_A_DT (1 << 10) /* device type (mbz) */ +#define RH_A_OCPM (1 << 11) /* over current protection mode */ +#define RH_A_NOCP (1 << 12) /* no over current protection */ +#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ #define min(a,b) (((a)<(b))?(a):(b)) @@ -347,23 +388,25 @@ typedef struct ohci { - struct ohci_hcca hcca; /* hcca */ + struct ohci_hcca hcca; /* hcca */ int irq; - struct ohci_regs * regs; /* OHCI controller's memory */ - struct list_head ohci_hcd_list; /* list of all ohci_hcd */ + int disabled; /* e.g. got a UE, we're hung */ + + struct ohci_regs * regs; /* OHCI controller's memory */ + struct list_head ohci_hcd_list; /* list of all ohci_hcd */ struct ohci * next; // chain of uhci device contexts struct list_head urb_list; // list of all pending urbs spinlock_t urb_list_lock; // lock to keep consistency - int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load ballancing)*/ + int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/ ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */ ed_t * ed_bulktail; /* last endpoint of bulk list */ ed_t * ed_controltail; /* last endpoint of control list */ ed_t * ed_isotail; /* last endpoint of iso list */ int intrstatus; - __u32 hc_control; /* copy of the hc control reg */ + __u32 hc_control; /* copy of the hc control reg */ struct usb_bus * bus; struct usb_device * dev[128]; struct virt_root_hub rh; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c --- v2.3.99-pre2/linux/drivers/usb/usb-storage.c Sun Mar 19 18:35:31 2000 +++ linux/drivers/usb/usb-storage.c Thu Mar 23 15:15:18 2000 @@ -3,20 +3,19 @@ * (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * - * Further reference: - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in mind - * when they created this document. The commands are all very similar - * to commands in the SCSI-II and ATAPI specifications. + * This driver is based on the 'USB Mass Storage Class' document. This + * describes in detail the protocol used to communicate with such + * devices. Clearly, the designers had SCSI and ATAPI commands in + * mind when they created this document. The commands are all very + * similar to commands in the SCSI-II and ATAPI specifications. * - * It is important to note that in a number of cases this class exhibits - * class-specific exemptions from the USB specification. Notably the - * usage of NAK, STALL and ACK differs from the norm, in that they are - * used to communicate wait, failed and OK on commands. - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. + * It is important to note that in a number of cases this class + * exhibits class-specific exemptions from the USB specification. + * Notably the usage of NAK, STALL and ACK differs from the norm, in + * that they are used to communicate wait, failed and OK on commands. * + * Also, for certain devices, the interrupt endpoint is used to convey + * status of a command. */ #include @@ -40,7 +39,6 @@ #include "usb-storage.h" #include "usb-storage-debug.h" - /* * This is the size of the structure Scsi_Host_Template. We create * an instance of this structure in this file and this is a check @@ -75,34 +73,47 @@ typedef int (*trans_reset)(struct us_data*); typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); +/* we allocate one of these for every device that we remember */ struct us_data { struct us_data *next; /* next device */ struct usb_device *pusb_dev; /* this usb_device */ unsigned int flags; /* from filter initially */ + + /* information about the device -- only good if device is attached */ __u8 ifnum; /* interface number */ __u8 ep_in; /* in endpoint */ __u8 ep_out; /* out ....... */ __u8 ep_int; /* interrupt . */ - __u8 subclass; /* as in overview */ - __u8 protocol; /* .............. */ - trans_cmnd transport; /* protocol specific do cmd */ - trans_reset transport_reset; /* .......... device reset */ + __u8 subclass; + __u8 protocol; + + /* function pointers for this device */ + trans_cmnd transport; /* transport function */ + trans_reset transport_reset; /* transport device reset */ proto_cmnd proto_handler; /* protocol handler */ + + /* SCSI interfaces */ GUID(guid); /* unique dev id */ struct Scsi_Host *host; /* our dummy host data */ Scsi_Host_Template htmplt; /* own host template */ int host_number; /* to find us */ int host_no; /* allocated by scsi */ Scsi_Cmnd *srb; /* current srb */ + + /* thread information */ Scsi_Cmnd *queue_srb; /* the single queue slot */ int action; /* what to do */ + int pid; /* control thread */ + + /* interrupt info for CBI devices */ struct semaphore ip_waitq; /* for CBI interrupts */ __u16 ip_data; /* interrupt data */ int ip_wanted; /* needed */ - int pid; /* control thread */ - struct semaphore *notify; /* wait for thread to begin */ void *irq_handle; /* for USB int requests */ unsigned int irqpipe; /* pipe for release_irq */ + + /* mutual exclusion structures */ + struct semaphore notify; /* wait for thread to begin */ struct semaphore sleeper; /* to sleep on */ struct semaphore queue_exclusion; /* to protect data structs */ }; @@ -116,6 +127,7 @@ #define US_ACT_DEVICE_RESET 3 #define US_ACT_BUS_RESET 4 #define US_ACT_HOST_RESET 5 +#define US_ACT_EXIT 6 /* The list of structures and the protective lock for them */ static struct us_data *us_list; @@ -254,11 +266,6 @@ case MODE_SENSE: return srb->cmnd[4]; - /* FIXME: this needs to come out when the other - * fix is in place */ - case READ_CAPACITY: - return 8; - /* FIXME: these should be removed and tested */ case LOG_SENSE: case MODE_SENSE_10: @@ -791,9 +798,8 @@ us->ifnum, srb->cmnd, srb->cmd_len, HZ*5); /* check the return code for the command */ + US_DEBUGP("Call to usb_control_msg() returned %d\n", result); if (result < 0) { - US_DEBUGP("Call to usb_control_msg() returned %d\n", result); - /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); @@ -820,15 +826,10 @@ /* STATUS STAGE */ - /* go to sleep until we get this interrup */ - /* FIXME: this should be changed to use a timeout -- or let the - * device reset routine up() this for us to unjam us - */ + /* go to sleep until we get this interrupt */ down(&(us->ip_waitq)); - /* FIXME: currently this code is unreachable, but the idea is - * necessary. See above comment. - */ + /* if we were woken up by a reset instead of the actual interrupt */ if (us->ip_wanted) { US_DEBUGP("Did not get interrupt on CBI\n"); us->ip_wanted = 0; @@ -837,8 +838,9 @@ US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data); - /* UFI gives us ASC and ASCQ, like a request sense */ - /* REQUEST_SENSE and INQUIRY don't affect the sense data, so we + /* UFI gives us ASC and ASCQ, like a request sense + * + * REQUEST_SENSE and INQUIRY don't affect the sense data, so we * ignore the information for those commands */ if (us->subclass == US_SC_UFI) { @@ -1114,29 +1116,27 @@ static int us_release(struct Scsi_Host *psh) { struct us_data *us = (struct us_data *)psh->hostdata[0]; - struct us_data *prev; unsigned long flags; + int result; + /* lock the data structures */ + spin_lock_irqsave(&us_list_spinlock, flags); + + US_DEBUGP("us_release() called for host %s\n", us->htmplt.name); + + /* release the interrupt handler, if necessary */ if (us->irq_handle) { - usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe); + US_DEBUGP("-- releasing irq\n"); + result = usb_release_irq(us->pusb_dev, us->irq_handle, + us->irqpipe); + US_DEBUGP("-- usb_release_irq() returned %d\n", result); us->irq_handle = NULL; } - /* FIXME: release the interface claim here? */ - - /* FIXME: we need to move this elsewhere -- - * the remove function only gets called to remove the module - */ - spin_lock_irqsave(&us_list_spinlock, flags); - if (us_list == us) - us_list = us->next; - else { - prev = us_list; - while (prev->next != us) - prev = prev->next; - prev->next = us->next; - } + /* lock the data structures */ spin_unlock_irqrestore(&us_list_spinlock, flags); + + /* we always have a successful release */ return 0; } @@ -1153,7 +1153,7 @@ { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - US_DEBUGP("Command wakeup\n"); + US_DEBUGP("us_queuecommand() called\n"); srb->host_scribble = (unsigned char *)us; /* get exclusive access to the structures we want */ @@ -1180,9 +1180,11 @@ /* FIXME: this doesn't do anything right now */ static int us_bus_reset( Scsi_Cmnd *srb ) { - // struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + struct us_data *us = (struct us_data *)srb->host->hostdata[0]; US_DEBUGP("Bus reset requested\n"); + if (us->ip_wanted) + up(&(us->ip_waitq)); // us->transport_reset(us); return SUCCESS; } @@ -1364,12 +1366,9 @@ unlock_kernel(); - up(us->notify); + up(&(us->notify)); for(;;) { - siginfo_t info; - int unsigned long signr; - US_DEBUGP("*** thread sleeping.\n"); down(&(us->sleeper)); down(&(us->queue_exclusion)); @@ -1378,7 +1377,7 @@ /* take the command off the queue */ action = us->action; us->action = 0; - us->srb = us-> queue_srb; + us->srb = us->queue_srb; /* release the queue lock as fast as possible */ up(&(us->queue_exclusion)); @@ -1433,7 +1432,8 @@ us->proto_handler(us->srb, us); } - US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); + US_DEBUGP("scsi cmd done, result=0x%x\n", + us->srb->result); us->srb->scsi_done(us->srb); us->srb = NULL; break; @@ -1452,19 +1452,12 @@ } /* end switch on action */ - /* FIXME: we ignore TERM and KILL... is this right? */ - if (signal_pending(current)) { - /* sending SIGUSR1 makes us print out some info */ - spin_lock_irq(¤t->sigmask_lock); - signr = dequeue_signal(¤t->blocked, &info); - spin_unlock_irq(¤t->sigmask_lock); - } /* if (singal_pending(current)) */ + /* exit if we get a signal to exit */ + if (action == US_ACT_EXIT) + break; } /* for (;;) */ - // MOD_DEC_USE_COUNT; - printk("usb_stor_control_thread exiting\n"); - return 0; } @@ -1495,14 +1488,12 @@ /* FIXME: this isn't quite right... */ /* We make an exception for the shuttle E-USB */ - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - protocol = US_PR_CB; - subclass = US_SC_8070; /* an assumption */ - } else if (dev->descriptor.bDeviceClass != 0 || - altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE || - altsetting->bInterfaceSubClass < US_SC_MIN || - altsetting->bInterfaceSubClass > US_SC_MAX) { + if (!(dev->descriptor.idVendor == 0x04e6 && + dev->descriptor.idProduct == 0x0001) && + !(dev->descriptor.bDeviceClass == 0 && + altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE && + altsetting->bInterfaceSubClass >= US_SC_MIN && + altsetting->bInterfaceSubClass <= US_SC_MAX)) { /* if it's not a mass storage, we go no further */ return NULL; } @@ -1510,7 +1501,43 @@ /* At this point, we know we've got a live one */ US_DEBUGP("USB Mass Storage device detected\n"); + /* Determine subclass and protocol, or copy from the interface */ + /* FIXME: this isn't quite right */ + if (dev->descriptor.idVendor == 0x04e6 && + dev->descriptor.idProduct == 0x0001) { + protocol = US_PR_CB; + subclass = US_SC_8070; /* an assumption */ + } else { + subclass = altsetting->bInterfaceSubClass; + protocol = altsetting->bInterfaceProtocol; + } + + /* shuttle E-USB */ + /* FIXME: all we should need to do here is determine the protocol */ + if (dev->descriptor.idVendor == 0x04e6 && + dev->descriptor.idProduct == 0x0001) { + __u8 qstat[2]; + + result = usb_control_msg(ss->pusb_dev, + usb_rcvctrlpipe(dev,0), + 1, 0xC0, + 0, ss->ifnum, + qstat, 2, HZ*5); + US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]); + init_MUTEX_LOCKED(&(ss->ip_waitq)); + ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); + result = usb_request_irq(ss->pusb_dev, ss->irqpipe, + CBI_irq, 255, (void *)ss, + &ss->irq_handle); + if (result < 0) + return NULL; + + /* FIXME: what is this?? */ + down(&(ss->ip_waitq)); + } + /* + * Find the endpoints we need * We are expecting a minimum of 2 endpoints - in and out (bulk). * An optional interrupt is OK (necessary for CBI protocol). * We will ignore any others. @@ -1519,6 +1546,7 @@ /* is it an BULK endpoint? */ if ((altsetting->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { + /* BULK in or out? */ if (altsetting->endpoint[i].bEndpointAddress & USB_DIR_IN) ep_in = altsetting->endpoint[i].bEndpointAddress & @@ -1542,36 +1570,14 @@ result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); US_DEBUGP("Result from usb_set_interface is %d\n", result); if (result == -EPIPE) { + US_DEBUGP("-- clearing stall on control interface\n"); usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); } else if (result != 0) { /* it's not a stall, but another error -- time to bail */ + US_DEBUGP("-- unknown error. rejecting device\n"); return NULL; } - /* shuttle E-USB */ - /* FIXME: all we should need to do here is determine the protocol */ - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - __u8 qstat[2]; - - result = usb_control_msg(ss->pusb_dev, - usb_rcvctrlpipe(dev,0), - 1, 0xC0, - 0, ss->ifnum, - qstat, 2, HZ*5); - US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]); - init_MUTEX_LOCKED(&(ss->ip_waitq)); - ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); - result = usb_request_irq(ss->pusb_dev, ss->irqpipe, - CBI_irq, 255, (void *)ss, - &ss->irq_handle); - if (result < 0) - return NULL; - - /* FIXME: what is this?? */ - down(&(ss->ip_waitq)); - } - /* Do some basic sanity checks, and bail if we find a problem */ if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Problems with device\n"); @@ -1638,8 +1644,8 @@ US_DEBUGP("Allocating IRQ for CBI transport\n"); ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); result = usb_request_irq(ss->pusb_dev, ss->irqpipe, - CBI_irq, 255, - (void *)ss, &ss->irq_handle); + CBI_irq, 255, (void *)ss, + &(ss->irq_handle)); US_DEBUGP("usb_request_irq returned %d\n", result); } } else { @@ -1656,23 +1662,12 @@ /* Initialize the mutexes only when the struct is new */ init_MUTEX_LOCKED(&(ss->sleeper)); + init_MUTEX_LOCKED(&(ss->notify)); init_MUTEX(&(ss->queue_exclusion)); - /* - * If we've allready determined the subclass and protocol, - * use that. Otherwise, use the interface ones. This - * allows us to support devices which are compliant but - * don't announce it. Note that this information is - * maintained in the us_data struct so we only have to do - * this for new devices. - */ - if (subclass) { - ss->subclass = subclass; - ss->protocol = protocol; - } else { - ss->subclass = altsetting->bInterfaceSubClass; - ss->protocol = altsetting->bInterfaceProtocol; - } + /* copy over the subclass and protocol data */ + ss->subclass = subclass; + ss->protocol = protocol; /* copy over the endpoint data */ ss->ep_in = ep_in; @@ -1762,9 +1757,9 @@ US_DEBUGP("Allocating IRQ for CBI transport\n"); ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); result = usb_request_irq(ss->pusb_dev, ss->irqpipe, - CBI_irq, 255, - (void *)ss, &ss->irq_handle); - US_DEBUGP("usb_request_irq returned %d", result); + CBI_irq, 255, (void *)ss, + &(ss->irq_handle)); + US_DEBUGP("usb_request_irq returned %d\n", result); } /* @@ -1786,23 +1781,18 @@ (struct us_data *)ss->htmplt.proc_dir = ss; /* start up our thread */ - { - DECLARE_MUTEX_LOCKED(sem); - - ss->notify = &sem; - ss->pid = kernel_thread(usb_stor_control_thread, ss, - CLONE_FS | CLONE_FILES | - CLONE_SIGHAND); - if (ss->pid < 0) { - printk(KERN_WARNING USB_STORAGE - "Unable to start control thread\n"); - kfree(ss); - return NULL; - } - - /* wait for it to start */ - down(&sem); + ss->pid = kernel_thread(usb_stor_control_thread, ss, + CLONE_FS | CLONE_FILES | + CLONE_SIGHAND); + if (ss->pid < 0) { + printk(KERN_WARNING USB_STORAGE + "Unable to start control thread\n"); + kfree(ss); + return NULL; } + + /* wait for it to start */ + down(&(ss->notify)); /* now register - our detect function will be called */ ss->htmplt.module = &__this_module; @@ -1829,18 +1819,26 @@ static void storage_disconnect(struct usb_device *dev, void *ptr) { struct us_data *ss = ptr; + int result; - if (!ss) + US_DEBUGP("storage_disconnect() called\n"); + + /* this is the odd case -- we disconnected but weren't using it */ + if (!ss) { + US_DEBUGP("-- device was not in use\n"); return; - - /* FIXME: we need mututal exclusion and resource freeing here */ + } /* release the IRQ, if we have one */ if (ss->irq_handle) { - usb_release_irq(ss->pusb_dev, ss->irq_handle, ss->irqpipe); + US_DEBUGP("-- releasing irq handle\n"); + result = usb_release_irq(ss->pusb_dev, ss->irq_handle, + ss->irqpipe); + US_DEBUGP("-- usb_release_irq() returned %d\n", result); ss->irq_handle = NULL; } + /* mark the device as gone */ ss->pusb_dev = NULL; } @@ -1851,11 +1849,16 @@ int __init usb_stor_init(void) { + /* + * Check to see if the host template is a different size from + * what we're expected -- people have updated this in the past + * and forgotten about this driver. + */ if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) { - printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ; - printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n", + printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE bad\n"); + printk(KERN_ERR + "usb-storage: expected %d bytes, got %d bytes\n", SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ; - return -1 ; } @@ -1863,6 +1866,7 @@ if (usb_register(&storage_driver) < 0) return -1; + /* we're all set */ printk(KERN_INFO "USB Mass Storage support registered.\n"); return 0; } @@ -1870,17 +1874,35 @@ void __exit usb_stor_exit(void) { static struct us_data *ptr; - + static struct us_data *next; + unsigned long flags; + + /* + * deregister the driver -- this eliminates races with probes and + * disconnects + */ + usb_deregister(&storage_driver) ; + + /* lock access to the data structures */ + spin_lock_irqsave(&us_list_spinlock, flags); + /* unregister all the virtual hosts */ for (ptr = us_list; ptr != NULL; ptr = ptr->next) - scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt)); - - /* free up the data structures */ - + scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt)); + /* kill the threads */ + /* FIXME: we can do this by sending them a signal to die */ - /* deregister the driver */ - usb_deregister(&storage_driver) ; + /* free up the data structures */ + /* FIXME: we need to eliminate the host structure also */ + while (ptr) { + next = ptr->next; + kfree(ptr); + ptr = next; + } + + /* unlock the data structures */ + spin_unlock_irqrestore(&us_list_spinlock, flags); } module_init(usb_stor_init) ; diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.3.99-pre2/linux/drivers/usb/usb-uhci.c Sun Mar 19 18:35:31 2000 +++ linux/drivers/usb/usb-uhci.c Thu Mar 23 14:59:56 2000 @@ -1002,8 +1002,11 @@ urb_priv = urb->hcpriv; switch (usb_pipetype (urb->pipe)) { - case PIPE_ISOCHRONOUS: + case PIPE_INTERRUPT: + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + + case PIPE_ISOCHRONOUS: uhci_clean_iso_step1(s, urb_priv); uhci_wait_ms(1); uhci_clean_iso_step2(s, urb_priv); @@ -1131,8 +1134,10 @@ urb_priv = (urb_priv_t*)urb->hcpriv; switch (usb_pipetype (urb->pipe)) { - case PIPE_ISOCHRONOUS: case PIPE_INTERRUPT: + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + + case PIPE_ISOCHRONOUS: uhci_clean_iso_step1 (s, urb_priv); break; @@ -1617,8 +1622,8 @@ 0x00, /* __u16 bcdDevice; */ 0x00, 0x00, /* __u8 iManufacturer; */ - 0x00, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ 0x01 /* __u8 bNumConfigurations; */ }; @@ -1915,8 +1920,14 @@ len = min (leni, min (sizeof (root_hub_config_des), wLength)); memcpy (data, root_hub_config_des, len); OK (len); - case (0x03): /*string descriptors */ - stat = -EPIPE; + case (0x03): /* string descriptors */ + len = usb_root_hub_string (wValue & 0xff, + uhci->io_addr, "UHCI", + data, wLength); + if (len > 0) { + OK (min (leni, len)); + } else + stat = -EPIPE; } break; @@ -2597,6 +2608,15 @@ uhci_t *s; struct usb_bus *bus; struct pm_dev *pmdev; + char buf[8], *bufp = buf; + +#ifndef __sparc__ + sprintf(buf, "%d", irq); +#else + bufp = __irq_itoa(irq); +#endif + printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n", + io_addr, bufp); s = kmalloc (sizeof (uhci_t), GFP_KERNEL); if (!s) diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.99-pre2/linux/drivers/usb/usb.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/usb.c Thu Mar 23 14:59:08 2000 @@ -1184,6 +1184,54 @@ dev->actconfig = NULL; } +/* for returning string descriptors in UTF-16LE */ +static int ascii2utf (char *ascii, __u8 *utf, int utfmax) +{ + int retval; + + for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) { + *utf++ = *ascii++ & 0x7f; + *utf++ = 0; + } + return retval; +} + +/* + * root_hub_string is used by each host controller's root hub code, + * so that they're identified consistently throughout the system. + */ +int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) +{ + char buf [20]; + + // assert (len > (2 * (sizeof (buf) + 1))); + // assert (strlen (type) ~== 4); + + // language ids + if (id == 0) { + *data++ = 4; *data++ = 3; /* 4 bytes data */ + *data++ = 0; *data++ = 0; /* some language id */ + return 4; + + // serial number + } else if (id == 1) { + sprintf (buf, "%x", serial); + + // product description + } else if (id == 2) { + sprintf (buf, "USB %s Root Hub", type); + + // id 3 == vendor description + + // unsupported IDs --> "stall" + } else + return 0; + + data [0] = 2 + ascii2utf (buf, data + 2, len - 2); + data [1] = 3; + return data [0]; +} + /* * __usb_get_extra_descriptor() finds a descriptor of specific type in the * extra field of the interface and endpoint descriptor structs. @@ -1824,6 +1872,7 @@ EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_init_root_hub); +EXPORT_SYMBOL(usb_root_hub_string); EXPORT_SYMBOL(usb_new_device); EXPORT_SYMBOL(usb_connect); EXPORT_SYMBOL(usb_disconnect); diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/wacom.c linux/drivers/usb/wacom.c --- v2.3.99-pre2/linux/drivers/usb/wacom.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/usb/wacom.c Sun Mar 19 18:29:40 2000 @@ -1,5 +1,5 @@ /* - * wacom.c Version 0.4 + * wacom.c Version 0.5 * * Copyright (c) 2000 Vojtech Pavlik * Copyright (c) 2000 Andreas Bach Aaen @@ -14,8 +14,10 @@ * v0.1 (vp) - Initial release * v0.2 (aba) - Support for all buttons / combinations * v0.3 (vp) - Support for Intuos added - * v0.4 (sm) - Support for more Intuos models, menustrip, - * relative mode, proximity. + * v0.4 (sm) - Support for more Intuos models, menustrip + * relative mode, proximity. + * v0.5 (vp) - Big cleanup, nifty features removed, + * they belong in userspace */ /* @@ -50,16 +52,14 @@ /* * Wacom Graphire packet: * - * The input report: - * * byte 0: report ID (2) - * byte 1: bit7 mouse/pen/rubber near - * bit5-6 0 - pen, 1 - rubber, 2 - mouse - * bit4 1 ? - * bit3 0 ? - * bit2 mouse middle button / pen button2 - * bit1 mouse right button / pen button1 - * bit0 mouse left button / pen tip / rubber + * byte 1: bit7 pointer in range + * bit5-6 pointer type 0 - pen, 1 - rubber, 2 - mouse + * bit4 1 ? + * bit3 0 ? + * bit2 mouse middle button / pen button2 + * bit1 mouse right button / pen button1 + * bit0 mouse left button / touch * byte 2: X low bits * byte 3: X high bits * byte 4: Y low bits @@ -69,115 +69,58 @@ * * There are also two single-byte feature reports (2 and 3). * - * Resolution: - * X: 0 - 10206 - * Y: 0 - 7422 - * - * (0,0) is upper left corner - * - * Wacom Intuos Status packet: + * Wacom Intuos status packet: * - * byte 0: report ID (2) - * byte 1: bit7 1 (Sync Byte) - * bit6 Pointer Near - * bit5 0 - first proximity report - * bit4 0 ? - * bit3 0 ? - * bit2 pen button2 - * bit1 pen button1 - * bit0 0 ? - * byte 2: X high bits - * byte 3: X low bits - * byte 4: Y high bits - * byte 5: Y low bits - * byte 6: bits 0-7: pressure (bits 2-9) - * byte 7: bits 6-7: pressure (bits 0-1) - * byte 7: bits 0-5: X tilt (bits 1-6) - * byte 8: bit 7: X tilt (bit 0) - * byte 8: bits 0-6: Y tilt (bits 0-6) - * byte 9: bits 4-7: Proximity + * byte 0: report ID (2) + * byte 1: bit7 1 - sync bit + * bit6 pointer in range + * bit5 pointer type report + * bit4 0 ? + * bit3 0 ? + * bit2 pen button2 + * bit1 pen button1 + * bit0 0 ? + * byte 2: X high bits + * byte 3: X low bits + * byte 4: Y high bits + * byte 5: Y low bits + * byte 6: bits 0-7: pressure (bits 2-9) + * byte 7: bits 6-7: pressure (bits 0-1) + * byte 7: bits 0-5: X tilt (bits 1-6) + * byte 8: bit 7: X tilt (bit 0) + * byte 8: bits 0-6: Y tilt (bits 0-6) + * byte 9: bits 4-7: distance */ -#define USB_VENDOR_ID_WACOM 0x056a -#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 -#define USB_DEVICE_ID_WACOM_INTUOS45 0x0020 /* Guess */ -#define USB_DEVICE_ID_WACOM_INTUOS68 0x0021 -#define USB_DEVICE_ID_WACOM_INTUOS912 0x0022 /* Guess */ -#define USB_DEVICE_ID_WACOM_INTUOS1212 0x0023 -#define USB_DEVICE_ID_WACOM_INTUOS1218 0x0024 /* Guess */ - -#define USB_TOOL_ID_WACOM_PEN 0x0022 -#define USB_TOOL_ID_WACOM_ERASER 0x00fa -#define USB_TOOL_ID_WACOM_STROKE_PEN 0x0032 -#define USB_TOOL_ID_WACOM_INKING_PEN 0x0012 -#define USB_TOOL_ID_WACOM_AIRBRUSH 0x0112 -#define USB_TOOL_ID_WACOM_MOUSE4D 0x0094 -#define USB_TOOL_ID_WACOM_LENS_CURSOR 0x0096 - -#define INTUOS_PEN_MODE_ABS 0x00 -#define INTUOS_PEN_MODE_REL 0x01 -#define INTUOS_PEN_MODE_QUICKPOINT 0x02 - -#define INTUOS_PRESSURE_MODE_SOFT 0x00 -#define INTUOS_PRESSURE_MODE_MED 0x01 -#define INTUOS_PRESSURE_MODE_FIRM 0x02 - -#define INTUOS_MENUSTRIP_Y_ZONE 1400 -#define INTUOS_MENUSTRIP_BTN_YMIN 270 -#define INTUOS_MENUSTRIP_BTN_YMAX 1070 -#define INTUOS_MENUSTRIP_F1_XMIN 40 -#define INTUOS_MENUSTRIP_F7_XMIN 8340 -#define INTUOS_MENUSTRIP_F12_XMIN 15300 +#define USB_VENDOR_ID_WACOM 0x056a -#define INTUOS_MENUSTRIP_BTN_WIDTH 1300 - -#define INTUOS_MENUSTRIP_F7_IX_OFFSET 6 /* offset into wacom_fkeys */ -#define INTUOS_MENUSTRIP_F12_IX_OFFSET 11 +struct wacom_features { + char *name; + int idProduct; + int pktlen; + int x_max; + int y_max; + int pressure_max; + int distance_max; + void (*irq)(struct urb *urb); + unsigned long evbit; + unsigned long relbit; + unsigned long absbit; + unsigned long btnbit; + unsigned long digibit; +}; struct wacom { - signed char data[10]; + signed char data[10]; struct input_dev dev; struct urb irq; - - int last_x, last_y; - unsigned int tool, device; - unsigned int ymax, menustrip_touch; - unsigned int pen_mode; - unsigned int pressure_mode; + struct wacom_features *features; + int tool; }; -static int wacom_fkeys[16] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4, - KEY_F5, KEY_F6, KEY_F7, KEY_F8, - KEY_F9, KEY_F10, KEY_F11, KEY_F12, - KEY_F13, KEY_F14, KEY_F15, KEY_F16}; - -#define INTUOS_EXTENTS_MAX_X 0x00 -#define INTUOS_EXTENTS_MAX_Y 0x01 -#define INTUOS_EXTENTS_HAS_F7 0x02 -#define INTUOS_EXTENTS_HAS_F12 0x03 -#define INTUOS_EXTENTS_PEN_MODE 0x04 -#define INTUOS_EXTENTS_HAS_QUICKPOINT 0x05 -#define INTUOS_EXTENTS_HAS_PRESSURE_MODE 0x06 -#define INTUOS_EXTENTS_PRESSURE_MODE 0x07 - -#define WACOM_TRUE 1 -#define WACOM_FALSE 0 - -static int intuos_extents[5][8] = { - { 12700, 10360, WACOM_FALSE, WACOM_FALSE, 8340, WACOM_FALSE, WACOM_FALSE, 0}, /* Intuos 4x5 */ - { 20320, 15040, WACOM_TRUE, WACOM_FALSE, 15300, WACOM_FALSE, WACOM_TRUE, 18360}, /* Intuos 6x8 */ - { 30480, 23060, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 9x12 */ - { 30480, 30480, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 12x12 */ - { 47720, 30480, WACOM_TRUE, WACOM_TRUE, 29260, WACOM_TRUE, WACOM_TRUE, 33620}}; /* Intuos 12x18 */ - -static char intuos_names[5][12] = { - {"Intuos 4x5 "}, {"Intuos 6x8 "}, - {"Intuos 9x12 "}, {"Intuos 12x12"}, - {"Intuos 12x18"}}; - static void wacom_graphire_irq(struct urb *urb) { - struct wacom *wacom = urb->context; + struct wacom *wacom = urb->context; unsigned char *data = wacom->data; struct input_dev *dev = &wacom->dev; @@ -186,285 +129,135 @@ if (data[0] != 2) dbg("received unknown report #%d", data[0]); - if ( data[1] & 0x80 ) { - input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8)); - input_report_abs(dev, ABS_Y, 7422 - (data[4] | ((__u32)data[5] << 8))); + if ( data[1] & 0x80 ) { + input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8)); + input_report_abs(dev, ABS_Y, data[4] | ((__u32)data[5] << 8)); } switch ((data[1] >> 5) & 3) { - case 0: /* Pen */ - input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80); - input_report_btn(dev, BTN_TOUCH, data[1] & 0x01); - input_report_btn(dev, BTN_STYLUS, data[1] & 0x02); - input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04); - input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8)); - break; - - case 1: /* Rubber */ - input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80); - input_report_btn(dev, BTN_TOUCH, data[1] & 0x01); - input_report_btn(dev, BTN_STYLUS, data[1] & 0x02); - input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04); - input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8)); - break; - - case 2: /* Mouse */ - input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24); - input_report_btn(dev, BTN_LEFT, data[1] & 0x01); - input_report_btn(dev, BTN_RIGHT, data[1] & 0x02); - input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04); - input_report_abs(dev, ABS_DISTANCE, data[7]); - input_report_rel(dev, REL_WHEEL, (signed char) data[6]); - break; - } -} + case 0: /* Pen */ + input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80); + break; -static void intuos_menustrip( unsigned int x, unsigned int y, struct wacom *wacom ) -{ - struct input_dev *dev = &wacom->dev; - unsigned int local_x = x; - unsigned int local_y = y - ( wacom->ymax - INTUOS_MENUSTRIP_Y_ZONE ); - unsigned int fkey_index ; - - /* Ensure we are in the vertical strip for the buttons */ - if ( (local_y > INTUOS_MENUSTRIP_BTN_YMIN) && (local_y < INTUOS_MENUSTRIP_BTN_YMAX) ) { - - /* Handle Pressure Mode */ - if ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_PRESSURE_MODE] ) { - int pressure_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PRESSURE_MODE]) - / INTUOS_MENUSTRIP_BTN_WIDTH ); - if ( ( pressure_mode >= INTUOS_PRESSURE_MODE_SOFT ) && - ( pressure_mode <= INTUOS_PRESSURE_MODE_FIRM ) ) { - wacom->pressure_mode = pressure_mode; - return; - } - } - - /* Handle Pen Mode */ - { - int pen_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PEN_MODE]) - / INTUOS_MENUSTRIP_BTN_WIDTH ); - if ( ( pen_mode == INTUOS_PEN_MODE_ABS ) || - ( pen_mode == INTUOS_PEN_MODE_REL ) || - ( ( pen_mode == INTUOS_PEN_MODE_QUICKPOINT ) && - ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_QUICKPOINT] ) ) ) { - wacom->pen_mode = pen_mode; - return; - } - } - - /* Handle Function Keys */ - if ( local_x > INTUOS_MENUSTRIP_F12_XMIN ) { - fkey_index = INTUOS_MENUSTRIP_F12_IX_OFFSET - + ( (local_x - INTUOS_MENUSTRIP_F12_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH ); - fkey_index = ( fkey_index > 16 ) ? 16 : fkey_index; /* Ensure in range */ - } - else if ( local_x > INTUOS_MENUSTRIP_F7_XMIN ) { - fkey_index = INTUOS_MENUSTRIP_F7_IX_OFFSET - + ( (local_x - INTUOS_MENUSTRIP_F7_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH ); - fkey_index = ( fkey_index > 11 ) ? 11 : fkey_index; - } - else { - fkey_index = ( (local_x - INTUOS_MENUSTRIP_F1_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH ); - fkey_index = ( fkey_index > 6 ) ? 6 : fkey_index; - } - input_report_key(dev, wacom_fkeys[fkey_index], 1); - input_report_key(dev, wacom_fkeys[fkey_index], 0); + case 1: /* Rubber */ + input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80); + break; - return; + case 2: /* Mouse */ + input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24); + input_report_btn(dev, BTN_LEFT, data[1] & 0x01); + input_report_btn(dev, BTN_RIGHT, data[1] & 0x02); + input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04); + input_report_abs(dev, ABS_DISTANCE, data[7]); + input_report_rel(dev, REL_WHEEL, (signed char) data[6]); + return; } + + input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8)); + + input_report_btn(dev, BTN_TOUCH, data[1] & 0x01); + input_report_btn(dev, BTN_STYLUS, data[1] & 0x02); + input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04); } - + static void wacom_intuos_irq(struct urb *urb) { - struct wacom *wacom = urb->context; + struct wacom *wacom = urb->context; unsigned char *data = wacom->data; struct input_dev *dev = &wacom->dev; unsigned int t; - int x, y; if (urb->status) return; if (data[0] != 2) dbg("received unknown report #%d", data[0]); - if ( ((data[1] >> 5) & 0x3) == 0x2 ) /* First record, feature report */ - { - wacom->tool = (((char)data[2] << 4) | (char)data[3] >> 4) & 0xff ; - /* Report tool type */ - switch ( wacom->tool ) { - case USB_TOOL_ID_WACOM_PEN: - input_report_btn(dev, BTN_TOOL_PEN, 1); - break; - case USB_TOOL_ID_WACOM_ERASER: - input_report_btn(dev, BTN_TOOL_RUBBER, 1); - break; - case USB_TOOL_ID_WACOM_STROKE_PEN: - input_report_btn(dev, BTN_TOOL_BRUSH, 1); - break; - case USB_TOOL_ID_WACOM_INKING_PEN: - input_report_btn(dev, BTN_TOOL_PENCIL, 1); - break; - case USB_TOOL_ID_WACOM_AIRBRUSH: - input_report_btn(dev, BTN_TOOL_AIRBRUSH, 1); - break; - case USB_TOOL_ID_WACOM_MOUSE4D: - case USB_TOOL_ID_WACOM_LENS_CURSOR: - input_report_btn(dev, BTN_TOOL_MOUSE, 1); - break; - default: - break; - } - return; - } + if (((data[1] >> 5) & 0x3) == 0x2) { /* Enter report */ - if ( ( data[1] | data[2] | data[3] | data[4] | data[5] | data[6] - | data[7] | data[8] | data[9] ) == 0x80 ) { /* exit report */ - switch ( wacom->tool ) { - case USB_TOOL_ID_WACOM_PEN: - input_report_btn(dev, BTN_TOOL_PEN, 0); - break; - case USB_TOOL_ID_WACOM_ERASER: - input_report_btn(dev, BTN_TOOL_RUBBER, 0); - break; - case USB_TOOL_ID_WACOM_STROKE_PEN: - input_report_btn(dev, BTN_TOOL_BRUSH, 0); - break; - case USB_TOOL_ID_WACOM_INKING_PEN: - input_report_btn(dev, BTN_TOOL_PENCIL, 0); - break; - case USB_TOOL_ID_WACOM_AIRBRUSH: - input_report_btn(dev, BTN_TOOL_AIRBRUSH, 0); - break; - case USB_TOOL_ID_WACOM_MOUSE4D: - case USB_TOOL_ID_WACOM_LENS_CURSOR: - input_report_btn(dev, BTN_TOOL_MOUSE, 0); - break; - default: - break; + switch (((__u32)data[2] << 4) | (data[3] >> 4)) { + case 0x012: wacom->tool = BTN_TOOL_PENCIL; break; /* Inking pen */ + case 0x022: wacom->tool = BTN_TOOL_PEN; break; /* Pen */ + case 0x032: wacom->tool = BTN_TOOL_BRUSH; break; /* Stroke pen */ + case 0x094: wacom->tool = BTN_TOOL_MOUSE; break; /* Mouse 4D */ + case 0x096: wacom->tool = BTN_TOOL_LENS; break; /* Lens cursor */ + case 0x0fa: wacom->tool = BTN_TOOL_RUBBER; break; /* Eraser */ + case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH; break; /* Airbrush */ + default: wacom->tool = BTN_TOOL_PEN; break; /* Unknown tool */ } + input_report_btn(dev, wacom->tool, 1); return; } - x = (((unsigned int) data[2]) << 8) | data[3] ; - y = wacom->dev.absmax[ABS_Y] - ((((unsigned int) data[4]) << 8) | data[5]); - - t = (((unsigned int) data[6]) << 2) | ((data[7] & 0xC0) >> 6); - - /* Handle touch near menustrip */ - if ( y > ( wacom->dev.absmax[ABS_Y] - INTUOS_MENUSTRIP_Y_ZONE ) ) { - if ( t > 10 ) /* Touch */ - wacom->menustrip_touch = 1; - if ( (wacom->menustrip_touch) && (t <= 10) ) { /* Pen Up */ - intuos_menustrip( x, y, wacom ); - wacom->menustrip_touch = 0; - } + if ((data[1] | data[2] | data[3] | data[4] | data[5] | + data[6] | data[7] | data[8] | data[9]) == 0x80) { /* Exit report */ + input_report_btn(dev, wacom->tool, 0); return; } - else - wacom->menustrip_touch = 0; - switch ( wacom->pen_mode ) { - case INTUOS_PEN_MODE_ABS: - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); - break; - case INTUOS_PEN_MODE_REL: - input_report_rel(dev, REL_X, ( x - wacom->last_x) / 8 ); - input_report_rel(dev, REL_Y, - ( y - wacom->last_y) / 8 ); - break; - default: break; - } - - wacom->last_x = x; - wacom->last_y = y; - - input_report_btn(dev, BTN_STYLUS, data[1] & 0x02); - input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04); + input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]); + input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]); + input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); + input_report_abs(dev, ABS_DISTANCE, data[9] >> 4); + input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7)); + input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f); + input_report_btn(dev, BTN_STYLUS, data[1] & 2); + input_report_btn(dev, BTN_STYLUS2, data[1] & 4); input_report_btn(dev, BTN_TOUCH, t > 10); - input_report_abs(dev, ABS_PRESSURE, t); - - input_report_abs(dev, ABS_DISTANCE, ( data[9] & 0xf0 ) >> 4 ); +} - input_report_abs(dev, ABS_TILT_X, ((((unsigned int) data[7]) & 0x3f) << 1) | ((data[8] & 0x80) >> 7)); - input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f); +#define WACOM_INTUOS_TOOLS (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS)) -} +struct wacom_features wacom_features[] = { + { "Graphire", 0x10, 8, 10206, 7422, 511, 32, wacom_graphire_irq, + BIT(EV_REL), 0, BIT(REL_WHEEL), BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE), 0 }, + { "Intuos 4x5", 0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq, + 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, + { "Intuos 6x8", 0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq, + 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, + { "Intuos 9x12", 0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq, + 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, + { "Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq, + 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, + { "Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq, + 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS }, + { NULL , 0 } +}; static void *wacom_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; - char *name; + int i; - if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM || - (dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_GRAPHIRE && - dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS45 && - dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS68 && - dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS912 && - dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1212 && - dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1218)) - return NULL; + if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM) return NULL; + for (i = 0; wacom_features[i].idProduct && wacom_features[i].idProduct != dev->descriptor.idProduct; i++); + if (!wacom_features[i].idProduct) return NULL; endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL; memset(wacom, 0, sizeof(struct wacom)); - if ( dev->descriptor.idProduct == USB_DEVICE_ID_WACOM_GRAPHIRE ) { - wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); - wacom->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); - wacom->dev.relbit[0] |= BIT(REL_WHEEL); - wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE); - - wacom->dev.absmax[ABS_X] = 10206; - wacom->dev.absmax[ABS_Y] = 7422; - wacom->dev.absmax[ABS_PRESSURE] = 511; - wacom->dev.absmax[ABS_DISTANCE] = 32; + wacom->features = wacom_features + i; - FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - wacom->data, 8, wacom_graphire_irq, wacom, endpoint->bInterval); + wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | wacom->features->evbit; + wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | wacom->features->absbit; + wacom->dev.relbit[0] |= wacom->features->relbit; + wacom->dev.keybit[LONG(BTN_LEFT)] |= wacom->features->btnbit; + wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | + BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | wacom->features->digibit; + + wacom->dev.absmax[ABS_X] = wacom->features->x_max; + wacom->dev.absmax[ABS_Y] = wacom->features->y_max; + wacom->dev.absmax[ABS_PRESSURE] = wacom->features->pressure_max; + wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max; + wacom->dev.absmax[ABS_TILT_X] = 127; + wacom->dev.absmax[ABS_TILT_Y] = 127; - name = "Graphire"; - } - else { /* Intuos */ - - wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); - wacom->dev.keybit[LONG(KEY_F1)] |= BIT(KEY_F1) | BIT(KEY_F2) | BIT(KEY_F3) | BIT(KEY_F4) | BIT(KEY_F5); - wacom->dev.keybit[LONG(KEY_F6)] |= BIT(KEY_F6) | BIT(KEY_F7) | BIT(KEY_F8); - wacom->dev.keybit[LONG(KEY_F9)] |= BIT(KEY_F9) | BIT(KEY_F10) | BIT(KEY_F11) | BIT(KEY_F12); - wacom->dev.keybit[LONG(KEY_F13)] |= BIT(KEY_F13) | BIT(KEY_F14) | BIT(KEY_F15) | BIT(KEY_F16); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_BRUSH); - wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_MOUSE); - wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE); - wacom->dev.absbit[0] |= BIT(ABS_TILT_X) | BIT(ABS_TILT_Y); - wacom->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y); - - wacom->dev.absmax[ABS_PRESSURE] = 1023; - wacom->dev.absmax[ABS_DISTANCE] = 15; - wacom->dev.absmax[ABS_TILT_X] = 127; - wacom->dev.absmax[ABS_TILT_Y] = 127; - - wacom->device = dev->descriptor.idProduct - USB_DEVICE_ID_WACOM_INTUOS45; - - wacom->dev.absmax[ABS_X] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_X]; - wacom->dev.absmax[ABS_Y] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y]; - - wacom->ymax = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y]; - wacom->pen_mode = INTUOS_PEN_MODE_ABS; - wacom->pressure_mode = INTUOS_PRESSURE_MODE_SOFT; - - name = intuos_names[wacom->device]; - - FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - wacom->data, 10, wacom_intuos_irq, wacom, endpoint->bInterval); - - } + FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), + wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval); if (usb_submit_urb(&wacom->irq)) { kfree(wacom); @@ -473,7 +266,7 @@ input_register_device(&wacom->dev); - printk(KERN_INFO "input%d: Wacom %s\n", wacom->dev.number, name); + printk(KERN_INFO "input%d: Wacom %s on usb%d\n", wacom->dev.number, wacom->features->name, dev->devnum); return wacom; } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.99-pre2/linux/drivers/video/Makefile Fri Mar 10 16:40:45 2000 +++ linux/drivers/video/Makefile Thu Mar 23 10:07:42 2000 @@ -16,7 +16,8 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o fbcon-afb.o fbcon-ilbm.o \ +export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \ + fbcon-afb.o fbcon-ilbm.o \ fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ @@ -46,6 +47,7 @@ obj-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o fbmon.o +obj-$(CONFIG_FB_COMPAT_XPMAC) += macmodes.o obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_AMIGA) += amifb.o @@ -64,9 +66,9 @@ obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o -obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o +obj-$(CONFIG_FB_MAC) += macfb.o obj-$(CONFIG_FB_HP300) += hpfb.o -obj-$(CONFIG_FB_OF) += offb.o macmodes.o +obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_CLGEN) += clgenfb.o fbgen.o diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/video/amifb.c linux/drivers/video/amifb.c --- v2.3.99-pre2/linux/drivers/video/amifb.c Fri Mar 10 16:40:45 2000 +++ linux/drivers/video/amifb.c Thu Mar 23 10:07:42 2000 @@ -1765,37 +1765,11 @@ fb_info.flags = FBINFO_FLAG_DEFAULT; memset(&var, 0, sizeof(var)); -#ifdef MODULE - var.xres = ami_modedb[defmode].xres; - var.yres = ami_modedb[defmode].yres; - var.xres_virtual = ami_modedb[defmode].xres; - var.yres_virtual = ami_modedb[defmode].yres; - var.xoffset = 0; - var.yoffset = 0; - var.bits_per_pixel = 4; - var.activate |= FB_ACTIVATE_TEST; - var.pixclock = ami_modedb[defmode].pixclock; - var.left_margin = ami_modedb[defmode].left_margin; - var.right_margin = ami_modedb[defmode].right_margin; - var.upper_margin = ami_modedb[defmode].upper_margin; - var.lower_margin = ami_modedb[defmode].lower_margin; - var.hsync_len = ami_modedb[defmode].hsync_len; - var.vsync_len = ami_modedb[defmode].vsync_len; - var.sync = ami_modedb[defmode].sync; - var.vmode = ami_modedb[defmode].vmode; - err = fb_info.fbops->fb_set_var(&var, -1, &fb_info); - var.activate &= ~FB_ACTIVATE_TEST; - if (err) { - err = -EINVAL; - goto amifb_error; - } -#else if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { err = -EINVAL; goto amifb_error; } -#endif round_down_bpp = 0; chipptr = chipalloc(videomemorysize+ diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/video/cgthreefb.c linux/drivers/video/cgthreefb.c --- v2.3.99-pre2/linux/drivers/video/cgthreefb.c Wed Dec 29 13:13:20 1999 +++ linux/drivers/video/cgthreefb.c Tue Mar 21 23:38:25 2000 @@ -1,4 +1,4 @@ -/* $Id: cgthreefb.c,v 1.8 1999/11/19 09:57:08 davem Exp $ +/* $Id: cgthreefb.c,v 1.9 2000/03/19 04:20:44 anton Exp $ * cgthreefb.c: CGthree frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -114,9 +114,9 @@ u8 tmp; spin_lock_irqsave(&fb->lock, flags); - tmp = sbus_readl(&fb->s.cg3.regs->control); + tmp = sbus_readb(&fb->s.cg3.regs->control); tmp &= ~CG3_CR_ENABLE_VIDEO; - sbus_writel(tmp, &fb->s.cg3.regs->control); + sbus_writeb(tmp, &fb->s.cg3.regs->control); spin_unlock_irqrestore(&fb->lock, flags); } @@ -126,9 +126,9 @@ u8 tmp; spin_lock_irqsave(&fb->lock, flags); - tmp = sbus_readl(&fb->s.cg3.regs->control); + tmp = sbus_readb(&fb->s.cg3.regs->control); tmp |= CG3_CR_ENABLE_VIDEO; - sbus_writel(tmp, &fb->s.cg3.regs->control); + sbus_writeb(tmp, &fb->s.cg3.regs->control); spin_unlock_irqrestore(&fb->lock, flags); } diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/video/macmodes.c linux/drivers/video/macmodes.c --- v2.3.99-pre2/linux/drivers/video/macmodes.c Wed Aug 18 10:10:06 1999 +++ linux/drivers/video/macmodes.c Thu Mar 23 10:07:42 2000 @@ -3,15 +3,22 @@ * * Copyright (C) 1998 Geert Uytterhoeven * + * 2000 - Removal of OpenFirmware dependencies by: + * - Ani Joshi + * - Brad Douglas + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ -#include +#include #include #include +#include + +#include