diff -u --recursive --new-file v2.3.22/linux/CREDITS linux/CREDITS --- v2.3.22/linux/CREDITS Mon Oct 4 15:49:29 1999 +++ linux/CREDITS Wed Oct 20 22:13:20 1999 @@ -860,7 +860,7 @@ N: David Hinds E: dhinds@zen.stanford.edu -W: http://hyper.stanford.edu/~dhinds +W: http://tao.stanford.edu/~dhinds D: PCMCIA and CardBus stuff, PCMCIA-HOWTO, PCMCIA client drivers S: 2019 W. Middlefield Rd #1 S: Mountain View, CA 94043 @@ -907,14 +907,14 @@ S: United Kingdom N: Ron Holt -E: ron@caldera.com +E: ron@holt.org W: http://www.holt.org/ -P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A 40 E3 FB 71 D1 C8 0B 56 +W: http://www.ronholt.com/ D: Kernel development -D: Minor kernel modifications to support Wabi and Wine -S: Caldera, Inc. -S: 240 West Center Street -S: Orem, Utah 84059-1920 +D: Kernel LDT modifications to support Wabi and Wine +S: Holtron Internetics, Inc. +S: 998 East 900 South, Suite 26 +S: Provo, Utah 84606-5607 S: USA N: Rob W. W. Hooft @@ -1323,11 +1323,11 @@ S: Czech Republic N: Paul Mackerras -E: paulus@cs.anu.edu.au +E: paulus@linuxcare.com D: Linux port for PCI Power Macintosh -S: Dept. of Computer Science -S: Australian National University -S: Canberra ACT 0200 +S: Linuxcare, Inc. +S: 24 Marcus Clarke Street +S: Canberra ACT 2601 S: Australia N: Pat Mackinlay diff -u --recursive --new-file v2.3.22/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.22/linux/Documentation/Changes Fri Oct 15 15:25:13 1999 +++ linux/Documentation/Changes Wed Oct 20 21:33:12 1999 @@ -43,7 +43,7 @@ encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -- Kernel modutils 2.3.5 ; insmod -V +- Kernel modutils 2.3.6 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version - Binutils 2.8.1.0.23 ; ld -v - Linux libc5 C Library 5.4.46 ; ls -l /lib/libc* @@ -60,7 +60,7 @@ - NFS 2.2beta40 ; showmount --version - Bash 1.14.7 ; bash -version - Ncpfs 2.2.0 ; ncpmount -v -- Pcmcia-cs 3.0.7 ; cardmgr -V +- Pcmcia-cs 3.1.2 ; cardmgr -V - PPP 2.3.9 ; pppd --version - Util-linux 2.9i ; chsh -v @@ -567,8 +567,8 @@ Modules utilities ================= -The 2.3.5 release: -ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.5.tar.gz +The 2.3.6 release: +ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.6.tar.gz Procps utilities ================ @@ -684,8 +684,8 @@ Pcmcia-cs ========= -The 3.0.7 release: -ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.7.tar.gz +The 3.1.2 release: +ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.2.tar.gz Setserial ========= diff -u --recursive --new-file v2.3.22/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.22/linux/Documentation/Configure.help Fri Oct 15 15:25:13 1999 +++ linux/Documentation/Configure.help Wed Oct 20 21:33:12 1999 @@ -175,18 +175,25 @@ on the Alpha. The only time you would ever not say Y is to say M in order to debug the code. Say Y unless you know what you are doing. -Big memory support -CONFIG_BIGMEM - Linux can use up to 2 Gigabytes (= 2^31 bytes) of physical memory. - If you are compiling a kernel which will never run on a machine with - more than 1 Gigabyte, answer N here. Otherwise, say Y. - - The actual amount of physical memory should be specified 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://metalab.unc.edu/mdw/linux.html#howto .) +High Memory support +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). + + 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 + mapped by the kernel - ie. 3GB if there is 4GB RAM in the system, + 7GB if there is 8GB RAM in the system. + + If 4 Gigabytes physical RAM or less is used then answer "4GB" here. + + If more than 4 Gigabytes is used then answer "64GB" here. This + selection turns Intel PAE (Physical Address Extension) mode on. + PAE implements 3-level paging on IA32 processors. PAE is fully + supported by Linux, PAE mode is implemented on all recent Intel + processors (PPro and better). NOTE: The "64GB" kernel will not + boot CPUs that not support PAE! Normal PC floppy disk support CONFIG_BLK_DEV_FD @@ -578,12 +585,6 @@ If in doubt, say N. -Winbond SL82c105 support -CONFIG_BLK_DEV_SL82C105 - If you have a Winbond SL82c105 IDE controller, say Y here to enable - special configuration for this chip. This is common on various CHRP - motherboards, but could be used elsewhere. If in doubt, say Y. - Boot off-board chipsets first support CONFIG_BLK_DEV_OFFBOARD Normally, IDE controllers built into the motherboard (on-board @@ -621,82 +622,32 @@ It is normally safe to answer Y to this question unless your motherboard uses a VIA VP2 chipset, in which case you should say N. -Other IDE chipset support -CONFIG_IDE_CHIPSETS - Say Y here if you want to include enhanced support for various IDE - interface chipsets used on motherboards and add-on cards. You can - then pick your particular IDE chip from among the following options. - This enhanced support may be necessary for Linux to be able to - access the 3rd/4th drives in some systems. It may also enable - setting of higher speed I/O rates to improve system performance with - these chipsets. Most of these also require special kernel boot - parameters to actually turn on the support at runtime; you can find - a list of these in the file Documentation/ide.txt. - - People with SCSI-only systems can say N here. - -Generic 4 drives/port support -CONFIG_BLK_DEV_4DRIVES - Certain older chipsets, including the Tekram 690CD, use a single set - of I/O ports at 0x1f0 to control up to four drives, instead of the - customary two drives per port. Support for this can be enabled at - runtime using the "ide0=four" kernel boot parameter if you say Y - here. - -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 - files for more info. - -Holtek HT6560B support -CONFIG_BLK_DEV_HT6560B - 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 - more info. +AEC6210 chipset support +CONFIG_BLK_DEV_AEC6210 + This driver adds up to 4 more EIDE devices sharing a single + interrupt. This add-on card is a bootable PCI UDMA controller. In + order to get this card to initialize correctly in some cases, you + should say Y here, and preferably also to "Use DMA by default when + available". -PROMISE DC4030 support (EXPERIMENTAL) -CONFIG_BLK_DEV_PDC4030 - This driver provides support for the secondary IDE interface and - cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver - is known to incur timeouts/retries during heavy I/O to drives - 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. + Please read the comments at the top of drivers/block/aec6210.c -PS/2 ESDI hard disk support -CONFIG_BLK_DEV_PS2 - Say Y here if you have a PS/2 machine with a MCA bus and an ESDI - hard disk. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called ps2esdi.o. +ALI M15x3 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_ALI15X3 + This driver ensures (U)DMA support for ALI 1543 and 1543C, + 1535, 1535D onboard chipsets. It also tests for Simplex mode and + enables normal dual channel support. -Tekram TRM290 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_TRM290 - 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. + If you say Y here, you also need to say Y to "Use DMA by default + when available", above. -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/block/alim15x3.c -NS87415 support (EXPERIMENTAL) -CONFIG_BLK_DEV_NS87415 - This driver adds detection and support for the NS87415 chip - (used in SPARC64, among others). + If unsure, say N. - Please read the comments at the top of drivers/block/ns87415.c. +CMD646 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_CMD646 + Say Y here if you have an IDE controller which uses this chipset. CY82C693 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_CY82C693 @@ -706,36 +657,80 @@ If you say Y here, you need to say Y to "Use DMA by default when available" as well. -VIA82C586 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_VIA82C586 - Saying Y here adds initial timing settings for VIA (U)DMA onboard - IDE controllers that are ATA3 compliant. May work with ATA4 systems, - but not tested to date. To use some features of this chipset, you - will have to issue a kernel command line as described in the file - drivers/block/via82c586.c. Furthermore, if you also say Y to "/proc - filesystem support" and set DISPLAY_APOLLO_TIMINGS in via82c586.c, - you will be able to read information about the IDE controller from - the virtual file /proc/ide/via. +HPT34X chipset support +CONFIG_BLK_DEV_HPT34X + This driver adds up to 4 more EIDE devices sharing a single + interrupt. The HPT343 chipset in its current form is a non-bootable + controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX) + PCI UDMA controllers. This driver requires dynamic tuning of the + chipset during the ide-probe at boot time. It is reported to support + DVD II drives, by the manufacturer. - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. +HPT34X DMA support (EXPERIMENTAL) +CONFIG_BLK_DEV_HPT34X_DMA + you need to say Y to "Use DMA by default when available" if you say + Y here. + + Please read the comments at the top of drivers/block/hpt34x.c + +HPT366 chipset support +CONFIG_BLK_DEV_HPT366 + This is an Ultra DMA chipset for ATA-66. + + This driver adds up to 4 more EIDE devices sharing a single + interrupt. The HPT366 chipset in its current form is a non-bootable. + This driver requires dynamic tuning of the chipset during the + ide-probe at boot. It is reported to support DVD II drives, by the + manufacturer. + + Please read the comments at the top of drivers/block/hpt366.c + +HPT366 (EXPERIMENTAL) +CONFIG_BLK_DEV_HPT366_SHARED + This requires CONFIG_BLK_DEV_HPT366. + It appears that there are different versions or releases of this hardware + by ABit. Since some cases the second channel of the onboard chipset works + and others fail, it is default disabled. This is required to be set if you + want to attempt the setup of the second channel. + + JUMBO WARNING, do not boot a kernel with this enabled if it is your only + one. You may not be able to get back into your machine without physically + detaching the attached devices. If unsure, say N. -CMD646 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_CMD646 - Say Y here if you have an IDE controller which uses this chipset. +NS87415 support (EXPERIMENTAL) +CONFIG_BLK_DEV_NS87415 + This driver adds detection and support for the NS87415 chip + (used in SPARC64, among others). -ALI M15x3 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_ALI15X3 - This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C - onboard chipsets. It also tests for Simplex mode and enables - normal dual channel support. + Please read the comments at the top of drivers/block/ns87415.c. - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. +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/block/alim15x3.c +Intel PIIXn chipsets support +CONFIG_BLK_DEV_PIIX + This driver adds PIO mode setting and tuning for all PIIX IDE + controllers by Intel. Since the BIOS can sometimes improperly tune + 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 + + If unsure, say N. + +PIIXn Tuning support +CONFIG_BLK_DEV_PIIX_TUNING + This driver extension adds DMA mode setting and tuning for all PIIX + IDE controllers by Intel. Since the BIOS can sometimes improperly + set up the device/adapter combination and speed limits, it has + become a necessity to back/forward speed devices as needed. + + Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode + 2 if the BIOS can not perform this task at initialization. If unsure, say N. @@ -767,7 +762,7 @@ If unsure, say N. -Special UDMA Feature (EXPERIMENTAL) +Special UDMA Feature PDC202XX_FORCE_BURST_BIT For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally for PDC20246/Ultra33 that has BIOS setup failures when using 3 or @@ -777,71 +772,97 @@ If unsure, say N. -Special Mode Feature (DANGEROUS) +Special Mode Feature (EXPERIMENTAL) PDC202XX_FORCE_MASTER_MODE For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for possible Hardware RAID 0,1 for the FastTrak Series. Say N. -AEC6210 chipset support -CONFIG_BLK_DEV_AEC6210 - This driver adds up to 4 more EIDE devices sharing a single - interrupt. This add-on card is a bootable PCI UDMA controller. In - order to get this card to initialize correctly in some cases, you - should say Y here, and preferably also to "Use DMA by default when - available". +Winbond SL82c105 support +CONFIG_BLK_DEV_SL82C105 + If you have a Winbond SL82c105 IDE controller, say Y here to enable + special configuration for this chip. This is common on various CHRP + motherboards, but could be used elsewhere. If in doubt, say Y. - Please read the comments at the top of drivers/block/aec6210.c +Tekram TRM290 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_TRM290 + 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. -HPT366 chipset support -CONFIG_BLK_DEV_HPT366 - This is an Ultra DMA chipset for ATA-66. - - This driver adds up to 4 more EIDE devices sharing a single - interrupt. The HPT366 chipset in its current form is a non-bootable. - This driver requires dynamic tuning of the chipset during the - ide-probe at boot. It is reported to support DVD II drives, by the - manufacturer. - -Intel PIIXn chipsets support -CONFIG_BLK_DEV_PIIX - This driver adds PIO mode setting and tuning for all PIIX IDE - controllers by Intel. Since the BIOS can sometimes improperly tune - PIO 0-4 mode settings, this allows dynamic tuning of the chipset - via the standard end-user tool 'hdparm'. +VIA82CXXX chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_VIA82CXXX + This allows you to to configure your chipset for a better use while + running (U)DMA: it will allow you to enable efficiently the second + channel dma usage, as it is may not be set by BIOS. It allows you to + run a kernel command line at boot time in order to set fifo config. + 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/block/piix.c + If you say Y here, you also need to say Y to "Use DMA by default + when available", above. If unsure, say N. -PIIXn Tuning support (EXPERIMENTAL) -CONFIG_BLK_DEV_PIIX_TUNING - This driver extension adds DMA mode setting and tuning for all PIIX - IDE controllers by Intel. Since the BIOS can sometimes improperly - set up the device/adapter combination and speed limits, it has - become a necessity to back/forward speed devices as needed. +Other IDE chipset support +CONFIG_IDE_CHIPSETS + Say Y here if you want to include enhanced support for various IDE + interface chipsets used on motherboards and add-on cards. You can + then pick your particular IDE chip from among the following options. + This enhanced support may be necessary for Linux to be able to + access the 3rd/4th drives in some systems. It may also enable + setting of higher speed I/O rates to improve system performance with + these chipsets. Most of these also require special kernel boot + parameters to actually turn on the support at runtime; you can find + a list of these in the file Documentation/ide.txt. + + People with SCSI-only systems can say N here. - Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode - 2 if the BIOS can not perform this task at initialization. +Generic 4 drives/port support +CONFIG_BLK_DEV_4DRIVES + Certain older chipsets, including the Tekram 690CD, use a single set + of I/O ports at 0x1f0 to control up to four drives, instead of the + customary two drives per port. Support for this can be enabled at + runtime using the "ide0=four" kernel boot parameter if you say Y + here. - If unsure, say N. +ALI M14xx support +CONFIG_BLK_DEV_ALI14XX + This driver is enabled at runtime using the "ide0=ali14xx" kernel + 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. -HPT34X chipset support -CONFIG_BLK_DEV_HPT34X - This driver adds up to 4 more EIDE devices sharing a single - interrupt. The HPT343 chipset in its current form is a non-bootable - controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX) - PCI UDMA controllers. This driver requires dynamic tuning of the - chipset during the ide-probe at boot time. It is reported to support - DVD II drives, by the manufacturer. +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 + files for more info. -HPT34X DMA support (DANGEROUS) -CONFIG_BLK_DEV_HPT34X_DMA - you need to say Y to "Use DMA by default when available" if you say - Y here. +Holtek HT6560B support +CONFIG_BLK_DEV_HT6560B + 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 + more info. - Please read the comments at the top of drivers/block/hpt343.c +PROMISE DC4030 support (EXPERIMENTAL) +CONFIG_BLK_DEV_PDC4030 + This driver provides support for the secondary IDE interface and + cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver + is known to incur timeouts/retries during heavy I/O to drives + 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. QDI QD6580 support CONFIG_BLK_DEV_QD6580 @@ -858,13 +879,15 @@ See the files Documentation/ide.txt and drivers/block/umc8672.c for more info. -ALI M14xx support -CONFIG_BLK_DEV_ALI14XX - This driver is enabled at runtime using the "ide0=ali14xx" kernel - 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. +PS/2 ESDI hard disk support +CONFIG_BLK_DEV_PS2 + Say Y here if you have a PS/2 machine with a MCA bus and an ESDI + hard disk. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ps2esdi.o. Amiga builtin Gayle IDE interface support CONFIG_BLK_DEV_GAYLE @@ -1809,20 +1832,41 @@ If unsure, say Y. -PCMCIA/Cardbus support +PCMCIA/CardBus support CONFIG_PCMCIA - Say Y here if you want to attach PCMCIA's (PC-cards) to your Linux - computer. These are credit-card size devices such as network cards, - modems or hard drives popular with laptops. + Include kernel support for PCMCIA and CardBus devices. Because + PCMCIA support requires additional components that are not part of + the kernel (i.e., the pcmcia-cs package), building PCMCIA into the + kernel is generally not recommended unless you have a specific + need. If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + When compiled this way, there will be modules called pcmcia_core.o + and ds.o. If you want to compile it as a module, say M here and + read Documentation/modules.txt. You will also need David Hinds' pcmcia-cs package (see the file - Documentation/Changes for location). + Documentation/Changes for location). For more information, see the + PCMCIA-HOWTO. CardBus support CONFIG_CARDBUS - CardBus is a bus mastering architecture for PC-cards (it allows - PC-cards to talk to the rest of the stuff inside your computer). If - unsure, say Y. + There are two types of PCMCIA devices: 16-bit PC Cards, and higher + performance 32-bit CardBus devices. Use this option to include + support for CardBus devices. If unsure, say Y. + +i82365/Yenta compatible bridge support +CONFIG_I82365 + Include support for PCMCIA and CardBus host bridges that are + register compatible with the Intel i82365 and/or the Yenta + specification: this includes virtually all modern PCMCIA bridges. + If unsure, say Y. + +Databook TCIC host bridge support +CONFIG_TCIC + Include support for the Databook TCIC family of PCMCIA host bridges. + These are only found on a handful of old systems. If unsure, say N. System V IPC CONFIG_SYSVIPC @@ -5455,10 +5499,48 @@ say M here and read Documentation/modules.txt. The module will be called x25_asy.o. If unsure, say N. -PCMCIA ethernet cards (NE2000 compatibles: DE-650, ...) +PCMCIA network device support +CONFIG_NET_PCMCIA + Say Y if you would like to include support for any PCMCIA network + adapters. If unsure, say N. + +3Com 3c589 PCMCIA support +CONFIG_PCMCIA_3C589 + Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA + (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c589_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +3Com 3c574 PCMCIA support +CONFIG_PCMCIA_3C574 + Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA + (PC-card) Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c574_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Fujitsu FMV-J18x PCMCIA support +CONFIG_PCMCIA_FMVJ18X + Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible + PCMCIA (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fmvj18x_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +NE2000 compatible PCMCIA support CONFIG_PCMCIA_PCNET Say Y here if you intend to attach an NE2000 compatible PCMCIA - (PC-card) Ethernet networking card to your computer. + (PC-card) Ethernet or Fast Ethernet card to your computer. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -5466,18 +5548,40 @@ module, say M here and read Documentation/modules.txt. If unsure, say N. -3Com 3c589 PCMCIA card -CONFIG_PCMCIA_3C589 - Say Y here if you intend to attach a 3Com 3c589 PCMCIA - (PC-card) Ethernet networking card to your computer. +New Media PCMCIA support +CONFIG_PCMCIA_NMCLAN + Say Y here if you intend to attach a New Media Ethernet or LiveWire + PCMCIA (PC-card) Ethernet card to your computer. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called 3c589_cs.o. If you want to compile it as a + The module will be called nmclan_cs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -Aviator/Raytheon 2.4MHz wireless +SMC 91Cxx PCMCIA support +CONFIG_PCMCIA_SMC91C92 + Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA + (PC-card) Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc91c92_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Xircom 16-bit PCMCIA support +CONFIG_PCMCIA_XIRC2PS + Say Y here if you intend to attach a Xircom 16-bit PCMCIA + (PC-card) Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xirc2ps_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Aviator/Raytheon 2.4MHz wireless support CONFIG_PCMCIA_RAYCS Say Y here if you intend to attach an Aviator/Raytheon PCMCIA (PC-card) wireless Ethernet networking card to your computer. @@ -5488,6 +5592,29 @@ module, say M here and read Documentation/modules.txt. If unsure, say N. +Xircom Netwave AirSurfer wireless support +CONFIG_PCMCIA_NETWAVE + Say Y here if you intend to attach a Xircom Netwave AirSurfer PCMCIA + (PC-card) wireless Ethernet networking card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called netwave_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +AT&T/Lucent Wavelan wireless support +CONFIG_PCMCIA_WAVELAN + Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA + (PC-card) wireless Ethernet networking card to your computer. This + driver is for the non-IEEE-802.11 Wavelan cards. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wavelan_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + PLIP (parallel port) support CONFIG_PLIP PLIP (Parallel Line Internet Protocol) is used to create a @@ -12164,18 +12291,44 @@ CONFIG_ARCH_NETWINDER Say Y here if you intend to run this kernel on the NetWinder. -Maximum Physical Memory +Virtual/Physical Memory Split CONFIG_1GB - Linux can use up to 2 Gigabytes (= 2^31 bytes) of physical memory. - If you are compiling a kernel which will never run on a machine with - more than 1 Gigabyte, answer "1GB" here. Otherwise, say "2GB". - - The actual amount of physical memory should be specified 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://metalab.unc.edu/mdw/linux.html#howto .) + 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://metalab.unc.edu/mdw/linux.html#howto .) Math emulation CONFIG_NWFPE @@ -12786,7 +12939,7 @@ # LocalWords: KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb # LocalWords: dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS # LocalWords: nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY -# LocalWords: Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs BIGMEM DAC IRQ's +# LocalWords: Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs HIGHMEM DAC IRQ's # LocalWords: IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu # LocalWords: unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS # LocalWords: BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Brutus linux/Documentation/arm/SA1100/Brutus --- v2.3.22/linux/Documentation/arm/SA1100/Brutus Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/Brutus Wed Oct 20 16:29:07 1999 @@ -0,0 +1,36 @@ +Brutus is an evaluation platform for the SA1100 manufactured by Intel. +For more details, see: + +http://developer.intel.com/design/strong/applnots/sa1100lx/getstart.htm + +To compile for Brutus, you must issue the following comands: + + make brutus_config + make config + [accept all the defaults] + make dep + make zImage + +The resulting kernel will end up in linux/arch/arm/boot/zImage. This file +must be loaded at 0xc0008000 in Brutus's memory and execution started at +0xc0008000 as well. + +But prior to execute the kernel, a ramdisk image must also be loaded in +memory. Use memory address 0x00800000 for this. + +Currently supported: + - RS232 serial ports + - audio output + - LCD screen + - keyboard (needs to be cleaned up badly... any volunteer?) + +A full PCMCIA support is still missing, although it's possible to hack +some drivers in order to drive already inserted cards at boot time with +little modifications. + +Any contribution is welcome. + +Please send patches to nico@cam.org + +Have Fun ! + diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Itsy linux/Documentation/arm/SA1100/Itsy --- v2.3.22/linux/Documentation/arm/SA1100/Itsy Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/Itsy Wed Oct 20 16:29:07 1999 @@ -0,0 +1,12 @@ +Itsy is a research project done by the Western Research Lab, and Systems +Research Center in Palo Alto, CA. The Itsy project is one of several +research projects at Compaq that are related to pocket computing. + +Itsy support has yet to be fully integrated in this kernel. Linux 2.0.x +support is available though. + +For more information, see: + + http://www.research.digital.com/wrl/itsy/index.html + + diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/LART linux/Documentation/arm/SA1100/LART --- v2.3.22/linux/Documentation/arm/SA1100/LART Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/LART Wed Oct 20 16:29:07 1999 @@ -0,0 +1,17 @@ +Linux Advanced Radio Terminal (LART) +------------------------------------ + +The LART is a small (7.5 x 10cm) SA-1100 board, designed for embedded +applications. It has 32 MB DRAM, 4MB Flash ROM, double RS232 and all +other StrongARM-gadgets. Almost all SA signals are directly accessible +through a number of connectors. The powersupply accepts voltages +between 3.5V and 16V and is overdimensioned to support a range of +daughterboards. A quad Ethernet / IDE / PS2 / sound daughterboard +is under development, with plenty of others in different stages of +planning. + +The designs for this board are to be released under a GPL-like license; +we're working on the details. + +Contact: J.D. Bakker ; +pictures at http://www-ict.its.tudelft.nl/~erik/open-source/LART/ diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/PLEB linux/Documentation/arm/SA1100/PLEB --- v2.3.22/linux/Documentation/arm/SA1100/PLEB Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/PLEB Wed Oct 20 16:29:07 1999 @@ -0,0 +1,11 @@ +The PLEB project was started as a student initiative at the School of +Computer Science and Engineering, University of New South Wales to make a +pocket computer capable of running the Linux Kernel. + +PLEB support has yet to be fully integrated. + +For more information, see: + + http://www.cse.unsw.edu.au/~pleb/ + + diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Tifon linux/Documentation/arm/SA1100/Tifon --- v2.3.22/linux/Documentation/arm/SA1100/Tifon Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/Tifon Wed Oct 20 16:29:07 1999 @@ -0,0 +1,7 @@ +Tifon +----- + +More info has to come... + +Contact: Peter Danielsson + diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Victor linux/Documentation/arm/SA1100/Victor --- v2.3.22/linux/Documentation/arm/SA1100/Victor Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/Victor Wed Oct 20 16:29:07 1999 @@ -0,0 +1,16 @@ +Victor is known as a "digital talking book player" manufactured by +VisuAide, Inc. to be used by blind people. + +For more information related to Victor, see: + + http://www.visuaide.com/victor + +Of course Victor is using Linux as its main operating system. +The Victor implementation for Linux is maintained by Nicolas Pitre: + + nico@visuaide.com + nico@cam.org + +For any comments, please feel free to contact me through the above +addresses. + diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/empeg linux/Documentation/arm/SA1100/empeg --- v2.3.22/linux/Documentation/arm/SA1100/empeg Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/empeg Wed Oct 20 16:29:07 1999 @@ -0,0 +1,2 @@ +See ../empeg/README + diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/Setup linux/Documentation/arm/Setup --- v2.3.22/linux/Documentation/arm/Setup Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/Setup Wed Oct 20 16:29:08 1999 @@ -0,0 +1,121 @@ +Kernel initialisation parameters on ARM Linux +--------------------------------------------- + +The following document describes the kernel initialisation parameter +structure, otherwise known as 'struct param_struct' which is used +for most ARM Linux architectures. + +This structure is used to pass initialisation parameters from the +kernel loader to the Linux kernel proper, and may be short lived +through the kernel initialisation process. As a general rule, it +should not be referenced outside of arch/arm/kernel/setup.c:setup_arch(). + +There are a lot of parameters listed in there, and they are described +below: + + page_size + + This parameter must be set to the page size of the machine, and + will be checked by the kernel. + + nr_pages + + This is the total number of pages of memory in the system. If + the memory is banked, then this should contain the total number + of pages in the system. + + If the system contains separate VRAM, this value should not + include this information. + + ramdisk_size + + This is now obsolete, and should not be used. + + flags + + Various kernel flags, including: + bit 0 - 1 = mount root read only + bit 1 - unused + bit 2 - 0 = load ramdisk + bit 3 - 0 = prompt for ramdisk + + rootdev + + major/minor number pair of device to mount as the root filesystem. + + video_num_cols + video_num_rows + + These two together describe the character size of the dummy console, + or VGA console character size. They should not be used for any other + purpose. + + It's generally a good idea to set these to be either standard VGA, or + the equivalent character size of your fbcon display. This then allows + all the bootup messages to be displayed correctly. + + video_x + video_y + + This describes the character position of cursor on VGA console, and + is otherwise unused. (should not used for other console types, and + should not be used for other purposes). + + memc_control_reg + + MEMC chip control register for Acorn Archimedes and Acorn A5000 + based machines. May be used differently by different architectures. + + sounddefault + + Default sound setting on Acorn machines. May be used differently by + different architectures. + + adfsdrives + + Number of ADFS/MFM disks. May be used differently by different + architectures. + + bytes_per_char_h + bytes_per_char_v + + These are now obsolete, and should not be used. + + pages_in_bank[4] + + Number of pages in each bank of the systems memory (used for RiscPC). + This is intended to be used on systems where the physical memory + is non-contiguous from the processors point of view. + + pages_in_vram + + Number of pages in VRAM (used on Acorn RiscPC). This value may also + be used by loaders if the size of the video RAM can't be obtained + from the hardware. + + initrd_start + initrd_size + + This describes the kernel virtual start address and size of the + inital ramdisk. + + rd_start + + Start address in sectors of the ramdisk image on a floppy disk. + + system_rev + + system revision number. + + system_serial_low + system_serial_high + + system 64-bit serial number + + paths[8][128] + + These are now obsolete, and should not be used. + + commandline + + Kernel command line parameters. Details can be found elsewhere. diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/empeg/README linux/Documentation/arm/empeg/README --- v2.3.22/linux/Documentation/arm/empeg/README Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/empeg/README Wed Oct 20 16:29:08 1999 @@ -0,0 +1,13 @@ +Empeg, Ltd's Empeg MP3 Car Audio Player + +The initial design is to go in your car, but you can use it at home, on a +boat... almost anywhere. The principle is to store CD-quality music using +MPEG technology onto a hard disk in the unit, and use the power of the +embedded computer to serve up the music you want. + +For more details, see: + + http://www.empeg.com + + + diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/empeg/ir.txt linux/Documentation/arm/empeg/ir.txt --- v2.3.22/linux/Documentation/arm/empeg/ir.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/empeg/ir.txt Wed Oct 20 16:29:08 1999 @@ -0,0 +1,49 @@ +Infra-red driver documentation. + +Mike Crowe +(C) Empeg Ltd 1999 + +Not a lot here yet :-) + +The Kenwood KCA-R6A remote control generates a sequence like the following: + +Go low for approx 16T (Around 9000us) +Go high for approx 8T (Around 4000us) +Go low for less than 2T (Around 750us) + +For each of the 32 bits + Go high for more than 2T (Around 1500us) == 1 + Go high for less than T (Around 400us) == 0 + Go low for less than 2T (Around 750us) + +Rather than repeat a signal when the button is held down certain buttons +generate the following code to indicate repitition. + +Go low for approx 16T +Go high for approx 4T +Go low for less than 2T + +(By removing the <2T from the start of the sequence and placing at the end + it can be considered a stop bit but I found it easier to deal with it at + the start). + +The 32 bits are encoded as XxYy where x and y are the actual data values +while X and Y are the logical inverses of the associated data values. Using +LSB first yields sensible codes for the numbers. + +All codes are of the form b9xx + +The numeric keys generate the code 0x where x is the number pressed. + +Tuner 1c +Tape 1d +CD 1e +CD-MD-CH 1f +Track- 0a +Track+ 0b +Rewind 0c +FF 0d +DNPP 5e +Play/Pause 0e +Vol+ 14 +Vol- 15 diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/empeg/mkdevs linux/Documentation/arm/empeg/mkdevs --- v2.3.22/linux/Documentation/arm/empeg/mkdevs Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/empeg/mkdevs Wed Oct 20 16:29:08 1999 @@ -0,0 +1,11 @@ +#!/bin/sh +mknod /dev/display c 244 0 +mknod /dev/ir c 242 0 +mknod /dev/usb0 c 243 0 +mknod /dev/audio c 245 4 +mknod /dev/dsp c 245 3 +mknod /dev/mixer c 245 0 +mknod /dev/empeg_state c 246 0 +mknod /dev/radio0 c 81 64 +ln -sf radio0 radio +ln -sf usb0 usb diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/nwfpe/README linux/Documentation/arm/nwfpe/README --- v2.3.22/linux/Documentation/arm/nwfpe/README Sun May 2 09:51:16 1999 +++ linux/Documentation/arm/nwfpe/README Wed Oct 20 16:29:08 1999 @@ -35,7 +35,7 @@ remains to be done, and other ideas for the emulator. Bug reports, comments, suggestions should be directed to me at -. General reports of "this program doesn't +. General reports of "this program doesn't work correctly when your emulator is installed" are useful for determining that bugs still exist; but are virtually useless when attempting to isolate the problem. Please report them, but don't @@ -46,7 +46,7 @@ Legal Notices ------------- -The NetWinder Floating Point Emulator is free software. Everything Corel +The NetWinder Floating Point Emulator is free software. Everything Rebel.com has written is provided under the GNU GPL. See the file COPYING for copying conditions. Excluded from the above is the SoftFloat code. John Hauser's legal notice for SoftFloat is included below. diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/nwfpe/README.FPE linux/Documentation/arm/nwfpe/README.FPE --- v2.3.22/linux/Documentation/arm/nwfpe/README.FPE Sun May 2 09:51:16 1999 +++ linux/Documentation/arm/nwfpe/README.FPE Wed Oct 20 16:29:08 1999 @@ -139,10 +139,10 @@ Signalling: -Signals are implemented. However current ELF kernels produced by Corel -Computer have a bug in them that prevents the module from generating a -SIGFPE. This is caused by a failure to alias fp_current to the kernel -variable current_set[0] correctly. +Signals are implemented. However current ELF kernels produced by Rebel.com +have a bug in them that prevents the module from generating a SIGFPE. This +is caused by a failure to alias fp_current to the kernel variable +current_set[0] correctly. The kernel provided with this distribution (vmlinux-nwfpe-0.93) contains a fix for this problem and also incorporates the current version of the diff -u --recursive --new-file v2.3.22/linux/Documentation/pci.txt linux/Documentation/pci.txt --- v2.3.22/linux/Documentation/pci.txt Thu Jun 17 12:56:11 1999 +++ linux/Documentation/pci.txt Fri Oct 15 18:55:26 1999 @@ -4,10 +4,19 @@ "What should you avoid when writing PCI drivers" - by Martin Mares on 17-Jun-1999 + by Martin Mares on 09-Oct-1999 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +0. Structure of PCI drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Aa typical PCI device driver needs to perform the following actions: + + 1. Find PCI devices it's able to handle + 2. Enable them + 3. Access their configuration space + 4. Discover addresses and IRQ numbers + 1. How to find PCI devices ~~~~~~~~~~~~~~~~~~~~~~~~~~ In case your driver wants to search for all devices with given vendor/device @@ -19,6 +28,9 @@ For class-based search, use pci_find_class(CLASS_ID, dev). + If you need to match by subsystem vendor/device ID, use +pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev). + You can use the constant PCI_ANY_ID as a wildcard replacement for VENDOR_ID or DEVICE_ID. This allows searching for any device from a specific vendor, for example. @@ -26,44 +38,57 @@ In case you want to do some complex matching, look at pci_devices -- it's a linked list of pci_dev structures for all PCI devices in the system. - All these methods return a pointer to a pci_dev structure which is used as a -parameter for many other PCI functions. The rest of them accept bus and -device/function numbers which can be found in pci_dev->bus->number and -pci_dev->devfn. Feel free to use all other fields of the pci_dev structure, but -don't modify them. + The `struct pci_dev *' pointer serves as an identification of a PCI device +and is passed to all other functions operating on PCI devices. - The pci_present() function can be used to test presence of PCI in the -machine. +2. Enabling devices +~~~~~~~~~~~~~~~~~~~ + Before you do anything with the device you've found, you need to enable +it by calling pci_enable_device() which enables I/O and memory regions of +the device, assigns missing resources if needed and wakes up the device +if it was in suspended state. Please note that this function can fail. + + If you want to use the device in bus mastering mode, call pci_set_master() +which enables the bus master bit in PCI_COMMAND register and also fixes +the latency timer value if it's set to something bogus by the BIOS. -2. How to access PCI config space +3. How to access PCI config space ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use pci_(read|write)_config_(byte|word|dword) to access the config -space of a device represented by pci_dev. All these functions return 0 when -successful or an error code (PCIBIOS_...) which can be translated to a text +space of a device represented by struct pci_dev *. All these functions return 0 +when successful or an error code (PCIBIOS_...) which can be translated to a text string by pcibios_strerror. Most drivers expect that accesses to valid PCI devices don't fail. - In case you want to address the devices by bus/device/function numbers, -use pcibios_(read_write)_config_(byte|word|dword). - If you access fields in the standard portion of the config header, please use symbolic names of locations and bits declared in . -3. Addresses and interrupts + If you need to access Extended PCI Capability registers, just call +pci_find_capability() for the particular capability and it will find the +corresponding register block for you. + +4. Addresses and interrupts ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Memory and port addresses and interrupt numbers should NOT be read from the config space. You should use the values in the pci_dev structure as they might have been remapped by the kernel. -4. Obsolete functions -~~~~~~~~~~~~~~~~~~~~~ - is obsolete and should not be included in new code. +5. Other interesting functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +pci_find_slot() Find pci_dev corresponding to given bus and + slot numbers. +pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) -pcibios_find_(device|class) are also obsolete and should be replaced by -pci_find_(device|class). +6. Obsolete functions +~~~~~~~~~~~~~~~~~~~~~ +There are several functions kept only for compatibility with old drivers +not updated to the new PCI interface. Please don't use them in new code. -5. Bus mastering -~~~~~~~~~~~~~~~~ - If you need to setup a bus-mastering card, just call pci_set_master(). It -should set PCI_COMMAND_MASTER in the command register and adjust the latency -timer if needed. +pcibios_present() Since ages, you don't need to test presence + of PCI subsystem when trying to talk with it. + If it's not there, the list of PCI devices + is empty and all functions for searching for + devices just return NULL. +pcibios_(read|write)_* Superseded by their pci_(read|write)_* + counterparts. +pcibios_find_* Superseded by their pci_find_* counterparts. diff -u --recursive --new-file v2.3.22/linux/Documentation/vm/locking linux/Documentation/vm/locking --- v2.3.22/linux/Documentation/vm/locking Wed Dec 31 16:00:00 1969 +++ linux/Documentation/vm/locking Mon Oct 18 13:01:40 1999 @@ -0,0 +1,88 @@ +Started Oct 1999 by Kanoj Sarcar + +The intent of this file is to have an uptodate, running commentary +from different people about how locking and synchronization is done +in the Linux vm code. + +vmlist_access_lock/vmlist_modify_lock +-------------------------------------- + +Page stealers pick processes out of the process pool and scan for +the best process to steal pages from. To guarantee the existance +of the victim mm, a mm_count inc and a mmdrop are done in swap_out(). +Page stealers hold kernel_lock to protect against a bunch of races. +The vma list of the victim mm is also scanned by the stealer, +and the vmlist_lock is used to preserve list sanity against the +process adding/deleting to the list. This also gurantees existance +of the vma. Vma existance gurantee while invoking the driver +swapout() method in try_to_swap_out() also relies on the fact +that do_munmap() temporarily gets lock_kernel before decimating +the vma, thus the swapout() method must snapshot all the vma +fields it needs before going to sleep (which will release the +lock_kernel held by the page stealer). Currently, filemap_swapout +is the only method that depends on this shaky interlocking. + +Any code that modifies the vmlist, or the vm_start/vm_end/ +vm_flags:VM_LOCKED/vm_next of any vma *in the list* must prevent +kswapd from looking at the chain. This does not include driver mmap() +methods, for example, since the vma is still not in the list. + +The rules are: +1. To modify the vmlist (add/delete or change fields in an element), +you must hold mmap_sem to guard against clones doing mmap/munmap/faults, +(ie all vm system calls and faults), and from ptrace, swapin due to +swap deletion etc. +2. To modify the vmlist (add/delete or change fields in an element), +you must also hold vmlist_modify_lock, to guard against page stealers +scanning the list. +3. To scan the vmlist (find_vma()), you must either + a. grab mmap_sem, which should be done by all cases except + page stealer. +or + b. grab vmlist_access_lock, only done by page stealer. +4. While holding the vmlist_modify_lock, you must be able to guarantee +that no code path will lead to page stealing. A better guarantee is +to claim non sleepability, which ensures that you are not sleeping +for a lock, whose holder might in turn be doing page stealing. +5. You must be able to guarantee that while holding vmlist_modify_lock +or vmlist_access_lock of mm A, you will not try to get either lock +for mm B. + +The caveats are: +1. find_vma() makes use of, and updates, the mmap_cache pointer hint. +The update of mmap_cache is racy (page stealer can race with other code +that invokes find_vma with mmap_sem held), but that is okay, since it +is a hint. This can be fixed, if desired, by having find_vma grab the +vmlist lock. + + +Code that add/delete elements from the vmlist chain are +1. callers of insert_vm_struct +2. callers of merge_segments +3. callers of avl_remove + +Code that changes vm_start/vm_end/vm_flags:VM_LOCKED of vma's on +the list: +1. expand_stack +2. mprotect +3. mlock +4. mremap + +It is advisable that changes to vm_start/vm_end be protected, although +in some cases it is not really needed. Eg, vm_start is modified by +expand_stack(), it is hard to come up with a destructive scenario without +having the vmlist protection in this case. + +The vmlist lock nests with the inode i_shared_lock and the kmem cache +c_spinlock spinlocks. This is okay, since code that holds i_shared_lock +never asks for memory, and the kmem code asks for pages after dropping +c_spinlock. + +The vmlist lock can be a sleeping or spin lock. In either case, care +must be taken that it is not held on entry to the driver methods, since +those methods might sleep or ask for memory, causing deadlocks. + +The current implementation of the vmlist lock uses the page_table_lock, +which is also the spinlock that page stealers use to protect changes to +the victim process' ptes. Thus we have a reduction in the total number +of locks. diff -u --recursive --new-file v2.3.22/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.22/linux/MAINTAINERS Fri Oct 15 15:25:13 1999 +++ linux/MAINTAINERS Thu Oct 21 12:15:36 1999 @@ -396,6 +396,12 @@ W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained +i386 BOOT CODE +P: Riley H. Williams +M: rhw@memalpha.cx +L: Linux-Kernel@vger.rutgers.edu +S: Maintained + IBM MCA SCSI SUBSYSTEM DRIVER P: Michael Lang M: langa2@kph.uni-mainz.de @@ -502,8 +508,9 @@ LINUX FOR POWER MACINTOSH P: Paul Mackerras -M: paulus@cs.anu.edu.au -L: linux-pmac@samba.anu.edu.au +M: paulus@linuxcare.com +W: http://www.linuxppc.org/ +L: linuxppc-dev@lists.linuxppc.org S: Maintained M68K @@ -687,6 +694,7 @@ P: David Hinds M: dhinds@zen.stanford.edu L: linux-kernel@vger.rutgers.edu +W: http://pcmcia.sourceforge.org S: Maintained PCNET32 NETWORK DRIVER @@ -830,6 +838,16 @@ STARMODE RADIO IP (STRIP) PROTOCOL DRIVER W: http://mosquitonet.Stanford.EDU/strip.html S: Unsupported ? + +SUPERH +P: Niibe Yutaka +M: gniibe@chroot.org +P: Kazumoto Kojima +M: kkojima@rr.iij4u.or.jp +L: linux-sh@m17n.org +W: http://www.m17n.org/linux-sh/ +W: http://www.rr.iij4u.or.jp/~kkojima/linux-sh4.html +S: Maintained SVGA HANDLING P: Martin Mares diff -u --recursive --new-file v2.3.22/linux/Makefile linux/Makefile --- v2.3.22/linux/Makefile Fri Oct 15 15:25:13 1999 +++ linux/Makefile Fri Oct 15 15:25:27 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 22 +SUBLEVEL = 23 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.3.22/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.3.22/linux/arch/alpha/mm/init.c Thu Jul 29 13:37:22 1999 +++ linux/arch/alpha/mm/init.c Sat Oct 16 10:50:48 1999 @@ -166,6 +166,7 @@ printk("%ld pages shared\n",shared); printk("%ld pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif diff -u --recursive --new-file v2.3.22/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.3.22/linux/arch/arm/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/Makefile Wed Oct 20 16:29:08 1999 @@ -12,91 +12,101 @@ # # Copyright (C) 1995-1999 by Russell King -# GCC 2.7 uses different options to later compilers; sort out which we have -CONFIG_GCC_NEW := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi) +LD := $(CROSS_COMPILE)ld +OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S +CPP := $(CC) -E +PERL := perl +LINKFLAGS := -X -T arch/arm/vmlinux.lds +ARCHCC := $(word 1,$(CC)) + + +CFLAGS_PIPE := -pipe +CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) + +ifdef CONFIG_FRAME_POINTER +CFLAGS := $(CFLAGS:-fomit-frame-pointer=) +endif + +ifdef CONFIG_DEBUG_INFO +CFLAGS += -g +endif -# See if this is ld "2.9.4" or later -NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) -# CFLAGS_PROC - processor dependent CFLAGS -# PROCESSOR - processor type -# TEXTADDR - Uncompressed kernel link text address -# ZTEXTADDR - Compressed kernel link text address -# ZRELADDR - Compressed kernel relocating address -# (point at which uncompressed kernel is loaded). +# GCC 2.7 uses different options to later compilers; sort out which we have +NEW_GCC := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi) # # select flags depending on the compiler # -ifeq ($(CONFIG_GCC_NEW),y) - CFLAGS_PROC := -mshort-load-bytes -msoft-float - CFLAGS_PROC_CPU_26 := -mcpu=arm3 -Os - CFLAGS_PROC_CPU_32v3 := -march=armv3 - CFLAGS_PROC_CPU_32v4 := -march=armv4 - CFLAGS_ARM6 := -mtune=arm6 - CFLAGS_ARM7 := -mtune=arm7 - CFLAGS_SA110 := -mtune=strongarm110 +ifeq ($(NEW_GCC),y) +CFLAGS += -mshort-load-bytes -msoft-float +CFLAGS_PROC_CPU_26 := -mcpu=arm3 -Os +CFLAGS_PROC_CPU_32v3 := -march=armv3 +CFLAGS_PROC_CPU_32v4 := -march=armv4 +CFLAGS_ARM6 := -mtune=arm6 +CFLAGS_ARM7 := -mtune=arm7 +CFLAGS_SA110 := -mtune=strongarm110 else - CFLAGS_PROC := - CFLAGS_PROC_CPU_26 := -m3 - CFLAGS_PROC_CPU_32v3 := - CFLAGS_PROC_CPU_32v4 := - CFLAGS_ARM6 := -m6 - CFLAGS_ARM7 := -m6 - CFLAGS_SA110 := -m6 +CFLAGS_PROC_CPU_26 := -m3 +CFLAGS_PROC_CPU_32v3 := +CFLAGS_PROC_CPU_32v4 := +CFLAGS_ARM6 := -m6 +CFLAGS_ARM7 := -m6 +CFLAGS_SA110 := -m6 endif +# See if this is ld "2.9.4" or later +NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) + ifeq ($(NEW_LINKER),y) - ASFLAGS_PROC := -mno-fpu - ASFLAGS_PROC_CPU_26 := -mapcs-26 - ASFLAGS_PROC_CPU_32v3 := -mapcs-32 -marmv3m - ASFLAGS_PROC_CPU_32v4 := -mapcs-32 -marmv4t - LINKFLAGS := -p +AFLAGS += -mno-fpu +AFLAGS_PROC_CPU_26 := -mapcs-26 +AFLAGS_PROC_CPU_32v3 := -mapcs-32 -marmv3m +AFLAGS_PROC_CPU_32v4 := -mapcs-32 -marmv4t +LINKFLAGS := -p $(LINKFLAGS) else - ASFLAGS_PROC := - ASFLAGS_PROC_CPU_26 := -m3 - ASFLAGS_PROC_CPU_32v3 := -m6 - ASFLAGS_PROC_CPU_32v4 := -m6 - LINKFLAGS := +AFLAGS_PROC_CPU_26 := -m3 +AFLAGS_PROC_CPU_32v3 := -m6 +AFLAGS_PROC_CPU_32v4 := -m6 endif +# +# Select CPU dependent flags +# ifeq ($(CONFIG_CPU_26),y) - PROCESSOR = armo - TEXTADDR = 0x02080000 - ZTEXTADDR = 0x01800000 - ZRELADDR = 0x02080000 - CFLAGS_PROC += $(CFLAGS_PROC_CPU_26) - ASFLAGS_PROC += $(ASFLAGS_PROC_CPU_26) + PROCESSOR = armo + TEXTADDR = 0x02080000 + CFLAGS += $(CFLAGS_PROC_CPU_26) + AFLAGS += $(AFLAGS_PROC_CPU_26) endif ifeq ($(CONFIG_CPU_32),y) - PROCESSOR = armv - TEXTADDR = 0xC0008000 - ifeq ($(CONFIG_CPU_32v4),y) - CFLAGS_PROC += $(CFLAGS_PROC_CPU_32v4) - ASFLAGS_PROC += $(ASFLAGS_PROC_CPU_32v4) - else - CFLAGS_PROC += $(CFLAGS_PROC_CPU_32v3) - ASFLAGS_PROC += $(ASFLAGS_PROC_CPU_32v3) - endif - # - # Exactly one of the following must be selected - # - ifeq ($(CONFIG_CPU_ARM6),y) - CFLAGS_PROC += $(CFLAGS_ARM6) - else - ifeq ($(CONFIG_CPU_ARM7),y) - CFLAGS_PROC += $(CFLAGS_ARM7) - else - ifeq ($(CONFIG_CPU_SA110),y) - CFLAGS_PROC += $(CFLAGS_SA110) - endif - endif - endif + PROCESSOR = armv + TEXTADDR = 0xC0008000 + ifeq ($(CONFIG_CPU_32v4),y) + CFLAGS += $(CFLAGS_PROC_CPU_32v4) + AFLAGS += $(AFLAGS_PROC_CPU_32v4) + else + CFLAGS += $(CFLAGS_PROC_CPU_32v3) + AFLAGS += $(AFLAGS_PROC_CPU_32v3) + endif + # + # Exactly one of the following must be selected + # + ifeq ($(CONFIG_CPU_ARM6),y) + CFLAGS += $(CFLAGS_ARM6) + else + ifeq ($(CONFIG_CPU_ARM7),y) + CFLAGS += $(CFLAGS_ARM7) + else + ifeq ($(CONFIG_CPU_SA110),y) + CFLAGS += $(CFLAGS_SA110) + endif + endif + endif endif - -COMPRESSED_HEAD = head.o +GCCLIB := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) ifeq ($(CONFIG_ARCH_A5K),y) MACHINE = a5k @@ -111,22 +121,16 @@ ifeq ($(CONFIG_ARCH_RPC),y) MACHINE = rpc ARCHDIR = rpc -ZTEXTADDR = 0x10008000 -ZRELADDR = 0x10008000 endif ifeq ($(CONFIG_ARCH_EBSA110),y) MACHINE = ebsa110 ARCHDIR = ebsa110 -ZTEXTADDR = 0x00008000 -ZRELADDR = 0x00008000 endif ifeq ($(CONFIG_FOOTBRIDGE),y) MACHINE = footbridge ARCHDIR = ebsa285 -ZTEXTADDR = 0x00008000 -ZRELADDR = 0x00008000 endif ifeq ($(CONFIG_ARCH_CO285),y) @@ -136,56 +140,31 @@ ifeq ($(CONFIG_ARCH_NEXUSPCI),y) MACHINE = nexuspci ARCHDIR = nexuspci -ZTEXTADDR = 0x40200000 -ZRELADDR = 0x40008000 -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o -COMPRESSED_HEAD = head-nexuspci.o endif - - -PERL = perl -LD = $(CROSS_COMPILE)ld -OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S -OBJDUMP = $(CROSS_COMPILE)objdump -CPP = $(CC) -E -ARCHCC := $(word 1,$(CC)) -GCCLIB := `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name` -HOSTCFLAGS := $(CFLAGS:-fomit-frame-pointer=) -ifeq ($(CONFIG_FRAME_POINTER),y) -CFLAGS := $(CFLAGS:-fomit-frame-pointer=) -endif -CFLAGS := $(CFLAGS_PROC) $(CFLAGS) -pipe -ASFLAGS := $(ASFLAGS_PROC) $(ASFLAGS) -LINKFLAGS += -X -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext -ZLINKFLAGS = -Ttext $(ZTEXTADDR) - -# If we're intending to debug the kernel, make sure it has line number -# information. This gets stripped out when building (z)Image so it doesn't -# add anything to the footprint of the running kernel. -ifeq ($(CONFIG_DEBUG_INFO),y) -CFLAGS += -g +ifeq ($(CONFIG_ARCH_SA1100),u) +MACHINE = sa1100 +ARCHDIR = sa1100 endif HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ arch/arm/kernel/init_task.o -SUBDIRS := arch/arm/special $(SUBDIRS) arch/arm/lib arch/arm/kernel \ - arch/arm/mm arch/arm/nwfpe +SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \ + arch/arm/special arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB) DRIVERS += arch/arm/special/special.a -ifeq ($(CONFIG_ARCH_ACORN),y) -SUBDIRS += drivers/acorn/block drivers/acorn/char drivers/acorn/net \ - drivers/acorn/scsi -DRIVERS += drivers/acorn/block/acorn-block.a \ - drivers/acorn/char/acorn-char.a \ - drivers/acorn/net/acorn-net.a \ - drivers/acorn/scsi/acorn-scsi.a +ifeq ($(CONFIG_NWFPE),y) +CORE_FILES += arch/arm/nwfpe/math-emu.o endif -ifeq ($(CONFIG_NWFPE),y) -DRIVERS += arch/arm/nwfpe/math-emu.a +ifeq ($(CONFIG_ARCH_ACORN),y) +SUBDIRS += drivers/acorn +DRIVERS += drivers/acorn/block/acorn-block.a +DRIVERS += drivers/acorn/char/acorn-char.a +DRIVERS += drivers/acorn/net/acorn-net.a +DRIVERS += drivers/acorn/scsi/acorn-scsi.a endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot @@ -203,14 +182,9 @@ $(RM) include/asm-arm/arch include/asm-arm/proc (cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc) -# We need to rebuild the linker script -# each time, in case the architecture has -# changed. -.PHONY: arch/arm/vmlinux-$(PROCESSOR).lds - -vmlinux: arch/arm/vmlinux-$(PROCESSOR).lds +vmlinux: arch/arm/vmlinux.lds -arch/arm/vmlinux-$(PROCESSOR).lds: $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds.in +arch/arm/vmlinux.lds: arch/arm/vmlinux-$(PROCESSOR).lds.in dummy @sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@ arch/arm/kernel: dummy @@ -225,15 +199,13 @@ zImage zinstall Image install: vmlinux @$(MAKEBOOT) $@ -# Once we've finished integrating the sources, the @$(MAKE) will disappear archmrproper: - rm -f include/asm-arm/arch include/asm-arm/proc @$(MAKE) -C arch/$(ARCH)/special mrproper - rm -f $(TOPDIR)/arch/arm/vmlinux-*.lds + $(RM) include/asm-arm/arch include/asm-arm/proc archclean: @$(MAKEBOOT) clean - $(RM) arch/arm/lib/constants.h + $(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds archdep: @$(MAKEBOOT) dep @@ -244,6 +216,10 @@ i:; @$(MAKEBOOT) install zi:; @$(MAKEBOOT) zinstall +# +# Configuration targets. Use these to select a +# configuration for your architecture +# a5k_config: $(RM) arch/arm/defconfig cp arch/arm/def-configs/a5k arch/arm/defconfig @@ -259,4 +235,17 @@ rpc_config: $(RM) arch/arm/defconfig cp arch/arm/def-configs/rpc arch/arm/defconfig + +brutus_config: + $(RM) arch/arm/defconfig + cp arch/arm/def-configs/brutus arch/arm/defconfig + +victor_config: + $(RM) arch/arm/defconfig + cp arch/arm/def-configs/victor arch/arm/defconfig + +empeg_config: + $(RM) arch/arm/defconfig + cp arch/arm/def-configs/empeg arch/arm/defconfig + diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.3.22/linux/arch/arm/boot/compressed/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/boot/compressed/Makefile Wed Oct 20 16:29:08 1999 @@ -2,47 +2,97 @@ # linux/arch/arm/boot/compressed/Makefile # # create a compressed vmlinuz image from the original vmlinux -# -# With this config, max compressed image size = 640k -# Uncompressed image size = 1.3M (text+data) -SYSTEM =$(TOPDIR)/vmlinux -HEAD =$(COMPRESSED_HEAD) -OBJS =$(HEAD) misc.o $(COMPRESSED_EXTRA) -CFLAGS =-O2 -DSTDC_HEADERS $(CFLAGS_PROC) -ARFLAGS =rc -FONTC =$(TOPDIR)/drivers/video/font_acorn_8x8.c +HEAD = head.o +OBJS = misc.o +SYSTEM = $(TOPDIR)/vmlinux +CFLAGS = -O2 -DSTDC_HEADERS $(CFLAGS_PROC) +FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c +ZLDFLAGS = -X -T vmlinux.lds +# +# Architecture dependencies +# ifeq ($(CONFIG_ARCH_ACORN),y) -OBJS += ll_char_wr.o font.o +OBJS += ll_char_wr.o font.o +endif + +ifeq ($(CONFIG_CPU_26),y) +ZTEXTADDR = 0x02080000 +endif + +ifeq ($(CONFIG_ARCH_RPC),y) +ZTEXTADDR = 0x10008000 +endif + +ifeq ($(CONFIG_ARCH_EBSA110),y) +ZTEXTADDR = 0x00008000 +endif + +ifeq ($(CONFIG_FOOTBRIDGE),y) +ZTEXTADDR = 0x00008000 +endif + +ifeq ($(CONFIG_ARCH_NETWINDER),y) +OBJS += head-netwinder.o endif -ifeq ($(NEW_LINKER),y) -BINFMT := elf32-littlearm +ifeq ($(CONFIG_ARCH_NEXUSPCI),y) +HEAD = head-nexuspci.o +OBJS += $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o +ZTEXTADDR = 0x40200000 +ZRELADDR = 0x40008000 +endif + +ifeq ($(CONFIG_ARCH_SA110),y) +ifeq ($(CONFIG_SA1100_VICTOR),y) +HEAD = head-victor.o +ZTEXTADDR = 0x00002000 +ZBSSADDR = 0xc0100000 else -BINFMT := elf32-arm +ZTEXTADDR = 0xc0008000 +endif +ZRELADDR = 0xc0008000 +endif + +# +# If you don't define ZRELADDR above, +# then it defaults to ZTEXTADDR +# +ifeq ($(ZRELADDR),) +ZRELADDR = $(ZTEXTADDR) endif +SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/; + +ifneq ($(ZBSSADDR),) +SEDFLAGS += s/BSS_START/$(ZBSSADDR)/ +else +SEDFLAGS += s/BSS_START/ALIGN(4)/ +endif all: vmlinux -vmlinux: $(OBJS) piggy.o - $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJS) piggy.o +vmlinux: $(HEAD) $(OBJS) piggy.o vmlinux.lds + $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux $(HEAD): $(HEAD:.o=.S) - $(CC) -traditional -DLOADADDR=$(ZRELADDR) -c $(HEAD:.o=.S) + $(CC) -traditional -c $(HEAD:.o=.S) piggy.o: $(SYSTEM) - tmppiggy=_tmp_$$$$piggy; \ - rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ - $(OBJCOPY) $(SYSTEM) $$tmppiggy; \ - gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ - echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ - $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b $(BINFMT) -T $$tmppiggy.lnk; \ - rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; + $(OBJCOPY) $(SYSTEM) piggy + gzip -9 < piggy > piggy.gz + $(LD) -r -o $@ -b binary piggy.gz + rm -f piggy piggy.gz font.o: $(FONTC) $(CC) -Dstatic= -c -o $@ $(FONTC) -clean:; rm -f vmlinux core +vmlinux.lds: vmlinux.lds.in + @sed "$(SEDFLAGS)" < vmlinux.lds.in > $@ + +clean:; rm -f vmlinux core piggy* + +.PHONY: vmlinux.lds clean +misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/head-netwinder.S linux/arch/arm/boot/compressed/head-netwinder.S --- v2.3.22/linux/arch/arm/boot/compressed/head-netwinder.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/head-netwinder.S Wed Oct 20 16:29:08 1999 @@ -0,0 +1,30 @@ + .section ".start", #alloc, #execinstr + + adr r2, 1f + ldmdb r2, {r7, r8} + and r3, r2, #0xc000 + teq r3, #0x8000 + beq 2f + bic r3, r2, #0xc000 + orr r3, r3, #0x8000 + mov r0, r3 + mov r4, #64 + sub r5, r8, r7 + b 1f + + .word _start + .word __bss_start + +1: + .rept 4 + ldmia r2!, {r6, r7, r8, r9} + stmia r3!, {r6, r7, r8, r9} + .endr + subs r4, r4, #64 + bcs 1b + movs r4, r5 + mov r5, #0 + movne pc, r0 + + mov r0, #0 +2: diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/head-victor.S linux/arch/arm/boot/compressed/head-victor.S --- v2.3.22/linux/arch/arm/boot/compressed/head-victor.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/head-victor.S Wed Oct 20 16:29:08 1999 @@ -0,0 +1,45 @@ +/* + * linux/arch/arm/boot/compressed/head-victor.S + * + * Copyright (C) 1998 Nicolas Pitre + */ + +#include + + .text + .globl _start +_start: + @ just in case we still use an a.out loader... + nop + nop + nop + nop + nop + nop + nop + nop + + @ load different addresses + adr r2, LC0 + ldmia r2, {r4, r5, r6, sp} + + @ clear BSS + mov r2, #0 +1: str r2, [r5], #4 + cmp r5, r6 + blt 1b + + @ uncompress the kernel + mov r8, r0 @ save cmdline ptr + mov r0, r4 @ where to put uncompressed data + add r1, r6, #31 + bic r1, r1, #31 @ free memory space + add r2, r1, #65536 @ end of free mem space + bl SYMBOL_NAME(decompress_kernel) + mov r0, r8 @ retrieve cmdline ptr + mov pc, r4 @ call via EXEC entry + +LC0: .word _load_addr + .word __bss_start + .word SYMBOL_NAME(_end) + .word SYMBOL_NAME(user_stack)+4096 diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.3.22/linux/arch/arm/boot/compressed/head.S Sat Jul 18 11:55:22 1998 +++ linux/arch/arm/boot/compressed/head.S Wed Oct 20 16:29:08 1999 @@ -1,129 +1,232 @@ /* * linux/arch/arm/boot/compressed/head.S * - * Copyright (C) 1996,1997,1998 Russell King + * Copyright (C) 1996-1999 Russell King */ #include - .text + .section ".start", #alloc, #execinstr /* * sort out different calling conventions */ .align - .globl _start -_start: -start: mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 +start: + .type start,#function + .rept 8 mov r0, r0 + .endr + b 1f - .word 0x016f2818 @ Magic numbers to help the loader - .word _start + .word 0x016f2818 @ Magic numbers to help the loader + .word start +1: + + /* + * some architecture specific code can + * be inserted by the linker here + */ + + .text 1: teq r0, #0 - beq 2f - mov r4, #0x02000000 - add r4, r4, #0x7C000 - mov r3, #0x4000 - sub r3, r3, #4 -1: ldmia r0!, {r5 - r12} - stmia r4!, {r5 - r12} - subs r3, r3, #32 - bpl 1b -2: adr r2, LC0 - ldmia r2, {r2, r3, r4, r5, r6, sp} - add r2, r2, #3 - add r3, r3, #3 - add sp, sp, #3 - bic r2, r2, #3 - bic r3, r3, #3 - bic sp, sp, #3 - adr r7, start - sub r6, r7, r6 -/* - * Relocate pointers - */ - add r2, r2, r6 - add r3, r3, r6 - add r5, r5, r6 - add sp, sp, r6 -/* - * Clear zero-init - */ - mov r6, #0 -1: str r6, [r2], #4 + bne 1b + mov r7, r1 @ save architecture ID + mrc p15, 0, r6, c0, c0 @ get processor ID + adr r2, LC0 + ldmia r2, {r2, r3, r4, r5, sp} + + mov r0, #0 +1: str r0, [r2], #4 @ clear bss + str r0, [r2], #4 + str r0, [r2], #4 + str r0, [r2], #4 cmp r2, r3 blt 1b - str r1, [r5] @ save architecture -/* - * Uncompress the kernel - */ - mov r1, #0x8000 - add r3, r2, r1, lsl #1 @ Add 64k for malloc - sub r1, r1, #1 - add r3, r3, r1 - bic r5, r3, r1 @ decompress kernel to after end of the compressed + + mov r1, sp @ malloc space above stack + add r2, sp, #0x10000 @ 64k max + + teq r4, r5 @ will we overwrite ourselves? + moveq r5, r2 + movne r5, r4 + mov r0, r5 - mov r1, r2 - mov r2, r0 + mov r3, r7 bl SYMBOL_NAME(decompress_kernel) - add r0, r0, #7 - bic r2, r0, #7 + + teq r4, r5 @ do we need to relocate + beq call_kernel @ the kernel? + + add r0, r0, #127 + bic r0, r0, #127 @ align the kernel length /* - * Now move the kernel to the correct location (r5 -> r4, len r0) - */ - mov r0, r4 @ r0 = start of real kernel - mov r1, r5 @ r1 = start of kernel image - add r3, r5, r2 @ r3 = end of kernel - adr r4, movecode - adr r5, movecodeend -1: ldmia r4!, {r6 - r12, lr} - stmia r3!, {r6 - r12, lr} - cmp r4, r5 + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + add r1, r5, r0 @ end of decompressed kernel + adr r2, reloc_start + adr r3, reloc_end +1: ldmia r2!, {r8 - r13} @ copy relocation code + stmia r1!, {r8 - r13} + ldmia r2!, {r8 - r13} + stmia r1!, {r8 - r13} + cmp r2, r3 blt 1b - mrc p15, 0, r5, c0, c0 - eor r5, r5, #0x44 << 24 - eor r5, r5, #0x01 << 16 - eor r5, r5, #0xa1 << 8 - movs r5, r5, lsr #4 - mov r5, #0 - mcreq p15, 0, r5, c7, c5, 0 @ flush I cache - ldr r5, LC0 + 12 @ get architecture - ldr r5, [r5] - add pc, r1, r2 @ Call move code + + eor r1, r6, #0x44 << 24 @ SA-110? + eor r1, r1, #0x01 << 16 + eor r1, r1, #0xa1 << 8 + movs r1, r1, lsr #4 + mcreq p15, 0, r1, c7, c7, 0 @ flush I & D-cache + mcreq p15, 0, r1, c7, c10, 4 @ drain WB + add pc, r5, r0 @ call relocation code /* - * r0 = length, r1 = to, r2 = from - */ -movecode: add r3, r1, r2 - mov r4, r0 -1: ldmia r1!, {r6 - r12, lr} - stmia r0!, {r6 - r12, lr} - cmp r1, r3 + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ +reloc_start: add r8, r5, r0 +#if 0 + mov r0, r6 + mov r1, #8 + bl phex + mov r0, #':' + bl putc + mov r0, r5 + mov r1, #8 + bl phex + mov r0, #'-' + bl putc + mov r0, r8 + mov r1, #8 + bl phex + mov r0, #'>' + bl putc + mov r0, r4 + mov r1, #8 + bl phex + mov r0, #'\n' + bl putc +#endif + mov r0, r8 + mov r1, r4 +1: + .rept 4 + ldmia r5!, {r2, r3, r8 - r13} @ relocate kernel + stmia r1!, {r2, r3, r8 - r13} + .endr + + cmp r5, r0 blt 1b - mrc p15, 0, r0, c0, c0 - eor r0, r0, #0x44 << 24 +#if 0 + mov r8, r0 + mov r0, r5 + mov r1, #8 + bl phex + mov r0, #'-' + bl putc + mov r0, r8 + mov r1, #8 + bl phex + mov r0, #'\n' + bl putc + mov r0, r4 + bl memdump +#endif + eor r0, r6, #0x44 << 24 @ SA-110? eor r0, r0, #0x01 << 16 eor r0, r0, #0xa1 << 8 movs r0, r0, lsr #4 + mcreq p15, 0, r0, c7, c7, 0 @ flush I cache + mcreq p15, 0, r1, c7, c10, 4 @ drain WB + +call_kernel: mov r0, #0 + mov r1, r7 @ restore architecture number + mov pc, r4 @ call kernel + +phexbuf: .space 12 + +phex: adr r3, phexbuf + mov r2, #0 + strb r2, [r3, r1] +1: subs r1, r1, #1 + movmi r0, r3 + bmi puts + and r2, r0, #15 + mov r0, r0, lsr #4 + cmp r2, #10 + addge r2, r2, #7 + add r2, r2, #'0' + strb r2, [r3, r1] + b 1b + +puts: mov r3, #0x7c000000 +1: ldrb r2, [r0], #1 + teq r2, #0 + moveq pc, lr +2: strb r2, [r3, #0x3f8] + mov r1, #0x00020000 +3: subs r1, r1, #1 + bne 3b + teq r2, #'\n' + moveq r2, #'\r' + beq 2b + teq r0, #0 + bne 1b + mov pc, lr +putc: + mov r2, r0 mov r0, #0 - mcreq p15, 0, r0, c7, c5, 0 @ flush I cache - mov r1, r5 @ call kernel correctly - mov pc, r4 @ call via EXEC entry -movecodeend: - -LC0: .word SYMBOL_NAME(_edata) - .word SYMBOL_NAME(_end) - .word LOADADDR - .word SYMBOL_NAME(architecture) - .word start - .word SYMBOL_NAME(user_stack)+4096 - .align + mov r3, #0x7c000000 + b 2b - .bss -SYMBOL_NAME(architecture): - .space 4 +memdump: mov r12, r0 + mov r10, lr + mov r1, #8 + bl phex + mov r0, #'\n' + bl putc + mov r11, #0 +2: mov r0, r11, lsl #2 + mov r1, #4 + bl phex + mov r0, #':' + bl putc +1: mov r0, #' ' + bl putc + ldr r0, [r12, r11, lsl #2] + mov r1, #8 + bl phex + and r0, r11, #7 + teq r0, #3 + moveq r0, #' ' + bleq putc + and r0, r11, #7 + add r11, r11, #1 + teq r0, #7 + bne 1b + mov r0, #'\n' + bl putc + cmp r11, #64 + blt 2b + mov pc, r10 +reloc_end: + +LC0: .word __bss_start + .word _end + .word _load_addr + .word _start + .word user_stack+4096 .align + + .section ".stack" +user_stack: .space 4096 diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/misc.c linux/arch/arm/boot/compressed/misc.c --- v2.3.22/linux/arch/arm/boot/compressed/misc.c Sun Sep 6 10:44:47 1998 +++ linux/arch/arm/boot/compressed/misc.c Thu Oct 21 12:15:36 1999 @@ -7,8 +7,17 @@ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 * * Modified for ARM Linux by Russell King + * + * Nicolas Pitre 1999/04/14 : + * For this code to run directly from Flash, all constant variables must + * be marked with 'const' and all other variables initialized at run-time + * only. This way all non constant variables will end up in the bss segment, + * which should point to addresses in RAM and cleared to 0 on start. + * This allows for a much quicker boot time. */ +unsigned int __machine_arch_type; + #include #include #include @@ -22,7 +31,7 @@ /* * Optimised C version of memzero for the ARM. */ -extern __inline__ __ptr_t __memzero (__ptr_t s, size_t n) +void __memzero (__ptr_t s, size_t n) { union { void *vp; unsigned long *ulp; unsigned char *ucp; } u; int i; @@ -62,11 +71,8 @@ if (n & 1) *u.ucp++ = 0; - return s; } -#define memzero(s,n) __memzero(s,n) - extern __inline__ __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src, size_t __n) { @@ -157,11 +163,11 @@ static void gzip_release(void **); extern char input_data[]; -extern int input_len; +extern char input_data_end[]; static uch *output_data; static ulg output_ptr; -static ulg bytes_out = 0; +static ulg bytes_out; static void *malloc(int size); static void free(void *where); @@ -226,13 +232,14 @@ * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed. */ -int fill_inbuf() +int fill_inbuf(void) { if (insize != 0) error("ran out of input data\n"); inbuf = input_data; - insize = input_len; + insize = &input_data_end[0] - &input_data[0]; + inptr = 1; return inbuf[0]; } @@ -241,7 +248,7 @@ * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ -void flush_window() +void flush_window(void) { ulg c = crc; unsigned n; @@ -257,6 +264,7 @@ bytes_out += (ulg)outcnt; output_ptr += (ulg)outcnt; outcnt = 0; + puts("."); } static void error(char *x) @@ -270,26 +278,24 @@ while(1); /* Halt */ } -#define STACK_SIZE (4096) - -ulg user_stack [STACK_SIZE]; - #ifndef STANDALONE_DEBUG -ulg decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p) -{ - free_mem_ptr = free_mem_ptr_p; - free_mem_ptr_end = free_mem_ptr_end_p; - - proc_decomp_setup (); - arch_decomp_setup (); +ulg +decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, + int arch_id) +{ + output_data = (uch *)output_start; /* Points to kernel start */ + free_mem_ptr = free_mem_ptr_p; + free_mem_ptr_end = free_mem_ptr_end_p; + __machine_arch_type = arch_id; - output_data = (uch *)output_start; /* Points to kernel start */ + proc_decomp_setup(); + arch_decomp_setup(); makecrc(); puts("Uncompressing Linux..."); gunzip(); - puts("done.\nNow booting the kernel\n"); + puts(" done, booting the kernel.\n"); return output_ptr; } #else diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/vmlinux.lds.in linux/arch/arm/boot/compressed/vmlinux.lds.in --- v2.3.22/linux/arch/arm/boot/compressed/vmlinux.lds.in Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/vmlinux.lds.in Wed Oct 20 16:29:08 1999 @@ -0,0 +1,52 @@ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = LOAD_ADDR; + _load_addr = .; + + . = TEXT_START; + _text = .; + + .text : { + _start = .; + head.o(.start) + *(.start) + head.o(.text) + *(.text) + *(.fixup) + *(.gnu.warning) + input_data = .; + piggy.o + input_data_end = .; + . = ALIGN(4); + } + + _etext = .; + + .data : { + *(.data) + } + + _edata = .; + + . = BSS_START; + __bss_start = .; + .bss : { + *(.bss) + } + _end = .; + + .stack : { + *(.stack) + } + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} + diff -u --recursive --new-file v2.3.22/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.3.22/linux/arch/arm/config.in Sat Oct 9 11:47:50 1999 +++ linux/arch/arm/config.in Wed Oct 20 16:29:08 1999 @@ -20,7 +20,7 @@ RiscPC CONFIG_ARCH_RPC \ EBSA-110 CONFIG_ARCH_EBSA110 \ FootBridge-based CONFIG_FOOTBRIDGE" RiscPC - +# SA1100-based CONFIG_ARCH_SA1100 if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then @@ -31,9 +31,9 @@ fi if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then - bool ' Include support for Intel EBSA285' CONFIG_ARCH_EBSA285 - bool ' Include support for Chalice CATS boards' CONFIG_CATS - bool ' Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER + bool ' Include support for EBSA285' CONFIG_ARCH_EBSA285 + bool ' Include support for CATS' CONFIG_CATS + bool ' Include support for NetWinder' CONFIG_ARCH_NETWINDER fi if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then @@ -42,6 +42,18 @@ define_bool CONFIG_ARCH_CO285 y fi +if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + define_bool CONFIG_CPU_SA1100 y + choice 'SA1100 implementation' \ + "Brutus CONFIG_SA1100_BRUTUS \ + empeg CONFIG_SA1100_EMPEG \ + Itsy CONFIG_SA1100_ITSY \ + LART CONFIG_SA1100_LART \ + PLEB CONFIG_SA1100_PLEB \ + Victor CONFIG_SA1100_VICTOR \ + Tifon CONFIG_SA1100_TIFON" Brutus +fi + # # Select various configuration options depending on the machine type # Easy check for Acorn-style architectures @@ -76,6 +88,7 @@ # Select CPU and optimisation dependent on architecture # if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_FOOTBRIDGE" = "y" -o \ "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then define_bool CONFIG_CPU_32v4 y @@ -139,21 +152,10 @@ tristate 'RISC OS personality' CONFIG_ARTHUR fi -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - if [ "$CONFIG_ARCH_ARC" = "y" ]; then - dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT - fi - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - # If exactly one hardware type is selected then parport will optimise away - # support for loading any others. Defeat this if the user is keen. - if [ "$CONFIG_PARPORT_PC" = "n" -o "$CONFIG_PARPORT_ARC" = "n" ]; then - if [ "$CONFIG_PARPORT_PC" != "n" -o "$CONFIG_PARPORT_ARC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi - fi -fi +source drivers/parport/Config.in + if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_CATS" = "y" ]; then string 'Initial kernel command string' CONFIG_CMDLINE @@ -165,10 +167,10 @@ bool 'Timer and CPU usage LEDs' CONFIG_LEDS if [ "$CONFIG_LEDS" = "y" ]; then if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ - "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ "$CONFIG_ARCH_CO285" = "y" ]; then - bool ' Timer LED' CONFIG_LEDS_TIMER - bool ' CPU usage LED' CONFIG_LEDS_CPU + bool ' Timer LED' CONFIG_LEDS_TIMER + bool ' CPU usage LED' CONFIG_LEDS_CPU fi fi fi @@ -186,11 +188,11 @@ source drivers/char/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - if [ "$CONFIG_MOUSE" = "y" ]; then + if [ "$CONFIG_BUSMOUSE" = "y" ]; then if [ "$CONFIG_ARCH_RPC" != "y" ]; then - define_bool CONFIG_KBDMOUSE y + define_bool CONFIG_KBDMOUSE y else - define_bool CONFIG_RPCMOUSE y + define_bool CONFIG_RPCMOUSE y fi fi fi @@ -230,7 +232,7 @@ # # tristate 'ISDN support' CONFIG_ISDN # if [ "$CONFIG_ISDN" != "n" ]; then -# source drivers/isdn/Config.in +# source drivers/isdn/Config.in # fi # endmenu @@ -267,17 +269,17 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_CPU_26" = "y" ]; then - bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE - fi - - # These options are only for real kernel hackers - # who want to get their hands dirty. - bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL - if [ "$CONFIG_DEBUG_LL" = "y" ]; then - if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT - fi - fi + if [ "$CONFIG_CPU_26" = "y" ]; then + bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE + fi + + # These options are only for real kernel hackers + # who want to get their hands dirty. + bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL + if [ "$CONFIG_DEBUG_LL" = "y" ]; then + if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT + fi + fi fi endmenu diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/brutus linux/arch/arm/def-configs/brutus --- v2.3.22/linux/arch/arm/def-configs/brutus Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/def-configs/brutus Wed Oct 20 16:29:08 1999 @@ -0,0 +1,221 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_FOOTBRIDGE is not set +CONFIG_ARCH_SA1100=y +CONFIG_CPU_SA1100=y +CONFIG_SA1100_BRUTUS=y +# CONFIG_SA1100_EMPEG is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_TIFON 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_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# General setup +# +# CONFIG_NET is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_NWFPE=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set +# CONFIG_PARPORT is not set +CONFIG_CMDLINE="" + +# +# I2O 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 + +# +# 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 is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP 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_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL_SA1100=y +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# 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_DRM is not set + +# +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_SA1100=y +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_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_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +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_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/empeg linux/arch/arm/def-configs/empeg --- v2.3.22/linux/arch/arm/def-configs/empeg Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/def-configs/empeg Wed Oct 20 16:29:08 1999 @@ -0,0 +1,264 @@ +# +# Example empeg-car kernel configuration file. +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_FOOTBRIDGE is not set +CONFIG_ARCH_SA1100=y +CONFIG_CPU_SA1100=y +# CONFIG_SA1100_BRUTUS is not set +CONFIG_SA1100_EMPEG=y +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_EMPEG_HENRY is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_ISA_DMA is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM2 is not set +# CONFIG_CPU_ARM3 is not set +# CONFIG_CPU_ARM6 is not set +# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_SA110=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_TEXT_SECTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +# CONFIG_KMOD is not set + +# +# General setup +# +CONFIG_NET=y +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_NWFPE=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set +# CONFIG_PARPORT is not set +CONFIG_CMDLINE="" + +# +# Plug and Play support +# +# CONFIG_PNP 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_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set +# 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=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_EMPEG_IR=y +CONFIG_EMPEG_USB=y + +# +# Video For Linux +# +CONFIG_VIDEO_DEV=y +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_GEMTEK is not set +CONFIG_RADIO_EMPEG=y +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_FILTER is not set +# CONFIG_UNIX is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_RARP is not set +# CONFIG_SKB_LARGE is not set +# CONFIG_IPV6 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# 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 +# +# CONFIG_NET_SCHED is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA subsystem support +# +# CONFIG_IRDA is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_ETHERNET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_DLCI is not set +CONFIG_PPP=y +# CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set +# CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_RCPCI is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_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_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=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_USER_BACKTRACE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge --- v2.3.22/linux/arch/arm/def-configs/footbridge Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/def-configs/footbridge Wed Oct 20 16:29:08 1999 @@ -17,22 +17,18 @@ # CONFIG_CATS is not set CONFIG_ARCH_NETWINDER=y # CONFIG_ARCH_ACORN is not set -CONFIG_PCI=y -CONFIG_ISA_DMA=y CONFIG_CPU_32=y # CONFIG_CPU_26 is not set -# CONFIG_CPU_ARM2 is not set -# CONFIG_CPU_ARM3 is not set -# CONFIG_CPU_ARM6 is not set -# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_32v4=y CONFIG_CPU_SA110=y +CONFIG_PCI=y +CONFIG_ISA_DMA=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y # CONFIG_ALIGNMENT_TRAP is not set -# CONFIG_TEXT_SECTIONS is not set # # Loadable module support @@ -55,15 +51,35 @@ # CONFIG_ARTHUR is not set CONFIG_PARPORT=y CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_PCMCIA is not set +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y CONFIG_CMDLINE="root=/dev/hda2 ro mem=32M parport=0x378,7 ide0=autotune" CONFIG_LEDS=y CONFIG_LEDS_TIMER=y # CONFIG_LEDS_CPU is not set # -# Plug and Play support +# I2O device support # -# CONFIG_PNP is not set +# 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 + +# +# Plug and Play configuration +# +CONFIG_PNP=y +CONFIG_ISAPNP=y # # Block devices @@ -76,6 +92,7 @@ # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -89,7 +106,7 @@ # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_CMD646 is not set CONFIG_BLK_DEV_SL82C105=y # CONFIG_IDE_CHIPSETS is not set @@ -136,6 +153,7 @@ CONFIG_PARIDE_KTTI=m CONFIG_PARIDE_ON20=m CONFIG_PARIDE_ON26=m +CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_BLK_DEV_HD is not set # @@ -149,15 +167,14 @@ # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_UNIX98_PTYS is not set CONFIG_PRINTER=m -CONFIG_PRINTER_READBACK=y -CONFIG_MOUSE=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set # # Mice # -# CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set @@ -172,6 +189,8 @@ CONFIG_SOFT_WATCHDOG=y # CONFIG_PCWATCHDOG is not set # CONFIG_ACQUIRE_WDT is not set +# CONFIG_21285_WATCHDOG is not set +CONFIG_977_WATCHDOG=m CONFIG_DS1620=y CONFIG_NWBUTTON=y CONFIG_NWBUTTON_REBOOT=y @@ -189,6 +208,8 @@ # # 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 @@ -196,11 +217,35 @@ # CONFIG_FTAPE is not set # +# USB drivers - not for the faint of heart +# +CONFIG_USB=m +# CONFIG_USB_UHCI is not set +CONFIG_USB_OHCI=m +CONFIG_USB_OHCI_DEBUG=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_VROOTHUB=y +# CONFIG_USB_DEBUG_ISOC is not set +CONFIG_USB_HUB=m +CONFIG_USB_MOUSE=m +CONFIG_USB_KBD=m +CONFIG_USB_AUDIO=m +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_CPIA is not set +CONFIG_USB_SCSI=m +CONFIG_USB_SCSI_DEBUG=m +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_USS720 is not set +CONFIG_USB_PROC=y + +# # Console drivers # CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set CONFIG_FB_CYBER2000=y # CONFIG_FB_MATROX is not set @@ -220,6 +265,7 @@ # CONFIG_FBCON_IPLAN2P4 is not set # CONFIG_FBCON_IPLAN2P8 is not set # CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set CONFIG_FBCON_VGA=y # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y @@ -235,8 +281,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 @@ -254,15 +301,17 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set 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 is not set +# CONFIG_DECNET is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -271,7 +320,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 @@ -284,7 +332,7 @@ # CONFIG_HAMRADIO is not set # -# IrDA subsystem support +# IrDA (infrared) support # # CONFIG_IRDA is not set @@ -292,9 +340,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y # CONFIG_ARM_AM79C961A is not set CONFIG_NET_VENDOR_3COM=y @@ -309,11 +366,12 @@ # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set +# CONFIG_SIS900 is not set # CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -332,23 +390,32 @@ # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set # CONFIG_PLIP is not set CONFIG_PPP=m - -# -# CCP compressors for PPP are only built as modules. -# +CONFIG_PPP_ASYNC=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y CONFIG_SLIP_MODE_SLIP6=y # 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_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # # SCSI support @@ -359,8 +426,10 @@ # Sound # CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_SONICVIBES is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set @@ -410,6 +479,7 @@ CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=m CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set @@ -438,12 +508,17 @@ # # Partition Types # +CONFIG_PARTITION_ADVANCED=y # CONFIG_OSF_PARTITION is not set # CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# 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 @@ -479,6 +554,7 @@ # 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=m # CONFIG_NLS_KOI8_R is not set @@ -487,7 +563,7 @@ # CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y -# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/victor linux/arch/arm/def-configs/victor --- v2.3.22/linux/arch/arm/def-configs/victor Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/def-configs/victor Wed Oct 20 16:29:08 1999 @@ -0,0 +1,207 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_FOOTBRIDGE is not set +CONFIG_ARCH_SA1100=y +CONFIG_CPU_SA1100=y +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_EMPEG is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_PLEB is not set +CONFIG_SA1100_VICTOR=y +# CONFIG_VICTOR_BOARD1 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_ISA_DMA is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM2 is not set +# CONFIG_CPU_ARM3 is not set +# CONFIG_CPU_ARM6 is not set +# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_SA110=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_TEXT_SECTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# General setup +# +# CONFIG_NET is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_NWFPE=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set +# CONFIG_PARPORT is not set +CONFIG_CMDLINE="" + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +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_IDEDISK 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 is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP 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 +# CONFIG_BLK_DEV_HD is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_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_ISO9660_FS=y +CONFIG_JOLIET=y +# 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_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ACORN_PARTITION is not set +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=y +# 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=y +# 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_15 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.3.22/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.3.22/linux/arch/arm/defconfig Sat Jun 26 08:34:19 1999 +++ linux/arch/arm/defconfig Wed Oct 20 16:29:08 1999 @@ -55,7 +55,7 @@ # CONFIG_ARTHUR is not set CONFIG_PARPORT=y CONFIG_PARPORT_PC=y -CONFIG_CMDLINE="root=/dev/hda2 ro mem=32M parport=0x378,7 ide0=autotune" +CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune" CONFIG_LEDS=y CONFIG_LEDS_TIMER=y # CONFIG_LEDS_CPU is not set @@ -89,7 +89,7 @@ # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_CMD646 is not set CONFIG_BLK_DEV_SL82C105=y # CONFIG_IDE_CHIPSETS is not set diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.3.22/linux/arch/arm/kernel/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/Makefile Wed Oct 20 16:29:08 1999 @@ -22,6 +22,7 @@ O_OBJS_ebsa110 = dma-dummy.o O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS) isa.o O_OBJS_nexuspci = dma-dummy.o +O_OBJS_sa1100 = dma-dummy.o fiq.o OX_OBJS_arc = dma.o OX_OBJS_a5k = dma.o @@ -29,11 +30,16 @@ OX_OBJS_ebsa110 = OX_OBJS_footbridge= dma.o hw-footbridge.o OX_OBJS_nexuspci = +OX_OBJS_sa1100 = all: kernel.o $(HEAD_OBJ) init_task.o O_OBJS += $(O_OBJS_$(MACHINE)) +ifeq ($(CONFIG_DEBUG_LL),y) + O_OBJS += debug-$(PROCESSOR).o +endif + ifeq ($(CONFIG_MODULES),y) OX_OBJS = armksyms.o endif @@ -42,17 +48,15 @@ OX_OBJS += ecard.o endif -ifeq ($(MACHINE),nexuspci) - ifdef CONFIG_PCI +ifeq ($(CONFIG_PCI),y) + ifeq ($(MACHINE),nexuspci) O_OBJS += plx9080.o - endif -else - ifdef CONFIG_PCI + else O_OBJS += bios32.o dec21285.o endif endif -ifdef CONFIG_LEDS +ifeq ($(CONFIG_LEDS),y) OX_OBJS += leds-$(MACHINE).o endif @@ -73,13 +77,11 @@ $(HEAD_OBJ): $(HEAD_OBJ:.o=.S) $(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ -$(ENTRY_OBJ): $(ENTRY_OBJ:.o=.S) - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $(ENTRY_OBJ:.o=.S) -o $@ - include $(TOPDIR)/Rules.make -$(ENTRY_OBJ): ../lib/constants.h +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $< # Spell out some dependencies that `make dep' doesn't spot -entry-armv.o: calls.S -entry-armo.o: calls.S +entry-armv.o: calls.S ../lib/constants.h +entry-armo.o: calls.S ../lib/constants.h diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.3.22/linux/arch/arm/kernel/armksyms.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/armksyms.c Wed Oct 20 16:29:08 1999 @@ -2,12 +2,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -93,6 +95,9 @@ EXPORT_SYMBOL(__iounmap); #endif EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(system_rev); +EXPORT_SYMBOL(system_serial_low); +EXPORT_SYMBOL(system_serial_high); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -108,7 +113,7 @@ EXPORT_SYMBOL(cpu_flush_ram_page); EXPORT_SYMBOL(cpu_flush_tlb_all); EXPORT_SYMBOL(cpu_flush_tlb_area); -EXPORT_SYMBOL(cpu_switch_mm); +EXPORT_SYMBOL(cpu_set_pgd); EXPORT_SYMBOL(cpu_set_pmd); EXPORT_SYMBOL(cpu_set_pte); EXPORT_SYMBOL(cpu_flush_icache_area); @@ -165,19 +170,20 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(__memset); +EXPORT_SYMBOL_NOVERS(memset); /* needed for some versions of gcc */ EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memzero); +EXPORT_SYMBOL_NOVERS(__memzero); /* user mem (segment) */ #if defined(CONFIG_CPU_32) EXPORT_SYMBOL(__arch_copy_from_user); EXPORT_SYMBOL(__arch_copy_to_user); EXPORT_SYMBOL(__arch_clear_user); -EXPORT_SYMBOL(__arch_strlen_user); +EXPORT_SYMBOL(__arch_strnlen_user); #elif defined(CONFIG_CPU_26) EXPORT_SYMBOL(uaccess_kernel); EXPORT_SYMBOL(uaccess_user); diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.3.22/linux/arch/arm/kernel/bios32.c Tue Sep 7 12:14:06 1999 +++ linux/arch/arm/kernel/bios32.c Wed Oct 20 16:29:08 1999 @@ -7,6 +7,7 @@ */ #include #include +#include #include #include @@ -71,6 +72,38 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553 }, { 0 } }; + +/* + * Assign new address to PCI resource. We hope our resource information + * is complete. On the PC, we don't re-assign resources unless we are + * forced to do so. + * + * Expects start=0, end=size-1, flags=resource type. + */ + +int __init pcibios_assign_resource(struct pci_dev *dev, int i) +{ + struct resource *r = &dev->resource[i]; + struct resource *pr = pci_find_parent_resource(dev, r); + unsigned long size = r->end + 1; + unsigned long flags = 0; + + if (!pr) + return -EINVAL; + if (r->flags & IORESOURCE_IO) { + if (size > 0x100) + return -EFBIG; + if (allocate_resource(pr, r, size, 0x9000, ~0, 1024)) + return -EBUSY; + flags = PCI_BASE_ADDRESS_SPACE_IO; + } else { + if (allocate_resource(pr, r, size, 0x00100000, 0x7fffffff, size)) + return -EBUSY; + } + if (i < 6) + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start | flags); + return 0; +} /* * Assign an address to an I/O range. diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/debug-armo.S linux/arch/arm/kernel/debug-armo.S --- v2.3.22/linux/arch/arm/kernel/debug-armo.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/debug-armo.S Wed Oct 20 16:29:08 1999 @@ -0,0 +1,86 @@ +/* + * linux/arch/arm/kernel/debug-armo.S + * + * Copyright (C) 1999 Russell King + * + * 26-bit debugging code + */ +#include + + .macro addruart,rx + mov \rx, #0x03000000 + orr \rx, \rx, #0x00010000 + orr \rx, \rx, #0x00000fe0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x14] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x18] + tst \rd, #0x10 + beq 1001b + .endm + + .text +/* + * Useful debugging routines + */ +ENTRY(printhex8) + mov r1, #8 + b printhex + +ENTRY(printhex4) + mov r1, #4 + b printhex + +ENTRY(printhex2) + mov r1, #2 +printhex: ldr r2, =hexbuf + add r3, r2, r1 + mov r1, #0 + strb r1, [r3] +1: and r1, r0, #15 + mov r0, r0, lsr #4 + cmp r1, #10 + addlt r1, r1, #'0' + addge r1, r1, #'a' - 10 + strb r1, [r3, #-1]! + teq r3, r2 + bne 1b + mov r0, r2 + b printascii + + .ltorg + +ENTRY(printascii) + addruart r3 + b 2f +1: waituart r2, r3 + senduart r1, r3 + busyuart r2, r3 + teq r1, #'\n' + moveq r1, #'\r' + beq 1b +2: teq r0, #0 + ldrneb r1, [r0], #1 + teqne r1, #0 + bne 1b + mov pc, lr + +ENTRY(printch) + addruart r3 + mov r1, r0 + mov r0, #0 + b 1b + + .bss +hexbuf: .space 16 diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S --- v2.3.22/linux/arch/arm/kernel/debug-armv.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/debug-armv.S Wed Oct 20 16:29:08 1999 @@ -0,0 +1,206 @@ +/* + * linux/arch/arm/kernel/debug-armv.S + * + * Copyright (C) 1994-1999 Russell King + * + * 32-bit debugging code + */ +#include +#include +#include +#include + + .text + +/* + * Some debugging routines (useful if you've got MM problems and + * printk isn't working). For DEBUGGING ONLY!!! Do not leave + * references to these in a production kernel! + */ +#if defined(CONFIG_ARCH_RPC) + .macro addruart,rx + mov \rx, #0xe0000000 + orr \rx, \rx, #0x00010000 + orr \rx, \rx, #0x00000fe0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x14] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x18] + tst \rd, #0x10 + beq 1001b + .endm + +#elif defined(CONFIG_ARCH_EBSA110) + .macro addruart,rx + mov \rx, #0xf0000000 + orr \rx, \rx, #0x00000be0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x14] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x18] + tst \rd, #0x10 + beq 1001b + .endm + +#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE) +#ifndef CONFIG_DEBUG_DC21285_PORT + /* For NetWinder debugging */ + .macro addruart,rx + mov \rx, #0xff000000 + orr \rx, \rx, #0x000003f8 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x5] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x6] + tst \rd, #0x10 + beq 1001b + .endm +#else + /* For EBSA285 debugging */ + .equ dc21285_high, ARMCSR_BASE & 0xff000000 + .equ dc21285_low, ARMCSR_BASE & 0x00ffffff + + .macro addruart,rx + mov \rx, #dc21285_high + .if dc21285_low + orr \rx, \rx, #dc21285_low + .endif + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x160] @ UARTDR + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x178] @ UARTFLG + tst \rd, #1 << 3 + bne 1001b + .endm + + .macro waituart,rd,rx + .endm +#endif +#elif defined(CONFIG_ARCH_NEXUSPCI) + .macro addruart,rx + ldr \rx, =0xfff00000 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0xc] + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x4] + tst \rd, #1 << 0 + bne 1001b + .endm + + .macro waituart,rd,rx + .endm + +#elif defined(CONFIG_ARCH_SA1100) + .macro addruart,rx + mov \rx, #0xf8000000 + add \rx, \rx, #0x00050000 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x14] @ UARTDR + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x20] @ UTSR1 + tst \rd, #1 << 2 + beq 1001b + .endm + +#else +#error Unknown architecture +#endif + +/* + * Useful debugging routines + */ +ENTRY(printhex8) + mov r1, #8 + b printhex + +ENTRY(printhex4) + mov r1, #4 + b printhex + +ENTRY(printhex2) + mov r1, #2 +printhex: ldr r2, =hexbuf + add r3, r2, r1 + mov r1, #0 + strb r1, [r3] +1: and r1, r0, #15 + mov r0, r0, lsr #4 + cmp r1, #10 + addlt r1, r1, #'0' + addge r1, r1, #'a' - 10 + strb r1, [r3, #-1]! + teq r3, r2 + bne 1b + mov r0, r2 + b printascii + + .ltorg + +ENTRY(printascii) + addruart r3 + b 2f +1: waituart r2, r3 + senduart r1, r3 + busyuart r2, r3 + teq r1, #'\n' + moveq r1, #'\r' + beq 1b +2: teq r0, #0 + ldrneb r1, [r0], #1 + teqne r1, #0 + bne 1b + mov pc, lr + +ENTRY(printch) + addruart r3 + mov r1, r0 + mov r0, #0 + b 1b + + .bss +hexbuf: .space 16 diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.3.22/linux/arch/arm/kernel/dec21285.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/dec21285.c Wed Oct 20 16:29:08 1999 @@ -13,241 +13,318 @@ #include #include +#include +#include #include #include -#include #define MAX_SLOTS 21 -extern void pcibios_fixup_ebsa285(struct pci_dev *dev); -extern void pcibios_init_ebsa285(void); +extern int setup_arm_irq(int, struct irqaction *); +extern void pcibios_report_device_errors(void); +extern int (*pci_irq_fixup)(struct pci_dev *dev); -int -pcibios_present(void) +static unsigned long +dc21285_base_address(struct pci_dev *dev, int where) { - return 1; + unsigned long addr = 0; + unsigned int devfn = dev->devfn; + + if (dev->bus->number != 0) + addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8); + else if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) + addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); + + return addr; } -static unsigned long -pcibios_base_address(unsigned char bus, unsigned char dev_fn) +static int +dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - if (bus == 0) { - int slot = PCI_SLOT(dev_fn); - - if (slot < MAX_SLOTS) - return PCICFG0_BASE + 0xc00000 + - (slot << 11) + (PCI_FUNC(dev_fn) << 8); - else - return 0; - } else - return PCICFG1_BASE | (bus << 16) | (dev_fn << 8); -} - -int -pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char *val) -{ - unsigned long addr = pcibios_base_address(bus, dev_fn); - unsigned char v; - - if (addr) - __asm__("ldr%?b %0, [%1, %2]" - : "=r" (v) - : "r" (addr), "r" (where)); + unsigned long addr = dc21285_base_address(dev, where); + u8 v; + + if (addr) + asm("ldr%?b %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); else v = 0xff; - *val = v; + + *value = v; + return PCIBIOS_SUCCESSFUL; } -int -pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short *val) +static int +dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); - unsigned short v; + unsigned long addr = dc21285_base_address(dev, where); + u16 v; if (addr) - __asm__("ldr%?h %0, [%1, %2]" - : "=r" (v) - : "r" (addr), "r" (where)); + asm("ldr%?h %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); else v = 0xffff; - *val = v; + + *value = v; + return PCIBIOS_SUCCESSFUL; } -int -pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int *val) +static int +dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); - unsigned int v; + unsigned long addr = dc21285_base_address(dev, where); + u32 v; if (addr) - __asm__("ldr%? %0, [%1, %2]" - : "=r" (v) - : "r" (addr), "r" (where)); + asm("ldr%? %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); else v = 0xffffffff; - *val = v; + + *value = v; + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char val) +static int +dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); + unsigned long addr = dc21285_base_address(dev, where); if (addr) - __asm__("str%?b %0, [%1, %2]" - : : "r" (val), "r" (addr), "r" (where)); + asm("str%?b %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short val) +static int +dc21285_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); + unsigned long addr = dc21285_base_address(dev, where); if (addr) - __asm__("str%?h %0, [%1, %2]" - : : "r" (val), "r" (addr), "r" (where)); + asm("str%?h %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int val) +static int +dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); + unsigned long addr = dc21285_base_address(dev, where); if (addr) - __asm__("str%? %0, [%1, %2]" - : : "r" (val), "r" (addr), "r" (where)); + asm("str%? %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + return PCIBIOS_SUCCESSFUL; } -void __init pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set) +static struct pci_ops dc21285_ops = { + dc21285_read_config_byte, + dc21285_read_config_word, + dc21285_read_config_dword, + dc21285_write_config_byte, + dc21285_write_config_word, + dc21285_write_config_dword, +}; + +/* + * Warn on PCI errors. + */ +static void +dc21285_error(int irq, void *dev_id, struct pt_regs *regs) +{ + static unsigned long next_warn; + unsigned long cmd = *CSR_PCICMD & 0x0000ffff; + unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07; + unsigned long irqstatus = *CSR_IRQ_RAWSTATUS; + int warn = time_after_eq(jiffies, next_warn); + + ctrl |= SA110_CNTL_DISCARDTIMER; + + if (warn) { + next_warn = jiffies + HZ; + printk(KERN_DEBUG "PCI: "); + } + + if (irqstatus & (1 << 31)) { + if (warn) + printk("parity error "); + cmd |= 1 << 31; + } + + if (irqstatus & (1 << 30)) { + if (warn) + printk("target abort "); + cmd |= 1 << 28; + } + + if (irqstatus & (1 << 29)) { + if (warn) + printk("master abort "); + cmd |= 1 << 29; + } + + if (irqstatus & (1 << 28)) { + if (warn) + printk("data parity error "); + cmd |= 1 << 24; + } + + if (irqstatus & (1 << 27)) { + if (warn) + printk("discard timer expired "); + ctrl &= ~SA110_CNTL_DISCARDTIMER; + } + + if (irqstatus & (1 << 23)) { + if (warn) + printk("system error "); + ctrl |= SA110_CNTL_RXSERR; + } + + if (warn) + printk("pc=[<%08lX>]\n", instruction_pointer(regs)); + + pcibios_report_device_errors(); + + *CSR_PCICMD = cmd; + *CSR_SA110_CNTL = ctrl; +} + +static struct irqaction dc21285_error_action = { + dc21285_error, SA_INTERRUPT, 0, "PCI error", NULL, NULL +}; + +static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; + +static int __init ebsa_irqval(struct pci_dev *dev) { - unsigned short cmd; + u8 pin; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd = (cmd & ~clear) | set; - pci_write_config_word(dev, PCI_COMMAND, cmd); + return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; } -void __init pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr) +static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; + +static int __init cats_irqval(struct pci_dev *dev) { - int reg = PCI_BASE_ADDRESS_0 + (idx << 2); + if (dev->irq >= 128) + return 16 + (dev->irq & 0x1f); - pci_write_config_dword(dev, reg, addr); - pci_read_config_dword(dev, reg, &addr); + switch (dev->irq) { + case 1 ... 4: + return irqmap_cats[dev->irq - 1]; - dev->base_address[idx] = addr; + default: + printk("PCI: device %02x:%02x has unknown irq line %x\n", + dev->bus->number, dev->devfn, dev->irq); + case 0: + break; + } + return 0; } -void __init pcibios_fixup(void) +static int __init netwinder_irqval(struct pci_dev *dev) { - struct pci_dev *dev; +#define DEV(v,d) ((v)<<16|(d)) + switch (DEV(dev->vendor, dev->device)) { + case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): + return IRQ_NETWINDER_ETHER100; + + case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): + return IRQ_NETWINDER_ETHER10; - for (dev = pci_devices; dev; dev = dev->next) { - pcibios_fixup_ebsa285(dev); + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553): + return 0; - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105): + return IRQ_ISA_HARDDISK1; - printk(KERN_DEBUG - "PCI: %02x:%02x [%04x/%04x] on irq %d\n", + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): + return IRQ_NETWINDER_VGA; + + default: + printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n", dev->bus->number, dev->devfn, - dev->vendor, dev->device, dev->irq); + dev->vendor, dev->device); + return 0; } - - hw_init(); } -void __init pcibios_init(void) +struct pci_ops * __init dc21285_init(int pass) { - unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET; + unsigned int mem_size; unsigned long cntl; - *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; - *CSR_SDRAMBASEOFFSET = 0; - *CSR_ROMBASEMASK = 0x80000000; - *CSR_CSRBASEMASK = 0; - *CSR_CSRBASEOFFSET = 0; - *CSR_PCIADDR_EXTN = 0; + if (pass == 0) { + mem_size = (unsigned int)high_memory - PAGE_OFFSET; + *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; + *CSR_SDRAMBASEOFFSET = 0; + *CSR_ROMBASEMASK = 0x80000000; + *CSR_CSRBASEMASK = 0; + *CSR_CSRBASEOFFSET = 0; + *CSR_PCIADDR_EXTN = 0; #ifdef CONFIG_HOST_FOOTBRIDGE - /* - * Against my better judgement, Philip Blundell still seems - * to be saying that we should initialise the PCI stuff here - * when the PCI_CFN bit is not set, dispite my comment below, - * which he decided to remove. If it is not set, then - * the card is in add-in mode, and we're in a machine where - * the bus is set up by 'others'. - * - * We should therefore not mess about with the mapping in - * anyway, and we should not be using the virt_to_bus functions - * that exist in the HOST architecture mode (since they assume - * a fixed mapping). - * - * Instead, you should be using ADDIN mode, which allows for - * this situation. This does assume that you have correctly - * initialised the PCI bus, which you must have done to get - * your PC booted. - * - * Unfortunately, he seems to be blind to this. I guess he'll - * also remove all this. - * - * And THIS COMMENT STAYS, even if this gets patched, thank - * you. - */ - - /* - * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is - * necessary, since some VGA cards forcefully use PCI addresses - * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). - * - * NOTE! If you need to chec the PCI_CFN bit in the SA110 - * control register then you've configured the kernel wrong. - * If you're not using host mode, then DO NOT set - * CONFIG_HOST_FOOTBRIDGE, but use CONFIG_ADDIN_FOOTBRIDGE - * instead. In this case, you MUST supply some firmware - * to allow your PC to boot, plus we should not modify the - * mappings that the PC BIOS has set up for us. - */ - *CSR_PCICACHELINESIZE = 0x00002008; - *CSR_PCICSRBASE = 0; - *CSR_PCICSRIOBASE = 0; - *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); - *CSR_PCIROMBASE = 0; - *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | - PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | - (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). + */ + *CSR_PCICACHELINESIZE = 0x00002008; + *CSR_PCICSRBASE = 0; + *CSR_PCICSRIOBASE = 0; + *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | + PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | + (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); #endif - /* - * Clear any existing errors - we aren't - * interested in historical data... - */ - cntl = *CSR_SA110_CNTL & 0xffffde07; - *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; - - pcibios_init_ebsa285(); + printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n", + *CSR_CLASSREV & 0xff); - printk(KERN_DEBUG"PCI: DEC21285 revision %02lX\n", *CSR_CLASSREV & 0xff); -} - -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ -} + switch (machine_arch_type) { + case MACH_TYPE_EBSA285: + pci_irq_fixup = ebsa_irqval; + break; + + case MACH_TYPE_CATS: + pci_irq_fixup = cats_irqval; + break; + + case MACH_TYPE_NETWINDER: + pci_irq_fixup = netwinder_irqval; + break; + } + + return &dc21285_ops; + } else { + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + cntl = *CSR_SA110_CNTL & 0xffffde07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + cntl = *CSR_PCICMD & 0x0000ffff; + *CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; + + /* + * Initialise PCI error IRQ after we've finished probing + */ + setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action); -char * __init pcibios_setup(char *str) -{ - return str; + return NULL; + } } diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-dummy.c linux/arch/arm/kernel/dma-dummy.c --- v2.3.22/linux/arch/arm/kernel/dma-dummy.c Fri Sep 10 23:57:27 1999 +++ linux/arch/arm/kernel/dma-dummy.c Wed Oct 20 16:29:08 1999 @@ -17,15 +17,18 @@ return -EINVAL; } -void free_dma(int channel) -{ -} - -int get_dma_list(char *buf) +int no_dma(void) { return 0; } -void __init init_dma(void) -{ -} +#define GLOBAL_ALIAS(_a,_b) asm (".set " #_a "," #_b "; .globl " #_a) +GLOBAL_ALIAS(disable_dma, no_dma); +GLOBAL_ALIAS(enable_dma, no_dma); +GLOBAL_ALIAS(free_dma, no_dma); +GLOBAL_ALIAS(get_dma_residue, no_dma); +GLOBAL_ALIAS(get_dma_list, no_dma); +GLOBAL_ALIAS(set_dma_mode, no_dma); +GLOBAL_ALIAS(set_dma_count, no_dma); +GLOBAL_ALIAS(set_dma_addr, no_dma); +GLOBAL_ALIAS(init_dma, no_dma); diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-footbridge.c linux/arch/arm/kernel/dma-footbridge.c --- v2.3.22/linux/arch/arm/kernel/dma-footbridge.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/dma-footbridge.c Wed Oct 20 16:29:08 1999 @@ -13,14 +13,11 @@ #include #include -#include -#include +#include #include -#include #include #include -#include #include "dma.h" #include "dma-isa.h" diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-isa.c linux/arch/arm/kernel/dma-isa.c --- v2.3.22/linux/arch/arm/kernel/dma-isa.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/dma-isa.c Wed Oct 20 16:29:08 1999 @@ -126,6 +126,13 @@ outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); } +static struct resource dma_resources[] = { + { "dma1", 0x0000, 0x000f }, + { "dma low page", 0x0080, 0x008f }, + { "dma2", 0x00c0, 0x00df }, + { "dma high page", 0x0480, 0x048f } +}; + int __init isa_init_dma(void) { int dmac_found; diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.3.22/linux/arch/arm/kernel/dma-rpc.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/dma-rpc.c Wed Oct 20 16:29:08 1999 @@ -357,6 +357,8 @@ } outb(tcr, IOMD_DMATCR); + + return speed; } void __init arch_dma_init(dma_t *dma) diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.3.22/linux/arch/arm/kernel/ecard.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/ecard.c Wed Oct 20 16:29:08 1999 @@ -82,7 +82,7 @@ /* List of descriptions of cards which don't have an extended * identification, or chunk directories containing a description. */ -static const struct expcard_blacklist __init blacklist[] = { +static struct expcard_blacklist __initdata blacklist[] = { { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } }; @@ -827,6 +827,8 @@ ectcr |= 1 << slot; break; #endif + default: + break; } #ifdef IOMD_ECTCR diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.3.22/linux/arch/arm/kernel/entry-armv.S Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/entry-armv.S Wed Oct 20 16:29:08 1999 @@ -298,6 +298,30 @@ .macro irq_prio_table .endm + +#elif defined(CONFIG_ARCH_SA1100) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base + mov r4, #0xfa000000 @ ICIP = 0xfa050000 + add r4, r4, #0x00050000 + ldr \irqstat, [r4] @ get irqs + ldr \irqnr, [r4, #4] @ ICMR = 0xfa050004 + ands \irqstat, \irqstat, \irqnr + mov \irqnr, #0 + beq 1002f +1001: tst \irqstat, #1 + addeq \irqnr, \irqnr, #1 + moveq \irqstat, \irqstat, lsr #1 + beq 1001b +1002: + .endm + + .macro irq_prio_table + .endm + #else #error Unknown architecture #endif @@ -449,11 +473,15 @@ add r5, sp, #S_SP mov r1, lr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + + mrs r9, cpsr @ Enable interrupts if they were tst r3, #I_BIT - mrseq r0, cpsr @ Enable interrupts if they were - biceq r0, r0, #I_BIT @ previously - msreq cpsr, r0 + biceq r9, r9, #I_BIT @ previously + mov r0, r2 +/* + * This routine must not corrupt r9 + */ #ifdef MULTI_CPU ldr r2, .LCprocfns mov lr, pc @@ -461,6 +489,7 @@ #else bl cpu_data_abort #endif + msr cpsr, r9 mov r3, sp bl SYMBOL_NAME(do_DataAbort) ldr r0, [sp, #S_PSR] @@ -544,9 +573,6 @@ #endif mov fp, #0 - mrs r2, cpsr @ Enable interrupts if they were - bic r2, r2, #I_BIT @ previously - msr cpsr, r2 #ifdef MULTI_CPU ldr r2, .LCprocfns mov lr, pc @@ -554,6 +580,10 @@ #else bl cpu_data_abort #endif + mrs r3, cpsr @ Enable interrupts if they were + bic r3, r3, #I_BIT @ previously + msr cpsr, r3 + mov r3, sp adrsvc al, lr, ret_from_sys_call b SYMBOL_NAME(do_DataAbort) diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S --- v2.3.22/linux/arch/arm/kernel/head-armo.S Thu Dec 17 09:05:42 1998 +++ linux/arch/arm/kernel/head-armo.S Wed Oct 20 16:29:08 1999 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/kernel/head.S + * linux/arch/arm/kernel/head-armo.S * * Copyright (C) 1994, 1995, 1996, 1997 Russell King * @@ -7,11 +7,13 @@ */ #include - .text - .align + .globl SYMBOL_NAME(swapper_pg_dir) + .equ SYMBOL_NAME(swapper_pg_dir), 0x0207d000 + /* * Entry point. */ + .section ".text.init",#alloc,#execinstr ENTRY(stext) ENTRY(_stext) __entry: cmp pc, #0x02000000 diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.3.22/linux/arch/arm/kernel/head-armv.S Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/head-armv.S Wed Oct 20 16:29:08 1999 @@ -1,54 +1,60 @@ /* - * linux/arch/arm/kernel/head32.S + * linux/arch/arm/kernel/head-armv.S * - * Copyright (C) 1994-1998 Russell King + * Copyright (C) 1994-1999 Russell King * - * Kernel 32 bit startup code for ARM6 / ARM7 / StrongARM + * 32-bit kernel startup code for all architectures */ #include #include + +#include #include #include +#if (TEXTADDR & 0xffff) != 0x8000 +#error TEXTADDR must start at 0xXXXX8000 +#endif + +#define SWAPPER_PGDIR_OFFSET 0x4000 + .globl SYMBOL_NAME(swapper_pg_dir) - .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 + .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x8000 + SWAPPER_PGDIR_OFFSET .section ".text.init",#alloc,#execinstr ENTRY(stext) ENTRY(_stext) -#if (TEXTADDR & 0xffff) != 0x8000 -#error TEXTADDR must start at 0xXXXX8000 -#endif - #ifdef CONFIG_ARCH_NETWINDER +/* + * Compatability cruft for old NetWinder NeTTroms. This + * code is currently scheduled for destruction in 2.5.xx + */ + .rept 8 mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 + .endr adr r2, 1f ldmdb r2, {r7, r8} - and r3, r2, #0x0000c000 - teq r3, #0x00008000 + and r3, r2, #0xc000 + teq r3, #0x8000 beq __entry bic r3, r2, #0xc000 orr r3, r3, #0x8000 mov r0, r3 - mov r4, #32 + mov r4, #64 sub r5, r8, r7 b 1f .word _stext - .word _end + .word __bss_start -1: ldmia r2!, {r6, r7, r8, r9} +1: + .rept 4 + ldmia r2!, {r6, r7, r8, r9} stmia r3!, {r6, r7, r8, r9} - subs r4, r4, #16 + .endr + subs r4, r4, #64 bcs 1b movs r4, r5 mov r5, #0 @@ -59,78 +65,114 @@ #endif /* - * Entry point and restart point. Entry *must* be called with r0 == 0, - * MMU off. Note! These should be unique!!! Please read Documentation/ARM-README - * for more information. - * - * r1 = 0 -> DEC EBSA-110 - * r1 = 1 -> Acorn RiscPC - * r1 = 2 -> ebsit - * r1 = 3 -> nexuspci - * r1 = 4 -> DEC EBSA-285 - * r1 = 5 -> Corel Netwinder - * r1 = 6 -> CATS - * r1 = 7 -> tbox - * r1 = 8 -> SA110/21285 as co-processor - * r1 = 9 -> CL-PS7110 system - * r1 = 12 -> SA1100 based system - */ + * Entry point. Entry *must* be called with r0 == 0, with the MMU off. + * r1 contains the unique architecture number. See + * linux/arch/arm/kernel/setup.c machine_desc[] array for the complete + * list. If you require a new number, please follow the instructions + * given in Documentation/ARM-README. + */ +__entry: teq r0, #0 + movne r0, #'i' + bne __error + bl __lookup_processor_type + teq r10, #0 @ invalid processor? + moveq r0, #'p' + beq __error + bl __lookup_architecture_type + teq r7, #0 @ invalid architecture? + moveq r0, #'a' + beq __error + bl __create_page_tables + adr lr, __aligned_call + add pc, r10, #12 @ flush caches (returns ctrl reg) + +__switch_data: .long __mmap_switched + .long SYMBOL_NAME(__bss_start) + .long SYMBOL_NAME(_end) + .long SYMBOL_NAME(processor_id) + .long SYMBOL_NAME(__machine_arch_type) + .long SYMBOL_NAME(cr_alignment) + .long SYMBOL_NAME(init_task_union)+8192 + + /* + * This needs to be aligned to a cache line. + */ + .align 5 +__aligned_call: + ldr lr, __switch_data +#ifdef CONFIG_ALIGNMENT_TRAP + orr r0, r0, #2 @ ...........A. +#endif + mcr p15, 0, r0, c1, c0 + mov pc, lr + + /* + * This code follows on after the page + * table switch and jump above. + * + * r0 = processor control register + * r1 = machine ID + * r9 = processor ID + */ + .align 5 +__mmap_switched: + adr r3, __switch_data + 4 + ldmia r3, {r4, r5, r6, r7, r8, sp} @ Setup stack + + mov fp, #0 @ Clear BSS +1: cmp r4, r5 + strcc fp, [r4],#4 + bcc 1b + + str r9, [r6] @ Save processor ID + str r1, [r7] @ Save machine type + bic r2, r0, #2 @ Clear 'A' bit + stmia r8, {r0, r2} @ Save control register values + b SYMBOL_NAME(start_kernel) + -__entry: teq r0, #0 @ check for illegal entry... - bne .Lerror @ loop indefinitely - cmp r1, #9 @ Unknown machine architecture - bge .Lerror -/* First thing to do is to get the page tables set up so that we can call - * the kernel in the correct place. This is relocatable code... - * - Read processor ID register (CP#15, CR0). - */ - mrc p15, 0, r9, c0, c0 @ get Processor ID -/* Values are: - * XX01XXXX = ARMv4 architecture (StrongARM) - * XX00XXXX = ARMv3 architecture - * 4156061X = ARM 610 - */ - adr r10, .LCProcTypes -1: ldmia r10!, {r5, r6, r8} @ Get Set, Mask, MMU Flags - teq r5, #0 @ End of list? - beq .Lerror - eor r5, r5, r9 - tst r5, r6 - addne r10, r10, #8 - bne 1b - adr r4, .LCMachTypes - add r4, r4, r1, lsl #4 - ldmia r4, {r4, r5, r6, r7} /* - * r4 = page dir in physical ram + * Setup the initial page tables. We only setup the barest + * amount which are required to get the kernel running, which + * generally means mapping in the kernel code. + * + * We only map in 2MB of RAM, which should be sufficient in + * all cases. + * + * r4 = physical address of page tables * r5 = physical address of start of RAM - * r6 = I/O address + * r6 = physical IO address + * r7 = byte offset into page tables for IO + * r8 = page table flags */ +__create_page_tables: mov r0, r4 mov r3, #0 - add r2, r0, #0x4000 -1: str r3, [r0], #4 @ Clear page table + add r2, r0, #0x4000 @ Clear page table +1: str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 teq r0, r2 bne 1b -/* - * Add enough entries to allow the kernel to be called. - * It will sort out the real mapping in paging_init. - * We map in 2MB of memory into (TEXTADDR-0x8000) + 2MB - */ + /* + * map in two sections (2MB) for kernel. + * these are marked cacheable and bufferable. + */ add r0, r4, #(TEXTADDR - 0x8000) >> 18 - mov r3, #0x0000000c @ SECT_CACHEABLE | SECT_BUFFERABLE + mov r3, #0x0c orr r3, r3, r8 add r3, r3, r5 str r3, [r0], #4 add r3, r3, #1 << 20 str r3, [r0], #4 - add r3, r3, #1 << 20 #ifdef CONFIG_DEBUG_LL -/* Map in IO space - * This allows debug messages to be output via a serial - * before/while paging_init. - */ + /* + * Map in IO space for serial debugging. + * This allows debug messages to be output + * via a serial before paging_init. + */ add r0, r4, r7 orr r3, r6, r8 add r2, r0, #0x0800 @@ -147,45 +189,39 @@ str r3, [r0], #4 add r3, r3, #1 << 20 str r3, [r0], #4 -1: #endif #endif #ifdef CONFIG_ARCH_RPC -/* Map in screen at 0x02000000 & SCREEN2_BASE - * Similar reasons here - for debug, and when things go - * wrong to a certain extent. This is of limited use to - * non-Acorn RiscPC architectures though. - */ + /* + * Map in screen at 0x02000000 & SCREEN2_BASE + * Similar reasons here - for debug. This is + * only for Acorn RiscPC architectures. + */ teq r5, #0 - addne r0, r4, #0x80 @ 02000000 + addne r0, r4, #0x80 @ 02000000 movne r3, #0x02000000 orrne r3, r3, r8 strne r3, [r0] - addne r0, r4, #0x3600 @ d8000000 + addne r0, r4, #0x3600 @ d8000000 strne r3, [r0] #endif - b aligned_call -/* - * The following should work on both v3 and v4 implementations - * Note: it seems that if the mov pc,lr is on the next cache - * line, it doesn't get fetched before the MMU starts - * translating, which prevents the kernel from booting. - * Ensure that this never happens. - */ - .align 5 -aligned_call: - mov lr, pc - mov pc, r10 @ Call processor flush (returns ctrl reg) - adr r5, __entry - sub r10, r10, r5 @ Make r10 PIC - ldr lr, .Lbranch - mcr p15, 0, r0, c1, c0 @ Enable MMU & caches. In 3 instructions - @ we lose this page! mov pc, lr -.Lerror: + + +/* + * Exception handling. Something went wrong and we can't + * proceed. We ought to tell the user, but since we + * don't have any guarantee that we're even running on + * the right architecture, we do virtually nothing. + * r0 = ascii error character + * + * Generally, only serious errors cause this. + */ +__error: #ifdef CONFIG_ARCH_RPC -/* Turn the screen red on a error - RiscPC only. +/* + * Turn the screen red on a error - RiscPC only. */ mov r0, #0x02000000 mov r3, #0x11 @@ -199,356 +235,171 @@ 1: mov r0, r0 b 1b -.Lbranch: .long .Lalready_done_mmap @ Real address of routine - - @ DEC EBSA110 (pg dir phys, phys ram start, phys i/o) -.LCMachTypes: .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0xe0000000 @ I/O address - .long 0x3800 - - @ Acorn RiscPC - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x10000000 - .long 0x10000000 - .long 0x03000000 - .long 0x3800 - - @ EBSIT ??? - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 - .long 0 - .long 0xe0000000 - .long 0x3800 - - @ NexusPCI - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x40000000 - .long 0x40000000 - .long 0x10000000 - .long 0x3800 - - @ DEC EBSA285 - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0x24000000 @ I/O base address (0x42000000 -> 0xFE000000) - .long 0x3800 - - @ Corel VNC - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) - .long 0x3800 - - @ CATS - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) - .long 0x3800 - - @ tbox - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x80000000 - .long 0x80000000 @ Address of RAM - .long 0x00400000 @ Uart - .long 0x3800 - - @ DEC EBSA285 as co-processor - .long 0x4000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long DC21285_ARMCSR_BASE @ Physical I/O base address - .long 0x7cf00000 >> 18 @ Virtual I/O base address - @ SA1100 - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0xc0000000 - .long 0xc0000000 - .long 0x80000000 @ IO mapping will change when kernel gets on its feet - .long 0x3800 -.LCProcTypes: @ ARM6 / 610 - .long 0x41560600 - .long 0xffffff00 - .long 0x00000c12 - b .Larmv3_flush_early @ arm v3 flush & ctrl early setup +/* + * Read processor ID register (CP#15, CR0), and determine + * processor type. + * + * Returns: + * r5, r6, r7 corrupted + * r8 = page table flags + * r9 = processor ID + * r10 = pointer to processor structure + */ +__lookup_processor_type: + adr r5, 2f + ldmia r5, {r7, r9, r10} + sub r5, r5, r9 + add r7, r7, r5 + add r10, r10, r5 + mrc p15, 0, r9, c0, c0 @ get processor id +1: ldmia r10, {r5, r6, r8} @ value, mask, mmuflags + eor r5, r5, r9 + tst r5, r6 + moveq pc, lr + add r10, r10, #36 @ sizeof(proc_info_list) + cmp r10, r7 + blt 1b + mov r10, #0 mov pc, lr - @ ARM7 - .long 0x41007000 - .long 0xfffff000 - .long 0x00000c12 - b .Larmv3_flush_late @ arm v3 flush & ctrl late setup - mov pc, lr +2: .long __proc_info_end + .long 2b + .long __proc_info_begin - @ ARM710 - .long 0x41007000 - .long 0xfff8f000 @ arm710 processors are weird - .long 0x00000c12 - b .Larmv3_flush_late @ arm v3 flush & ctrl late setup +/* + * Lookup machine architecture + * r1 = machine architecture number + * Returns: + * r4 = physical address of page tables + * r5 = physical start address of RAM + * r6 = physical address of IO + * r7 = byte offset into page tables for IO + */ +__lookup_architecture_type: + cmp r1, #(__arch_types_end - __arch_types_start) / 16 + bge 1f + adr r4, __arch_types_start + add r4, r4, r1, lsl #4 + ldmia r4, {r4, r5, r6, r7} + add r4, r5, #SWAPPER_PGDIR_OFFSET + mov r7, r7, lsr #18 mov pc, lr - - @ StrongARM-110 and StrongARM-1100 - .long 0x4401a100 @ 4401a100 and 4401a110 - .long 0xffffffe0 - .long 0x00000c02 - b .Larmv4_flush_early - b .Lsa_fastclock - - .long 0 - .align - -.Larmv3_flush_early: - mov r0, #0 - mcr p15, 0, r0, c7, c0 @ flush caches on v3 - mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 - mcr p15, 0, r4, c2, c0 @ load page table pointer - mov r0, #0x1f @ Domains 0, 1 = client - mcr p15, 0, r0, c3, c0 @ load domain access register -#ifdef CONFIG_ALIGNMENT_TRAP - mov r0, #0x3f @ ....S..DPWCAM -#else - mov r0, #0x3d @ ....S..DPWC.M -#endif - orr r0, r0, #0x100 +1: mov r7, #0 mov pc, lr -.Larmv3_flush_late: - mov r0, #0 - mcr p15, 0, r0, c7, c0 @ flush caches on v3 - mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 - mcr p15, 0, r4, c2, c0 @ load page table pointer - mov r0, #0x1f @ Domains 0, 1 = client - mcr p15, 0, r0, c3, c0 @ load domain access register -#ifdef CONFIG_ALIGNMENT_TRAP - mov r0, #0x7f @ ....S.LDPWCAM -#else - mov r0, #0x7d @ ....S.LDPWC.M -#endif - orr r0, r0, #0x100 - mov pc, lr +/* + * Machine parameters. Each machine requires 4 words, which are: + * + * word0: unused + * word1: physical start address of RAM + * word2: physical start address of IO + * word3: virtual start address of IO + * + * The IO mappings entered here are used to set up mappings + * required for debugging information to be shown to the user. + * paging_init() does the real page table initialisation. + */ + @ 0x00 - DEC EBSA110 +__arch_types_start: + .long 0 + .long 0 + .long 0xe0000000 + .long 0xe0000000 -.Larmv4_flush_early: - mov r0, #0 - mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4 - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 - mcr p15, 0, r0, c8, c7 @ flush I,D TLBs on v4 - mcr p15, 0, r4, c2, c0 @ load page table pointer - mov r0, #0x1f @ Domains 0, 1 = client - mcr p15, 0, r0, c3, c0 @ load domain access register - mrc p15, 0, r0, c1, c0 @ get control register v4 - bic r0, r0, #0x0e00 - bic r0, r0, #0x0002 -#ifdef CONFIG_ALIGNMENT_TRAP - orr r0, r0, #0x003f @ I...S..DPWCAM -#else - orr r0, r0, #0x003d @ I...S..DPWC.M -#endif - orr r0, r0, #0x1100 @ v4 supports separate I cache - mov pc, lr + @ 0x01 - Acorn RiscPC + .long 0 + .long 0x10000000 + .long 0x03000000 + .long 0xe0000000 -.Lsa_fastclock: mcr p15, 0, r4, c15, c1, 2 @ Enable clock switching - mov pc, lr + @ 0x02 - Unused + .long 0 + .long 0 + .long 0xe0000000 + .long 0xe0000000 -.LC0: .long SYMBOL_NAME(__entry) - .long SYMBOL_NAME(__machine_arch_type) - .long SYMBOL_NAME(__bss_start) - .long SYMBOL_NAME(processor_id) - .long SYMBOL_NAME(_end) - .long SYMBOL_NAME(cr_alignment) - .long SYMBOL_NAME(init_task_union)+8192 - .align + @ 0x03 - NexusPCI + .long 0 + .long 0x40000000 + .long 0x10000000 + .long 0xe0000000 -.Lalready_done_mmap: - adr r4, .LC0 - ldmia r4, {r3, r4, r5, r6, r7, r8, sp} @ Setup stack - add r10, r10, r3 @ Add base back in - mov fp, #0 -1: cmp r5, r7 @ Clear BSS - strcc fp, [r5],#4 - bcc 1b + @ 0x04 - DEC EBSA285 + .long 0 + .long 0 + .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) + .long 0xe0000000 - bic r2, r0, #2 @ Clear 'A' bit - stmia r8, {r0, r2} @ Save control register values + @ 0x05 - Rebel.com NetWinder + .long 0 + .long 0 + .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) + .long 0xe0000000 - str r1, [r4] @ Save machine type - str r9, [r6] @ Save processor ID - mov lr, pc - add pc, r10, #4 @ Call post-processor init - mov fp, #0 - b SYMBOL_NAME(start_kernel) + @ 0x06 - CATS + .long 0 + .long 0 + .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) + .long 0xe0000000 - .text + @ 0x07 - tbox + .long 0 + .long 0x80000000 + .long 0x00400000 @ Uart + .long 0xe0000000 -#ifdef CONFIG_DEBUG_LL -/* - * Some debugging routines (useful if you've got MM problems and - * printk isn't working). For DEBUGGING ONLY!!! Do not leave - * references to these in a production kernel! - */ -#if defined(CONFIG_ARCH_RPC) - .macro addruart,rx - mov \rx, #0xe0000000 - orr \rx, \rx, #0x00010000 - orr \rx, \rx, #0x00000fe0 - .endm - - .macro senduart,rd,rx - strb \rd, [\rx] - .endm - - .macro busyuart,rd,rx -1002: ldrb \rd, [\rx, #0x14] - and \rd, \rd, #0x60 - teq \rd, #0x60 - bne 1002b - .endm - - .macro waituart,rd,rx -1001: ldrb \rd, [\rx, #0x18] - tst \rd, #0x10 - beq 1001b - .endm - -#elif defined(CONFIG_ARCH_EBSA110) - .macro addruart,rx - mov \rx, #0xf0000000 - orr \rx, \rx, #0x00000be0 - .endm - - .macro senduart,rd,rx - strb \rd, [\rx] - .endm - - .macro busyuart,rd,rx -1002: ldrb \rd, [\rx, #0x14] - and \rd, \rd, #0x60 - teq \rd, #0x60 - bne 1002b - .endm - - .macro waituart,rd,rx -1001: ldrb \rd, [\rx, #0x18] - tst \rd, #0x10 - beq 1001b - .endm - -#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE) -#ifndef CONFIG_DEBUG_DC21285_PORT - /* For NetWinder debugging */ - .macro addruart,rx - mov \rx, #0xff000000 - orr \rx, \rx, #0x000003f8 - .endm - - .macro senduart,rd,rx - strb \rd, [\rx] - .endm - - .macro busyuart,rd,rx -1002: ldrb \rd, [\rx, #0x5] - and \rd, \rd, #0x60 - teq \rd, #0x60 - bne 1002b - .endm - - .macro waituart,rd,rx -1001: ldrb \rd, [\rx, #0x6] - tst \rd, #0x10 - beq 1001b - .endm -#else - /* For EBSA285 debugging */ - .equ dc21285_high, ARMCSR_BASE & 0xff000000 - .equ dc21285_low, ARMCSR_BASE & 0x00ffffff - - .macro addruart,rx - mov \rx, #dc21285_high - .if dc21285_low - orr \rx, \rx, #dc21285_low - .endif - .endm - - .macro senduart,rd,rx - str \rd, [\rx, #0x160] @ UARTDR - .endm - - .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #0x178] @ UARTFLG - tst \rd, #1 << 3 - bne 1001b - .endm + @ 0x08 - DEC EBSA285 as co-processor + .long 0 + .long 0 + .long DC21285_ARMCSR_BASE @ Physical I/O base address + .long 0x7cf00000 @ Virtual I/O base address - .macro waituart,rd,rx - .endm -#endif -#elif defined(CONFIG_ARCH_NEXUSPCI) - .macro addruart,rx - ldr \rx, =0xfff00000 - .endm - - .macro senduart,rd,rx - str \rd, [\rx, #0xc] - .endm - - .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #0x4] - tst \rd, #1 << 0 - bne 1001b - .endm - - .macro waituart,rd,rx - .endm -#else -#error Unknown architecture -#endif + @ 0x09 - CL-PS7110 + .long 0 + .long 0 + .long 0 + .long 0 -/* - * Useful debugging routines - */ -ENTRY(printhex8) - mov r1, #8 - b printhex - -ENTRY(printhex4) - mov r1, #4 - b printhex - -ENTRY(printhex2) - mov r1, #2 -printhex: ldr r2, =hexbuf - add r3, r2, r1 - mov r1, #0 - strb r1, [r3] -1: and r1, r0, #15 - mov r0, r0, lsr #4 - cmp r1, #10 - addlt r1, r1, #'0' - addge r1, r1, #'a' - 10 - strb r1, [r3, #-1]! - teq r3, r2 - bne 1b - mov r0, r2 - b printascii + @ 0x0a - Acorn Archimedes + .long 0 + .long 0 + .long 0 + .long 0 - .ltorg + @ 0x0b - Acorn A5000 + .long 0 + .long 0 + .long 0 + .long 0 -ENTRY(printascii) - addruart r3 - b 2f -1: waituart r2, r3 - senduart r1, r3 - busyuart r2, r3 - teq r1, #'\n' - moveq r1, #'\r' - beq 1b -2: teq r0, #0 - ldrneb r1, [r0], #1 - teqne r1, #0 - bne 1b - mov pc, lr + @ 0x0c - Etoile + .long 0 + .long 0 + .long 0 + .long 0 -ENTRY(printch) - addruart r3 - mov r1, r0 - mov r0, #0 - b 1b + @ 0x0d - LaCie_NAS + .long 0 + .long 0 + .long 0 + .long 0 - .bss -hexbuf: .space 16 + @ 0x0e - CL-PS7500 + .long 0 + .long 0 + .long 0 + .long 0 -#endif + @ 0x0f - Shark + .long 0 + .long 0 + .long 0 + .long 0 +__arch_types_end: + @ unknown - SA1100 + .long 0 + .long 0xc0000000 + .long 0x80000000 + .long 0xe0000000 diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c --- v2.3.22/linux/arch/arm/kernel/hw-footbridge.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/hw-footbridge.c Wed Oct 20 16:29:08 1999 @@ -25,269 +25,8 @@ #include #define IRDA_IO_BASE 0x180 -#define ETHER10_IO_BASE 0x301 #define GP1_IO_BASE 0x338 #define GP2_IO_BASE 0x33a -#define DEC21143_IO_BASE 0x401 -#define DEC21143_MEM_BASE 0x00800000 -#define CYBER2000_MEM_BASE 0x01000000 - -int have_isa_bridge; - -extern int setup_arm_irq(int, struct irqaction *); -extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set); -extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr); -extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq); -extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); - -#ifdef CONFIG_PCI - -static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; - -static int __init ebsa_irqval(struct pci_dev *dev) -{ - unsigned char pin; - - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_PIN, - &pin); - - return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; -} - -#ifdef CONFIG_CATS -static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; - -static int __init cats_irqval(struct pci_dev *dev) -{ - if (dev->irq >= 128) - return 16 + (dev->irq & 0x1f); - - switch (dev->irq) { - case 1: - case 2: - case 3: - case 4: - return irqmap_cats[dev->irq - 1]; - case 0: - return 0; - } - - printk("PCI: device %02x:%02x has unknown irq line %x\n", - dev->bus->number, dev->devfn, dev->irq); - return 0; -} -#endif - -void __init pcibios_fixup_ebsa285(struct pci_dev *dev) -{ - /* Latency timer of 32 */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); - - /* 32-byte cache line size */ - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); - - /* Set SysErr enable, Parity enable */ - pci_set_cmd(dev, 0, PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | PCI_COMMAND_PARITY); - - /* If this device is an ISA bridge, set the - * have_isa_bridge flag. We will then go looking - * for things like keyboard, etc - */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA || - (dev->class >> 8) == PCI_CLASS_BRIDGE_EISA) - have_isa_bridge = !0; - - /* sort out the irq mapping for this device */ - switch (machine_arch_type) { - case MACH_TYPE_EBSA285: - dev->irq = ebsa_irqval(dev); - /* Turn on bus mastering - boot loader doesn't - * - perhaps it should! - dag - */ - pci_set_cmd(dev, 0, PCI_COMMAND_MASTER); - break; - -#ifdef CONFIG_CATS - case MACH_TYPE_CATS: - dev->irq = cats_irqval(dev); - /* Turn on bus mastering - boot loader doesn't - * - perhaps it should! - dag - */ - pci_set_cmd(dev, 0, PCI_COMMAND_MASTER); - break; -#endif -#ifdef CONFIG_ARCH_NETWINDER - case MACH_TYPE_NETWINDER: - /* disable ROM */ - pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); - -#define DEV(v,d) ((v)<<16|(d)) - switch (DEV(dev->vendor, dev->device)) { - /* Ether 100 */ - case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): - pci_set_base_addr(dev, 0, DEC21143_IO_BASE); - pci_set_base_addr(dev, 1, DEC21143_MEM_BASE); - pci_set_cmd(dev, 0, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO); - /* Put the chip to sleep in case the driver isn't loaded */ - pci_write_config_dword(dev, 0x40, 0x80000000); - dev->irq = IRQ_NETWINDER_ETHER100; - break; - - /* Ether 10 */ - case DEV(PCI_VENDOR_ID_WINBOND2,0x5a5a): - pci_set_base_addr(dev, 0, ETHER10_IO_BASE); - pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO); - dev->irq = IRQ_NETWINDER_ETHER10; - break; - - /* ISA bridge */ - case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_83C553): - pci_set_base_addr(dev, 0, 0); - pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO); - /* - * Enable all memory requests from ISA to be channeled to PCI - */ - pci_write_config_byte(dev, 0x48, 255); - /* - * Disable ping-pong (as per errata) - */ - pci_write_config_byte(dev, 0x42, 0); - /* - * Enable PCI packet retry - */ - pci_write_config_byte(dev, 0x40, 0x22); - /* - * Do not use PCI CPU park enable, park on - * last master, disable GAT bit - */ - pci_write_config_byte(dev, 0x83, 0x02); - /* - * Default rotating priorities - */ - pci_write_config_byte(dev, 0x80, 0xe0); - /* - * Rotate bank 4 - */ - pci_write_config_byte(dev, 0x81, 0x01); - break; - - /* IDE */ - case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_82C105): - pci_set_base_addr(dev, 0, 0x1f1); - pci_set_base_addr(dev, 1, 0x3f5); - pci_set_base_addr(dev, 2, 0x171); - pci_set_base_addr(dev, 3, 0x375); - pci_set_base_addr(dev, 4, 0xe801); - pci_set_cmd(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MASTER | PCI_COMMAND_IO); - dev->irq = IRQ_ISA_HARDDISK1; - break; - - /* VGA */ - case DEV(PCI_VENDOR_ID_INTERG,0x2000): - pci_set_base_addr(dev, 0, CYBER2000_MEM_BASE); - pci_set_cmd(dev, PCI_COMMAND_MASTER, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - dev->irq = IRQ_NETWINDER_VGA; - break; - } -#endif - } -} - -static inline void -report_pci_dev_error(void) -{ - struct pci_dev *dev; - - for (dev = pci_devices; dev; dev = dev->next) { - unsigned short status; - - pci_read_config_word(dev, PCI_STATUS, &status); - if (status & 0xf900) { - printk(KERN_DEBUG "PCI: [%04X:%04X] status = %X\n", - dev->vendor, dev->device, status); - - pci_write_config_word(dev, PCI_STATUS, status & 0xf900); - } - } -} -#else -#define report_pci_dev_error() -#endif - -/* - * Warn on PCI errors. Please report any occurances! - */ -static void -irq_pci_err(int irq, void *dev_id, struct pt_regs *regs) -{ - static unsigned long next_warn; - unsigned long cmd = *CSR_PCICMD & 0x0000ffff; - unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07; - unsigned long irqstatus = *CSR_IRQ_RAWSTATUS; - int warn = time_after_eq(jiffies, next_warn); - - ctrl |= SA110_CNTL_DISCARDTIMER; - - if (warn) { - next_warn = jiffies + 3 * HZ / 100; - printk(KERN_DEBUG "PCI: "); - } - - if (irqstatus & (1 << 31)) { - if (warn) - printk("parity error "); - cmd |= 1 << 31; - } - - if (irqstatus & (1 << 30)) { - if (warn) - printk("target abort "); - cmd |= 1 << 28; - } - - if (irqstatus & (1 << 29)) { - if (warn) - printk("master abort "); - cmd |= 1 << 29; - } - - if (irqstatus & (1 << 28)) { - if (warn) - printk("data parity error "); - cmd |= 1 << 24; - } - - if (irqstatus & (1 << 27)) { - if (warn) - printk("discard timer expired "); - ctrl &= ~SA110_CNTL_DISCARDTIMER; - } - - if (irqstatus & (1 << 23)) { - if (warn) - printk("system error "); - ctrl |= SA110_CNTL_RXSERR; - } - - if (warn) - printk("pc=[<%08lX>]\n", instruction_pointer(regs)); - - report_pci_dev_error(); - - *CSR_PCICMD = cmd; - *CSR_SA110_CNTL = ctrl; -} - -static struct irqaction irq_pci_error = { - irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL -}; - -void __init pcibios_init_ebsa285(void) -{ - setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error); -} /* * Netwinder stuff @@ -627,7 +366,7 @@ current_cpld = (current_cpld & ~mask) | set; - gpio_modify_io(GPIO_DATA, 0); + gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0); gpio_modify_op(GPIO_IOLOAD, 0); for (msk = 8; msk; msk >>= 1) { @@ -647,7 +386,7 @@ unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); - cpld_modify(-1, CPLD_UNMUTE | 4); + cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE); spin_unlock_irqrestore(&gpio_lock, flags); } @@ -713,12 +452,15 @@ dprintk("Card no = %d\n", inb(0x203)); + /* disable the modem section of the chip */ WRITE_RWA(7, 3); WRITE_RWA(0x30, 0); + /* disable the cdrom section of the chip */ WRITE_RWA(7, 4); WRITE_RWA(0x30, 0); + /* disable the MPU-401 section of the chip */ WRITE_RWA(7, 2); WRITE_RWA(0x30, 0); } @@ -925,6 +667,7 @@ extern void register_isa_ports(unsigned int, unsigned int, unsigned int); register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); + #ifdef CONFIG_ARCH_NETWINDER /* * this ought to have a better home... diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c --- v2.3.22/linux/arch/arm/kernel/init_task.c Mon Jul 26 22:41:09 1999 +++ linux/arch/arm/kernel/init_task.c Wed Oct 20 16:29:08 1999 @@ -1,4 +1,5 @@ #include +#include #include #include diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/ioport.c linux/arch/arm/kernel/ioport.c --- v2.3.22/linux/arch/arm/kernel/ioport.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/ioport.c Wed Oct 20 16:29:08 1999 @@ -9,10 +9,12 @@ #include #include #include +#include #include #include +#ifdef CONFIG_CPU_32 asmlinkage int sys_iopl(unsigned long turn_on) { if (turn_on && !capable(CAP_SYS_RAWIO)) @@ -25,3 +27,9 @@ return 0; } +#else +asmlinkage int sys_iopl(unsigned long turn_on) +{ + return -ENOSYS; +} +#endif diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.3.22/linux/arch/arm/kernel/irq.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/irq.c Wed Oct 20 16:29:08 1999 @@ -494,8 +494,5 @@ } irq_init_irq(); -#ifdef CONFIG_ARCH_ACORN - init_FIQ(); -#endif init_dma(); } diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c --- v2.3.22/linux/arch/arm/kernel/leds-footbridge.c Fri Sep 10 23:57:27 1999 +++ linux/arch/arm/kernel/leds-footbridge.c Wed Oct 20 16:29:08 1999 @@ -138,7 +138,7 @@ switch (evt) { case led_start: led_state |= LED_STATE_ENABLED; - hw_led_state = 0; + hw_led_state = GPIO_GREEN_LED; break; case led_stop: @@ -223,25 +223,19 @@ { } -void __init +static void __init init_leds_event(led_event_t evt) { - switch (machine_arch_type) { + leds_event = dummy_leds_event; + #ifdef CONFIG_FOOTBRIDGE - case MACH_TYPE_EBSA285: - case MACH_TYPE_CO285: + if (machine_is_ebsa285() || machine_is_co285()) leds_event = ebsa285_leds_event; - break; #endif #ifdef CONFIG_ARCH_NETWINDER - case MACH_TYPE_NETWINDER: + if (machine_is_netwinder()) leds_event = netwinder_leds_event; - break; #endif - - default: - leds_event = dummy_leds_event; - } leds_event(evt); } diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.3.22/linux/arch/arm/kernel/process.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/process.c Wed Oct 20 16:29:08 1999 @@ -1,7 +1,7 @@ /* * linux/arch/arm/kernel/process.c * - * Copyright (C) 1996 Russell King - Converted to ARM. + * Copyright (C) 1996-1999 Russell King - Converted to ARM. * Origional Copyright (C) 1995 Linus Torvalds */ @@ -32,6 +32,7 @@ #include #include +#include #include extern char *processor_modes[]; @@ -60,26 +61,38 @@ current->priority = 0; current->counter = -100; while (1) { - if (!current->need_resched && !hlt_counter) - proc_idle(); - schedule(); + if (!hlt_counter) + arch_do_idle(); + if (current->need_resched) { + schedule(); #ifndef CONFIG_NO_PGT_CACHE - check_pgt_cache(); + check_pgt_cache(); #endif + } } } static char reboot_mode = 'h'; -void __init reboot_setup(char *str, int *ints) +int __init reboot_setup(char *str) { reboot_mode = str[0]; + return 0; } +__setup("reboot=", reboot_setup); + void machine_restart(char * __unused) { + /* + * Turn off caches, interrupts, etc + */ + cpu_proc_fin(); + arch_reset(reboot_mode); - panic("Reboot failed\n"); + + printk("Reboot failed -- System halted\n"); + while (1); } @@ -135,6 +148,35 @@ #endif } +void show_fpregs(struct user_fp *regs) +{ + int i; + + for (i = 0; i < 8; i++) { + unsigned long *p; + char type; + + p = (unsigned long *)(regs->fpregs + i); + + switch (regs->ftype[i]) { + case 1: type = 'f'; break; + case 2: type = 'd'; break; + case 3: type = 'e'; break; + default: type = '?'; break; + } + if (regs->init_flag) + type = '?'; + + printk(" f%d(%c): %08lx %08lx %08lx%c", + i, type, p[0], p[1], p[2], i & 1 ? '\n' : ' '); + } + + + printk("FPSR: %08lx FPCR: %08lx\n", + (unsigned long)regs->fpsr, + (unsigned long)regs->fpcr); +} + /* * Task structure and kernel stack allocation. * @@ -206,6 +248,7 @@ void flush_thread(void) { memset(¤t->thread.debug, 0, sizeof(current->thread.debug)); + memset(¤t->thread.fpstate, 0, sizeof(current->thread.fpstate)); current->used_math = 0; current->flags &= ~PF_USEDFPU; } @@ -237,12 +280,10 @@ */ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) { - int fpvalid = 0; - if (current->used_math) - memcpy (fp, ¤t->thread.fpstate.soft, sizeof (fp)); + memcpy(fp, ¤t->thread.fpstate.soft, sizeof (fp)); - return fpvalid; + return current->used_math; } /* @@ -281,6 +322,7 @@ */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { + extern long sys_exit(int) __attribute__((noreturn)); pid_t __ret; __asm__ __volatile__( diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.3.22/linux/arch/arm/kernel/ptrace.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/ptrace.c Wed Oct 20 16:29:08 1999 @@ -447,8 +447,8 @@ unsigned long tmp; ret = read_long(child, addr, &tmp); - if (ret) - put_user(tmp, (unsigned long *) data); + if (!ret) + ret = put_user(tmp, (unsigned long *) data); goto out; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c --- v2.3.22/linux/arch/arm/kernel/semaphore.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/semaphore.c Wed Oct 20 16:29:08 1999 @@ -8,6 +8,7 @@ * Modified for ARM by Russell King */ #include +#include #include diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.3.22/linux/arch/arm/kernel/setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/kernel/setup.c Wed Oct 20 16:29:08 1999 @@ -10,36 +10,27 @@ */ #include -#include -#include #include #include #include -#include -#include -#include -#include -#include #include #include #include -#include #include #include -#include #include +#include #include #include #include -#include #include -#include #include #include +#ifndef MEM_SIZE #define MEM_SIZE (16*1024*1024) -#define COMMAND_LINE_SIZE 256 +#endif #ifndef CONFIG_CMDLINE #define CONFIG_CMDLINE "" @@ -50,7 +41,6 @@ #endif extern void reboot_setup(char *str, int *ints); -extern void fpe_init(void); extern void disable_hlt(void); struct drive_info_struct { char dummy[32]; } drive_info; @@ -64,10 +54,9 @@ }; extern int root_mountflags; -extern int _etext, _edata, _end; +extern int _text, _etext, _edata, _end; unsigned char aux_device_present; - char elf_platform[ELF_PLATFORM_SIZE]; unsigned int elf_hwcap; @@ -76,13 +65,16 @@ */ unsigned int processor_id; unsigned int __machine_arch_type; +unsigned int vram_size; +unsigned int system_rev; +unsigned int system_serial_low; +unsigned int system_serial_high; #ifdef MULTI_CPU struct processor processor; #endif #ifdef CONFIG_ARCH_ACORN -int memc_ctrl_reg; -int number_mfm_drives; -unsigned int vram_size; +unsigned int memc_ctrl_reg; +unsigned int number_mfm_drives; #endif static struct proc_info_item proc_info; @@ -95,39 +87,41 @@ * symbol to be empty if not configured. */ -/* - * initial ram disk - */ -#ifdef CONFIG_BLK_DEV_INITRD -static void __init -check_initrd(unsigned long mem_start, unsigned long mem_end) +static void __init setup_processor(void) { - if (initrd_end > mem_end) { - printk ("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx) - disabling initrd\n", - initrd_end, mem_end); - initrd_start = 0; - } -} + extern struct proc_info_list __proc_info_begin, __proc_info_end; + struct proc_info_list *list; -#else -#define check_initrd(ms,me) -#endif + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc-*.S + */ + for (list = &__proc_info_begin; list < &__proc_info_end ; list++) + if ((processor_id & list->cpu_mask) == list->cpu_val) + break; -void __init -setup_processor(void) -{ - armidindex = 0; + /* + * If processor type is unrecognised, then we + * can do nothing... + */ + if (list >= &__proc_info_end) { + printk("CPU configuration botched (ID %08x), unable " + "to continue.\n", processor_id); + while (1); + } - while ((armidlist[armidindex].id ^ processor_id) & - armidlist[armidindex].mask) - armidindex += 1; + proc_info = *list->info; - if (armidlist[armidindex].id == 0) - while (1); +#ifdef MULTI_CPU + processor = *list->proc; +#endif - processor = *armidlist[armidindex].proc; - processor._proc_init(); + sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); + sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); + elf_hwcap = list->elf_hwcap; + + cpu_proc_init(); } static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; @@ -135,12 +129,13 @@ char saved_command_line[COMMAND_LINE_SIZE]; static void __init -setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz) +setup_mem(char *cmd_line, unsigned long *mem_sz) { char c = ' ', *to = command_line; int len = 0; - *mem_start = (unsigned long)&_end; + if (!*mem_sz) + *mem_sz = MEM_SIZE; for (;;) { if (c == ' ') { @@ -181,24 +176,27 @@ } static void __init -setup_ram(int doload, int prompt, int image_start) +setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) { #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; extern int rd_prompt; extern int rd_image_start; + extern int rd_size; rd_image_start = image_start; rd_prompt = prompt; rd_doload = doload; + + if (rd_sz) + rd_size = rd_sz; #endif } /* * initial ram disk */ -static void __init -setup_initrd(unsigned int start, unsigned int size) +static void __init setup_initrd(unsigned int start, unsigned int size) { #ifdef CONFIG_BLK_DEV_INITRD if (start) { @@ -211,30 +209,62 @@ #endif } -#ifdef CONFIG_ARCH_ACORN -int memc_ctrl_reg; -int number_mfm_drives; -unsigned int vram_size; +static void __init check_initrd(unsigned long mem_end) +{ +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_end > mem_end) { + printk ("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx) - disabling initrd\n", + initrd_end, mem_end); + initrd_start = 0; + } #endif +} -#ifndef PARAMS_BASE -#define PARAMS_BASE NULL -#endif +/* + * Standard memory resources + */ +static struct resource system_ram = { "System RAM", 0, 0, IORESOURCE_MEM | IORESOURCE_BUSY }; +static struct resource video_ram = { "Video RAM", 0, 0, IORESOURCE_MEM }; +static struct resource kernel_code = { "Kernel code", 0, 0, IORESOURCE_MEM }; +static struct resource kernel_data = { "Kernel data", 0, 0, IORESOURCE_MEM }; +static struct resource lpt1 = { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY }; +static struct resource lpt2 = { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY }; +static struct resource lpt3 = { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }; -static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; -#define ENDIANNESS ((char)endian_test.l) +static void __init request_standard_resources(unsigned long end) +{ + kernel_code.start = __virt_to_bus((unsigned long) &_text); + kernel_code.end = __virt_to_bus((unsigned long) &_etext - 1); + kernel_data.start = __virt_to_bus((unsigned long) &_etext); + kernel_data.end = __virt_to_bus((unsigned long) &_edata - 1); + system_ram.start = __virt_to_bus(PAGE_OFFSET); + system_ram.end = __virt_to_bus(end - 1); + + request_resource(&iomem_resource, &system_ram); + request_resource(&system_ram, &kernel_code); + request_resource(&system_ram, &kernel_data); + if (video_ram.start != video_ram.end) + request_resource(&iomem_resource, &video_ram); -void __init -setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) + /* + * Some machines don't have the possibility of ever + * possessing LPT1 (lp0) and LPT3 (lp2) + */ + if (machine_is_ebsa110() || machine_is_riscpc() || + machine_is_netwinder()) + request_resource(&ioport_resource, &lpt1); + if (machine_is_riscpc()) + request_resource(&ioport_resource, &lpt2); + if (machine_is_ebsa110() || machine_is_netwinder()) + request_resource(&ioport_resource, &lpt3); +} + +void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { struct param_struct *params = (struct param_struct *)PARAMS_BASE; - static unsigned char smptrap; unsigned long memory_end = 0; - char *from = NULL; - - if (smptrap == 1) - return; - smptrap = 1; + char *from = default_command_line; #if defined(CONFIG_ARCH_ARC) __machine_arch_type = MACH_TYPE_ARCHIMEDES; @@ -244,10 +274,11 @@ setup_processor(); - init_mm.start_code = TASK_SIZE; - init_mm.end_code = TASK_SIZE + (unsigned long) &_etext; - init_mm.end_data = TASK_SIZE + (unsigned long) &_edata; - init_mm.brk = TASK_SIZE + (unsigned long) &_end; + /* + * Defaults + */ + ROOT_DEV = MKDEV(0, 255); + setup_ramdisk(1, 1, 0, 0); /* * Add your machine dependencies here @@ -256,14 +287,35 @@ case MACH_TYPE_EBSA110: /* EBSA110 locks if we execute 'wait for interrupt' */ disable_hlt(); - if (params && params->u1.s.page_size != 4096) + if (params && params->u1.s.page_size != PAGE_SIZE) params = NULL; break; +#ifdef CONFIG_ARCH_ACORN +#ifdef CONFIG_ARCH_RPC case MACH_TYPE_RISCPC: /* RiscPC can't handle half-word loads and stores */ elf_hwcap &= ~HWCAP_HALF; + { + extern void init_dram_banks(struct param_struct *); + init_dram_banks(params); + } + + switch (params->u1.s.pages_in_vram) { + case 512: + vram_size += PAGE_SIZE * 256; + case 256: + vram_size += PAGE_SIZE * 256; + default: + break; + } +#endif + case MACH_TYPE_ARCHIMEDES: + case MACH_TYPE_A5K: + memc_ctrl_reg = params->u1.s.memc_control_reg; + number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; break; +#endif case MACH_TYPE_EBSA285: if (params) { @@ -271,6 +323,8 @@ ORIG_Y = params->u1.s.video_y; ORIG_VIDEO_COLS = params->u1.s.video_num_cols; ORIG_VIDEO_LINES = params->u1.s.video_num_rows; + video_ram.start = 0x0a0000; + video_ram.end = 0x0bffff; } break; @@ -288,53 +342,67 @@ break; case MACH_TYPE_CATS: - /* CATS must use soft-reboot */ + /* CATS uses soft-reboot by default, since hard reboots + * fail on early boards. + */ reboot_setup("s", NULL); + params = NULL; + ORIG_VIDEO_LINES = 25; + ORIG_VIDEO_POINTS = 16; + ORIG_Y = 24; + video_ram.start = 0x0a0000; + video_ram.end = 0x0bffff; break; case MACH_TYPE_NETWINDER: /* * to be fixed in a future NeTTrom */ - if (params->u1.s.page_size == 4096) { + if (params->u1.s.page_size == PAGE_SIZE) { if (params->u1.s.nr_pages != 0x2000 && params->u1.s.nr_pages != 0x4000) { printk("Warning: bad NeTTrom parameters detected, using defaults\n"); - /* - * This stuff doesn't appear to be initialised - * properly by NeTTrom 2.0.6 and 2.0.7 - */ + /* + * This stuff doesn't appear to be initialised + * properly by NeTTrom 2.0.6 and 2.0.7 + */ params->u1.s.nr_pages = 0x2000; /* 32MB */ params->u1.s.ramdisk_size = 0; params->u1.s.flags = FLAG_READONLY; params->u1.s.initrd_start = 0; params->u1.s.initrd_size = 0; params->u1.s.rd_start = 0; - params->u1.s.video_x = 0; - params->u1.s.video_y = 0; - params->u1.s.video_num_cols = 80; - params->u1.s.video_num_rows = 30; } } else { printk("Warning: no NeTTrom parameter page detected, using " "compiled-in settings\n"); params = NULL; } + video_ram.start = 0x0a0000; + video_ram.end = 0x0bffff; break; default: break; } - if (params) { - memory_end = params->u1.s.page_size * - params->u1.s.nr_pages; - - ROOT_DEV = to_kdev_t(params->u1.s.rootdev); + if (params && params->u1.s.page_size != PAGE_SIZE) { + printk("Warning: wrong page size configuration, " + "trying to continue\n"); + params = NULL; + } - setup_ram((params->u1.s.flags & FLAG_RDLOAD) == 0, - (params->u1.s.flags & FLAG_RDPROMPT) == 0, - params->u1.s.rd_start); + if (params) { + memory_end = PAGE_SIZE * params->u1.s.nr_pages; + ROOT_DEV = to_kdev_t(params->u1.s.rootdev); + system_rev = params->u1.s.system_rev; + system_serial_low = params->u1.s.system_serial_low; + system_serial_high = params->u1.s.system_serial_high; + + setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0, + (params->u1.s.flags & FLAG_RDPROMPT) == 0, + params->u1.s.rd_start, + params->u1.s.ramdisk_size); setup_initrd(params->u1.s.initrd_start, params->u1.s.initrd_size); @@ -342,57 +410,27 @@ if (!(params->u1.s.flags & FLAG_READONLY)) root_mountflags &= ~MS_RDONLY; -#ifdef CONFIG_ARCH_ACORN -#ifdef CONFIG_ARCH_RPC - { - extern void init_dram_banks(struct param_struct *); - init_dram_banks(params); - } -#endif - - memc_ctrl_reg = params->u1.s.memc_control_reg; - number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; - vram_size = 0; - - switch (params->u1.s.pages_in_vram) { - case 512: - vram_size += PAGE_SIZE * 256; - case 256: - vram_size += PAGE_SIZE * 256; - default: - break; - } - - memory_end -= vram_size; -#endif - from = params->commandline; - } else { - ROOT_DEV = to_kdev_t(0x00ff); - - setup_ram(1, 1, 0); - setup_initrd(0, 0); } - if (!memory_end) - memory_end = MEM_SIZE; - - if (!from) - from = default_command_line; - -#ifdef CONFIG_NWFPE - fpe_init(); -#endif - /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, from, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - setup_mem(from, memory_start_p, &memory_end); + setup_mem(from, &memory_end); memory_end += PAGE_OFFSET; - check_initrd(*memory_start_p, memory_end); + *cmdline_p = command_line; + init_mm.start_code = (unsigned long) &_text; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + *memory_start_p = (unsigned long) &_end; + *memory_end_p = memory_end; + + request_standard_resources(memory_end); + check_initrd(memory_end); #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) @@ -401,40 +439,49 @@ conswitchp = &dummy_con; #endif #endif - - *cmdline_p = command_line; - *memory_end_p = memory_end; } static const char *machine_desc[] = { - "EBSA110", - "Acorn-RiscPC", + /* Machine name Allocater */ + "EBSA110", /* RMK */ + "Acorn-RiscPC", /* RMK */ "unknown", - "Nexus-FTV/PCI", - "EBSA285", - "Rebel-NetWinder", - "Chalice-CATS", - "unknown-TBOX", - "co-EBSA285", - "CL-PS7110", - "Acorn-Archimedes", - "Acorn-A5000" + "Nexus-FTV/PCI", /* Philip Blundell */ + "EBSA285", /* RMK */ + "Rebel-NetWinder", /* RMK */ + "Chalice-CATS", /* Philip Blundell */ + "unknown-TBOX", /* Philip Blundell */ + "co-EBSA285", /* Mark van Doesburg */ + "CL-PS7110", /* Werner Almesberger */ + "Acorn-Archimedes", /* RMK/DAG */ + "Acorn-A5000", /* RMK/PB */ + "Etoile", /* Alex de Vries */ + "LaCie_NAS", /* Benjamin Herrenschmidt */ + "CL-PS7500", /* Philip Blundell */ + "Shark" /* Alexander Schulz */ }; int get_cpuinfo(char * buffer) { - int len; + char *p = buffer; + + p += sprintf(p, "Processor\t: %s %s rev %d (%s)\n", + proc_info.manufacturer, proc_info.cpu_name, + (int)processor_id & 15, elf_platform); + + p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n", + (loops_per_sec+2500) / 500000, + ((loops_per_sec+2500) / 5000) % 100); + + p += sprintf(p, "Hardware\t: %s\n", + machine_desc[machine_arch_type]); + + p += sprintf(p, "Revision\t: %04x\n", + system_rev); + + p += sprintf(p, "Serial\t\t: %08x%08x\n", + system_serial_high, + system_serial_low); - len = sprintf(buffer, - "Processor\t: %s %s rev %d (%s)\n" - "BogoMips\t: %lu.%02lu\n" - "Hardware\t: %s\n", - proc_info.manufacturer, - proc_info.cpu_name, - (int)processor_id & 15, - elf_platform, - (loops_per_sec+2500) / 500000, - ((loops_per_sec+2500) / 5000) % 100, - machine_desc[machine_arch_type]); - return len; + return p - buffer; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.3.22/linux/arch/arm/kernel/signal.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/kernel/signal.c Wed Oct 20 16:29:08 1999 @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -550,6 +552,7 @@ default: lock_kernel(); sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c --- v2.3.22/linux/arch/arm/kernel/sys_arm.c Thu Jun 24 23:56:23 1999 +++ linux/arch/arm/kernel/sys_arm.c Wed Oct 20 16:29:08 1999 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.3.22/linux/arch/arm/kernel/traps.c Fri Sep 10 23:57:27 1999 +++ linux/arch/arm/kernel/traps.c Wed Oct 20 16:29:08 1999 @@ -365,7 +365,6 @@ { pgd_t *pgd; - printk ("current->thread.memmap = %08lX\n", current->thread.memmap); pgd = pgd_offset(current->mm, addr); printk ("*pgd = %08lx", pgd_val (*pgd)); if (!pgd_none (*pgd)) { diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.3.22/linux/arch/arm/lib/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/lib/Makefile Wed Oct 20 16:29:08 1999 @@ -1,11 +1,11 @@ # # linux/arch/arm/lib/Makefile # -# Copyright (C) 1995-1998 Russell King +# Copyright (C) 1995-1999 Russell King # L_TARGET := lib.a -L_OBJS := backtrace.o bitops.o checksum.o delay.o memcpy.o \ +L_OBJS := backtrace.o bitops.o checksum.o delay.o \ string.o system.o uaccess.o ifeq ($(PROCESSOR),armo) @@ -13,7 +13,7 @@ endif ifdef CONFIG_ARCH_ACORN - L_OBJS += loaders.o io-acorn.o + L_OBJS += io-acorn.o ifdef CONFIG_ARCH_A5K L_OBJS += floppydma.o endif @@ -34,13 +34,13 @@ include $(TOPDIR)/Rules.make +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< + constants.h: getconsdata.o extractconstants.pl $(PERL) extractconstants.pl $(OBJDUMP) > $@ getconsdata.o: getconsdata.c $(CC) $(CFLAGS) -c getconsdata.c -checksum.o: constants.h - -%.o: %.S - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< +checksum.o string.o: constants.h diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/backtrace.S linux/arch/arm/lib/backtrace.S --- v2.3.22/linux/arch/arm/lib/backtrace.S Fri May 8 00:42:38 1998 +++ linux/arch/arm/lib/backtrace.S Wed Oct 20 16:29:08 1999 @@ -21,6 +21,11 @@ mov r0, fp ENTRY(c_backtrace) + +#ifndef CONFIG_FRAME_POINTER + mov pc, lr +#else + stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... #ifdef CONFIG_CPU_32 tst r1, #0x10 @ 26 or 32-bit? @@ -103,3 +108,5 @@ .align .Ldsi: .word 0x00e92dd8 >> 2 .word 0x00e92d00 >> 2 + +#endif diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/checksum.S linux/arch/arm/lib/checksum.S --- v2.3.22/linux/arch/arm/lib/checksum.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/lib/checksum.S Wed Oct 20 16:29:08 1999 @@ -74,8 +74,9 @@ stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} .endm -#define LOAD_REGS(cond) \ - LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r8, fp, sp, pc}) + .macro load_regs,flags + ldm\flags fp, {r1, r2, r4-r8, fp, sp, pc} + .endm .macro load1b, reg1 9999: ldrbt \reg1, [r0], $1 @@ -134,8 +135,9 @@ mov r9, r9, lsr #24 .endm -#define LOAD_REGS(cond) \ - LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r9, fp, sp, pc}) + .macro load_regs,flags + ldm\flags fp, {r1, r2, r4-r9, fp, sp, pc}^ + .endm .macro load1b, reg1 tst r9, #0x01 @@ -245,7 +247,7 @@ adcs r3, r3, r4 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + load_regs eqea load1l r4 tst r2, #2 beq .exit @@ -259,11 +261,11 @@ andne r4, r4, #255 adcnes r3, r3, r4 adcs r0, r3, #0 - LOAD_REGS(al) + load_regs ea .too_small_user: teq r2, #0 - LOAD_REGS(eq) + load_regs eqea cmp r2, #2 blt .too_small_user1 load2b ip, r8 @@ -278,7 +280,7 @@ strb ip, [r1], #1 adcs r3, r3, ip .csum_exit: adc r0, r3, #0 - LOAD_REGS(al) + load_regs ea .src_not_aligned_user: cmp r2, #4 @@ -331,7 +333,7 @@ mov r4, r5, lsr #8 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + load_regs eqea tst r2, #2 beq .exit adcs r3, r3, r4, lsl #16 @@ -384,7 +386,7 @@ mov r4, r5, lsr #16 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + load_regs eqea tst r2, #2 beq .exit adcs r3, r3, r4, lsl #16 @@ -437,7 +439,7 @@ mov r4, r5, lsr #24 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + load_regs eqea tst r2, #2 beq .exit adcs r3, r3, r4, lsl #16 @@ -461,7 +463,7 @@ 6002: teq r2, r1 strneb r3, [r1], #1 bne 6002b - LOAD_REGS(al) + load_regs ea #if defined(CONFIG_CPU_32) .previous #endif diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c --- v2.3.22/linux/arch/arm/lib/getconsdata.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/lib/getconsdata.c Wed Oct 20 16:29:08 1999 @@ -6,7 +6,7 @@ #include #include #include -#include + #include #include @@ -15,13 +15,6 @@ #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) #define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n) -#ifdef KERNEL_DOMAIN -unsigned long DOM_KERNELDOMAIN = KERNEL_DOMAIN; -#endif -#ifdef USER_DOMAIN -unsigned long DOM_USERDOMAIN = USER_DOMAIN; -#endif - unsigned long TSK_STATE = OFF_TSK(state); unsigned long TSK_FLAGS = OFF_TSK(flags); unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched); @@ -34,10 +27,7 @@ unsigned long TSS_SAVE = OFF_TSK(thread.save); unsigned long TSS_FPESAVE = OFF_TSK(thread.fpstate.soft.save); -#ifdef CONFIG_CPU_26 -unsigned long TSS_MEMMAP = OFF_TSK(thread.memmap); -unsigned long TSS_MEMCMAP = OFF_TSK(thread.memcmap); -#elif defined(CONFIG_CPU_32) +#ifdef CONFIG_CPU_32 unsigned long TSS_DOMAIN = OFF_TSK(thread.domain); #endif @@ -85,6 +75,8 @@ unsigned long LPTE_EXEC = L_PTE_EXEC; unsigned long LPTE_DIRTY = L_PTE_DIRTY; #endif + +unsigned long PAGE_SZ = PAGE_SIZE; unsigned long KSWI_BASE = 0x900000; unsigned long KSWI_SYS_BASE = 0x9f0000; diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/loaders.S linux/arch/arm/lib/loaders.S --- v2.3.22/linux/arch/arm/lib/loaders.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/lib/loaders.S Wed Dec 31 16:00:00 1969 @@ -1,53 +0,0 @@ -/* - * linux/arch/arm/lib/loaders.S - * - * This file contains the ROM loaders for buggy cards - */ -#include -#include - -/* - * Oak SCSI - */ - -ENTRY(oak_scsi_loader) - b Loak_scsi_read - .word 0 -Loak_scsi_reset: bic r10, r11, #0x00ff0000 - ldr r2, [r10] - RETINSTR(mov,pc,lr) - -Loak_scsi_read: mov r2, r1, lsr #3 - and r2, r2, #15 << 9 - bic r10, r11, #0x00ff0000 - ldr r2, [r10, r2] - mov r2, r1, lsl #20 - ldrb r0, [r11, r2, lsr #18] - ldr r2, [r10] - RETINSTR(mov,pc,lr) - -ENTRY(atomwide_serial_loader) - b Latomwide_serial_read - .word 0 -Latomwide_serial_reset: mov r2, #0x3c00 - strb r2, [r11, r2] - RETINSTR(mov,pc,lr) - -Latomwide_serial_read: cmp r1, #0x8000 - RETINSTR(movhi,pc,lr) - add r0, r1, #0x800 - mov r0, r0, lsr #11 - mov r3, #0x3c00 - strb r0, [r11, r3] - mov r2, r1, lsl #21 - ldrb r0, [r11, r2, lsr #19] - strb r2, [r11, r3] - RETINSTR(mov,pc,lr) - -/* - * Cards we don't know about yet - */ -ENTRY(noloader) - mov r0, r0 - mov r0, #0 - RETINSTR(mov,pc,lr) diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S --- v2.3.22/linux/arch/arm/lib/memcpy.S Sun Apr 12 11:42:15 1998 +++ linux/arch/arm/lib/memcpy.S Wed Dec 31 16:00:00 1969 @@ -1,319 +0,0 @@ -/* - * linux/arch/arm/lib/segment.S - * - * Copyright (C) 1995, 1996 Russell King - * Except memcpy/memmove routine. - */ - -#include -#include - -#ifndef ENTRY -#define ENTRY(x...) \ - .globl _##x; \ -_##x: -#endif - - .text -#define ENTER \ - mov ip,sp ;\ - stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ - sub fp,ip,#4 - -#define EXIT \ - LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) - -#define EXITEQ \ - LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) - -# Prototype: void memcpy(void *to,const void *from,unsigned long n); -# ARM3: cant use memcopy here!!! - -ENTRY(memcpy) -ENTRY(memmove) - ENTER - cmp r1, r0 - bcc 19f - subs r2, r2, #4 - blt 6f - ands ip, r0, #3 - bne 7f - ands ip, r1, #3 - bne 8f - -1: subs r2, r2, #8 - blt 5f - subs r2, r2, #0x14 - blt 3f -2: ldmia r1!,{r3 - r9, ip} - stmia r0!,{r3 - r9, ip} - subs r2, r2, #32 - bge 2b - cmn r2, #16 - ldmgeia r1!, {r3 - r6} - stmgeia r0!, {r3 - r6} - subge r2, r2, #0x10 -3: adds r2, r2, #0x14 -4: ldmgeia r1!, {r3 - r5} - stmgeia r0!, {r3 - r5} - subges r2, r2, #12 - bge 4b -5: adds r2, r2, #8 - blt 6f - subs r2, r2, #4 - ldrlt r3, [r1], #4 - strlt r3, [r0], #4 - ldmgeia r1!, {r3, r4} - stmgeia r0!, {r3, r4} - subge r2, r2, #4 - -6: adds r2, r2, #4 - EXITEQ - cmp r2, #2 - ldrb r3, [r1], #1 - strb r3, [r0], #1 - ldrgeb r3, [r1], #1 - strgeb r3, [r0], #1 - ldrgtb r3, [r1], #1 - strgtb r3, [r0], #1 - EXIT - -7: rsb ip, ip, #4 - cmp ip, #2 - ldrb r3, [r1], #1 - strb r3, [r0], #1 - ldrgeb r3, [r1], #1 - strgeb r3, [r0], #1 - ldrgtb r3, [r1], #1 - strgtb r3, [r0], #1 - subs r2, r2, ip - blt 6b - ands ip, r1, #3 - beq 1b - -8: bic r1, r1, #3 - ldr r7, [r1], #4 - cmp ip, #2 - bgt 15f - beq 11f - cmp r2, #12 - blt 10f - sub r2, r2, #12 -9: mov r3, r7, lsr #8 - ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 - stmia r0!, {r3 - r6} - subs r2, r2, #16 - bge 9b - adds r2, r2, #12 - blt 100f -10: mov r3, r7, lsr #8 - ldr r7, [r1], #4 - orr r3, r3, r7, lsl #24 - str r3, [r0], #4 - subs r2, r2, #4 - bge 10b -100: sub r1, r1, #3 - b 6b - -11: cmp r2, #12 - blt 13f /* */ - sub r2, r2, #12 -12: mov r3, r7, lsr #16 - ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7,LSL#16 - stmia r0!, {r3 - r6} - subs r2, r2, #16 - bge 12b - adds r2, r2, #12 - blt 14f -13: mov r3, r7, lsr #16 - ldr r7, [r1], #4 - orr r3, r3, r7, lsl #16 - str r3, [r0], #4 - subs r2, r2, #4 - bge 13b -14: sub r1, r1, #2 - b 6b - -15: cmp r2, #12 - blt 17f - sub r2, r2, #12 -16: mov r3, r7, lsr #24 - ldmia r1!,{r4 - r7} - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 - stmia r0!, {r3 - r6} - subs r2, r2, #16 - bge 16b - adds r2, r2, #12 - blt 18f -17: mov r3, r7, lsr #24 - ldr r7, [r1], #4 - orr r3, r3, r7, lsl#8 - str r3, [r0], #4 - subs r2, r2, #4 - bge 17b -18: sub r1, r1, #1 - b 6b - - -19: add r1, r1, r2 - add r0, r0, r2 - subs r2, r2, #4 - blt 24f - ands ip, r0, #3 - bne 25f - ands ip, r1, #3 - bne 26f - -20: subs r2, r2, #8 - blt 23f - subs r2, r2, #0x14 - blt 22f -21: ldmdb r1!, {r3 - r9, ip} - stmdb r0!, {r3 - r9, ip} - subs r2, r2, #32 - bge 21b -22: cmn r2, #16 - ldmgedb r1!, {r3 - r6} - stmgedb r0!, {r3 - r6} - subge r2, r2, #16 - adds r2, r2, #20 - ldmgedb r1!, {r3 - r5} - stmgedb r0!, {r3 - r5} - subge r2, r2, #12 -23: adds r2, r2, #8 - blt 24f - subs r2, r2, #4 - ldrlt r3, [r1, #-4]! - strlt r3, [r0, #-4]! - ldmgedb r1!, {r3, r4} - stmgedb r0!, {r3, r4} - subge r2, r2, #4 - -24: adds r2, r2, #4 - EXITEQ - cmp r2, #2 - ldrb r3, [r1, #-1]! - strb r3, [r0, #-1]! - ldrgeb r3, [r1, #-1]! - strgeb r3, [r0, #-1]! - ldrgtb r3, [r1, #-1]! - strgtb r3, [r0, #-1]! - EXIT - -25: cmp ip, #2 - ldrb r3, [r1, #-1]! - strb r3, [r0, #-1]! - ldrgeb r3, [r1, #-1]! - strgeb r3, [r0, #-1]! - ldrgtb r3, [r1, #-1]! - strgtb r3, [r0, #-1]! - subs r2, r2, ip - blt 24b - ands ip, r1, #3 - beq 20b - -26: bic r1, r1, #3 - ldr r3, [r1], #0 - cmp ip, #2 - blt 34f - beq 30f - cmp r2, #12 - blt 28f - sub r2, r2, #12 -27: mov r7, r3, lsl #8 - ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #24 - mov r6, r6, lsl #8 - orr r6, r6, r5, lsr #24 - mov r5, r5, lsl #8 - orr r5, r5, r4, lsr #24 - mov r4, r4, lsl #8 - orr r4, r4, r3, lsr #24 - stmdb r0!, {r4, r5, r6, r7} - subs r2, r2, #16 - bge 27b - adds r2, r2, #12 - blt 29f -28: mov ip, r3, lsl #8 - ldr r3, [r1, #-4]! - orr ip, ip, r3, lsr #24 - str ip, [r0, #-4]! - subs r2, r2, #4 - bge 28b -29: add r1, r1, #3 - b 24b - -30: cmp r2, #12 - blt 32f - sub r2, r2, #12 -31: mov r7, r3, lsl #16 - ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #16 - mov r6, r6, lsl #16 - orr r6, r6, r5, lsr #16 - mov r5, r5, lsl #16 - orr r5, r5, r4, lsr #16 - mov r4, r4, lsl #16 - orr r4, r4, r3, lsr #16 - stmdb r0!, {r4, r5, r6, r7} - subs r2, r2, #16 - bge 31b - adds r2, r2, #12 - blt 33f -32: mov ip, r3, lsl #16 - ldr r3, [r1, #-4]! - orr ip, ip, r3, lsr #16 - str ip, [r0, #-4]! - subs r2, r2, #4 - bge 32b -33: add r1, r1, #2 - b 24b - -34: cmp r2, #12 - blt 36f - sub r2, r2, #12 -35: mov r7, r3, lsl #24 - ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #8 - mov r6, r6, lsl #24 - orr r6, r6, r5, lsr #8 - mov r5, r5, lsl #24 - orr r5, r5, r4, lsr #8 - mov r4, r4, lsl #24 - orr r4, r4, r3, lsr #8 - stmdb r0!, {r4, r5, r6, r7} - subs r2, r2, #16 - bge 35b - adds r2, r2, #12 - blt 37f -36: mov ip, r3, lsl #24 - ldr r3, [r1, #-4]! - orr ip, ip, r3, lsr #8 - str ip, [r0, #-4]! - subs r2, r2, #4 - bge 36b -37: add r1, r1, #1 - b 24b - - .align - diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/string.S linux/arch/arm/lib/string.S --- v2.3.22/linux/arch/arm/lib/string.S Fri May 8 00:42:38 1998 +++ linux/arch/arm/lib/string.S Wed Oct 20 16:29:08 1999 @@ -1,69 +1,112 @@ /* * linux/arch/arm/lib/string.S * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1999 Russell King * - * This is commonly used to clear the frame buffer and the frame - * backing buffer. As such, it will be rarely called with r2 < 32. + * ASM optimised string functions * - * Optimisations by Matthew Wilcox */ #include #include +#include "constants.h" + .text -# Prototype: char *strrchr(const char *s,char c); /* * Prototype: void memzero(void *d, size_t n) */ -ENTRY(memzero) - mov r2, r1 - mov r1, #0 +1: @ 4 <= r1 + cmp ip, #2 @ 1 + strltb r2, [r0], #1 @ 1 + strleb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + rsb ip, ip, #4 @ 1 + sub r1, r1, ip @ 1 + cmp r1, #3 @ 1 + bgt 2f @ 1 @ +8 + b 4f @ 1 @ +9 + + .align 5 + +ENTRY(__memzero) + mov r2, #0 @ 1 + cmp r1, #4 @ 1 + blt 4f @ 1 @ = 3 + + @ r1 >= 4 + + ands ip, r0, #3 @ 1 + bne 1b @ 1 @ = 5 + +2: @ r1 >= 4 && (r0 & 3) = 0 @ = 5 or 11 + + str lr, [sp, #-4]! @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 + + @ 4 <= r1 <= 32 @ = 9 or 15 + +3: subs r1, r1, #32 @ 1 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + bgt 3b @ 1 + LOADREGS(eqfd, sp!, {pc}) @ 1/2 + + @ -28 <= r1 <= -1 + + cmp r1, #-16 @ 1 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + ldr lr, [sp], #4 @ 1 + addlts r1, r1, #16 @ 1 + RETINSTR(moveq,pc,lr) @ 1 + + @ -12 <= r1 <= -1 + + cmp r1, #-8 @ 1 + stmgeia r0!, {r2, r3} @ 2 + addlts r1, r1, #8 @ 1 + RETINSTR(moveq,pc,lr) @ 1 + + @ -4 <= r1 <= -1 + + cmp r1, #-4 @ 1 + strge r2, [r0], #4 @ 1 + adds r1, r1, #4 @ 1 + RETINSTR(moveq,pc,lr) @ 1 + +4: @ 1 <= r1 <= 3 + cmp r1, #2 @ 1 + strgtb r2, [r0], #1 @ 1 + strgeb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + RETINSTR(mov,pc,lr) @ 1 + /* - * Prototype: void memsetl(unsigned long *d, unsigned long c, size_t n) + * StrongARM optimised copy_page routine + * now 1.72bytes/cycle, was 1.60 bytes/cycle + * (50MHz bus -> 86MB/s) */ -ENTRY(memsetl) - teq r2, #0 - RETINSTR(moveq,pc,lr) - stmfd sp!, {lr} - mov lr, r1 - mov r3, r1 - mov ip, r1 - - @ r2 = {32 ... 4} - -1: subs r2, r2, #32 - stmgeia r0!, {r1, r3, ip, lr} - stmgeia r0!, {r1, r3, ip, lr} - bgt 1b - LOADREGS(eqfd, sp!, {pc}) - - @ r2 can be {-4 ... -28} - cmp r2, #-16 - stmgeia r0!, {r1, r3, ip, lr} - addlts r2, r2, #16 - LOADREGS(eqfd, sp!, {pc}) - - @ r2 can be {-4 ... -12} - - cmp r2, #-8 - stmgeia r0!, {r1, r3} - strne r1, [r0] - LOADREGS(fd, sp!, {pc}) - - .global __page_memcpy -__page_memcpy: stmfd sp!, {r4, r5, lr} -1: subs r2, r2, #4*8 - ldmgeia r1!, {r3, r4, r5, ip} - stmgeia r0!, {r3, r4, r5, ip} - ldmgeia r1!, {r3, r4, r5, ip} - stmgeia r0!, {r3, r4, r5, ip} - bgt 1b - LOADREGS(fd, sp!, {r4, r5, pc}) - - .global memset -memset: mov r3, r0 +ENTRY(copy_page) + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/64 @ 1 +1: ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + LOADREGS(fd, sp!, {r4, pc}) @ 3 + + .align 5 +ENTRY(memset) /* needed for some versions of gcc */ +ENTRY(__memset) + mov r3, r0 cmp r2, #16 blt 6f ands ip, r3, #3 @@ -168,3 +211,309 @@ 2: movne r0, #0 subeq r0, r0, #1 LOADREGS(fd, sp!, {pc}) + + +#define ENTER \ + mov ip,sp ;\ + stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ + sub fp,ip,#4 + +#define EXIT \ + LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) + +#define EXITEQ \ + LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) + +/* + * Prototype: void memcpy(void *to,const void *from,unsigned long n); + * ARM3: cant use memcopy here!!! + */ +ENTRY(memcpy) +ENTRY(memmove) + ENTER + cmp r1, r0 + bcc 19f + subs r2, r2, #4 + blt 6f + ands ip, r0, #3 + bne 7f + ands ip, r1, #3 + bne 8f + +1: subs r2, r2, #8 + blt 5f + subs r2, r2, #0x14 + blt 3f +2: ldmia r1!,{r3 - r9, ip} + stmia r0!,{r3 - r9, ip} + subs r2, r2, #32 + bge 2b + cmn r2, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} + subge r2, r2, #0x10 +3: adds r2, r2, #0x14 +4: ldmgeia r1!, {r3 - r5} + stmgeia r0!, {r3 - r5} + subges r2, r2, #12 + bge 4b +5: adds r2, r2, #8 + blt 6f + subs r2, r2, #4 + ldrlt r3, [r1], #4 + strlt r3, [r0], #4 + ldmgeia r1!, {r3, r4} + stmgeia r0!, {r3, r4} + subge r2, r2, #4 + +6: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + EXIT + +7: rsb ip, ip, #4 + cmp ip, #2 + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + subs r2, r2, ip + blt 6b + ands ip, r1, #3 + beq 1b + +8: bic r1, r1, #3 + ldr r7, [r1], #4 + cmp ip, #2 + bgt 15f + beq 11f + cmp r2, #12 + blt 10f + sub r2, r2, #12 +9: mov r3, r7, lsr #8 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 9b + adds r2, r2, #12 + blt 100f +10: mov r3, r7, lsr #8 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl #24 + str r3, [r0], #4 + subs r2, r2, #4 + bge 10b +100: sub r1, r1, #3 + b 6b + +11: cmp r2, #12 + blt 13f /* */ + sub r2, r2, #12 +12: mov r3, r7, lsr #16 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7,LSL#16 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 12b + adds r2, r2, #12 + blt 14f +13: mov r3, r7, lsr #16 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl #16 + str r3, [r0], #4 + subs r2, r2, #4 + bge 13b +14: sub r1, r1, #2 + b 6b + +15: cmp r2, #12 + blt 17f + sub r2, r2, #12 +16: mov r3, r7, lsr #24 + ldmia r1!,{r4 - r7} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 16b + adds r2, r2, #12 + blt 18f +17: mov r3, r7, lsr #24 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl#8 + str r3, [r0], #4 + subs r2, r2, #4 + bge 17b +18: sub r1, r1, #1 + b 6b + + +19: add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 24f + ands ip, r0, #3 + bne 25f + ands ip, r1, #3 + bne 26f + +20: subs r2, r2, #8 + blt 23f + subs r2, r2, #0x14 + blt 22f +21: ldmdb r1!, {r3 - r9, ip} + stmdb r0!, {r3 - r9, ip} + subs r2, r2, #32 + bge 21b +22: cmn r2, #16 + ldmgedb r1!, {r3 - r6} + stmgedb r0!, {r3 - r6} + subge r2, r2, #16 + adds r2, r2, #20 + ldmgedb r1!, {r3 - r5} + stmgedb r0!, {r3 - r5} + subge r2, r2, #12 +23: adds r2, r2, #8 + blt 24f + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + strlt r3, [r0, #-4]! + ldmgedb r1!, {r3, r4} + stmgedb r0!, {r3, r4} + subge r2, r2, #4 + +24: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + EXIT + +25: cmp ip, #2 + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + subs r2, r2, ip + blt 24b + ands ip, r1, #3 + beq 20b + +26: bic r1, r1, #3 + ldr r3, [r1], #0 + cmp ip, #2 + blt 34f + beq 30f + cmp r2, #12 + blt 28f + sub r2, r2, #12 +27: mov r7, r3, lsl #8 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #24 + mov r6, r6, lsl #8 + orr r6, r6, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r4, lsr #24 + mov r4, r4, lsl #8 + orr r4, r4, r3, lsr #24 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 27b + adds r2, r2, #12 + blt 29f +28: mov ip, r3, lsl #8 + ldr r3, [r1, #-4]! + orr ip, ip, r3, lsr #24 + str ip, [r0, #-4]! + subs r2, r2, #4 + bge 28b +29: add r1, r1, #3 + b 24b + +30: cmp r2, #12 + blt 32f + sub r2, r2, #12 +31: mov r7, r3, lsl #16 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #16 + mov r6, r6, lsl #16 + orr r6, r6, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r4, lsr #16 + mov r4, r4, lsl #16 + orr r4, r4, r3, lsr #16 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 31b + adds r2, r2, #12 + blt 33f +32: mov ip, r3, lsl #16 + ldr r3, [r1, #-4]! + orr ip, ip, r3, lsr #16 + str ip, [r0, #-4]! + subs r2, r2, #4 + bge 32b +33: add r1, r1, #2 + b 24b + +34: cmp r2, #12 + blt 36f + sub r2, r2, #12 +35: mov r7, r3, lsl #24 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #8 + mov r6, r6, lsl #24 + orr r6, r6, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r4, lsr #8 + mov r4, r4, lsl #24 + orr r4, r4, r3, lsr #8 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 35b + adds r2, r2, #12 + blt 37f +36: mov ip, r3, lsl #24 + ldr r3, [r1, #-4]! + orr ip, ip, r3, lsr #8 + str ip, [r0, #-4]! + subs r2, r2, #4 + bge 36b +37: add r1, r1, #1 + b 24b + + .align + + diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/system.S linux/arch/arm/lib/system.S --- v2.3.22/linux/arch/arm/lib/system.S Sun Sep 6 10:44:47 1998 +++ linux/arch/arm/lib/system.S Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -/* - * linux/arch/arm/lib/system.S - * - * Copyright (C) 1995, 1996 Russell King - * - * 07/06/96: Now support tasks running in SVC mode. - */ -#include -#include - - .text - -ENTRY(abort) - adr r0, .abort_msg - mov r1, lr - b SYMBOL_NAME(panic) - -.abort_msg: .ascii "Eek! Got to an abort() from %p! " - .ascii "(Please report to rmk@arm.uk.linux.org)\n\0" - .align diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/system.c linux/arch/arm/lib/system.c --- v2.3.22/linux/arch/arm/lib/system.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/system.c Wed Oct 20 16:29:08 1999 @@ -0,0 +1,22 @@ +/* + * linux/arch/arm/lib/system.c + * + * Copyright (C) 1999 Russell King + * + * Converted from ASM version 04/09/1999 + */ +#include + +extern void abort(void) +{ + void *lr = __builtin_return_address(0); + + printk(KERN_CRIT "kernel abort from %p! (Please report to rmk@arm.linux.org.uk)\n", + lr); + + /* force an oops */ + *(int *)0 = 0; + + /* if that doesn't kill us, halt */ + panic("Oops failed to kill thread"); +} diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/uaccess-armo.S linux/arch/arm/lib/uaccess-armo.S --- v2.3.22/linux/arch/arm/lib/uaccess-armo.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/lib/uaccess-armo.S Wed Oct 20 16:29:08 1999 @@ -30,7 +30,7 @@ .word __arch_copy_to_user .word __arch_clear_user .word __arch_strncpy_from_user - .word __arch_strlen_user + .word __arch_strnlen_user @ In : r0 = x, r1 = addr, r2 = error diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S --- v2.3.22/linux/arch/arm/lib/uaccess.S Sun Sep 6 10:44:47 1998 +++ linux/arch/arm/lib/uaccess.S Wed Oct 20 16:29:08 1999 @@ -42,11 +42,11 @@ rsb ip, ip, #4 cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault sub r2, r2, ip b .c2u_dest_aligned @@ -69,8 +69,8 @@ addmi ip, r2, #4 bmi .c2u_0nowords ldr r3, [r1], #4 -USER( strt r3, [r0], #4) // May fault - mov ip, r0, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction +USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT beq .c2u_0fupi @@ -84,31 +84,31 @@ blt .c2u_0rem8lp .c2u_0cpy8lp: ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #32 bpl .c2u_0cpy8lp .c2u_0rem8lp: cmn ip, #16 ldmgeia r1!, {r3 - r6} - stmgeia r0!, {r3 - r6} // Shouldn't fault + stmgeia r0!, {r3 - r6} @ Shouldn't fault tst ip, #8 ldmneia r1!, {r3 - r4} - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 ldrne r3, [r1], #4 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_0fupi .c2u_0nowords: teq ip, #0 beq .c2u_finished .c2u_nowords: cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_not_enough: @@ -129,7 +129,7 @@ mov r3, r7, lsr #8 ldr r7, [r1], #4 orr r3, r3, r7, lsl #24 -USER( strt r3, [r0], #4) // May fault +USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -149,7 +149,7 @@ orr r5, r5, r6, lsl #24 mov r6, r6, lsr #8 orr r6, r6, r7, lsl #24 - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #16 bpl .c2u_1cpy8lp .c2u_1rem8lp: tst ip, #8 @@ -158,23 +158,23 @@ orrne r3, r3, r4, lsl #24 movne r4, r4, lsr #8 orrne r4, r4, r7, lsl #24 - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 movne r3, r7, lsr #8 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #24 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_1fupi .c2u_1nowords: mov r3, r7, lsr #8 teq ip, #0 beq .c2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault movge r3, r3, lsr #8 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault movgt r3, r3, lsr #8 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_2fupi: subs r2, r2, #4 @@ -183,7 +183,7 @@ mov r3, r7, lsr #16 ldr r7, [r1], #4 orr r3, r3, r7, lsl #16 -USER( strt r3, [r0], #4) // May fault +USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -203,7 +203,7 @@ orr r5, r5, r6, lsl #16 mov r6, r6, lsr #16 orr r6, r6, r7, lsl #16 - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #16 bpl .c2u_2cpy8lp .c2u_2rem8lp: tst ip, #8 @@ -212,23 +212,23 @@ orrne r3, r3, r4, lsl #16 movne r4, r4, lsr #16 orrne r4, r4, r7, lsl #16 - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 movne r3, r7, lsr #16 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #16 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_2fupi .c2u_2nowords: mov r3, r7, lsr #16 teq ip, #0 beq .c2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault movge r3, r3, lsr #8 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_3fupi: subs r2, r2, #4 @@ -237,7 +237,7 @@ mov r3, r7, lsr #24 ldr r7, [r1], #4 orr r3, r3, r7, lsl #8 -USER( strt r3, [r0], #4) // May fault +USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -257,7 +257,7 @@ orr r5, r5, r6, lsl #8 mov r6, r6, lsr #24 orr r6, r6, r7, lsl #8 - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #16 bpl .c2u_3cpy8lp .c2u_3rem8lp: tst ip, #8 @@ -266,23 +266,23 @@ orrne r3, r3, r4, lsl #8 movne r4, r4, lsr #24 orrne r4, r4, r7, lsl #8 - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 movne r3, r7, lsr #24 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #8 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_3fupi .c2u_3nowords: mov r3, r7, lsr #24 teq ip, #0 beq .c2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault ldrge r3, [r1], #0 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault movgt r3, r3, lsr #8 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished #ifndef TESTING @@ -302,11 +302,11 @@ .cfu_dest_not_aligned: rsb ip, ip, #4 cmp ip, #2 -USER( ldrbt r3, [r1], #1) // May fault +USER( ldrbt r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) // May fault +USER( ldrgebt r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) // May fault +USER( ldrgtbt r3, [r1], #1) @ May fault strgtb r3, [r0], #1 sub r2, r2, ip b .cfu_dest_aligned @@ -330,7 +330,7 @@ bmi .cfu_0nowords USER( ldrt r3, [r1], #4) str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction + mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT beq .cfu_0fupi @@ -343,31 +343,31 @@ subs ip, ip, #32 blt .cfu_0rem8lp -.cfu_0cpy8lp: ldmia r1!, {r3 - r6} // Shouldn't fault +.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldn't fault stmia r0!, {r3 - r6} - ldmia r1!, {r3 - r6} // Shouldn't fault + ldmia r1!, {r3 - r6} @ Shouldn't fault stmia r0!, {r3 - r6} subs ip, ip, #32 bpl .cfu_0cpy8lp .cfu_0rem8lp: cmn ip, #16 - ldmgeia r1!, {r3 - r6} // Shouldn't fault + ldmgeia r1!, {r3 - r6} @ Shouldn't fault stmgeia r0!, {r3 - r6} tst ip, #8 - ldmneia r1!, {r3 - r4} // Shouldn't fault + ldmneia r1!, {r3 - r4} @ Shouldn't fault stmneia r0!, {r3 - r4} tst ip, #4 - ldrnet r3, [r1], #4 // Shouldn't fault + ldrnet r3, [r1], #4 @ Shouldn't fault strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_0fupi .cfu_0nowords: teq ip, #0 beq .cfu_finished .cfu_nowords: cmp ip, #2 -USER( ldrbt r3, [r1], #1) // May fault +USER( ldrbt r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) // May fault +USER( ldrgebt r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) // May fault +USER( ldrgtbt r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .cfu_finished @@ -380,7 +380,7 @@ .cfu_src_not_aligned: bic r1, r1, #3 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault cmp ip, #2 bgt .cfu_3fupi beq .cfu_2fupi @@ -388,7 +388,7 @@ addmi ip, r2, #4 bmi .cfu_1nowords mov r3, r7, lsr #8 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault orr r3, r3, r7, lsl #24 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -402,7 +402,7 @@ blt .cfu_1rem8lp .cfu_1cpy8lp: mov r3, r7, lsr #8 - ldmia r1!, {r4 - r7} // Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldn't fault orr r3, r3, r4, lsl #24 mov r4, r4, lsr #8 orr r4, r4, r5, lsl #24 @@ -415,14 +415,14 @@ bpl .cfu_1cpy8lp .cfu_1rem8lp: tst ip, #8 movne r3, r7, lsr #8 - ldmneia r1!, {r4, r7} // Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldn't fault orrne r3, r3, r4, lsl #24 movne r4, r4, lsr #8 orrne r4, r4, r7, lsl #24 stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, lsr #8 -USER( ldrnet r7, [r1], #4) // May fault +USER( ldrnet r7, [r1], #4) @ May fault orrne r3, r3, r7, lsl #24 strne r3, [r0], #4 ands ip, ip, #3 @@ -442,7 +442,7 @@ addmi ip, r2, #4 bmi .cfu_2nowords mov r3, r7, lsr #16 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault orr r3, r3, r7, lsl #16 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -456,7 +456,7 @@ blt .cfu_2rem8lp .cfu_2cpy8lp: mov r3, r7, lsr #16 - ldmia r1!, {r4 - r7} // Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldn't fault orr r3, r3, r4, lsl #16 mov r4, r4, lsr #16 orr r4, r4, r5, lsl #16 @@ -469,14 +469,14 @@ bpl .cfu_2cpy8lp .cfu_2rem8lp: tst ip, #8 movne r3, r7, lsr #16 - ldmneia r1!, {r4, r7} // Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldn't fault orrne r3, r3, r4, lsl #16 movne r4, r4, lsr #16 orrne r4, r4, r7, lsl #16 stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, lsr #16 -USER( ldrnet r7, [r1], #4) // May fault +USER( ldrnet r7, [r1], #4) @ May fault orrne r3, r3, r7, lsl #16 strne r3, [r0], #4 ands ip, ip, #3 @@ -488,7 +488,7 @@ strb r3, [r0], #1 movge r3, r3, lsr #8 strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #0) // May fault +USER( ldrgtbt r3, [r1], #0) @ May fault strgtb r3, [r0], #1 b .cfu_finished @@ -496,7 +496,7 @@ addmi ip, r2, #4 bmi .cfu_3nowords mov r3, r7, lsr #24 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault orr r3, r3, r7, lsl #8 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -510,7 +510,7 @@ blt .cfu_3rem8lp .cfu_3cpy8lp: mov r3, r7, lsr #24 - ldmia r1!, {r4 - r7} // Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldn't fault orr r3, r3, r4, lsl #8 mov r4, r4, lsr #24 orr r4, r4, r5, lsl #8 @@ -523,14 +523,14 @@ bpl .cfu_3cpy8lp .cfu_3rem8lp: tst ip, #8 movne r3, r7, lsr #24 - ldmneia r1!, {r4, r7} // Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldn't fault orrne r3, r3, r4, lsl #8 movne r4, r4, lsr #24 orrne r4, r4, r7, lsl #8 stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, lsr #24 -USER( ldrnet r7, [r1], #4) // May fault +USER( ldrnet r7, [r1], #4) @ May fault orrne r3, r3, r7, lsl #8 strne r3, [r0], #4 ands ip, ip, #3 @@ -540,7 +540,7 @@ beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 -USER( ldrget r3, [r1], #0) // May fault +USER( ldrget r3, [r1], #0) @ May fault strgeb r3, [r0], #1 movgt r3, r3, lsr #8 strgtb r3, [r0], #1 @@ -553,7 +553,8 @@ data was copied. */ 9001: ldr r0, [sp], #4 ldr r1, [sp] - bl SYMBOL_NAME(memzero) + teq r1, #0 + blne SYMBOL_NAME(__memzero) LOADREGS(fd,sp!, {r0, r4 - r7, pc}) .previous #endif @@ -597,19 +598,23 @@ 9001: LOADREGS(fd,sp!, {r0, pc}) .previous -/* Prototype: int __arch_strlen_user(char *str) +/* Prototype: unsigned long __arch_strnlen_user(const char *str, long n) * Purpose : get length of a string in user memory * Params : str - address of string in user memory - * Returns : length of string *including terminator*, or zero on error + * Returns : length of string *including terminator* + * or zero on exception, or n + 1 if too long */ -ENTRY(__arch_strlen_user) +ENTRY(__arch_strnlen_user) stmfd sp!, {lr} mov r2, r0 1: -USER( ldrbt r1, [r0], #1) - teq r1, #0 +USER( ldrbt r3, [r0], #1) + teq r3, #0 + beq 2f + subs r1, r1, #1 bne 1b - sub r0, r0, r2 + add r0, r0, #1 +2: sub r0, r0, r2 LOADREGS(fd,sp!, {pc}) .section .fixup,"ax" diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.3.22/linux/arch/arm/mm/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/Makefile Wed Oct 20 16:29:08 1999 @@ -8,7 +8,8 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o +O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(PROCESSOR).o \ + small_page.o ifeq ($(CONFIG_CPU_26),y) O_OBJS += proc-arm2,3.o @@ -24,13 +25,16 @@ ifeq ($(CONFIG_CPU_SA110),y) P_OBJS += proc-sa110.o endif + ifeq ($(CONFIG_CPU_SA1100),y) + P_OBJS += proc-sa110.o + endif O_OBJS += mm-$(MACHINE).o ioremap.o $(sort $(P_OBJS)) endif include $(TOPDIR)/Rules.make -%.o: %.S - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $< # Special dependencies fault-armv.o: fault-common.c diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c --- v2.3.22/linux/arch/arm/mm/fault-armo.c Sun Jul 25 13:45:25 1999 +++ linux/arch/arm/mm/fault-armo.c Wed Oct 20 16:29:08 1999 @@ -23,61 +23,12 @@ #define FAULT_CODE_FORCECOW 0x80 #define FAULT_CODE_PREFETCH 0x04 #define FAULT_CODE_WRITE 0x02 -#define FAULT_CODE_USER 0x01 #define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) #define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) #include "fault-common.c" -static void *alloc_table(int size, int prio) -{ - if (size != 128) - printk("invalid table size\n"); - return (void *)get_page_8k(prio); -} - -void free_table(void *table) -{ - free_page_8k((unsigned long)table); -} - -pgd_t *get_pgd_slow(void) -{ - pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); - pgd_t *init; - - if (pgd) { - init = pgd_offset(&init_mm, 0); - memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); - memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); - } - return pgd; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR); - set_pmd(pmd, mk_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); - return NULL; - } - free_table((void *)pte); - if (pmd_bad(*pmd)) { - __bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - /* * Handle a data abort. Note that we have to handle a range of addresses * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force @@ -96,11 +47,11 @@ do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { #if 0 - if (the memc mapping for this page exists - can check now...) { + if (the memc mapping for this page exists) { printk ("Page in, but got abort (undefined instruction?)\n"); return 0; } #endif - do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs); + do_page_fault(addr, FAULT_CODE_PREFETCH, regs); return 1; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.3.22/linux/arch/arm/mm/fault-armv.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/fault-armv.c Wed Oct 20 16:29:08 1999 @@ -25,104 +25,12 @@ #include #define FAULT_CODE_READ 0x02 -#define FAULT_CODE_USER 0x01 #define DO_COW(m) (!((m) & FAULT_CODE_READ)) #define READ_FAULT(m) ((m) & FAULT_CODE_READ) #include "fault-common.c" -/* - * need to get a 16k page for level 1 - */ -pgd_t *get_pgd_slow(void) -{ - pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2); - pgd_t *init; - pmd_t *new_pmd; - - if (pgd) { - init = pgd_offset(&init_mm, 0); - memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); - memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); - clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR); - - /* - * On ARM, first page must always be allocated - */ - if (!pmd_alloc(pgd, 0)) - goto nomem; - else { - pmd_t *old_pmd = pmd_offset(init, 0); - new_pmd = pmd_offset(pgd, 0); - - if (!pte_alloc(new_pmd, 0)) - goto nomem_pmd; - else { - pte_t *new_pte = pte_offset(new_pmd, 0); - pte_t *old_pte = pte_offset(old_pmd, 0); - - set_pte (new_pte, *old_pte); - } - } - } - return pgd; - -nomem_pmd: - pmd_free(new_pmd); -nomem: - return NULL; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *)get_page_2k(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); - clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); - pte += PTRS_PER_PTE; - set_pmd(pmd, mk_user_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); - return NULL; - } - free_page_2k((unsigned long)pte); - if (pmd_bad(*pmd)) { - __bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *)get_page_2k(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); - clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); - pte += PTRS_PER_PTE; - set_pmd(pmd, mk_kernel_pmd(pte)); - return pte + offset; - } - set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); - return NULL; - } - free_page_2k((unsigned long)pte); - if (pmd_bad(*pmd)) { - __bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - #ifdef DEBUG static int sp_valid(unsigned long *sp) { @@ -406,6 +314,10 @@ #endif +#define BUG_PROC_MSG \ + "Buggy processor (%08X), trying to continue.\n" \ + "Please read http://www.arm.linux.org.uk/state.html for more information" + asmlinkage void do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) { @@ -416,17 +328,11 @@ /* * I want statistical information on this problem! */ - printk(KERN_ERR "Buggy processor (%08X), " - "trying to continue.\n" - "Please send contents of /proc/cpuinfo " - "and this message to linux@arm.linux.org.uk", - fsr); + printk(KERN_ERR BUG_PROC_MSG, fsr); first = 0; } return; } - - error_code |= FAULT_CODE_USER; } #define DIE(signr,nam)\ @@ -522,6 +428,6 @@ asmlinkage int do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { - do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs); + do_page_fault(addr, FAULT_CODE_READ, regs); return 1; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.3.22/linux/arch/arm/mm/fault-common.c Mon Aug 2 10:19:52 1999 +++ linux/arch/arm/mm/fault-common.c Wed Oct 20 16:29:08 1999 @@ -30,7 +30,7 @@ * This is useful to dump out the page tables associated with * 'addr' in mm 'mm'. */ -void show_pte(struct mm_struct *mm, unsigned long addr) +static void show_pte(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; @@ -62,7 +62,9 @@ pte = pte_offset(pmd, addr); printk(", *pte = %08lx", pte_val(*pte)); +#ifdef CONFIG_CPU_32 printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE])); +#endif } while(0); printk("\n"); @@ -73,7 +75,7 @@ * terminate things with extreme prejudice. */ static void -kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs, +kernel_page_fault(unsigned long addr, int write_access, struct pt_regs *regs, struct task_struct *tsk, struct mm_struct *mm) { char *reason; @@ -90,7 +92,7 @@ printk(KERN_ALERT "pgd = %p\n", mm->pgd); show_pte(mm, addr); - die("Oops", regs, mode); + die("Oops", regs, write_access); do_exit(SIGKILL); } @@ -153,7 +155,7 @@ up(&mm->mmap_sem); /* User mode accesses just cause a SIGSEGV */ - if (mode & FAULT_CODE_USER) { + if (user_mode(regs)) { tsk->thread.error_code = mode; tsk->thread.trap_no = 14; #ifdef CONFIG_DEBUG_USER @@ -194,7 +196,7 @@ force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ - if (!(mode & FAULT_CODE_USER)) + if (!user_mode(regs)) goto no_context; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.3.22/linux/arch/arm/mm/init.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/init.c Thu Oct 21 12:15:36 1999 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/init.c * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995-1999 Russell King */ #include @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_BLK_DEV_INITRD @@ -26,14 +27,18 @@ #include #include #include -#include + +#include "map.h" pgd_t swapper_pg_dir[PTRS_PER_PGD]; #ifndef CONFIG_NO_PGT_CACHE struct pgtable_cache_struct quicklists; #endif -extern char _etext, _stext, _edata, __bss_start, _end; +extern unsigned long free_area_init(unsigned long, unsigned long); +extern void show_net_buffers(void); + +extern char _etext, _text, _edata, __bss_start, _end; extern char __init_begin, __init_end; int do_check_pgt_cache(int low, int high) @@ -67,7 +72,6 @@ * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. */ -#if PTRS_PER_PTE != 1 pte_t *empty_bad_page_table; pte_t *__bad_pagetable(void) @@ -81,7 +85,6 @@ return empty_bad_page_table; } -#endif unsigned long *empty_zero_page; unsigned long *empty_bad_page; @@ -94,27 +97,39 @@ void show_mem(void) { - extern void show_net_buffers(void); - int i,free = 0,total = 0,reserved = 0; - int shared = 0; + int free = 0, total = 0, reserved = 0; + int shared = 0, cached = 0; + struct page *page, *end; printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = MAP_NR(high_memory); - while (i-- > 0) { + for (page = mem_map, end = mem_map + max_mapnr; + page < end; page++) { + if (PageSkip(page)) { + if (page->next_hash < page) + break; + page = page->next_hash; + } total++; - if (PageReserved(mem_map+i)) + if (PageReserved(page)) reserved++; - else if (!atomic_read(&mem_map[i].count)) + else if (PageSwapCache(page)) + cached++; + else if (!atomic_read(&page->count)) free++; else - shared += atomic_read(&mem_map[i].count) - 1; + shared += atomic_read(&page->count) - 1; } - printk("%d pages of RAM\n",total); - printk("%d free pages\n",free); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); + printk("%d pages of RAM\n", total); + printk("%d free pages\n", free); + printk("%d reserved pages\n", reserved); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n", cached); +#ifndef CONFIG_NO_PGT_CACHE + printk("%ld page tables cached\n", pgtable_cache_size); +#endif + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif @@ -125,25 +140,24 @@ */ unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) { - extern unsigned long free_area_init(unsigned long, unsigned long); - start_mem = PAGE_ALIGN(start_mem); + empty_zero_page = (unsigned long *)start_mem; + memzero(empty_zero_page, PAGE_SIZE); start_mem += PAGE_SIZE; + empty_bad_page = (unsigned long *)start_mem; start_mem += PAGE_SIZE; -#if PTRS_PER_PTE != 1 + #ifdef CONFIG_CPU_32 start_mem += PTRS_PER_PTE * BYTES_PER_PTR; #endif empty_bad_page_table = (pte_t *)start_mem; start_mem += PTRS_PER_PTE * BYTES_PER_PTR; -#endif - memzero (empty_zero_page, PAGE_SIZE); - start_mem = setup_pagetables (start_mem, end_mem); + + start_mem = setup_page_tables(start_mem, end_mem); flush_tlb_all(); - update_memc_all(); end_mem &= PAGE_MASK; high_memory = (void *)end_mem; @@ -151,6 +165,31 @@ return free_area_init(start_mem, end_mem); } +static inline void free_unused_mem_map(void) +{ + struct page *page, *end; + + end = mem_map + max_mapnr; + + for (page = mem_map; page < end; page++) { + unsigned long low, high; + + if (!PageSkip(page)) + continue; + + low = PAGE_ALIGN((unsigned long)(page + 1)); + if (page->next_hash < page) + high = ((unsigned long)end) & PAGE_MASK; + else + high = ((unsigned long)page->next_hash) & PAGE_MASK; + + while (low < high) { + clear_bit(PG_reserved, &mem_map[MAP_NR(low)].flags); + low += PAGE_SIZE; + } + } +} + /* * mem_init() marks the free areas in the mem_map and tells us how much * memory is free. This is done after various parts of the system have @@ -158,28 +197,48 @@ */ void __init mem_init(unsigned long start_mem, unsigned long end_mem) { - extern void sound_init(void); int codepages = 0; int reservedpages = 0; int datapages = 0; - int initpages = 0; + int initpages = 0, i, min_nr; unsigned long tmp; - end_mem &= PAGE_MASK; - high_memory = (void *)end_mem; - max_mapnr = num_physpages = MAP_NR(end_mem); + end_mem &= PAGE_MASK; + high_memory = (void *)end_mem; + max_mapnr = MAP_NR(end_mem); + num_physpages = 0; + + /* setup address validity bitmap */ + start_mem = create_mem_holes(start_mem, end_mem); + + start_mem = PAGE_ALIGN(start_mem); /* mark usable pages in the mem_map[] */ - mark_usable_memory_areas(&start_mem, end_mem); + mark_usable_memory_areas(start_mem, end_mem); + + /* free unused mem_map[] entries */ + free_unused_mem_map(); #define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \ (w) < (unsigned long)(max)) for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) { + if (PageSkip(mem_map+MAP_NR(tmp))) { + unsigned long next; + + next = mem_map[MAP_NR(tmp)].next_hash - mem_map; + + next = (next << PAGE_SHIFT) + PAGE_OFFSET; + + if (next < tmp || next >= end_mem) + break; + tmp = next; + } + num_physpages++; if (PageReserved(mem_map+MAP_NR(tmp))) { if (BETWEEN(tmp, &__init_begin, &__init_end)) initpages++; - else if (BETWEEN(tmp, &_stext, &_etext)) + else if (BETWEEN(tmp, &_text, &_etext)) codepages++; else if (BETWEEN(tmp, &_etext, &_edata)) datapages++; @@ -200,11 +259,24 @@ printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), - max_mapnr >> (20 - PAGE_SHIFT), - codepages << (PAGE_SHIFT-10), + num_physpages >> (20 - PAGE_SHIFT), + codepages << (PAGE_SHIFT-10), reservedpages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10), - initpages << (PAGE_SHIFT-10)); + datapages << (PAGE_SHIFT-10), + initpages << (PAGE_SHIFT-10)); + + i = nr_free_pages >> 7; + if (PAGE_SIZE < 32768) + min_nr = 10; + else + min_nr = 2; + if (i < min_nr) + i = min_nr; + if (i > 256) + i = 256; + freepages.min = i; + freepages.low = i * 2; + freepages.high = i * 3; #ifdef CONFIG_CPU_26 if (max_mapnr <= 128) { @@ -240,14 +312,16 @@ #ifdef CONFIG_FOOTBRIDGE { - extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end; + extern int __netwinder_begin, __netwinder_end, + __ebsa285_begin, __ebsa285_end; if (!machine_is_netwinder()) free_area((unsigned long)(&__netwinder_begin), (unsigned long)(&__netwinder_end), "netwinder"); - if (!machine_is_ebsa285() && !machine_is_cats() && !machine_is_co285()) + if (!machine_is_ebsa285() && !machine_is_cats() && + !machine_is_co285()) free_area((unsigned long)(&__ebsa285_begin), (unsigned long)(&__ebsa285_end), "ebsa285/cats"); @@ -259,22 +333,28 @@ void si_meminfo(struct sysinfo *val) { - int i; + struct page *page, *end; - i = MAP_NR(high_memory); val->totalram = 0; val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; val->bufferram = atomic_read(&buffermem); - while (i-- > 0) { - if (PageReserved(mem_map+i)) + for (page = mem_map, end = mem_map + max_mapnr; + page < end; page++) { + if (PageSkip(page)) { + if (page->next_hash < page) + break; + page = page->next_hash; + } + if (PageReserved(page)) continue; val->totalram++; - if (!atomic_read(&mem_map[i].count)) + if (!atomic_read(&page->count)) continue; - val->sharedram += atomic_read(&mem_map[i].count) - 1; + val->sharedram += atomic_read(&page->count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; + val->totalbig = 0; + val->freebig = 0; } - diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c --- v2.3.22/linux/arch/arm/mm/ioremap.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/ioremap.c Wed Oct 20 16:29:08 1999 @@ -27,8 +27,12 @@ * FIFO. Unfortunately, it is not possible to tell the DC21285 to * flush this - flushing the area causes the bus to lock. */ - +#include +#include #include + +#include +#include #include static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, @@ -145,5 +149,5 @@ void __iounmap(void *addr) { - return vfree((void *) (PAGE_MASK & (unsigned long) addr)); + vfree((void *) (PAGE_MASK & (unsigned long) addr)); } diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/map.h linux/arch/arm/mm/map.h --- v2.3.22/linux/arch/arm/mm/map.h Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/map.h Wed Oct 20 16:29:08 1999 @@ -0,0 +1,32 @@ +/* + * linux/arch/arm/mm/map.h + * + * Copyright (C) 1999 Russell King + * + * Page table mapping constructs and function prototypes + */ +struct map_desc { + unsigned long virtual; + unsigned long physical; + unsigned long length; + int domain:4, + prot_read:1, + prot_write:1, + cacheable:1, + bufferable:1; +}; + +struct mem_desc { + unsigned long virt_start; + unsigned long virt_end; +}; + +extern struct map_desc io_desc[]; +extern unsigned int io_desc_size; +extern struct mem_desc mem_desc[]; +extern unsigned int mem_desc_size; + +extern void mark_usable_memory_areas(unsigned long start, unsigned long end); +extern unsigned long create_mem_holes(unsigned long start, unsigned long end); +extern unsigned long setup_page_tables(unsigned long start, unsigned long end); + diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-armo.c linux/arch/arm/mm/mm-armo.c --- v2.3.22/linux/arch/arm/mm/mm-armo.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/mm-armo.c Wed Oct 20 16:29:08 1999 @@ -0,0 +1,170 @@ +/* + * arch/arm/mm/mm-armo.c + * + * Page table sludge for older ARM processor architectures. + * + * Copyright (C) 1998-1999 Russell King + */ +#include +#include +#include + +#include +#include +#include + +#include "map.h" + +#define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) +#define PGD_TABLE_SIZE (PTRS_PER_PGD * BYTES_PER_PTR) + +/* + * FIXME: the following over-allocates by 6400% + */ +static inline void *alloc_table(int size, int prio) +{ + if (size != 128) + printk("invalid table size\n"); + return (void *)get_page_8k(prio); +} + +/* + * Allocate a page table. Note that we place the MEMC + * table before the page directory. This means we can + * easily get to both tightly-associated data structures + * with a single pointer. This function is slightly + * better - it over-allocates by only 711% + */ +static inline void *alloc_pgd_table(int priority) +{ + unsigned long pg8k; + + pg8k = get_page_8k(priority); + if (pg8k) + pg8k += MEMC_TABLE_SIZE; + + return (void *)pg8k; +} + +void free_table(void *table) +{ + unsigned long tbl = (unsigned long)table; + + tbl &= ~8191; + free_page_8k(tbl); +} + +pgd_t *get_pgd_slow(void) +{ + pgd_t *pgd = (pgd_t *)alloc_pgd_table(GFP_KERNEL); + pmd_t *new_pmd; + + if (pgd) { + pgd_t *init = pgd_offset(&init_mm, 0); + + memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + + /* + * On ARM, first page must always be allocated + */ + if (!pmd_alloc(pgd, 0)) + goto nomem; + else { + pmd_t *old_pmd = pmd_offset(init, 0); + new_pmd = pmd_offset(pgd, 0); + + if (!pte_alloc(new_pmd, 0)) + goto nomem_pmd; + else { + pte_t *new_pte = pte_offset(new_pmd, 0); + pte_t *old_pte = pte_offset(old_pmd, 0); + + set_pte (new_pte, *old_pte); + } + } + /* update MEMC tables */ + cpu_memc_update_all(pgd); + } + return pgd; + +nomem_pmd: + pmd_free(new_pmd); +nomem: + free_table(pgd); + return NULL; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR); + set_pmd(pmd, mk_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + return NULL; + } + free_table((void *)pte); + if (pmd_bad(*pmd)) { + __bad_pmd(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +/* + * This contains the code to setup the memory map on an ARM2/ARM250/ARM3 + * machine. This is both processor & architecture specific, and requires + * some more work to get it to fit into our separate processor and + * architecture structure. + */ +int page_nr; + +#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR) + +static inline void setup_swapper_dir (int index, pte_t *ptep) +{ + set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep)); +} + +unsigned long __init +setup_page_tables(unsigned long start_mem, unsigned long end_mem) +{ + unsigned int i; + union { unsigned long l; pte_t *pte; } u; + + page_nr = MAP_NR(end_mem); + + /* map in pages for (0x0000 - 0x8000) */ + u.l = ((start_mem + (PTE_SIZE-1)) & ~(PTE_SIZE-1)); + start_mem = u.l + PTE_SIZE; + memzero (u.pte, PTE_SIZE); + u.pte[0] = mk_pte(PAGE_OFFSET + 491520, PAGE_READONLY); + setup_swapper_dir (0, u.pte); + + for (i = 1; i < PTRS_PER_PGD; i++) + pgd_val(swapper_pg_dir[i]) = 0; + + return start_mem; +} + +unsigned long __init +create_mem_holes(unsigned long start, unsigned long end) +{ + return start; +} + +void __init +mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem) +{ + while (start_mem < end_mem) { + clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); + start_mem += PAGE_SIZE; + } +} diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.3.22/linux/arch/arm/mm/mm-armv.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/mm-armv.c Wed Oct 20 16:29:08 1999 @@ -1,72 +1,375 @@ /* * arch/arm/mm/mm-armv.c * - * Common routines for ARM v3 and v4 architectures. + * Page table sludge for ARM v3 and v4 processor architectures. * - * Copyright (C) 1998 Russell King - * - * Do not compile this file directly! + * Copyright (C) 1998-1999 Russell King */ +#include +#include +#include -#ifndef MAPPING -#error MAPPING not defined - do not compile this file individually -#endif +#include +#include +#include -static const struct mapping { - unsigned long virtual; - unsigned long physical; - unsigned long length; - int domain:4, - prot_read:1, - prot_write:1; -} mapping[] __initdata = { - MAPPING -}; +#include "map.h" + +unsigned long *valid_addr_bitmap; + +/* + * need to get a 16k page for level 1 + */ +pgd_t *get_pgd_slow(void) +{ + pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2); + pmd_t *new_pmd; + + if (pgd) { + pgd_t *init = pgd_offset(&init_mm, 0); + + memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR); + + /* + * On ARM, first page must always be allocated + */ + if (!pmd_alloc(pgd, 0)) + goto nomem; + else { + pmd_t *old_pmd = pmd_offset(init, 0); + new_pmd = pmd_offset(pgd, 0); + + if (!pte_alloc(new_pmd, 0)) + goto nomem_pmd; + else { + pte_t *new_pte = pte_offset(new_pmd, 0); + pte_t *old_pte = pte_offset(old_pmd, 0); + + set_pte (new_pte, *old_pte); + } + } + } + return pgd; + +nomem_pmd: + pmd_free(new_pmd); +nomem: + free_pages((unsigned long)pgd, 2); + return NULL; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *)get_page_2k(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); + clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); + pte += PTRS_PER_PTE; + set_pmd(pmd, mk_user_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); + return NULL; + } + free_page_2k((unsigned long)pte); + if (pmd_bad(*pmd)) { + __bad_pmd(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *)get_page_2k(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); + clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); + pte += PTRS_PER_PTE; + set_pmd(pmd, mk_kernel_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); + return NULL; + } + free_page_2k((unsigned long)pte); + if (pmd_bad(*pmd)) { + __bad_pmd_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +/* + * Create a SECTION PGD between VIRT and PHYS in domain + * DOMAIN with protection PROT + */ +static inline void +alloc_init_section(unsigned long virt, unsigned long phys, int prot) +{ + pmd_t pmd; + + pmd_val(pmd) = phys | prot; + + set_pmd(pmd_offset(pgd_offset_k(virt), virt), pmd); +} + +/* + * Add a PAGE mapping between VIRT and PHYS in domain + * DOMAIN with protection PROT. Note that due to the + * way we map the PTEs, we must allocate two PTE_SIZE'd + * blocks - one for the Linux pte table, and one for + * the hardware pte table. + */ +static inline void +alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot) +{ + pmd_t *pmdp; + pte_t *ptep; + + pmdp = pmd_offset(pgd_offset_k(virt), virt); + +#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR) + + if (pmd_none(*pmdp)) { + unsigned long memory = *mem; + + memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1); + + ptep = (pte_t *)memory; + memzero(ptep, PTE_SIZE); + memory += PTE_SIZE; + + ptep = (pte_t *)memory; + memzero(ptep, PTE_SIZE); + + set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain))); + + *mem = memory + PTE_SIZE; + } -#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0])) +#undef PTE_SIZE -unsigned long __init setup_io_pagetables(unsigned long start_mem) + ptep = pte_offset(pmdp, virt); + + set_pte(ptep, mk_pte_phys(phys, __pgprot(prot))); +} + +/* + * Clear any PGD mapping. On a two-level page table system, + * the clearance is done by the middle-level functions (pmd) + * rather than the top-level (pgd) functions. + */ +static inline void +free_init_section(unsigned long virt) +{ + pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); +} + +/* + * Create the page directory entries and any necessary + * page tables for the mapping specified by `md'. We + * are able to cope here with varying sizes and address + * offsets, and we take full advantage of sections. + */ +static void __init +create_mapping(unsigned long *mem_ptr, struct map_desc *md) { - const struct mapping *mp; - int i; + unsigned long virt, length; + int prot_sect, prot_pte; + long off; + + prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + (md->prot_read ? L_PTE_USER : 0) | + (md->prot_write ? L_PTE_WRITE : 0) | + (md->cacheable ? L_PTE_CACHEABLE : 0) | + (md->bufferable ? L_PTE_BUFFERABLE : 0); + + prot_sect = PMD_TYPE_SECT | PMD_DOMAIN(md->domain) | + (md->prot_read ? PMD_SECT_AP_READ : 0) | + (md->prot_write ? PMD_SECT_AP_WRITE : 0) | + (md->cacheable ? PMD_SECT_CACHEABLE : 0) | + (md->bufferable ? PMD_SECT_BUFFERABLE : 0); + + virt = md->virtual; + off = md->physical - virt; + length = md->length; + + while ((virt & 1048575 || (virt + off) & 1048575) && length >= PAGE_SIZE) { + alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte); - for (i = 0, mp = mapping; i < SIZEOFMAP; i++, mp++) { - unsigned long virtual, physical, length; - int prot; + virt += PAGE_SIZE; + length -= PAGE_SIZE; + } + + while (length >= PGDIR_SIZE) { + alloc_init_section(virt, virt + off, prot_sect); - virtual = mp->virtual; - physical = mp->physical; - length = mp->length; - prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0) - | L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY; + virt += PGDIR_SIZE; + length -= PGDIR_SIZE; + } - while ((virtual & 1048575 || physical & 1048575) && length >= PAGE_SIZE) { - alloc_init_page(&start_mem, virtual, physical, mp->domain, prot); - length -= PAGE_SIZE; - virtual += PAGE_SIZE; - physical += PAGE_SIZE; + while (length >= PAGE_SIZE) { + alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte); + + virt += PAGE_SIZE; + length -= PAGE_SIZE; + } +} + +/* + * Initial boot-time mapping. This covers just the + * zero page, kernel and the flush area. NB: it + * must be sorted by virtual address, and no + * virtual address overlaps. + * init_map[2..4] are for architectures with small + * amounts of banked memory. + */ +static struct map_desc init_map[] __initdata = { + { 0, 0, PAGE_SIZE, DOMAIN_USER, 0, 0, 1, 0 }, /* zero page */ + { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, /* kernel memory */ + { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, + { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, + { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, + { 0, 0, PGDIR_SIZE, DOMAIN_KERNEL, 1, 0, 1, 1 }, /* cache flush 1 */ + { 0, 0, 0, DOMAIN_KERNEL, 1, 0, 1, 0 } /* cache flush 2 */ +}; + +#define NR_INIT_MAPS (sizeof(init_map) / sizeof(init_map[0])) + +unsigned long __init +setup_page_tables(unsigned long start_mem, unsigned long end_mem) +{ + unsigned long address = 0; + int idx = 0; + + /* + * Correct the above mappings + */ + init_map[0].physical = + init_map[1].physical = __virt_to_phys(PAGE_OFFSET); + init_map[1].virtual = PAGE_OFFSET; + init_map[1].length = end_mem - PAGE_OFFSET; + init_map[5].physical = FLUSH_BASE_PHYS; + init_map[5].virtual = FLUSH_BASE; +#ifdef FLUSH_BASE_MINICACHE + init_map[6].physical = FLUSH_BASE_PHYS + PGDIR_SIZE; + init_map[6].virtual = FLUSH_BASE_MINICACHE; + init_map[6].length = PGDIR_SIZE; +#endif + + /* + * Firstly, go through the initial mappings, + * but clear out any pgdir entries that are + * not in the description. + */ + do { + if (address < init_map[idx].virtual || idx == NR_INIT_MAPS) { + free_init_section(address); + address += PGDIR_SIZE; + } else { + create_mapping(&start_mem, init_map + idx); + + address = init_map[idx].virtual + init_map[idx].length; + address = (address + PGDIR_SIZE - 1) & PGDIR_MASK; + + do { + idx += 1; + } while (init_map[idx].length == 0 && idx < NR_INIT_MAPS); } + } while (address != 0); + + /* + * Now, create the architecture specific mappings + */ + for (idx = 0; idx < io_desc_size; idx++) + create_mapping(&start_mem, io_desc + idx); + + flush_cache_all(); + + return start_mem; +} + +/* + * The mem_map array can get very big. Mark the end of the + * valid mem_map banks with PG_skip, and setup the address + * validity bitmap. + */ +unsigned long __init +create_mem_holes(unsigned long start_mem, unsigned long end_mem) +{ + struct page *pg = NULL; + unsigned int sz, i; + + if (!machine_is_riscpc()) + return start_mem; + + sz = (end_mem - PAGE_OFFSET) >> 20; + sz = (sz + 31) >> 3; - prot = (mp->prot_read ? PMD_SECT_AP_READ : 0) | - (mp->prot_write ? PMD_SECT_AP_WRITE : 0); + valid_addr_bitmap = (unsigned long *)start_mem; + start_mem += sz; - while (length >= 1048576) { - alloc_init_section(&start_mem, virtual, physical, mp->domain, prot); - length -= 1048576; - virtual += 1048576; - physical += 1048576; + memset(valid_addr_bitmap, 0, sz); + + if (start_mem > mem_desc[0].virt_end) + printk(KERN_CRIT "*** Error: RAM bank 0 too small\n"); + + for (i = 0; i < mem_desc_size; i++) { + unsigned int idx, end; + + if (pg) { + pg->next_hash = mem_map + + MAP_NR(mem_desc[i].virt_start); + pg = NULL; } - prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0) - | L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY; + idx = __kern_valid_idx(mem_desc[i].virt_start); + end = __kern_valid_idx(mem_desc[i].virt_end); - while (length >= PAGE_SIZE) { - alloc_init_page(&start_mem, virtual, physical, mp->domain, prot); - length -= PAGE_SIZE; - virtual += PAGE_SIZE; - physical += PAGE_SIZE; + do + set_bit(idx, valid_addr_bitmap); + while (++idx < end); + + if (mem_desc[i].virt_end < end_mem) { + pg = mem_map + MAP_NR(mem_desc[i].virt_end); + + set_bit(PG_skip, &pg->flags); } } + if (pg) + pg->next_hash = NULL; + return start_mem; } + +void __init +mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem) +{ + /* + * Mark all of memory from the end of kernel to end of memory + */ + while (start_mem < end_mem) { + clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); + start_mem += PAGE_SIZE; + } + + /* + * Mark memory from page 1 to start of the swapper page directory + */ + start_mem = PAGE_OFFSET + PAGE_SIZE; + while (start_mem < (unsigned long)&swapper_pg_dir) { + clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); + start_mem += PAGE_SIZE; + } +} diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c --- v2.3.22/linux/arch/arm/mm/mm-ebsa110.c Sun Sep 6 10:44:47 1998 +++ linux/arch/arm/mm/mm-ebsa110.c Wed Oct 20 16:29:08 1999 @@ -3,19 +3,27 @@ * * Extra MM routines for the EBSA-110 architecture * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998-1999 Russell King */ -#include #include #include #include #include -#include -#include + +#include "map.h" -#define MAPPING \ - { IO_BASE - PGDIR_SIZE , 0xc0000000 , PGDIR_SIZE , DOMAIN_IO, 0, 1 }, \ - { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1 } +struct mem_desc mem_desc[] __initdata = { + 0, 0 +}; + +unsigned int __initdata mem_desc_size = 0; + +const struct map_desc io_desc[] __initdata = { + { IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 } +}; + +#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0])) -#include "mm-armv.c" +unsigned int __initdata io_desc_size = SIZEOFMAP; diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c --- v2.3.22/linux/arch/arm/mm/mm-footbridge.c Sat May 8 11:06:57 1999 +++ linux/arch/arm/mm/mm-footbridge.c Wed Oct 20 16:29:08 1999 @@ -1,9 +1,9 @@ /* - * arch/arm/mm/mm-ebsa285.c + * arch/arm/mm/mm-footbridge.c * * Extra MM routines for the EBSA285 architecture * - * Copyright (C) 1998 Russell King, Dave Gilbert. + * Copyright (C) 1998-1999 Russell King, Dave Gilbert. */ #include #include @@ -13,9 +13,10 @@ #include #include #include -#include #include +#include "map.h" + /* * The first entry allows us to fiddle with the EEPROM from user-space. * This entry will go away in time, once the fmu32 can mmap() the @@ -32,15 +33,15 @@ * The mapping when the footbridge is in host mode. */ #define MAPPING \ - { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \ - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 }, \ - { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1 }, \ - { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1 }, \ - { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1 }, \ - { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \ - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \ - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \ - { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 } + { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 } #else @@ -79,13 +80,26 @@ * The mapping when the footbridge is in add-in mode. */ #define MAPPING \ - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \ - { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 }, \ - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \ - { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \ - { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \ - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 } + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 } #endif -#include "mm-armv.c" +struct mem_desc mem_desc[] __initdata = { + 0, 0 +}; + +unsigned int __initdata mem_desc_size = 0; + +struct map_desc io_desc[] __initdata = { + MAPPING +}; + +#define SIZE(x) (sizeof(x) / sizeof(x[0])) + +unsigned int __initdata io_desc_size = SIZE(io_desc); + diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-nexuspci.c linux/arch/arm/mm/mm-nexuspci.c --- v2.3.22/linux/arch/arm/mm/mm-nexuspci.c Sat Jul 18 11:55:23 1998 +++ linux/arch/arm/mm/mm-nexuspci.c Wed Oct 20 16:29:08 1999 @@ -5,7 +5,7 @@ * Extra MM routines for the NexusPCI architecture * * Copyright (C) 1998 Phil Blundell - * Copyright (C) 1998 Russell King + * Copyright (C) 1998-1999 Russell King */ #include @@ -15,13 +15,23 @@ #include #include #include -#include + +#include "map.h" -#define MAPPING \ - { 0xfff00000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffe00000, 0x20000000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffc00000, 0x60000000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xfe000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1 }, \ - { 0xfd000000, 0x88000000, 0x00100000, DOMAIN_IO, 0, 1 } +struct mem_desc mem_desc[] __initdata = { + 0, 0 +}; + +unsigned int __initdata mem_desc_size = 0; + +const struct map_desc io_desc[] __initdata = { + { 0xfff00000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffe00000, 0x20000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffc00000, 0x60000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xfe000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xfd000000, 0x88000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 } +}; + +#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0])) -#include "mm-armv.c" +unsigned int __initdata io_desc_size = SIZEOFMAP; diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c --- v2.3.22/linux/arch/arm/mm/mm-rpc.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/mm-rpc.c Wed Oct 20 16:29:08 1999 @@ -3,95 +3,48 @@ * * Extra MM routines for RiscPC architecture * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998-1999 Russell King */ -#include -#include #include -#include +#include +#include +#include #include -#include -#include -#include -#define NR_DRAM_BANKS 4 -#define NR_VRAM_BANKS 1 +#include "map.h" -#define NR_BANKS (NR_DRAM_BANKS + NR_VRAM_BANKS) +#define SIZE(x) (sizeof(x) / sizeof(x[0])) -#define FIRST_BANK 0 -#define FIRST_DRAM_BANK 0 -#define FIRST_VRAM_BANK NR_DRAM_BANKS - -#define BANK_SHIFT 26 -#define FIRST_DRAM_ADDR 0x10000000 - -#define PHYS_TO_BANK(x) (((x) >> BANK_SHIFT) & (NR_DRAM_BANKS - 1)) -#define BANK_TO_PHYS(x) ((FIRST_DRAM_ADDR) + \ - (((x) - FIRST_DRAM_BANK) << BANK_SHIFT)) - -struct ram_bank { - unsigned int virt_addr; /* virtual address of the *end* of this bank + 1 */ - signed int phys_offset; /* offset to physical address of this bank */ +struct mem_desc mem_desc[] __initdata = { + { 0xc0000000, 0xc0000000 }, + { 0xc4000000, 0xc4000000 }, + { 0xc8000000, 0xc8000000 }, + { 0xcc000000, 0xcc000000 } }; -static struct ram_bank rambank[NR_BANKS]; - -/* - * Return the physical (0x10000000 -> 0x20000000) address of - * the virtual (0xc0000000 -> 0xd0000000) address - */ -unsigned long __virt_to_phys(unsigned long vpage) -{ - unsigned int bank = FIRST_BANK; - - while (vpage >= rambank[bank].virt_addr && bank < NR_BANKS) - bank ++; - - return vpage - rambank[bank].phys_offset; -} - -/* - * Return the virtual (0xc0000000 -> 0xd0000000) address of - * the physical (0x10000000 -> 0x20000000) address - */ -unsigned long __phys_to_virt(unsigned long phys) -{ - unsigned int bank; - - if (phys > FIRST_DRAM_ADDR) - bank = PHYS_TO_BANK(phys); - else - bank = FIRST_VRAM_BANK; - - return phys + rambank[bank].phys_offset; -} +unsigned int __initdata mem_desc_size = SIZE(mem_desc); void __init init_dram_banks(struct param_struct *params) { unsigned int bank; - unsigned int bytes = 0; - for (bank = FIRST_DRAM_BANK; bank < NR_DRAM_BANKS; bank++) { - rambank[bank].phys_offset = PAGE_OFFSET + bytes - - BANK_TO_PHYS(bank); + for (bank = 0; bank < mem_desc_size; bank++) + mem_desc[bank].virt_end += PAGE_SIZE * + params->u1.s.pages_in_bank[bank]; - bytes += params->u1.s.pages_in_bank[bank - FIRST_DRAM_BANK] * PAGE_SIZE; - - rambank[bank].virt_addr = PAGE_OFFSET + bytes; - } - - rambank[FIRST_VRAM_BANK].phys_offset = 0xd6000000; - rambank[FIRST_VRAM_BANK].virt_addr = 0xd8000000; + params->u1.s.nr_pages = mem_desc[3].virt_end - PAGE_OFFSET; + params->u1.s.nr_pages /= PAGE_SIZE; } -#define MAPPING \ - { SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1 }, /* VRAM */ \ - { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 }, /* IO space */ \ - { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1 } /* EASI space */ -/* - * Include common routine to set up page tables - */ -#include "mm-armv.c" +struct map_desc io_desc[] __initdata = { + /* VRAM */ + { SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, + /* IO space */ + { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, + /* EASI space */ + { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1, 0, 0 } +}; + +unsigned int __initdata io_desc_size = SIZE(io_desc); diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c --- v2.3.22/linux/arch/arm/mm/mm-sa1100.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/mm-sa1100.c Wed Oct 20 16:29:08 1999 @@ -0,0 +1,84 @@ +/* + * arch/arm/mm/mm-sa1100.c + * + * Extra MM routines for the SA1100 architecture + * + * Copyright (C) 1998-1999 Russell King + * Copyright (C) 1999 Hugo Fiennes + * + * 1999/09/12 Nicolas Pitre + * Specific RAM implementation details are in + * linux/include/asm/arch-sa1100/memory.h now. + * Allows for better macro optimisations when possible. + */ +#include +#include +#include + +#include +#include + +#include "map.h" + +#define SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* + * These are the memory size mappings for the + * SA1100. Note that LART is a special case - + * it doesn't use physical address A23 on the + * DRAM, so we effectively have 4 * 8MB in + * two banks. + */ +struct mem_desc mem_desc[] __initdata = { + /* virt start virt end */ +#if defined(CONFIG_SA1100_BRUTUS) + { 0xc0000000, 0xc0400000 }, /* 4MB */ + { 0xc1000000, 0xc1400000 }, /* 4MB */ + { 0xc2000000, 0xc2400000 }, /* 4MB */ + { 0xc3000000, 0xc3400000 } /* 4MB */ +#elif defined(CONFIG_SA1100_EMPEG) + { 0xc0000000, 0xc0400000 }, /* 4MB */ + { 0xc1000000, 0xc1400000 } /* 4MB */ +#elif defined(CONFIG_SA1100_LART) + { 0xc0000000, 0xc0800000 }, /* 16MB */ + { 0xc1000000, 0xc1800000 }, + { 0xc2000000, 0xc2800000 }, /* 16MB */ + { 0xc3000000, 0xc3800000 } +#elif defined(CONFIG_SA1100_VICTOR) + { 0xc0000000, 0xc0400000 } /* 4MB */ +#elif defined(CONFIG_SA1100_TIFON) + { 0xc0000000, 0xc1000000 }, /* 16MB */ + { 0xc1000000, 0xc2000000 } /* 16MB */ +#else +#error missing memory configuration +#endif +}; + +unsigned int __initdata mem_desc_size = SIZE(mem_desc); + +struct map_desc io_desc[] __initdata = { + /* virtual physical length domain r w c b */ +#if defined(CONFIG_SA1100_VICTOR) + { 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ +#elif defined(CONFIG_SA1100_EMPEG) + { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ +#elif defined(CONFIG_SA1100_TIFON) + { 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ + { 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */ +#endif +#ifdef CONFIG_SA1101 + { 0xdc000000, SA1101_BASE, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1101 */ +#endif + { 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ + { 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ + { 0xe8000000, 0x28000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */ + { 0xec000000, 0x38000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */ + { 0xf0000000, 0x2c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */ + { 0xf4000000, 0x3c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */ + { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ + { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ + { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ + { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 } /* LCD + DMA */ +}; + +unsigned int __initdata io_desc_size = SIZE(io_desc); diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-tbox.c linux/arch/arm/mm/mm-tbox.c --- v2.3.22/linux/arch/arm/mm/mm-tbox.c Sat Jul 18 11:55:23 1998 +++ linux/arch/arm/mm/mm-tbox.c Wed Oct 20 16:29:08 1999 @@ -5,7 +5,7 @@ * Extra MM routines for the Tbox architecture * * Copyright (C) 1998 Phil Blundell - * Copyright (C) 1998 Russell King + * Copyright (C) 1998-1999 Russell King */ #include @@ -15,9 +15,15 @@ #include #include #include -#include - + +#include "map.h" +struct mem_desc mem_desc[] __initdata = { + 0, 0 +}; + +unsigned int __initdata mem_desc_size = 0; + /* Logical Physical * 0xffff1000 0x00100000 DMA registers * 0xffff2000 0x00200000 MPEG @@ -34,23 +40,26 @@ * 0xffffd000 0x00d00000 Interrupt reset * 0xffffe000 0x00e00000 MPEG DMA throttle */ - -#define MAPPING \ - { 0xffff0000, 0x01000000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff1000, 0x00100000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff2000, 0x00200000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff3000, 0x00300000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff4000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xfe000000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff5000, 0x00500000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff6000, 0x00600000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff7000, 0x00700000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff8000, 0x00800000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffff9000, 0x00900000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffffa000, 0x00a00000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffffb000, 0x00b00000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffffc000, 0x00c00000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffffd000, 0x00d00000, 0x00001000, DOMAIN_IO, 0, 1 }, \ - { 0xffffe000, 0x00e00000, 0x00001000, DOMAIN_IO, 0, 1 } -#include "mm-armv.c" +const struct map_desc io_desc[] __initdata = { + { 0xffff0000, 0x01000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff1000, 0x00100000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff2000, 0x00200000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff3000, 0x00300000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff4000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xfe000000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff5000, 0x00500000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff6000, 0x00600000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff7000, 0x00700000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff8000, 0x00800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffff9000, 0x00900000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffffa000, 0x00a00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffffb000, 0x00b00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffffc000, 0x00c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffffd000, 0x00d00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { 0xffffe000, 0x00e00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 } +}; + +#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0])) + +unsigned int __initdata io_desc_size = SIZEOFMAP; diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S --- v2.3.22/linux/arch/arm/mm/proc-arm2,3.S Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/proc-arm2,3.S Wed Oct 20 16:29:08 1999 @@ -12,349 +12,184 @@ #include "../lib/constants.h" /* - * Code common to all processors - MEMC specific not processor - * specific! + * MEMC workhorse code. It's both a horse which things it's a pig. */ - -LC1: .word SYMBOL_NAME(page_nr) /* - * Function: arm2_3_update_map (struct task_struct *tsk) - * - * Params : tsk Task structure to be updated - * - * Purpose : Re-generate memc maps for task from its pseudo page tables - */ -_arm2_3_update_map: - mov ip, sp - stmfd sp!, {r4 - r6, fp, ip, lr, pc} - sub fp, ip, #4 - add r1, r0, #TSS_MEMCMAP - ldr r2, LC1 - ldr r2, [r2] - mov r3, #0x03f00000 - orr r3, r3, #0x00000f00 - orr r4, r3, #1 - orr r5, r3, #2 - orr r6, r3, #3 -1: stmia r1!, {r3, r4, r5, r6} @ Default mapping (null mapping) - add r3, r3, #4 - add r4, r4, #4 - add r5, r5, #4 - add r6, r6, #4 - stmia r1!, {r3, r4, r5, r6} @ Default mapping (null mapping) - add r3, r3, #4 - add r4, r4, #4 - add r5, r5, #4 - add r6, r6, #4 - subs r2, r2, #8 - bhi 1b - - adr r2, Lphystomemc32 @ r2 = conversion table to logical page number - ldr r4, [r0, #TSS_MEMMAP] @ r4 = active mem map - add r5, r4, #32 << 2 @ r5 = end of active mem map - add r0, r0, #TSS_MEMCMAP @ r0 = memc map - - mov r6, #0 -2: ldmia r4!, {r1, r3} - tst r1, #PAGE_PRESENT - blne update_map_pgd - add r6, r6, #32 << 2 - tst r3, #PAGE_PRESENT - blne update_map_pgd3 - add r6, r6, #32 << 2 - cmp r4, r5 - blt 2b - ldmea fp, {r4 - r6, fp, sp, pc}^ - -@ r0,r2,r3,r4,r5 = preserve -@ r1,ip = available -@ r0 = memc map -@ r1 = pgd entry -@ r2 = conversion table -@ r6 = logical page no << 2 - -update_map_pgd3: - mov r1, r3 -update_map_pgd: stmfd sp!, {r3, r4, r5, lr} - bic r4, r1, #3 @ r4 = page table - sub r5, r6, #1 << 2 - add ip, r4, #32 << 2 @ ip = end of page table - -1: ldr r1, [r4], #4 @ get entry - add r5, r5, #1 << 2 - tst r1, #PAGE_PRESENT @ page present? - blne Lconvertmemc @ yes - ldr r1, [r4], #4 @ get entry - add r5, r5, #1 << 2 - tst r1, #PAGE_PRESENT @ page present? - blne Lconvertmemc @ yes - ldr r1, [r4], #4 @ get entry - add r5, r5, #1 << 2 - tst r1, #PAGE_PRESENT @ page present? - blne Lconvertmemc @ yes - ldr r1, [r4], #4 @ get entry - add r5, r5, #1 << 2 - tst r1, #PAGE_PRESENT @ page present? - blne Lconvertmemc @ yes - cmp r4, ip - blt 1b - ldmfd sp!, {r3, r4, r5, pc}^ - -Lconvertmemc: mov r3, r1, lsr #13 @ - and r3, r3, #0x3fc @ Convert to memc physical page no - ldr r3, [r2, r3] @ - - tst r1, #PAGE_OLD|PAGE_NOT_USER @ check for MEMC read - biceq r3, r3, #0x200 @ - tsteq r1, #PAGE_READONLY|PAGE_CLEAN @ check for MEMC write - biceq r3, r3, #0x300 @ - - orr r3, r3, r5, lsl #13 - and r1, r5, #0x01800000 >> 13 - orr r3, r3, r1 - - and r1, r3, #255 - str r3, [r0, r1, lsl #2] - movs pc, lr - -/* - * Function: arm2_3_update_cache (struct task_struct *tsk, unsigned long addr, pte_t pte) - * Params : tsk Task to update - * address Address of fault. - * pte New PTE at address - * Purpose : Update the mapping for this address. - * Notes : does the ARM3 run faster if you do not use the result in the next instruction? - */ -_arm2_3_update_cache: - tst r2, #PAGE_PRESENT - moveqs pc, lr - mov r3, r2, lsr #13 @ Physical page no. - adr ip, Lphystomemc32 @ Convert to logical page number + * Function: cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long addr) + * Params : pgd Page tables/MEMC mapping + * : phys_pte physical address, or PTE + * : addr virtual address + */ +ENTRY(cpu_memc_update_entry) + tst r1, #PAGE_PRESENT @ is the page present + orreq r1, r1, #PAGE_OLD | PAGE_CLEAN + moveq r2, #0x01f00000 + mov r3, r1, lsr #13 @ convert to physical page nr and r3, r3, #0x3fc - mov r1, r1, lsr #15 - ldr r3, [ip, r3] @ Convert to memc phys page no. - tst r2, #PAGE_OLD|PAGE_NOT_USER + adr ip, memc_phys_table_32 + ldr r3, [ip, r3] + tst r1, #PAGE_OLD | PAGE_NOT_USER biceq r3, r3, #0x200 - tsteq r2, #PAGE_READONLY|PAGE_CLEAN + tsteq r1, #PAGE_READONLY | PAGE_CLEAN biceq r3, r3, #0x300 - mov ip, sp, lsr #13 - orr r3, r3, r1, lsl #15 - mov ip, ip, lsl #13 - and r1, r1, #0x300 - teq ip, r0 - orr r3, r3, r1, lsl #2 - add r0, r0, #TSS_MEMCMAP + mov r2, r2, lsr #15 @ virtual -> nr + orr r3, r3, r2, lsl #15 + and r2, r2, #0x300 + orr r3, r3, r2, lsl #2 and r2, r3, #255 - streqb r3, [r3] + sub r0, r0, #256 * 4 str r3, [r0, r2, lsl #2] - movs pc, lr - -#define PCD(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \ - .long a0| 0x03800300; .long a1| 0x03800300;\ - .long a2| 0x03800300; .long a3| 0x03800300;\ - .long a4| 0x03800300; .long a5| 0x03800300;\ - .long a6| 0x03800300; .long a7| 0x03800300;\ - .long a8| 0x03800300; .long a9| 0x03800300;\ - .long aa| 0x03800300; .long ab| 0x03800300;\ - .long ac| 0x03800300; .long ad| 0x03800300;\ - .long ae| 0x03800300; .long af| 0x03800300 - -@ Table to map from page number to vidc page number -Lphystomemc32: PCD(0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78) - PCD(0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39,0x41,0x49,0x51,0x59,0x61,0x69,0x71,0x79) - PCD(0x04,0x0C,0x14,0x1C,0x24,0x2C,0x34,0x3C,0x44,0x4C,0x54,0x5C,0x64,0x6C,0x74,0x7C) - PCD(0x05,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7D) - PCD(0x02,0x0A,0x12,0x1A,0x22,0x2A,0x32,0x3A,0x42,0x4A,0x52,0x5A,0x62,0x6A,0x72,0x7A) - PCD(0x03,0x0B,0x13,0x1B,0x23,0x2B,0x33,0x3B,0x43,0x4B,0x53,0x5B,0x63,0x6B,0x73,0x7B) - PCD(0x06,0x0E,0x16,0x1E,0x26,0x2E,0x36,0x3E,0x46,0x4E,0x56,0x5E,0x66,0x6E,0x76,0x7E) - PCD(0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F) - PCD(0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8) - PCD(0x81,0x89,0x91,0x99,0xA1,0xA9,0xB1,0xB9,0xC1,0xC9,0xD1,0xD9,0xE1,0xE9,0xF1,0xF9) - PCD(0x84,0x8C,0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,0xE4,0xEC,0xF4,0xFC) - PCD(0x85,0x8D,0x95,0x9D,0xA5,0xAD,0xB5,0xBD,0xC5,0xCD,0xD5,0xDD,0xE5,0xED,0xF5,0xFD) - PCD(0x82,0x8A,0x92,0x9A,0xA2,0xAA,0xB2,0xBA,0xC2,0xCA,0xD2,0xDA,0xE2,0xEA,0xF2,0xFA) - PCD(0x83,0x8B,0x93,0x9B,0xA3,0xAB,0xB3,0xBB,0xC3,0xCB,0xD3,0xDB,0xE3,0xEB,0xF3,0xFB) - PCD(0x86,0x8E,0x96,0x9E,0xA6,0xAE,0xB6,0xBE,0xC6,0xCE,0xD6,0xDE,0xE6,0xEE,0xF6,0xFE) - PCD(0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF) - -/* - * Function: arm2_3_data_abort () - * - * Params : r0 = address of aborted instruction - * - * Purpose : - * - * Returns : r0 = address of abort - * : r1 = FSR - * : r2 != 0 if writing - */ - -_arm2_3_data_abort: + strb r3, [r3] movs pc, lr - -_arm2_3_check_bugs: - bics pc, lr, #0x04000000 @ Clear FIQ disable bit - -/* - * Processor specific - ARM2 - */ - -LC0: .word SYMBOL_NAME(page_nr) /* - * Function: arm2_switch_to (struct task_struct *prev, struct task_struct *next) - * Params : prev Old task structure - * : next New task structure for process to run - * Returns : prev - * Purpose : Perform a task switch, saving the old processes state, and restoring - * the new. - * Notes : We don't fiddle with the FP registers here - we postpone this until - * the new task actually uses FP. This way, we don't swap FP for tasks - * that do not require it. - */ -_arm2_switch_to: - stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack - str sp, [r0, #TSS_SAVE] @ Save sp_SVC - ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - mov r4, r1 - add r7, r1, #TSS_MEMCMAP @ Remap MEMC - ldr r1, LC0 - ldr r1, [r1] -1: ldmia r7!, {r2, r3, r5, r6} - strb r2, [r2] - strb r3, [r3] - strb r5, [r5] - strb r6, [r6] - ldmia r7!, {r2, r3, r5, r6} - strb r2, [r2] - strb r3, [r3] - strb r5, [r5] - strb r6, [r6] - subs r1, r1, #8 - bhi 1b - ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously - -/* - * Function: arm2_remap_memc (struct task_struct *tsk) - * - * Params : tsk Task structure specifing the new mapping structure - * - * Purpose : remap MEMC tables - */ -_arm2_remap_memc: - stmfd sp!, {lr} - add r0, r0, #TSS_MEMCMAP - ldr r1, LC0 - ldr r1, [r1] -1: ldmia r0!, {r2, r3, ip, lr} - strb r2, [r2] - strb r3, [r3] - strb ip, [ip] - strb lr, [lr] - ldmia r0!, {r2, r3, ip, lr} - strb r2, [r2] - strb r3, [r3] - strb ip, [ip] - strb lr, [lr] - subs r1, r1, #8 - bhi 1b - ldmfd sp!, {pc}^ + * Params : r0 = preserved + * : r1 = memc table base (preserved) + * : r2 = page table entry + * : r3 = preserved + * : r4 = unused + * : r5 = memc physical address translation table + * : ip = virtual address (preserved) + */ +update_pte: + mov r4, r2, lsr #13 + and r4, r4, #0x3fc + ldr r4, [r5, r4] @ covert to MEMC page + + tst r2, #PAGE_OLD | PAGE_NOT_USER @ check for MEMC read + biceq r4, r4, #0x200 + tsteq r2, #PAGE_READONLY | PAGE_CLEAN @ check for MEMC write + biceq r4, r4, #0x300 + + orr r4, r4, ip + and r2, ip, #0x01800000 + orr r4, r4, r2, lsr #13 -/* - * Function: arm2_xchg_1 (int new, volatile void *ptr) - * - * Params : new New value to store at... - * : ptr pointer to byte-wide location - * - * Purpose : Performs an exchange operation - * - * Returns : Original byte data at 'ptr' - * - * Notes : This will have to be changed if we ever use multi-processing using these - * processors, but that is very unlikely... - */ -_arm2_xchg_1: mov r2, pc - orr r2, r2, #I_BIT - teqp r2, #0 - ldrb r2, [r1] - strb r0, [r1] - mov r0, r2 + and r2, r4, #255 + str r4, [r1, r2, lsl #2] movs pc, lr /* - * Function: arm2_xchg_4 (int new, volatile void *ptr) - * - * Params : new New value to store at... - * : ptr pointer to word-wide location - * - * Purpose : Performs an exchange operation - * - * Returns : Original word data at 'ptr' - * - * Notes : This will have to be changed if we ever use multi-processing using these - * processors, but that is very unlikely... + * Params : r0 = preserved + * : r1 = memc table base (preserved) + * : r2 = page table base + * : r3 = preserved + * : r4 = unused + * : r5 = memc physical address translation table + * : ip = virtual address (updated) + */ +update_pte_table: + stmfd sp!, {r0, lr} + bic r0, r2, #3 +1: ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + tst ip, #32768 * 31 @ finished? + bne 1b + ldmfd sp!, {r0, pc}^ + +/* + * Function: cpu_memc_update_all(pgd_t *pgd) + * Params : pgd Page tables/MEMC mapping + * Notes : this is optimised for 32k pages + */ +ENTRY(cpu_memc_update_all) + stmfd sp!, {r4, r5, lr} + bl clear_tables + sub r1, r0, #256 * 4 @ start of MEMC tables + adr r5, memc_phys_table_32 @ Convert to logical page number + mov ip, #0 @ virtual address +1: ldmia r0!, {r2, r3} + tst r2, #PAGE_PRESENT + addeq ip, ip, #1048576 + blne update_pte_table + mov r2, r3 + tst r2, #PAGE_PRESENT + addeq ip, ip, #1048576 + blne update_pte_table + teq ip, #32 * 1048576 + bne 1b + ldmfd sp!, {r4, r5, pc}^ + +/* + * Build the table to map from physical page number to memc page number + */ + .type memc_phys_table_32, #object +memc_phys_table_32: + .irp b7, 0x00, 0x80 + .irp b6, 0x00, 0x02 + .irp b5, 0x00, 0x04 + .irp b4, 0x00, 0x01 + + .irp b3, 0x00, 0x40 + .irp b2, 0x00, 0x20 + .irp b1, 0x00, 0x10 + .irp b0, 0x00, 0x08 + .long 0x03800300 + \b7 + \b6 + \b5 + \b4 + \b3 + \b2 + \b1 + \b0 + .endr + .endr + .endr + .endr + + .endr + .endr + .endr + .endr + .size memc_phys_table_32, . - memc_phys_table_32 + +/* + * helper for cpu_memc_update_all, this clears out all + * mappings, setting them close to the top of memory, + * and inaccessible (0x01f00000). + * Params : r0 = page table pointer */ -_arm2_xchg_4: mov r2, pc - orr r2, r2, #I_BIT - teqp r2, #0 +clear_tables: ldr r1, _arm3_set_pgd - 4 ldr r2, [r1] - str r0, [r1] - mov r0, r2 -/* - * fall through - */ -/* - * Function: arm2_proc_init (void) - * : arm2_proc_fin (void) - * - * Purpose : Initialise / finalise processor specifics (none required) - */ -_arm2_proc_init: -_arm2_proc_fin: movs pc, lr + sub r1, r0, #256 * 4 @ start of MEMC tables + add r2, r1, r2, lsl #2 @ end of tables + mov r3, #0x03f00000 @ Default mapping (null mapping) + orr r3, r3, #0x00000f00 + orr r4, r3, #1 + orr r5, r3, #2 + orr ip, r3, #3 +1: stmia r1!, {r3, r4, r5, ip} + add r3, r3, #4 + add r4, r4, #4 + add r5, r5, #4 + add ip, ip, #4 + stmia r1!, {r3, r4, r5, ip} + add r3, r3, #4 + add r4, r4, #4 + add r5, r5, #4 + add ip, ip, #4 + teq r1, r2 + bne 1b + mov pc, lr + /* - * Function: arm3_switch_to (struct task_struct *prev, struct task_struct *next) - * Params : prev Old task structure - * : next New task structure for process to run - * Returns : prev - * Purpose : Perform a task switch, saving the old processes state, and restoring - * the new. - * Notes : We don't fiddle with the FP registers here - we postpone this until - * the new task actually uses FP. This way, we don't swap FP for tasks - * that do not require it. - */ -_arm3_switch_to: - stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack - str sp, [r0, #TSS_SAVE] @ Save sp_SVC - ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - mov r4, r1 - add r7, r1, #TSS_MEMCMAP @ Remap MEMC - ldr r1, LC0 - ldr r1, [r1] -1: ldmia r7!, {r2, r3, r5, r6} - strb r2, [r2] - strb r3, [r3] - strb r5, [r5] - strb r6, [r6] - ldmia r7!, {r2, r3, r5, r6} - strb r2, [r2] - strb r3, [r3] - strb r5, [r5] - strb r6, [r6] - subs r1, r1, #8 - bhi 1b - mcr p15, 0, r7, c1, c0, 0 @ flush cache - ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously -/* - * Function: arm3_remap_memc (struct task_struct *tsk) - * - * Params : tsk Task structure specifing the new mapping structure - * - * Purpose : remap MEMC tables - */ -_arm3_remap_memc: - stmfd sp!, {lr} - add r0, r0, #TSS_MEMCMAP - ldr r1, LC0 - ldr r1, [r1] + * Function: *_set_pgd(pgd_t *pgd) + * Params : pgd New page tables/MEMC mapping + * Purpose : update MEMC hardware with new mapping + */ + .word SYMBOL_NAME(page_nr) +_arm3_set_pgd: mcr p15, 0, r1, c1, c0, 0 @ flush cache +_arm2_set_pgd: stmfd sp!, {lr} + ldr r1, _arm3_set_pgd - 4 + ldr r2, [r1] + sub r0, r0, #256 * 4 @ start of MEMC tables + add r1, r0, r2, lsl #2 @ end of tables 1: ldmia r0!, {r2, r3, ip, lr} strb r2, [r2] strb r3, [r3] @@ -365,14 +200,12 @@ strb r3, [r3] strb ip, [ip] strb lr, [lr] - subs r1, r1, #8 - bhi 1b - mcr p15, 0, r0, c1, c0, 0 @ flush cache + teq r0, r1 + bne 1b ldmfd sp!, {pc}^ /* - * Function: arm3_proc_init (void) - * + * Function: *_proc_init (void) * Purpose : Initialise the cache control registers */ _arm3_proc_init: @@ -386,43 +219,55 @@ mcr p15, 0, r0, c1, c0 @ ARM3 Flush mov r0, #3 mcr p15, 0, r0, c2, c0 @ ARM3 Control +_arm2_proc_init: movs pc, lr /* - * Function: arm3_proc_fin (void) - * + * Function: *_proc_fin (void) * Purpose : Finalise processor (disable caches) */ _arm3_proc_fin: mov r0, #2 mcr p15, 0, r0, c2, c0 - movs pc, lr +_arm2_proc_fin: orrs pc, lr, #I_BIT|F_BIT /* - * Function: arm3_xchg_1 (int new, volatile void *ptr) - * + * Function: *_xchg_1 (int new, volatile void *ptr) * Params : new New value to store at... * : ptr pointer to byte-wide location - * * Purpose : Performs an exchange operation - * * Returns : Original byte data at 'ptr' */ +_arm2_xchg_1: mov r2, pc + orr r2, r2, #I_BIT + teqp r2, #0 + ldrb r2, [r1] + strb r0, [r1] + mov r0, r2 + movs pc, lr + _arm3_xchg_1: swpb r0, r0, [r1] movs pc, lr /* - * Function: arm3_xchg_4 (int new, volatile void *ptr) - * + * Function: *_xchg_4 (int new, volatile void *ptr) * Params : new New value to store at... * : ptr pointer to word-wide location - * * Purpose : Performs an exchange operation - * * Returns : Original word data at 'ptr' */ +_arm2_xchg_4: mov r2, pc + orr r2, r2, #I_BIT + teqp r2, #0 + ldr r2, [r1] + str r0, [r1] + mov r0, r2 + movs pc, lr + _arm3_xchg_4: swp r0, r0, [r1] movs pc, lr +_arm2_3_check_bugs: + bics pc, lr, #0x04000000 @ Clear FIQ disable bit armvlsi_name: .asciz "ARM/VLSI" _arm2_name: .asciz "arm2" @@ -436,57 +281,42 @@ */ .globl SYMBOL_NAME(arm2_processor_functions) SYMBOL_NAME(arm2_processor_functions): - .word _arm2_switch_to @ 4 - .word _arm2_3_data_abort @ 8 - .word _arm2_3_check_bugs @ 12 - .word _arm2_proc_init @ 16 - .word _arm2_proc_fin @ 20 - - .word _arm2_remap_memc @ 24 - .word _arm2_3_update_map @ 28 - .word _arm2_3_update_cache @ 32 - .word _arm2_xchg_1 @ 36 - .word SYMBOL_NAME(abort) @ 40 - .word _arm2_xchg_4 @ 44 - - .globl SYMBOL_NAME(arm250_processor_functions) -SYMBOL_NAME(arm250_processor_functions): - .word _arm2_switch_to @ 4 - .word _arm2_3_data_abort @ 8 - .word _arm2_3_check_bugs @ 12 - .word _arm2_proc_init @ 16 - .word _arm2_proc_fin @ 20 - - .word _arm2_remap_memc @ 24 - .word _arm2_3_update_map @ 28 - .word _arm2_3_update_cache @ 32 - .word _arm3_xchg_1 @ 36 - .word SYMBOL_NAME(abort) @ 40 - .word _arm3_xchg_4 @ 44 - - .globl SYMBOL_NAME(arm3_processor_functions) -SYMBOL_NAME(arm3_processor_functions): - .word _arm3_switch_to @ 4 - .word _arm2_3_data_abort @ 8 - .word _arm2_3_check_bugs @ 12 - .word _arm3_proc_init @ 16 - .word _arm3_proc_fin @ 20 - - .word _arm3_remap_memc @ 24 - .word _arm2_3_update_map @ 28 - .word _arm2_3_update_cache @ 32 - .word _arm3_xchg_1 @ 36 - .word SYMBOL_NAME(abort) @ 40 - .word _arm3_xchg_4 @ 44 + .word _arm2_3_check_bugs + .word _arm2_proc_init + .word _arm2_proc_fin + .word _arm2_set_pgd + .word _arm2_xchg_1 + .word SYMBOL_NAME(abort) + .word _arm2_xchg_4 cpu_arm2_info: .long armvlsi_name .long _arm2_name + .globl SYMBOL_NAME(arm250_processor_functions) +SYMBOL_NAME(arm250_processor_functions): + .word _arm2_3_check_bugs + .word _arm2_proc_init + .word _arm2_proc_fin + .word _arm2_set_pgd + .word _arm3_xchg_1 + .word SYMBOL_NAME(abort) + .word _arm3_xchg_4 + cpu_arm250_info: .long armvlsi_name .long _arm250_name + .globl SYMBOL_NAME(arm3_processor_functions) +SYMBOL_NAME(arm3_processor_functions): + .word _arm2_3_check_bugs + .word _arm3_proc_init + .word _arm3_proc_fin + .word _arm3_set_pgd + .word _arm3_xchg_1 + .word SYMBOL_NAME(abort) + .word _arm3_xchg_4 + cpu_arm3_info: .long armvlsi_name .long _arm3_name @@ -501,6 +331,8 @@ .long 0x41560200 .long 0xfffffff0 + .long 0 + mov pc, lr .long arm2_arch_name .long arm2_elf_name .long 0 @@ -509,6 +341,8 @@ .long 0x41560250 .long 0xfffffff0 + .long 0 + mov pc, lr .long arm3_arch_name .long arm3_elf_name .long 0 @@ -517,6 +351,8 @@ .long 0x41560300 .long 0xfffffff0 + .long 0 + mov pc, lr .long arm3_arch_name .long arm3_elf_name .long 0 diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.3.22/linux/arch/arm/mm/proc-arm6,7.S Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/mm/proc-arm6,7.S Wed Oct 20 16:29:08 1999 @@ -9,6 +9,7 @@ #include #include #include +#include #include "../lib/constants.h" /* @@ -70,6 +71,19 @@ mov pc, lr /* + * Function: arm6_7_flush_tlb_page (unsigned long address, int flags) + * + * Params : address Address + * : flags b0 = I-TLB as well + * + * Purpose : flush a TLB entry + */ +ENTRY(cpu_arm6_flush_tlb_page) +ENTRY(cpu_arm7_flush_tlb_page) + mcr p15, 0, r0, c6, c0, 0 @ flush TLB + mov pc, lr + +/* * Function: arm6_7_data_abort () * * Params : r0 = address of aborted instruction @@ -89,6 +103,16 @@ .align ENTRY(cpu_arm6_data_abort) +Ldata_simple: + ldr r4, [r0] @ read instruction causing problem + mov r2, r4, lsr #19 @ r2 b1 = L + and r2, r2, #2 @ check read/write bit + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r1, c5, c0, 0 @ get FSR + and r1, r1, #15 + mov pc, lr + +ENTRY(cpu_arm7_data_abort) ldr r4, [r0] @ read instruction causing problem mov r2, r4, lsr #19 @ r2 b1 = L and r1, r4, #15 << 24 @@ -98,10 +122,10 @@ b Ldata_unknown b Ldata_unknown b Ldata_unknown - b Ldata_earlyldrpost @ ldr rd, [rn], #m - b Ldata_simple @ ldr rd, [rn, #m] @ RegVal - b Ldata_earlyldrpost @ ldr rd, [rn], rm - b Ldata_simple @ ldr rd, [rn, rm] + b Ldata_lateldrpostconst @ ldr rd, [rn], #m + b Ldata_lateldrpreconst @ ldr rd, [rn, #m] @ RegVal + b Ldata_lateldrpostreg @ ldr rd, [rn], rm + b Ldata_lateldrprereg @ ldr rd, [rn, rm] b Ldata_ldmstm @ ldm*a rn, b Ldata_ldmstm @ ldm*b rn, b Ldata_unknown @@ -119,29 +143,6 @@ bl SYMBOL_NAME(panic) Lstop: b Lstop -ENTRY(cpu_arm7_data_abort) - ldr r4, [r0] @ read instruction causing problem - mov r2, r4, lsr #19 @ r2 b1 = L - and r1, r4, #15 << 24 - add pc, pc, r1, lsr #22 @ Now branch to the relevent processing routine - movs pc, lr - b Ldata_unknown - b Ldata_unknown - b Ldata_unknown - b Ldata_unknown - b Ldata_lateldrpostconst @ ldr rd, [rn], #m - b Ldata_lateldrpreconst @ ldr rd, [rn, #m] @ RegVal - b Ldata_lateldrpostreg @ ldr rd, [rn], rm - b Ldata_lateldrprereg @ ldr rd, [rn, rm] - b Ldata_ldmstm @ ldm*a rn, - b Ldata_ldmstm @ ldm*b rn, - b Ldata_unknown - b Ldata_unknown - b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m - b Ldata_simple @ ldc rd, [rn, #m] - b Ldata_unknown - b Ldata_unknown - Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit beq Ldata_simple @@ -165,31 +166,16 @@ add r7, r0, r7, lsl #2 @ Do correction (signed) str r7, [sp, r5, lsr #14] @ Put register -Ldata_simple: and r2, r2, #2 @ check read/write bit - mrc p15, 0, r0, c6, c0, 0 @ get FAR - mrc p15, 0, r1, c5, c0, 0 @ get FSR - and r1, r1, #15 - mov pc, lr - -Ldata_earlyldrpost: - tst r2, #4 - and r2, r2, #2 @ check read/write bit - orrne r2, r2, #1 @ T bit - mrc p15, 0, r0, c6, c0, 0 @ get FAR - mrc p15, 0, r1, c5, c0, 0 @ get FSR - and r1, r1, #15 - mov pc, lr - Ldata_lateldrpostconst: movs r1, r4, lsl #20 @ Get offset - beq Ldata_earlyldrpost @ if offset is zero, no effect + beq Ldata_simple @ if offset is zero, no effect and r5, r4, #15 << 16 @ Get Rn ldr r0, [sp, r5, lsr #14] tst r4, #1 << 23 @ U bit subne r0, r0, r1, lsr #20 addeq r0, r0, r1, lsr #20 str r0, [sp, r5, lsr #14] @ Put register - b Ldata_earlyldrpost + b Ldata_simple Ldata_lateldrpreconst: tst r4, #1 << 21 @ check writeback bit @@ -252,7 +238,7 @@ subne r0, r0, r1 addeq r0, r0, r1 str r0, [sp, r5, lsr #14] @ Put register - b Ldata_earlyldrpost + b Ldata_simple Ldata_lateldrprereg: tst r4, #1 << 21 @ check writeback bit @@ -319,10 +305,24 @@ mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip + mov pc, lr + ENTRY(cpu_arm6_proc_init) ENTRY(cpu_arm7_proc_init) + mov pc, lr + ENTRY(cpu_arm6_proc_fin) ENTRY(cpu_arm7_proc_fin) + mrs r0, cpsr + orr r0, r0, #F_BIT | I_BIT + msr cpsr, r0 + mov r0, #0x31 @ ....S..DP...M + mcr p15, 0, r0, c1, c0, 0 @ disable caches + mov pc, lr + +ENTRY(cpu_arm6_do_idle) +ENTRY(cpu_arm7_do_idle) + mov r0, #-EINVAL mov pc, lr /* @@ -381,23 +381,22 @@ ENTRY(cpu_arm7_set_pte) str r1, [r0], #-1024 @ linux version + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + bic r2, r1, #0xff0 bic r2, r2, #3 orr r2, r2, #HPTE_TYPE_SMALL - tst r1, #LPTE_USER | LPTE_EXEC + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? orrne r2, r2, #HPTE_AP_READ - tst r1, #LPTE_WRITE - tstne r1, #LPTE_DIRTY - orrne r2, r2, #HPTE_AP_WRITE - - tst r1, #LPTE_PRESENT - tstne r1, #LPTE_YOUNG - moveq r2, #0 + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young + movne r2, #0 str r2, [r0] @ hardware version - mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) mov pc, lr /* @@ -407,13 +406,9 @@ */ ENTRY(cpu_arm6_reset) ENTRY(cpu_arm7_reset) - mrs r1, cpsr - orr r1, r1, #F_BIT|I_BIT - msr cpsr, r1 mov r0, #0 mcr p15, 0, r0, c7, c0, 0 @ flush cache mcr p15, 0, r0, c5, c0, 0 @ flush TLB - mov r1, #F_BIT | I_BIT | 3 mov pc, lr cpu_armvlsi_name: @@ -428,6 +423,26 @@ .section ".text.init", #alloc, #execinstr +__arm6_setup: mov r0, #0 + mcr p15, 0, r0, c7, c0 @ flush caches on v3 + mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mov r0, #0x3d @ ....S..DPWC.M + orr r0, r0, #0x100 + mov pc, lr + +__arm7_setup: mov r0, #0 + mcr p15, 0, r0, c7, c0 @ flush caches on v3 + mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mov r0, #0x7d @ ....S.LDPWC.M + orr r0, r0, #0x100 + mov pc, lr + /* * Purpose : Function pointers used to access above functions - all calls * come through these @@ -452,6 +467,8 @@ .word cpu_arm6_flush_icache_area .word cpu_arm6_cache_wback_area .word cpu_arm6_cache_purge_area + .word cpu_arm6_flush_tlb_page + .word cpu_arm7_do_idle .size arm6_processor_functions, . - arm6_processor_functions /* @@ -478,6 +495,8 @@ .word cpu_arm7_flush_icache_area .word cpu_arm7_cache_wback_area .word cpu_arm7_cache_purge_area + .word cpu_arm7_flush_tlb_page + .word cpu_arm7_do_idle .size arm7_processor_functions, . - arm7_processor_functions .type cpu_arm6_info, #object @@ -519,9 +538,11 @@ __arm6_proc_info: .long 0x41560600 .long 0xfffffff0 + .long 0x00000c12 + b __arm6_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP + .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm6_info .long arm6_processor_functions .size __arm6_proc_info, . - __arm6_proc_info @@ -530,9 +551,11 @@ __arm610_proc_info: .long 0x41560610 .long 0xfffffff0 + .long 0x00000c12 + b __arm6_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP + .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm610_info .long arm6_processor_functions .size __arm610_proc_info, . - __arm610_proc_info @@ -541,9 +564,11 @@ __arm7_proc_info: .long 0x41007000 .long 0xffffff00 + .long 0x00000c12 + b __arm7_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP + .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm7_info .long arm7_processor_functions .size __arm7_proc_info, . - __arm7_proc_info @@ -552,9 +577,11 @@ __arm710_proc_info: .long 0x41007100 .long 0xfff8ff00 + .long 0x00000c12 + b __arm7_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP + .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm710_info .long arm7_processor_functions .size __arm710_proc_info, . - __arm710_proc_info diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.3.22/linux/arch/arm/mm/proc-sa110.S Tue Sep 7 12:14:06 1999 +++ linux/arch/arm/mm/proc-sa110.S Wed Oct 20 16:29:08 1999 @@ -4,7 +4,7 @@ * (C) 1997-1999 Russell King * * These are the low level assembler for performing cache and TLB - * functions on the sa110. + * functions on the StrongARM-110 and StrongARM-1100 */ #include #include @@ -17,6 +17,27 @@ */ #define MAX_AREA_SIZE 32768 + .macro flush_110_dcache rd, ra, re + add \re, \ra, #16384 @ only necessary for 16k +1001: ldr \rd, [\ra], #32 + teq \re, \ra + bne 1001b + .endm + + .macro flush_1100_dcache rd, ra, re + add \re, \ra, #8192 @ only necessary for 8k +1001: ldr \rd, [\ra], #32 + teq \re, \ra + bne 1001b +#ifdef FLUSH_BASE_MINICACHE + add \ra, \ra, #FLUSH_BASE_MINICACHE - FLUSH_BASE + add \re, \ra, #512 @ only 512 bytes +1002: ldr \rd, [\ra], #32 + teq \re, \ra + bne 1002b +#endif + .endm + .data Lclean_switch: .long 0 .text @@ -36,12 +57,27 @@ eor r1, r1, #1 str r1, [r3] addne ip, ip, #32768 - add r1, ip, #16384 @ only necessary for 16k -1: ldr r3, [ip], #32 - teq r1, ip - bne 1b + flush_110_dcache r3, ip, r1 + mov ip, #0 + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ flush I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + + .align 5 +ENTRY(cpu_sa1100_flush_cache_all) @ preserves r0 + mov r2, #1 +cpu_sa1100_flush_cache_all_r2: + ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE + ldr r1, [r3] + ands r1, r1, #1 + eor r1, r1, #1 + str r1, [r3] + addne ip, ip, #32768 + flush_1100_dcache r3, ip, r1 mov ip, #0 - tst r2, #1 + teq r2, #0 mcrne p15, 0, ip, c7, c5, 0 @ flush I cache mcr p15, 0, ip, c7, c10, 4 @ drain WB mov pc, lr @@ -66,11 +102,17 @@ add r0, r0, #32 cmp r0, r1 blt 1b - tst r2, #1 + teq r2, #0 movne r0, #0 mcrne p15, 0, r0, c7, c5, 0 @ flush I cache mov pc, lr +ENTRY(cpu_sa1100_flush_cache_area) + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_sa1100_flush_cache_all_r2 + b 1b + /* * Function: sa110_cache_wback_area(unsigned long address, unsigned long end) * Params : address Area start address @@ -94,6 +136,13 @@ mcr p15, 0, r2, c7, c10, 4 @ drain WB mov pc, lr +ENTRY(cpu_sa1100_cache_wback_area) + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_sa1100_flush_cache_all_r2 + bic r0, r0, #31 + b 1b /* * Function: sa110_cache_purge_area(unsigned long address, unsigned long end) * Params : address Area start address @@ -105,6 +154,7 @@ */ .align 5 ENTRY(cpu_sa110_cache_purge_area) +ENTRY(cpu_sa1100_cache_purge_area) tst r0, #31 bic r0, r0, #31 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry @@ -123,6 +173,7 @@ */ .align 5 ENTRY(cpu_sa110_flush_cache_entry) +ENTRY(cpu_sa1100_flush_cache_entry) mov r1, #0 mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r1, c7, c10, 4 @ drain WB @@ -136,6 +187,7 @@ * for page table purposes. */ ENTRY(cpu_sa110_clean_cache_area) +ENTRY(cpu_sa1100_clean_cache_area) 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) add r0, r0, #32 subs r1, r1, #32 @@ -149,6 +201,7 @@ */ .align 5 ENTRY(cpu_sa110_flush_ram_page) +ENTRY(cpu_sa1100_flush_ram_page) mov r1, #4096 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, #32 @@ -170,6 +223,7 @@ */ .align 5 ENTRY(cpu_sa110_flush_tlb_all) +ENTRY(cpu_sa1100_flush_tlb_all) mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c8, c7, 0 @ flush I & D tlbs @@ -184,6 +238,7 @@ */ .align 5 ENTRY(cpu_sa110_flush_tlb_area) +ENTRY(cpu_sa1100_flush_tlb_area) mov r3, #0 mcr p15, 0, r3, c7, c10, 4 @ drain WB 1: cmp r0, r1 @@ -193,12 +248,35 @@ mcrlt p15, 0, r0, c8, c6, 1 @ flush D TLB entry addlt r0, r0, #4096 blt 1b - tst r2, #1 + teq r2, #0 + mcrne p15, 0, r3, c8, c5, 0 @ flush I TLB + mov pc, lr + +/* + * Function: sa110_flush_tlb_page (unsigned long address, int flags) + * Params : address Address to flush + * : flags b0 = I-TLB as well + * Purpose : flush a TLB entry + */ + .align 5 +ENTRY(cpu_sa110_flush_tlb_page) +ENTRY(cpu_sa1100_flush_tlb_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c6, 1 @ flush D TLB entry + teq r1, #0 mcrne p15, 0, r3, c8, c5, 0 @ flush I TLB mov pc, lr +/* + * Function: sa110_flush_icache_area (unsigned long address, unsigned long size) + * Params : address Address of area to flush + * : size Size of area to flush + * Purpose : flush an area from the Icache + */ .align 5 ENTRY(cpu_sa110_flush_icache_area) +ENTRY(cpu_sa1100_flush_icache_area) 1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry add r0, r0, #32 subs r1, r1, #32 @@ -218,6 +296,7 @@ */ .align 5 ENTRY(cpu_sa110_data_abort) +ENTRY(cpu_sa1100_data_abort) ldr r2, [r0] @ read instruction causing problem mrc p15, 0, r0, c6, c0, 0 @ get FAR mov r2, r2, lsr #19 @ b1 = L @@ -237,16 +316,30 @@ .align 5 ENTRY(cpu_sa110_set_pgd) ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE ldr r2, [r3] ands r2, r2, #1 eor r2, r2, #1 str r2, [r3] - ldr r2, =FLUSH_BASE - addne r2, r2, #32768 - add r1, r2, #16384 @ only necessary for 16k -1: ldr r3, [r2], #32 - teq r1, r2 - bne 1b + addne ip, ip, #32768 + flush_110_dcache r3, ip, r1 + mov r1, #0 + mcr p15, 0, r1, c7, c5, 0 @ flush I cache + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, r1, c8, c7, 0 @ flush TLBs + mov pc, lr + + .align 5 +ENTRY(cpu_sa1100_set_pgd) + ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE + ldr r2, [r3] + ands r2, r2, #1 + eor r2, r2, #1 + str r2, [r3] + addne ip, ip, #32768 + flush_1100_dcache r3, ip, r1 mov r1, #0 mcr p15, 0, r1, c7, c5, 0 @ flush I cache mcr p15, 0, r1, c7, c10, 4 @ drain WB @@ -262,9 +355,10 @@ */ .align 5 ENTRY(cpu_sa110_set_pmd) +ENTRY(cpu_sa1100_set_pmd) str r1, [r0] mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c10, 4 @ drain WB (TLB bypasses WB) + mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr /* @@ -275,6 +369,7 @@ */ .align 5 ENTRY(cpu_sa110_set_pte) +ENTRY(cpu_sa1100_set_pte) str r1, [r0], #-1024 @ linux version eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY @@ -294,8 +389,8 @@ str r2, [r0] @ hardware version mov r0, r0 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) - mcr p15, 0, r0, c7, c10, 4 @ drain WB (TLB bypasses WB) + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr /* @@ -305,12 +400,39 @@ * Notes : This processor does not require these */ ENTRY(cpu_sa110_check_bugs) +ENTRY(cpu_sa1100_check_bugs) mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip + mov pc, lr ENTRY(cpu_sa110_proc_init) +ENTRY(cpu_sa1100_proc_init) + mov r0, #0 + mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching + mov pc, lr + ENTRY(cpu_sa110_proc_fin) +ENTRY(cpu_sa1100_proc_fin) + mrs r0, cpsr + orr r0, r0, #F_BIT | I_BIT + msr cpsr, r0 + mov r0, #0 + mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x1100 @ ...i...s........ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + mov pc, lr + + .align 5 +ENTRY(cpu_sa110_do_idle) +ENTRY(cpu_sa1100_do_idle) + mov r0, #0 + mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching + @ load from uncacheable loc? + mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt + mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching mov pc, lr /* @@ -318,17 +440,13 @@ * Notes : This sets up everything for a reset */ ENTRY(cpu_sa110_reset) - mrs r1, cpsr - orr r1, r1, #F_BIT | I_BIT - msr cpsr, r1 +ENTRY(cpu_sa1100_reset) stmfd sp!, {r1, lr} - mov r2, #1 bl cpu_sa110_flush_cache_all bl cpu_sa110_flush_tlb_all mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches mrc p15, 0, r0, c1, c0, 0 @ ctrl register - bic r0, r0, #0x1800 - bic r0, r0, #0x000f + bic r0, r0, #1 @ ...............m ldmfd sp!, {r1, pc} /* * Purpose : Function pointers used to access above functions - all calls @@ -338,10 +456,26 @@ cpu_manu_name: .asciz "Intel" ENTRY(cpu_sa110_name) .asciz "sa110" +ENTRY(cpu_sa1100_name) + .asciz "sa1100" .align .section ".text.init", #alloc, #execinstr +__sa110_setup: mov r0, #0 + mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ flush I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + orr r0, r0, #0x003d @ ..........DPWC.M + orr r0, r0, #0x1100 @ ...I...S........ + mov pc, lr + .type sa110_processor_functions, #object ENTRY(sa110_processor_functions) .word cpu_sa110_data_abort @@ -362,7 +496,8 @@ .word cpu_sa110_flush_icache_area .word cpu_sa110_cache_wback_area .word cpu_sa110_cache_purge_area - + .word cpu_sa110_flush_tlb_page + .word cpu_sa110_do_idle .size sa110_processor_functions, . - sa110_processor_functions .type cpu_sa110_info, #object @@ -371,6 +506,36 @@ .long cpu_sa110_name .size cpu_sa110_info, . - cpu_sa110_info + + .type sa1100_processor_functions, #object +ENTRY(sa1100_processor_functions) + .word cpu_sa1100_data_abort + .word cpu_sa1100_check_bugs + .word cpu_sa1100_proc_init + .word cpu_sa1100_proc_fin + .word cpu_sa1100_flush_cache_all + .word cpu_sa1100_flush_cache_area + .word cpu_sa1100_flush_cache_entry + .word cpu_sa1100_clean_cache_area + .word cpu_sa1100_flush_ram_page + .word cpu_sa1100_flush_tlb_all + .word cpu_sa1100_flush_tlb_area + .word cpu_sa1100_set_pgd + .word cpu_sa1100_set_pmd + .word cpu_sa1100_set_pte + .word cpu_sa1100_reset + .word cpu_sa1100_flush_icache_area + .word cpu_sa1100_cache_wback_area + .word cpu_sa1100_cache_purge_area + .word cpu_sa1100_flush_tlb_page + .word cpu_sa1100_do_idle + .size sa1100_processor_functions, . - sa1100_processor_functions + +cpu_sa1100_info: + .long cpu_manu_name + .long cpu_sa1100_name + .size cpu_sa1100_info, . - cpu_sa1100_info + .type cpu_arch_name, #object cpu_arch_name: .asciz "armv4" .size cpu_arch_name, . - cpu_arch_name @@ -385,9 +550,26 @@ __sa110_proc_info: .long 0x4401a100 .long 0xfffffff0 + .long 0x00000c02 + b __sa110_setup .long cpu_arch_name .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT .long cpu_sa110_info .long sa110_processor_functions .size __sa110_proc_info, . - __sa110_proc_info + + .type __sa1100_proc_info,#object +__sa1100_proc_info: + .long 0x4401a110 + .long 0xfffffff0 + .long 0x00000c02 + b __sa110_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_sa1100_info + .long sa1100_processor_functions + .size __sa1100_proc_info, . - __sa1100_proc_info + + diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/ChangeLog linux/arch/arm/nwfpe/ChangeLog --- v2.3.22/linux/arch/arm/nwfpe/ChangeLog Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/ChangeLog Wed Oct 20 16:29:08 1999 @@ -1,10 +1,50 @@ -1998-11-23 Scott Bambrough +1999-08-19 Scott Bambrough + + * fpmodule.c - Changed version number to 0.95 + * fpa11.h - modified FPA11, FPREG structures + * fpa11.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cpdt.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cprt.c - Changes due to FPA11, FPREG structure alterations. + * single_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * double_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * extended_cpdo.c - Changes due to FPA11, FPREG structure alterations. + + * I discovered several bugs. First and worst is that the kernel + passes in a pointer to the FPE's state area. This is defined + as a struct user_fp (see user.h). This pointer was cast to a + FPA11*. Unfortunately FPA11 and user_fp are of different sizes; + user_fp is smaller. This meant that the FPE scribbled on things + below its area, which is bad, as the area is in the thread_struct + embedded in the process task structure. Thus we were scribbling + over one of the most important structures in the entire OS. + + * user_fp and FPA11 have now been harmonized. Most of the changes + in the above code were dereferencing problems due to moving the + register type out of FPREG, and getting rid of the union variable + fpvalue. + + * Second I noticed resetFPA11 was not always being called for a + task. This should happen on the first floating point exception + that occurs. It is controlled by init_flag in FPA11. The + comment in the code beside init_flag state the kernel guarantees + this to be zero. Not so. I found that the kernel recycles task + structures, and that recycled ones may not have init_flag zeroed. + I couldn't even find anything that guarantees it is zeroed when + when the task structure is initially allocated. In any case + I now initialize the entire FPE state in the thread structure to + zero when allocated and recycled. See alloc_task_struct() and + flush_thread() in arch/arm/process.c. The change to + alloc_task_struct() may not be necessary, but I left it in for + completeness (better safe than sorry). + +1998-11-23 Scott Bambrough * README.FPE - fix typo in description of lfm/sfm instructions * NOTES - Added file to describe known bugs/problems * fpmodule.c - Changed version number to 0.94 -1998-11-20 Scott Bambrough +1998-11-20 Scott Bambrough * README.FPE - fix description of URD, NRM instructions * TODO - remove URD, NRM instructions from TODO list @@ -12,7 +52,7 @@ * double_cpdo.c - implement URD, NRM * extended_cpdo.c - implement URD, NRM -1998-11-19 Scott Bambrough +1998-11-19 Scott Bambrough * ChangeLog - Added this file to track changes made. * fpa11.c - added code to initialize register types to typeNone diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/Makefile linux/arch/arm/nwfpe/Makefile --- v2.3.22/linux/arch/arm/nwfpe/Makefile Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/Makefile Wed Oct 20 16:29:08 1999 @@ -14,16 +14,15 @@ NWFPE_OBJS += entry.o endif -L_TARGET := math-emu.a - ifeq ($(CONFIG_NWFPE),y) -L_OBJS = $(NWFPE_OBJS) +O_TARGET := math-emu.o +O_OBJS = $(NWFPE_OBJS) else ifeq ($(CONFIG_NWFPE),m) M_OBJS = nwfpe.o MI_OBJS = $(NWFPE_OBJS) endif -endif +endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/double_cpdo.c linux/arch/arm/nwfpe/double_cpdo.c --- v2.3.22/linux/arch/arm/nwfpe/double_cpdo.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/double_cpdo.c Wed Oct 20 16:29:08 1999 @@ -19,7 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" @@ -54,14 +53,14 @@ } else { - switch (fpa11->fpreg[Fm].fType) + switch (fpa11->fType[Fm]) { case typeSingle: - rFm = float32_to_float64(fpa11->fpreg[Fm].fValue.fSingle); + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); break; case typeDouble: - rFm = fpa11->fpreg[Fm].fValue.fDouble; + rFm = fpa11->fpreg[Fm].fDouble; break; case typeExtended: @@ -80,14 +79,14 @@ if (!MONADIC_INSTRUCTION(opcode)) { Fn = getFn(opcode); - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: - rFn = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle); + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); break; case typeDouble: - rFn = fpa11->fpreg[Fn].fValue.fDouble; + rFn = fpa11->fpreg[Fn].fDouble; break; default: return 0; @@ -100,62 +99,62 @@ { /* dyadic opcodes */ case ADF_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_add(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm); break; case MUF_CODE: case FML_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_mul(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm); break; - case SUF_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFn,rFm); + case SUF_CODE: + fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm); break; case RSF_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFm,rFn); + fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn); break; case DVF_CODE: case FDV_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm); break; case RDF_CODE: case FRD_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFm,rFn); + fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn); break; #if 0 case POW_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); break; case RPW_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFm,rFn); + fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); break; #endif case RMF_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_rem(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm); break; #if 0 case POL_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_pol(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); break; #endif /* monadic opcodes */ case MVF_CODE: - fpa11->fpreg[Fd].fValue.fDouble = rFm; + fpa11->fpreg[Fd].fDouble = rFm; break; case MNF_CODE: { unsigned int *p = (unsigned int*)&rFm; p[1] ^= 0x80000000; - fpa11->fpreg[Fd].fValue.fDouble = rFm; + fpa11->fpreg[Fd].fDouble = rFm; } break; @@ -163,55 +162,55 @@ { unsigned int *p = (unsigned int*)&rFm; p[1] &= 0x7fffffff; - fpa11->fpreg[Fd].fValue.fDouble = rFm; + fpa11->fpreg[Fd].fDouble = rFm; } break; case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fValue.fDouble = + fpa11->fpreg[Fd].fDouble = int32_to_float64(float64_to_int32(rFm)); break; case SQT_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_sqrt(rFm); + fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm); break; #if 0 case LOG_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_log(rFm); + fpa11->fpreg[Fd].fDouble = float64_log(rFm); break; case LGN_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_ln(rFm); + fpa11->fpreg[Fd].fDouble = float64_ln(rFm); break; case EXP_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_exp(rFm); + fpa11->fpreg[Fd].fDouble = float64_exp(rFm); break; case SIN_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_sin(rFm); + fpa11->fpreg[Fd].fDouble = float64_sin(rFm); break; case COS_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_cos(rFm); + fpa11->fpreg[Fd].fDouble = float64_cos(rFm); break; case TAN_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_tan(rFm); + fpa11->fpreg[Fd].fDouble = float64_tan(rFm); break; case ASN_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_arcsin(rFm); + fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); break; case ACS_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_arccos(rFm); + fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); break; case ATN_CODE: - fpa11->fpreg[Fd].fValue.fDouble = float64_arctan(rFm); + fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); break; #endif @@ -224,7 +223,7 @@ } } - if (0 != nRc) fpa11->fpreg[Fd].fType = typeDouble; + if (0 != nRc) fpa11->fType[Fd] = typeDouble; return nRc; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/entry.S linux/arch/arm/nwfpe/entry.S --- v2.3.22/linux/arch/arm/nwfpe/entry.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/entry.S Wed Oct 20 16:29:08 1999 @@ -3,7 +3,7 @@ (c) Corel Computer Corporation, 1998 (c) Philip Blundell 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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 @@ -85,14 +85,15 @@ mov r10, lr @ save the failure-return addresses ldr r5, [r4, #60] @ get contents of PC; - ldr r0, [r5, #-4] @ get actual instruction into r0 + sub r8, r5, #4 +.Lx2: ldrt r0, [r8], #0 @ get actual instruction into r0 emulate: bl EmulateAll @ emulate the instruction cmp r0, #0 @ was emulation successful moveq pc, r10 @ no, return failure next: -__x1: ldrt r6, [r5], #4 @ get the next instruction and +.Lx1: ldrt r6, [r5], #4 @ get the next instruction and @ increment PC and r2, r6, #0x0F000000 @ test for FP insns @@ -114,13 +115,15 @@ mov r0, r6 @ prepare for EmulateAll() b emulate @ if r0 != 0, goto EmulateAll - @ We need to be prepared for the instruction at __x1 to fault. - @ Emit the appropriate exception gunk to fix things up. + @ We need to be prepared for the instruction at .Lx1 or .Lx2 + @ to fault. .section .fixup,"ax" .align -__f1: mov pc, r9 +.Lfix: mov pc, r9 .previous + .section __ex_table,"a" .align 3 - .long __x1, __f1 + .long .Lx2, .Lfix + .long .Lx1, .Lfix .previous diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/entry26.S linux/arch/arm/nwfpe/entry26.S --- v2.3.22/linux/arch/arm/nwfpe/entry26.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/entry26.S Wed Oct 20 16:29:08 1999 @@ -3,7 +3,7 @@ (c) Corel Computer Corporation, 1998 (c) Philip Blundell 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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.22/linux/arch/arm/nwfpe/extended_cpdo.c linux/arch/arm/nwfpe/extended_cpdo.c --- v2.3.22/linux/arch/arm/nwfpe/extended_cpdo.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/extended_cpdo.c Wed Oct 20 16:29:08 1999 @@ -19,7 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" @@ -52,18 +51,18 @@ } else { - switch (fpa11->fpreg[Fm].fType) + switch (fpa11->fType[Fm]) { case typeSingle: - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle); + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); break; case typeDouble: - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble); + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); break; case typeExtended: - rFm = fpa11->fpreg[Fm].fValue.fExtended; + rFm = fpa11->fpreg[Fm].fExtended; break; default: return 0; @@ -73,18 +72,18 @@ if (!MONADIC_INSTRUCTION(opcode)) { Fn = getFn(opcode); - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); break; case typeDouble: - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); break; case typeExtended: - rFn = fpa11->fpreg[Fn].fValue.fExtended; + rFn = fpa11->fpreg[Fn].fExtended; break; default: return 0; @@ -96,112 +95,112 @@ { /* dyadic opcodes */ case ADF_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_add(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); break; case MUF_CODE: case FML_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_mul(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm); break; case SUF_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm); break; case RSF_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFm,rFn); + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn); break; case DVF_CODE: case FDV_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm); break; case RDF_CODE: case FRD_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFm,rFn); + fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn); break; #if 0 case POW_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); break; case RPW_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFm,rFn); + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); break; #endif case RMF_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_rem(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm); break; #if 0 case POL_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_pol(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); break; #endif /* monadic opcodes */ case MVF_CODE: - fpa11->fpreg[Fd].fValue.fExtended = rFm; + fpa11->fpreg[Fd].fExtended = rFm; break; case MNF_CODE: rFm.high ^= 0x8000; - fpa11->fpreg[Fd].fValue.fExtended = rFm; + fpa11->fpreg[Fd].fExtended = rFm; break; case ABS_CODE: rFm.high &= 0x7fff; - fpa11->fpreg[Fd].fValue.fExtended = rFm; + fpa11->fpreg[Fd].fExtended = rFm; break; case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fValue.fExtended = + fpa11->fpreg[Fd].fExtended = int32_to_floatx80(floatx80_to_int32(rFm)); break; case SQT_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_sqrt(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm); break; #if 0 case LOG_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_log(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); break; case LGN_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_ln(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); break; case EXP_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_exp(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); break; case SIN_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_sin(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); break; case COS_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_cos(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); break; case TAN_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_tan(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); break; case ASN_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_arcsin(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); break; case ACS_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_arccos(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); break; case ATN_CODE: - fpa11->fpreg[Fd].fValue.fExtended = floatx80_arctan(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); break; #endif @@ -214,7 +213,7 @@ } } - if (0 != nRc) fpa11->fpreg[Fd].fType = typeExtended; + if (0 != nRc) fpa11->fType[Fd] = typeExtended; return nRc; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11.c linux/arch/arm/nwfpe/fpa11.c --- v2.3.22/linux/arch/arm/nwfpe/fpa11.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/fpa11.c Wed Oct 20 16:29:08 1999 @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" +#include + #include "fpa11.h" -#include "milieu.h" #include "fpopcode.h" #include "fpmodule.h" @@ -39,17 +39,18 @@ void resetFPA11(void) { int i; - /* initialize the registers */ + + /* initialize the register type array */ for (i=0;i<=7;i++) { - fpa11->fpreg[i].fType = typeNone; + fpa11->fType[i] = typeNone; } /* FPSR: set system id to FP_EMULATOR, clear all other bits */ fpa11->fpsr = FP_EMULATOR; /* FPCR: set SB, AB and DA bits, clear all others */ -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr = MASK_RESET; #endif } @@ -128,6 +129,9 @@ unsigned int EmulateAll(unsigned int opcode) { unsigned int nRc = 0; + unsigned long flags; + + save_flags(flags); sti(); if (fpa11->initflag == 0) /* good place for __builtin_expect */ { @@ -161,6 +165,8 @@ /* Invalid instruction detected. Return FALSE. */ nRc = 0; } + + restore_flags(flags); return(nRc); } diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11.h linux/arch/arm/nwfpe/fpa11.h --- v2.3.22/linux/arch/arm/nwfpe/fpa11.h Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/fpa11.h Wed Oct 20 16:29:08 1999 @@ -31,25 +31,25 @@ #define typeDouble 0x02 #define typeExtended 0x03 -typedef struct tagFPREG { - unsigned int fType; - union { - float32 fSingle; - float64 fDouble; - floatx80 fExtended; - } fValue; +typedef union tagFPREG { + float32 fSingle; + float64 fDouble; + floatx80 fExtended; } FPREG; /* FPA11 device model */ typedef struct tagFPA11 { + FPREG fpreg[8]; /* 8 floating point registers */ + FPSR fpsr; /* floating point status register */ + FPCR fpcr; /* floating point control register */ + unsigned char fType[8]; /* type of floating point value held in + floating point registers. One of none + single, double or extended. */ int initflag; /* this is special. The kernel guarantees to set it to 0 when a thread is launched, so we can use it to detect whether this instance of the emulator needs to be initialised. */ - FPREG fpreg[8]; /* 8 floating point registers */ - FPSR fpsr; /* floating point status register */ - FPCR fpcr; /* floating point control register */ } FPA11; extern void resetFPA11(void); diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11.inl linux/arch/arm/nwfpe/fpa11.inl --- v2.3.22/linux/arch/arm/nwfpe/fpa11.inl Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpa11.inl Wed Oct 20 16:29:08 1999 @@ -2,7 +2,7 @@ NetWinder Floating Point Emulator (c) Corel Computer Corporation, 1998 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough 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.22/linux/arch/arm/nwfpe/fpa11_cpdo.c linux/arch/arm/nwfpe/fpa11_cpdo.c --- v2.3.22/linux/arch/arm/nwfpe/fpa11_cpdo.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/fpa11_cpdo.c Wed Oct 20 16:29:08 1999 @@ -19,7 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" #include "fpa11.h" #include "fpopcode.h" @@ -48,14 +47,14 @@ if (MONADIC_INSTRUCTION(opcode)) nType = nDest; else - nType = fpa11->fpreg[getFn(opcode)].fType; + nType = fpa11->fType[getFn(opcode)]; if (!CONSTANT_FM(opcode)) { register unsigned int Fm = getFm(opcode); - if (nType < fpa11->fpreg[Fm].fType) + if (nType < fpa11->fType[Fm]) { - nType = fpa11->fpreg[Fm].fType; + nType = fpa11->fType[Fm]; } } @@ -71,7 +70,7 @@ destination register is the correct size. If not force it to be. */ Fd = getFd(opcode); - nType = fpa11->fpreg[Fd].fType; + nType = fpa11->fType[Fd]; if ((0 != nRc) && (nDest != nType)) { switch (nDest) @@ -79,38 +78,38 @@ case typeSingle: { if (typeDouble == nType) - fpa11->fpreg[Fd].fValue.fSingle = - float64_to_float32(fpa11->fpreg[Fd].fValue.fDouble); + fpa11->fpreg[Fd].fSingle = + float64_to_float32(fpa11->fpreg[Fd].fDouble); else - fpa11->fpreg[Fd].fValue.fSingle = - floatx80_to_float32(fpa11->fpreg[Fd].fValue.fExtended); + fpa11->fpreg[Fd].fSingle = + floatx80_to_float32(fpa11->fpreg[Fd].fExtended); } break; case typeDouble: { if (typeSingle == nType) - fpa11->fpreg[Fd].fValue.fDouble = - float32_to_float64(fpa11->fpreg[Fd].fValue.fSingle); + fpa11->fpreg[Fd].fDouble = + float32_to_float64(fpa11->fpreg[Fd].fSingle); else - fpa11->fpreg[Fd].fValue.fDouble = - floatx80_to_float64(fpa11->fpreg[Fd].fValue.fExtended); + fpa11->fpreg[Fd].fDouble = + floatx80_to_float64(fpa11->fpreg[Fd].fExtended); } break; case typeExtended: { if (typeSingle == nType) - fpa11->fpreg[Fd].fValue.fExtended = - float32_to_floatx80(fpa11->fpreg[Fd].fValue.fSingle); + fpa11->fpreg[Fd].fExtended = + float32_to_floatx80(fpa11->fpreg[Fd].fSingle); else - fpa11->fpreg[Fd].fValue.fExtended = - float64_to_floatx80(fpa11->fpreg[Fd].fValue.fDouble); + fpa11->fpreg[Fd].fExtended = + float64_to_floatx80(fpa11->fpreg[Fd].fDouble); } break; } - fpa11->fpreg[Fd].fType = nDest; + fpa11->fType[Fd] = nDest; } return nRc; diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11_cpdt.c linux/arch/arm/nwfpe/fpa11_cpdt.c --- v2.3.22/linux/arch/arm/nwfpe/fpa11_cpdt.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/fpa11_cpdt.c Wed Oct 20 16:29:08 1999 @@ -20,7 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" @@ -32,16 +31,16 @@ extern __inline__ void loadSingle(const unsigned int Fn,const unsigned int *pMem) { - fpa11->fpreg[Fn].fType = typeSingle; - get_user(fpa11->fpreg[Fn].fValue.fSingle, pMem); + fpa11->fType[Fn] = typeSingle; + get_user(fpa11->fpreg[Fn].fSingle, pMem); } extern __inline__ void loadDouble(const unsigned int Fn,const unsigned int *pMem) { unsigned int *p; - p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fDouble; - fpa11->fpreg[Fn].fType = typeDouble; + p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; + fpa11->fType[Fn] = typeDouble; get_user(p[0], &pMem[1]); get_user(p[1], &pMem[0]); /* sign & exponent */ } @@ -50,8 +49,8 @@ void loadExtended(const unsigned int Fn,const unsigned int *pMem) { unsigned int *p; - p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fExtended; - fpa11->fpreg[Fn].fType = typeExtended; + p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; + fpa11->fType[Fn] = typeExtended; get_user(p[0], &pMem[0]); /* sign & exponent */ get_user(p[1], &pMem[2]); /* ls bits */ get_user(p[2], &pMem[1]); /* ms bits */ @@ -63,11 +62,11 @@ register unsigned int *p; unsigned long x; - p = (unsigned int*)&(fpa11->fpreg[Fn].fValue); + p = (unsigned int*)&(fpa11->fpreg[Fn]); get_user(x, &pMem[0]); - fpa11->fpreg[Fn].fType = (x >> 14) & 0x00000003; + fpa11->fType[Fn] = (x >> 14) & 0x00000003; - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: case typeDouble: @@ -94,17 +93,17 @@ float32 val; register unsigned int *p = (unsigned int*)&val; - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeDouble: - val = float64_to_float32(fpa11->fpreg[Fn].fValue.fDouble); + val = float64_to_float32(fpa11->fpreg[Fn].fDouble); break; case typeExtended: - val = floatx80_to_float32(fpa11->fpreg[Fn].fValue.fExtended); + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); break; - default: val = fpa11->fpreg[Fn].fValue.fSingle; + default: val = fpa11->fpreg[Fn].fSingle; } put_user(p[0], pMem); @@ -116,17 +115,17 @@ float64 val; register unsigned int *p = (unsigned int*)&val; - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: - val = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle); + val = float32_to_float64(fpa11->fpreg[Fn].fSingle); break; case typeExtended: - val = floatx80_to_float64(fpa11->fpreg[Fn].fValue.fExtended); + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); break; - default: val = fpa11->fpreg[Fn].fValue.fDouble; + default: val = fpa11->fpreg[Fn].fDouble; } put_user(p[1], &pMem[0]); /* msw */ put_user(p[0], &pMem[1]); /* lsw */ @@ -138,17 +137,17 @@ floatx80 val; register unsigned int *p = (unsigned int*)&val; - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: - val = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); break; case typeDouble: - val = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); break; - default: val = fpa11->fpreg[Fn].fValue.fExtended; + default: val = fpa11->fpreg[Fn].fExtended; } put_user(p[0], &pMem[0]); /* sign & exp */ @@ -161,8 +160,8 @@ { register unsigned int nType, *p; - p = (unsigned int*)&(fpa11->fpreg[Fn].fValue); - nType = fpa11->fpreg[Fn].fType; + p = (unsigned int*)&(fpa11->fpreg[Fn]); + nType = fpa11->fType[Fn]; switch (nType) { @@ -187,12 +186,17 @@ unsigned int PerformLDF(const unsigned int opcode) { - unsigned int *pBase, *pAddress, *pFinal, nRc = 1; - + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) pBase += 2; + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } pFinal = pBase; if (BIT_UP_SET(opcode)) @@ -210,19 +214,24 @@ default: nRc = 0; } - if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } unsigned int PerformSTF(const unsigned int opcode) { - unsigned int *pBase, *pAddress, *pFinal, nRc = 1; + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); SetRoundingMode(ROUND_TO_NEAREST); pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) pBase += 2; + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } pFinal = pBase; if (BIT_UP_SET(opcode)) @@ -240,15 +249,21 @@ default: nRc = 0; } - if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } unsigned int PerformLFM(const unsigned int opcode) { - unsigned int i, Fd, *pBase, *pAddress, *pFinal; + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); + pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) pBase += 2; + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } pFinal = pBase; if (BIT_UP_SET(opcode)) @@ -266,16 +281,21 @@ if (Fd == 8) Fd = 0; } - if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return 1; } unsigned int PerformSFM(const unsigned int opcode) { - unsigned int i, Fd, *pBase, *pAddress, *pFinal; + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) pBase += 2; + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } pFinal = pBase; if (BIT_UP_SET(opcode)) @@ -293,7 +313,7 @@ if (Fd == 8) Fd = 0; } - if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return 1; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11_cprt.c linux/arch/arm/nwfpe/fpa11_cprt.c --- v2.3.22/linux/arch/arm/nwfpe/fpa11_cprt.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/fpa11_cprt.c Wed Oct 20 16:29:08 1999 @@ -20,7 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" #include "milieu.h" #include "softfloat.h" #include "fpopcode.h" @@ -65,37 +64,10 @@ case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; -#if 0 - /* ?? Not at all sure about the mode checks here. Linux never - calls the emulator from a non-USR fault but we always run in SVC - mode. Is there even any point trying to emulate the way FPA11 - behaves in this respect? - - No - and I quote: 'The FPCR may only be present in some - implementations: it is there to control the hardware in an - implementation-specific manner, ... The user mode of the - ARM is not permitted to use this register, and the WFC and - RFC instructions will trap if tried from user mode.' - Therefore, we do not provide the RFC and WFC instructions. - (rmk, 3/05/1999) - */ - case WFC_CODE >> 20: - { - int mode = 0; - __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode)); - nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */ - if (nRc) writeFPCR(readRegister(getRd(opcode))); - } - break; - - case RFC_CODE >> 20: - { - int mode = 0; - __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode)); - nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */ - if (nRc) writeRegister(getRd(opcode),readFPCR()); break; - } - break; +#if 0 /* We currently have no use for the FPCR, so there's no point + in emulating it. */ + case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); + case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; #endif default: nRc = 0; @@ -114,24 +86,24 @@ { case ROUND_SINGLE: { - fpa11->fpreg[getFn(opcode)].fType = typeSingle; - fpa11->fpreg[getFn(opcode)].fValue.fSingle = + fpa11->fType[getFn(opcode)] = typeSingle; + fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(readRegister(getRd(opcode))); } break; case ROUND_DOUBLE: { - fpa11->fpreg[getFn(opcode)].fType = typeDouble; - fpa11->fpreg[getFn(opcode)].fValue.fDouble = + fpa11->fType[getFn(opcode)] = typeDouble; + fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode))); } break; case ROUND_EXTENDED: { - fpa11->fpreg[getFn(opcode)].fType = typeExtended; - fpa11->fpreg[getFn(opcode)].fValue.fExtended = + fpa11->fType[getFn(opcode)] = typeExtended; + fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode))); } break; @@ -149,26 +121,26 @@ SetRoundingMode(opcode); - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: { writeRegister(getRd(opcode), - float32_to_int32(fpa11->fpreg[Fn].fValue.fSingle)); + float32_to_int32(fpa11->fpreg[Fn].fSingle)); } break; case typeDouble: { writeRegister(getRd(opcode), - float64_to_int32(fpa11->fpreg[Fn].fValue.fDouble)); + float64_to_int32(fpa11->fpreg[Fn].fDouble)); } break; case typeExtended: { writeRegister(getRd(opcode), - floatx80_to_int32(fpa11->fpreg[Fn].fValue.fExtended)); + floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); } break; @@ -226,27 +198,27 @@ ?? Might be some mileage in avoiding this conversion if possible. Eg, if both operands are 32-bit, detect this and do a 32-bit comparison (cheaper than an 80-bit one). */ - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: //fp_printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fn].fValue.fSingle)) + if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) goto unordered; - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); break; case typeDouble: //fp_printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fn].fValue.fDouble)) + if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) goto unordered; - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); break; case typeExtended: //fp_printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fn].fValue.fExtended)) + if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) goto unordered; - rFn = fpa11->fpreg[Fn].fValue.fExtended; + rFn = fpa11->fpreg[Fn].fExtended; break; default: return 0; @@ -262,27 +234,27 @@ else { //fp_printk("Fm = r%d which contains a ",Fm); - switch (fpa11->fpreg[Fm].fType) + switch (fpa11->fType[Fm]) { case typeSingle: //fp_printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fm].fValue.fSingle)) + if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) goto unordered; - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle); + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); break; case typeDouble: //fp_printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fm].fValue.fDouble)) + if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) goto unordered; - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble); + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); break; case typeExtended: //fp_printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fm].fValue.fExtended)) + if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) goto unordered; - rFm = fpa11->fpreg[Fm].fValue.fExtended; + rFm = fpa11->fpreg[Fm].fExtended; break; default: return 0; @@ -303,6 +275,7 @@ the data sheet, observation of how the Acorn emulator actually behaves (and how programs expect it to) and guesswork. */ flags |= CC_OVERFLOW; + flags &= ~(CC_ZERO | CC_NEGATIVE); if (BIT_AC & readFPSR()) flags |= CC_CARRY; diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c --- v2.3.22/linux/arch/arm/nwfpe/fpmodule.c Fri Sep 10 23:57:27 1999 +++ linux/arch/arm/nwfpe/fpmodule.c Wed Oct 20 16:29:08 1999 @@ -1,3 +1,4 @@ + /* NetWinder Floating Point Emulator (c) Rebel.com, 1998-1999 @@ -20,30 +21,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" - -#ifdef MODULE #include #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif +#include /* XXX */ #include #include #include #include -#include #include -#include - -#include -#include -#include -#include -#include /* XXX */ #include "softfloat.h" @@ -62,7 +49,7 @@ int fp_printk(const char *,...); void fp_send_sig(unsigned long sig, PTASK p, int priv); #if LINUX_VERSION_CODE > 0x20115 -MODULE_AUTHOR("Scott Bambrough "); +MODULE_AUTHOR("Scott Bambrough "); MODULE_DESCRIPTION("NWFPE floating point emulator"); #endif @@ -73,57 +60,51 @@ #endif /* kernel function prototypes required */ -void C_SYMBOL_NAME(fp_setup)(void); +void fp_setup(void); /* external declarations for saved kernel symbols */ -extern unsigned int C_SYMBOL_NAME(kern_fp_enter); +extern void (*kern_fp_enter)(void); + +/* Original value of fp_enter from kernel before patched by fpe_init. */ +static void (*orig_fp_enter)(void); /* forward declarations */ extern void nwfpe_enter(void); -/* Original value of fp_enter from kernel before patched by fpe_init. */ -static unsigned int orig_fp_enter; - /* Address of user registers on the kernel stack. */ unsigned int *userRegisters; -void __init C_SYMBOL_NAME(fpe_version)(void) +void __init fpe_version(void) { static const char szTitle[] = "<4>NetWinder Floating Point Emulator "; - static const char szVersion[] = "V0.94.1 "; + static const char szVersion[] = "V0.95 "; static const char szCopyright[] = "(c) 1998-1999 Rebel.com\n"; - C_SYMBOL_NAME(fp_printk)(szTitle); - C_SYMBOL_NAME(fp_printk)(szVersion); - C_SYMBOL_NAME(fp_printk)(szCopyright); + fp_printk(szTitle); + fp_printk(szVersion); + fp_printk(szCopyright); } int __init fpe_init(void) { - /* Display title, version and copyright information. */ - C_SYMBOL_NAME(fpe_version)(); - - /* Save pointer to the old FP handler and then patch ourselves in */ - orig_fp_enter = C_SYMBOL_NAME(kern_fp_enter); - C_SYMBOL_NAME(kern_fp_enter) = (unsigned int)C_SYMBOL_NAME(nwfpe_enter); + if (sizeof(FPA11) > sizeof(union fp_state)) + printk(KERN_ERR "nwfpe: bad structure size\n"); + else { + /* Display title, version and copyright information. */ + fpe_version(); + + /* Save pointer to the old FP handler and then patch ourselves in */ + orig_fp_enter = kern_fp_enter; + kern_fp_enter = nwfpe_enter; + } return 0; } -#ifdef MODULE -int init_module(void) -{ - return(fpe_init()); -} - -void cleanup_module(void) +void __exit fpe_exit(void) { /* Restore the values we saved earlier. */ - C_SYMBOL_NAME(kern_fp_enter) = orig_fp_enter; + kern_fp_enter = orig_fp_enter; } -#endif - -#define _ARM_pc 60 -#define _ARM_cpsr 64 /* ScottB: November 4, 1998 @@ -135,7 +116,7 @@ [1/1/99: Not quite true any more unfortunately. There is Linux-specific code to access data in user space in some other source files at the -moment. --philb] +moment (grep for get_user / put_user calls). --philb] float_exception_flags is a global variable in SoftFloat. @@ -147,8 +128,9 @@ void float_raise(signed char flags) { -#if 0 - printk(KERN_DEBUG "NWFPE: exception %08x at %08x from %08x\n", flags, +#ifdef CONFIG_DEBUG_USER + printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", + current->comm, current->pid, flags, __builtin_return_address(0), userRegisters[15]); #endif @@ -156,7 +138,7 @@ if (readFPSR() & (flags << 16)) { /* raise exception */ - C_SYMBOL_NAME(fp_send_sig)(SIGFPE,C_SYMBOL_NAME(current),1); + fp_send_sig(SIGFPE, current, 1); } else { @@ -164,3 +146,6 @@ writeFPSR(flags); } } + +module_init(fpe_init); +module_exit(fpe_exit); diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpmodule.inl linux/arch/arm/nwfpe/fpmodule.inl --- v2.3.22/linux/arch/arm/nwfpe/fpmodule.inl Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/nwfpe/fpmodule.inl Wed Oct 20 16:29:08 1999 @@ -1,23 +1,23 @@ /* NetWinder Floating Point Emulator - (c) Corel Computer Corporation, 1998 + (c) Rebel.com, 1998-1999 - Direct questions, comments to Scott Bambrough + Direct questions, comments to Scott Bambrough - 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. - */ + 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. +*/ /* Address of user registers on the kernel stack. */ extern unsigned int *userRegisters; @@ -25,64 +25,60 @@ extern __inline__ unsigned int readRegister(const unsigned int nReg) { - /* Note: The CPU thinks it has dealt with the current instruction. As - a result the program counter has been advanced to the next - instruction, and points 4 bytes beyond the actual instruction - that caused the invalid instruction trap to occur. We adjust - for this in this routine. LDF/STF instructions with Rn = PC - depend on the PC being correct, as they use PC+8 in their - address calculations. */ - unsigned int val = userRegisters[nReg]; - - if (REG_PC == nReg) - val -= 4; - - return val; + /* Note: The CPU thinks it has dealt with the current instruction. As + a result the program counter has been advanced to the next + instruction, and points 4 bytes beyond the actual instruction + that caused the invalid instruction trap to occur. We adjust + for this in this routine. LDF/STF instructions with Rn = PC + depend on the PC being correct, as they use PC+8 in their + address calculations. */ + unsigned int val = userRegisters[nReg]; + if (REG_PC == nReg) val -= 4; + return val; } extern __inline__ void writeRegister(const unsigned int nReg, const unsigned int val) { - userRegisters[nReg] = val; + userRegisters[nReg] = val; } extern __inline__ unsigned int readCPSR(void) { - return (readRegister(REG_CPSR)); + return(readRegister(REG_CPSR)); } extern __inline__ void writeCPSR(const unsigned int val) { - writeRegister(REG_CPSR, val); + writeRegister(REG_CPSR,val); } extern __inline__ unsigned int readConditionCodes(void) { #ifdef __FPEM_TEST__ - return (0); + return(0); #else - return (readCPSR() & CC_MASK); + return(readCPSR() & CC_MASK); #endif } extern __inline__ void writeConditionCodes(const unsigned int val) { - unsigned int rval; - - /* - * Operate directly on userRegisters since - * the CPSR may be the PC register itself. - */ - rval = userRegisters[REG_CPSR] & ~CC_MASK; - userRegisters[REG_CPSR] = rval | (val & CC_MASK); + unsigned int rval; + /* + * Operate directly on userRegisters since + * the CPSR may be the PC register itself. + */ + rval = userRegisters[REG_CPSR] & ~CC_MASK; + userRegisters[REG_CPSR] = rval | (val & CC_MASK); } extern __inline__ unsigned int readMemoryInt(unsigned int *pMem) { - return *pMem; + return *pMem; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpopcode.c linux/arch/arm/nwfpe/fpopcode.c --- v2.3.22/linux/arch/arm/nwfpe/fpopcode.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/fpopcode.c Wed Oct 20 16:29:08 1999 @@ -19,7 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" #include "softfloat.h" #include "fpopcode.h" #include "fpsr.h" diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/single_cpdo.c linux/arch/arm/nwfpe/single_cpdo.c --- v2.3.22/linux/arch/arm/nwfpe/single_cpdo.c Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/single_cpdo.c Wed Oct 20 16:29:08 1999 @@ -19,8 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" -#include "milieu.h" #include "softfloat.h" #include "fpopcode.h" #include "fpa11.h" @@ -51,10 +49,10 @@ } else { - switch (fpa11->fpreg[Fm].fType) + switch (fpa11->fType[Fm]) { case typeSingle: - rFm = fpa11->fpreg[Fm].fValue.fSingle; + rFm = fpa11->fpreg[Fm].fSingle; break; default: return 0; @@ -64,10 +62,10 @@ if (!MONADIC_INSTRUCTION(opcode)) { Fn = getFn(opcode); - switch (fpa11->fpreg[Fn].fType) + switch (fpa11->fType[Fn]) { case typeSingle: - rFn = fpa11->fpreg[Fn].fValue.fSingle; + rFn = fpa11->fpreg[Fn].fSingle; break; default: return 0; @@ -79,112 +77,112 @@ { /* dyadic opcodes */ case ADF_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_add(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm); break; case MUF_CODE: case FML_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_mul(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm); break; case SUF_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm); break; case RSF_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFm,rFn); + fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn); break; case DVF_CODE: case FDV_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm); break; case RDF_CODE: case FRD_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFm,rFn); + fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn); break; #if 0 case POW_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); break; case RPW_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFm,rFn); + fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); break; #endif case RMF_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_rem(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm); break; #if 0 case POL_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_pol(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); break; #endif /* monadic opcodes */ case MVF_CODE: - fpa11->fpreg[Fd].fValue.fSingle = rFm; + fpa11->fpreg[Fd].fSingle = rFm; break; case MNF_CODE: rFm ^= 0x80000000; - fpa11->fpreg[Fd].fValue.fSingle = rFm; + fpa11->fpreg[Fd].fSingle = rFm; break; case ABS_CODE: rFm &= 0x7fffffff; - fpa11->fpreg[Fd].fValue.fSingle = rFm; + fpa11->fpreg[Fd].fSingle = rFm; break; case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fValue.fSingle = + fpa11->fpreg[Fd].fSingle = int32_to_float32(float32_to_int32(rFm)); break; case SQT_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_sqrt(rFm); + fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm); break; #if 0 case LOG_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_log(rFm); + fpa11->fpreg[Fd].fSingle = float32_log(rFm); break; case LGN_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_ln(rFm); + fpa11->fpreg[Fd].fSingle = float32_ln(rFm); break; case EXP_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_exp(rFm); + fpa11->fpreg[Fd].fSingle = float32_exp(rFm); break; case SIN_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_sin(rFm); + fpa11->fpreg[Fd].fSingle = float32_sin(rFm); break; case COS_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_cos(rFm); + fpa11->fpreg[Fd].fSingle = float32_cos(rFm); break; case TAN_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_tan(rFm); + fpa11->fpreg[Fd].fSingle = float32_tan(rFm); break; case ASN_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_arcsin(rFm); + fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); break; case ACS_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_arccos(rFm); + fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); break; case ATN_CODE: - fpa11->fpreg[Fd].fValue.fSingle = float32_arctan(rFm); + fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); break; #endif @@ -197,7 +195,7 @@ } } - if (0 != nRc) fpa11->fpreg[Fd].fType = typeSingle; + if (0 != nRc) fpa11->fType[Fd] = typeSingle; return nRc; } diff -u --recursive --new-file v2.3.22/linux/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in --- v2.3.22/linux/arch/arm/vmlinux-armo.lds.in Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/vmlinux-armo.lds.in Wed Oct 20 16:29:08 1999 @@ -3,16 +3,36 @@ * Written by Martin Mares */ OUTPUT_ARCH(arm) -ENTRY(_start) +ENTRY(stext) SECTIONS { . = TEXTADDR; + __init_begin = .; + .text.init : { *(.text.init) } + __proc_info_begin = .; + .proc.info : { *(.proc.info) } + __proc_info_end = .; + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(32768); + __init_end = .; + + .init.task : { + *(.init.task) + } + _text = .; /* Text and read-only data */ .text : { *(.text) *(.fixup) *(.gnu.warning) - } = 0x9090 + } .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } @@ -26,26 +46,16 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + .got : { *(.got) } /* Global offset table */ + _etext = .; /* End of text section */ - . = ALIGN(8192); .data : { /* Data */ - *(.init.task) *(.data) CONSTRUCTORS } _edata = .; /* End of data section */ - - . = ALIGN(32768); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - __proc_info_begin = .; - .proc.info : { *(.proc.info) } - __proc_info_end = .; - .data.init : { *(.data.init) } - . = ALIGN(32768); - __init_end = .; __bss_start = .; /* BSS */ .bss : { diff -u --recursive --new-file v2.3.22/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in --- v2.3.22/linux/arch/arm/vmlinux-armv.lds.in Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/vmlinux-armv.lds.in Wed Oct 20 16:29:08 1999 @@ -3,11 +3,10 @@ * Written by Martin Mares */ OUTPUT_ARCH(arm) -ENTRY(_start) +ENTRY(stext) SECTIONS { . = TEXTADDR; - _text = .; /* Text and read-only data */ .text : { } /* Set text start address */ __init_begin = .; /* Init code and data */ @@ -38,6 +37,7 @@ . = ALIGN(4096); __netwinder_end = .; + _text = .; /* Text and read-only data */ .text.real : { /* Real text segment */ *(.text) *(.fixup) @@ -56,6 +56,8 @@ __start___ksymtab = .; /* Kernel symbol table */ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + + .got : { *(.got) } /* Global offset table */ _etext = .; /* End of text section */ diff -u --recursive --new-file v2.3.22/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.3.22/linux/arch/i386/Makefile Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/Makefile Sat Oct 16 21:00:11 1999 @@ -84,9 +84,6 @@ vmlinux: arch/i386/vmlinux.lds -arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE - $(CPP) -C -P -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds - FORCE: ; .PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \ @@ -119,7 +116,6 @@ @$(MAKEBOOT) clean archmrproper: - rm -f arch/i386/vmlinux.lds archdep: @$(MAKEBOOT) dep diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v2.3.22/linux/arch/i386/boot/Makefile Mon Oct 11 15:38:14 1999 +++ linux/arch/i386/boot/Makefile Tue Oct 19 17:30:18 1999 @@ -51,11 +51,11 @@ bootsect.s: bootsect.S Makefile $(BOOT_INCL) $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ -bbootsect: bbootsect.o bsetup - $(LD) -Ttext 0x0 -s -oformat binary $< -R bsetup.o -o $@ +bbootsect: bbootsect.o + $(LD) -Ttext 0x0 -s -oformat binary $< -o $@ bbootsect.o: bbootsect.s - $(AS) -o $@ $< + $(AS) --defsym bootsect_kludge=0x220 -o $@ $< bbootsect.s: bootsect.S Makefile $(BOOT_INCL) $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S --- v2.3.22/linux/arch/i386/boot/bootsect.S Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/boot/bootsect.S Tue Oct 19 17:30:18 1999 @@ -64,12 +64,12 @@ movw %ax, %ds movw $INITSEG, %ax movw %ax, %es - movw $128, %cx + movw $256, %cx subw %si, %si subw %di, %di cld rep - movsl + movsw ljmp $INITSEG, $go # bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We @@ -105,11 +105,11 @@ movw $0x78, %bx # fs:bx is parameter table address pushw %ds ldsw %fs:(%bx), %si # ds:si is source - movb $3, %cl # copy 12 bytes + movb $6, %cl # copy 12 bytes cld pushw %di # di = 0x4000-12. rep - movsl + movsw popw %di popw %ds movb $36, 0x4(%di) # patch sector count @@ -118,7 +118,7 @@ # Load the setup-sectors directly after the bootblock. # Note that 'es' is already set up. -# Also, cx = 0 from rep movsl above. +# Also, cx = 0 from rep movsw above. load_setup: xorb %ah, %ah # reset FDC @@ -247,7 +247,7 @@ xorw %bx, %bx # bx is starting address within segment rp_read: #ifdef __BIG_KERNEL__ - .word 0x1eff, 0x0220 # lcall *bootsect_kludge in setup.S + lcall bootsect_kludge # in setup.S #else movw %es, %ax subw $SYSSEG, %ax diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.3.22/linux/arch/i386/boot/setup.S Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/boot/setup.S Tue Oct 19 17:30:18 1999 @@ -209,14 +209,14 @@ addw $SYSSEG, %bx movw %bx, %cs:start_sys_seg # Move rest of setup code/data to here - movw $2048, %di # four sectors loaded by LILO + movw $4096, %di # four sectors loaded by LILO subw %si, %si movw %cs, %ax # aka SETUPSEG movw %ax, %es movw $SYSSEG, %ax movw %ax, %ds rep - movsl + movsw movw %cs, %ax # aka SETUPSEG movw %ax, %ds cmpw $SIG1, setup_sig1 @@ -532,9 +532,9 @@ addw $0x100, %bx subw %di, %di subw %si, %si - movw $0x400, %cx + movw $0x800, %cx rep - movsl + movsw cmpw %bp, %bx # assume start_sys_seg > 0x200, # so we will perhaps read one # page more than needed, but diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S --- v2.3.22/linux/arch/i386/boot/video.S Mon Oct 11 15:38:14 1999 +++ linux/arch/i386/boot/video.S Tue Oct 19 17:30:18 1999 @@ -1152,7 +1152,7 @@ pushw %es movw $0xc000, %bx movw %bx, %es - call ax # Call test routine + call *%ax # Call test routine popw %es popw %di popw %si @@ -1741,7 +1741,7 @@ cmpb %bh, %al jne isnot - movb $VIDEO_FIRST_V7>>8, $svga_prefix # Use special mode switching + movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching ret video7_md: diff -u --recursive --new-file v2.3.22/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.22/linux/arch/i386/config.in Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/config.in Tue Oct 19 10:22:20 1999 @@ -42,9 +42,17 @@ define_bool CONFIG_X86_USE_3DNOW y fi -choice 'Maximum Physical Memory' \ - "1GB CONFIG_1GB \ - 2GB CONFIG_2GB" 1GB +choice 'High Memory Support' \ + "off CONFIG_NOHIGHMEM \ + 4GB CONFIG_HIGHMEM4G \ + 64GB CONFIG_HIGHMEM64G" off +if [ "$CONFIG_HIGHMEM4G" = "y" ]; then + define_bool CONFIG_HIGHMEM y +fi +if [ "$CONFIG_HIGHMEM64G" = "y" ]; then + define_bool CONFIG_HIGHMEM y + define_bool CONFIG_X86_PAE y +fi bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR @@ -63,7 +71,6 @@ mainmenu_option next_comment comment 'General setup' -bool 'BIGMEM support' CONFIG_BIGMEM bool 'Networking support' CONFIG_NET bool 'SGI Visual Workstation support' CONFIG_VISWS if [ "$CONFIG_VISWS" = "y" ]; then diff -u --recursive --new-file v2.3.22/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.22/linux/arch/i386/defconfig Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/defconfig Thu Oct 21 12:32:47 1999 @@ -24,8 +24,9 @@ CONFIG_X86_POPAD_OK=y CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y -CONFIG_1GB=y -# CONFIG_2GB is not set +CONFIG_NOHIGHMEM=y +# CONFIG_HIGHMEM4G is not set +# CONFIG_HIGHMEM64G is not set # CONFIG_MATH_EMULATION is not set # CONFIG_MTRR is not set CONFIG_SMP=y @@ -40,7 +41,6 @@ # # General setup # -# CONFIG_BIGMEM is not set CONFIG_NET=y # CONFIG_VISWS is not set CONFIG_X86_IO_APIC=y @@ -54,10 +54,12 @@ # CONFIG_MCA is not set # -# PCMCIA/Cardbus support +# PCMCIA/CardBus support # CONFIG_PCMCIA=y CONFIG_CARDBUS=y +CONFIG_I82365=y +# CONFIG_TCIC is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -111,7 +113,7 @@ # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set CONFIG_BLK_DEV_PIIX=y -# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_PIIX_TUNING is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set @@ -284,11 +286,19 @@ # CONFIG_WAN is not set # -# PCMCIA network devices +# PCMCIA network device support # -CONFIG_PCMCIA_PCNET=y +CONFIG_NET_PCMCIA=y # CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set CONFIG_PCMCIA_RAYCS=y +# CONFIG_PCMCIA_NETWAVE is not set +# CONFIG_PCMCIA_WAVELAN is not set CONFIG_PCMCIA_NETCARD=y # diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.3.22/linux/arch/i386/kernel/head.S Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/head.S Tue Oct 19 10:22:20 1999 @@ -367,11 +367,13 @@ .org 0x1000 ENTRY(swapper_pg_dir) .long 0x00102007 - .fill __USER_PGD_PTRS-1,4,0 - /* default: 767 entries */ + .long 0x00103007 + .fill BOOT_USER_PGD_PTRS-2,4,0 + /* default: 766 entries */ .long 0x00102007 - /* default: 255 entries */ - .fill __KERNEL_PGD_PTRS-1,4,0 + .long 0x00103007 + /* default: 254 entries */ + .fill BOOT_KERNEL_PGD_PTRS-2,4,0 /* * The page tables are initialized to only 4MB here - the final page @@ -509,16 +511,156 @@ .long 0x3f0007,0x3f1007,0x3f2007,0x3f3007,0x3f4007,0x3f5007,0x3f6007,0x3f7007 .long 0x3f8007,0x3f9007,0x3fa007,0x3fb007,0x3fc007,0x3fd007,0x3fe007,0x3ff007 -.org 0x3000 -ENTRY(empty_bad_page) - +ENTRY(pg1) + .long 0x400007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007 + .long 0x408007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007 + .long 0x410007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007 + .long 0x418007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007 + .long 0x420007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007 + .long 0x428007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007 + .long 0x430007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007 + .long 0x438007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007 + .long 0x440007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007 + .long 0x448007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007 + .long 0x450007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007 + .long 0x458007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007 + .long 0x460007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007 + .long 0x468007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007 + .long 0x470007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007 + .long 0x478007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007 + .long 0x480007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007 + .long 0x488007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007 + .long 0x490007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007 + .long 0x498007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007 + .long 0x4a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007 + .long 0x4a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007 + .long 0x4b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007 + .long 0x4b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007 + .long 0x4c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007 + .long 0x4c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007 + .long 0x4d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007 + .long 0x4d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007 + .long 0x4e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007 + .long 0x4e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007 + .long 0x4f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007 + .long 0x4f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007 + .long 0x500007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007 + .long 0x508007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007 + .long 0x510007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007 + .long 0x518007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007 + .long 0x520007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007 + .long 0x528007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007 + .long 0x530007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007 + .long 0x538007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007 + .long 0x540007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007 + .long 0x548007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007 + .long 0x550007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007 + .long 0x558007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007 + .long 0x560007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007 + .long 0x568007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007 + .long 0x570007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007 + .long 0x578007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007 + .long 0x580007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007 + .long 0x588007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007 + .long 0x590007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007 + .long 0x598007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007 + .long 0x5a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007 + .long 0x5a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007 + .long 0x5b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007 + .long 0x5b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007 + .long 0x5c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007 + .long 0x5c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007 + .long 0x5d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007 + .long 0x5d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007 + .long 0x5e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007 + .long 0x5e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007 + .long 0x5f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007 + .long 0x5f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007 + .long 0x600007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007 + .long 0x608007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007 + .long 0x610007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007 + .long 0x618007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007 + .long 0x620007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007 + .long 0x628007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007 + .long 0x630007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007 + .long 0x638007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007 + .long 0x640007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007 + .long 0x648007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007 + .long 0x650007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007 + .long 0x658007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007 + .long 0x660007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007 + .long 0x668007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007 + .long 0x670007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007 + .long 0x678007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007 + .long 0x680007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007 + .long 0x688007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007 + .long 0x690007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007 + .long 0x698007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007 + .long 0x6a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007 + .long 0x6a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007 + .long 0x6b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007 + .long 0x6b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007 + .long 0x6c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007 + .long 0x6c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007 + .long 0x6d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007 + .long 0x6d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007 + .long 0x6e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007 + .long 0x6e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007 + .long 0x6f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007 + .long 0x6f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007 + .long 0x700007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007 + .long 0x708007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007 + .long 0x710007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007 + .long 0x718007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007 + .long 0x720007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007 + .long 0x728007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007 + .long 0x730007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007 + .long 0x738007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007 + .long 0x740007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007 + .long 0x748007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007 + .long 0x750007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007 + .long 0x758007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007 + .long 0x760007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007 + .long 0x768007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007 + .long 0x770007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007 + .long 0x778007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007 + .long 0x780007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007 + .long 0x788007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007 + .long 0x790007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007 + .long 0x798007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007 + .long 0x7a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007 + .long 0x7a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007 + .long 0x7b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007 + .long 0x7b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007 + .long 0x7c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007 + .long 0x7c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007 + .long 0x7d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007 + .long 0x7d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007 + .long 0x7e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007 + .long 0x7e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007 + .long 0x7f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007 + .long 0x7f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007 .org 0x4000 -ENTRY(empty_bad_page_table) +ENTRY(empty_zero_page) .org 0x5000 -ENTRY(empty_zero_page) +ENTRY(empty_bad_page) .org 0x6000 +ENTRY(empty_bad_pte_table) + +#if CONFIG_X86_PAE + + .org 0x7000 + ENTRY(empty_bad_pmd_table) + + .org 0x8000 + +#else + + .org 0x7000 + +#endif /* * This starts the data section. Note that the above is all diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.22/linux/arch/i386/kernel/irq.c Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/irq.c Tue Oct 19 10:22:20 1999 @@ -20,6 +20,7 @@ * Naturally it's not a 1:1 relation, but there are similarities. */ +#include #include #include #include diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c --- v2.3.22/linux/arch/i386/kernel/pci-i386.c Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/pci-i386.c Fri Oct 15 18:55:26 1999 @@ -177,7 +177,7 @@ * (4) Assign new addresses to resources which were either * not configured at all or misconfigured. If explicitly * requested by the user, configure expansion ROM address - * as well. Finally enable the I/O and Memory bits. + * as well. */ static void __init pcibios_allocate_bus_resources(struct pci_bus *bus) @@ -252,21 +252,18 @@ static void __init pcibios_assign_resources(void) { struct pci_dev *dev; - u16 cmd, old_cmd; int idx; - int fault = 0; struct resource *r; for(dev=pci_devices; dev; dev=dev->next) { - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; for(idx=0; idx<6; idx++) { r = &dev->resource[idx]; if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || - ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) + ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)) || + !dev->class || (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) /* * Don't touch IDE controllers and I/O ports of video cards! - * Neither enable anything in their command registers. + * Also avoid classless devices and host bridges. */ continue; if (!r->start && r->end) { @@ -275,24 +272,9 @@ * the BIOS forgot to do so or because we have decided the old * address was unusable for some reason. */ - if (pcibios_assign_resource(dev, idx) < 0) - fault = 1; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - if (cmd != old_cmd) { - if (fault) - printk("PCI: Not enabling device %s because of resource collisions\n", dev->slot_name); - else { - printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); + pcibios_assign_resource(dev, idx); } } - if (pci_probe & PCI_ASSIGN_ROMS) { r = &dev->resource[PCI_ROM_RESOURCE]; r->end -= r->start; @@ -309,4 +291,30 @@ pcibios_allocate_resources(0); pcibios_allocate_resources(1); pcibios_assign_resources(); +} + +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; } diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-i386.h linux/arch/i386/kernel/pci-i386.h --- v2.3.22/linux/arch/i386/kernel/pci-i386.h Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/pci-i386.h Fri Oct 15 18:55:26 1999 @@ -18,12 +18,13 @@ #define PCI_NO_SORT 0x100 #define PCI_BIOS_SORT 0x200 #define PCI_NO_CHECKS 0x400 -#define PCI_NO_PEER_FIXUP 0x800 +#define PCI_PEER_FIXUP 0x800 #define PCI_ASSIGN_ROMS 0x1000 -#define PCI_NO_IRQ_SCAN 0x2000 +#define PCI_BIOS_IRQ_SCAN 0x2000 extern unsigned int pci_probe; /* pci-i386.c */ void pcibios_resource_survey(void); +int pcibios_enable_resources(struct pci_dev *); diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.3.22/linux/arch/i386/kernel/pci-pc.c Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/kernel/pci-pc.c Fri Oct 15 18:55:26 1999 @@ -688,7 +688,7 @@ struct irq_routing_table *rt; int ret, map; - if (pci_probe & PCI_NO_IRQ_SCAN) + if (!(pci_probe & PCI_BIOS_IRQ_SCAN)) return NULL; pcibios_irq_page = __get_free_page(GFP_KERNEL); if (!pcibios_irq_page) @@ -868,7 +868,30 @@ if (suba < subb) pci_scan_bus(suba+1, pci_root->ops, NULL); /* Bus B */ } - pci_probe |= PCI_NO_PEER_FIXUP; +} + +static void __init pci_fixup_rcc(struct pci_dev *d) +{ + /* + * RCC host bridges -- Find and scan all secondary buses. + * Register 0x44 contains first, 0x45 last bus number routed there. + */ + u8 busno; + pci_read_config_byte(d, 0x44, &busno); + printk("PCI: RCC host bridge: secondary bus %02x\n", busno); + pci_scan_bus(busno, pci_root->ops, NULL); +} + +static void __init pci_fixup_compaq(struct pci_dev *d) +{ + /* + * Compaq host bridges -- Find and scan all secondary buses. + * This time registers 0xc8 and 0xc9. + */ + u8 busno; + pci_read_config_byte(d, 0xc8, &busno); + printk("PCI: Compaq host bridge: secondary bus %02x\n", busno); + pci_scan_bus(busno, pci_root->ops, NULL); } static void __init pci_fixup_umc_ide(struct pci_dev *d) @@ -905,6 +928,9 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_HE, pci_fixup_rcc }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_LE, pci_fixup_rcc }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, { 0 } @@ -919,6 +945,8 @@ #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) #define PIRQ_VERSION 0x0100 +static struct irq_routing_table *pirq_table; + /* * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. */ @@ -974,7 +1002,6 @@ */ if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL)) printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); - pci_probe |= PCI_NO_PEER_FIXUP; } /* @@ -982,7 +1009,7 @@ * table, but unfortunately we have to know the interrupt router chip. */ -static char * __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin) +static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin, int assign) { struct irq_info *q; struct pci_dev *router; @@ -1012,9 +1039,9 @@ return NULL; } DBG(" -> PIRQ %02x, mask %04x", pirq, mask); - if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + if (!assign || (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) newirq = 0; - else for(newirq = 15; newirq && !(mask & (1 << newirq)); newirq--) + else for(newirq = 13; newirq && !(mask & (1 << newirq)); newirq--) ; if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) { DBG(" -> router not found\n"); @@ -1068,7 +1095,7 @@ struct pci_dev *dev; u8 pin; - rtable = pcibios_find_irq_routing_table(); + rtable = pirq_table = pcibios_find_irq_routing_table(); #ifdef CONFIG_PCI_BIOS if (!rtable && pci_bios_present) rtable = pcibios_get_irq_routing_table(); @@ -1106,7 +1133,7 @@ dev->irq = irq; } } - rtable = NULL; /* Avoid IRQ assignment below */ + pirq_table = NULL; /* Avoid automatic IRQ assignment */ } #endif /* @@ -1114,10 +1141,10 @@ */ if (dev->irq >= NR_IRQS) dev->irq = 0; - if (pin && !dev->irq && rtable && rtable->version) { - char *msg = pcibios_lookup_irq(dev, rtable, pin); + if (pin && !dev->irq && pirq_table) { + char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 0); if (msg) - printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg); + printk("PCI: Found IRQ %d for device %s [%s]\n", dev->irq, dev->slot_name, msg); } } @@ -1173,7 +1200,7 @@ pci_scan_bus(0, ops, NULL); pcibios_fixup_irqs(); - if (!(pci_probe & PCI_NO_PEER_FIXUP)) + if (pci_probe & PCI_PEER_FIXUP) pcibios_fixup_peer_bridges(); pcibios_resource_survey(); @@ -1199,8 +1226,8 @@ } else if (!strcmp(str, "nosort")) { pci_probe |= PCI_NO_SORT; return NULL; - } else if (!strcmp(str, "noirq")) { - pci_probe |= PCI_NO_IRQ_SCAN; + } else if (!strcmp(str, "biosirq")) { + pci_probe |= PCI_BIOS_IRQ_SCAN; return NULL; } #endif @@ -1214,12 +1241,30 @@ return NULL; } #endif - else if (!strcmp(str, "nopeer")) { - pci_probe |= PCI_NO_PEER_FIXUP; + else if (!strcmp(str, "peer")) { + pci_probe |= PCI_PEER_FIXUP; return NULL; } else if (!strcmp(str, "rom")) { pci_probe |= PCI_ASSIGN_ROMS; return NULL; } return str; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + int err; + + if ((err = pcibios_enable_resources(dev)) < 0) + return err; + if (!dev->irq && pirq_table) { + u8 pin; + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 1); + if (msg) + printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg); + } + } + return 0; } diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-visws.c linux/arch/i386/kernel/pci-visws.c --- v2.3.22/linux/arch/i386/kernel/pci-visws.c Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/pci-visws.c Mon Oct 18 11:26:31 1999 @@ -14,6 +14,7 @@ #include #include +#include #include "pci-i386.h" @@ -128,4 +129,9 @@ char * __init pcibios_setup(char *str) { return str; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + return pcibios_enable_resources(dev); } diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.22/linux/arch/i386/kernel/setup.c Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/kernel/setup.c Fri Oct 22 10:30:27 1999 @@ -54,7 +54,8 @@ #ifdef CONFIG_BLK_DEV_RAM #include #endif -#include +#include +#include #include #include #include @@ -401,12 +402,15 @@ } /* add_memory_region */ -#define LOWMEMSIZE() ((*(unsigned short *)__va(0x413)) * 1024) - +/* + * Do NOT EVER look at the BIOS memory size location. + * It does not work on many machines. + */ +#define LOWMEMSIZE() (0x9f000) void __init setup_memory_region(void) { -#define E820_DEBUG 0 +#define E820_DEBUG 1 #ifdef E820_DEBUG int i; #endif @@ -432,9 +436,8 @@ memcpy(e820.map, E820_MAP, e820.nr_map * sizeof e820.map[0]); #ifdef E820_DEBUG for (i=0; i < e820.nr_map; i++) { - printk("e820: %ld @ %08lx ", - (unsigned long)(e820.map[i].size), - (unsigned long)(e820.map[i].addr)); + printk("e820: %08x @ %08x ", (int)e820.map[i].size, + (int)e820.map[i].addr); switch (e820.map[i].type) { case E820_RAM: printk("(usable)\n"); break; @@ -464,48 +467,11 @@ } /* setup_memory_region */ -void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) +static inline void parse_mem_cmdline (char ** cmdline_p) { - unsigned long high_pfn, max_pfn; char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; - int i; - int usermem=0; - -#ifdef CONFIG_VISWS - visws_get_board_type_and_rev(); -#endif - - ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); - drive_info = DRIVE_INFO; - screen_info = SCREEN_INFO; - apm_bios_info = APM_BIOS_INFO; - if( SYS_DESC_TABLE.length != 0 ) { - MCA_bus = SYS_DESC_TABLE.table[3] &0x2; - machine_id = SYS_DESC_TABLE.table[0]; - machine_submodel_id = SYS_DESC_TABLE.table[1]; - BIOS_revision = SYS_DESC_TABLE.table[2]; - } - aux_device_present = AUX_DEVICE_INFO; - -#ifdef CONFIG_BLK_DEV_RAM - rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; - rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); - rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); -#endif - setup_memory_region(); - - if (!MOUNT_ROOT_RDONLY) - root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) &_text; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) &_end; - - code_resource.start = virt_to_bus(&_text); - code_resource.end = virt_to_bus(&_etext)-1; - data_resource.start = virt_to_bus(&_etext); - data_resource.end = virt_to_bus(&_edata)-1; + int usermem = 0; /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); @@ -519,8 +485,9 @@ * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from * to +, overriding the bios size. */ - if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") { - if (to != command_line) to--; + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; if (!memcmp(from+4, "nopentium", 9)) { from += 9+4; boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE; @@ -542,7 +509,7 @@ } mem_size = memparse(from+4, &from); if (*from == '@') - start_at = memparse(from+1,&from); + start_at = memparse(from+1, &from); else { start_at = HIGH_MEMORY; mem_size -= HIGH_MEMORY; @@ -559,54 +526,166 @@ } *to = '\0'; *cmdline_p = command_line; +} - /* Find the highest page frame number we have available */ - max_pfn = 0; - for (i=0; i < e820.nr_map; i++) { - /* RAM? */ - if (e820.map[i].type == E820_RAM) { - unsigned long end_pfn = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT; +void __init setup_arch(char **cmdline_p) +{ + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn, max_low_pfn; + int i; - if (end_pfn > max_pfn) - max_pfn = end_pfn; - } +#ifdef CONFIG_VISWS + visws_get_board_type_and_rev(); +#endif + + ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); + drive_info = DRIVE_INFO; + screen_info = SCREEN_INFO; + apm_bios_info = APM_BIOS_INFO; + if( SYS_DESC_TABLE.length != 0 ) { + MCA_bus = SYS_DESC_TABLE.table[3] &0x2; + machine_id = SYS_DESC_TABLE.table[0]; + machine_submodel_id = SYS_DESC_TABLE.table[1]; + BIOS_revision = SYS_DESC_TABLE.table[2]; } + aux_device_present = AUX_DEVICE_INFO; -/* - * We can only allocate a limited amount of direct-mapped memory - */ -#define VMALLOC_RESERVE (128 << 20) /* 128MB for vmalloc and initrd */ -#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) -#define MAXMEM_PFN (MAXMEM >> PAGE_SHIFT) - - high_pfn = MAXMEM_PFN; - if (max_pfn < high_pfn) - high_pfn = max_pfn; +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); +#endif + setup_memory_region(); + + if (!MOUNT_ROOT_RDONLY) + root_mountflags &= ~MS_RDONLY; + init_mm.start_code = (unsigned long) &_text; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + code_resource.start = virt_to_bus(&_text); + code_resource.end = virt_to_bus(&_etext)-1; + data_resource.start = virt_to_bus(&_etext); + data_resource.end = virt_to_bus(&_edata)-1; + + parse_mem_cmdline(cmdline_p); + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) /* - * But the bigmem stuff may be able to use more of it - * (but currently only up to about 4GB) + * 128MB for vmalloc and initrd */ -#ifdef CONFIG_BIGMEM - #define MAXBIGMEM ((unsigned long)(~(VMALLOC_RESERVE-1))) - #define MAXBIGMEM_PFN (MAXBIGMEM >> PAGE_SHIFT) - if (max_pfn > MAX_PFN) - max_pfn = MAX_PFN; - -/* When debugging, make half of "normal" memory be BIGMEM memory instead */ -#ifdef BIGMEM_DEBUG - high_pfn >>= 1; -#endif +#define VMALLOC_RESERVE (unsigned long)(128 << 20) +#define MAXMEM (unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE) +#define MAXMEM_PFN PFN_DOWN(MAXMEM) + + /* + * partially used pages are not usable - thus + * we are rounding upwards: + */ + start_pfn = PFN_UP(__pa(&_end)); - bigmem_start = high_pfn << PAGE_SHIFT; - bigmem_end = max_pfn << PAGE_SHIFT; - printk(KERN_NOTICE "%ldMB BIGMEM available.\n", (bigmem_end-bigmem_start) >> 20); + /* + * Find the highest page frame number we have available + */ + max_pfn = 0; + for (i = 0; i < e820.nr_map; i++) { + unsigned long curr_pfn; + /* RAM? */ + if (e820.map[i].type != E820_RAM) + continue; + curr_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); + if (curr_pfn > max_pfn) + max_pfn = curr_pfn; + } + + /* + * Determine low and high memory ranges: + */ + max_low_pfn = max_pfn; + if (max_low_pfn > MAXMEM_PFN) + max_low_pfn = MAXMEM_PFN; + +#ifdef CONFIG_HIGHMEM + highstart_pfn = highend_pfn = max_pfn; + if (max_pfn > MAXMEM_PFN) { + highstart_pfn = MAXMEM_PFN; + highend_pfn = max_pfn; + printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", + pages_to_mb(highend_pfn - highstart_pfn)); + } #endif + /* + * Initialize the boot-time allocator (with low memory only): + */ + bootmap_size = init_bootmem(start_pfn, max_low_pfn); + + /* + * FIXME: what about high memory? + */ + ram_resources[1].end = PFN_PHYS(max_low_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + for (i = 0; i < e820.nr_map; i++) { + unsigned long curr_pfn, last_pfn, size; + /* + * Reserve usable low memory + */ + if (e820.map[i].type != E820_RAM) + continue; + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(e820.map[i].addr); + if (curr_pfn >= max_low_pfn) + continue; + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); - ram_resources[1].end = (high_pfn << PAGE_SHIFT)-1; + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; - *memory_start_p = (unsigned long) &_end; - *memory_end_p = PAGE_OFFSET + (high_pfn << PAGE_SHIFT); + /* + * .. finally, did all the rounding and playing + * around just make the area go away? + */ + if (last_pfn <= curr_pfn) + continue; + + size = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + } + /* + * Reserve the bootmem bitmap itself as well. We do this in two + * steps (first step was init_bootmem()) because this catches + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + */ + reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) + + bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY)); + + /* + * reserve physical page 0 - it's a special BIOS page on many boxes, + * enabling clean reboots, SMP operation, laptop functions. + */ + reserve_bootmem(0, PAGE_SIZE); + +#ifdef __SMP__ + /* + * But first pinch a few for the stack/trampoline stuff + * FIXME: Don't need the extra page at 4K, but need to fix + * trampoline before removing it. (see the GDT stuff) + */ + reserve_bootmem(PAGE_SIZE, PAGE_SIZE); + smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ +#endif #ifdef __SMP__ /* @@ -616,10 +695,11 @@ #endif #ifdef CONFIG_BLK_DEV_INITRD +// FIXME needs to do the new bootmem alloc stuff if (LOADER_TYPE) { initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0; initrd_end = initrd_start+INITRD_SIZE; - if (initrd_end > memory_end) { + if (initrd_end > (max_low_pfn << PAGE_SHIFT)) { printk("initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", initrd_end,memory_end); diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.3.22/linux/arch/i386/kernel/smpboot.c Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/smpboot.c Wed Oct 20 11:32:17 1999 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -630,12 +631,15 @@ * We are called very early to get the low memory for the * SMP bootup trampoline page. */ -unsigned long __init smp_alloc_memory(unsigned long mem_base) +void __init smp_alloc_memory(void) { - if (virt_to_phys((void *)mem_base) >= 0x9F000) + trampoline_base = (void *) alloc_bootmem_low_pages(PAGE_SIZE); + /* + * Has to be in very low memory so we can execute + * real-mode AP code. + */ + if (__pa(trampoline_base) >= 0x9F000) BUG(); - trampoline_base = (void *)mem_base; - return mem_base + PAGE_SIZE; } /* @@ -804,11 +808,10 @@ apic_write(APIC_DFR, value); } -unsigned long __init init_smp_mappings(unsigned long memory_start) +void __init init_smp_mappings(void) { unsigned long apic_phys; - memory_start = PAGE_ALIGN(memory_start); if (smp_found_config) { apic_phys = mp_lapic_addr; } else { @@ -818,11 +821,10 @@ * could use the real zero-page, but it's safer * this way if some buggy code writes to this page ... */ - apic_phys = __pa(memory_start); - memset((void *)memory_start, 0, PAGE_SIZE); - memory_start += PAGE_SIZE; + apic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE)); + memset((void *)apic_phys, 0, PAGE_SIZE); } - set_fixmap(FIX_APIC_BASE,apic_phys); + set_fixmap(FIX_APIC_BASE, apic_phys); dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); #ifdef CONFIG_X86_IO_APIC @@ -834,9 +836,8 @@ if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; } else { - ioapic_phys = __pa(memory_start); - memset((void *)memory_start, 0, PAGE_SIZE); - memory_start += PAGE_SIZE; + ioapic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE)); + memset((void *)ioapic_phys, 0, PAGE_SIZE); } set_fixmap(idx,ioapic_phys); dprintk("mapped IOAPIC to %08lx (%08lx)\n", @@ -845,8 +846,6 @@ } } #endif - - return memory_start; } /* @@ -1112,6 +1111,12 @@ smp_callin(); while (!atomic_read(&smp_commenced)) /* nothing */ ; + /* + * low-memory mappings have been cleared, flush them from + * the local TLBs too. + */ + local_flush_tlb(); + return cpu_idle(); } @@ -1153,7 +1158,6 @@ static void __init do_boot_cpu(int i) { unsigned long cfg; - pgd_t maincfg; struct task_struct *idle; unsigned long send_status, accept_status; int timeout, num_starts, j; @@ -1207,9 +1211,6 @@ *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; dprintk("3.\n"); - maincfg=swapper_pg_dir[0]; - ((unsigned long *)swapper_pg_dir)[0]=0x102007; - /* * Be paranoid about clearing APIC errors. */ @@ -1367,9 +1368,6 @@ cpucount--; } - swapper_pg_dir[0]=maincfg; - local_flush_tlb(); - /* mark "stuck" area as not stuck */ *((volatile unsigned long *)phys_to_virt(8192)) = 0; } @@ -1567,14 +1565,9 @@ #ifndef CONFIG_VISWS { - unsigned long cfg; - /* * Install writable page 0 entry to set BIOS data area. */ - cfg = pg0[0]; - /* writeable, present, addr 0 */ - pg0[0] = _PAGE_RW | _PAGE_PRESENT | 0; local_flush_tlb(); /* @@ -1584,12 +1577,6 @@ CMOS_WRITE(0, 0xf); *((volatile long *) phys_to_virt(0x467)) = 0; - - /* - * Restore old page 0 entry. - */ - pg0[0] = cfg; - local_flush_tlb(); } #endif @@ -1646,5 +1633,7 @@ */ if (cpu_has_tsc && cpucount) synchronize_tsc_bp(); + + zap_low_mappings(); } diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.3.22/linux/arch/i386/kernel/traps.c Sat Oct 9 11:47:50 1999 +++ linux/arch/i386/kernel/traps.c Fri Oct 22 11:35:01 1999 @@ -581,6 +581,7 @@ #endif /* CONFIG_MATH_EMULATION */ +#ifndef CONFIG_M686 void __init trap_init_f00f_bug(void) { unsigned long page; @@ -596,8 +597,8 @@ pgd = pgd_offset(&init_mm, page); pmd = pmd_offset(pgd, page); pte = pte_offset(pmd, page); - free_page(pte_page(*pte)); - *pte = mk_pte(&idt_table, PAGE_KERNEL_RO); + __free_page(pte_page(*pte)); + *pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO); local_flush_tlb(); /* @@ -608,6 +609,7 @@ idt = (struct desc_struct *)page; __asm__ __volatile__("lidt %0": "=m" (idt_descr)); } +#endif #define _set_gate(gate_addr,type,dpl,addr) \ do { \ @@ -772,7 +774,7 @@ #endif void __init trap_init(void) { - if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) + if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) EISA_bus = 1; set_trap_gate(0,÷_error); diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c --- v2.3.22/linux/arch/i386/kernel/visws_apic.c Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/kernel/visws_apic.c Mon Oct 18 11:26:31 1999 @@ -37,7 +37,7 @@ #include -#include "irq.h" +#include /* * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.3.22/linux/arch/i386/kernel/vm86.c Mon Jul 19 15:23:49 1999 +++ linux/arch/i386/kernel/vm86.c Tue Oct 19 10:22:20 1999 @@ -102,7 +102,7 @@ if (pgd_none(*pgd)) return; if (pgd_bad(*pgd)) { - printk("vm86: bad pgd entry [%p]:%08lx\n", pgd, pgd_val(*pgd)); + pgd_ERROR(*pgd); pgd_clear(pgd); return; } @@ -110,7 +110,7 @@ if (pmd_none(*pmd)) return; if (pmd_bad(*pmd)) { - printk("vm86: bad pmd entry [%p]:%08lx\n", pmd, pmd_val(*pmd)); + pmd_ERROR(*pmd); pmd_clear(pmd); return; } diff -u --recursive --new-file v2.3.22/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.3.22/linux/arch/i386/lib/Makefile Mon Oct 11 15:38:14 1999 +++ linux/arch/i386/lib/Makefile Tue Oct 19 12:36:05 1999 @@ -7,7 +7,7 @@ L_TARGET = lib.a L_OBJS = checksum.o old-checksum.o delay.o \ - usercopy.o getuser.o putuser.o + usercopy.o getuser.o putuser.o iodebug.o ifdef CONFIG_X86_USE_3DNOW L_OBJS += mmx.o diff -u --recursive --new-file v2.3.22/linux/arch/i386/lib/iodebug.c linux/arch/i386/lib/iodebug.c --- v2.3.22/linux/arch/i386/lib/iodebug.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/iodebug.c Tue Oct 19 12:26:53 1999 @@ -0,0 +1,19 @@ +#include + +void * __io_virt_debug(unsigned long x, const char *file, int line) +{ + if (x < PAGE_OFFSET) { + printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line); + return __va(x); + } + return (void *)x; +} + +unsigned long __io_phys_debug(unsigned long x, const char *file, int line) +{ + if (x < PAGE_OFFSET) { + printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line); + return x; + } + return __pa(x); +} diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile --- v2.3.22/linux/arch/i386/mm/Makefile Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/mm/Makefile Tue Oct 19 10:22:20 1999 @@ -10,8 +10,4 @@ O_TARGET := mm.o O_OBJS := init.o fault.o ioremap.o extable.o -ifeq ($(CONFIG_BIGMEM),y) -O_OBJS += bigmem.o -endif - include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/bigmem.c linux/arch/i386/mm/bigmem.c --- v2.3.22/linux/arch/i386/mm/bigmem.c Tue Aug 31 17:29:12 1999 +++ linux/arch/i386/mm/bigmem.c Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -/* - * BIGMEM IA32 code and variables. - * - * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de - * Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de - */ - -#include -#include - -unsigned long bigmem_start, bigmem_end; - -/* NOTE: fixmap_init alloc all the fixmap pagetables contigous on the - physical space so we can cache the place of the first one and move - around without checking the pgd every time. */ -pte_t *kmap_pte; -pgprot_t kmap_prot; - -#define kmap_get_fixmap_pte(vaddr) \ - pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) - -void __init kmap_init(void) -{ - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; - if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) - pgprot_val(kmap_prot) |= _PAGE_GLOBAL; -} diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.3.22/linux/arch/i386/mm/fault.c Mon Aug 2 15:56:47 1999 +++ linux/arch/i386/mm/fault.c Tue Oct 19 10:22:20 1999 @@ -76,6 +76,31 @@ return 0; } +static inline void handle_wp_test (void) +{ + const unsigned long vaddr = PAGE_OFFSET; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + /* + * make it read/writable temporarily, so that the fault + * can be handled. + */ + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + *pte = mk_pte_phys(0, PAGE_KERNEL); + local_flush_tlb(); + + boot_cpu_data.wp_works_ok = 1; + /* + * Beware: Black magic here. The printk is needed here to flush + * CPU state on certain buggy processors. + */ + printk("Ok"); +} + asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); extern unsigned long idt; @@ -226,15 +251,8 @@ * First we check if it was the bootup rw-test, though.. */ if (boot_cpu_data.wp_works_ok < 0 && - address == PAGE_OFFSET && (error_code & 1)) { - boot_cpu_data.wp_works_ok = 1; - pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_KERNEL)); - local_flush_tlb(); - /* - * Beware: Black magic here. The printk is needed here to flush - * CPU state on certain buggy processors. - */ - printk("Ok"); + address == PAGE_OFFSET && (error_code & 1)) { + handle_wp_test(); return; } diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.3.22/linux/arch/i386/mm/init.c Fri Oct 15 15:25:13 1999 +++ linux/arch/i386/mm/init.c Wed Oct 20 11:32:17 1999 @@ -22,7 +22,9 @@ #ifdef CONFIG_BLK_DEV_INITRD #include #endif -#include +#include +#include +#include #include #include @@ -32,22 +34,81 @@ #include #include -static unsigned long totalram = 0; -static unsigned long totalbig = 0; +unsigned long highstart_pfn, highend_pfn; +static unsigned long totalram_pages = 0; +static unsigned long totalhigh_pages = 0; extern void show_net_buffers(void); -extern unsigned long init_smp_mappings(unsigned long); -void __bad_pte_kernel(pmd_t *pmd) +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving an inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ + +/* + * These are allocated in head.S so that we get proper page alignment. + * If you change the size of these then change head.S as well. + */ +extern char empty_bad_page[PAGE_SIZE]; +#if CONFIG_X86_PAE +extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; +#endif +extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; + +/* + * We init them before every return and make them writable-shared. + * This guarantees we get out of the kernel in some more or less sane + * way. + */ +#if CONFIG_X86_PAE +static pmd_t * get_bad_pmd_table(void) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); + pmd_t v; + int i; + + pmd_val(v) = _PAGE_TABLE + __pa(empty_bad_pte_table); + + for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++) + empty_bad_pmd_table[i] = v; + + return empty_bad_pmd_table; } +#endif -void __bad_pte(pmd_t *pmd) +static pte_t * get_bad_pte_table(void) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); + pte_t v; + int i; + + v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); + + for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) + empty_bad_pte_table[i] = v; + + return empty_bad_pte_table; +} + + + +void __handle_bad_pmd(pmd_t *pmd) +{ + pmd_ERROR(*pmd); + pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); +} + +void __handle_bad_pmd_kernel(pmd_t *pmd) +{ + pmd_ERROR(*pmd); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); } pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) @@ -57,16 +118,16 @@ pte = (pte_t *) __get_free_page(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - clear_page((unsigned long)pte); + clear_page(pte); pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); return pte + offset; } - pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); return NULL; } free_page((unsigned long)pte); if (pmd_bad(*pmd)) { - __bad_pte_kernel(pmd); + __handle_bad_pmd_kernel(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + offset; @@ -79,19 +140,19 @@ pte = (unsigned long) __get_free_page(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - clear_page(pte); + clear_page((void *)pte); pmd_val(*pmd) = _PAGE_TABLE + __pa(pte); - return (pte_t *)(pte + offset); + return (pte_t *)pte + offset; } - pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); + pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); return NULL; } free_page(pte); if (pmd_bad(*pmd)) { - __bad_pte(pmd); + __handle_bad_pmd(pmd); return NULL; } - return (pte_t *) (pmd_page(*pmd) + offset); + return (pte_t *) pmd_page(*pmd) + offset; } int do_check_pgt_cache(int low, int high) @@ -110,52 +171,36 @@ return freed; } -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving an inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ -pte_t * __bad_pagetable(void) +/* NOTE: fixmap_init alloc all the fixmap pagetables contigous on the + physical space so we can cache the place of the first one and move + around without checking the pgd every time. */ + +#if CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; + +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + +void __init kmap_init(void) { - extern char empty_bad_page_table[PAGE_SIZE]; - int d0, d1; + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - __asm__ __volatile__("cld ; rep ; stosl" - : "=&D" (d0), "=&c" (d1) - : "a" (pte_val(BAD_PAGE)), - "0" ((long) empty_bad_page_table), - "1" (PAGE_SIZE/4) - : "memory"); - return (pte_t *) empty_bad_page_table; -} - -pte_t __bad_page(void) -{ - extern char empty_bad_page[PAGE_SIZE]; - int d0, d1; - - __asm__ __volatile__("cld ; rep ; stosl" - : "=&D" (d0), "=&c" (d1) - : "a" (0), - "0" ((long) empty_bad_page), - "1" (PAGE_SIZE/4) - : "memory"); - return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED)); + kmap_prot = PAGE_KERNEL; + if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) + pgprot_val(kmap_prot) |= _PAGE_GLOBAL; } +#endif void show_mem(void) { - int i,free = 0,total = 0,reserved = 0; + int i,free = 0, total = 0, reserved = 0; int shared = 0, cached = 0; - int bigmem = 0; + int highmem = 0; printk("Mem-info:\n"); show_free_areas(); @@ -163,8 +208,8 @@ i = max_mapnr; while (i-- > 0) { total++; - if (PageBIGMEM(mem_map+i)) - bigmem++; + if (PageHighMem(mem_map+i)) + highmem++; if (PageReserved(mem_map+i)) reserved++; else if (PageSwapCache(mem_map+i)) @@ -174,59 +219,42 @@ else shared += page_count(mem_map+i) - 1; } - printk("%d pages of RAM\n",total); - printk("%d pages of BIGMEM\n",bigmem); + printk("%d pages of RAM\n", total); + printk("%d pages of HIGHMEM\n",highmem); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif } -extern unsigned long free_area_init(unsigned long, unsigned long); - /* References to section boundaries */ extern char _text, _etext, _edata, __bss_start, _end; extern char __init_begin, __init_end; -/* - * allocate page table(s) for compile-time fixed mappings - */ -static unsigned long __init fixmap_init(unsigned long start_mem) -{ - pgd_t * pg_dir; - unsigned int idx; - unsigned long address; - - start_mem = PAGE_ALIGN(start_mem); - - for (idx=1; idx <= __end_of_fixed_addresses; idx += PTRS_PER_PTE) - { - address = __fix_to_virt(__end_of_fixed_addresses-idx); - pg_dir = swapper_pg_dir + (address >> PGDIR_SHIFT); - memset((void *)start_mem, 0, PAGE_SIZE); - pgd_val(*pg_dir) = _PAGE_TABLE | __pa(start_mem); - start_mem += PAGE_SIZE; - } - - return start_mem; -} - static void set_pte_phys (unsigned long vaddr, unsigned long phys) { pgprot_t prot; - pte_t * pte; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; - pte = pte_offset(pmd_offset(pgd_offset_k(vaddr), vaddr), vaddr); + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); prot = PAGE_KERNEL; if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) pgprot_val(prot) |= _PAGE_GLOBAL; set_pte(pte, mk_pte_phys(phys, prot)); - local_flush_tlb(); + /* + * It's enough to flush this one mapping. + */ + __flush_tlb_one(vaddr); } void set_fixmap (enum fixed_addresses idx, unsigned long phys) @@ -240,6 +268,123 @@ set_pte_phys (address,phys); } +static void __init pagetable_init(void) +{ + pgd_t *pgd, *pgd_base; + pmd_t *pmd; + pte_t *pte; + int i, j, k; + unsigned long vaddr; + unsigned long end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); + + pgd_base = swapper_pg_dir; + + vaddr = PAGE_OFFSET; + i = __pgd_offset(vaddr); + pgd = pgd_base + i; + + for (; (i < PTRS_PER_PGD) && (vaddr <= end); pgd++, i++) { + vaddr = i*PGDIR_SIZE; +#if CONFIG_X86_PAE + pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pmd, 0, PAGE_SIZE); + pgd_val(*pgd) = __pa(pmd) + 0x1; +#else + pmd = (pmd_t *)pgd; +#endif + if (pmd != pmd_offset(pgd, 0)) + BUG(); + for (j = 0; (j < PTRS_PER_PMD) && (vaddr <= end); pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (cpu_has_pse) { + unsigned long __pe; + + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + __pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr); + /* Make it "global" too if supported */ + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); + __pe += _PAGE_GLOBAL; + } + pmd_val(*pmd) = __pe; + continue; + } + + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pte, 0, PAGE_SIZE); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + + if (pte != pte_offset(pmd, 0)) + BUG(); + + for (k = 0; + (k < PTRS_PER_PTE) && (vaddr <= end); + pte++, k++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + *pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL); + } + } + } + + /* + * Fixed mappings, only the page table structure has to be + * created - mappings will be set by set_fixmap(): + */ + + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; + i = __pgd_offset(vaddr); + j = __pmd_offset(vaddr); + pgd = pgd_base + i; + + for ( ; (i < PTRS_PER_PGD) && vaddr; pgd++, i++) { +#if CONFIG_X86_PAE + if (pgd_none(*pgd)) { + pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pmd, 0, PAGE_SIZE); + pgd_val(*pgd) = __pa(pmd) + 0x1; + if (pmd != pmd_offset(pgd, vaddr)) + BUG(); + } + pmd = pmd_offset(pgd, vaddr); +#else + pmd = (pmd_t *)pgd; +#endif + for (; (j < PTRS_PER_PMD) && vaddr; pmd++, j++) { + if (pmd_none(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pte, 0, PAGE_SIZE); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + if (pte != pte_offset(pmd, 0)) + BUG(); + } + vaddr += PMD_SIZE; + } + j = 0; + } + +#if CONFIG_X86_PAE + /* + * Add low memory identity-mappings - SMP needs it when + * starting up on an AP from real-mode. In the non-PAE + * case we already have these mappings through head.S. + * All user-space mappings are explicitly cleared after + * SMP startup. + */ + pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; +#endif +} + +void __init zap_low_mappings (void) +{ + int i; + /* + * Zap initial low-memory mappings: + */ + for (i = 0; i < USER_PTRS_PER_PGD; i++) + pgd_clear(swapper_pg_dir + i); +} + /* * paging_init() sets up the page tables - note that the first 4MB are * already mapped by head.S. @@ -247,89 +392,36 @@ * This routines also unmaps the page at virtual kernel address 0, so * that we can trap those pesky NULL-reference errors in the kernel. */ -unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) +void __init paging_init(void) { - pgd_t * pg_dir; - pte_t * pg_table; - unsigned long tmp; - unsigned long address; + pagetable_init(); -/* - * Physical page 0 is special; it's not touched by Linux since BIOS - * and SMM (for laptops with [34]86/SL chips) may need it. It is read - * and write protected to detect null pointer references in the - * kernel. - * It may also hold the MP configuration table when we are booting SMP. - */ - start_mem = PAGE_ALIGN(start_mem); - address = PAGE_OFFSET; - pg_dir = swapper_pg_dir; - /* unmap the original low memory mappings */ - pgd_val(pg_dir[0]) = 0; - - /* Map whole memory from PAGE_OFFSET */ - pg_dir += USER_PGD_PTRS; - while (address < end_mem) { - /* - * If we're running on a Pentium CPU, we can use the 4MB - * page tables. - * - * The page tables we create span up to the next 4MB - * virtual memory boundary, but that's OK as we won't - * use that memory anyway. - */ - if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) { - unsigned long __pe; - - set_in_cr4(X86_CR4_PSE); - boot_cpu_data.wp_works_ok = 1; - __pe = _KERNPG_TABLE + _PAGE_4M + __pa(address); - /* Make it "global" too if supported */ - if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) { - set_in_cr4(X86_CR4_PGE); - __pe += _PAGE_GLOBAL; - } - pgd_val(*pg_dir) = __pe; - pg_dir++; - address += 4*1024*1024; - continue; - } + __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir))); - /* - * We're on a [34]86, use normal page tables. - * pg_table is physical at this point - */ - pg_table = (pte_t *) (PAGE_MASK & pgd_val(*pg_dir)); - if (!pg_table) { - pg_table = (pte_t *) __pa(start_mem); - start_mem += PAGE_SIZE; - } +#if CONFIG_X86_PAE + /* + * We will bail out later - printk doesnt work right now so + * the user would just see a hanging kernel. + */ + if (cpu_has_pae) + set_in_cr4(X86_CR4_PAE); +#endif - pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pg_table; - pg_dir++; + __flush_tlb(); - /* now change pg_table to kernel virtual addresses */ - pg_table = (pte_t *) __va(pg_table); - for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) { - pte_t pte = mk_pte(address, PAGE_KERNEL); - if (address >= end_mem) - pte_val(pte) = 0; - set_pte(pg_table, pte); - address += PAGE_SIZE; - } - } - start_mem = fixmap_init(start_mem); #ifdef __SMP__ - start_mem = init_smp_mappings(start_mem); + init_smp_mappings(); #endif - local_flush_tlb(); -#ifndef CONFIG_BIGMEM - return free_area_init(start_mem, end_mem); -#else +#ifdef CONFIG_HIGHMEM kmap_init(); /* run after fixmap_init */ - return free_area_init(start_mem, bigmem_end + PAGE_OFFSET); #endif +#ifdef CONFIG_HIGHMEM + free_area_init(highend_pfn); +#else + free_area_init(max_low_pfn); +#endif + return; } /* @@ -340,23 +432,38 @@ void __init test_wp_bit(void) { - unsigned char tmp_reg; - unsigned long old = pg0[0]; +/* + * Ok, all PAE-capable CPUs are definitely handling the WP bit right. + */ +//#ifndef CONFIG_X86_PAE + const unsigned long vaddr = PAGE_OFFSET; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte, old_pte; + char tmp_reg; printk("Checking if this processor honours the WP bit even in supervisor mode... "); - pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY)); + + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + old_pte = *pte; + *pte = mk_pte_phys(0, PAGE_READONLY); local_flush_tlb(); + __asm__ __volatile__( "jmp 1f; 1:\n" "movb %0,%1\n" "movb %1,%0\n" "jmp 1f; 1:\n" - :"=m" (*(char *) __va(0)), + :"=m" (*(char *) vaddr), "=q" (tmp_reg) :/* no inputs */ :"memory"); - pg0[0] = old; + + *pte = old_pte; local_flush_tlb(); + if (boot_cpu_data.wp_works_ok < 0) { boot_cpu_data.wp_works_ok = 0; printk("No.\n"); @@ -365,136 +472,95 @@ #endif } else printk(".\n"); +//#endif } -static void __init mem_init_region(unsigned long pfn, unsigned long count, unsigned long start_mem_pfn) +static inline int page_is_ram (unsigned long pagenr) { - printk("memory region: %luk @ %08lx000\n", count << 2, pfn); + int i; - do { - if (pfn >= max_mapnr) - break; + for (i = 0; i < e820.nr_map; i++) { + unsigned long addr, size; - /* Avoid the kernel mapping between HIGH_MEMORY and "start_mem".. */ - if (pfn < (HIGH_MEMORY >> PAGE_SHIFT) || pfn >= start_mem_pfn) - clear_bit(PG_reserved, &mem_map[pfn].flags); - - pfn++; - } while (--count > 0); + if (e820.map[i].type != E820_RAM) /* not usable memory */ + continue; + addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; + size = e820.map[i].size >> PAGE_SHIFT; + if ((pagenr >= addr) && (pagenr < addr+size)) + return 1; + } + return 0; } -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +void __init mem_init(void) { - unsigned long start_low_mem = PAGE_SIZE; int codepages = 0; int reservedpages = 0; int datapages = 0; int initpages = 0; - unsigned long tmp; - int i, avail; +#ifdef CONFIG_HIGHMEM + int tmp; - end_mem &= PAGE_MASK; -#ifdef CONFIG_BIGMEM - bigmem_start = PAGE_ALIGN(bigmem_start); - bigmem_end &= PAGE_MASK; -#endif - high_memory = (void *) end_mem; -#ifndef CONFIG_BIGMEM - max_mapnr = num_physpages = MAP_NR(end_mem); + if (!mem_map) + BUG(); + highmem_start_page = mem_map + highstart_pfn; + /* cache the highmem_mapnr */ + highmem_mapnr = highstart_pfn; + max_mapnr = num_physpages = highend_pfn; #else - max_mapnr = num_physpages = PHYSMAP_NR(bigmem_end); - /* cache the bigmem_mapnr */ - bigmem_mapnr = PHYSMAP_NR(bigmem_start); + max_mapnr = num_physpages = max_low_pfn; #endif + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); - /* mark usable pages in the mem_map[] */ - start_low_mem = PAGE_ALIGN(start_low_mem)+PAGE_OFFSET; + /* this will put all low memory onto the freelists */ + totalram_pages += free_all_bootmem(); -#ifdef __SMP__ - /* - * But first pinch a few for the stack/trampoline stuff - * FIXME: Don't need the extra page at 4K, but need to fix - * trampoline before removing it. (see the GDT stuff) - * - */ - start_low_mem += PAGE_SIZE; /* 32bit startup code */ - start_low_mem = smp_alloc_memory(start_low_mem); /* AP processor stacks */ -#endif - start_mem = PAGE_ALIGN(start_mem); - - /* walk the whitelist, unreserving good memory - */ - for (avail = i = 0; i < e820.nr_map; i++) { - unsigned long start_pfn, end_pfn; - - if (e820.map[i].type != E820_RAM) /* not usable memory */ - continue; - - start_pfn = (e820.map[i].addr + PAGE_SIZE - 1) >> PAGE_SHIFT; - end_pfn = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT; - - /* We have a certain amount of low memory reserved */ - if (start_pfn < MAP_NR(start_low_mem)) - start_pfn = MAP_NR(start_low_mem); +#ifdef CONFIG_HIGHMEM + for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { + struct page *page = mem_map + tmp; - if (end_pfn <= start_pfn) - continue; - - mem_init_region(start_pfn, end_pfn - start_pfn, MAP_NR(start_mem)); - } - - for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) { - if (tmp >= MAX_DMA_ADDRESS) - clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); - if (PageReserved(mem_map+MAP_NR(tmp))) { - if (tmp >= (unsigned long) &_text && tmp < (unsigned long) &_edata) { - if (tmp < (unsigned long) &_etext) - codepages++; - else - datapages++; - } else if (tmp >= (unsigned long) &__init_begin - && tmp < (unsigned long) &__init_end) - initpages++; - else if (tmp >= (unsigned long) &__bss_start - && tmp < (unsigned long) start_mem) - datapages++; - else - reservedpages++; + if (!page_is_ram(tmp)) { + SetPageReserved(page); continue; } - set_page_count(mem_map+MAP_NR(tmp), 1); - totalram += PAGE_SIZE; -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) -#endif - free_page(tmp); - } -#ifdef CONFIG_BIGMEM - for (tmp = bigmem_start; tmp < bigmem_end; tmp += PAGE_SIZE) { - clear_bit(PG_reserved, &mem_map[PHYSMAP_NR(tmp)].flags); - set_bit(PG_BIGMEM, &mem_map[PHYSMAP_NR(tmp)].flags); - atomic_set(&mem_map[PHYSMAP_NR(tmp)].count, 1); - free_page(tmp + PAGE_OFFSET); - totalbig += PAGE_SIZE; + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; } - totalram += totalbig; + totalram_pages += totalhigh_pages; #endif - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %dk bigmem)\n", + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), - (int) (totalbig >> 10) + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) ); +#if CONFIG_X86_PAE + if (!cpu_has_pae) + panic("cannot execute a PAE-enabled kernel on a PAE-incapable CPU!"); +#endif if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); + /* + * Subtle. SMP is doing it's boot stuff late (because it has to + * fork idle threads) - but it also needs low mappings for the + * protected-mode entry to work. We zap these entries only after + * the WP-bit has been tested. + */ +#ifndef CONFIG_SMP + zap_low_mappings(); +#endif + } void free_initmem(void) @@ -503,21 +569,22 @@ addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + ClearPageReserved(mem_map + MAP_NR(addr)); set_page_count(mem_map+MAP_NR(addr), 1); free_page(addr); - totalram += PAGE_SIZE; + totalram_pages++; } printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } void si_meminfo(struct sysinfo *val) { - val->totalram = totalram; + val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); - val->totalbig = totalbig; - val->freebig = nr_free_bigpages << PAGE_SHIFT; + val->freeram = nr_free_pages; + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = totalhigh_pages; + val->freehigh = nr_free_highpages; + val->mem_unit = PAGE_SIZE; return; } diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c --- v2.3.22/linux/arch/i386/mm/ioremap.c Sun Jul 25 13:45:25 1999 +++ linux/arch/i386/mm/ioremap.c Tue Oct 19 10:22:20 1999 @@ -20,15 +20,19 @@ end = address + size; if (end > PMD_SIZE) end = PMD_SIZE; + if (address >= end) + BUG(); do { - if (!pte_none(*pte)) + if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); + BUG(); + } set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | flags))); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; - } while (address < end); + } while (address && (address < end)); } static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, @@ -41,6 +45,8 @@ if (end > PGDIR_SIZE) end = PGDIR_SIZE; phys_addr -= address; + if (address >= end) + BUG(); do { pte_t * pte = pte_alloc_kernel(pmd, address); if (!pte) @@ -48,7 +54,7 @@ remap_area_pte(pte, address, end - address, address + phys_addr, flags); address = (address + PMD_SIZE) & PMD_MASK; pmd++; - } while (address < end); + } while (address && (address < end)); return 0; } @@ -61,8 +67,11 @@ phys_addr -= address; dir = pgd_offset(&init_mm, address); flush_cache_all(); - while (address < end) { - pmd_t *pmd = pmd_alloc_kernel(dir, address); + if (address >= end) + BUG(); + do { + pmd_t *pmd; + pmd = pmd_alloc_kernel(dir, address); if (!pmd) return -ENOMEM; if (remap_area_pmd(pmd, address, end - address, @@ -71,7 +80,7 @@ set_pgdir(address, *dir); address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; - } + } while (address && (address < end)); flush_tlb_all(); return 0; } diff -u --recursive --new-file v2.3.22/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds --- v2.3.22/linux/arch/i386/vmlinux.lds Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/vmlinux.lds Sat Oct 16 21:00:59 1999 @@ -0,0 +1,75 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = 0xC0000000 + 0x100000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --recursive --new-file v2.3.22/linux/arch/i386/vmlinux.lds.S linux/arch/i386/vmlinux.lds.S --- v2.3.22/linux/arch/i386/vmlinux.lds.S Mon Aug 2 13:57:59 1999 +++ linux/arch/i386/vmlinux.lds.S Wed Dec 31 16:00:00 1969 @@ -1,75 +0,0 @@ -/* ld script to make i386 Linux kernel - * Written by Martin Mares ; - */ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(_start) -SECTIONS -{ - . = PAGE_OFFSET_RAW + 0x100000; - _text = .; /* Text and read-only data */ - .text : { - *(.text) - *(.fixup) - *(.gnu.warning) - } = 0x9090 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } - .kstrtab : { *(.kstrtab) } - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - _etext = .; /* End of text section */ - - .data : { /* Data */ - *(.data) - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - . = ALIGN(8192); /* init_task */ - .data.init_task : { *(.data.init_task) } - - . = ALIGN(4096); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(16); - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(4096); - __init_end = .; - - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } - _end = . ; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } -} diff -u --recursive --new-file v2.3.22/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.3.22/linux/arch/m68k/mm/init.c Tue Sep 7 12:14:06 1999 +++ linux/arch/m68k/mm/init.c Sat Oct 16 10:50:48 1999 @@ -112,6 +112,7 @@ printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif diff -u --recursive --new-file v2.3.22/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.3.22/linux/arch/mips/mm/init.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/mm/init.c Sat Oct 16 10:50:48 1999 @@ -265,6 +265,7 @@ printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); printk("%d free pages\n", free); + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.3.22/linux/arch/ppc/kernel/apus_setup.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/apus_setup.c Wed Oct 20 22:13:20 1999 @@ -255,8 +255,7 @@ /*********************************************************** SETUP */ /* From arch/m68k/kernel/setup.c. */ -void __init apus_setup_arch(unsigned long * memory_start_p, - unsigned long * memory_end_p) +void __init apus_setup_arch(void) { #ifdef CONFIG_APUS extern char cmd_line[]; diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.3.22/linux/arch/ppc/kernel/chrp_pci.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/chrp_pci.c Mon Oct 18 11:14:22 1999 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "pci.h" diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.3.22/linux/arch/ppc/kernel/chrp_setup.c Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/kernel/chrp_setup.c Wed Oct 20 22:13:20 1999 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,13 +36,12 @@ #include #include #include +#include #include #include #include #include -#include -#include #include #include #include @@ -227,7 +227,7 @@ void __init -chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) +chrp_setup_arch(void) { extern char cmd_line[]; struct device_node *device; @@ -278,7 +278,7 @@ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif - *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); + pmac_find_bridges(); /* Get the event scan rate for the rtas so we know how * often it expects a heartbeat. -- Cort @@ -363,10 +363,7 @@ irq = *chrp_int_ack_special; else irq = i8259_irq( smp_processor_id() ); - /* - * Acknowledge as soon as possible to allow i8259 - * interrupt nesting */ - openpic_eoi( smp_processor_id() ); + openpic_eoi( smp_processor_id() ); } if (irq == OPENPIC_VEC_SPURIOUS) /* @@ -374,6 +371,11 @@ * acknowledged */ irq = -1; + /* + * I would like to openpic_eoi here but there seem to be timing problems + * between the openpic ack and the openpic eoi. + * -- Cort + */ return irq; } @@ -382,88 +384,14 @@ /* * If it's an i8259 irq then we've already done the * openpic irq. So we just check to make sure the controller - * is an openpic and if it is then eoi -- Cort + * is an openpic and if it is then eoi + * + * We do it this way since our irq_desc[irq].ctl can change + * with RTL and no longer be open_pic -- Cort */ - if ( irq_desc[irq].ctl == &open_pic ) + if ( irq >= open_pic.irq_offset) openpic_eoi( smp_processor_id() ); } - -#if 0 -void -chrp_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) -{ - int irq; - unsigned long bits = 0; - int openpic_eoi_done = 0; - -#ifdef __SMP__ - { - unsigned int loops = 1000000; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } -#endif /* __SMP__ */ - - irq = openpic_irq(0); - if (irq == IRQ_8259_CASCADE) - { - /* - * This magic address generates a PCI IACK cycle. - * - * This should go in the above mask/ack code soon. -- Cort - */ - if ( chrp_int_ack_special ) - irq = *chrp_int_ack_special; - else - irq = i8259_irq(0); - /* - * Acknowledge as soon as possible to allow i8259 - * interrupt nesting */ - openpic_eoi(0); - openpic_eoi_done = 1; - } - if (irq == OPENPIC_VEC_SPURIOUS) - { - /* - * Spurious interrupts should never be - * acknowledged - */ - ppc_spurious_interrupts++; - openpic_eoi_done = 1; - goto out; - } - bits = 1UL << irq; - - if (irq < 0) - { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - } - else - { - ppc_irq_dispatch_handler( regs, irq ); - } -out: - if (!openpic_eoi_done) - openpic_eoi(0); -} -#endif void __init chrp_init_IRQ(void) { diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.3.22/linux/arch/ppc/kernel/gemini_setup.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/gemini_setup.c Wed Oct 20 22:13:20 1999 @@ -134,7 +134,7 @@ extern char cmd_line[]; -void __init gemini_setup_arch(unsigned long *memstart, unsigned long *memend) +void __init gemini_setup_arch(void) { unsigned int cpu; extern char cmd_line[]; diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.3.22/linux/arch/ppc/kernel/idle.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/idle.c Wed Oct 20 22:13:20 1999 @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.67 1999/09/10 05:05:47 paulus Exp $ + * $Id: idle.c,v 1.68 1999/10/15 18:16:03 cort Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -293,11 +293,8 @@ /* set the POW bit in the MSR, and enable interrupts * so we wake up sometime! */ + __sti(); /* this keeps rtl from getting confused -- Cort */ _nmask_and_or_msr(0, MSR_POW | MSR_EE); - - /* Disable interrupts again so restore_flags will - * work. */ - _nmask_and_or_msr(MSR_EE, 0); } restore_flags(msr); default: diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.22/linux/arch/ppc/kernel/irq.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/irq.c Wed Oct 20 22:13:20 1999 @@ -296,15 +296,19 @@ irq = ppc_md.get_irq( regs ); if ( irq < 0 ) { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - return; + /* -2 means ignore, already handled */ + if (irq != -2) { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } + goto out; } ppc_irq_dispatch_handler( regs, irq ); if ( ppc_md.post_irq ) ppc_md.post_irq( irq ); - + + out: hardirq_exit( cpu ); } diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c --- v2.3.22/linux/arch/ppc/kernel/m8xx_setup.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/m8xx_setup.c Wed Oct 20 22:13:20 1999 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -83,13 +84,12 @@ } void __init -m8xx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) +m8xx_setup_arch(void) { int cpm_page; extern char cmd_line[]; - cpm_page = *memory_start_p; - *memory_start_p += PAGE_SIZE; + cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE); printk("Boot arguments: %s\n", cmd_line); @@ -108,6 +108,9 @@ rd_doload = 1; rd_image_start = 0; #endif +#if 0 /* XXX this may need to be updated for the new bootmem stuff, + or possibly just deleted (see set_phys_avail() in init.c). + - paulus. */ /* initrd_start and size are setup by boot/head.S and kernel/head.S */ if ( initrd_start ) { @@ -119,6 +122,7 @@ initrd_start = 0; } } +#endif #endif } diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c --- v2.3.22/linux/arch/ppc/kernel/mbx_setup.c Tue Aug 31 17:29:13 1999 +++ linux/arch/ppc/kernel/mbx_setup.c Wed Oct 20 22:13:20 1999 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include #include @@ -76,13 +76,12 @@ } void __init -mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) +mbx_setup_arch(void) { int cpm_page; extern char cmd_line[]; - cpm_page = *memory_start_p; - *memory_start_p += PAGE_SIZE; + cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE); sprintf(cmd_line, "%s root=/dev/nfs nfsroot=/sys/mbxroot", @@ -104,6 +103,9 @@ rd_doload = 1; rd_image_start = 0; #endif +#if 0 /* XXX this may need to be updated for the new bootmem stuff, + or possibly just deleted (see set_phys_avail() in init.c). + - paulus. */ /* initrd_start and size are setup by boot/head.S and kernel/head.S */ if ( initrd_start ) { @@ -115,6 +117,7 @@ initrd_start = 0; } } +#endif #endif #ifdef notdef diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.3.22/linux/arch/ppc/kernel/misc.S Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/kernel/misc.S Wed Oct 20 22:13:20 1999 @@ -235,9 +235,9 @@ * snoop from the data cache. * This is a no-op on the 601 which has a unified cache. * - * void flush_page_to_ram(void *page) + * void __flush_page_to_ram(void *page) */ -_GLOBAL(flush_page_to_ram) +_GLOBAL(__flush_page_to_ram) mfspr r5,PVR rlwinm r5,r5,16,16,31 cmpi 0,r5,1 diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.3.22/linux/arch/ppc/kernel/pci.c Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/kernel/pci.c Wed Oct 20 22:13:20 1999 @@ -146,3 +146,25 @@ { return 0; } + +/* the next two are stolen from the alpha port... */ +void __init +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + unsigned long where, size; + u32 reg; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); +} + +void __init +pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); + /* XXX FIXME - update OF device tree node interrupt property */ +} diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.3.22/linux/arch/ppc/kernel/pmac_pci.c Tue Aug 31 17:29:13 1999 +++ linux/arch/ppc/kernel/pmac_pci.c Wed Oct 20 22:13:20 1999 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ struct bridge_data **bridges, *bridge_list; static int max_bus; -static void add_bridges(struct device_node *dev, unsigned long *mem_ptr); +static void add_bridges(struct device_node *dev); /* * Magic constants for enabling cache coherency in the bandit/PSX bridge. @@ -362,24 +363,22 @@ bp->io_base); } -unsigned long __init pmac_find_bridges(unsigned long mem_start, unsigned long mem_end) +void __init pmac_find_bridges(void) { int bus; struct bridge_data *bridge; bridge_list = 0; max_bus = 0; - add_bridges(find_devices("bandit"), &mem_start); - add_bridges(find_devices("chaos"), &mem_start); - add_bridges(find_devices("pci"), &mem_start); - bridges = (struct bridge_data **) mem_start; - mem_start += (max_bus + 1) * sizeof(struct bridge_data *); + add_bridges(find_devices("bandit")); + add_bridges(find_devices("chaos")); + add_bridges(find_devices("pci")); + bridges = (struct bridge_data **) + alloc_bootmem((max_bus + 1) * sizeof(struct bridge_data *)); memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *)); for (bridge = bridge_list; bridge != NULL; bridge = bridge->next) for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus) bridges[bus] = bridge; - - return mem_start; } /* @@ -387,7 +386,7 @@ * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, * if we have one or more bandit or chaos bridges, we don't have a MPC106. */ -static void __init add_bridges(struct device_node *dev, unsigned long *mem_ptr) +static void __init add_bridges(struct device_node *dev) { int *bus_range; int len; @@ -413,8 +412,7 @@ printk(KERN_INFO "PCI buses %d..%d", bus_range[0], bus_range[1]); printk(" controlled by %s at %x\n", dev->name, addr->address); - bp = (struct bridge_data *) *mem_ptr; - *mem_ptr += sizeof(struct bridge_data); + bp = (struct bridge_data *) alloc_bootmem(sizeof(*bp)); if (strcmp(dev->name, "pci") != 0) { bp->cfg_addr = (volatile unsigned int *) ioremap(addr->address + 0x800000, 0x1000); diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.3.22/linux/arch/ppc/kernel/pmac_pic.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/pmac_pic.c Wed Oct 20 22:13:20 1999 @@ -225,7 +225,7 @@ xmon(regs); #endif smp_message_recv(); - return -1; + return -2; /* ignore, already handled */ } { @@ -374,7 +374,7 @@ } /* get addresses of second controller */ - irqctrler = (irqctrler->next) ? irqctrler->next : NULL; + irqctrler = irqctrler->next; if (irqctrler && irqctrler->n_addrs > 0) { addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); @@ -382,6 +382,11 @@ pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) (addr + (4 - i) * 0x10); } + } else { + /* older powermacs have a GC (grand central) or ohare at + f3000000, with interrupt control registers at f3000020. */ + addr = (unsigned long) ioremap(0xf3000000, 0x40); + pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20); } /* disable all interrupts in all controllers */ diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.3.22/linux/arch/ppc/kernel/pmac_setup.c Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/kernel/pmac_setup.c Wed Oct 20 22:13:20 1999 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -57,7 +58,6 @@ #include #include #include -#include #include #include #include @@ -238,7 +238,7 @@ static volatile u32 *sysctrl_regs; void __init -pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p) +pmac_setup_arch(void) { struct device_node *cpu; int *fp; @@ -269,7 +269,7 @@ __ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY)); ohare_init(); - *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); + pmac_find_bridges(); init_p2pbridge(); /* Checks "l2cr-value" property in the registry */ @@ -421,7 +421,7 @@ #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) extern int pmac_ide_count; extern struct device_node *pmac_ide_node[]; -static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89 }; +static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 }; kdev_t __init find_ide_boot(void) { diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.3.22/linux/arch/ppc/kernel/ppc_ksyms.c Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/kernel/ppc_ksyms.c Wed Oct 20 22:13:20 1999 @@ -60,7 +60,6 @@ EXPORT_SYMBOL(syscall_trace); EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(do_IRQ); -EXPORT_SYMBOL(init_task_union); EXPORT_SYMBOL(MachineCheckException); EXPORT_SYMBOL(AlignmentException); EXPORT_SYMBOL(ProgramCheckException); diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.3.22/linux/arch/ppc/kernel/prep_setup.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/prep_setup.c Wed Oct 20 22:13:20 1999 @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -211,7 +210,7 @@ } void __init -prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) +prep_setup_arch() { extern char cmd_line[]; unsigned char reg; diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.22/linux/arch/ppc/kernel/setup.c Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/kernel/setup.c Wed Oct 20 22:13:20 1999 @@ -11,12 +11,11 @@ #include #include #include +#include #include #include #include -#include -#include #include #include #include @@ -540,14 +539,12 @@ } } -void __init setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +void __init setup_arch(char **cmdline_p) { extern int panic_timeout; extern char _etext[], _edata[]; extern char *klimit; - extern unsigned long find_available_memory(void); - extern unsigned long *end_of_DRAM; + extern void do_init_bootmem(void); #ifdef CONFIG_XMON extern void xmon_map_scc(void); @@ -556,22 +553,22 @@ xmon(0); #endif /* CONFIG_XMON */ - /* reboot on panic */ + /* reboot on panic */ panic_timeout = 180; init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) _etext; init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) klimit; + init_mm.brk = (unsigned long) klimit; /* Save unparsed command line copy for /proc/cmdline */ strcpy(saved_command_line, cmd_line); *cmdline_p = cmd_line; - *memory_start_p = find_available_memory(); - *memory_end_p = (unsigned long) end_of_DRAM; + /* set up the bootmem stuff with available memory */ + do_init_bootmem(); - ppc_md.setup_arch(memory_start_p, memory_end_p); + ppc_md.setup_arch(); /* clear the progress line */ if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); } diff -u --recursive --new-file v2.3.22/linux/arch/ppc/mbx_defconfig linux/arch/ppc/mbx_defconfig --- v2.3.22/linux/arch/ppc/mbx_defconfig Sat Jun 26 08:34:19 1999 +++ linux/arch/ppc/mbx_defconfig Mon Oct 18 11:14:22 1999 @@ -74,7 +74,7 @@ # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_CMD646 is not set CONFIG_BLK_DEV_SL82C105=y # CONFIG_IDE_CHIPSETS is not set diff -u --recursive --new-file v2.3.22/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.22/linux/arch/ppc/mm/init.c Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/mm/init.c Wed Oct 20 22:13:20 1999 @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.193 1999/10/11 18:50:35 geert Exp $ + * $Id: init.c,v 1.195 1999/10/15 16:39:39 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include /* for initrd_* */ #endif @@ -59,6 +60,9 @@ atomic_t next_mmu_context; unsigned long *end_of_DRAM; int mem_init_done; +int init_bootmem_done; +int boot_mapsize; +unsigned long totalram_pages = 0; extern pgd_t swapper_pg_dir[]; extern char _start[], _end[]; extern char etext[], _stext[]; @@ -108,9 +112,9 @@ }; struct mem_pieces phys_mem; struct mem_pieces phys_avail; -struct mem_pieces prom_mem; static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int); +static void set_phys_avail(void); void *find_mem_piece(unsigned, unsigned); static void print_mem_pieces(struct mem_pieces *); #if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) @@ -202,7 +206,7 @@ pte = (pte_t *) MMU_get_page(); else if ((pte = (pte_t *) get_zero_page_fast()) == NULL) if ((pte = (pte_t *) __get_free_page(GFP_KERNEL))) - clear_page((unsigned long)pte); + clear_page(pte); if (pte) { pmd_val(*pmd) = (unsigned long)pte; return pte + offset; @@ -246,20 +250,20 @@ * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. */ -unsigned long empty_bad_page_table; +pte_t *empty_bad_page_table; pte_t * __bad_pagetable(void) { - __clear_user((void *)empty_bad_page_table, PAGE_SIZE); - return (pte_t *) empty_bad_page_table; + clear_page(empty_bad_page_table); + return empty_bad_page_table; } -unsigned long empty_bad_page; +void *empty_bad_page; pte_t __bad_page(void) { - __clear_user((void *)empty_bad_page, PAGE_SIZE); - return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED)); + clear_page(empty_bad_page); + return pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); } void show_mem(void) @@ -289,6 +293,7 @@ printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%d pages in page table cache\n",(int)pgtable_cache_size); + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif @@ -345,7 +350,7 @@ val->totalram = 0; val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); + val->bufferram = atomic_read(&buffermem_pages); while (i-- > 0) { if (PageReserved(mem_map+i)) continue; @@ -590,6 +595,37 @@ #endif /* CONFIG_8xx */ /* + * Set phys_avail to phys_mem less the kernel text/data/bss. + */ +static void __init set_phys_avail(void) +{ + unsigned long kstart, ksize; + + /* we can't call the prom any more at this stage, so + all of memory is available (after klimit) */ + phys_avail = phys_mem; + + /* + * phys_avail records memory we can use. + * Make sure the kernel text/data/bss is not in it. + */ + kstart = __pa(_stext); /* should be 0 */ + ksize = PAGE_ALIGN(klimit - _stext); + remove_mem_piece(&phys_avail, kstart, ksize, 0); + remove_mem_piece(&phys_avail, 0, 0x4000, 0); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + /* + * Remove the initialized ramdisk from the available memory. + */ + remove_mem_piece(&phys_avail, __pa(initrd_start), + initrd_end - initrd_start, 1); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +/* * Scan a region for a piece of a given size with the required alignment. */ void __init *find_mem_piece(unsigned size, unsigned align) @@ -681,7 +717,7 @@ printk("\n"); } -#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_PPC_ALL) +#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) /* * Add some memory to an array of pieces */ @@ -833,8 +869,8 @@ { int i; unsigned long v, p, s, f; -#ifndef CONFIG_8xx +#ifndef CONFIG_8xx if (!__map_without_bats) { unsigned long tot, mem_base, bl, done; unsigned long max_size = (256<<20); @@ -869,24 +905,7 @@ RAM_PAGE); } } - v = KERNELBASE; - for (i = 0; i < phys_mem.n_regions; ++i) { - p = phys_mem.regions[i].address; - for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { - f = _PAGE_PRESENT | _PAGE_ACCESSED; - if ((char *) v < _stext || (char *) v >= etext) - f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; - else - /* On the powerpc, no user access - forces R/W kernel access */ - f |= _PAGE_USER; - map_page(v, p, f); - v += PAGE_SIZE; - p += PAGE_SIZE; - } - } - -#else /* CONFIG_8xx */ +#endif /* CONFIG_8xx */ for (i = 0; i < phys_mem.n_regions; ++i) { v = (ulong)__va(phys_mem.regions[i].address); @@ -896,37 +915,35 @@ * don't get ASID compares on kernel space. */ f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; - - /* I don't really need the rest of this code, but - * I grabbed it because I think the line: - * f |= _PAGE_USER - * is incorrect. It needs to be set to bits we - * don't define to cause a kernel read-only. On - * the MPC8xx, the PAGE_DIRTY takes care of that - * for us (along with the RW software state). - */ if ((char *) v < _stext || (char *) v >= etext) f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; +#ifndef CONFIG_8xx + else + /* On the powerpc (not 8xx), no user access + forces R/W kernel access */ + f |= _PAGE_USER; +#endif /* CONFIG_8xx */ map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; } - } -#endif /* CONFIG_8xx */ + } } -/* This can get called from ioremap, so don't make it an __init, OK? */ +/* In fact this is only called until mem_init is done. */ static void __init *MMU_get_page(void) { void *p; if (mem_init_done) { p = (void *) __get_free_page(GFP_KERNEL); - if (p == 0) - panic("couldn't get a page in MMU_get_page"); + } else if (init_bootmem_done) { + p = alloc_bootmem_pages(PAGE_SIZE); } else { p = find_mem_piece(PAGE_SIZE, PAGE_SIZE); } + if (p == 0) + panic("couldn't get a page in MMU_get_page"); __clear_user(p, PAGE_SIZE); return p; } @@ -1106,6 +1123,51 @@ } /* + * Initialize the bootmem system and give it all the memory we + * have available. + */ +void __init do_init_bootmem(void) +{ + unsigned long start, size; + int i; + + /* + * Find an area to use for the bootmem bitmap. + * We look for the first area which is at least + * 128kB in length (128kB is enough for a bitmap + * for 4GB of memory, using 4kB pages), plus 1 page + * (in case the address isn't page-aligned). + */ + start = 0; + size = 0; + for (i = 0; i < phys_avail.n_regions; ++i) { + unsigned long a = phys_avail.regions[i].address; + unsigned long s = phys_avail.regions[i].size; + if (s <= size) + continue; + start = a; + size = s; + if (s >= 33 * PAGE_SIZE) + break; + } + start = PAGE_ALIGN(start); + + boot_mapsize = init_bootmem(start >> PAGE_SHIFT, + __pa(end_of_DRAM) >> PAGE_SHIFT); + + /* remove the bootmem bitmap from the available memory */ + remove_mem_piece(&phys_avail, start, start + boot_mapsize, 1); + + /* add everything in phys_avail into the bootmem map */ + for (i = 0; i < phys_avail.n_regions; ++i) + free_bootmem(phys_avail.regions[i].address, + phys_avail.regions[i].size); + + init_bootmem_done = 1; +} + +#if 0 +/* * Find some memory for setup_arch to return. * We use the largest chunk of available memory as the area * that setup_arch returns, making sure that there are at @@ -1143,97 +1205,56 @@ avail_start = (unsigned long) __va(a); return avail_start; } +#endif /* 0 */ /* * paging_init() sets up the page tables - in fact we've already done this. */ -unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) +void __init paging_init(void) { - extern unsigned long free_area_init(unsigned long, unsigned long); /* * Grab some memory for bad_page and bad_pagetable to use. */ - empty_bad_page = PAGE_ALIGN(start_mem); - empty_bad_page_table = empty_bad_page + PAGE_SIZE; - start_mem = empty_bad_page + 2 * PAGE_SIZE; + empty_bad_page = alloc_bootmem_pages(PAGE_SIZE); + empty_bad_page_table = alloc_bootmem_pages(PAGE_SIZE); - /* note: free_area_init uses its second argument - to size the mem_map array. */ - start_mem = free_area_init(start_mem, end_mem); - return start_mem; + free_area_init(max_low_pfn); } -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +void __init mem_init(void) { unsigned long addr; - int i; - unsigned long a, lim; int codepages = 0; int datapages = 0; int initpages = 0; extern unsigned int rtas_data, rtas_size; - end_mem &= PAGE_MASK; - high_memory = (void *) end_mem; - max_mapnr = MAP_NR(high_memory); - - /* mark usable pages in the mem_map[] */ - start_mem = PAGE_ALIGN(start_mem); - + max_mapnr = max_low_pfn; + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ - remove_mem_piece(&phys_avail, __pa(avail_start), - start_mem - avail_start, 1); - for (i = 0; i < phys_avail.n_regions; ++i) { - a = (unsigned long) __va(phys_avail.regions[i].address); - lim = (a + phys_avail.regions[i].size) & PAGE_MASK; - a = PAGE_ALIGN(a); - for (; a < lim; a += PAGE_SIZE) - clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); - } + totalram_pages += free_all_bootmem(); #ifdef CONFIG_BLK_DEV_INITRD /* if we are booted from BootX with an initial ramdisk, make sure the ramdisk pages aren't reserved. */ if (initrd_start) { - for (a = initrd_start; a < initrd_end; a += PAGE_SIZE) - clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); + for (addr = initrd_start; addr < initrd_end; addr += PAGE_SIZE) + clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); } #endif /* CONFIG_BLK_DEV_INITRD */ - /* free the prom's memory - no-op on prep */ - for (i = 0; i < prom_mem.n_regions; ++i) { - a = (unsigned long) __va(prom_mem.regions[i].address); - lim = (a + prom_mem.regions[i].size) & PAGE_MASK; - a = PAGE_ALIGN(a); - for (; a < lim; a += PAGE_SIZE) - clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); - } - - prom_trashed = 1; - - for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { - if (PageReserved(mem_map + MAP_NR(addr))) { - if (addr < (ulong) etext) - codepages++; - else if (addr >= (unsigned long)&__init_begin - && addr < (unsigned long)&__init_end) - initpages++; - else if (addr < (ulong) start_mem) - datapages++; + for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM; + addr += PAGE_SIZE) { + if (!PageReserved(mem_map + MAP_NR(addr))) continue; - } - set_page_count(mem_map + MAP_NR(addr), 1); -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || - addr < (initrd_start & PAGE_MASK) || addr >= initrd_end) -#endif /* CONFIG_BLK_DEV_INITRD */ -#ifndef CONFIG_8xx - if ( !rtas_data || - addr < (rtas_data & PAGE_MASK) || - addr >= (rtas_data+rtas_size)) -#endif /* CONFIG_8xx */ - free_page(addr); + if (addr < (ulong) etext) + codepages++; + else if (addr >= (unsigned long)&__init_begin + && addr < (unsigned long)&__init_end) + initpages++; + else if (addr < (ulong) klimit) + datapages++; } printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", @@ -1241,7 +1262,7 @@ codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), - PAGE_OFFSET, end_mem); + PAGE_OFFSET, (unsigned long) end_of_DRAM); mem_init_done = 1; } @@ -1257,11 +1278,9 @@ unsigned long __init *pmac_find_end_of_memory(void) { unsigned long a, total; - unsigned long kstart, ksize; - int i; /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (256<<20) +#define RAM_LIMIT (768<<20) memory_node = find_devices("memory"); if (memory_node == NULL) { @@ -1309,32 +1328,8 @@ phys_mem.n_regions = 1; } - if (boot_infos == 0) { - /* record which bits the prom is using */ - get_mem_prop("available", &phys_avail); - prom_mem = phys_mem; - for (i = 0; i < phys_avail.n_regions; ++i) - remove_mem_piece(&prom_mem, - phys_avail.regions[i].address, - phys_avail.regions[i].size, 0); - } else { - /* booted from BootX - it's all available (after klimit) */ - phys_avail = phys_mem; - prom_mem.n_regions = 0; - } + set_phys_avail(); - /* - * phys_avail records memory we can use now. - * prom_mem records memory allocated by the prom that we - * don't want to use now, but we'll reclaim later. - * Make sure the kernel text/data/bss is in neither. - */ - kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(klimit - _stext); - remove_mem_piece(&phys_avail, kstart, ksize, 0); - remove_mem_piece(&prom_mem, kstart, ksize, 0); - remove_mem_piece(&phys_avail, 0, 0x4000, 0); - remove_mem_piece(&prom_mem, 0, 0x4000, 0); #undef RAM_LIMIT return __va(total); } @@ -1349,7 +1344,6 @@ */ unsigned long __init *prep_find_end_of_memory(void) { - unsigned long kstart, ksize; unsigned long total; total = res->TotalMemory; @@ -1364,11 +1358,7 @@ printk("Ramsize default to be %ldM\n", total>>20); } append_mem_piece(&phys_mem, 0, total); - phys_avail = phys_mem; - kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(klimit - _stext); - remove_mem_piece(&phys_avail, kstart, ksize, 0); - remove_mem_piece(&phys_avail, 0, 0x4000, 0); + set_phys_avail(); return (__va(total)); } @@ -1378,7 +1368,7 @@ #if defined(CONFIG_GEMINI) unsigned long __init *gemini_find_end_of_memory(void) { - unsigned long total, kstart, ksize, *ret; + unsigned long total, *ret; unsigned char reg; reg = readb(GEMINI_MEMCFG); @@ -1390,10 +1380,7 @@ phys_mem.n_regions = 1; ret = __va(phys_mem.regions[0].size); - phys_avail = phys_mem; - kstart = __pa(_stext); - ksize = PAGE_ALIGN( _end - _stext ); - remove_mem_piece( &phys_avail, kstart, ksize, 0 ); + set_phys_avail(); return ret; } #endif /* defined(CONFIG_GEMINI) || defined(CONFIG_ALL_PPC) */ @@ -1429,15 +1416,8 @@ } /* Now register the memory block. */ - { - unsigned long kstart, ksize; - - append_mem_piece(&phys_mem, memory[0].addr, memory[0].size); - phys_avail = phys_mem; - kstart = __pa(_stext); - ksize = PAGE_ALIGN(klimit - _stext); - remove_mem_piece(&phys_avail, kstart, ksize, 0); - } + append_mem_piece(&phys_mem, memory[0].addr, memory[0].size); + set_phys_avail(); /* Remove the memory chunks that are controlled by special Phase5 hardware. */ @@ -1586,7 +1566,6 @@ */ unsigned long __init *m8xx_find_end_of_memory(void) { - unsigned long kstart, ksize; bd_t *binfo; unsigned long *ret; extern unsigned char __res[]; @@ -1600,11 +1579,7 @@ ret = __va(phys_mem.regions[0].address+ phys_mem.regions[0].size); - phys_avail = phys_mem; - - kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(_end - _stext); - remove_mem_piece(&phys_avail, kstart, ksize, 0); + set_phys_avail(); return ret; } #endif /* ndef CONFIG_8xx */ diff -u --recursive --new-file v2.3.22/linux/arch/sh/Makefile linux/arch/sh/Makefile --- v2.3.22/linux/arch/sh/Makefile Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/Makefile Mon Oct 18 11:16:12 1999 @@ -1,9 +1,11 @@ -# $Id$ +# $Id: Makefile,v 1.1 1999/09/18 16:55:51 gniibe Exp gniibe $ # # 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. # +# Copyright (C) 1999 Kaz Kojima +# # This file is included by the global makefile so that you can add your own # architecture-specific flags and dependencies. Remember to do have actions # for "archclean" and "archdep" for cleaning up and making dependencies for @@ -13,25 +15,35 @@ # # Select the object file format to substitute into the linker script. # -tool-prefix = sh-gniibe- -oformat = elf +tool-prefix = sh-elf + +ifdef CONFIG_LITTLE_ENDIAN +CFLAGS += -ml +AFLAGS += -ml +# LINKFLAGS += -EL +LDFLAGS := -EL + +LD =$(CROSS_COMPILE)ld $(LDFLAGS) + +endif ifdef CONFIG_CROSSCOMPILE CROSS_COMPILE = $(tool-prefix) endif -LINKFLAGS = # -EL # -static #-N MODFLAGS += # # -CFLAGS += -m3 # -ml -LINKFLAGS += -LDFLAGS += # -EL -# -# -HOSTCC = cc +ifdef CONFIG_CPU_SH3 +CFLAGS += -m3 +AFLAGS += -m3 +endif +ifdef CONFIG_CPU_SH4 +CFLAGS += -m4 +AFLAGS += -m4 +endif # # Choosing incompatible machines durings configuration will result in @@ -52,14 +64,16 @@ SUBDIRS := $(SUBDIRS) $(addprefix arch/sh/, kernel mm lib) CORE_FILES := arch/sh/kernel/kernel.o arch/sh/mm/mm.o $(CORE_FILES) -LIBS := $(TOPDIR)/arch/sh/lib/lib.a $(LIBS) $(TOPDIR)/arch/sh/lib/lib.a /home/niibe/lib/gcc-lib/sh-gniibe-elf/egcs-2.91.66/libgcc.a +LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +LIBS := $(TOPDIR)/arch/sh/lib/lib.a $(LIBS) $(TOPDIR)/arch/sh/lib/lib.a \ + $(LIBGCC) MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot vmlinux: arch/sh/vmlinux.lds arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE - gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/linux/config.h -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds + gcc -E -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds FORCE: ; @@ -77,6 +91,7 @@ # $(MAKE) -C arch/$(ARCH)/tools clean archmrproper: + rm -f arch/sh/vmlinux.lds archdep: @$(MAKEBOOT) dep diff -u --recursive --new-file v2.3.22/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.3.22/linux/arch/sh/config.in Mon Oct 11 15:38:14 1999 +++ linux/arch/sh/config.in Mon Oct 18 11:16:13 1999 @@ -12,28 +12,24 @@ mainmenu_option next_comment comment 'Processor type and features' choice 'Processor family' \ - "SH3 CONFIG_CPU_SH3 \ - SH4 CONFIG_CPU_SH4" SH3 + "SH-3 CONFIG_CPU_SH3 \ + SH-4 CONFIG_CPU_SH4" SH-3 bool 'Little Endian' CONFIG_LITTLE_ENDIAN -hex 'Physical memory start address' CONFIG_MEMORY_START 0c000000 +hex 'Physical memory start address' CONFIG_MEMORY_START 08000000 +bool 'Use SH CPU internal real time clock' CONFIG_SH_CPU_RTC endmenu mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool ' Kernel module loader' CONFIG_KMOD + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD fi endmenu -define_bool CONFIG_SERIAL n -define_bool CONFIG_SH3SCI_SERIAL y -define_bool CONFIG_SERIAL_CONSOLE y - mainmenu_option next_comment -comment 'Floppy, IDE, and other block devices' - +comment 'General setup' bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT @@ -41,6 +37,18 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +endmenu + +mainmenu_option next_comment +comment 'Character devices' +define_bool CONFIG_SERIAL n +define_bool CONFIG_SERIAL_CONSOLE y +bool 'SuperH SCI support' CONFIG_SH_SCI_SERIAL +bool 'SuperH SCIF support' CONFIG_SH_SCIF_SERIAL +endmenu + +mainmenu_option next_comment +comment 'Floppy, IDE, and other block devices' tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then @@ -75,4 +83,5 @@ comment 'Kernel hacking' bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'GDB Stub kernel debug' CONFIG_DEBUG_KERNEL_WITH_GDB_STUB endmenu diff -u --recursive --new-file v2.3.22/linux/arch/sh/defconfig linux/arch/sh/defconfig --- v2.3.22/linux/arch/sh/defconfig Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/defconfig Mon Oct 18 11:16:13 1999 @@ -10,48 +10,41 @@ # # Processor type and features # -CONFIG_CPU_SH3=y -# CONFIG_CPU_SH4 is not set -# CONFIG_LITTLE_ENDIAN is not set -CONFIG_MEMORY_START=0c000000 +# CONFIG_CPU_SH3 is not set +CONFIG_CPU_SH4=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_MEMORY_START=08000000 # # Loadable module support # # CONFIG_MODULES is not set -# CONFIG_SERIAL is not set -CONFIG_SH3SCI_SERIAL=y -CONFIG_SERIAL_CONSOLE=y # -# Floppy, IDE, and other block devices +# General setup # # CONFIG_NET is not set -CONFIG_SYSVIPC=y +# CONFIG_SYSVIPC is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_SYSCTL is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set # -# Networking options +# Character devices # -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set -# CONFIG_FILTER is not set -# CONFIG_UNIX is not set -# CONFIG_INET is not set +# CONFIG_SERIAL is not set +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SH_SCI_SERIAL is not set +CONFIG_SH_SCIF_SERIAL=y # -# +# Floppy, IDE, and other block devices # -# CONFIG_IPX is not set -# CONFIG_ATALK is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set # # Unix 98 PTY support @@ -66,8 +59,12 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_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_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -78,16 +75,15 @@ # CONFIG_UFS_FS is not set # -# Network File Systems -# - -# # Partition Types # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_SMD_DISKLABEL is not set -# CONFIG_SGI_DISKLABEL is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # @@ -99,3 +95,4 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL_WITH_GDB_STUB=y diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile --- v2.3.22/linux/arch/sh/kernel/Makefile Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/Makefile Mon Oct 18 11:16:13 1999 @@ -11,7 +11,7 @@ O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o irq_onchip.o \ - ptrace.o setup.o time.o sys_sh.o test-img.o semaphore.o + ptrace.o setup.o time.o sys_sh.o semaphore.o OX_OBJS := sh_ksyms.o MX_OBJS := diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.3.22/linux/arch/sh/kernel/entry.S Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/entry.S Mon Oct 18 11:16:13 1999 @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: entry.S,v 1.15 1999/10/17 01:32:52 gniibe Exp $ * * linux/arch/sh/entry.S * @@ -12,6 +12,7 @@ #include #include +#include ! NOTE: ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address @@ -28,18 +29,18 @@ * Stack layout in 'ret_from_syscall': * ptrace needs to have all regs on the stack. * if the order here is changed, it needs to be - * updated in process.c:copy_thread, signal.c:do_signal, - * ptrace.c and ptrace.h + * updated in ptrace.c and ptrace.h * - * syscall # + * syscall # + * ssr + * r15 = stack pointer * r0 * ... - * r15 + * r14 * gbr * mach * macl * pr - * ssr * spc * */ @@ -57,14 +58,23 @@ ENOSYS = 38 -TRA = 0xffffffd0 -EXPEVT = 0xffffffd4 -INTEVT = 0xffffffd8 +#if defined(__sh3__) +TRA = 0xffffffd0 +EXPEVT = 0xffffffd4 +INTEVT = 0xffffffd8 +MMU_TEA = 0xfffffffc ! TLB Exception Address Register +#elif defined(__SH4__) +TRA = 0xff000020 +EXPEVT = 0xff000024 +INTEVT = 0xff000028 +MMU_TEA = 0xff00000c ! TLB Exception Address Register +#endif /* Offsets to the stack */ SYSCALL_NR = 0 -R0 = 4 -R15 = 64 +SR = 4 +SP = 8 +R0 = 12 #define k0 r0 #define k1 r1 @@ -99,20 +109,19 @@ ! Although this could be written in assembly language (and it'd be faster), ! this first version depends *much* on C implementation. ! -MMU_TEA = 0xfffffffc ! TLB Exception Address Register -#define DO_FAULT(write) \ - mov #MMU_TEA,r0; \ - mov.l @r0,r6; \ - /* STI */ \ - mov.l 3f,r1; \ - stc sr,r0; \ - and r1,r0; \ - ldc r0,sr; \ - /* */ \ - mov r15,r4; \ - mov.l 2f,r0; \ - jmp @r0; \ +#define DO_FAULT(write) \ + mov.l 4f,r0; \ + mov.l @r0,r6; \ + /* STI */ \ + mov.l 3f,r1; \ + stc sr,r0; \ + and r1,r0; \ + ldc r0,sr; \ + /* */ \ + mov r15,r4; \ + mov.l 2f,r0; \ + jmp @r0; \ mov #write,r5; .balign 4 @@ -133,22 +142,65 @@ .balign 4 2: .long SYMBOL_NAME(do_page_fault) 3: .long 0xefffffff ! BL=0 +4: .long MMU_TEA +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + .balign 4 + /* Unwind the stack and jmp to the debug entry */ +debug: + add #4,r15 ! skip syscall number + ldc.l @r15+,ssr + mov.l @r15+,r10 ! original stack + mov.l @r15+,r0 + mov.l @r15+,r1 + mov.l @r15+,r2 + mov.l @r15+,r3 + mov.l @r15+,r4 + mov.l @r15+,r5 + mov.l @r15+,r6 + mov.l @r15+,r7 + stc sr,r14 + mov.l 8f,r9 ! BL =1, RB=1 + or r9,r14 + ldc r14,sr ! here, change the register bank + mov r10,k0 + mov.l @r15+,r8 + mov.l @r15+,r9 + mov.l @r15+,r10 + mov.l @r15+,r11 + mov.l @r15+,r12 + mov.l @r15+,r13 + mov.l @r15+,r14 + ldc.l @r15+,gbr + lds.l @r15+,mach + lds.l @r15+,macl + lds.l @r15+,pr + ldc.l @r15+,spc + mov k0,r15 + ! + mov.l 9f,k0 + jmp @k0 + nop + .balign 4 +8: .long 0x300000f0 +9: .long 0xa0000100 +#endif .balign 4 -error: mov #-1,r0 +error: ! STI mov.l 2f,r1 stc sr,r0 and r1,r0 ldc r0,sr ! - mov.l r0,@r15 ! syscall nr = -1 mov.l 1f,r1 + mov #-1,r0 jmp @r1 - nop + mov.l r0,@r15 ! syscall nr = -1 .balign 4 1: .long SYMBOL_NAME(do_exception_error) +2: .long 0xefffffff ! BL=0 reschedule: mova SYMBOL_NAME(ret_from_syscall),r0 @@ -159,12 +211,13 @@ 1: .long SYMBOL_NAME(schedule) badsys: mov #-ENOSYS,r0 - bra SYMBOL_NAME(ret_from_syscall) + rts ! go to ret_from_syscall.. mov.l r0,@(R0,r15) signal_return: ! We can reach here from an interrupt handler, ! so, we need to unblock interrupt. + /* STI */ mov.l 1f,r1 stc sr,r0 and r1,r0 @@ -185,15 +238,25 @@ ! ENTRY(ret_from_fork) bra SYMBOL_NAME(ret_from_syscall) - add #4,r15 ! pop down bogus r0 + add #4,r15 ! pop down bogus r0 (see switch_to MACRO) ! ! The immediate value of "trapa" indicates the number of arguments ! placed on the stack. ! +! Note that TRA register contains the value = Imm x 4. +! system_call: - mov #TRA,r2 + mov.l 1f,r2 mov.l @r2,r8 + ! +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + mov #0x20,r1 + extu.b r1,r1 + shll2 r1 + cmp/hs r1,r8 + bt debug +#endif ! STI mov.l 2f,r1 stc sr,r2 @@ -202,14 +265,15 @@ ! mov.l __n_sys,r1 cmp/ge r1,r0 - bt badsys + bt/s badsys + mov r0,r2 ! stc ksp,r1 ! mov.l __tsk_flags,r0 ! add r0,r1 ! mov.l @r1,r0 ! Is it trace? tst #PF_TRACESYS,r0 - bt 6f + bt 5f ! Trace system call mov #-ENOSYS,r1 mov.l r1,@(R0,r15) @@ -217,32 +281,36 @@ jsr @r1 nop mova 4f,r0 - bra 7f + bra 6f lds r0,pr ! -6: mova 1f,r0 +5: mova ret,r0 ! normal case lds r0,pr ! Build the stack frame if TRA > 0 -7: cmp/pl r8 + ! +6: mov r2,r3 + mov r8,r2 + cmp/pl r8 bf 9f - shll2 r8 ! x4 - mov #R15,r0 - mov.l @(r0,r15),r0 ! get original stack -8: add #-4,r8 - mov.l @(r0,r8),r1 + mov.l @(SP,r15),r0 ! get original stack +7: add #-4,r8 +8: mov.l @(r0,r8),r1 ! May cause address error exception.. mov.l r1,@-r15 cmp/pl r8 - bt 8b + bt 7b ! -9: mov.l @(SYSCALL_NR,r15),r0 +9: mov r3,r0 shll2 r0 ! x4 mov.l __sct,r1 add r1,r0 mov.l @r0,r1 jmp @r1 - nop + mov r2,r8 + + ! In case of trace .balign 4 -4: mov.l r0,@(R0,r15) ! save the return value +4: add r8,r15 ! pop off the arguments + mov.l r0,@(R0,r15) ! save the return value mov.l 3f,r1 mova SYMBOL_NAME(ret_from_syscall),r0 jmp @r1 @@ -250,11 +318,36 @@ .balign 4 3: .long SYMBOL_NAME(syscall_trace) 2: .long 0xefffffff ! BL=0 -1: mov.l r0,@(R0,r15) ! save the return value +1: .long TRA + + .section .fixup,"ax" +fixup_syscall_argerr: + rts + mov.l 1f,r0 +1: .long -22 ! -EINVAL +.previous + + .section __ex_table, "a" + .balign 4 + .long 8b,fixup_syscall_argerr +.previous + + +ENTRY(ret_from_irq) + mov.l @(SR,r15),r0 ! get original stack + shll r0 + shll r0 ! kernel space? + bt restore_all ! Yes, it's from kernel, go back soon + ! XXX: Is it better to run through bottom half? + ! In such a case, we should go "ret_from_syscall" instead + bra ret_with_reschedule + nop + +ret: add r8,r15 ! pop off the arguments + mov.l r0,@(R0,r15) ! save the return value /* fall through */ ENTRY(ret_from_syscall) -ENTRY(ret_from_irq) mov.l __bh_mask,r0 mov.l @r0,r1 mov.l __bh_active,r0 @@ -276,9 +369,10 @@ tst #0xff,r0 bf signal_return ! - .balign 4 restore_all: add #4,r15 ! skip syscall number + ldc.l @r15+,ssr + mov.l @r15+,r10 ! original stack mov.l @r15+,r0 mov.l @r15+,r1 mov.l @r15+,r2 @@ -291,6 +385,7 @@ mov.l __blrb_flags,r9 ! BL =1, RB=1 or r9,r14 ldc r14,sr ! here, change the register bank + mov r10,k0 mov.l @r15+,r8 mov.l @r15+,r9 mov.l @r15+,r10 @@ -298,12 +393,10 @@ mov.l @r15+,r12 mov.l @r15+,r13 mov.l @r15+,r14 - mov.l @r15+,k0 ldc.l @r15+,gbr lds.l @r15+,mach lds.l @r15+,macl lds.l @r15+,pr - ldc.l @r15+,ssr ldc.l @r15+,spc mov k0,r15 rte @@ -330,29 +423,32 @@ ! .balign 256,0,256 general_exception: - mov #EXPEVT,k2 + mov.l 1f,k2 mov.l 2f,k3 bra handle_exception mov.l @k2,k2 .balign 4 2: .long SYMBOL_NAME(ret_from_syscall) +1: .long EXPEVT ! ! .balign 1024,0,1024 tlb_miss: - mov #EXPEVT,k2 + mov.l 1f,k2 mov.l 3f,k3 bra handle_exception mov.l @k2,k2 ! .balign 512,0,512 interrupt: - mov #INTEVT,k2 + mov.l 2f,k2 mov.l 4f,k3 bra handle_exception mov.l @k2,k2 .balign 4 +1: .long EXPEVT +2: .long INTEVT 3: .long SYMBOL_NAME(ret_from_syscall) 4: .long SYMBOL_NAME(ret_from_irq) @@ -362,15 +458,13 @@ ! Using k0, k1 for scratch registers (r0_bank1, and r1_bank1), ! save all registers onto stack. ! - mov.l 2f,k1 stc ssr,k0 ! from kernel space? shll k0 ! Check MD bit (bit30) shll k0 bt/s 1f ! it's from kernel to kernel transition mov r15,k0 ! save original stack to k0 anyway mov kernel_sp,r15 ! change to kernel stack -1: stc.l spc,@-r15 ! save control registers - stc.l ssr,@-r15 +1: stc.l spc,@-r15 sts.l pr,@-r15 ! lds k3,pr ! Set the return address to pr @@ -378,9 +472,9 @@ sts.l macl,@-r15 sts.l mach,@-r15 stc.l gbr,@-r15 - mov.l k0,@-r15 ! save orignal stack, and general registers mov.l r14,@-r15 ! + mov.l 2f,k1 stc sr,r14 ! back to normal register bank, and and k1,r14 ! .. ldc r14,sr ! ...changed here. @@ -399,6 +493,8 @@ mov.l r2,@-r15 mov.l r1,@-r15 mov.l r0,@-r15 + stc.l r0_bank,@-r15 ! save orignal stack + stc.l ssr,@-r15 mov.l r0,@-r15 ! push r0 again (for syscall number) ! Then, dispatch to the handler, according to the excepiton code. stc k_ex_code,r1 @@ -413,10 +509,14 @@ 1: .long SYMBOL_NAME(exception_handling_table) 2: .long 0xdfffffff ! RB=0, BL=1 +none: + rts + nop + .data ENTRY(exception_handling_table) - .long 0 - .long 0 + .long none /* XXX: Avoid spurious interrupt */ + .long error .long tlb_miss_load .long tlb_miss_store .long initial_page_write @@ -424,13 +524,13 @@ .long tlb_protection_violation_store .long error ! address_error_load (filled by trap_init) .long error ! address_error_store (filled by trap_init) - .long 0 - .long 0 + .long error ! fpu_exception + .long error .long system_call ! Unconditional Trap .long error ! reserved_instruction (filled by trap_init) .long error ! illegal_slot_instruction (filled by trap_init) ENTRY(nmi_slot) - .long error ! Not implemented yet + .long none ! Not implemented yet ENTRY(user_break_point_trap) .long error ! Not implemented yet ENTRY(interrupt_table) @@ -450,7 +550,7 @@ .long SYMBOL_NAME(do_IRQ) ! 1100 .long SYMBOL_NAME(do_IRQ) ! 1101 .long SYMBOL_NAME(do_IRQ) ! 1110 - .long 0 + .long error ! Internal hardware .long SYMBOL_NAME(do_IRQ) ! TMU0 tuni0 .long SYMBOL_NAME(do_IRQ) ! TMU1 tuni1 @@ -468,14 +568,24 @@ .long SYMBOL_NAME(do_IRQ) ! rovi .long SYMBOL_NAME(do_IRQ) .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) ! Hitachi UDI + .long SYMBOL_NAME(do_IRQ) ! GPIO + .long SYMBOL_NAME(do_IRQ) ! DMAC dmte0 + .long SYMBOL_NAME(do_IRQ) ! dmte1 + .long SYMBOL_NAME(do_IRQ) ! dmte2 + .long SYMBOL_NAME(do_IRQ) ! dmte3 + .long SYMBOL_NAME(do_IRQ) ! dmae .long SYMBOL_NAME(do_IRQ) - .long SYMBOL_NAME(do_IRQ) - .long SYMBOL_NAME(do_IRQ) - .long SYMBOL_NAME(do_IRQ) - .long SYMBOL_NAME(do_IRQ) - .long SYMBOL_NAME(do_IRQ) - .long SYMBOL_NAME(do_IRQ) - .long SYMBOL_NAME(do_IRQ) + .long SYMBOL_NAME(do_IRQ) ! SCIF eri + .long SYMBOL_NAME(do_IRQ) ! rxi + .long SYMBOL_NAME(do_IRQ) ! bri + .long SYMBOL_NAME(do_IRQ) ! txi + .long error + .long error + .long error + .long error + .long error ! fpu + .long error ! fpu ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ @@ -568,7 +678,7 @@ .long SYMBOL_NAME(sys_swapon) .long SYMBOL_NAME(sys_reboot) .long SYMBOL_NAME(old_readdir) - .long SYMBOL_NAME(sys_ni_syscall) /* old_mmap */ /* 90 */ + .long SYMBOL_NAME(sys_mmap) /* 90 */ .long SYMBOL_NAME(sys_munmap) .long SYMBOL_NAME(sys_truncate) .long SYMBOL_NAME(sys_ftruncate) diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S --- v2.3.22/linux/arch/sh/kernel/head.S Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/head.S Mon Oct 18 11:16:13 1999 @@ -1,8 +1,8 @@ -/* $Id$ +/* $Id: head.S,v 1.6 1999/10/05 12:34:16 gniibe Exp $ * * arch/sh/kernel/head.S * - * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 1999 Niibe Yutaka & Kaz Kojima * * 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 @@ -10,60 +10,74 @@ * * Head.S contains the SH exception handlers and startup code. */ -#include -#include #include -#include -#include -#ifdef CONFIG_CPU_SH3 -/* Following values are assumed to be as small as immediate. */ -#define CCR 0xffffffec /* Address of Cache Control Register */ -#define CACHE_INIT 0x00000009 /* 8k-byte cache, flush, enable */ -#elif CONFIG_CPU_SH4 -/* Should fill here. */ -#endif + .section .empty_zero_page, "aw" +ENTRY(empty_zero_page) + .long 1 /* MOUNT_ROOT_RDONLY */ + .long 0 /* RAMDISK_FLAGS */ + .long 0x0200 /* ORIG_ROOT_DEV */ + .long 1 /* LOADER_TYPE */ + .long 0x88400000 /* INITRD_START */ + .long 0x00400000 /* INITRD_SIZE */ + .long 0x89000000 /* MEMORY_END */ + .long 0 + .text + .balign 4096,0,4096 +/* + * Condition at the entry of _stext: + * + * BSC has already been initialized. + * INTC may or may not be initialized. + * VBR may or may not be initialized. + * MMU may or may not be initialized. + * Cache may or may not be initialized. + * Hardware (including on-chip modules) may or may not be initialized. + * + * The register R4&R5 holds the address of the parameter block, which has + * command-line data, etc. + * + */ ENTRY(_stext) - ! Switch to register bank 0 - stc sr,r1 ! - mov.l 1f,r0 ! RB=0, BL=1 - and r1,r0 - ldc r0,sr - ! Enable cache -#ifdef CONFIG_CPU_SH3 - mov #CCR,r1 - mov.l @r1,r0 - cmp/eq #1,r0 ! If it's enabled already, don't flush it - bt/s 8f - mov #CACHE_INIT,r0 - mov.l r0,@r1 -#elif CONFIG_CPU_SH4 - ! Should fill here. +#if defined(__SH4__) + ! Initialize FPSCR + /* GCC (as of 2.95.1) assumes FPU with double precision mode. */ + mov.l 7f,r0 + lds r0,fpscr #endif -8: + ! Initialize Status Register + mov.l 1f,r0 ! MD=1, RB=0, BL=1 + ldc r0,sr ! mov.l 2f,r0 mov r0,r15 ! Set initial r15 (stack pointer) ldc r0,r4_bank ! and stack base + ! + ! Enable cache + mov.l 6f,r0 + jsr @r0 + nop ! Clear BSS area mov.l 3f,r1 + add #4,r1 mov.l 4f,r2 mov #0,r0 -9: mov.l r0,@r1 - cmp/hs r2,r1 - bf/s 9b - add #4,r1 +9: cmp/hs r2,r1 + bf/s 9b ! while (r1 < r2) + mov.l r0,@-r2 ! Start kernel mov.l 5f,r0 jmp @r0 nop .balign 4 -1: .long 0xdfffffff ! RB=0, BL=1 -2: .long SYMBOL_NAME(stack) -3: .long SYMBOL_NAME(__bss_start) -4: .long SYMBOL_NAME(_end) -5: .long SYMBOL_NAME(start_kernel) - -.data +1: .long 0x50000000 ! MD=1, RB=0, BL=1 +2: .long SYMBOL_NAME(stack) +3: .long SYMBOL_NAME(__bss_start) +4: .long SYMBOL_NAME(_end) +5: .long SYMBOL_NAME(start_kernel) +6: .long SYMBOL_NAME(cache_init) +#if defined(__SH4__) +7: .long 0x00080000 +#endif diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c --- v2.3.22/linux/arch/sh/kernel/irq.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/irq.c Mon Oct 18 11:16:13 1999 @@ -1,10 +1,11 @@ -/* +/* $Id: irq.c,v 1.4 1999/10/11 13:12:14 gniibe Exp $ + * * linux/arch/sh/kernel/irq.c * * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar * * - * SuperH version: Copyright (C) 1999 Niibe Yutaka + * SuperH version: Copyright (C) 1999 Niibe Yutaka */ /* @@ -48,7 +49,7 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; /* * Special irq handlers. @@ -57,6 +58,37 @@ void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } /* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ + printk("unexpected IRQ trap at vector %02x\n", irq); +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +/* * Generic, controller-independent functions: */ @@ -203,6 +235,8 @@ struct irqaction * action; unsigned int status; + regs.syscall_nr = -1; /* It's not system call */ + /* Get IRQ number */ asm volatile("stc r2_bank,%0\n\t" "shlr2 %0\n\t" @@ -257,7 +291,7 @@ for (;;) { handle_IRQ_event(irq, ®s, action); spin_lock(&irq_controller_lock); - + if (!(desc->status & IRQ_PENDING)) break; desc->status &= ~IRQ_PENDING; @@ -265,7 +299,7 @@ } desc->status &= ~IRQ_INPROGRESS; if (!(desc->status & IRQ_DISABLED)){ - irq_desc[irq].handler->end(irq); + irq_desc[irq].handler->end(irq); } spin_unlock(&irq_controller_lock); @@ -334,16 +368,22 @@ /* Found it - now remove it from the list of entries */ *pp = action->next; - if (irq_desc[irq].action) - break; - irq_desc[irq].status |= IRQ_DISABLED; - irq_desc[irq].handler->shutdown(irq); - break; + if (!irq_desc[irq].action) { + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->shutdown(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + while (irq_desc[irq].status & IRQ_INPROGRESS) + barrier(); + kfree(action); + return; } printk("Trying to free free IRQ%d\n",irq); - break; + spin_unlock_irqrestore(&irq_controller_lock,flags); + return; } - spin_unlock_irqrestore(&irq_controller_lock,flags); } /* diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c --- v2.3.22/linux/arch/sh/kernel/irq_onchip.c Tue Sep 7 12:14:06 1999 +++ linux/arch/sh/kernel/irq_onchip.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: irq_onchip.c,v 1.3 1999/10/11 13:12:19 gniibe Exp $ + * * linux/arch/sh/kernel/irq_onchip.c * * Copyright (C) 1999 Niibe Yutaka @@ -31,32 +32,6 @@ #include - -/* - * SH (non-)specific no controller code - */ - -static void enable_none(unsigned int irq) { } -static unsigned int startup_none(unsigned int irq) { return 0; } -static void disable_none(unsigned int irq) { } -static void ack_none(unsigned int irq) -{ -} - -/* startup is the same as "enable", shutdown is same as "disable" */ -#define shutdown_none disable_none -#define end_none enable_none - -struct hw_interrupt_type no_irq_type = { - "none", - startup_none, - shutdown_none, - enable_none, - disable_none, - ack_none, - end_none -}; - struct ipr_data { int offset; int priority; @@ -104,22 +79,25 @@ * IPRC 15-12 11-8 7-4 3-0 * */ +#if defined(__sh3__) #define INTC_IPR 0xfffffee2UL /* Word access */ +#define INTC_SIZE 0x2 +#elif defined(__SH4__) +#define INTC_IPR 0xffd00004UL /* Word access */ +#define INTC_SIZE 0x4 +#endif void disable_onChip_irq(unsigned int irq) { /* Set priority in IPR to 0 */ int offset = ipr_data[irq-TIMER_IRQ].offset; - unsigned long intc_ipr_address = INTC_IPR + offset/16; + unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE); unsigned short mask = 0xffff ^ (0xf << (offset%16)); - unsigned long __dummy; + unsigned long val; - asm volatile("mov.w @%1,%0\n\t" - "and %2,%0\n\t" - "mov.w %0,@%1" - : "=&z" (__dummy) - : "r" (intc_ipr_address), "r" (mask) - : "memory" ); + val = ctrl_inw(intc_ipr_address); + val &= mask; + ctrl_outw(val, intc_ipr_address); } static void enable_onChip_irq(unsigned int irq) @@ -127,16 +105,13 @@ /* Set priority in IPR back to original value */ int offset = ipr_data[irq-TIMER_IRQ].offset; int priority = ipr_data[irq-TIMER_IRQ].priority; - unsigned long intc_ipr_address = INTC_IPR + offset/16; + unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE); unsigned short value = (priority << (offset%16)); - unsigned long __dummy; + unsigned long val; - asm volatile("mov.w @%1,%0\n\t" - "or %2,%0\n\t" - "mov.w %0,@%1" - : "=&z" (__dummy) - : "r" (intc_ipr_address), "r" (value) - : "memory" ); + val = ctrl_inw(intc_ipr_address); + val |= value; + ctrl_outw(val, intc_ipr_address); } void make_onChip_irq(unsigned int irq) @@ -149,13 +124,11 @@ static void mask_and_ack_onChip(unsigned int irq) { disable_onChip_irq(irq); - sti(); } static void end_onChip_irq(unsigned int irq) { enable_onChip_irq(irq); - cli(); } void __init init_IRQ(void) diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.3.22/linux/arch/sh/kernel/process.c Tue Sep 7 12:14:06 1999 +++ linux/arch/sh/kernel/process.c Mon Oct 18 11:16:13 1999 @@ -1,9 +1,10 @@ -/* +/* $Id: process.c,v 1.7 1999/09/23 00:05:41 gniibe Exp $ + * * linux/arch/sh/kernel/process.c * * Copyright (C) 1995 Linus Torvalds * - * SuperH version: Copyright (C) 1999 Niibe Yutaka + * SuperH version: Copyright (C) 1999 Niibe Yutaka & Kaz Kojima */ /* @@ -41,6 +42,10 @@ #include +#if defined(__SH4__) +struct task_struct *last_task_used_math = NULL; +#endif + static int hlt_counter=0; #define HARD_IDLE_TIMEOUT (HZ / 3) @@ -92,22 +97,21 @@ void show_regs(struct pt_regs * regs) { printk("\n"); - printk("PC: [<%08lx>]", regs->pc); - printk(" SP: %08lx", regs->u_regs[UREG_SP]); - printk(" SR: %08lx\n", regs->sr); - printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", - regs->u_regs[0],regs->u_regs[1], - regs->u_regs[2],regs->u_regs[3]); - printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", - regs->u_regs[4],regs->u_regs[5], - regs->u_regs[6],regs->u_regs[7]); - printk("R8 : %08lx R9 : %08lx R10: %08lx R11: %08lx\n", - regs->u_regs[8],regs->u_regs[9], - regs->u_regs[10],regs->u_regs[11]); - printk("R12: %08lx R13: %08lx R14: %08lx\n", - regs->u_regs[12],regs->u_regs[13], - regs->u_regs[14]); - printk("MACH: %08lx MACL: %08lx GBR: %08lx PR: %08lx", + printk("PC : %08lx SP : %08lx SR : %08lx TEA : %08lx\n", + regs->pc, regs->sp, regs->sr, ctrl_inl(MMU_TEA)); + printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", + regs->regs[0],regs->regs[1], + regs->regs[2],regs->regs[3]); + printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", + regs->regs[4],regs->regs[5], + regs->regs[6],regs->regs[7]); + printk("R8 : %08lx R9 : %08lx R10 : %08lx R11 : %08lx\n", + regs->regs[8],regs->regs[9], + regs->regs[10],regs->regs[11]); + printk("R12 : %08lx R13 : %08lx R14 : %08lx\n", + regs->regs[12],regs->regs[13], + regs->regs[14]); + printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n", regs->mach, regs->macl, regs->gbr, regs->pr); } @@ -163,13 +167,35 @@ */ void exit_thread(void) { +#if defined(__sh3__) /* nothing to do ... */ +#elif defined(__SH4__) +#if 0 /* for the time being... */ + /* Forget lazy fpu state */ + if (last_task_used_math == current) { + set_status_register (SR_FD, 0); + write_system_register (fpscr, FPSCR_PR); + last_task_used_math = NULL; + } +#endif +#endif } void flush_thread(void) { +#if defined(__sh3__) /* do nothing */ /* Possibly, set clear debug registers */ +#elif defined(__SH4__) +#if 0 /* for the time being... */ + /* Forget lazy fpu state */ + if (last_task_used_math == current) { + set_status_register (SR_FD, 0); + write_system_register (fpscr, FPSCR_PR); + last_task_used_math = NULL; + } +#endif +#endif } void release_thread(struct task_struct *dead_task) @@ -180,6 +206,15 @@ /* Fill in the fpu structure for a core dump.. */ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) { +#if defined(__SH4__) +#if 0 /* for the time being... */ + /* We store the FPU info in the task->thread area. */ + if (! (regs->sr & SR_FD)) { + memcpy (r, ¤t->thread.fpu, sizeof (*r)); + return 1; + } +#endif +#endif return 0; /* Task didn't use the fpu at all. */ } @@ -191,14 +226,26 @@ struct pt_regs *childregs; childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1; - *childregs = *regs; + +#if defined(__SH4__) +#if 0 /* for the time being... */ + if (last_task_used_math == current) { + set_status_register (SR_FD, 0); + sh4_save_fp (p); + } + /* New tasks loose permission to use the fpu. This accelerates context + switching for most programs since they don't use the fpu. */ + p->thread.sr = (read_control_register (sr) &~ SR_MD) | SR_FD; + childregs->sr |= SR_FD; +#endif +#endif if (user_mode(regs)) { - childregs->u_regs[UREG_SP] = usp; + childregs->sp = usp; } else { - childregs->u_regs[UREG_SP] = (unsigned long)p+2*PAGE_SIZE; + childregs->sp = (unsigned long)p+2*PAGE_SIZE; } - childregs->u_regs[0] = 0; /* Set return value for child */ + childregs->regs[0] = 0; /* Set return value for child */ p->thread.sp = (unsigned long) childregs; p->thread.pc = (unsigned long) ret_from_fork; @@ -215,18 +262,22 @@ { /* changed the size calculations - should hopefully work better. lbt */ dump->magic = CMAGIC; - dump->start_code = 0; - dump->start_stack = regs->u_regs[UREG_SP] & ~(PAGE_SIZE - 1); - dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; - dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; - dump->u_dsize -= dump->u_tsize; - dump->u_ssize = 0; + dump->start_code = current->mm->start_code; + dump->start_data = current->mm->start_data; + dump->start_stack = regs->sp & ~(PAGE_SIZE - 1); + dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT; + dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT; + dump->u_ssize = (current->mm->start_stack - dump->start_stack + + PAGE_SIZE - 1) >> PAGE_SHIFT; /* Debug registers will come here. */ - if (dump->start_stack < TASK_SIZE) - dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; - dump->regs = *regs; + +#if 0 /* defined(__SH4__) */ + /* FPU */ + memcpy (&dump->regs[EF_SIZE/4], ¤t->thread.fpu, + sizeof (current->thread.fpu)); +#endif } /* @@ -248,7 +299,7 @@ unsigned long r6, unsigned long r7, struct pt_regs regs) { - return do_fork(SIGCHLD, regs.u_regs[UREG_SP], ®s); + return do_fork(SIGCHLD, regs.sp, ®s); } asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, @@ -256,7 +307,7 @@ struct pt_regs regs) { if (!newsp) - newsp = regs.u_regs[UREG_SP]; + newsp = regs.sp; return do_fork(clone_flags, newsp, ®s); } @@ -274,8 +325,7 @@ unsigned long r6, unsigned long r7, struct pt_regs regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - regs.u_regs[UREG_SP], ®s); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, ®s); } /* diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c --- v2.3.22/linux/arch/sh/kernel/setup.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/setup.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: setup.c,v 1.4 1999/10/17 02:49:24 gniibe Exp $ + * * linux/arch/sh/kernel/setup.c * * Copyright (C) 1999 Niibe Yutaka @@ -29,6 +30,7 @@ #endif #include #include +#include #include #include #include @@ -38,8 +40,7 @@ * Machine setup.. */ -struct sh_cpuinfo boot_cpu_data = { 0, 0, 0, 0, }; -extern int _text, _etext, _edata, _end, _stext, __bss_start; +struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 0, 0, }; #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ @@ -48,13 +49,31 @@ #endif extern int root_mountflags; +extern int _text, _etext, _edata, _end; + +/* + * This is set up by the setup-routine at boot-time + */ +#define PARAM ((unsigned char *)empty_zero_page) + +#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000)) +#define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004)) +#define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008)) +#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c)) +#define INITRD_START (*(unsigned long *) (PARAM+0x010)) +#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014)) +#define MEMORY_END (*(unsigned long *) (PARAM+0x018)) +/* ... */ +#define COMMAND_LINE ((char *) (PARAM+0x100)) +#define COMMAND_LINE_SIZE 256 + +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 -#define COMMAND_LINE_SIZE 1024 static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; -extern unsigned char *root_fs_image; - struct resource standard_io_resources[] = { { "dma1", 0x00, 0x1f }, { "pic1", 0x20, 0x3f }, @@ -68,7 +87,6 @@ #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) - /* System RAM - interrupted by the 640kB-1M hole */ #define code_resource (ram_resources[3]) #define data_resource (ram_resources[4]) @@ -87,17 +105,26 @@ { "Video ROM", 0xc0000, 0xc7fff } }; - void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { - *cmdline_p = command_line; - *memory_start_p = (unsigned long) &_end; - *memory_end_p = 0x8c400000; /* For my board. */ - ram_resources[1].end = *memory_end_p-1; + unsigned long memory_start, memory_end; + + ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); +#endif + if (!MOUNT_ROOT_RDONLY) + root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long)&_stext; + memory_start = (unsigned long) &_end; + memory_end = MEMORY_END; + + init_mm.start_code = (unsigned long)&_text; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; @@ -107,51 +134,25 @@ data_resource.start = virt_to_bus(&_etext); data_resource.end = virt_to_bus(&_edata)-1; - ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); - - initrd_below_start_ok = 1; - initrd_start = (long)&root_fs_image; - initrd_end = (long)&__bss_start; - mount_initrd = 1; - - -#if 0 - /* Request the standard RAM and ROM resources - they eat up PCI memory space */ - request_resource(&iomem_resource, ram_resources+0); - request_resource(&iomem_resource, ram_resources+1); - request_resource(&iomem_resource, ram_resources+2); - request_resource(ram_resources+1, &code_resource); - request_resource(ram_resources+1, &data_resource); -#endif - -#if 0 - for (i = 0; i < STANDARD_IO_RESOURCES; i++) - request_resource(&ioport_resource, standard_io_resources+i); -#endif + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; -#if 0 - rd_image_start = (long)root_fs_image; - rd_prompt = 0; - rd_doload = 1; -#endif + memcpy(command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + command_line[COMMAND_LINE_SIZE-1] = '\0'; -#if 0 - ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); + /* Not support "mem=XXX[kKmM]" command line option. */ + *cmdline_p = command_line; -#ifdef CONFIG_BLK_DEV_RAM - rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; - rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); - rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); -#endif + memory_end &= PAGE_MASK; + ram_resources[1].end = memory_end-1; - if (!MOUNT_ROOT_RDONLY) - root_mountflags &= ~MS_RDONLY; -#endif + *memory_start_p = memory_start; + *memory_end_p = memory_end; #ifdef CONFIG_BLK_DEV_INITRD -#if 0 if (LOADER_TYPE) { - initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0; + initrd_start = INITRD_START ? INITRD_START : 0; initrd_end = initrd_start+INITRD_SIZE; if (initrd_end > memory_end) { printk("initrd extends beyond end of memory " @@ -162,6 +163,29 @@ } #endif +#if 0 + /* + * Request the standard RAM and ROM resources - + * they eat up PCI memory space + */ + request_resource(&iomem_resource, ram_resources+0); + request_resource(&iomem_resource, ram_resources+1); + request_resource(&iomem_resource, ram_resources+2); + request_resource(ram_resources+1, &code_resource); + request_resource(ram_resources+1, &data_resource); + probe_roms(); + + /* request I/O space for devices used on all i[345]86 PCs */ + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, standard_io_resources+i); +#endif + +#ifdef CONFIG_VT +#if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif #endif } @@ -173,12 +197,12 @@ { char *p = buffer; -#ifdef CONFIG_CPU_SH3 - p += sprintf(p,"cpu family\t: SH3\n" +#if defined(__sh3__) + p += sprintf(p,"cpu family\t: SH-3\n" "cache size\t: 8K-byte\n"); -#elif CONFIG_CPU_SH4 - p += sprintf(p,"cpu family\t: SH4\n" - "cache size\t: ??K-byte\n"); +#elif defined(__SH4__) + p += sprintf(p,"cpu family\t: SH-4\n" + "cache size\t: 8K-byte/16K-byte\n"); #endif p += sprintf(p, "bogomips\t: %lu.%02lu\n\n", (loops_per_sec+2500)/500000, diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c --- v2.3.22/linux/arch/sh/kernel/signal.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/signal.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: signal.c,v 1.10 1999/09/27 23:25:44 gniibe Exp $ + * * linux/arch/sh/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -9,8 +10,6 @@ * */ -#include - #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include #define DEBUG_SIG 0 @@ -50,7 +50,7 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - regs.u_regs[0] = -EINTR; + regs.regs[0] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -80,7 +80,7 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - regs.u_regs[0] = -EINTR; + regs.regs[0] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -126,7 +126,7 @@ unsigned long r6, unsigned long r7, struct pt_regs regs) { - return do_sigaltstack(uss, uoss, regs.u_regs[UREG_SP]); + return do_sigaltstack(uss, uoss, regs.sp); } @@ -137,7 +137,7 @@ struct sigframe { struct sigcontext sc; - /* FPU should come here: SH-3 has no FPU */ + /* FPU data should come here: SH-3 has no FPU */ unsigned long extramask[_NSIG_WORDS-1]; char retcode[4]; }; @@ -158,22 +158,22 @@ { unsigned int err = 0; -#define COPY(x) err |= __get_user(regs->x, &sc->x) - COPY(u_regs[1]); - COPY(u_regs[2]); COPY(u_regs[3]); - COPY(u_regs[4]); COPY(u_regs[5]); - COPY(u_regs[6]); COPY(u_regs[7]); - COPY(u_regs[8]); COPY(u_regs[9]); - COPY(u_regs[10]); COPY(u_regs[11]); - COPY(u_regs[12]); COPY(u_regs[13]); - COPY(u_regs[14]); COPY(u_regs[15]); - COPY(gbr); COPY(mach); - COPY(macl); COPY(pr); - COPY(sr); COPY(pc); +#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) + COPY(regs[1]); + COPY(regs[2]); COPY(regs[3]); + COPY(regs[4]); COPY(regs[5]); + COPY(regs[6]); COPY(regs[7]); + COPY(regs[8]); COPY(regs[9]); + COPY(regs[10]); COPY(regs[11]); + COPY(regs[12]); COPY(regs[13]); + COPY(regs[14]); COPY(sp); + COPY(gbr); COPY(mach); + COPY(macl); COPY(pr); + COPY(sr); COPY(pc); #undef COPY regs->syscall_nr = -1; /* disable syscall checks */ - err |= __get_user(*r0_p, &sc->u_regs[0]); + err |= __get_user(*r0_p, &sc->sc_regs[0]); return err; } @@ -182,7 +182,7 @@ unsigned long r6, unsigned long r7, struct pt_regs regs) { - struct sigframe *frame = (struct sigframe *)regs.u_regs[UREG_SP]; + struct sigframe *frame = (struct sigframe *)regs.sp; sigset_t set; int r0; @@ -213,7 +213,7 @@ unsigned long r6, unsigned long r7, struct pt_regs regs) { - struct rt_sigframe *frame = (struct rt_sigframe *)regs.u_regs[UREG_SP]; + struct rt_sigframe *frame = (struct rt_sigframe *)regs.sp; sigset_t set; stack_t st; int r0; @@ -236,7 +236,7 @@ goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs.u_regs[UREG_SP]); + do_sigaltstack(&st, NULL, regs.sp); return r0; @@ -255,18 +255,18 @@ { int err = 0; -#define COPY(x) err |= __put_user(regs->x, &sc->x) - COPY(u_regs[0]); COPY(u_regs[1]); - COPY(u_regs[2]); COPY(u_regs[3]); - COPY(u_regs[4]); COPY(u_regs[5]); - COPY(u_regs[6]); COPY(u_regs[7]); - COPY(u_regs[8]); COPY(u_regs[9]); - COPY(u_regs[10]); COPY(u_regs[11]); - COPY(u_regs[12]); COPY(u_regs[13]); - COPY(u_regs[14]); COPY(u_regs[15]); - COPY(gbr); COPY(mach); - COPY(macl); COPY(pr); - COPY(sr); COPY(pc); +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(regs[0]); COPY(regs[1]); + COPY(regs[2]); COPY(regs[3]); + COPY(regs[4]); COPY(regs[5]); + COPY(regs[6]); COPY(regs[7]); + COPY(regs[8]); COPY(regs[9]); + COPY(regs[10]); COPY(regs[11]); + COPY(regs[12]); COPY(regs[13]); + COPY(regs[14]); COPY(sp); + COPY(gbr); COPY(mach); + COPY(macl); COPY(pr); + COPY(sr); COPY(pc); #undef COPY /* non-iBCS2 extensions.. */ @@ -294,7 +294,7 @@ int err = 0; int signal; - frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame)); + frame = get_sigframe(ka, regs->sp, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; @@ -318,8 +318,8 @@ regs->pr = (unsigned long) ka->sa.sa_restorer; } else { /* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */ -#ifdef CONFIG_LITTLE_ENDIAN - unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8); +#ifdef __LITTLE_ENDIAN__ + unsigned long code = 0xc300e000 | (__NR_sigreturn); #else unsigned long code = 0xe000c300 | (__NR_sigreturn << 16); #endif @@ -332,8 +332,8 @@ goto give_sigsegv; /* Set up registers for signal handler */ - regs->u_regs[UREG_SP] = (unsigned long) frame; - regs->u_regs[4] = signal; /* Arg for signal handler */ + regs->sp = (unsigned long) frame; + regs->regs[4] = signal; /* Arg for signal handler */ regs->pc = (unsigned long) ka->sa.sa_handler; set_fs(USER_DS); @@ -343,6 +343,7 @@ current->comm, current->pid, frame, regs->pc, regs->pr); #endif + flush_icache_range(regs->pr, regs->pr+4); return; give_sigsegv: @@ -358,7 +359,7 @@ int err = 0; int signal; - frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame)); + frame = get_sigframe(ka, regs->sp, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; @@ -376,9 +377,9 @@ /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->u_regs[UREG_SP]), - &frame->uc.uc_stack.ss_flags); + err |= __put_user((void *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); @@ -390,8 +391,8 @@ regs->pr = (unsigned long) ka->sa.sa_restorer; } else { /* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */ -#ifdef CONFIG_LITTLE_ENDIAN - unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8); +#ifdef __LITTLE_ENDIAN__ + unsigned long code = 0xc300e000 | (__NR_sigreturn); #else unsigned long code = 0xe000c300 | (__NR_sigreturn << 16); #endif @@ -404,8 +405,8 @@ goto give_sigsegv; /* Set up registers for signal handler */ - regs->u_regs[UREG_SP] = (unsigned long) frame; - regs->u_regs[4] = signal; /* Arg for signal handler */ + regs->sp = (unsigned long) frame; + regs->regs[4] = signal; /* Arg for signal handler */ regs->pc = (unsigned long) ka->sa.sa_handler; set_fs(USER_DS); @@ -415,6 +416,7 @@ current->comm, current->pid, frame, regs->pc, regs->pr); #endif + flush_icache_range(regs->pr, regs->pr+4); return; give_sigsegv: @@ -434,19 +436,19 @@ /* Are we from a system call? */ if (regs->syscall_nr >= 0) { /* If so, check system call restarting.. */ - switch (regs->u_regs[0]) { + switch (regs->regs[0]) { case -ERESTARTNOHAND: - regs->u_regs[0] = -EINTR; + regs->regs[0] = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->u_regs[0] = -EINTR; + regs->regs[0] = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: - regs->u_regs[0] = regs->syscall_nr; + regs->regs[0] = regs->syscall_nr; regs->pc -= 2; } } @@ -577,7 +579,6 @@ /* NOTREACHED */ } } - /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); return 1; @@ -586,10 +587,10 @@ /* Did we come from a system call? */ if (regs->syscall_nr >= 0) { /* Restart the system call - no handlers present */ - if (regs->u_regs[0] == -ERESTARTNOHAND || - regs->u_regs[0] == -ERESTARTSYS || - regs->u_regs[0] == -ERESTARTNOINTR) { - regs->u_regs[0] = regs->syscall_nr; + if (regs->regs[0] == -ERESTARTNOHAND || + regs->regs[0] == -ERESTARTSYS || + regs->regs[0] == -ERESTARTNOINTR) { + regs->regs[0] = regs->syscall_nr; regs->pc -= 2; } } diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c --- v2.3.22/linux/arch/sh/kernel/sys_sh.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/sys_sh.c Mon Oct 18 11:16:13 1999 @@ -1,9 +1,11 @@ /* - * linux/arch/i386/kernel/sys_i386.c + * linux/arch/sh/kernel/sys_sh.c * * This file contains various random system calls that - * have a non-standard calling sequence on the Linux/i386 + * have a non-standard calling sequence on the Linux/SuperH * platform. + * + * Taken from i386 version. */ #include @@ -41,66 +43,32 @@ return error; } -/* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory - * block for parameter passing.. - */ - -struct mmap_arg_struct { - unsigned long addr; - unsigned long len; - unsigned long prot; - unsigned long flags; - unsigned long fd; - unsigned long offset; -}; - -asmlinkage int old_mmap(struct mmap_arg_struct *arg) +asmlinkage unsigned long +sys_mmap(int fd, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flags, unsigned long off) { int error = -EFAULT; - struct file * file = NULL; - struct mmap_arg_struct a; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; + struct file *file = NULL; down(¤t->mm->mmap_sem); lock_kernel(); - if (!(a.flags & MAP_ANONYMOUS)) { + if (!(flags & MAP_ANONYMOUS)) { error = -EBADF; - file = fget(a.fd); + file = fget(fd); if (!file) goto out; } - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); + error = do_mmap(file, addr, len, prot, flags, off); if (file) fput(file); out: unlock_kernel(); up(¤t->mm->mmap_sem); - return error; -} - -extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); - -struct sel_arg_struct { - unsigned long n; - fd_set *inp, *outp, *exp; - struct timeval *tvp; -}; - -asmlinkage int old_select(struct sel_arg_struct *arg) -{ - struct sel_arg_struct a; - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - /* sys_select() does the appropriate kernel locking */ - return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); + return error; } /* @@ -198,9 +166,6 @@ return -EINVAL; } -/* - * Old cruft - */ asmlinkage int sys_uname(struct old_utsname * name) { int err; @@ -210,35 +175,6 @@ err=copy_to_user(name, &system_utsname, sizeof (*name)); up(&uts_sem); return err?-EFAULT:0; -} - -asmlinkage int sys_olduname(struct oldold_utsname * name) -{ - int error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down(&uts_sem); - - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); - - up(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; } asmlinkage int sys_pause(void) diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/test-img.c linux/arch/sh/kernel/test-img.c --- v2.3.22/linux/arch/sh/kernel/test-img.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/test-img.c Wed Dec 31 16:00:00 1969 @@ -1,69 +0,0 @@ -unsigned char root_fs_image[] -__attribute__((__section__(".data.disk_image"))) -= { -0x1f,0x8b,0x08,0x08,0x5d,0xd5,0xc7,0x37,0x00,0x03,0x72,0x2e,0x62,0x69,0x6e,0x00, -0xed,0xdc,0x3f,0x6c,0x1b,0x55,0x1c,0xc0,0xf1,0xdf,0xf9,0xdc,0x04,0x27,0x69,0xb1, -0x93,0x14,0x10,0x48,0x91,0xd3,0x02,0x4d,0x8a,0xb8,0xd4,0x21,0x8a,0x09,0x02,0x02, -0xb5,0x4a,0xab,0x52,0x65,0x69,0x11,0x03,0x42,0xc2,0xb1,0x8f,0xc4,0x92,0xe3,0x03, -0x9f,0x8d,0xca,0x14,0xd8,0x88,0x2a,0xa6,0x0e,0x88,0xa9,0x20,0xb1,0x87,0x8d,0xa5, -0x5b,0x86,0xcc,0x90,0x78,0x77,0xd4,0x60,0x75,0xa9,0x40,0xe2,0xdf,0xd0,0x42,0x78, -0x77,0xef,0x9c,0x38,0x24,0x72,0x49,0x20,0xc9,0x70,0xdf,0x8f,0xf2,0xf3,0xd9,0x77, -0xbf,0xf3,0xbb,0x67,0xbf,0xdf,0xf9,0x4f,0xf4,0x2c,0x02,0x20,0xac,0xe2,0x2a,0x5e, -0x53,0x61,0xaa,0x18,0x0e,0xd6,0x19,0xad,0x09,0x49,0x1d,0x5e,0x5e,0x7d,0x75,0x39, -0xfd,0x6c,0x6d,0x39,0x6d,0x48,0xbf,0x5c,0xfd,0xc9,0xf0,0xf3,0x56,0xd5,0x3a,0x99, -0xba,0xf7,0xd0,0x76,0x8a,0x53,0x5f,0xc4,0xdf,0xcd,0x24,0x56,0x6e,0x9e,0x59,0xb9, -0x30,0x3e,0x73,0x3b,0xf7,0x3f,0x76,0x01,0xc0,0x3e,0x79,0x75,0x1f,0x55,0x71,0x4c, -0x74,0xfd,0x47,0x8f,0xf6,0x70,0x00,0x1c,0xa2,0x8d,0x8d,0x49,0x6f,0xf1,0xc9,0x06, -0x00,0x00,0x08,0x8d,0xe6,0xfb,0x00,0xef,0x73,0x7c,0x33,0x0e,0xf3,0xfd,0xc7,0xbd, -0xd7,0xc5,0xff,0xd0,0x31,0x5a,0x5b,0x4e,0xf7,0x05,0xa1,0xb7,0x1c,0x93,0x48,0x4b, -0x5e,0xe7,0x61,0x1e,0x14,0x80,0x50,0xf0,0xcf,0x3f,0xe7,0x76,0x3b,0xff,0x45,0xe4, -0x89,0x96,0xbc,0x47,0x54,0xc4,0x54,0x74,0xa9,0xe8,0x56,0xd1,0xa3,0xe2,0xb8,0x8a, -0x13,0x2a,0x1e,0x15,0xfd,0xfd,0x68,0x42,0x45,0xaf,0x8a,0xbe,0xbd,0xb6,0xaf,0xce, -0x7f,0x7f,0xaa,0x76,0xef,0x07,0xd1,0x6c,0xbf,0xf5,0xfc,0xd7,0xbf,0xf7,0xae,0x6d, -0x32,0xda,0x6c,0x6b,0xb6,0x7f,0x56,0x9d,0x77,0x4f,0x05,0xb1,0x5b,0xfb,0x27,0x0f, -0xa8,0xfd,0x6f,0x06,0xf5,0xf2,0xfe,0x8e,0xfe,0xff,0x63,0xaf,0xff,0xf0,0xc5,0x54, -0xdb,0xfe,0x7f,0x7a,0xeb,0xf2,0x15,0x53,0xe4,0xe6,0xaa,0x7e,0xed,0x19,0x0b,0xda, -0xbf,0x75,0xd9,0xd8,0xd6,0xff,0xc7,0xf6,0xdf,0x7c,0xdb,0xf6,0x37,0xbe,0xd6,0x63, -0x6a,0xe7,0xe3,0xbf,0x7d,0x2f,0xcb,0x1a,0x29,0x16,0x4a,0xd5,0xeb,0xe5,0x7d,0x7c, -0x73,0xde,0xae,0x7d,0xaf,0x8f,0x3d,0x2a,0xc3,0xda,0xbc,0x1e,0x51,0x6d,0xe9,0x31, -0xde,0xaf,0x8e,0xac,0xe8,0xb8,0x95,0xe7,0xde,0x77,0xaa,0xa5,0xbc,0x1e,0xf3,0x3d, -0x62,0x4a,0xde,0xfe,0xc8,0x1f,0xfb,0x3d,0xea,0x49,0x71,0xa7,0x0b,0x25,0x6f,0xfc, -0xdf,0x36,0x3b,0x65,0xdf,0x07,0x08,0xe0,0x48,0xe8,0xd7,0xb2,0xad,0xfa,0xff,0xd5, -0xd4,0xf5,0x0f,0x20,0x24,0xf8,0xa7,0x1f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f, -0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f, -0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f, -0x10,0x4a,0x7a,0x4e,0xcf,0xce,0xf9,0x3f,0xde,0xbc,0xb6,0xbb,0x66,0xa7,0xe4,0x9c, -0x92,0xeb,0x14,0xed,0xa3,0x3d,0x48,0x00,0x07,0x42,0xcf,0xe3,0xdb,0x59,0xff,0xde, -0x7c,0xd6,0xbb,0x66,0x54,0x0a,0xa5,0x42,0xe5,0x68,0x8f,0x10,0xc0,0x41,0x99,0xbf, -0x70,0xe5,0x0d,0x23,0xd2,0x32,0x43,0x38,0x22,0x67,0xc5,0x9f,0x32,0x1c,0xff,0x4a, -0x2d,0xc7,0xd4,0xd5,0x75,0x7f,0xfd,0x98,0x24,0xd5,0xb6,0x21,0x89,0xf9,0x53,0xe1, -0x83,0x1d,0xe2,0x41,0x18,0xd3,0x3a,0xfc,0x9f,0x11,0x34,0x74,0x78,0xb7,0x07,0x83, -0xd8,0xd4,0xe1,0x27,0x67,0xd6,0x8d,0x46,0x7c,0xa4,0x51,0x8f,0xd6,0x3a,0x4a,0xbf, -0x2c,0xc9,0x7b,0xa7,0x3f,0x33,0x16,0xcc,0x5a,0xb4,0x61,0xd6,0xa3,0x4b,0xe2,0xdc, -0x91,0xee,0xd2,0xef,0x22,0x89,0xa7,0x55,0xbc,0x38,0xd2,0x98,0xff,0xb9,0x1e,0xf1, -0xb2,0xa6,0xcd,0xf3,0x89,0x85,0xce,0x75,0xa3,0xf6,0x78,0xe3,0xa4,0x97,0x27,0xb1, -0xc5,0xbf,0x24,0x76,0x6a,0x68,0xa1,0x7b,0xa5,0x6f,0x4d,0x3e,0x34,0x52,0xe9,0x1b, -0x0f,0xf2,0xa7,0x7f,0x34,0xea,0xcf,0x2c,0xc9,0xe2,0x1f,0x6b,0x6a,0xfb,0xf7,0x27, -0xd6,0x0d,0xab,0xd7,0xbe,0xb3,0x26,0x03,0x89,0x86,0x0c,0xf4,0xd6,0x33,0x03,0x7d, -0x4b,0xf2,0x43,0xd7,0xba,0x21,0xb1,0x5a,0xac,0x71,0xdc,0xbb,0x17,0x2f,0x4f,0xed, -0x7b,0xe6,0xc6,0x83,0xc5,0xdf,0xbc,0xf5,0xaa,0xcd,0x97,0xe5,0x9d,0xcf,0xe7,0x55, -0xbf,0x2a,0xf2,0xdd,0x93,0x1b,0xea,0xf6,0xb5,0x6b,0xb3,0x05,0x37,0xa9,0xfe,0xae, -0x56,0x3f,0xb0,0xcb,0x97,0x06,0xbd,0xe9,0xda,0x32,0x39,0xd9,0x25,0xae,0x33,0x67, -0x57,0x66,0x0b,0xa5,0x99,0x64,0xb5,0x54,0x75,0xab,0xd9,0xa2,0x65,0x59,0xde,0xc6, -0x4b,0x76,0xb1,0xe8,0x24,0xdf,0x76,0xca,0xc5,0xbc,0x97,0x7c,0x31,0x93,0x79,0x29, -0x39,0x74,0x71,0xea,0xad,0xe1,0xa4,0x3d,0x93,0x73,0x9f,0x1f,0xb5,0x26,0x52,0xd6, -0xf8,0x78,0x32,0x35,0x31,0x31,0x71,0xee,0x85,0xd4,0x58,0x72,0xc8,0x5f,0x9d,0xb2, -0x52,0xd6,0x68,0xb2,0x6c,0x17,0xed,0xac,0x6b,0x0f,0x8b,0x58,0xee,0xc7,0x73,0x95, -0xec,0xb4,0x5a,0x56,0xca,0x7a,0x39,0xdb,0xbc,0x56,0xb1,0xaf,0x57,0xc4,0x2a,0x3b, -0xf9,0x6c,0x25,0x2b,0x96,0xbe,0xcc,0x55,0x9c,0xb2,0xab,0x6e,0xe8,0xc5,0xb4,0xab, -0x2e,0x72,0xce,0xdc,0x9c,0x5d,0xda,0xd3,0xe9,0xfb,0xa9,0xe0,0xf9,0xeb,0xf0,0xfb, -0x2f,0xe2,0xc5,0xb7,0x2d,0xdb,0x9b,0x9f,0x14,0x07,0x83,0xbc,0x88,0x7e,0x9e,0x0c, -0x15,0xf2,0xea,0x2e,0x79,0xc3,0x41,0x9e,0xa9,0xc7,0x81,0xd1,0x3a,0x16,0x64,0x6b, -0x1c,0xc9,0xc8,0xd6,0xb8,0x69,0x9b,0x37,0xfe,0x2f,0xf3,0x5e,0x11,0xfd,0x93,0x0d, -0x0f,0x6b,0xf7,0xbc,0x6c,0x9b,0x1e,0xef,0xe7,0xa5,0x77,0xc9,0x4b,0xe8,0xfb,0xda, -0x5c,0xfd,0xa5,0xba,0x78,0x73,0x97,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x87,0xe8,0x6f,0x20,0x01,0xec,0xc5,0x00,0x00,0x01,0x00, -}; diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.3.22/linux/arch/sh/kernel/time.c Tue Sep 7 12:14:06 1999 +++ linux/arch/sh/kernel/time.c Mon Oct 18 11:16:13 1999 @@ -1,12 +1,15 @@ -/* +/* $Id: time.c,v 1.2 1999/10/11 13:12:02 gniibe Exp $ + * * linux/arch/sh/kernel/time.c * - * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka * * Some code taken from i386 version. * Copyright (C) 1991, 1992, 1995 Linus Torvalds */ +#include + #include #include #include @@ -28,6 +31,11 @@ #include #include +#define TMU_TOCR_INIT 0x00 +#define TMU0_TCR_INIT 0x0020 +#define TMU_TSTR_INIT 1 + +#if defined(__sh3__) #define TMU_TOCR 0xfffffe90 /* Byte access */ #define TMU_TSTR 0xfffffe92 /* Byte access */ @@ -35,13 +43,63 @@ #define TMU0_TCNT 0xfffffe98 /* Long access */ #define TMU0_TCR 0xfffffe9c /* Word access */ -#define TMU_TOCR_INIT 0x00 -#define TMU0_TCR_INIT 0x0020 -#define TMU_TSTR_INIT 1 - -#define CLOCK_MHZ (60/4) #define INTERVAL 37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? */ +/* SH-3 RTC */ +#define R64CNT 0xfffffec0 +#define RSECCNT 0xfffffec2 +#define RMINCNT 0xfffffec4 +#define RHRCNT 0xfffffec6 +#define RWKCNT 0xfffffec8 +#define RDAYCNT 0xfffffeca +#define RMONCNT 0xfffffecc +#define RYRCNT 0xfffffece +#define RSECAR 0xfffffed0 +#define RMINAR 0xfffffed2 +#define RHRAR 0xfffffed4 +#define RWKAR 0xfffffed6 +#define RDAYAR 0xfffffed8 +#define RMONAR 0xfffffeda +#define RCR1 0xfffffedc +#define RCR2 0xfffffede + +#elif defined(__SH4__) +#define TMU_TOCR 0xffd80000 /* Byte access */ +#define TMU_TSTR 0xffd80004 /* Byte access */ + +#define TMU0_TCOR 0xffd80008 /* Long access */ +#define TMU0_TCNT 0xffd8000c /* Long access */ +#define TMU0_TCR 0xffd80010 /* Word access */ + +#define INTERVAL 83333 + +/* SH-4 RTC */ +#define R64CNT 0xffc80000 +#define RSECCNT 0xffc80004 +#define RMINCNT 0xffc80008 +#define RHRCNT 0xffc8000c +#define RWKCNT 0xffc80010 +#define RDAYCNT 0xffc80014 +#define RMONCNT 0xffc80018 +#define RYRCNT 0xffc8001c /* 16bit */ +#define RSECAR 0xffc80020 +#define RMINAR 0xffc80024 +#define RHRAR 0xffc80028 +#define RWKAR 0xffc8002c +#define RDAYAR 0xffc80030 +#define RMONAR 0xffc80034 +#define RCR1 0xffc80038 +#define RCR2 0xffc8003c +#endif + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif + extern rwlock_t xtime_lock; #define TICK_SIZE tick @@ -82,14 +140,48 @@ write_unlock_irq(&xtime_lock); } -/* - */ static int set_rtc_time(unsigned long nowtime) { -/* XXX should be implemented XXXXXXXXXX */ - int retval = -1; +#ifdef CONFIG_SH_CPU_RTC + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + + ctrl_outb(2, RCR2); /* reset pre-scaler & stop RTC */ + + cmos_minutes = ctrl_inb(RMINCNT); + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + ctrl_outb(real_seconds, RSECCNT); + ctrl_outb(real_minutes, RMINCNT); + } else { + printk(KERN_WARNING + "set_rtc_time: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + ctrl_outb(2, RCR2); /* start RTC */ return retval; +#else + /* XXX should support other clock devices? */ + return -1; +#endif } /* last time the RTC clock got updated */ @@ -131,14 +223,12 @@ */ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - unsigned long __dummy; + unsigned long timer_status; /* Clear UNF bit */ - asm volatile("mov.w %1,%0\n\t" - "and %2,%0\n\t" - "mov.w %0,%1" - : "=&z" (__dummy) - : "m" (__m(TMU0_TCR)), "r" (~0x100)); + timer_status = ctrl_inw(TMU0_TCR); + timer_status &= ~0x100; + ctrl_outw(timer_status, TMU0_TCR); /* * Here we are in the timer irq handler. We just have irqs locally @@ -187,16 +277,67 @@ static unsigned long get_rtc_time(void) { -/* XXX not implemented yet */ +#ifdef CONFIG_SH_CPU_RTC + unsigned int sec, min, hr, wk, day, mon, yr, yr100; + + again: + ctrl_outb(1, RCR1); /* clear CF bit */ + do { + sec = ctrl_inb(RSECCNT); + min = ctrl_inb(RMINCNT); + hr = ctrl_inb(RHRCNT); + wk = ctrl_inb(RWKCNT); + day = ctrl_inb(RDAYCNT); + mon = ctrl_inb(RMONCNT); +#if defined(__SH4__) + yr = ctrl_inw(RYRCNT); + yr100 = (yr >> 8); + yr &= 0xff; +#else + yr = ctrl_inb(RYRCNT); + yr100 = (yr == 0x99) ? 0x19 : 0x20; +#endif + } while ((ctrl_inb(RCR1) & 0x80) != 0); + + BCD_TO_BIN(yr100); + BCD_TO_BIN(yr); + BCD_TO_BIN(mon); + BCD_TO_BIN(day); + BCD_TO_BIN(hr); + BCD_TO_BIN(min); + BCD_TO_BIN(sec); + + if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 || + hr > 23 || min > 59 || sec > 59) { + printk(KERN_ERR + "SH RTC: invalid value, resetting to 1 Jan 2000\n"); + ctrl_outb(2, RCR2); /* reset, stop */ + ctrl_outb(0, RSECCNT); + ctrl_outb(0, RMINCNT); + ctrl_outb(0, RHRCNT); + ctrl_outb(6, RWKCNT); + ctrl_outb(1, RDAYCNT); + ctrl_outb(1, RMONCNT); +#if defined(__SH4__) + ctrl_outw(0x2000, RYRCNT); +#else + ctrl_outb(0, RYRCNT); +#endif + ctrl_outb(1, RCR2); /* start */ + goto again; + } + + return mktime(yr100 * 100 + yr, mon, day, hr, min, sec); +#else + /* XXX should support other clock devices? */ return 0; +#endif } static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; void __init time_init(void) { - unsigned long __dummy; - xtime.tv_sec = get_rtc_time(); xtime.tv_usec = 0; @@ -204,19 +345,12 @@ setup_irq(TIMER_IRQ, &irq0); /* Start TMU0 */ - asm volatile("mov %1,%0\n\t" - "mov.b %0,%2 ! external clock input\n\t" - "mov %3,%0\n\t" - "mov.w %0,%4 ! enable timer0 interrupt\n\t" - "mov.l %5,%6\n\t" - "mov.l %5,%7\n\t" - "mov %8,%0\n\t" - "mov.b %0,%9" - : "=&z" (__dummy) - : "i" (TMU_TOCR_INIT), "m" (__m(TMU_TOCR)), - "i" (TMU0_TCR_INIT), "m" (__m(TMU0_TCR)), - "r" (INTERVAL), "m" (__m(TMU0_TCOR)), "m" (__m(TMU0_TCNT)), - "i" (TMU_TSTR_INIT), "m" (__m(TMU_TSTR))); + ctrl_outb(TMU_TOCR_INIT,TMU_TOCR); + ctrl_outw(TMU0_TCR_INIT,TMU0_TCR); + ctrl_outl(INTERVAL,TMU0_TCOR); + ctrl_outl(INTERVAL,TMU0_TCNT); + ctrl_outb(TMU_TSTR_INIT,TMU_TSTR); + #if 0 /* Start RTC */ asm volatile(""); diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c --- v2.3.22/linux/arch/sh/kernel/traps.c Fri Sep 10 23:57:28 1999 +++ linux/arch/sh/kernel/traps.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: traps.c,v 1.3 1999/09/21 14:37:19 gniibe Exp $ + * * linux/arch/sh/traps.c * * SuperH version: Copyright (C) 1999 Niibe Yutaka @@ -56,10 +57,6 @@ #define VMALLOC_OFFSET (8*1024*1024) #define MODULE_RANGE (8*1024*1024) -static void show_registers(struct pt_regs *regs) -{/* Not implemented yet. */ -} - spinlock_t die_lock; void die(const char * str, struct pt_regs * regs, long err) @@ -67,7 +64,7 @@ console_verbose(); spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); - show_registers(regs); + show_regs(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/Makefile linux/arch/sh/lib/Makefile --- v2.3.22/linux/arch/sh/lib/Makefile Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/lib/Makefile Mon Oct 18 11:16:13 1999 @@ -6,9 +6,7 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o L_TARGET = lib.a -# L_OBJS = checksum.o old-checksum.o semaphore.o delay.o \ -# usercopy.o getuser.o putuser.o -L_OBJS = delay.o memcpy.o memset.o memmove.o csum_partial_copy.o \ - wordcopy.o checksum.o # usercopy.o getuser.o putuser.o +L_OBJS = delay.o memcpy.o memset.o memmove.o old-checksum.o \ + checksum.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/checksum.S linux/arch/sh/lib/checksum.S --- v2.3.22/linux/arch/sh/lib/checksum.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/lib/checksum.S Mon Oct 18 11:16:13 1999 @@ -0,0 +1,318 @@ +/* $Id: checksum.S,v 1.1 1999/09/18 16:56:53 gniibe Exp $ + * + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Pentium Pro/II routines: + * Alexander Kjeldaas + * Finn Arne Gangstad + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception + * handling. + * Andi Kleen, add zeroing on error + * converted to pure assembler + * + * SuperH version: Copyright (C) 1999 Niibe Yutaka + * + * 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. + */ + +#include +#include + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +/* + * unsigned int csum_partial(const unsigned char *buf, int len, + * unsigned int sum); + */ + +.text +ENTRY(csum_partial) + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ + mov r5,r1 + mov r4,r0 + tst #2,r0 ! Check alignment. + bt 2f ! Jump if alignment is ok. + ! + add #-2,r5 ! Alignment uses up two bytes. + cmp/pz r5 ! + bt/s 1f ! Jump if we had at least two bytes. + clrt + bra 6f + add #2,r5 ! r5 was < 2. Deal with it. +1: + mov.w @r4+,r0 + extu.w r0,r0 + addc r0,r6 + bf 2f + add #1,r6 +2: + mov #-5,r0 + shld r0,r5 + tst r5,r5 + bt/s 4f ! if it's =0, go to 4f + clrt +3: + mov.l @r4+,r0 + addc r0,r6 + mov.l @r4+,r0 + addc r0,r6 + mov.l @r4+,r0 + addc r0,r6 + mov.l @r4+,r0 + addc r0,r6 + mov.l @r4+,r0 + addc r0,r6 + mov.l @r4+,r0 + addc r0,r6 + mov.l @r4+,r0 + addc r0,r6 + mov.l @r4+,r0 + addc r0,r6 + movt r0 + dt r5 + bf/s 3b + cmp/eq #1,r0 + mov #0,r0 + addc r0,r6 +4: + mov r1,r5 + mov #0x1c,r0 + and r0,r5 + tst r5,r5 + bt/s 6f + clrt + shlr2 r5 +5: + mov.l @r4+,r0 + addc r0,r6 + movt r0 + dt r5 + bf/s 5b + cmp/eq #1,r0 + mov #0,r0 + addc r0,r6 +6: + mov r1,r5 + mov #3,r0 + and r0,r5 + tst r5,r5 + bt 9f ! if it's =0 go to 9f + mov #2,r1 + cmp/hs r1,r5 + bf 7f + mov.w @r4+,r0 + extu.w r0,r0 + cmp/eq r1,r5 + bt/s 8f + clrt + shll16 r0 + addc r0,r6 +7: + mov.b @r4+,r0 + extu.b r0,r0 +8: + addc r0,r6 + mov #0,r0 + addc r0,r6 +9: + rts + mov r6,r0 + +/* +unsigned int csum_partial_copy_generic (const char *src, char *dst, int len, + int sum, int *src_err_ptr, int *dst_err_ptr) + */ + +/* + * Copy from ds while checksumming, otherwise like csum_partial + * + * The macros SRC and DST specify the type of access for the instruction. + * thus we can call a custom exception handler for all access types. + * + * FIXME: could someone double-check whether I haven't mixed up some SRC and + * DST definitions? It's damn hard to trigger all cases. I hope I got + * them all but there's no guarantee. + */ + +#define SRC(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6001f ; \ + .previous + +#define DST(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6002f ; \ + .previous + +ENTRY(csum_partial_copy_generic) + mov.l r5,@-r15 + mov.l r6,@-r15 + + mov #2,r0 + tst r0,r5 ! Check alignment. + bt 2f ! Jump if alignment is ok. + add #-2,r6 ! Alignment uses up two bytes. + cmp/pz r6 ! Jump if we had at least two bytes. + bt/s 1f + clrt + bra 4f + add #2,r6 ! ecx was < 2. Deal with it. +SRC(1: mov.w @r4+,r0 ) +DST( mov.w r0,@r5 ) + add #2,r5 + extu.w r0,r0 + addc r0,r7 + mov #0,r0 + addc r0,r7 +2: + mov r6,r2 + mov #-5,r0 + shld r0,r6 + tst r6,r6 + bf/s 2f + clrt +SRC(1: mov.l @r4+,r0 ) +SRC( mov.l @r4+,r1 ) + addc r0,r7 +DST( mov.l r0,@r5 ) + add #4,r5 + addc r1,r7 +DST( mov.l r1,@r5 ) + add #4,r5 + +SRC( mov.l @r4+,r0 ) +SRC( mov.l @r4+,r1 ) + addc r0,r7 +DST( mov.l r0,@r5 ) + add #4,r5 + addc r1,r7 +DST( mov.l r1,@r5 ) + add #4,r5 + +SRC( mov.l @r4+,r0 ) +SRC( mov.l @r4+,r1 ) + addc r0,r7 +DST( mov.l r0,@r5 ) + add #4,r5 + addc r1,r7 +DST( mov.l r1,@r5 ) + add #4,r5 + +SRC( mov.l @r4+,r0 ) +SRC( mov.l @r4+,r1 ) + addc r0,r7 +DST( mov.l r0,@r5 ) + add #4,r5 + addc r1,r7 +DST( mov.l r1,@r5 ) + add #4,r5 + movt r0 + dt r6 + bf/s 1b + cmp/eq #1,r0 + mov #0,r0 + addc r0,r7 + +2: mov r2,r6 + mov #0x1c,r0 + and r0,r6 + cmp/pl r6 + bf/s 4f + clrt + shlr2 r6 +SRC(3: mov.l @r4+,r0 ) + addc r0,r7 +DST( mov.l r0,@r5 ) + add #4,r5 + movt r0 + dt r6 + bf/s 3b + cmp/eq #1,r0 + mov #0,r0 + addc r0,r7 +4: mov r2,r6 + mov #3,r0 + and r0,r6 + cmp/pl r6 + bf 7f + mov #2,r1 + cmp/hs r1,r6 + bf 5f +SRC( mov.w @r4+,r0 ) +DST( mov.w r0,@r5 ) + extu.w r0,r0 + add #2,r5 + cmp/eq r1,r6 + bt/s 6f + clrt + shll16 r0 + addc r0,r7 +SRC(5: mov.b @r4+,r0 ) +DST( mov.b r0,@r5 ) + extu.b r0,r0 +6: addc r0,r7 + mov #0,r0 + addc r0,r7 +7: +5000: + +# Exception handler: +.section .fixup, "ax" + +6001: + mov.l @(8,r15),r0 ! src_err_ptr + mov #-EFAULT,r1 + mov.l r1,@r0 + + ! zero the complete destination - computing the rest + ! is too much work + mov.l @(4,r15),r5 ! dst + mov.l @r15,r6 ! len + mov #0,r7 +1: mov.b r7,@r5 + dt r6 + bf/s 1b + add #1,r5 + mov.l 8000f,r0 + jmp @r0 + nop + .balign 4 +8000: .long 5000b + +6002: + mov.l @(12,r15),r0 ! dst_err_ptr + mov #-EFAULT,r1 + mov.l r1,@r0 + mov.l 8001f,r0 + jmp @r0 + nop + .balign 4 +8001: .long 5000b + +.previous + add #8,r15 + rts + mov r7,r0 diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/checksum.c linux/arch/sh/lib/checksum.c --- v2.3.22/linux/arch/sh/lib/checksum.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/lib/checksum.c Wed Dec 31 16:00:00 1969 @@ -1,170 +0,0 @@ -/* - * Taken from: - * arch/alpha/lib/checksum.c - * - * This file contains network checksum routines that are better done - * in an architecture-specific manner due to speed.. - */ - -#include - -#include - -static inline unsigned short from64to16(unsigned long long x) -{ - /* add up 32-bit words for 33 bits */ - x = (x & 0xffffffff) + (x >> 32); - /* add up 16-bit and 17-bit words for 17+c bits */ - x = (x & 0xffff) + (x >> 16); - /* add up 16-bit and 2-bit for 16+c bit */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); - return x; -} - -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented. - */ -unsigned short int csum_tcpudp_magic(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) -{ - return ~from64to16(saddr + daddr + sum + - ((unsigned long) ntohs(len) << 16) + - ((unsigned long) proto << 8)); -} - -unsigned int csum_tcpudp_nofold(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) -{ - unsigned long long result; - - result = (saddr + daddr + sum + - ((unsigned long) ntohs(len) << 16) + - ((unsigned long) proto << 8)); - - /* Fold down to 32-bits so we don't loose in the typedef-less - network stack. */ - /* 64 to 33 */ - result = (result & 0xffffffff) + (result >> 32); - /* 33 to 32 */ - result = (result & 0xffffffff) + (result >> 32); - return result; -} - -/* - * Do a 64-bit checksum on an arbitrary memory area.. - * - * This isn't a great routine, but it's not _horrible_ either. The - * inner loop could be unrolled a bit further, and there are better - * ways to do the carry, but this is reasonable. - */ -static inline unsigned long do_csum(const unsigned char * buff, int len) -{ - int odd, count; - unsigned long long result = 0; - - if (len <= 0) - goto out; - odd = 1 & (unsigned long) buff; - if (odd) { - result = *buff << 8; - len--; - buff++; - } - count = len >> 1; /* nr of 16-bit words.. */ - if (count) { - if (2 & (unsigned long) buff) { - result += *(unsigned short *) buff; - count--; - len -= 2; - buff += 2; - } - count >>= 1; /* nr of 32-bit words.. */ - if (count) { - if (4 & (unsigned long) buff) { - result += *(unsigned int *) buff; - count--; - len -= 4; - buff += 4; - } - count >>= 1; /* nr of 64-bit words.. */ - if (count) { - unsigned long carry = 0; - do { - unsigned long w = *(unsigned long *) buff; - count--; - buff += 8; - result += carry; - result += w; - carry = (w > result); - } while (count); - result += carry; - result = (result & 0xffffffff) + (result >> 32); - } - if (len & 4) { - result += *(unsigned int *) buff; - buff += 4; - } - } - if (len & 2) { - result += *(unsigned short *) buff; - buff += 2; - } - } - if (len & 1) - result += *buff; - result = from64to16(result); - if (odd) - result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); -out: - return result; -} - -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - */ -unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) -{ - return ~do_csum(iph,ihl*4); -} - -/* - * computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit) - * - * returns a 32-bit number suitable for feeding into itself - * or csum_tcpudp_magic - * - * this function must be called with even lengths, except - * for the last fragment, which may be odd - * - * it's best to have buff aligned on a 32-bit boundary - */ -unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) -{ - unsigned long long result = do_csum(buff, len); - - /* add in old sum, and carry.. */ - result += sum; - /* 32+c bits -> 32 bits */ - result = (result & 0xffffffff) + (result >> 32); - return result; -} - -/* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c - */ -unsigned short ip_compute_csum(unsigned char * buff, int len) -{ - return ~from64to16(do_csum(buff,len)); -} diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/csum_partial_copy.c linux/arch/sh/lib/csum_partial_copy.c --- v2.3.22/linux/arch/sh/lib/csum_partial_copy.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/lib/csum_partial_copy.c Wed Dec 31 16:00:00 1969 @@ -1,75 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * MIPS specific IP/TCP/UDP checksumming routines - * - * Authors: Ralf Baechle, - * Lots of code moved from tcp.c and ip.c; see those files - * for more names. - * - * 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. - * - * $Id: csum_partial_copy.c,v 1.2 1998/09/16 13:29:32 ralf Exp $ - */ -#include -#include -#include -#include -#include - -/* - * copy while checksumming, otherwise like csum_partial - */ -unsigned int csum_partial_copy(const char *src, char *dst, - int len, unsigned int sum) -{ - /* - * It's 2:30 am and I don't feel like doing it real ... - * This is lots slower than the real thing (tm) - */ - sum = csum_partial(src, len, sum); - memcpy(dst, src, len); - - return sum; -} - -/* - * Copy from userspace and compute checksum. If we catch an exception - * then zero the rest of the buffer. - */ -unsigned int csum_partial_copy_from_user (const char *src, char *dst, - int len, unsigned int sum, - int *err_ptr) -{ - int missing; - - missing = copy_from_user(dst, src, len); - if (missing) { - memset(dst + len - missing, 0, missing); - *err_ptr = -EFAULT; - } - - return csum_partial(dst, len, sum); -} - -/* - * Copy to userspace and compute checksum. - */ -unsigned int csum_partial_copy_to_user (const char *src, char *dst, - int len, unsigned int sum, - int *err_ptr) -{ - sum = csum_partial(src, len, sum); - - if (copy_to_user(dst, src, len)) { - *err_ptr = -EFAULT; - return sum; - } - - return sum; -} diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/memcpy.S linux/arch/sh/lib/memcpy.S --- v2.3.22/linux/arch/sh/lib/memcpy.S Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/lib/memcpy.S Mon Oct 18 11:16:13 1999 @@ -1,131 +1,227 @@ -! Taken from newlib-1.8.0 +/* $Id: memcpy.S,v 1.3 1999/09/28 11:32:48 gniibe Exp $ + * + * "memcpy" implementation of SuperH + * + * Copyright (C) 1999 Niibe Yutaka + * + */ -! -! Fast SH memcpy -! -! by Toshiyasu Morita (tm@netcom.com) -! hacked by J"orn Rernnecke (amylaar@cygnus.co.uk) ("o for o-umlaut) -! -! Entry: r4: destination pointer -! r5: source pointer -! r6: byte count -! -! Exit: r0: destination pointer -! r1-r7: trashed -! -! Notes: Usually one wants to do small reads and write a longword, but -! unfortunately it is difficult in some cases to concatanate bytes -! into a longword on the SH, so this does a longword read and small -! writes. -! -! This implementation makes two assumptions about how it is called: -! -! 1.: If the byte count is nonzero, the address of the last byte to be -! copied is unsigned greater than the address of the first byte to -! be copied. This could be easily swapped for a signed comparison, -! but the algorithm used needs some comparison. -! -! 2.: When there are two or three bytes in the last word of an 11-or-bore -! bytes memory chunk to b copied, the rest of the word can be read -! without size effects. -! This could be easily changed by increasing the minumum size of -! a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2, -! however, this would cost a few extra cyles on average. -! +/* + * void *memcpy(void *dst, const void *src, size_t n); + * No overlap between the memory of DST and of SRC are assumed. + */ #include ENTRY(memcpy) - ! Big endian version copies with decreasing addresses. - mov r4,r0 - add r6,r0 - sub r4,r5 - mov #11,r1 - cmp/hs r1,r6 - bf/s L_small + tst r6,r6 + bt/s 9f ! if n=0, do nothing + mov r4,r0 + sub r4,r5 ! From here, r5 has the distance to r0 + add r6,r0 ! From here, r0 points the end of copying point + mov #12,r1 + cmp/gt r6,r1 + bt/s 7f ! if it's too small, copy a byte at once add #-1,r5 - mov r5,r3 - add r0,r3 - shlr r3 - bt/s L_even - mov r4,r7 - mov.b @(r0,r5),r2 - add #-1,r3 - mov.b r2,@-r0 -L_even: - tst #1,r0 - add #-1,r5 - bf/s L_odddst - add #8,r7 - tst #2,r0 - bt L_al4dst - add #-1,r3 - mov.w @(r0,r5),r1 - mov.w r1,@-r0 -L_al4dst: - shlr r3 - bt L_al4both - mov.w @(r0,r5),r1 - swap.w r1,r1 - add #4,r7 - add #-4,r5 - .align 2 -L_2l_loop: - mov.l @(r0,r5),r2 - xtrct r2,r1 - mov.l r1,@-r0 - cmp/hs r7,r0 - mov.l @(r0,r5),r1 - xtrct r1,r2 - mov.l r2,@-r0 - bt L_2l_loop - bra L_cleanup - add #5,r5 + add #1,r5 + ! From here, r6 is free + ! + ! r4 --> [ ... ] DST [ ... ] SRC + ! [ ... ] [ ... ] + ! : : + ! r0 --> [ ... ] r0+r5 --> [ ... ] + ! + ! + mov r5,r1 + mov #3,r2 + and r2,r1 + shll2 r1 + mov r0,r3 ! Save the value on R0 to R3 + mova jmptable,r0 + add r1,r0 + mov.l @r0,r1 + jmp @r1 + mov r3,r0 ! and back to R0 + .balign 4 +jmptable: + .long case0 + .long case1 + .long case2 + .long case3 - nop ! avoid nop in executed code. -L_al4both: - add #-2,r5 - .align 2 -L_al4both_loop: - mov.l @(r0,r5),r1 - cmp/hs r7,r0 - bt/s L_al4both_loop + ! copy a byte at once +7: mov r4,r2 + add #1,r2 +8: + cmp/hi r2,r0 + mov.b @(r0,r5),r1 + bt/s 8b ! while (r0>r2) + mov.b r1,@-r0 +9: + rts + nop + +case0: + ! + ! GHIJ KLMN OPQR --> GHIJ KLMN OPQR + ! + ! First, align to long word boundary + mov r0,r3 + and r2,r3 + tst r3,r3 + bt/s 2f + add #-4,r5 + add #3,r5 +1: dt r3 + mov.b @(r0,r5),r1 + bf/s 1b + mov.b r1,@-r0 + ! + add #-3,r5 +2: ! Second, copy a long word at once + mov r4,r2 + add #7,r2 +3: mov.l @(r0,r5),r1 + cmp/hi r2,r0 + bt/s 3b mov.l r1,@-r0 - bra L_cleanup + ! + ! Third, copy a byte at once, if necessary + cmp/eq r4,r0 + bt/s 9b add #3,r5 + bra 8b + add #-6,r2 - nop ! avoid nop in executed code. -L_odddst: - shlr r3 - bt L_al4src - mov.w @(r0,r5),r1 - mov.b r1,@-r0 - shlr8 r1 - mov.b r1,@-r0 -L_al4src: - add #-2,r5 - .align 2 -L_odd_loop: - mov.l @(r0,r5),r2 - cmp/hs r7,r0 - mov.b r2,@-r0 - shlr8 r2 - mov.w r2,@-r0 - shlr16 r2 - mov.b r2,@-r0 - bt L_odd_loop - - add #3,r5 -L_cleanup: -L_small: +case1: + ! + ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR. + ! + ! First, align to long word boundary + mov r0,r3 + and r2,r3 + tst r3,r3 + bt/s 2f + add #-1,r5 +1: dt r3 + mov.b @(r0,r5),r1 + bf/s 1b + mov.b r1,@-r0 + ! +2: ! Second, read a long word and write a long word at once + mov.l @(r0,r5),r1 + add #-4,r5 + mov r4,r2 + add #7,r2 + ! +#ifdef __LITTLE_ENDIAN__ +3: mov r1,r3 ! RQPO + shll16 r3 + shll8 r3 ! Oxxx + mov.l @(r0,r5),r1 ! NMLK + mov r1,r6 + shlr8 r6 ! xNML + or r6,r3 ! ONML + cmp/hi r2,r0 + bt/s 3b + mov.l r3,@-r0 +#else +3: mov r1,r3 ! OPQR + shlr16 r3 + shlr8 r3 ! xxxO + mov.l @(r0,r5),r1 ! KLMN + mov r1,r6 + shll8 r6 ! LMNx + or r6,r3 ! LMNO + cmp/hi r2,r0 + bt/s 3b + mov.l r3,@-r0 +#endif + ! + ! Third, copy a byte at once, if necessary cmp/eq r4,r0 - bt L_ready - add #1,r4 - .align 2 -L_cleanup_loop: - mov.b @(r0,r5),r2 + bt/s 9b + add #4,r5 + bra 8b + add #-6,r2 + +case2: + ! + ! GHIJ KLMN OPQR --> ..GH IJKL MNOP QR.. + ! + ! First, align to word boundary + tst #1,r0 + bt/s 2f + add #-1,r5 + mov.b @(r0,r5),r1 + mov.b r1,@-r0 + ! +2: ! Second, read a word and write a word at once + add #-1,r5 + mov r4,r2 + add #3,r2 + ! +3: mov.w @(r0,r5),r1 + cmp/hi r2,r0 + bt/s 3b + mov.w r1,@-r0 + ! + ! Third, copy a byte at once, if necessary cmp/eq r4,r0 - mov.b r2,@-r0 - bf L_cleanup_loop -L_ready: + bt/s 9b + add #1,r5 + mov.b @(r0,r5),r1 rts - nop + mov.b r1,@-r0 + +case3: + ! + ! GHIJ KLMN OPQR --> .GHI JKLM NOPQ R... + ! + ! First, align to long word boundary + mov r0,r3 + and r2,r3 + tst r3,r3 + bt/s 2f + add #-1,r5 +1: dt r3 + mov.b @(r0,r5),r1 + bf/s 1b + mov.b r1,@-r0 + ! +2: ! Second, read a long word and write a long word at once + add #-2,r5 + mov.l @(r0,r5),r1 + add #-4,r5 + mov r4,r2 + add #7,r2 + ! +#ifdef __LITTLE_ENDIAN__ +3: mov r1,r3 ! RQPO + shll8 r3 ! QPOx + mov.l @(r0,r5),r1 ! NMLK + mov r1,r6 + shlr16 r6 + shlr8 r6 ! xxxN + or r6,r3 ! QPON + cmp/hi r2,r0 + bt/s 3b + mov.l r3,@-r0 +#else +3: mov r1,r3 ! OPQR + shlr8 r3 ! xOPQ + mov.l @(r0,r5),r1 ! KLMN + mov r1,r6 + shll16 r6 + shll8 r6 ! Nxxx + or r6,r3 ! NOPQ + cmp/hi r2,r0 + bt/s 3b + mov.l r3,@-r0 +#endif + ! + ! Third, copy a byte at once, if necessary + cmp/eq r4,r0 + bt/s 9b + add #6,r5 + bra 8b + add #-6,r2 diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/memmove.S linux/arch/sh/lib/memmove.S --- v2.3.22/linux/arch/sh/lib/memmove.S Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/lib/memmove.S Mon Oct 18 11:16:13 1999 @@ -1,422 +1,254 @@ +/* $Id: memmove.S,v 1.2 1999/09/21 12:55:49 gniibe Exp $ + * + * "memmove" implementation of SuperH + * + * Copyright (C) 1999 Niibe Yutaka + * + */ + +/* + * void *memmove(void *dst, const void *src, size_t n); + * The memory areas may overlap. + */ + #include ENTRY(memmove) - mov.l r8,@-r15 - mov.l r9,@-r15 - mov.l r14,@-r15 - sts.l pr,@-r15 - add #-28,r15 - mov r15,r14 - mov.l r4,@r14 - mov.l r5,@(4,r14) - mov.l r6,@(8,r14) - mov.l @r14,r1 - mov.l r1,@(12,r14) - mov.l @(4,r14),r1 - mov.l r1,@(16,r14) - mov.l @(12,r14),r1 - mov.l @(16,r14),r2 - sub r2,r1 - mov.l @(8,r14),r2 - cmp/hs r2,r1 - bt .L54 - bra .L2 - nop -.L54: - mov.l @(8,r14),r1 - mov #15,r2 - cmp/gt r2,r1 - bt .LF100 - bra .L52 - nop -.LF100: - mov.l @(12,r14),r2 - neg r2,r1 - mov #3,r2 - and r1,r2 - mov.l @(8,r14),r1 - mov r1,r9 - sub r2,r9 - mov r9,r2 - mov.l r2,@(8,r14) -.L4: - mov.l @(12,r14),r2 - neg r2,r1 - mov #3,r2 - and r1,r2 - mov.l r2,@(20,r14) -.L7: - mov.l @(20,r14),r1 - cmp/pl r1 - bt .L9 - bra .L6 - nop - .align 2 -.L9: - mov r14,r2 - mov r14,r1 - add #24,r1 - mov.l @(16,r14),r2 - mov.b @r2,r3 - mov.b r3,@r1 - mov.l @(16,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(16,r14) - mov.l @(20,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(20,r14) - mov.l @(12,r14),r1 - mov r14,r2 - mov r14,r3 - add #24,r3 - mov.b @r3,r2 - mov.b r2,@r1 - mov.l @(12,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(12,r14) - bra .L7 - nop - .align 2 -.L8: -.L6: - bra .L5 - nop - .align 2 -.L10: - bra .L4 - nop - .align 2 -.L5: - nop -.L11: - mov.l @(16,r14),r1 - mov #3,r2 - and r1,r2 - tst r2,r2 - bf .L14 - mov r15,r2 - mov.l @(12,r14),r1 - mov.l @(16,r14),r2 - mov.l @(8,r14),r7 - mov r7,r3 - shlr2 r3 - mov r1,r4 - mov r2,r5 - mov r3,r6 - mov.l .L46,r8 - jsr @r8 - nop - bra .L15 - nop - .align 2 -.L14: - mov r15,r2 - mov.l @(12,r14),r1 - mov.l @(16,r14),r2 - mov.l @(8,r14),r7 - mov r7,r3 - shlr2 r3 - mov r1,r4 - mov r2,r5 - mov r3,r6 - mov.l .L47,r8 - jsr @r8 - nop -.L15: - mov.l @(8,r14),r1 - mov #-4,r2 - and r2,r1 - mov.l @(16,r14),r2 - add r2,r1 - mov.l r1,@(16,r14) - mov.l @(8,r14),r1 - mov #-4,r2 - and r2,r1 - mov.l @(12,r14),r2 - add r2,r1 - mov.l r1,@(12,r14) - mov.l @(8,r14),r1 - mov #3,r2 - and r1,r2 - mov.l r2,@(8,r14) -.L13: -.L52: - bra .L3 - nop - .align 2 -.L16: - bra .L11 - nop - .align 2 -.L12: -.L3: - nop -.L17: - mov.l @(8,r14),r1 - mov.l r1,@(20,r14) -.L20: - mov.l @(20,r14),r1 - cmp/pl r1 - bt .L22 - bra .L19 - nop - .align 2 -.L22: - mov r14,r2 - mov r14,r1 - add #24,r1 - mov.l @(16,r14),r2 - mov.b @r2,r3 - mov.b r3,@r1 - mov.l @(16,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(16,r14) - mov.l @(20,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(20,r14) - mov.l @(12,r14),r1 - mov r14,r2 - mov r14,r3 - add #24,r3 - mov.b @r3,r2 - mov.b r2,@r1 - mov.l @(12,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(12,r14) - bra .L20 - nop - .align 2 -.L21: -.L19: - bra .L18 - nop - .align 2 -.L23: - bra .L17 - nop - .align 2 -.L18: - bra .L24 - nop - .align 2 -.L2: - mov.l @(16,r14),r1 - mov.l @(8,r14),r2 - add r2,r1 - mov.l r1,@(16,r14) - mov.l @(12,r14),r1 - mov.l @(8,r14),r2 - add r2,r1 - mov.l r1,@(12,r14) - mov.l @(8,r14),r1 - mov #15,r2 - cmp/gt r2,r1 - bt .LF101 - bra .L53 - nop -.LF101: - mov.l @(12,r14),r1 - mov #3,r2 - and r1,r2 - mov.l @(8,r14),r1 - mov r1,r9 - sub r2,r9 - mov r9,r2 - mov.l r2,@(8,r14) -.L26: - mov.l @(12,r14),r1 - mov #3,r2 - and r1,r2 - mov.l r2,@(20,r14) -.L29: - mov.l @(20,r14),r1 - cmp/pl r1 - bt .L31 - bra .L28 - nop - .align 2 -.L31: - mov.l @(16,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(16,r14) - mov r14,r2 - mov r14,r1 - add #24,r1 - mov.l @(16,r14),r2 - mov.b @r2,r3 - mov.b r3,@r1 - mov.l @(12,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(12,r14) - mov.l @(20,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(20,r14) - mov.l @(12,r14),r1 - mov r14,r2 - mov r14,r3 - add #24,r3 - mov.b @r3,r2 - mov.b r2,@r1 - bra .L29 - nop - .align 2 -.L30: -.L28: - bra .L27 - nop - .align 2 -.L32: - bra .L26 - nop - .align 2 -.L27: - nop -.L33: - mov.l @(16,r14),r1 + ! if dest > src, call memcpy (it copies in decreasing order) + cmp/hi r5,r4 + bf 1f + mov.l 2f,r0 + jmp @r0 + nop + .balign 4 +2: .long SYMBOL_NAME(memcpy) +1: + sub r5,r4 ! From here, r4 has the distance to r0 + tst r6,r6 + bt/s 9f ! if n=0, do nothing + mov r5,r0 + add r6,r5 + mov #12,r1 + cmp/gt r6,r1 + bt/s 8f ! if it's too small, copy a byte at once + add #-1,r4 + add #1,r4 + ! + ! [ ... ] DST [ ... ] SRC + ! [ ... ] [ ... ] + ! : : + ! r0+r4--> [ ... ] r0 --> [ ... ] + ! : : + ! [ ... ] [ ... ] + ! r5 --> + ! + mov r4,r1 mov #3,r2 - and r1,r2 - tst r2,r2 - bf .L36 - mov r15,r2 - mov.l @(12,r14),r1 - mov.l @(16,r14),r2 - mov.l @(8,r14),r7 - mov r7,r3 - shlr2 r3 - mov r1,r4 - mov r2,r5 - mov r3,r6 - mov.l .L48,r8 - jsr @r8 - nop - bra .L37 - nop - .align 2 -.L36: - mov r15,r2 - mov.l @(12,r14),r1 - mov.l @(16,r14),r2 - mov.l @(8,r14),r7 - mov r7,r3 - shlr2 r3 - mov r1,r4 - mov r2,r5 - mov r3,r6 - mov.l .L49,r8 - jsr @r8 - nop -.L37: - mov.l @(8,r14),r1 - mov #-4,r2 and r2,r1 - mov.l @(16,r14),r2 - mov r2,r9 - sub r1,r9 - mov r9,r1 - mov.l r1,@(16,r14) - mov.l @(8,r14),r1 - mov #-4,r2 - and r2,r1 - mov.l @(12,r14),r2 - mov r2,r9 - sub r1,r9 - mov r9,r1 - mov.l r1,@(12,r14) - mov.l @(8,r14),r1 - mov #3,r2 - and r1,r2 - mov.l r2,@(8,r14) -.L35: -.L53: - bra .L25 - nop - .align 2 -.L38: - bra .L33 - nop - .align 2 -.L34: -.L25: - nop -.L39: - mov.l @(8,r14),r1 - mov.l r1,@(20,r14) -.L42: - mov.l @(20,r14),r1 - cmp/pl r1 - bt .L44 - bra .L41 - nop - .align 2 -.L44: - mov.l @(16,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(16,r14) - mov r14,r2 - mov r14,r1 - add #24,r1 - mov.l @(16,r14),r2 - mov.b @r2,r3 - mov.b r3,@r1 - mov.l @(12,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(12,r14) - mov.l @(20,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(20,r14) - mov.l @(12,r14),r1 - mov r14,r2 - mov r14,r3 - add #24,r3 - mov.b @r3,r2 - mov.b r2,@r1 - bra .L42 - nop - .align 2 -.L43: -.L41: - bra .L24 - nop - .align 2 -.L45: - bra .L39 - nop - .align 2 -.L40: -.L24: - mov.l @r14,r1 - mov r1,r0 - bra .L1 - nop - .align 2 -.L1: - add #28,r14 - mov r14,r15 - lds.l @r15+,pr - mov.l @r15+,r14 - mov.l @r15+,r9 - mov.l @r15+,r8 - rts - nop -.L50: - .align 2 -.L46: - .long __wordcopy_fwd_aligned -.L47: - .long __wordcopy_fwd_dest_aligned -.L48: - .long __wordcopy_bwd_aligned -.L49: - .long __wordcopy_bwd_dest_aligned -.Lfe1: + shll2 r1 + mov r0,r3 ! Save the value on R0 to R3 + mova jmptable,r0 + add r1,r0 + mov.l @r0,r1 + jmp @r1 + mov r3,r0 ! and back to R0 + .balign 4 +jmptable: + .long case0 + .long case1 + .long case2 + .long case3 + + ! copy a byte at once +8: mov.b @r0+,r1 + cmp/hs r5,r0 + bf/s 8b ! while (r0 GHIJ KLMN OPQR + ! + ! First, align to long word boundary + mov r0,r3 + and r2,r3 + tst r3,r3 + bt/s 2f + add #-1,r4 + mov #4,r2 + sub r3,r2 +1: dt r2 + mov.b @r0+,r1 + bf/s 1b + mov.b r1,@(r0,r4) + ! +2: ! Second, copy a long word at once + add #-3,r4 + add #-3,r5 +3: mov.l @r0+,r1 + cmp/hs r5,r0 + bf/s 3b + mov.l r1,@(r0,r4) + add #3,r5 + ! + ! Third, copy a byte at once, if necessary + cmp/eq r5,r0 + bt/s 9b + add #4,r4 + bra 8b + add #-1,r4 + +case3: + ! + ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR. + ! + ! First, align to long word boundary + mov r0,r3 + and r2,r3 + tst r3,r3 + bt/s 2f + add #-1,r4 + mov #4,r2 + sub r3,r2 +1: dt r2 + mov.b @r0+,r1 + bf/s 1b + mov.b r1,@(r0,r4) + ! +2: ! Second, read a long word and write a long word at once + add #-2,r4 + mov.l @(r0,r4),r1 + add #-7,r5 + add #-4,r4 + ! +#ifdef __LITTLE_ENDIAN__ + shll8 r1 +3: mov r1,r3 ! JIHG + shlr8 r3 ! xJIH + mov.l @r0+,r1 ! NMLK + mov r1,r2 + shll16 r2 + shll8 r2 ! Kxxx + or r2,r3 ! KJIH + cmp/hs r5,r0 + bf/s 3b + mov.l r3,@(r0,r4) +#else + shlr8 r1 +3: mov r1,r3 ! GHIJ + shll8 r3 ! HIJx + mov.l @r0+,r1 ! KLMN + mov r1,r2 + shlr16 r2 + shlr8 r2 ! xxxK + or r2,r3 ! HIJK + cmp/hs r5,r0 + bf/s 3b + mov.l r3,@(r0,r4) +#endif + add #7,r5 + ! + ! Third, copy a byte at once, if necessary + cmp/eq r5,r0 + bt/s 9b + add #7,r4 + add #-3,r0 + bra 8b + add #-1,r4 + +case2: + ! + ! GHIJ KLMN OPQR --> ..GH IJKL MNOP QR.. + ! + ! First, align to word boundary + tst #1,r0 + bt/s 2f + add #-1,r4 + mov.b @r0+,r1 + mov.b r1,@(r0,r4) + ! +2: ! Second, read a word and write a word at once + add #-1,r4 + add #-1,r5 + ! +3: mov.w @r0+,r1 + cmp/hs r5,r0 + bf/s 3b + mov.w r1,@(r0,r4) + add #1,r5 + ! + ! Third, copy a byte at once, if necessary + cmp/eq r5,r0 + bt/s 9b + add #2,r4 + mov.b @r0,r1 + mov.b r1,@(r0,r4) + bra 9b + add #1,r0 + +case1: + ! + ! GHIJ KLMN OPQR --> .GHI JKLM NOPQ R... + ! + ! First, align to long word boundary + mov r0,r3 + and r2,r3 + tst r3,r3 + bt/s 2f + add #-1,r4 + mov #4,r2 + sub r3,r2 +1: dt r2 + mov.b @r0+,r1 + bf/s 1b + mov.b r1,@(r0,r4) + ! +2: ! Second, read a long word and write a long word at once + mov.l @(r0,r4),r1 + add #-7,r5 + add #-4,r4 + ! +#ifdef __LITTLE_ENDIAN__ + shll16 r1 + shll8 r1 +3: mov r1,r3 ! JIHG + shlr16 r3 + shlr8 r3 ! xxxJ + mov.l @r0+,r1 ! NMLK + mov r1,r2 + shll8 r2 ! MLKx + or r2,r3 ! MLKJ + cmp/hs r5,r0 + bf/s 3b + mov.l r3,@(r0,r4) +#else + shlr16 r1 + shlr8 r1 +3: mov r1,r3 ! GHIJ + shll16 r3 + shll8 r3 ! Jxxx + mov.l @r0+,r1 ! KLMN + mov r1,r2 + shlr8 r2 ! xKLM + or r2,r3 ! JKLM + cmp/hs r5,r0 + bf/s 3b ! while(r0 ENTRY(memset) - mov r4,r3 ! Save return value - - mov r6,r0 ! Check explicitly for zero - cmp/eq #0,r0 - bt L_exit - - mov #12,r0 ! Check for small number of bytes + tst r6,r6 + bt/s 5f ! if n=0, do nothing + add r6,r4 + mov #12,r0 cmp/gt r6,r0 - bt L_store_byte_loop - - neg r4,r0 ! Align destination - add #4,r0 + bt/s 4f ! if it's too small, set a byte at once + mov r4,r0 and #3,r0 - tst r0,r0 - bt L_dup_bytes - .balignw 4,0x0009 -L_align_loop: - mov.b r5,@r4 - add #-1,r6 - add #1,r4 + cmp/eq #0,r0 + bt/s 2f ! It's aligned + sub r0,r6 +1: dt r0 - bf L_align_loop - -L_dup_bytes: - extu.b r5,r5 ! Duplicate bytes across longword - swap.b r5,r0 - or r0,r5 - swap.w r5,r0 - or r0,r5 - - mov r6,r2 ! Calculate number of double longwords - shlr2 r2 - shlr r2 - - .balignw 4,0x0009 -L_store_long_loop: - mov.l r5,@r4 ! Store double longs to memory - dt r2 - mov.l r5,@(4,r4) - add #8,r4 - bf L_store_long_loop - + bf/s 1b + mov.b r5,@-r4 +2: ! make VVVV + swap.b r5,r0 ! V0 + or r0,r5 ! VV + swap.w r5,r0 ! VV00 + or r0,r5 ! VVVV + ! + mov r6,r0 + shlr2 r0 + shlr r0 ! r0 = r6 >> 3 +3: + dt r0 + mov.l r5,@-r4 ! set 8-byte at once + bf/s 3b + mov.l r5,@-r4 + ! mov #7,r0 and r0,r6 tst r6,r6 - bt L_exit - .balignw 4,0x0009 -L_store_byte_loop: - mov.b r5,@r4 ! Store bytes to memory - add #1,r4 + bt 5f + ! fill bytes +4: dt r6 - bf L_store_byte_loop - -L_exit: + bf/s 4b + mov.b r5,@-r4 +5: rts - mov r3,r0 + mov r4,r0 diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/old-checksum.c linux/arch/sh/lib/old-checksum.c --- v2.3.22/linux/arch/sh/lib/old-checksum.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/lib/old-checksum.c Mon Oct 18 11:16:13 1999 @@ -15,5 +15,3 @@ return sum; } - - diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/wordcopy.S linux/arch/sh/lib/wordcopy.S --- v2.3.22/linux/arch/sh/lib/wordcopy.S Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/lib/wordcopy.S Wed Dec 31 16:00:00 1969 @@ -1,1289 +0,0 @@ -#include -ENTRY(_wordcopy_fwd_aligned) - mov.l r14,@-r15 - add #-20,r15 - mov r15,r14 - mov.l r4,@r14 - mov.l r5,@(4,r14) - mov.l r6,@(8,r14) - mov.l @(8,r14),r2 - mov #7,r1 - and r2,r1 - mov #0,r2 - mov #7,r3 - sub r2,r1 - cmp/hi r3,r1 - bf .L29 - bra .L2 - nop -.L29: - mova .L22,r0 - add r1,r1 - mov.w @(r0,r1),r1 - add r0,r1 - jmp @r1 - nop - .align 2 - .align 2 -.L22: - .word .L15-.L22 - .word .L18-.L22 - .word .L3-.L22 - .word .L5-.L22 - .word .L7-.L22 - .word .L9-.L22 - .word .L11-.L22 - .word .L13-.L22 - .align 2 -.L3: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #-24,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-28,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #6,r2 - mov.l r2,@(8,r14) - bra .L4 - nop - .align 2 -.L5: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #-20,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-24,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #5,r2 - mov.l r2,@(8,r14) - bra .L6 - nop - .align 2 -.L7: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-20,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #4,r2 - mov.l r2,@(8,r14) - bra .L8 - nop - .align 2 -.L9: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #-12,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #3,r2 - mov.l r2,@(8,r14) - bra .L10 - nop - .align 2 -.L11: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-12,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #2,r2 - mov.l r2,@(8,r14) - bra .L12 - nop - .align 2 -.L13: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(8,r14) - bra .L14 - nop - .align 2 -.L15: - bra .L16 - nop - bra .L1 - nop - .align 2 -.L16: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@r14 - bra .L17 - nop - .align 2 -.L18: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #4,r2 - mov.l r2,@(4,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(8,r14) - bra .L19 - nop - bra .L20 - nop - .align 2 -.L19: - bra .L21 - nop - .align 2 -.L23: -.L2: - nop -.L24: -.L21: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L17: - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r2 - mov r2,r1 - add #4,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 -.L14: - mov.l @(4,r14),r2 - mov r2,r1 - add #8,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r2 - mov r2,r1 - add #8,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L12: - mov.l @(4,r14),r2 - mov r2,r1 - add #12,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r2 - mov r2,r1 - add #12,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 -.L10: - mov.l @(4,r14),r2 - mov r2,r1 - add #16,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r2 - mov r2,r1 - add #16,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L8: - mov.l @(4,r14),r2 - mov r2,r1 - add #20,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r2 - mov r2,r1 - add #20,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 -.L6: - mov.l @(4,r14),r2 - mov r2,r1 - add #24,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r2 - mov r2,r1 - add #24,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L4: - mov.l @(4,r14),r2 - mov r2,r1 - add #28,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r2 - mov r2,r1 - add #28,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 - mov.l @(4,r14),r1 - mov r1,r2 - add #32,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #32,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@(8,r14) -.L26: - mov.l @(8,r14),r1 - tst r1,r1 - bf .L27 - bra .L25 - nop - .align 2 -.L27: - bra .L21 - nop - .align 2 -.L25: - nop -.L20: - mov.l @r14,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L1: - add #20,r14 - mov r14,r15 - mov.l @r15+,r14 - rts - nop -.Lfe1: - .size __wordcopy_fwd_aligned,.Lfe1-__wordcopy_fwd_aligned - .global ___lshrsi3 - .global ___ashlsi3 - .align 2 - .global __wordcopy_fwd_dest_aligned - .type __wordcopy_fwd_dest_aligned,@function -__wordcopy_fwd_dest_aligned: - mov.l r8,@-r15 - mov.l r9,@-r15 - mov.l r14,@-r15 - sts.l pr,@-r15 - add #-40,r15 - mov r15,r14 - mov.l r4,@r14 - mov.l r5,@(4,r14) - mov.l r6,@(8,r14) - mov.l @(4,r14),r1 - mov #3,r2 - and r1,r2 - mov r2,r1 - mov r1,r2 - shll2 r2 - add r2,r2 - mov.l r2,@(28,r14) - mov.l @(28,r14),r2 - neg r2,r1 - add #32,r1 - mov.l r1,@(32,r14) - mov.l @(4,r14),r1 - mov #-4,r2 - and r2,r1 - mov.l r1,@(4,r14) - mov.l @(8,r14),r2 - mov #3,r1 - and r2,r1 - mov #0,r2 - mov #3,r3 - sub r2,r1 - cmp/hi r3,r1 - bf .L53 - bra .L31 - nop -.L53: - mova .L43,r0 - add r1,r1 - mov.w @(r0,r1),r1 - add r0,r1 - jmp @r1 - nop - .align 2 - .align 2 -.L43: - .word .L36-.L43 - .word .L39-.L43 - .word .L32-.L43 - .word .L34-.L43 - .align 2 -.L32: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(20,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-12,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #2,r2 - mov.l r2,@(8,r14) - bra .L33 - nop - .align 2 -.L34: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(8,r14) - bra .L35 - nop - .align 2 -.L36: - bra .L37 - nop - bra .L30 - nop - .align 2 -.L37: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(24,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #4,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@r14 - bra .L38 - nop - .align 2 -.L39: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(20,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(24,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #8,r2 - mov.l r2,@(4,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(8,r14) - bra .L40 - nop - bra .L41 - nop - .align 2 -.L40: - bra .L42 - nop - .align 2 -.L44: -.L31: - nop -.L45: -.L42: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r8 - mov.l .L49,r1 - mov.l @(20,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L50,r1 - mov.l @(24,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L38: - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r1 - mov r1,r8 - add #4,r8 - mov.l .L49,r1 - mov.l @(24,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L50,r1 - mov.l @(12,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L35: - mov.l @(4,r14),r2 - mov r2,r1 - add #8,r1 - mov.l @r1,r2 - mov.l r2,@(20,r14) - mov.l @r14,r1 - mov r1,r8 - add #8,r8 - mov.l .L49,r1 - mov.l @(12,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L50,r1 - mov.l @(16,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L33: - mov.l @(4,r14),r2 - mov r2,r1 - add #12,r1 - mov.l @r1,r2 - mov.l r2,@(24,r14) - mov.l @r14,r1 - mov r1,r8 - add #12,r8 - mov.l .L49,r1 - mov.l @(16,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L50,r1 - mov.l @(20,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 - mov.l @(4,r14),r1 - mov r1,r2 - add #16,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #16,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@(8,r14) -.L47: - mov.l @(8,r14),r1 - tst r1,r1 - bf .L48 - bra .L46 - nop - .align 2 -.L48: - bra .L42 - nop - .align 2 -.L46: - nop -.L41: - mov.l @r14,r8 - mov.l .L49,r1 - mov.l @(20,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L50,r1 - mov.l @(24,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L30: - add #40,r14 - mov r14,r15 - lds.l @r15+,pr - mov.l @r15+,r14 - mov.l @r15+,r9 - mov.l @r15+,r8 - rts - nop -.L51: - .align 2 -.L49: - .long ___lshrsi3 -.L50: - .long ___ashlsi3 -.Lfe2: - .size __wordcopy_fwd_dest_aligned,.Lfe2-__wordcopy_fwd_dest_aligned - .align 2 - .global __wordcopy_bwd_aligned - .type __wordcopy_bwd_aligned,@function -__wordcopy_bwd_aligned: - mov.l r14,@-r15 - add #-20,r15 - mov r15,r14 - mov.l r4,@r14 - mov.l r5,@(4,r14) - mov.l r6,@(8,r14) - mov.l @(8,r14),r2 - mov #7,r1 - and r2,r1 - mov #0,r2 - mov #7,r3 - sub r2,r1 - cmp/hi r3,r1 - bf .L82 - bra .L55 - nop -.L82: - mova .L75,r0 - add r1,r1 - mov.w @(r0,r1),r1 - add r0,r1 - jmp @r1 - nop - .align 2 - .align 2 -.L75: - .word .L68-.L75 - .word .L71-.L75 - .word .L56-.L75 - .word .L58-.L75 - .word .L60-.L75 - .word .L62-.L75 - .word .L64-.L75 - .word .L66-.L75 - .align 2 -.L56: - mov.l @(4,r14),r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #6,r2 - mov.l r2,@(8,r14) - bra .L57 - nop - .align 2 -.L58: - mov.l @(4,r14),r1 - mov r1,r2 - add #-12,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #8,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #5,r2 - mov.l r2,@(8,r14) - bra .L59 - nop - .align 2 -.L60: - mov.l @(4,r14),r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-12,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #12,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #4,r2 - mov.l r2,@(8,r14) - bra .L61 - nop - .align 2 -.L62: - mov.l @(4,r14),r1 - mov r1,r2 - add #-20,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #16,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #3,r2 - mov.l r2,@(8,r14) - bra .L63 - nop - .align 2 -.L64: - mov.l @(4,r14),r1 - mov r1,r2 - add #-24,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-20,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #20,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #2,r2 - mov.l r2,@(8,r14) - bra .L65 - nop - .align 2 -.L66: - mov.l @(4,r14),r1 - mov r1,r2 - add #-28,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-24,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #24,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(8,r14) - bra .L67 - nop - .align 2 -.L68: - bra .L69 - nop - bra .L54 - nop - .align 2 -.L69: - mov.l @(4,r14),r1 - mov r1,r2 - add #-32,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-28,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #28,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - bra .L70 - nop - .align 2 -.L71: - mov.l @(4,r14),r1 - mov r1,r2 - add #-36,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-32,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #32,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(8,r14) - bra .L72 - nop - bra .L73 - nop - .align 2 -.L72: - bra .L74 - nop - .align 2 -.L76: -.L55: - nop -.L77: -.L74: - mov.l @(4,r14),r2 - mov r2,r1 - add #28,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r2 - mov r2,r1 - add #28,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L70: - mov.l @(4,r14),r2 - mov r2,r1 - add #24,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r2 - mov r2,r1 - add #24,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 -.L67: - mov.l @(4,r14),r2 - mov r2,r1 - add #20,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r2 - mov r2,r1 - add #20,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L65: - mov.l @(4,r14),r2 - mov r2,r1 - add #16,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r2 - mov r2,r1 - add #16,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 -.L63: - mov.l @(4,r14),r2 - mov r2,r1 - add #12,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r2 - mov r2,r1 - add #12,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L61: - mov.l @(4,r14),r2 - mov r2,r1 - add #8,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r2 - mov r2,r1 - add #8,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 -.L59: - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r2 - mov r2,r1 - add #4,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L57: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r1 - mov.l @(12,r14),r2 - mov.l r2,@r1 - mov.l @(4,r14),r1 - mov r1,r2 - add #-32,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-32,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@(8,r14) -.L79: - mov.l @(8,r14),r1 - tst r1,r1 - bf .L80 - bra .L78 - nop - .align 2 -.L80: - bra .L74 - nop - .align 2 -.L78: - nop -.L73: - mov.l @r14,r2 - mov r2,r1 - add #28,r1 - mov.l @(16,r14),r2 - mov.l r2,@r1 -.L54: - add #20,r14 - mov r14,r15 - mov.l @r15+,r14 - rts - nop -.Lfe3: - .size __wordcopy_bwd_aligned,.Lfe3-__wordcopy_bwd_aligned - .align 2 - .global __wordcopy_bwd_dest_aligned - .type __wordcopy_bwd_dest_aligned,@function -__wordcopy_bwd_dest_aligned: - mov.l r8,@-r15 - mov.l r9,@-r15 - mov.l r14,@-r15 - sts.l pr,@-r15 - add #-40,r15 - mov r15,r14 - mov.l r4,@r14 - mov.l r5,@(4,r14) - mov.l r6,@(8,r14) - mov.l @(4,r14),r1 - mov #3,r2 - and r1,r2 - mov r2,r1 - mov r1,r2 - shll2 r2 - add r2,r2 - mov.l r2,@(28,r14) - mov.l @(28,r14),r2 - neg r2,r1 - add #32,r1 - mov.l r1,@(32,r14) - mov.l @(4,r14),r1 - mov #-4,r2 - and r2,r1 - mov.l r1,@(4,r14) - mov.l @(4,r14),r1 - mov r1,r2 - add #4,r2 - mov.l r2,@(4,r14) - mov.l @(8,r14),r2 - mov #3,r1 - and r2,r1 - mov #0,r2 - mov #3,r3 - sub r2,r1 - cmp/hi r3,r1 - bf .L106 - bra .L84 - nop -.L106: - mova .L96,r0 - add r1,r1 - mov.w @(r0,r1),r1 - add r0,r1 - jmp @r1 - nop - .align 2 - .align 2 -.L96: - .word .L89-.L96 - .word .L92-.L96 - .word .L85-.L96 - .word .L87-.L96 - .align 2 -.L85: - mov.l @(4,r14),r1 - mov r1,r2 - add #-12,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #8,r1 - mov.l @r1,r2 - mov.l r2,@(20,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #2,r2 - mov.l r2,@(8,r14) - bra .L86 - nop - .align 2 -.L87: - mov.l @(4,r14),r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-8,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #12,r1 - mov.l @r1,r2 - mov.l r2,@(24,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #8,r1 - mov.l @r1,r2 - mov.l r2,@(20,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #1,r2 - mov.l r2,@(8,r14) - bra .L88 - nop - .align 2 -.L89: - bra .L90 - nop - bra .L83 - nop - .align 2 -.L90: - mov.l @(4,r14),r1 - mov r1,r2 - add #-20,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-12,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #16,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #12,r1 - mov.l @r1,r2 - mov.l r2,@(24,r14) - bra .L91 - nop - .align 2 -.L92: - mov.l @(4,r14),r1 - mov r1,r2 - add #-24,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@r14 - mov.l @(4,r14),r2 - mov r2,r1 - add #20,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @(4,r14),r2 - mov r2,r1 - add #16,r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @(8,r14),r1 - mov r1,r2 - add #-1,r2 - mov.l r2,@(8,r14) - bra .L93 - nop - bra .L94 - nop - .align 2 -.L93: - bra .L95 - nop - .align 2 -.L97: -.L84: - nop -.L98: -.L95: - mov.l @(4,r14),r2 - mov r2,r1 - add #12,r1 - mov.l @r1,r2 - mov.l r2,@(24,r14) - mov.l @r14,r1 - mov r1,r8 - add #12,r8 - mov.l .L102,r1 - mov.l @(12,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L103,r1 - mov.l @(16,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L91: - mov.l @(4,r14),r2 - mov r2,r1 - add #8,r1 - mov.l @r1,r2 - mov.l r2,@(20,r14) - mov.l @r14,r1 - mov r1,r8 - add #8,r8 - mov.l .L102,r1 - mov.l @(24,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L103,r1 - mov.l @(12,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L88: - mov.l @(4,r14),r2 - mov r2,r1 - add #4,r1 - mov.l @r1,r2 - mov.l r2,@(16,r14) - mov.l @r14,r1 - mov r1,r8 - add #4,r8 - mov.l .L102,r1 - mov.l @(20,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L103,r1 - mov.l @(24,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L86: - mov.l @(4,r14),r1 - mov.l @r1,r2 - mov.l r2,@(12,r14) - mov.l @r14,r8 - mov.l .L102,r1 - mov.l @(16,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L103,r1 - mov.l @(20,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 - mov.l @(4,r14),r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@(4,r14) - mov.l @r14,r1 - mov r1,r2 - add #-16,r2 - mov.l r2,@r14 - mov.l @(8,r14),r1 - mov r1,r2 - add #-4,r2 - mov.l r2,@(8,r14) -.L100: - mov.l @(8,r14),r1 - tst r1,r1 - bf .L101 - bra .L99 - nop - .align 2 -.L101: - bra .L95 - nop - .align 2 -.L99: - nop -.L94: - mov.l @r14,r1 - mov r1,r8 - add #12,r8 - mov.l .L102,r1 - mov.l @(12,r14),r4 - mov.l @(28,r14),r5 - jsr @r1 - nop - mov r0,r9 - mov.l .L103,r1 - mov.l @(16,r14),r4 - mov.l @(32,r14),r5 - jsr @r1 - nop - mov.l r0,@(36,r14) - mov.l @(36,r14),r1 - or r9,r1 - mov.l r1,@r8 -.L83: - add #40,r14 - mov r14,r15 - lds.l @r15+,pr - mov.l @r15+,r14 - mov.l @r15+,r9 - mov.l @r15+,r8 - rts - nop -.L104: - .align 2 -.L102: - .long ___lshrsi3 -.L103: - .long ___ashlsi3 -.Lfe4: diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/Makefile linux/arch/sh/mm/Makefile --- v2.3.22/linux/arch/sh/mm/Makefile Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/mm/Makefile Mon Oct 18 11:16:13 1999 @@ -8,6 +8,6 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o ioremap.o extable.o +O_OBJS := init.o fault.o ioremap.o extable.o cache.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c --- v2.3.22/linux/arch/sh/mm/cache.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/mm/cache.c Mon Oct 18 11:16:13 1999 @@ -0,0 +1,366 @@ +/* $Id: cache.c,v 1.7 1999/09/23 11:43:07 gniibe Exp $ + * + * linux/arch/sh/mm/cache.c + * + * Copyright (C) 1999 Niibe Yutaka + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__sh3__) +#define CCR 0xffffffec /* Address of Cache Control Register */ +#define CCR_CACHE_VAL 0x00000005 /* 8k-byte cache, P1-wb, enable */ +#define CCR_CACHE_INIT 0x0000000d /* 8k-byte cache, CF, P1-wb, enable */ +#define CCR_CACHE_ENABLE 1 + +#define CACHE_IC_ADDRESS_ARRAY 0xf0000000 /* SH-3 has unified cache system */ +#define CACHE_OC_ADDRESS_ARRAY 0xf0000000 +#define CACHE_VALID 1 +#define CACHE_UPDATED 2 + +/* 7709A/7729 has 16K cache (256-entry), while 7702 has only 2K(direct) + 7702 is not supported (yet) */ +struct _cache_system_info { + int way_shift; + int entry_mask; + int num_entries; +}; + +static struct _cache_system_info cache_system_info; + +#define CACHE_OC_WAY_SHIFT (cache_system_info.way_shift) +#define CACHE_IC_WAY_SHIFT (cache_system_info.way_shift) +#define CACHE_OC_ENTRY_SHIFT 4 +#define CACHE_OC_ENTRY_MASK (cache_system_info.entry_mask) +#define CACHE_IC_ENTRY_MASK (cache_system_info.entry_mask) +#define CACHE_OC_NUM_ENTRIES (cache_system_info.num_entries) +#define CACHE_OC_NUM_WAYS 4 +#define CACHE_IC_NUM_WAYS 4 +#elif defined(__SH4__) +#define CCR 0xff00001c /* Address of Cache Control Register */ +#define CCR_CACHE_VAL 0x00000105 /* 8k+16k-byte cache,P1-wb,enable */ +#define CCR_CACHE_INIT 0x0000090d /* 8k+16k-byte cache,CF,P1-wb,enable */ +#define CCR_CACHE_ENABLE 0x00000101 + +#define CACHE_IC_ADDRESS_ARRAY 0xf0000000 +#define CACHE_OC_ADDRESS_ARRAY 0xf4000000 +#define CACHE_VALID 1 +#define CACHE_UPDATED 2 + +#define CACHE_OC_WAY_SHIFT 13 +#define CACHE_IC_WAY_SHIFT 13 +#define CACHE_OC_ENTRY_SHIFT 5 +#define CACHE_OC_ENTRY_MASK 0x3fe0 +#define CACHE_IC_ENTRY_MASK 0x1fe0 +#define CACHE_OC_NUM_ENTRIES 512 +#define CACHE_OC_NUM_WAYS 1 +#define CACHE_IC_NUM_WAYS 1 +#endif + +#define jump_to_p2(__dummy) \ + asm volatile("mova 1f,%0\n\t" \ + "add %1,%0\n\t" \ + "jmp @r0 ! Jump to P2 area\n\t" \ + " nop\n\t" \ + ".balign 4\n" \ + "1:" \ + : "=&z" (__dummy) \ + : "r" (0x20000000)) + +#define back_to_p1(__dummy) \ + asm volatile("nop;nop;nop;nop;nop;nop\n\t" \ + "mova 9f,%0\n\t" \ + "sub %1,%0\n\t" \ + "jmp @r0 ! Back to P1 area\n\t" \ + " nop\n\t" \ + ".balign 4\n" \ + "9:" \ + : "=&z" (__dummy) \ + : "r" (0x20000000), "0" (__dummy)) + +/* Write back caches to memory (if needed) and invalidates the caches */ +void cache_flush_area(unsigned long start, unsigned long end) +{ + unsigned long flags, __dummy; + unsigned long addr, data, v, p; + + start &= ~(L1_CACHE_BYTES-1); + save_and_cli(flags); + jump_to_p2(__dummy); + + for (v = start; v < end; v+=L1_CACHE_BYTES) { + p = __pa(v); + addr = CACHE_IC_ADDRESS_ARRAY | + (v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */; + data = (v&0xfffffc00); /* U=0, V=0 */ + ctrl_outl(data,addr); +#if CACHE_IC_ADDRESS_ARRAY != CACHE_OC_ADDRESS_ARRAY + asm volatile("ocbp %0" + : /* no output */ + : "m" (__m(v))); +#endif + } + back_to_p1(__dummy); + restore_flags(flags); +} + +/* Purge (just invalidate, no write back) the caches */ +/* This is expected to work well.. but.. + + On SH7708S, the write-back cache is written back on "purge". + (it's not expected, though). + + It seems that we have no way to just purge (with no write back action) + the cache line. */ +void cache_purge_area(unsigned long start, unsigned long end) +{ + unsigned long flags, __dummy; + unsigned long addr, data, v, p, j; + + start &= ~(L1_CACHE_BYTES-1); + save_and_cli(flags); + jump_to_p2(__dummy); + + for (v = start; v < end; v+=L1_CACHE_BYTES) { + p = __pa(v); + for (j=0; jtype = CPU_SH7708; + } else { /* 7709A or 7729 */ + cache_system_info.way_shift = 12; + cache_system_info.entry_mask = 0xff0; + cache_system_info.num_entries = 256; + cpu_data->type = CPU_SH7729; + } +#elif defined(__SH4__) + cpu_data->type = CPU_SH7750; +#endif +} + +void __init cache_init(void) +{ + unsigned long __dummy, ccr; + + detect_cpu_and_cache_system(); + + ccr = ctrl_inl(CCR); + if (ccr == CCR_CACHE_VAL) + return; + if (ccr & CCR_CACHE_ENABLE) + /* Should check RA here. If RA was 1, + we only need to flush the half of the caches. */ + cache_wback_all(); + + jump_to_p2(__dummy); + ctrl_outl(CCR_CACHE_INIT, CCR); + back_to_p1(__dummy); +} + +#if defined(__SH4__) +/* Write back data caches, and invalidates instructiin caches */ +void flush_icache_range(unsigned long start, unsigned long end) +{ + unsigned long flags, __dummy; + unsigned long addr, data, v; + + start &= ~(L1_CACHE_BYTES-1); + save_and_cli(flags); + jump_to_p2(__dummy); + + for (v = start; v < end; v+=L1_CACHE_BYTES) { + /* Write back O Cache */ + asm volatile("ocbwb %0" + : /* no output */ + : "m" (__m(v))); + /* Invalidate I Cache */ + addr = CACHE_IC_ADDRESS_ARRAY | + (v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */; + data = (v&0xfffffc00); /* Valid=0 */ + ctrl_outl(data,addr); + } + back_to_p1(__dummy); + restore_flags(flags); +} + +void flush_cache_all(void) +{ + unsigned long flags,__dummy; + + /* Write back Operand Cache */ + cache_wback_all (); + + /* Then, invalidate Instruction Cache and Operand Cache */ + save_and_cli(flags); + jump_to_p2(__dummy); + ctrl_outl(CCR_CACHE_INIT, CCR); + back_to_p1(__dummy); + restore_flags(flags); +} + +void flush_cache_mm(struct mm_struct *mm) +{ + /* Is there any good way? */ + /* XXX: possibly call flush_cache_range for each vm area */ + flush_cache_all(); +} + +void flush_cache_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + unsigned long flags, __dummy; + unsigned long addr, data, v; + + start &= ~(L1_CACHE_BYTES-1); + save_and_cli(flags); + jump_to_p2(__dummy); + + for (v = start; v < end; v+=L1_CACHE_BYTES) { + addr = CACHE_IC_ADDRESS_ARRAY | + (v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */; + data = (v&0xfffffc00); /* Update=0, Valid=0 */ + ctrl_outl(data,addr); + addr = CACHE_OC_ADDRESS_ARRAY | + (v&CACHE_OC_ENTRY_MASK) | 0x8 /* A-bit */; + ctrl_outl(data,addr); + } + back_to_p1(__dummy); + restore_flags(flags); +} + +void flush_cache_page(struct vm_area_struct *vma, unsigned long addr) +{ + flush_cache_range(vma->vm_mm, addr, addr+PAGE_SIZE); +} + +void flush_page_to_ram(unsigned long page) +{ /* Page is in physical address */ + /* XXX: for the time being... */ + flush_cache_all(); +} +#endif diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/extable.c linux/arch/sh/mm/extable.c --- v2.3.22/linux/arch/sh/mm/extable.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/mm/extable.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: extable.c,v 1.1 1999/09/18 16:57:37 gniibe Exp $ + * * linux/arch/sh/mm/extable.c * Taken from: * linux/arch/i386/mm/extable.c diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c --- v2.3.22/linux/arch/sh/mm/fault.c Tue Sep 7 12:14:06 1999 +++ linux/arch/sh/mm/fault.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: fault.c,v 1.3 1999/09/21 23:09:53 gniibe Exp $ + * * linux/arch/sh/mm/fault.c * Copyright (C) 1999 Niibe Yutaka * @@ -20,6 +21,7 @@ #include #include +#include #include #include #include @@ -225,20 +227,23 @@ asid = get_asid(); - save_and_cli(flags); address &= PAGE_MASK; +#if 0/*defined(__SH4__)*//* SH-4 has separate I/D caches: XXX really needed? */ + if ((vma->vm_flags & VM_EXEC) != 0) +/* && + ((pte_val(pte) & (_PAGE_PRESENT | _PAGE_DIRTY)) == + (_PAGE_PRESENT | _PAGE_DIRTY))) */ + flush_icache_range(address,address+PAGE_SIZE); +#endif + save_and_cli(flags); /* Set PTEH register */ - asm volatile ("mov.l %0,%1" - : /* no output */ - : "r" (address | asid), "m" (__m(MMU_PTEH))); + ctrl_outl((address|asid), MMU_PTEH); pteval = pte_val(pte); pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */ /* Set PTEL register */ - asm volatile ("mov.l %0,%1" - : /* no output */ - : "r" (pteval), "m" (__m(MMU_PTEL))); + ctrl_outl(pteval, MMU_PTEL); /* Load the TLB */ asm volatile ("ldtlb" : /* no output */ : /* no input */ @@ -250,11 +255,27 @@ { unsigned long addr, data; +#if defined(__sh3__) addr = MMU_TLB_ADDRESS_ARRAY | (page & 0x1F000) | MMU_PAGE_ASSOC_BIT; data = page | asid; /* VALID bit is off */ - __asm__ __volatile__ ("mov.l %0,%1" - : /* no output */ - : "r" (data), "m" (__m(addr))); + ctrl_outl(data, addr); +#elif defined(__SH4__) + int i; + + addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT; + data = page | asid; /* VALID bit is off */ + ctrl_outl(data, addr); + + for (i=0; i<4; i++) { + addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8); + data = ctrl_inl(addr); + data &= ~0x30; + if (data == (page | asid)) { + ctrl_outl(data, addr); + break; + } + } +#endif } void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) @@ -262,9 +283,13 @@ unsigned long asid; if (vma->vm_mm->context != NO_CONTEXT) { + unsigned long flags; + page &= PAGE_MASK; asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK; + save_and_cli(flags); __flush_tlb_page (asid, page); + restore_flags(flags); } } @@ -277,7 +302,7 @@ save_and_cli(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - if (size > (MMU_NTLB_ENTRIES/4)) { /* So many TLB to flush */ + if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ get_new_mmu_context(mm); if (mm == current->mm) set_asid(mm->context & MMU_CONTEXT_ASID_MASK); @@ -314,13 +339,11 @@ void flush_tlb_all(void) { - unsigned long flags, __dummy; + unsigned long flags, status; save_and_cli(flags); - asm volatile("mov.l %1,%0\n\t" - "or #4,%0\n\t" /* Set TF-bit to flush */ - "mov.l %0,%1" - : "=&z" (__dummy) - : "m" (__m(MMUCR))); + status = ctrl_inl(MMUCR); + status |= 0x04; /* Set TF-bit to flush */ + ctrl_outl(status,MMUCR); restore_flags(flags); } diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c --- v2.3.22/linux/arch/sh/mm/init.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/mm/init.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: init.c,v 1.3 1999/10/11 10:41:30 gniibe Exp $ + * * linux/arch/sh/mm/init.c * * Copyright (C) 1999 Niibe Yutaka @@ -29,6 +30,7 @@ #include #include #include +#include /* * Cache of MMU context last used. @@ -127,7 +129,7 @@ */ pte_t * __bad_pagetable(void) { - extern char empty_bad_page_table[PAGE_SIZE]; + extern unsigned long empty_bad_page_table[PAGE_SIZE]; unsigned long page = (unsigned long)empty_bad_page_table; clear_page(page); @@ -202,16 +204,17 @@ pgd_val(pg_dir[0]) = 0; /* Enable MMU */ - __asm__ __volatile__ ("mov.l %0,%1" - : /* no output */ - : "r" (MMU_CONTROL_INIT), "m" (__m(MMUCR))); + ctrl_outl(MMU_CONTROL_INIT, MMUCR); + + mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; + set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); return free_area_init(start_mem, end_mem); } unsigned long empty_bad_page[1024]; unsigned long empty_bad_page_table[1024]; -unsigned long empty_zero_page[1024]; +extern unsigned long empty_zero_page[1024]; void __init mem_init(unsigned long start_mem, unsigned long end_mem) { diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/ioremap.c linux/arch/sh/mm/ioremap.c --- v2.3.22/linux/arch/sh/mm/ioremap.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/mm/ioremap.c Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: ioremap.c,v 1.1 1999/09/18 16:57:48 gniibe Exp $ + * * arch/sh/mm/ioremap.c * * Re-map IO memory to kernel address space so that we can access it. diff -u --recursive --new-file v2.3.22/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S --- v2.3.22/linux/arch/sh/vmlinux.lds.S Tue Sep 7 12:14:06 1999 +++ linux/arch/sh/vmlinux.lds.S Mon Oct 18 11:16:13 1999 @@ -1,4 +1,5 @@ -/* ld script to make SuperH Linux kernel +/* $Id: vmlinux.lds.S,v 1.3 1999/10/05 12:33:48 gniibe Exp $ + * ld script to make SuperH Linux kernel * Written by Niibe Yutaka */ #include @@ -15,6 +16,7 @@ __text = .; /* Text and read-only data */ _text = .; /* Text and read-only data */ .text : { + *(.empty_zero_page) *(.text) *(.fixup) *(.gnu.warning) @@ -65,9 +67,6 @@ . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - . = ALIGN(4096); - .data.disk_image : { *(.data.disk_image) } . = ALIGN(4); ___bss_start = .; /* BSS */ diff -u --recursive --new-file v2.3.22/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.3.22/linux/arch/sparc/mm/init.c Fri Sep 10 23:57:28 1999 +++ linux/arch/sparc/mm/init.c Sat Oct 16 10:50:48 1999 @@ -106,6 +106,7 @@ printk("%ld page tables cached\n",pgtable_cache_size); if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d) printk("%ld page dirs cached\n", pgd_cache_size); + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif diff -u --recursive --new-file v2.3.22/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.3.22/linux/arch/sparc64/mm/init.c Fri Sep 10 23:57:28 1999 +++ linux/arch/sparc64/mm/init.c Sat Oct 16 10:50:48 1999 @@ -150,6 +150,7 @@ #ifndef __SMP__ printk("%d entries in page dir cache\n",pgd_cache_size); #endif + show_buffers(); #ifdef CONFIG_NET show_net_buffers(); #endif diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/Makefile linux/drivers/acorn/Makefile --- v2.3.22/linux/drivers/acorn/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/Makefile Wed Oct 20 16:29:08 1999 @@ -0,0 +1,12 @@ +# +# Makefile for the Acorn-specific Linux kernel device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (not a .c file). + +SUB_DIRS := block char net scsi +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/README linux/drivers/acorn/README --- v2.3.22/linux/drivers/acorn/README Mon Feb 16 15:49:47 1998 +++ linux/drivers/acorn/README Wed Oct 20 16:29:08 1999 @@ -1,3 +1 @@ Drivers for the ACORN "podule" ARM specific bus. - - diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/block/Makefile linux/drivers/acorn/block/Makefile --- v2.3.22/linux/drivers/acorn/block/Makefile Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/block/Makefile Wed Oct 20 16:29:08 1999 @@ -32,17 +32,11 @@ include $(TOPDIR)/Rules.make +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< + fd1772_mod.o: $(FLOPPY) $(LD) -r -o $@ $(FLOPPY) mfmhd_mod.o: mfmhd.o mfm.o $(LD) -r -o $@ mfmhd.o mfm.o - -%.o: %.S -ifndef $(CONFIG_BINUTILS_NEW) - $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s - $(CC) $(CFLAGS) -c -o $@ ..tmp.s - $(RM) ..tmp.s -else - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< -endif diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c --- v2.3.22/linux/drivers/acorn/char/keyb_arc.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/acorn/char/keyb_arc.c Wed Oct 20 16:29:08 1999 @@ -31,7 +31,7 @@ #include #include -#include "../../char/mouse.h" +#include "../../char/busmouse.h" extern void kbd_reset_kdown(void); @@ -47,7 +47,7 @@ static unsigned char kbd_txhead, kbd_txtail; #define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3) static int kbd_id = -1; -static struct wait_queue *kbd_waitq; +static DECLARE_WAIT_QUEUE_HEAD(kbd_waitq); #ifdef CONFIG_KBDMOUSE static int mousedev; #endif diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.3.22/linux/drivers/acorn/net/ether1.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/acorn/net/ether1.c Wed Oct 20 16:29:08 1999 @@ -255,7 +255,7 @@ } static int __init -ether1_ramtest (struct net_device *dev, unsigned char byte) +ether1_ramtest(struct net_device *dev, unsigned char byte) { unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); int i, ret = BUFFER_SIZE; @@ -309,7 +309,7 @@ } static int __init -ether1_init_2 (struct net_device *dev) +ether1_init_2(struct net_device *dev) { int i; dev->mem_start = 0; @@ -613,7 +613,7 @@ } static int __init -ether1_probe1 (struct net_device *dev) +ether1_probe1(struct net_device *dev) { static unsigned int version_printed = 0; struct ether1_priv *priv; @@ -665,7 +665,7 @@ /* ------------------------------------------------------------------------- */ static void __init -ether1_addr (struct net_device *dev) +ether1_addr(struct net_device *dev) { int i; @@ -674,7 +674,7 @@ } int __init -ether1_probe (struct net_device *dev) +ether1_probe(struct net_device *dev) { #ifndef MODULE struct expansion_card *ec; diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/net/net-probe.c linux/drivers/acorn/net/net-probe.c --- v2.3.22/linux/drivers/acorn/net/net-probe.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/acorn/net/net-probe.c Wed Dec 31 16:00:00 1969 @@ -1,31 +0,0 @@ -/* - * Acorn specific net device driver probe routine - * - * Copyright (C) 1998 Russell King - */ -#include -#include -#include -#include - -extern int ether1_probe (struct net_device *dev); -extern int ether3_probe (struct net_device *dev); -extern int etherh_probe (struct net_device *dev); - -int __init acorn_ethif_probe(struct net_device *dev) -{ - if (1 -#ifdef CONFIG_ARM_ETHERH - && etherh_probe (dev) -#endif -#ifdef CONFIG_ARM_ETHER3 - && ether3_probe (dev) -#endif -#ifdef CONFIG_ARM_ETHER1 - && ether1_probe (dev) -#endif - && 1) { - return 1; - } - return 0; -} diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/scsi/Makefile linux/drivers/acorn/scsi/Makefile --- v2.3.22/linux/drivers/acorn/scsi/Makefile Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/scsi/Makefile Wed Oct 20 16:29:08 1999 @@ -108,14 +108,8 @@ 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 - -%.o: %.S -ifndef $(CONFIG_BINUTILS_NEW) - $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.$<.s - $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.$<.s - $(RM) ..tmp.$<.s -else - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< -endif diff -u --recursive --new-file v2.3.22/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.22/linux/drivers/block/Config.in Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/Config.in Mon Oct 18 11:26:31 1999 @@ -62,17 +62,15 @@ fi if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then - bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then + bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA fi bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 fi if [ "$CONFIG_X86" = "y" ]; then bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_PIIX" = "y" ]; then - bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING + if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then + bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING fi fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then @@ -83,19 +81,20 @@ fi if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX - if [ "$CONFIG_EXPERIMENTAL" = "y" -a \ - "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then - bool ' Special UDMA Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_BURST_BIT - bool ' Special Mode Feature (DANGEROUS)' CONFIG_PDC202XX_FORCE_MASTER_MODE + if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then + bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE + fi + fi + if [ "$CONFIG_X86" = "y" ]; then + bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 fi - fi - if [ "$CONFIG_X86" = "y" ]; then - bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 if [ "$CONFIG_X86" = "y" ]; then - bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX fi fi fi @@ -139,8 +138,7 @@ bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B - if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \ - "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 fi bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 @@ -225,6 +223,7 @@ "$CONFIG_BLK_DEV_HPT366" = "y" -o \ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ + "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then diff -u --recursive --new-file v2.3.22/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.22/linux/drivers/block/Makefile Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/Makefile Mon Oct 18 11:14:22 1999 @@ -230,8 +230,8 @@ IDE_OBJS += umc8672.o endif -ifeq ($(CONFIG_BLK_DEV_VIA82C586),y) -IDE_OBJS += via82c586.o +ifeq ($(CONFIG_BLK_DEV_VIA82CXXX),y) +IDE_OBJS += via82cxxx.o endif ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored @@ -379,4 +379,3 @@ ide-probe-mod.o: ide-probe.o ide-geometry.o $(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o - diff -u --recursive --new-file v2.3.22/linux/drivers/block/aec6210.c linux/drivers/block/aec6210.c --- v2.3.22/linux/drivers/block/aec6210.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/aec6210.c Mon Oct 18 11:14:22 1999 @@ -1,7 +1,8 @@ /* - * linux/drivers/block/aec6210.c Version 0.01 Nov 17, 1998 + * linux/drivers/block/aec6210.c Version 0.02 Sept. 3, 1999 * - * Copyright (C) 1998-99 Andre Hedrick + * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License * * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 * pio 1 :: 40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02 @@ -49,6 +50,10 @@ #include #include + +/* + * TO DO: active tuning and correction of cards without a bios. + */ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) { diff -u --recursive --new-file v2.3.22/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c --- v2.3.22/linux/drivers/block/alim15x3.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/alim15x3.c Mon Oct 18 11:14:22 1999 @@ -1,21 +1,28 @@ /* - * linux/drivers/block/alim15x3.c Version 0.05 Jun. 29, 1999 + * linux/drivers/block/alim15x3.c Version 0.06 Sept. 3, 1999 * * Copyright (C) 1998-99 Michel Aubry, Maintainer * Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer - * Copyright (C) 1998-99 Andre Hedrick, Integrater and Maintainer * - * (U)DMA capable version of ali 1533/1543(C) + * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License * - * Default disable (U)DMA on all devices execpt hard disks. - * This measure of overkill is needed to stablize the chipset code. + * (U)DMA capable version of ali 1533/1543(C), 1535(D) * + * version: 1.0 beta2 (Sep. 2, 1999) + * e-mail your problems to cjtsai@ali.com.tw + * + ********************************************************************** + * 9/7/99 --Parts from the above author are included and need to be + * converted into standard interface, once I finish the thought. */ #include #include #include #include +#include +#include #include #include @@ -59,188 +66,7 @@ "error DRQ ", "error DRQ busy" }; -#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - -static void ali15x3_tune_drive (ide_drive_t *drive, byte pio) -{ - ide_pio_data_t d; - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int s_time, a_time, c_time; - byte s_clc, a_clc, r_clc; - unsigned long flags; - int bus_speed = ide_system_bus_speed(); - int port = hwif->index ? 0x5c : 0x58; - - pio = ide_get_best_pio_mode(drive, pio, 5, &d); - s_time = ide_pio_timings[pio].setup_time; - a_time = ide_pio_timings[pio].active_time; - if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) - s_clc = 0; - if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8) - a_clc = 0; - c_time = ide_pio_timings[pio].cycle_time; - -#if 0 - if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16) - r_clc = 0; -#endif - - if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) { - r_clc = 1; - } else { - if (r_clc >= 16) - r_clc = 0; - } - save_flags(flags); - cli(); - pci_write_config_byte(dev, port, s_clc); - pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); - restore_flags(flags); - - /* - * setup active rec - * { 70, 165, 365 }, PIO Mode 0 - * { 50, 125, 208 }, PIO Mode 1 - * { 30, 100, 110 }, PIO Mode 2 - * { 30, 80, 70 }, PIO Mode 3 with IORDY - * { 25, 70, 25 }, PIO Mode 4 with IORDY ns - * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) - */ - -} - -unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) -{ - byte confreg0 = 0, confreg1 =0, progif = 0; - int errors = 0; - - if (pci_read_config_byte(dev, 0x50, &confreg1)) - goto veryspecialsettingserror; - if (!(confreg1 & 0x02)) - if (pci_write_config_byte(dev, 0x50, confreg1 | 0x02)) - goto veryspecialsettingserror; - - if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) - goto veryspecialsettingserror; - if (!(progif & 0x40)) { - /* - * The way to enable them is to set progif - * writable at 0x4Dh register, and set bit 6 - * of progif to 1: - */ - if (pci_read_config_byte(dev, 0x4d, &confreg0)) - goto veryspecialsettingserror; - if (confreg0 & 0x80) - if (pci_write_config_byte(dev, 0x4d, confreg0 & ~0x80)) - goto veryspecialsettingserror; - if (pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x40)) - goto veryspecialsettingserror; - if (confreg0 & 0x80) - if (pci_write_config_byte(dev, 0x4d, confreg0)) - errors++; - } - - if ((pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) || (!(progif & 0x40))) - goto veryspecialsettingserror; - - printk("%s: enabled read of IDE channels state (en/dis-abled) %s.\n", - name, errors ? "with Error(s)" : "Succeeded" ); - return 0; - -veryspecialsettingserror: - printk("%s: impossible to enable read of IDE channels state (en/dis-abled)!\n", name); - return 0; -} - -int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) -{ - switch (func) { - case ide_dma_check: - if (drive->media == ide_cdrom) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - struct hd_driveid *id = drive->id; - byte cd_dma_fifo = 0; - - pci_read_config_byte(dev, 0x53, &cd_dma_fifo); - - if (((id->field_valid & 4) || (id->field_valid & 2)) && - (id->capability & 1) && hwif->autodma) { - unsigned long dma_set_bit = hwif->dma_base + 2; -#if 0 - if (cd_dma_fifo & 0x02) - pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x02); - pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01); -#else - pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01|0x02); -#endif - if (drive->select.b.unit & 0x01) { - outb(inb(dma_set_bit)|0x40, dma_set_bit); - } else { - outb(inb(dma_set_bit)|0x20, dma_set_bit); - } - } else { - if (cd_dma_fifo & 0x01) - pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x01); - pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x02); - } - } else if (drive->media != ide_disk) { - return ide_dmaproc(ide_dma_off_quietly, drive); - } - default: - break; - } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ -} - -void __init ide_init_ali15x3 (ide_hwif_t *hwif) -{ - struct pci_dev *dev; - byte ideic, inmir, iderev; - byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, - 1, 11, 0, 12, 0, 14, 0, 15 }; - - pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &iderev); - - hwif->irq = hwif->channel ? 15 : 14; - for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */ - if (dev->vendor==PCI_VENDOR_ID_AL && - dev->device==PCI_DEVICE_ID_AL_M1533) - break; - if (dev) { - pci_read_config_byte(dev, 0x58, &ideic); - ideic = ideic & 0x03; - if ((hwif->channel && ideic == 0x03) || - (!hwif->channel && !ideic)) { - pci_read_config_byte(dev, 0x44, &inmir); - inmir = inmir & 0x0f; - hwif->irq = irq_routing_table[inmir]; - } else - if (hwif->channel && !(ideic & 0x01)) { - pci_read_config_byte(dev, 0x75, &inmir); - inmir = inmir & 0x0f; - hwif->irq = irq_routing_table[inmir]; - } - } -#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) - bmide_dev = hwif->pci_dev; - ali_display_info = &ali_get_info; -#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - hwif->tuneproc = &ali15x3_tune_drive; - if ((hwif->dma_base) && (iderev >= 0xC1)) { - /* M1543C or newer for DMAing */ - hwif->dmaproc = &ali15x3_dmaproc; - } else { - hwif->autodma = 0; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - } - return; -} - -#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy) { byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1; @@ -407,3 +233,540 @@ return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + +static byte m5229_revision = 0; +static byte chip_is_1543c_e = 0; +static byte cable_80_pin[2] = { 0, 0 }; + +byte ali_proc = 0; +static struct pci_dev *isa_dev; + +static void ali15x3_tune_drive (ide_drive_t *drive, byte pio) +{ + ide_pio_data_t d; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int s_time, a_time, c_time; + byte s_clc, a_clc, r_clc; + unsigned long flags; + int bus_speed = ide_system_bus_speed(); + int port = hwif->index ? 0x5c : 0x58; + + pio = ide_get_best_pio_mode(drive, pio, 5, &d); + s_time = ide_pio_timings[pio].setup_time; + a_time = ide_pio_timings[pio].active_time; + if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) + s_clc = 0; + if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8) + a_clc = 0; + c_time = ide_pio_timings[pio].cycle_time; + +#if 0 + if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16) + r_clc = 0; +#endif + + if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) { + r_clc = 1; + } else { + if (r_clc >= 16) + r_clc = 0; + } + save_flags(flags); + cli(); + pci_write_config_byte(dev, port, s_clc); + pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); + restore_flags(flags); + + /* + * setup active rec + * { 70, 165, 365 }, PIO Mode 0 + * { 50, 125, 208 }, PIO Mode 1 + * { 30, 100, 110 }, PIO Mode 2 + * { 30, 80, 70 }, PIO Mode 3 with IORDY + * { 25, 70, 25 }, PIO Mode 4 with IORDY ns + * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) + */ + +} + +static __inline__ unsigned char dma2_bits_to_command(unsigned char bits) +{ + if (bits & 0x04) + return XFER_MW_DMA_2; + if (bits & 0x02) + return XFER_MW_DMA_1; + return XFER_MW_DMA_0; +} + +static __inline__ unsigned char udma2_bits_to_command(unsigned char bits) +{ + if (bits & 0x10) + return XFER_UDMA_4; + if (bits & 0x08) + return XFER_UDMA_3; + if (bits & 0x04) + return XFER_UDMA_2; + if (bits & 0x02) + return XFER_UDMA_1; + return XFER_UDMA_0; +} + +static __inline__ int wait_for_ready(ide_drive_t *drive) +{ + int timeout = 20000; /* (old value: 100) */ + byte stat; + + while (--timeout) { + stat = GET_STAT(); + /* + * printk("STAT(%2x) ", stat); + */ + if (!(stat & BUSY_STAT)) { + if ((stat & READY_STAT) || (stat & ERR_STAT)) { + break; + } + } + /* + * (old value: 100) + */ + udelay(150); + } + if ((stat & ERR_STAT) || timeout <= 0) + return 1; + return 0; +} + +static void ali15x3_do_setfeature(ide_drive_t *drive, byte command) +{ + unsigned long flags; + byte old_select; + + save_flags(flags); + cli(); + + /* save old selected device */ + old_select = IN_BYTE(IDE_SELECT_REG); + /* "SELECT " */ + OUT_BYTE(drive->select.all, IDE_SELECT_REG); + /* "SETXFER " */ + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + /* "CMND " */ + OUT_BYTE(command, IDE_NSECTOR_REG); + + if(wait_for_ready(drive)) /* "wait " */ + goto out; + + /* "SETFEATURE " */ + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + /* "wait " */ + (void) wait_for_ready(drive); + +out: + /* + * restore to old "selected device" + */ + OUT_BYTE(old_select, IDE_SELECT_REG); + restore_flags(flags); +} + +static void ali15x3_dma2_enable(ide_drive_t *drive, unsigned long dma_base) +{ + byte unit = (drive->select.b.unit & 0x01); + byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07; + byte tmpbyte; + ide_hwif_t *hwif = HWIF(drive); + unsigned long flags; + int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56; + + ali15x3_do_setfeature(drive, dma2_bits_to_command(bits)); + + /* + * clear "ultra enable" bit + */ + pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte); + if (unit) { + tmpbyte &= 0x7f; + } else { + tmpbyte &= 0xf7; + } + save_flags(flags); + cli(); + pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte); + restore_flags(flags); + drive->id->dma_ultra = 0x00; + + /* + * Enable DMA + */ + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + printk("ALI15X3: MultiWord DMA enabled\n"); +} + +static void ali15x3_udma_enable(ide_drive_t *drive, unsigned long dma_base) +{ + byte unit = (drive->select.b.unit & 0x01); + byte bits = drive->id->dma_ultra & 0x1f; + byte tmpbyte; + ide_hwif_t *hwif = HWIF(drive); + unsigned long flags; + unsigned char udma_mode = 0; + int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56; + + if (bits & 0x18) { + /* + * 00011000, disk: ultra66 + */ + if (m5229_revision < 0xc2) { + /* + * controller: ultra33 + */ + bits = 0x04; + /* + * 00000100, use ultra33, mode 2 + */ + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0004; + } else { + /* + * controller: ultra66 + * + * Try to detect word93 bit13 and + * 80-pin cable (from host view) + */ + if (!((drive->id->word93 & 0x2000) && + cable_80_pin[hwif->channel])) { + bits = 0x04; + /* + * 00000100, use ultra33, mode 2 + */ + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0004; + } + } + } + + /* + * set feature regardless + */ + ali15x3_do_setfeature(drive, udma_mode = udma2_bits_to_command(bits)); + udma_mode &= 0x0f; /* get UDMA mode */ + + /* + * Enable DMA and UltraDMA + */ + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + /* + * m5229 ultra + */ + pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte); + /* + * clear bit0~3 or bit 4~7 + */ + tmpbyte &= (0x0f << ((1-unit) << 2)); + /* + * enable ultra dma and set timing + */ + tmpbyte |= ((0x08 | (4-udma_mode)) << (unit << 2)); + /* + * set to m5229 + */ + save_flags(flags); + cli(); + pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte); + restore_flags(flags); + + if (udma_mode >= 3) { + /* + * ultra 66 + */ + pci_read_config_byte(hwif->pci_dev, 0x4b, &tmpbyte); + tmpbyte |= 1; + save_flags(flags); + cli(); + pci_write_config_byte(hwif->pci_dev, 0x4b, tmpbyte); + restore_flags(flags); + } + + printk("ALI15X3: Ultra DMA enabled\n"); +} + +static int ali15x3_dma_onoff(ide_drive_t *drive, int enable) +{ + if (enable) { + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + struct hd_driveid *id = drive->id; + + if ((id->field_valid & 0x0004) && + (id->dma_ultra & 0x001f)) { + /* + * 1543C_E, in ultra mode, WDC "harddisk" + * will cause "CRC" errors (even if no CRC problem), + * so we try to use "DMA" here + */ + if (m5229_revision <= 0x20) { + /* + * Normal MultiWord DMA modes. + */ + ali15x3_dma2_enable(drive, dma_base); + } else if ((m5229_revision < 0xC2) && + ((drive->media!=ide_disk) || + (chip_is_1543c_e && + strstr(id->model, "WDC ")))) { + /* + * Normal MultiWord DMA modes. + */ + ali15x3_dma2_enable(drive, dma_base); + } else { + /* + * m5229_revision >= 0xC2 for UltraDMA modes. + */ + ali15x3_udma_enable(drive, dma_base); + } + } else { + /* + * Normal MultiWord DMA modes. + */ + ali15x3_dma2_enable(drive, dma_base); + } + } + + drive->using_dma = enable; /* on, off */ + return 0; +} + +static int ali15x3_config_drive_for_dma(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + + if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) + return hwif->dmaproc(ide_dma_off_quietly, drive); + /* + * Even if the drive is not _currently_ in a DMA + * mode, we succeed, and we'll enable it manually + * below in alim15x3_dma_onoff + */ + if ((id != NULL) && (id->capability & 1) && hwif->autodma) { + if (id->field_valid & 0x0004) { + if (id->dma_ultra & 0x001F) + return hwif->dmaproc(ide_dma_on, drive); + } + if (id->field_valid & 0x0002) { + if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) + return hwif->dmaproc(ide_dma_on, drive); + } + } + return hwif->dmaproc(ide_dma_off_quietly, drive); +} + +static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch(func) { + case ide_dma_check: + return ali15x3_config_drive_for_dma(drive); + case ide_dma_on: + case ide_dma_off: + case ide_dma_off_quietly: + return ali15x3_dma_onoff(drive, (func == ide_dma_on)); + case ide_dma_write: + if ((m5229_revision < 0xC2) && (drive->media != ide_disk)) + return 1; /* try PIO instead of DMA */ + break; + default: + break; + } + + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) +{ + struct pci_dev *isa; + unsigned long fixdma_base = dev->resource[4].start; + byte tmpbyte; + + pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision); + + for (isa = pci_devices; isa; isa=isa->next) { + /* + * look for ISA bridge + */ + if (isa->vendor == PCI_VENDOR_ID_AL && + isa->device == PCI_DEVICE_ID_AL_M1533) { + isa_dev = isa; + break; + } + } + + if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) { + /* + * + */ + } else { + /* + * enable DMA capable bit, and "not" simplex only + */ + outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); + + if (inb(fixdma_base+2) & 0x80) + printk("%s: simplex device: DMA will fail!!\n", name); + } + + /* + * FIXME !!! This detection needs to be in "ata66_ali15x3()" + * below as a standard detection return. + */ + + if (m5229_revision >= 0xC2) { + unsigned long flags; + /* + * 1543C-B?, 1535, 1535D, 1553 + * Note 1: not all "motherboard" support this detection + * Note 2: if no udma 66 device, the detection may "error". + * but in this case, we will not set the device to + * ultra 66, the detection result is not important + */ + save_flags(flags); + cli(); + + /* + * enable "Cable Detection", m5229, 0x4b, bit3 + */ + pci_read_config_byte(dev, 0x4b, &tmpbyte); + pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08); + + /* + * set south-bridge's enable bit, m1533, 0x79 + */ + pci_read_config_byte(isa_dev, 0x79, &tmpbyte); + if (m5229_revision == 0xC2) { + /* + * 1543C-B0 (m1533, 0x79, bit 2) + */ + pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04); + } else if (m5229_revision == 0xC3) { + /* + * 1553/1535 (m1533, 0x79, bit 1) + */ + pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02); + } + restore_flags(flags); + /* + * Ultra66 cable detection (from Host View) + * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin + */ + pci_read_config_byte(dev, 0x4a, &tmpbyte); + /* + * 0x4a, bit0 is 0 => primary channel + * has 80-pin (from host view) + */ + if (!(tmpbyte & 0x01)) + cable_80_pin[0] = 1; + /* + * 0x4a, bit1 is 0 => secondary channel + * has 80-pin (from host view) + */ + if (!(tmpbyte & 0x02)) + cable_80_pin[1] = 1; + } else { + unsigned long flags; + /* + * revision 0x20 (1543-E, 1543-F) + * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E) + * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7 + */ + pci_read_config_byte(dev, 0x4b, &tmpbyte); + save_flags(flags); + cli(); + /* + * clear bit 7 + */ + pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F); + restore_flags(flags); + + /* + * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010 + */ + pci_read_config_byte(isa_dev, 0x5e, &tmpbyte); + chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0; + } + + return 0; +} + +unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif) +{ + /* + * FIXME !!!! + * {0x4a,0x01,0x01}, {0x4a,0x02,0x02} + */ + return 0; +} + +void __init ide_init_ali15x3 (ide_hwif_t *hwif) +{ + byte ideic, inmir; + byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, + 1, 11, 0, 12, 0, 14, 0, 15 }; + + hwif->irq = hwif->channel ? 15 : 14; + + if (isa_dev) { + /* + * read IDE interface control + */ + pci_read_config_byte(isa_dev, 0x58, &ideic); + + /* bit0, bit1 */ + ideic = ideic & 0x03; + + /* get IRQ for IDE Controller */ + if ((hwif->channel && ideic == 0x03) || + (!hwif->channel && !ideic)) { + /* + * get SIRQ1 routing table + */ + pci_read_config_byte(isa_dev, 0x44, &inmir); + inmir = inmir & 0x0f; + hwif->irq = irq_routing_table[inmir]; + } else if (hwif->channel && !(ideic & 0x01)) { + /* + * get SIRQ2 routing table + */ + pci_read_config_byte(isa_dev, 0x75, &inmir); + inmir = inmir & 0x0f; + hwif->irq = irq_routing_table[inmir]; + } + } + + hwif->tuneproc = &ali15x3_tune_drive; + if ((hwif->dma_base) && (m5229_revision >= 0xC1)) { + /* + * 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; + } + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) + ali_proc = 1; + bmide_dev = hwif->pci_dev; + ali_display_info = &ali_get_info; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + + return; +} + +void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) +{ + if ((dmabase) && (m5229_revision < 0x20)) { + return; + } + ide_setup_dma(hwif, dmabase, 8); +} diff -u --recursive --new-file v2.3.22/linux/drivers/block/cy82c693.c linux/drivers/block/cy82c693.c --- v2.3.22/linux/drivers/block/cy82c693.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/cy82c693.c Mon Oct 18 11:14:22 1999 @@ -1,8 +1,8 @@ /* - * linux/drivers/block/cy82c693.c Version 0.33 Jan. 23, 1999 + * linux/drivers/block/cy82c693.c Version 0.34 Sept 3, 1999 * - * Copyright (C) 1998, 1999 Andreas S. Krebs (akrebs@altavista.net), Maintainer - * Copyright (C) 1998 Andre Hedrick, Integrater + * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer + * Copyright (C) 1998-99 Andre Hedrick, Integrater * * CYPRESS CY82C693 chipset IDE controller * @@ -31,6 +31,7 @@ * * * History: + * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693 * ASK@1999-01-23: v0.33 made a few minor code clean ups * removed DMA clock speed setting by default * added boot message @@ -53,7 +54,7 @@ #include "ide_modes.h" /* the current version */ -#define CY82_VERSION "CY82C693U driver v0.33 99-01-23 Andreas S. Krebs (akrebs@altavista.net)" +#define CY82_VERSION "CY82C693U driver v0.34 99-09-03 Andreas S. Krebs (akrebs@altavista.net)" /* * The following are used to debug the driver. @@ -377,20 +378,10 @@ unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name) { - return 0; -} - -static void init_cy82c693_chip (struct pci_dev *dev) -{ - static int initDone = 0; #ifdef CY82C693_SETDMA_CLOCK byte data; #endif /* CY82C693_SETDMA_CLOCK */ - if (initDone != 0) /* only perform setup once */ - return; - initDone = 1; - /* write info about this verion of the driver */ printk (KERN_INFO CY82_VERSION "\n"); @@ -401,7 +392,7 @@ data = IN_BYTE(CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "CY82U693: Peripheral Configuration Register: 0x%X\n", data); + printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data); #endif /* CY82C693_DEBUG_INFO */ /* @@ -422,10 +413,11 @@ OUT_BYTE(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "CY82U693: New Peripheral Configuration Register: 0x%X\n", data); + printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data); #endif /* CY82C693_DEBUG_INFO */ -#endif /* CY82C693_SETDMA_CLOCK */ +#endif /* CY82C693_SETDMA_CLOCK */ + return 0; } /* @@ -437,7 +429,5 @@ if (hwif->dma_base) hwif->dmaproc = &cy82c693_dmaproc; hwif->tuneproc = &cy82c693_tune_drive; - - init_cy82c693_chip(hwif->pci_dev); } diff -u --recursive --new-file v2.3.22/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.3.22/linux/drivers/block/genhd.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/genhd.c Tue Oct 19 13:47:59 1999 @@ -26,6 +26,8 @@ extern void console_map_init(void); extern int soc_probe(void); extern int atmdev_init(void); +extern int i2o_init(void); +extern int cpqarray_init(void); void __init device_init(void) { diff -u --recursive --new-file v2.3.22/linux/drivers/block/hpt34x.c linux/drivers/block/hpt34x.c --- v2.3.22/linux/drivers/block/hpt34x.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/hpt34x.c Mon Oct 18 11:14:22 1999 @@ -1,7 +1,9 @@ /* - * linux/drivers/block/hpt34x.c Version 0.25 July 11, 1999 + * linux/drivers/block/hpt34x.c Version 0.27 Sept 03, 1999 + * + * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License * - * Copyright (C) 1998-99 Andre Hedrick * * 00:12.0 Unknown mass storage controller: * Triones Technologies, Inc. @@ -14,9 +16,6 @@ * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) * - * drive_number - * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); */ #include @@ -58,7 +57,7 @@ pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); - tmp2 = ((0x00 << drive_number) | reg2); + tmp2 = (reg2 & ~(0x11 << drive_number)); pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); } @@ -105,7 +104,7 @@ * after the drive is reported by the OS. Initally for designed for * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. */ -static int config_chipset_for_dma (ide_drive_t *drive) +static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) { struct hd_driveid *id = drive->id; byte speed = 0x00; @@ -117,76 +116,29 @@ return ((int) ide_dma_off_quietly); #endif /* HPT343_DISABLE_ALL_DMAING */ - if (id->dma_ultra & 0x0010) { - goto backspeed; - } else if (id->dma_ultra & 0x0008) { - goto backspeed; - } else if (id->dma_ultra & 0x0004) { -backspeed: - if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } + hpt34x_clear_chipset(drive); + + if ((id->dma_ultra & 0x0010) && ultra) { speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } + } else if ((id->dma_ultra & 0x0008) && ultra) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0004) && ultra) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && ultra) { speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } + } else if ((id->dma_ultra & 0x0001) && ultra) { speed = XFER_UDMA_0; } else if (id->dma_mword & 0x0004) { - if (!((id->dma_mword >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0404; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_2; } else if (id->dma_mword & 0x0002) { - if (!((id->dma_mword >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0202; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { - if (!((id->dma_mword >> 8) & 1)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0101; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_0; } else if (id->dma_1word & 0x0004) { - if (!((id->dma_1word >> 8) & 4)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_2; } else if (id->dma_1word & 0x0002) { - if (!((id->dma_1word >> 8) & 2)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_1; } else if (id->dma_1word & 0x0001) { - if (!((id->dma_1word >> 8) & 1)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_0; } else { return ((int) ide_dma_off_quietly); @@ -242,7 +194,6 @@ { byte speed; - hpt34x_clear_chipset(drive); switch(pio) { case 4: speed = XFER_PIO_4;break; case 3: speed = XFER_PIO_3;break; @@ -250,6 +201,7 @@ case 1: speed = XFER_PIO_1;break; default: speed = XFER_PIO_0;break; } + hpt34x_clear_chipset(drive); (void) hpt34x_tune_chipset(drive, speed); } @@ -268,7 +220,7 @@ if (id->field_valid & 4) { if (id->dma_ultra & 0x0007) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive); + dma_func = config_chipset_for_dma(drive, 1); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -278,7 +230,7 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive); + dma_func = config_chipset_for_dma(drive, 0); if (dma_func != ide_dma_on) goto no_dma_set; } @@ -287,7 +239,7 @@ goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive); + dma_func = config_chipset_for_dma(drive, 0); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -300,6 +252,12 @@ config_chipset_for_pio(drive); } + +#if 0 + if (dma_func == ide_dma_on) + dma_func = ide_dma_off; +#endif + return HWIF(drive)->dmaproc(dma_func, drive); } @@ -313,22 +271,44 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); + unsigned int count, reading = 0; + byte dma_stat; + switch (func) { - case ide_dma_check: - hpt34x_clear_chipset(drive); - return config_drive_xfer_rate(drive); -#if 0 case ide_dma_off: case ide_dma_off_quietly: + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + break; case ide_dma_on: + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + break; case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_read: + reading = 1 << 3; case ide_dma_write: - case ide_dma_begin: - case ide_dma_end: - case ide_dma_test_irq: -#endif + if (!(count = ide_build_dmatable(drive, func))) + return 1; /* try PIO instead of DMA */ + outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */ + reading |= 0x01; + outb(reading, dma_base); /* specify r/w */ + outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + drive->waiting_for_dma = 1; + if (drive->media != ide_disk) + return 0; + drive->timeout = WAIT_CMD; + ide_set_handler(drive, &ide_dma_intr); /* issue cmd to drive */ + OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + return 0; + case ide_dma_end: /* returns 1 on error, 0 otherwise */ + drive->waiting_for_dma = 0; + outb(inb(dma_base)&~1, dma_base); /* stop DMA */ + dma_stat = inb(dma_base+2); /* get DMA status */ + outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ + return (dma_stat & 7) != 4; /* verify good DMA status */ default: break; } @@ -342,10 +322,17 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) { + int i = 0; + unsigned long hpt34xIoBase = dev->resource[4].start; unsigned short cmd; + unsigned long flags; + + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_MEMORY) { 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); @@ -353,27 +340,28 @@ } pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } else { - int i = 0; - unsigned long hpt34xIoBase = dev->resource[4].start; - - pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); - dev->resource[0].start = (hpt34xIoBase + 0x20); - dev->resource[1].start = (hpt34xIoBase + 0x34); - dev->resource[2].start = (hpt34xIoBase + 0x28); - dev->resource[3].start = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; - /* - * Since 20-23 can be assigned and are R/W, we correct them. - */ - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); - - pci_write_config_word(dev, PCI_COMMAND, cmd); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } + + pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); + dev->resource[0].start = (hpt34xIoBase + 0x20); + dev->resource[1].start = (hpt34xIoBase + 0x34); + dev->resource[2].start = (hpt34xIoBase + 0x28); + dev->resource[3].start = (hpt34xIoBase + 0x3c); + for(i=0; i<4; i++) + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; + /* + * Since 20-23 can be assigned and are R/W, we correct them. + */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); + + pci_write_config_word(dev, PCI_COMMAND, cmd); + + __restore_flags(flags); /* local CPU only */ + return dev->irq; } diff -u --recursive --new-file v2.3.22/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c --- v2.3.22/linux/drivers/block/hpt366.c Tue Sep 7 12:14:06 1999 +++ linux/drivers/block/hpt366.c Mon Oct 18 11:14:22 1999 @@ -1,11 +1,13 @@ /* - * linux/drivers/block/hpt366.c Version 0.12 August 16, 1999 + * linux/drivers/block/hpt366.c Version 0.13 Sept. 3, 1999 * * Copyright (C) 1999 Andre Hedrick + * May be copied or modified under the terms of the GNU General Public License * - * drive_number - * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * Thanks to HighPoint Technologies for their assistance, and hardware. + * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his + * donation of an ABit BP6 mainboard, processor, and memory acellerated + * development and support. */ #include @@ -114,17 +116,18 @@ }; #define HPT366_DEBUG_DRIVE_INFO 0 -#define HPT366_ALLOW_ATA66_4 0 +#define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 -#define HPT366_ALLOW_ATA33_2 1 -#define HPT366_ALLOW_ATA33_1 1 -#define HPT366_ALLOW_ATA33_0 1 extern char *ide_xfer_verbose (byte xfer_rate); +byte hpt363_shared_irq = 0; static int check_in_drive_lists (ide_drive_t *drive, const char **list) { struct hd_driveid *id = drive->id; +#if HPT366_DEBUG_DRIVE_INFO + printk("check_in_drive_lists(%s, %p)\n", drive->name, list); +#endif /* HPT366_DEBUG_DRIVE_INFO */ while (*list) { if (!strcmp(*list++,id->model)) { @@ -139,50 +142,62 @@ static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { +#if HPT366_DEBUG_DRIVE_INFO + printk("pci_bus_clock_list(speed=0x%02x, table=%p)\n", speed, chipset_table); +#endif /* HPT366_DEBUG_DRIVE_INFO */ for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) + if (chipset_table->xfer_speed == speed) { +#if HPT366_DEBUG_DRIVE_INFO + printk("pci_bus_clock_list: found match: 0x%08x\n", chipset_table->chipset_settings); +#endif /* HPT366_DEBUG_DRIVE_INFO */ return chipset_table->chipset_settings; + } +#if HPT366_DEBUG_DRIVE_INFO + printk("pci_bus_clock_list: using default: 0x%08x\n", 0x01208585); +#endif /* HPT366_DEBUG_DRIVE_INFO */ return 0x01208585; } static int hpt366_tune_chipset (ide_drive_t *drive, byte speed) { int err; - byte busclock; - #if HPT366_DEBUG_DRIVE_INFO int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); #endif /* HPT366_DEBUG_DRIVE_INFO */ - byte regtime = (drive->select.b.unit & 0x01) ? 0x43 : 0x40; + byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; unsigned int reg1 = 0; unsigned int reg2 = 0; +#if HPT366_DEBUG_DRIVE_INFO + printk("hpt366_tune_chipset(%s, speed=0x%02x)\n", drive->name, speed); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + pci_read_config_dword(HWIF(drive)->pci_dev, regtime, ®1); - pci_read_config_byte(HWIF(drive)->pci_dev, regtime|0x01, &busclock); - switch(busclock) { - case 0xd9: + /* detect bus speed by looking at control reg timing: */ + switch((reg1 >> 8) & 7) { + case 5: reg2 = pci_bus_clock_list(speed, forty_base); break; - case 0x85: + case 9: reg2 = pci_bus_clock_list(speed, twenty_five_base); break; - case 0xa7: default: + printk("hpt366: assuming 33Mhz PCI bus\n"); + case 7: reg2 = pci_bus_clock_list(speed, thirty_three_base); break; } - - if (drive->id->dword_io & 1) - reg2 |= 0x80000000; - else - reg2 &= ~0x80000000; + /* + * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later) + */ + reg2 &= ~0x80000000; pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2); err = ide_config_drive_speed(drive, speed); #if HPT366_DEBUG_DRIVE_INFO - printk("%s: %s drive%d (0x%08x 0x%08x) 0x%04x\n", - drive->name, ide_xfer_verbose(speed), + printk("%s: speed=0x%02x(%s), drive%d, old=0x%08x, new=0x%08x, err=0x%04x\n", + drive->name, speed, ide_xfer_verbose(speed), drive_number, reg1, reg2, err); #endif /* HPT366_DEBUG_DRIVE_INFO */ return(err); @@ -203,127 +218,89 @@ { struct hd_driveid *id = drive->id; byte speed = 0x00; + unsigned int reg40 = 0; + int rval; if ((id->dma_ultra & 0x0010) && (!check_in_drive_lists(drive, bad_ata66_4)) && (HPT366_ALLOW_ATA66_4) && (HWIF(drive)->udma_four)) { - if (!((id->dma_ultra >> 8) & 16)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x1010; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_UDMA_4; } else if ((id->dma_ultra & 0x0008) && (!check_in_drive_lists(drive, bad_ata66_3)) && (HPT366_ALLOW_ATA66_3) && (HWIF(drive)->udma_four)) { - if (!((id->dma_ultra >> 8) & 8)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0808; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_UDMA_3; - } else if ((id->dma_ultra & 0x0004) && - (HPT366_ALLOW_ATA33_2) && - (!check_in_drive_lists(drive, bad_ata33))) { - if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && - (HPT366_ALLOW_ATA33_1) && - (!check_in_drive_lists(drive, bad_ata33))) { - if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; + } else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) { + 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; } - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && - (HPT366_ALLOW_ATA33_0) && - (!check_in_drive_lists(drive, bad_ata33))) { - if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } - speed = XFER_UDMA_0; } else if (id->dma_mword & 0x0004) { - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_mword >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0404; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_2; } else if (id->dma_mword & 0x0002) { - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_mword >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0202; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_mword >> 8) & 1)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0101; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_0; } else if (id->dma_1word & 0x0004) { - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_1word >> 8) & 4)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_2; } else if (id->dma_1word & 0x0002) { - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_1word >> 8) & 2)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_1; } else if (id->dma_1word & 0x0001) { - drive->id->dma_ultra &= ~0xFF00; - if (!((id->dma_1word >> 8) & 1)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_0; } else { +#if HPT366_DEBUG_DRIVE_INFO + printk("%s: config_chipset_for_dma: returning 'ide_dma_off_quietly'\n", drive->name); +#endif /* HPT366_DEBUG_DRIVE_INFO */ return ((int) ide_dma_off_quietly); } + /* Disable the "fast interrupt" prediction. + * Instead, always wait for the real interrupt from the drive! + */ + { + byte reg51h = 0; + pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); + if (reg51h & 0x80) + pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); + } + + /* + * Preserve existing PIO settings: + */ + pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, ®40); + speed = (speed & ~0xc0000000) | (reg40 & 0xc0000000); + +#if HPT366_DEBUG_DRIVE_INFO + printk("%s: config_chipset_for_dma: speed=0x%04x\n", drive->name, speed); +#endif /* HPT366_DEBUG_DRIVE_INFO */ (void) hpt366_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + 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 : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); + +#if HPT366_DEBUG_DRIVE_INFO + printk("%s: config_chipset_for_dma: returning %d (%s)\n", drive->name, rval, rval == ide_dma_on ? "dma_on" : "dma_off"); +#endif /* HPT366_DEBUG_DRIVE_INFO */ + 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; + unsigned int reg40 = 0; +#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) @@ -353,6 +330,14 @@ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; break; } + /* + * Preserve existing DMA settings: + */ + pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, ®40); + speed = (speed & ~0x30070000) | (reg40 & 0x30070000); +#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); } @@ -428,8 +413,9 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { +#if 0 byte reg50h = 0, reg52h = 0; - +#endif switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); @@ -463,28 +449,81 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) { - byte ata66 = 0; + byte test = 0; - pci_read_config_byte(dev, 0x5a, &ata66); 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: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn)); + + pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test); + if (test != 0x08) + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08); + + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test); + if (test != 0x78) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); + + pci_read_config_byte(dev, PCI_MIN_GNT, &test); + if (test != 0x08) + pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); + + pci_read_config_byte(dev, PCI_MAX_LAT, &test); + if (test != 0x08) + pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); + return dev->irq; } +unsigned int __init ata66_hpt366 (ide_hwif_t *hwif) +{ + byte ata66 = 0; + + pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66); +#ifdef DEBUG + printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n", + ata66, (ata66 & 0x02) ? "33" : "66", + PCI_FUNC(hwif->pci_dev->devfn)); +#endif /* DEBUG */ + return ((ata66 & 0x02) ? 0 : 1); +} + void __init ide_init_hpt366 (ide_hwif_t *hwif) { +#if 0 + if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_irq)) { + hwif->mate = &ide_hwifs[hwif->index-1]; + hwif->mate->mate = hwif; + hwif->serialized = hwif->mate->serialized = 1; + } +#endif + hwif->tuneproc = &hpt366_tune_drive; if (hwif->dma_base) { - byte ata66 = 0; - hwif->dmaproc = &hpt366_dmaproc; - pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66); - hwif->udma_four = (ata66 & 0x02) ? 0 : 1; } else { - hwif->udma_four = 0; hwif->autodma = 0; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } +} + +void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase) +{ + byte masterdma = 0, slavedma = 0; + byte dma_new = 0, dma_old = inb(dmabase+2); + unsigned long flags; + + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + + dma_new = dma_old; + pci_read_config_byte(hwif->pci_dev, 0x43, &masterdma); + pci_read_config_byte(hwif->pci_dev, 0x47, &slavedma); + + if (masterdma & 0x30) dma_new |= 0x20; + if (slavedma & 0x30) dma_new |= 0x40; + if (dma_new != dma_old) outb(dma_new, dmabase+2); + + __restore_flags(flags); /* local CPU only */ + + ide_setup_dma(hwif, dmabase, 8); } diff -u --recursive --new-file v2.3.22/linux/drivers/block/icside.c linux/drivers/block/icside.c --- v2.3.22/linux/drivers/block/icside.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/icside.c Thu Oct 21 13:38:12 1999 @@ -288,7 +288,6 @@ static int icside_config_drive(ide_drive_t *drive, int mode) { - ide_hwif_t *hwif = HWIF(drive); int speed, err; if (mode == 2) { @@ -382,7 +381,8 @@ if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); + drive->timeout = WAIT_CMD; + ide_set_handler(drive, &ide_dma_intr); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.3.22/linux/drivers/block/ide-cd.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/block/ide-cd.c Tue Oct 19 13:47:40 1999 @@ -339,14 +339,15 @@ failed_command->c[0] == GPCMD_READ_SUBCHANNEL) return; } + if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) { /* * Suppress the following errors: - * "Medium not present", and "in progress of becoming ready", - * to keep the noise level down to a dull roar. + * "Medium not present", "in progress of becoming ready", + * and "writing" to keep the noise level down to a dull roar. */ return; } @@ -431,6 +432,19 @@ printk ("\"\n"); } + /* The SKSV bit specifies validity of the sense_key_specific + * in the next two commands. It is bit 7 of the first byte. + * In the case of NOT_READY, if SKSV is set the drive can + * give us nice ETA readings. + */ + if (reqbuf->sense_key == NOT_READY && + (reqbuf->sense_key_specific[0] & 0x80)) { + int progress = (reqbuf->sense_key_specific[1] << 8 | + reqbuf->sense_key_specific[2]) * 100; + printk(" Command is %02d%% complete\n", progress / 0xffff); + + } + if (reqbuf->sense_key == ILLEGAL_REQUEST && (reqbuf->sense_key_specific[0] & 0x80) != 0) { printk (" Error in %s byte %d", @@ -466,21 +480,6 @@ #endif /* not VERBOSE_IDE_CD_ERRORS */ } - -/* Fix up a possibly partially-processed request so that we can - start it over entirely, or even put it back on the request queue. */ -static void restore_request (struct request *rq) -{ - if (rq->buffer != rq->bh->b_data) { - int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; - rq->buffer = rq->bh->b_data; - rq->nr_sectors += n; - rq->sector -= n; - } - rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; -} - - static void cdrom_queue_request_sense (ide_drive_t *drive, struct semaphore *sem, struct atapi_request_sense *reqbuf, @@ -533,10 +532,8 @@ struct packet_command *pc = (struct packet_command *) rq->buffer; cdrom_analyze_sense_data (drive, - (struct atapi_request_sense *) - (pc->buffer - pc->c[4]), - (struct packet_command *) - pc->sense_data); + (struct atapi_request_sense *) (pc->buffer - pc->c[4]), + (struct packet_command *) pc->sense_data); } if (rq->cmd == READ && !rq->current_nr_sectors) uptodate = 1; @@ -680,7 +677,7 @@ struct cdrom_info *info = drive->driver_data; /* Wait for the controller to be idle. */ - if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1; + if (ide_wait_stat(drive, 0, BUSY_STAT, WAIT_READY)) return 1; if (info->dma) info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive); @@ -699,7 +696,7 @@ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { - ide_set_handler (drive, handler, WAIT_CMD); + ide_set_handler (drive, handler); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ @@ -716,9 +713,14 @@ HANDLER is the interrupt handler to call when the command completes or there's data ready. */ static int cdrom_transfer_packet_command (ide_drive_t *drive, - char *cmd_buf, int cmd_len, + unsigned char *cmd_buf, int cmd_len, ide_handler_t *handler) { + /* don't timeout for blank and format commands. they may take + * a _very_ long time. */ + if (cmd_buf[0] == GPCMD_BLANK || cmd_buf[0] == GPCMD_FORMAT_UNIT) + drive->timeout = 0; + if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* Here we should have been called after receiving an interrupt from the device. DRQ should how be set. */ @@ -734,7 +736,7 @@ } /* Arm the interrupt handler. */ - ide_set_handler (drive, handler, WAIT_CMD); + ide_set_handler (drive, handler); /* Send the command to the device. */ atapi_output_bytes (drive, cmd_buf, cmd_len); @@ -770,13 +772,12 @@ /* If we don't yet have a sector buffer, try to allocate one. If we can't get one atomically, it's not fatal -- we'll just throw the data away rather than caching it. */ - if (info->sector_buffer == NULL) { - info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE, - GFP_ATOMIC); + if (info->buffer == NULL) { + info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_ATOMIC); /* If we couldn't get a buffer, don't try to buffer anything... */ - if (info->sector_buffer == NULL) + if (info->buffer == NULL) sectors_to_buffer = 0; } @@ -785,7 +786,7 @@ info->sector_buffered = sector; /* Read the data into the buffer. */ - dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE; + dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE; while (sectors_to_buffer > 0) { atapi_input_bytes (drive, dest, SECTOR_SIZE); --sectors_to_buffer; @@ -802,7 +803,6 @@ } } - /* * Check the contents of the interrupt reason register from the cdrom * and attempt to recover if there are problems. Returns 0 if everything's @@ -827,6 +827,12 @@ atapi_output_bytes (drive, &dum, sizeof (dum)); len -= sizeof (dum); } + } else if (ireason == 1) { + /* Some drives (ASUS) seem to tell us that status + * info is available. just get it and ignore. + */ + GET_STAT(); + return 0; } else { /* Drive wants a command packet, or invalid ireason... */ printk ("%s: cdrom_read_intr: bad interrupt reason %d\n", @@ -837,7 +843,6 @@ return -1; } - /* * Interrupt routine. Called when a read request has completed. */ @@ -912,8 +917,7 @@ /* First, figure out if we need to bit-bucket any of the leading sectors. */ - nskip = MIN ((int)(rq->current_nr_sectors - - (rq->bh->b_size >> SECTOR_BITS)), + nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)), sectors_to_transfer); while (nskip > 0) { @@ -939,8 +943,7 @@ /* If the buffers are full, cache the rest of the data in our internal buffer. */ if (rq->current_nr_sectors == 0) { - cdrom_buffer_sectors (drive, - rq->sector, sectors_to_transfer); + cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer); sectors_to_transfer = 0; } else { /* Transfer data to the buffers. @@ -952,8 +955,7 @@ /* Read this_transfer sectors into the current buffer. */ while (this_transfer > 0) { - atapi_input_bytes (drive, - rq->buffer, SECTOR_SIZE); + atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; --rq->nr_sectors; --rq->current_nr_sectors; @@ -966,10 +968,9 @@ /* Done moving data! Wait for another interrupt. */ - ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD); + ide_set_handler(drive, &cdrom_read_intr); } - /* * Try to satisfy some of the current read request from our cached data. * Returns nonzero if the request has been completed, zero otherwise. @@ -980,7 +981,7 @@ struct request *rq = HWGROUP(drive)->rq; /* Can't do anything if there's no buffer. */ - if (info->sector_buffer == NULL) return 0; + if (info->buffer == NULL) return 0; /* Loop while this request needs data and the next block is present in our cache. */ @@ -991,7 +992,7 @@ cdrom_end_request (1, drive); memcpy (rq->buffer, - info->sector_buffer + + info->buffer + (rq->sector - info->sector_buffered) * SECTOR_SIZE, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; @@ -1026,8 +1027,6 @@ return 0; } - - /* * Routine to send a read packet command to the drive. * This is usually called directly from cdrom_start_read. @@ -1056,14 +1055,13 @@ nskip = (sector % SECTORS_PER_FRAME); if (nskip > 0) { /* Sanity check... */ - if (rq->current_nr_sectors != - (rq->bh->b_size >> SECTOR_BITS)) { - printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n", + if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS) && + (rq->sector % CD_FRAMESIZE != 0)) { + printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n", drive->name, rq->current_nr_sectors); cdrom_end_request (0, drive); return; } - sector -= nskip; nsect += nskip; rq->current_nr_sectors += nskip; @@ -1091,9 +1089,10 @@ &cdrom_read_intr); } + #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ -#define IDECD_SEEK_TIMER (2 * WAIT_MIN_SLEEP) /* 40 ms */ -#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ +#define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ +#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ static void cdrom_seek_intr (ide_drive_t *drive) { @@ -1107,7 +1106,7 @@ if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) { if (--retry == 0) { - printk ("%s: disabled DSC seek overlap\n", drive->name); + printk("%s: disabled DSC seek overlap\n", drive->name); drive->dsc_overlap = 0; } } @@ -1127,7 +1126,7 @@ memset (&pc.c, 0, sizeof (pc.c)); pc.c[0] = GPCMD_SEEK; - put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); + put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr); } @@ -1140,6 +1139,19 @@ cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation); } +/* Fix up a possibly partially-processed request so that we can + start it over entirely, or even put it back on the request queue. */ +static void restore_request (struct request *rq) +{ + if (rq->buffer != rq->bh->b_data) { + int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; + rq->buffer = rq->bh->b_data; + rq->nr_sectors += n; + rq->sector -= n; + } + rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; +} + /* * Start a read request from the CD-ROM. */ @@ -1162,25 +1174,22 @@ restore_request (rq); /* Satisfy whatever we can of this request from our cached sector. */ - if (cdrom_read_from_buffer (drive)) + if (cdrom_read_from_buffer(drive)) return; - /* Clear the local sector buffer. */ info->nsectors_buffered = 0; - if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && (rq->nr_sectors % SECTORS_PER_FRAME == 0)) + /* use dma, if possible. */ + if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && + (rq->nr_sectors % SECTORS_PER_FRAME == 0)) info->dma = 1; else info->dma = 0; /* Start sending the read request to the drive. */ - cdrom_start_packet_command (drive, 32768, - cdrom_start_read_continuation); + cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation); } - - - /**************************************************************************** * Execute all other packet commands. */ @@ -1197,6 +1206,9 @@ struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; + /* restore timeout after blank or format command */ + drive->timeout = WAIT_CMD; + /* Check for errors. */ if (cdrom_decode_status (drive, 0, &stat)) return; @@ -1282,7 +1294,7 @@ } /* Now we wait for another interrupt. */ - ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD); + ide_set_handler (drive, &cdrom_pc_intr); } @@ -1334,6 +1346,7 @@ if (pc->sense_data == NULL) pc->sense_data = &my_reqbuf; pc->sense_data->sense_key = 0; + /* Start of retry loop. */ do { ide_init_drive_cmd (&req); @@ -1353,7 +1366,7 @@ if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); else if (reqbuf->sense_key == NOT_READY && - reqbuf->asc == 4) { + reqbuf->asc == 4 && reqbuf->ascq != 4) { /* The drive is in the process of loading a disk. Retry, but wait a little to give the drive time to complete the load. */ @@ -1368,7 +1381,6 @@ /* End of retry loop. */ } while (pc->stat != 0 && retries >= 0); - /* Return an error if the command failed. */ if (pc->stat != 0) return -EIO; @@ -1397,25 +1409,17 @@ static void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block) { - if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND) - cdrom_do_packet_command (drive); - else if (rq -> cmd == RESET_DRIVE_COMMAND) { - cdrom_end_request (1, drive); - ide_do_reset (drive); - return; - } else if (rq -> cmd != READ) { - printk ("ide-cd: bad cmd %d\n", rq -> cmd); - cdrom_end_request (0, drive); - } else { - struct cdrom_info *info = drive->driver_data; + struct cdrom_info *info = drive->driver_data; + switch (rq->cmd) { + case READ: { if (CDROM_CONFIG_FLAGS(drive)->seeking) { unsigned long elpased = jiffies - info->start_seek; int stat = GET_STAT(); if ((stat & SEEK_STAT) != SEEK_STAT) { if (elpased < IDECD_SEEK_TIMEOUT) { - ide_stall_queue (drive, IDECD_SEEK_TIMER); + ide_stall_queue(drive, IDECD_SEEK_TIMER); return; } printk ("%s: DSC timeout\n", drive->name); @@ -1427,6 +1431,26 @@ else cdrom_start_read (drive, block); info->last_block = block; + break; + } + + case PACKET_COMMAND: + case REQUEST_SENSE_COMMAND: { + cdrom_do_packet_command(drive); + break; + } + + case RESET_DRIVE_COMMAND: { + cdrom_end_request(1, drive); + ide_do_reset(drive); + break; + } + + default: { + printk("ide-cd: bad cmd %d\n", rq -> cmd); + cdrom_end_request(0, drive); + break; + } } } @@ -1600,7 +1624,7 @@ stat = cdrom_queue_packet_command (drive, &pc); if (stat == 0) - *capacity = ntohl (capbuf.lba); + *capacity = be32_to_cpu(capbuf.lba); return stat; } @@ -1879,64 +1903,7 @@ -/* This gets the mechanism status per ATAPI draft spec 2.6 */ -static int -cdrom_read_mech_status (ide_drive_t *drive, char *buf, int buflen, - struct atapi_request_sense *reqbuf) -{ - struct packet_command pc; - - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; - - pc.buffer = buf; - pc.buflen = buflen; - pc.c[0] = GPCMD_MECHANISM_STATUS; - pc.c[8] = (buflen >> 8); - pc.c[9] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); -} - -/* Read the drive mechanism status and slot table into our internal buffer. - If the buffer does not yet exist, allocate it. */ -static int -cdrom_read_changer_info (ide_drive_t *drive) -{ - int nslots; - struct cdrom_info *info = drive->driver_data; - - if (info->changer_info) - nslots = info->changer_info->hdr.nslots; - - else { - struct atapi_mechstat_header mechbuf; - int stat; - - stat = cdrom_read_mech_status (drive, - (char *)&mechbuf, - sizeof (mechbuf), - NULL); - if (stat) - return stat; - - nslots = mechbuf.nslots; - info->changer_info = - (struct atapi_changer_info *) - kmalloc (sizeof (struct atapi_changer_info) + - nslots * sizeof (struct atapi_slot), - GFP_KERNEL); - - if (info->changer_info == NULL) - return -ENOMEM; - } - return cdrom_read_mech_status - (drive, - (char *)&info->changer_info->hdr, - sizeof (struct atapi_mechstat_header) + - nslots * sizeof (struct atapi_slot), - NULL); -} /* the generic packet interface to cdrom.c */ static int ide_cdrom_packet(struct cdrom_device_info *cdi, @@ -1952,8 +1919,7 @@ memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); pc.buffer = cgc->buffer; pc.buflen = cgc->buflen; - cgc->stat = cdrom_queue_packet_command(drive, &pc); - return cgc->stat; + return cgc->stat = cdrom_queue_packet_command(drive, &pc); } static @@ -2130,16 +2096,19 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; if (slot_nr == CDSL_CURRENT) { - struct atapi_request_sense my_reqbuf; - int stat = cdrom_check_status (drive, &my_reqbuf); - if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) + struct atapi_request_sense sense; + int stat = cdrom_check_status (drive, &sense); + if (stat == 0 || sense.sense_key == UNIT_ATTENTION) + return CDS_DISC_OK; + + if (sense.sense_key == NOT_READY && sense.asc == 0x04 && + sense.ascq == 0x04) return CDS_DISC_OK; - if (my_reqbuf.sense_key == NOT_READY) { + if (sense.sense_key == NOT_READY) { /* ATAPI doesn't have anything that can help us decide whether the drive is really emtpy or the tray is just open. irk. */ @@ -2147,24 +2116,8 @@ } return CDS_DRIVE_NOT_READY; - } - -#if ! STANDARD_ATAPI - else if (cdi->sanyo_slot > 0) - return CDS_NO_INFO; -#endif /* not STANDARD_ATAPI */ - - else { - struct atapi_changer_info *ci; - int stat = cdrom_read_changer_info (drive); - if (stat < 0) - return stat; - ci = info->changer_info; - - if (ci->slots[slot_nr].disc_present) - return CDS_DISC_OK; - else - return CDS_NO_DISC; + } else { + return -EINVAL; } } @@ -2215,47 +2168,14 @@ int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; - struct atapi_request_sense reqbuf; - int retval; if (slot_nr == CDSL_CURRENT) { (void) cdrom_check_status (drive, NULL); - retval = CDROM_STATE_FLAGS (drive)->media_changed; CDROM_STATE_FLAGS (drive)->media_changed = 0; + return CDROM_STATE_FLAGS (drive)->media_changed; + } else { + return -EINVAL; } - -#if ! STANDARD_ATAPI - else if (cdi->sanyo_slot > 0) { - retval = 0; - } -#endif /* not STANDARD_ATAPI */ - - else { - struct atapi_changer_info *ci; - int stat = cdrom_read_changer_info (drive); - if (stat < 0) - return stat; - ci = info->changer_info; - - /* This test may be redundant with cdrom.c. */ - if (slot_nr < 0 || slot_nr >= ci->hdr.nslots) - return -EINVAL; - - retval = ci->slots[slot_nr].change; - } - - /* if the media has changed, check if a disc is in the drive - and read the toc info. */ - if (retval || !CDROM_STATE_FLAGS (drive)->toc_valid) { - /* if cdrom_read_toc fails, return 1 to indicate - that a disc change has occured. there might not - be a disc in the drive. */ - if ((retval = cdrom_read_toc (drive, &reqbuf))) - return 1; - } - - return retval; } @@ -2361,11 +2281,12 @@ * be queued with ide_cdrom_packet(), which extracts the * drive from cdi->handle. Since this device hasn't been * registered with the Uniform layer yet, it can't do this. - * Same goes cdi->ops. + * Same goes for cdi->ops. */ cdi->handle = (ide_drive_t *) drive; cdi->ops = &ide_cdrom_dops; - do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + /* we seem to get stat=0x01,err=0x00 the first time (??) */ + do { if (attempts-- <= 0) return 0; stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); @@ -2402,14 +2323,9 @@ #endif /* not STANDARD_ATAPI */ if (buf.cap.mechtype == mechtype_individual_changer || buf.cap.mechtype == mechtype_cartridge_changer) { - struct atapi_mechstat_header mechbuf; - - stat = cdrom_read_mech_status (drive, (char*)&mechbuf, - sizeof (mechbuf), NULL); - if (!stat) { + if ((nslots = cdrom_number_of_slots(cdi)) > 1) { CDROM_CONFIG_FLAGS (drive)->is_changer = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1; - nslots = mechbuf.nslots; } } @@ -2445,7 +2361,7 @@ else printk (" drive"); - printk (", %dkB Cache", ntohs(buf.cap.buffer_size)); + printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size)); if (drive->using_dma) { if ((drive->id->field_valid & 4) && @@ -2473,7 +2389,6 @@ ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); } - static int ide_cdrom_setup (ide_drive_t *drive) { @@ -2482,13 +2397,12 @@ int minor = drive->select.b.unit << PARTN_BITS; int nslots; - kdev_t dev = MKDEV(HWIF(drive)->major, minor); - - set_device_ro (dev, 1); + set_device_ro(MKDEV(HWIF(drive)->major, minor), 1); blksize_size[HWIF(drive)->major][minor] = CD_FRAMESIZE; - drive->special.all = 0; - drive->ready_stat = 0; + drive->special.all = 0; + drive->ready_stat = 0; + drive->timeout = WAIT_CMD; CDROM_STATE_FLAGS (drive)->media_changed = 1; CDROM_STATE_FLAGS (drive)->toc_valid = 0; @@ -2589,11 +2503,13 @@ } #endif /* not STANDARD_ATAPI */ - info->toc = NULL; - info->sector_buffer = NULL; - info->sector_buffered = 0; - info->nsectors_buffered = 0; + info->toc = NULL; + info->buffer = NULL; + info->sector_buffered = 0; + info->nsectors_buffered = 0; info->changer_info = NULL; + info->last_block = 0; + info->start_seek = 0; nslots = ide_cdrom_probe_capabilities (drive); @@ -2653,15 +2569,15 @@ if (ide_unregister_subdriver (drive)) return 1; - if (info->sector_buffer != NULL) - kfree (info->sector_buffer); + if (info->buffer != NULL) + kfree(info->buffer); if (info->toc != NULL) - kfree (info->toc); + kfree(info->toc); if (info->changer_info != NULL) - kfree (info->changer_info); + kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom (devinfo)) printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); - kfree (info); + kfree(info); drive->driver_data = NULL; return 0; } diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h --- v2.3.22/linux/drivers/block/ide-cd.h Mon Oct 4 15:49:29 1999 +++ linux/drivers/block/ide-cd.h Fri Oct 22 12:46:22 1999 @@ -34,19 +34,13 @@ #define NO_DOOR_LOCKING 0 #endif - -/* Size of buffer to allocate, in blocks, for audio reads. */ - -#ifndef CDROM_NBLOCKS_BUFFER -#define CDROM_NBLOCKS_BUFFER 8 -#endif - - /************************************************************************/ -#define SECTOR_SIZE 512 -#define SECTOR_BITS 9 -#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE) +#define SECTOR_SIZE 512 +#define SECTOR_BITS 9 +#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE) +#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) +#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE / SECTOR_SIZE) #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -84,7 +78,8 @@ __u8 seeking : 1; /* Seeking in progress */ __u8 audio_play : 1; /* can do audio related commands */ __u8 close_tray : 1; /* can close the tray */ - __u8 reserved : 4; + __u8 writing : 1; /* pseudo write in progress */ + __u8 reserved : 3; byte max_speed; /* Max speed of the drive */ }; #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) @@ -96,7 +91,8 @@ __u8 media_changed : 1; /* Driver has noticed a media change. */ __u8 toc_valid : 1; /* Saved TOC information is current. */ __u8 door_locked : 1; /* We think that the drive door is locked. */ - __u8 reserved : 5; + __u8 writing : 1; /* the drive is currently writing */ + __u8 reserved : 4; byte current_speed; /* Current speed of the drive */ }; #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) @@ -487,13 +483,11 @@ byte reserved2[3]; }; - struct atapi_changer_info { struct atapi_mechstat_header hdr; struct atapi_slot slots[0]; }; - /* Extra per-device info for cdrom drives. */ struct cdrom_info { @@ -502,17 +496,9 @@ struct atapi_toc *toc; - /* Sector buffer. If a read request wants only the first part - of a cdrom block, we cache the rest of the block here, - in the expectation that the data is going to be wanted soon. - SECTOR_BUFFERED is the number of the first buffered sector, - and NSECTORS_BUFFERED is the number of sectors in the buffer. - Before the buffer is allocated, we should have - SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */ - - unsigned long sector_buffered; - unsigned long nsectors_buffered; - char *sector_buffer; + unsigned long sector_buffered; + unsigned long nsectors_buffered; + unsigned char *buffer; /* The result of the last successful request sense command on this device. */ @@ -533,10 +519,6 @@ struct cdrom_device_info devinfo; }; - -#define SECTOR_BUFFER_SIZE CD_FRAMESIZE - - /**************************************************************************** * Descriptions of ATAPI error codes. */ @@ -652,6 +634,7 @@ { 0x000013, "Play operation successfully completed" }, { 0x000014, "Play operation stopped due to error" }, { 0x000015, "No current audio status to return" }, + { 0x010c0a, "Write error - padding blocks added" }, { 0x011700, "Recovered data with no error correction applied" }, { 0x011701, "Recovered data with retries" }, { 0x011702, "Recovered data with positive head offset" }, @@ -668,6 +651,7 @@ { 0x015d01, "Failure prediction threshold exceeded - Predicted media failure" }, { 0x015dff, "Failure prediction threshold exceeded - False" }, + { 0x017301, "Power calibration area almost full" }, { 0x020400, "Logical unit not ready - cause not reportable" }, /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ { 0x020401, @@ -680,9 +664,35 @@ { 0x023a00, "Medium not present" }, { 0x025300, "Media load or eject failed" }, { 0x025700, "Unable to recover table of contents" }, + { 0x030300, "Peripheral device write fault" }, + { 0x030301, "No write current" }, + { 0x030302, "Excessive write errors" }, + { 0x030c00, "Write error" }, + { 0x030c01, "Write error - Recovered with auto reallocation" }, + { 0x030c02, "Write error - auto reallocation failed" }, + { 0x030c03, "Write error - recommend reassignment" }, + { 0x030c04, "Compression check miscompare error" }, + { 0x030c05, "Data expansion occurred during compress" }, + { 0x030c06, "Block not compressible" }, + { 0x030c07, "Write error - recovery needed" }, + { 0x030c08, "Write error - recovery failed" }, + { 0x030c09, "Write error - loss of streaming" }, { 0x031100, "Unrecovered read error" }, { 0x031106, "CIRC unrecovered error" }, { 0x033101, "Format command failed" }, + { 0x033200, "No defect spare location available" }, + { 0x033201, "Defect list update failure" }, + { 0x035100, "Erase failure" }, + { 0x037200, "Session fixation error" }, + { 0x037201, "Session fixation error writin lead-in" }, + { 0x037202, "Session fixation error writin lead-out" }, + { 0x037300, "CD control error" }, + { 0x037302, "Power calibration area is full" }, + { 0x037303, "Power calibration area error" }, + { 0x037304, "Program memory area / RMA update failure" }, + { 0x037305, "Program memory area / RMA is full" }, + { 0x037306, "Program memory area / RMA is (almost) full" }, + { 0x040200, "No seek complete" }, { 0x040300, "Write fault" }, { 0x040900, "Track following error" }, @@ -700,11 +710,15 @@ { 0x052000, "Invalid command operation code" }, { 0x052c00, "Command sequence error" }, { 0x052100, "Logical block address out of range" }, + { 0x052102, "Invalid address for write" }, { 0x052400, "Invalid field in command packet" }, { 0x052600, "Invalid field in parameter list" }, { 0x052601, "Parameter not supported" }, { 0x052602, "Parameter value invalid" }, { 0x052700, "Write protected media" }, + { 0x052c00, "Command sequence error" }, + { 0x052c03, "Current program area is not empty" }, + { 0x052c04, "Current program area is empty" }, { 0x053001, "Cannot read medium - unknown format" }, { 0x053002, "Cannot read medium - incompatible format" }, { 0x053900, "Saving parameters not supported" }, @@ -713,11 +727,15 @@ { 0x055500, "System resource failure" }, { 0x056300, "End of user area encountered on this track" }, { 0x056400, "Illegal mode for this track or incompatible medium" }, - { 0x056f00, - "Copy protection key exchange failure - Authentication failure" }, + { 0x056f00, "Copy protection key exchange failure - Authentication failure" }, { 0x056f01, "Copy protection key exchange failure - Key not present" }, - { 0x056f02, - "Copy protection key exchange failure - Key not established" }, + { 0x056f02, "Copy protection key exchange failure - Key not established" }, + { 0x056f03, "Read of scrambled sector without authentication" }, + { 0x056f04, "Media region code is mismatched to logical unit" }, + { 0x056f05, "Drive region must be permanent / region reset count error" }, + { 0x057203, "Session fixation error - incomplete track in session" }, + { 0x057204, "Empty or partially written reserved track" }, + { 0x057205, "No more RZONE reservations are allowed" }, { 0x05bf00, "Loss of streaming" }, { 0x062800, "Not ready to ready transition, medium may have changed" }, { 0x062900, "Power on, reset or hardware reset occurred" }, diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.3.22/linux/drivers/block/ide-disk.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/ide-disk.c Mon Oct 18 11:14:22 1999 @@ -175,7 +175,7 @@ if (i > 0) { if (msect) goto read_next; - ide_set_handler (drive, &read_intr, WAIT_CMD); + ide_set_handler (drive, &read_intr); } } @@ -206,7 +206,7 @@ ide_end_request(1, hwgroup); if (i > 0) { idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); - ide_set_handler (drive, &write_intr, WAIT_CMD); + ide_set_handler (drive, &write_intr); } goto out; } @@ -271,7 +271,7 @@ if (stat & DRQ_STAT) { if (rq->nr_sectors) { ide_multwrite(drive, drive->mult_count); - ide_set_handler (drive, &multwrite_intr, WAIT_CMD); + ide_set_handler (drive, &multwrite_intr); goto out; } } else { @@ -385,7 +385,7 @@ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) return; #endif /* CONFIG_BLK_DEV_IDEDMA */ - ide_set_handler(drive, &read_intr, WAIT_CMD); + ide_set_handler(drive, &read_intr); OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); return; } @@ -404,10 +404,10 @@ __cli(); /* local CPU only */ if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ - ide_set_handler (drive, &multwrite_intr, WAIT_CMD); + ide_set_handler (drive, &multwrite_intr); ide_multwrite(drive, drive->mult_count); } else { - ide_set_handler (drive, &write_intr, WAIT_CMD); + ide_set_handler (drive, &write_intr); idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); } return; @@ -506,6 +506,7 @@ drive->special.all = 0; drive->special.b.set_geometry = 1; drive->special.b.recalibrate = 1; + drive->timeout = WAIT_CMD; if (OK_TO_RESET_CONTROLLER) drive->mult_count = 0; if (!drive->keep_settings) diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.3.22/linux/drivers/block/ide-dma.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/ide-dma.c Tue Oct 19 10:22:20 1999 @@ -420,7 +420,8 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */ + drive->timeout = WAIT_CMD; + ide_set_handler(drive, &ide_dma_intr);/* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: /* Note that this is done *after* the cmd has @@ -460,7 +461,7 @@ int ide_release_dma (ide_hwif_t *hwif) { if (hwif->dmatable) { - clear_page((unsigned long)hwif->dmatable); /* clear PRD 1st */ + clear_page((void *)hwif->dmatable); /* clear PRD 1st */ free_page((unsigned long)hwif->dmatable); /* free PRD 2nd */ } if ((hwif->dma_extra) && (hwif->channel == 0)) @@ -537,14 +538,7 @@ switch(dev->device) { case PCI_DEVICE_ID_CMD_643: -#ifdef CONFIG_BLK_DEV_ALI15X3 case PCI_DEVICE_ID_AL_M5219: - case PCI_DEVICE_ID_AL_M5229: - /* - * Ali 15x3 chipsets know as ALI IV and V report - * this as simplex, skip this test for them. - */ -#endif /* CONFIG_BLK_DEV_ALI15X3 */ outb(inb(dma_base+2) & 0x60, dma_base+2); if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA forced\n", name); diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.3.22/linux/drivers/block/ide-floppy.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/ide-floppy.c Mon Oct 18 11:14:22 1999 @@ -916,7 +916,7 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n"); idefloppy_discard_data (drive,bcount.all); - ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); + ide_set_handler (drive,&idefloppy_pc_intr); return; } #if IDEFLOPPY_DEBUG_LOG @@ -938,7 +938,7 @@ pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); /* And set the interrupt handler again */ + ide_set_handler (drive,&idefloppy_pc_intr); /* And set the interrupt handler again */ } static void idefloppy_transfer_pc (ide_drive_t *drive) @@ -956,7 +956,7 @@ ide_do_reset (drive); return; } - ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD); /* Set the interrupt routine */ + ide_set_handler (drive, &idefloppy_pc_intr); /* Set the interrupt routine */ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ } @@ -1025,7 +1025,7 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { - ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD); + ide_set_handler (drive, &idefloppy_transfer_pc); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); @@ -1519,6 +1519,7 @@ *((unsigned short *) &gcw) = drive->id->config; drive->driver_data = floppy; drive->ready_stat = 0; + drive->timeout = IDEFLOPPY_WAIT_CMD; memset (floppy, 0, sizeof (idefloppy_floppy_t)); floppy->drive = drive; floppy->pc = floppy->pc_stack; diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-geometry.c linux/drivers/block/ide-geometry.c --- v2.3.22/linux/drivers/block/ide-geometry.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/ide-geometry.c Mon Oct 18 11:14:22 1999 @@ -5,6 +5,9 @@ #include +extern ide_drive_t * get_info_ptr(kdev_t); +extern unsigned long current_capacity (ide_drive_t *); + /* * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc * controller that is BIOS compatible with ST-506, and thus showing up in our diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.3.22/linux/drivers/block/ide-pci.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/block/ide-pci.c Mon Oct 18 11:14:22 1999 @@ -57,8 +57,9 @@ #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) #define DEVID_CX5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE}) +#define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, 0x7409}) -#define IDE_IGNORE ((void *)-1) +#define IDE_IGNORE ((void *)-1) #ifdef CONFIG_BLK_DEV_TRM290 extern void ide_init_trm290(ide_hwif_t *); @@ -106,54 +107,66 @@ #define INIT_RZ1000 IDE_IGNORE #endif -#ifdef CONFIG_BLK_DEV_VIA82C586 -extern unsigned int pci_init_via82c568(struct pci_dev *, const char *); -extern void ide_init_via82c586(ide_hwif_t *); -extern void ide_dmacapable_via82c586(ide_hwif_t *, unsigned long dmabase); -#define PCI_VIA82C586 &pci_init_via82c568 -#define INIT_VIA82C586 &ide_init_via82c586 -#define DMA_VIA82C586 &ide_dmacapable_via82c586 -#else -#define PCI_VIA82C586 NULL -#define INIT_VIA82C586 NULL -#define DMA_VIA82C586 NULL +#ifdef CONFIG_BLK_DEV_VIA82CXXX +extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *); +extern unsigned int ata66_via82cxxx(ide_hwif_t *); +extern void ide_init_via82cxxx(ide_hwif_t *); +extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long); +#define PCI_VIA82CXXX &pci_init_via82cxxx +#define ATA66_VIA82CXXX &ata66_via82cxxx +#define INIT_VIA82CXXX &ide_init_via82cxxx +#define DMA_VIA82CXXX &ide_dmacapable_via82cxxx +#else +#define PCI_VIA82CXXX NULL +#define ATA66_VIA82CXXX NULL +#define INIT_VIA82CXXX NULL +#define DMA_VIA82CXXX NULL #endif #ifdef CONFIG_BLK_DEV_ALI15X3 extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *); +extern unsigned int ata66_ali15x3(ide_hwif_t *); extern void ide_init_ali15x3(ide_hwif_t *); +extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long); #define PCI_ALI15X3 &pci_init_ali15x3 -#define INIT_ALI15X3 &ide_init_ali15x3 +#define ATA66_ALI15X3 &ata66_ali15x3 +#define INIT_ALI15X3 &ide_init_ali15x3 +#define DMA_ALI15X3 &ide_dmacapable_ali15x3 #else #define PCI_ALI15X3 NULL -#define INIT_ALI15X3 NULL +#define ATA66_ALI15X3 NULL +#define INIT_ALI15X3 NULL +#define DMA_ALI15X3 NULL #endif #ifdef CONFIG_BLK_DEV_CY82C693 extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *); extern void ide_init_cy82c693(ide_hwif_t *); #define PCI_CY82C693 &pci_init_cy82c693 -#define INIT_CY82C693 &ide_init_cy82c693 +#define INIT_CY82C693 &ide_init_cy82c693 #else #define PCI_CY82C693 NULL -#define INIT_CY82C693 NULL +#define INIT_CY82C693 NULL #endif #ifdef CONFIG_BLK_DEV_PDC202XX extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *); +extern unsigned int ata66_pdc202xx(ide_hwif_t *); extern void ide_init_pdc202xx(ide_hwif_t *); #define PCI_PDC202XX &pci_init_pdc202xx -#define INIT_PDC202XX &ide_init_pdc202xx +#define ATA66_PDC202XX &ata66_pdc202xx +#define INIT_PDC202XX &ide_init_pdc202xx #else #define PCI_PDC202XX NULL -#define INIT_PDC202XX NULL +#define ATA66_PDC202XX NULL +#define INIT_PDC202XX NULL #endif #ifdef CONFIG_BLK_DEV_PIIX extern void ide_init_piix(ide_hwif_t *); -#define INIT_PIIX &ide_init_piix +#define INIT_PIIX &ide_init_piix #else -#define INIT_PIIX NULL +#define INIT_PIIX NULL #endif #ifdef CONFIG_BLK_DEV_AEC6210 @@ -167,29 +180,40 @@ extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *); extern void ide_init_hpt34x(ide_hwif_t *); #define PCI_HPT34X &pci_init_hpt34x -#define INIT_HPT34X &ide_init_hpt34x +#define INIT_HPT34X &ide_init_hpt34x #else #define PCI_HPT34X NULL -#define INIT_HPT34X NULL +#define INIT_HPT34X NULL #endif #ifdef CONFIG_BLK_DEV_HPT366 +extern byte hpt363_shared_irq; extern unsigned int pci_init_hpt366(struct pci_dev *, const char *); +extern unsigned int ata66_hpt366(ide_hwif_t *); extern void ide_init_hpt366(ide_hwif_t *); +extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long); #define PCI_HPT366 &pci_init_hpt366 +#define ATA66_HPT366 &ata66_hpt366 #define INIT_HPT366 &ide_init_hpt366 +#define DMA_HPT366 &ide_dmacapable_hpt366 #else +static byte hpt363_shared_irq = 0; #define PCI_HPT366 NULL -#define INIT_HPT366 IDE_IGNORE +#define ATA66_HPT366 NULL +#define INIT_HPT366 NULL +#define DMA_HPT366 NULL #endif #ifdef CONFIG_BLK_DEV_SIS5513 extern unsigned int pci_init_sis5513(struct pci_dev *, const char *); +extern unsigned int ata66_sis5513(ide_hwif_t *); extern void ide_init_sis5513(ide_hwif_t *); #define PCI_SIS5513 &pci_init_sis5513 +#define ATA66_SIS5513 &ata66_sis5513 #define INIT_SIS5513 &ide_init_sis5513 #else #define PCI_SIS5513 NULL +#define ATA66_SIS5513 NULL #define INIT_SIS5513 NULL #endif @@ -206,49 +230,48 @@ ide_pci_devid_t devid; const char *name; unsigned int (*init_chipset)(struct pci_dev *dev, const char *name); + unsigned int (*ata66_check)(ide_hwif_t *hwif); void (*init_hwif)(ide_hwif_t *hwif); void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase); ide_pci_enablebit_t enablebits[2]; byte bootable; - byte sixtysix; unsigned int extra; } ide_pci_device_t; static ide_pci_device_t ide_pci_chipsets[] __initdata = { - {DEVID_PIIXa, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {DEVID_PIIXb, "PIIX", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {DEVID_PIIX3, "PIIX3", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {DEVID_PIIX4, "PIIX4", NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, - {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_VP_IDE, "VP_IDE", PCI_VIA82C586, INIT_VIA82C586, DMA_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, 0 }, - {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 0, 16 }, - {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 1, 48 }, - {DEVID_RZ1000, "RZ1000", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_RZ1001, "RZ1001", NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_SAMURAI, "SAMURAI", NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_CMD640, "CMD640", NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_NS87410, "NS87410", NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 }, - {DEVID_SIS5513, "SIS5513", PCI_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 1, 0 }, - {DEVID_CMD643, "CMD643", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_CMD646, "CMD646", NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0, 0 }, - {DEVID_HT6565, "HT6565", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_OPTI621, "OPTI621", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_OPTI621X,"OPTI621X", NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_TRM290, "TRM290", NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_NS87415, "NS87415", NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, 0 }, - {DEVID_W82C105, "W82C105", NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0, 0 }, - {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_HPT34X, "HPT34X", PCI_HPT34X, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, 16 }, - {DEVID_HPT366, "HPT366", PCI_HPT366, INIT_HPT366, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 1, 256 }, - {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, INIT_ALI15X3, NULL, {{0x09,0x20,0x20}, {0x09,0x10,0x10}}, ON_BOARD, 0, 0 }, - {DEVID_CY82C693,"CY82C693", PCI_CY82C693, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {DEVID_CX5530, "CX5530", NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, - {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }}; - -static byte hpt363_shared_irq = 0; + {DEVID_PIIXa, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIXb, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX3, "PIIX3", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4, "PIIX4", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, + {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, + {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, + {DEVID_RZ1000, "RZ1000", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_RZ1001, "RZ1001", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_SAMURAI, "SAMURAI", NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD640, "CMD640", NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_NS87410, "NS87410", NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, + {DEVID_SIS5513, "SIS5513", PCI_SIS5513, ATA66_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, + {DEVID_CMD643, "CMD643", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD646, "CMD646", NULL, NULL, INIT_CMD646, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, + {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, + {DEVID_TRM290, "TRM290", NULL, NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_NS87415, "NS87415", NULL, NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AEC6210, "AEC6210", PCI_AEC6210, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_W82C105, "W82C105", NULL, NULL, INIT_W82C105, NULL, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, + {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_HPT34X, "HPT34X", PCI_HPT34X, NULL, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, + {DEVID_HPT366, "HPT366", PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 256 }, + {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, ATA66_ALI15X3, INIT_ALI15X3, DMA_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CX5530, "CX5530", NULL, NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AMD7409, "AMD7409", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* * This allows offboard ide-pci cards the enable a BIOS, verify interrupt @@ -260,24 +283,24 @@ switch(dev->device) { case PCI_DEVICE_ID_TTI_HPT343: { + int i; + unsigned long hpt34xIoBase = dev->resource[4].start; unsigned short pcicmd = 0; pci_write_config_byte(dev, 0x80, 0x00); pci_read_config_word(dev, PCI_COMMAND, &pcicmd); if (!(pcicmd & PCI_COMMAND_MEMORY)) { - int i; - unsigned long hpt34xIoBase = dev->resource[4].start; - - dev->resource[0].start = (hpt34xIoBase + 0x20); - dev->resource[1].start = (hpt34xIoBase + 0x34); - dev->resource[2].start = (hpt34xIoBase + 0x28); - dev->resource[3].start = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } else { pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } + + dev->resource[0].start = (hpt34xIoBase + 0x20); + dev->resource[1].start = (hpt34xIoBase + 0x34); + dev->resource[2].start = (hpt34xIoBase + 0x28); + dev->resource[3].start = (hpt34xIoBase + 0x3c); + for(i=0; i<4; i++) + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_PROMISE_20246: @@ -530,8 +553,7 @@ hwif->irq = hwif->channel ? 15 : 14; goto bypass_umc_dma; } - if ((!d->sixtysix) && (hwif->udma_four)) - hwif->udma_four = 0; + hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; #ifdef CONFIG_BLK_DEV_IDEDMA if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) @@ -582,40 +604,35 @@ static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *dev2; + struct pci_dev *dev2 = NULL, *findev; ide_pci_device_t *d2; unsigned char pin1 = 0, pin2 = 0; - d2 = d; if (PCI_FUNC(dev->devfn) & 1) return; - - for (dev2=pci_devices; dev2; dev2=dev2->next) { - if ((dev2->vendor == dev->vendor) && - (dev2->device == dev->device) && - (PCI_FUNC(dev2->devfn) & 1)) - break; - } pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - if (dev2) { - pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); - hpt363_shared_irq = (pin1 != pin2) ? 1 : 0; - } - - if (hpt363_shared_irq) { - printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", - d->name, pin1, pin2); + for (findev=pci_devices; findev; findev=findev->next) { + if ((findev->vendor == dev->vendor) && + (findev->device == dev->device) && + ((findev->devfn - dev->devfn) == 1) && + (PCI_FUNC(findev->devfn) & 1)) { + dev2 = findev; + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); + hpt363_shared_irq = (pin1 != pin2) ? 1 : 0; + if (hpt363_shared_irq) { + d->bootable = ON_BOARD; + printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2); + } + break; + } } - - printk("%s: IDE controller on PCI bus %02x dev %02x\n", - d->name, dev->bus->number, dev->devfn); + printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); ide_setup_pci_device(dev, d); - - if (dev2 && !hpt363_shared_irq) { - printk("%s: IDE controller on PCI bus %02x dev %02x\n", - d2->name, dev2->bus->number, dev2->devfn); - ide_setup_pci_device(dev2, d2); - } + if (!dev2) + return; + d2 = d; + printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); + ide_setup_pci_device(dev2, d2); } /* diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.3.22/linux/drivers/block/ide-pmac.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/ide-pmac.c Mon Oct 18 11:14:22 1999 @@ -363,7 +363,8 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); + drive->timeout = WAIT_CMD; + ide_set_handler(drive, &ide_dma_intr); OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA, IDE_COMMAND_REG); case ide_dma_begin: diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.3.22/linux/drivers/block/ide-probe.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/ide-probe.c Mon Oct 18 11:14:22 1999 @@ -42,7 +42,6 @@ #include #include - #include #include #include @@ -85,6 +84,9 @@ ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap); ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap); + if (strstr(id->model, "E X A B Y T E N E S T")) + return; + id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */ printk("%s: %s, ", drive->name, id->model); drive->present = 1; @@ -324,6 +326,35 @@ } /* + * + */ +static void enable_nest (ide_drive_t *drive) +{ + unsigned long timeout; + + printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model); + SELECT_DRIVE(HWIF(drive), drive); + ide_delay_50ms(); + OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); + timeout = jiffies + WAIT_WORSTCASE; + do { + if (jiffies > timeout) { + printk("failed (timeout)\n"); + return; + } + ide_delay_50ms(); + } while (GET_STAT() & BUSY_STAT); + ide_delay_50ms(); + if (!OK_STAT(GET_STAT(), 0, BAD_STAT)) + printk("failed (status = 0x%02x)\n", GET_STAT()); + else + printk("success\n"); + if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ + (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ + } +} + +/* * probe_for_drive() tests for existence of a given drive using do_probe(). * * Returns: 0 no device was found @@ -336,6 +367,8 @@ if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ } + if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T")) + enable_nest(drive); if (!drive->present) return 0; /* drive not found */ if (drive->id == NULL) { /* identification failed? */ diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.3.22/linux/drivers/block/ide-proc.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/ide-proc.c Mon Oct 18 11:14:22 1999 @@ -73,14 +73,21 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -#ifdef CONFIG_BLK_DEV_VIA82C586 -int (*via_display_info)(char *, char **, off_t, int, int) = NULL; -#endif /* CONFIG_BLK_DEV_VIA82C586 */ - #ifdef CONFIG_BLK_DEV_ALI15X3 +extern byte ali_proc; int (*ali_display_info)(char *, char **, off_t, int, int) = NULL; #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_SIS5513 +extern byte sis_proc; +int (*sis_display_info)(char *, char **, off_t, int, int) = NULL; +#endif /* CONFIG_BLK_DEV_SIS5513 */ + +#ifdef CONFIG_BLK_DEV_VIA82CXXX +extern byte via_proc; +int (*via_display_info)(char *, char **, off_t, int, int) = NULL; +#endif /* CONFIG_BLK_DEV_VIA82CXXX */ + static int ide_getxdigit(char c) { int digit; @@ -243,7 +250,27 @@ } #endif /* CONFIG_BLK_DEV_IDEPCI */ } else { /* not pci */ -#ifndef CONFIG_Q40 +#if !defined(__mc68000__) && !defined(CONFIG_APUS) + +/* + * Geert Uytterhoeven + * + * unless you can explain me what it really does. + * On m68k, we don't have outw() and outl() yet, + * and I need a good reason to implement it. + * + * BTW, IMHO the main remaining portability problem with the IDE driver + * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms. + * + * I think all accesses should be done using + * + * ide_in[bwl](ide_device_instance, offset) + * ide_out[bwl](ide_device_instance, value, offset) + * + * so the architecture specific code can #define ide_{in,out}[bwl] to the + * appropriate function. + * + */ switch (digits) { case 2: outb(val, reg); break; @@ -252,7 +279,7 @@ case 8: outl(val, reg); break; } -#endif /* CONFIG_Q40 */ +#endif /* !__mc68000__ && !CONFIG_APUS */ } } } @@ -750,18 +777,24 @@ ent = create_proc_entry("drivers", 0, proc_ide_root); if (!ent) return; ent->read_proc = proc_ide_read_drivers; -#ifdef CONFIG_BLK_DEV_VIA82C586 - if (via_display_info) { - ent = create_proc_entry("via", 0, proc_ide_root); - ent->get_info = via_display_info; - } -#endif /* CONFIG_BLK_DEV_VIA82C586 */ #ifdef CONFIG_BLK_DEV_ALI15X3 - if (ali_display_info) { + if ((ali_display_info) && (ali_proc)) { ent = create_proc_entry("ali", 0, proc_ide_root); ent->get_info = ali_display_info; } #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_SIS5513 + if ((sis_display_info) && (sis_proc)) { + ent = create_proc_entry("sis", 0, proc_ide_root); + ent->get_info = sis_display_info; + } +#endif /* CONFIG_BLK_DEV_SIS5513 */ +#ifdef CONFIG_BLK_DEV_VIA82CXXX + if ((via_display_info) && (via_proc)) { + ent = create_proc_entry("via", 0, proc_ide_root); + ent->get_info = via_display_info; + } +#endif /* CONFIG_BLK_DEV_VIA82CXXX */ } void proc_ide_destroy(void) @@ -770,14 +803,18 @@ * Mmmm.. does this free up all resources, * or do we need to do a more proper cleanup here ?? */ -#ifdef CONFIG_BLK_DEV_VIA82C586 - if (via_display_info) - remove_proc_entry("ide/via",0); -#endif /* CONFIG_BLK_DEV_VIA82C586 */ #ifdef CONFIG_BLK_DEV_ALI15X3 - if (ali_display_info) + if ((ali_display_info) && (ali_proc)) remove_proc_entry("ide/ali",0); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_SIS5513 + if ((sis_display_info) && (sis_proc)) + remove_proc_entry("ide/sis", 0); +#endif /* CONFIG_BLK_DEV_SIS5513 */ +#ifdef CONFIG_BLK_DEV_VIA82CXXX + if ((via_display_info) && (via_proc)) + remove_proc_entry("ide/via",0); +#endif /* CONFIG_BLK_DEV_VIA82CXXX */ remove_proc_entry("ide/drivers", 0); destroy_proc_ide_interfaces(); remove_proc_entry("ide", 0); diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.3.22/linux/drivers/block/ide-tape.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/block/ide-tape.c Mon Oct 18 11:14:22 1999 @@ -1833,7 +1833,7 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); idetape_discard_data (drive,bcount.all); - ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD); + ide_set_handler (drive,&idetape_pc_intr); return; } #if IDETAPE_DEBUG_LOG @@ -1855,7 +1855,7 @@ pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD); /* And set the interrupt handler again */ + ide_set_handler (drive,&idetape_pc_intr); /* And set the interrupt handler again */ } /* @@ -1928,7 +1928,7 @@ ide_do_reset (drive); return; } - ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD); /* Set the interrupt routine */ + ide_set_handler(drive, &idetape_pc_intr); /* Set the interrupt routine */ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ } @@ -1995,7 +1995,7 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { - ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD); + ide_set_handler(drive, &idetape_transfer_pc); OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); } else { OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); @@ -3579,6 +3579,7 @@ spin_lock_init(&tape->spinlock); drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ + drive->timeout = IDETAPE_WAIT_CMD; #ifdef CONFIG_BLK_DEV_IDEPCI /* * These two ide-pci host adapters appear to need this disabled. diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.3.22/linux/drivers/block/ide.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/ide.c Tue Oct 19 13:47:40 1999 @@ -149,9 +149,9 @@ #include #endif /* CONFIG_KMOD */ -#ifdef CONFIG_BLK_DEV_VIA82C586 -extern byte fifoconfig; /* defined in via82c586.c used by ide_setup()*/ -#endif +#ifdef CONFIG_BLK_DEV_VIA82CXXX +extern byte fifoconfig; /* defined in via82cxxx.c used by ide_setup() */ +#endif /* CONFIG_BLK_DEV_VIA82CXXX */ static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, @@ -498,13 +498,25 @@ } /* + * The below two are helpers used when modifying the drive timeout. + */ +static inline unsigned long set_timeout(ide_drive_t *drive, unsigned long timeout) +{ + unsigned long foo = drive->timeout; + drive->timeout = timeout; + return foo; +} + +#define restore_timeout(drive, old) (drive->timeout = old) + +/* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive. handler() points * at the appropriate code to handle the next interrupt, and a * timer is started to prevent us from waiting forever in case * something goes wrong (see the ide_timer_expiry() handler later on). */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout) +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler) { unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -517,8 +529,11 @@ } #endif hwgroup->handler = handler; - hwgroup->timer.expires = jiffies + timeout; - add_timer(&(hwgroup->timer)); + /* 0 means don't timeout */ + if (drive->timeout && !timer_pending(&hwgroup->timer)) { + hwgroup->timer.expires = jiffies + drive->timeout; + add_timer(&(hwgroup->timer)); + } spin_unlock_irqrestore(&hwgroup->spinlock, flags); } @@ -565,6 +580,7 @@ static void atapi_reset_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long old_timeout; byte stat; SELECT_DRIVE(HWIF(drive),drive); @@ -574,7 +590,9 @@ printk("%s: ATAPI reset complete\n", drive->name); } else { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); + old_timeout = set_timeout(drive, HZ / 20); + ide_set_handler (drive, &atapi_reset_pollfunc); + restore_timeout(drive, old_timeout); return; /* continue polling */ } hwgroup->poll_timeout = 0; /* end of polling */ @@ -595,11 +613,14 @@ { ide_hwgroup_t *hwgroup = HWGROUP(drive); ide_hwif_t *hwif = HWIF(drive); + unsigned long old_timeout; byte tmp; if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - ide_set_handler (drive, &reset_pollfunc, HZ/20); + old_timeout = set_timeout(drive, HZ / 20); + ide_set_handler (drive, &reset_pollfunc); + restore_timeout(drive, old_timeout); return; /* continue polling */ } printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp); @@ -667,6 +688,7 @@ unsigned long flags; ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long old_timeout; __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ @@ -678,7 +700,9 @@ udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); + old_timeout = set_timeout(drive, HZ / 20); + ide_set_handler (drive, &atapi_reset_pollfunc); + restore_timeout(drive, old_timeout); __restore_flags (flags); /* local CPU only */ return; } @@ -708,7 +732,18 @@ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &reset_pollfunc, HZ/20); + old_timeout = set_timeout(drive, HZ / 20); + ide_set_handler (drive, &reset_pollfunc); + restore_timeout(drive, old_timeout); + + /* + * Some weird controller like resetting themselves to a strange + * state when the disks are reset this way. At least, the Winbond + * 553 documentation says that + */ + if (hwif->resetproc != NULL) + hwif->resetproc(drive); + #endif /* OK_TO_RESET_CONTROLLER */ __restore_flags (flags); /* local CPU only */ @@ -899,7 +934,7 @@ */ void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { - ide_set_handler (drive, handler, WAIT_CMD); + ide_set_handler (drive, handler); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ OUT_BYTE(nsect,IDE_NSECTOR_REG); @@ -1018,6 +1053,10 @@ if (args[0] == WIN_SMART) { OUT_BYTE(0x4f, IDE_LCYL_REG); OUT_BYTE(0xc2, IDE_HCYL_REG); + OUT_BYTE(args[2],IDE_FEATURE_REG); + OUT_BYTE(args[1],IDE_SECTOR_REG); + ide_cmd(drive, args[0], args[3], &drive_cmd_intr); + return; } OUT_BYTE(args[2],IDE_FEATURE_REG); ide_cmd(drive, args[0], args[1], &drive_cmd_intr); @@ -1218,13 +1257,37 @@ bdev->current_request = hwgroup->rq = drive->queue; spin_unlock_irqrestore(&io_request_lock, io_flags); +#if 0 if (hwif->irq != masked_irq) - disable_irq(hwif->irq); + disable_irq_nosync(hwif->irq); spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags); start_request(drive); spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags); if (hwif->irq != masked_irq) enable_irq(hwif->irq); +#else + + if (masked_irq && hwif->irq != masked_irq) { + printk("%s: (disable_irq) %smasked_irq %d\n", + drive->name, + masked_irq ? "" : "un_", hwif->irq); + +#if 0 + disable_irq(hwif->irq); +#else + disable_irq_nosync(hwif->irq); +#endif + } + spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags); + start_request(drive); + spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags); + if (masked_irq && hwif->irq != masked_irq) { + printk("%s: (enable_irq) %smasked_irq %d\n", + drive->name, + masked_irq ? "" : "un_", hwif->irq); + enable_irq(hwif->irq); + } +#endif } } @@ -1373,8 +1436,8 @@ } hwgroup->busy = 1; /* should already be "1" */ hwgroup->handler = NULL; - del_timer(&hwgroup->timer); /* Is this needed?? */ - if (hwgroup->poll_timeout != 0) { /* polling in progress? */ + /* polling in progress or just don't timeout */ + if (hwgroup->poll_timeout != 0) { spin_unlock_irqrestore(&hwgroup->spinlock, flags); handler(drive); } else if (drive_is_ready(drive)) { @@ -1612,8 +1675,10 @@ } spin_unlock_irqrestore(&io_request_lock, flags); do_hwgroup_request(hwgroup); - if (action == ide_wait && rq->rq_status != RQ_INACTIVE) + if (action == ide_wait) { down(&sem); /* wait for it to be serviced */ + rq->sem = NULL; + } return rq->errors ? -EIO : 0; /* return -EIO if errors */ } @@ -2270,8 +2335,13 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed) { + struct hd_driveid *id = drive->id; + unsigned long flags; int err; + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ + /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, @@ -2287,6 +2357,109 @@ err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); +#if 0 + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); +#endif + + __restore_flags(flags); /* local CPU only */ + + switch(speed) { + case XFER_UDMA_4: + if (!((id->dma_ultra >> 8) & 16)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x1010; + } + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_UDMA_3: + if (!((id->dma_ultra >> 8) & 8)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0808; + } + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_UDMA_2: + if (!((id->dma_ultra >> 8) & 4)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0404; + } + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_UDMA_1: + if (!((id->dma_ultra >> 8) & 2)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0202; + } + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_UDMA_0: + if (!((id->dma_ultra >> 8) & 1)) { + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_ultra |= 0x0101; + } + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_MW_DMA_2: + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 4)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0404; + } + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_MW_DMA_1: + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 2)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0202; + } + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_MW_DMA_0: + drive->id->dma_ultra &= ~0xFF00; + if (!((id->dma_mword >> 8) & 1)) { + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_mword |= 0x0101; + } + drive->id->dma_1word &= ~0x0F00; + break; + case XFER_SW_DMA_2: + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_mword &= ~0x0F00; + if (!((id->dma_1word >> 8) & 4)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0404; + } + break; + case XFER_SW_DMA_1: + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_mword &= ~0x0F00; + if (!((id->dma_1word >> 8) & 2)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0202; + } + break; + case XFER_SW_DMA_0: + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_mword &= ~0x0F00; + if (!((id->dma_1word >> 8) & 1)) { + drive->id->dma_1word &= ~0x0F00; + drive->id->dma_1word |= 0x0101; + } + break; + default: + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + break; + } + return(err); } @@ -2803,7 +2976,7 @@ } } -#if defined(CONFIG_BLK_DEV_VIA82C586) +#if defined(CONFIG_BLK_DEV_VIA82CXXX) /* * Look for drive option "splitfifo=..." */ @@ -2853,7 +3026,7 @@ fifoconfig = tmp; goto done; } -#endif /* defined(CONFIG_BLK_DEV_VIA82C586) */ +#endif /* defined(CONFIG_BLK_DEV_VIA82CXXX) */ if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e') goto bad_option; @@ -3393,6 +3566,7 @@ EXPORT_SYMBOL(ide_scan_devices); EXPORT_SYMBOL(ide_register_subdriver); EXPORT_SYMBOL(ide_unregister_subdriver); +EXPORT_SYMBOL(ide_replace_subdriver); EXPORT_SYMBOL(ide_input_data); EXPORT_SYMBOL(ide_output_data); EXPORT_SYMBOL(atapi_input_bytes); @@ -3464,7 +3638,11 @@ while ((line = next) != NULL) { if ((next = strchr(line,' ')) != NULL) *next++ = 0; - if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '=')) + if (!strncmp(line,"ide",3) || +#ifdef CONFIG_BLK_DEV_VIA82CXXX + !strncmp(line,"splitfifo",9) || +#endif /* CONFIG_BLK_DEV_VIA82CXXX */ + (!strncmp(line,"hd",2) && line[2] != '=')) ide_setup(line); } } diff -u --recursive --new-file v2.3.22/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.22/linux/drivers/block/ll_rw_blk.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/block/ll_rw_blk.c Sat Oct 16 10:50:48 1999 @@ -416,10 +416,6 @@ count = bh->b_size >> 9; sector = bh->b_rsector; - /* We'd better have a real physical mapping! */ - if (!buffer_mapped(bh)) - BUG(); - /* It had better not be a new buffer by the time we see it */ if (buffer_new(bh)) BUG(); @@ -480,6 +476,13 @@ goto end_io; } + /* We'd better have a real physical mapping! + Check this bit only if the buffer was dirty and just locked + down by us so at this point flushpage will block and + won't clear the mapped bit under us. */ + if (!buffer_mapped(bh)) + BUG(); + /* look for a free request. */ /* Loop uses two requests, 1 for loop and 1 for the real device. * Cut max_req in half to avoid running out and deadlocking. */ @@ -694,7 +697,7 @@ sorry: for (i = 0; i < nr; i++) { - clear_bit(BH_Dirty, &bh[i]->b_state); + mark_buffer_clean(bh[i]); /* remeber to refile it */ clear_bit(BH_Uptodate, &bh[i]->b_state); bh[i]->b_end_io(bh[i], 0); } diff -u --recursive --new-file v2.3.22/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c --- v2.3.22/linux/drivers/block/paride/pcd.c Fri Oct 15 15:25:13 1999 +++ linux/drivers/block/paride/pcd.c Mon Oct 18 11:14:22 1999 @@ -214,8 +214,11 @@ static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn); static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg); +static int pcd_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc); static int pcd_detect(void); +static void pcd_probe_capabilities(void); static void do_pcd_read_drq(void); static void do_pcd_request(void); static void do_pcd_read(void); @@ -276,14 +279,18 @@ pcd_drive_reset, pcd_audio_ioctl, 0, /* dev_ioctl */ - CDC_CLOSE_TRAY | - CDC_OPEN_TRAY | - CDC_LOCK | - CDC_MCN | - CDC_MEDIA_CHANGED | - CDC_RESET | - CDC_PLAY_AUDIO, - 0 + CDC_CLOSE_TRAY | + CDC_OPEN_TRAY | + CDC_LOCK | + CDC_MCN | + CDC_MEDIA_CHANGED | + CDC_RESET | + CDC_PLAY_AUDIO | + CDC_GENERIC_PACKET | + CDC_CD_R | + CDC_CD_RW, + 0, + pcd_packet, }; static void pcd_init_units( void ) @@ -325,6 +332,9 @@ if (pcd_detect()) return -1; + /* get the atapi capabilities page */ + pcd_probe_capabilities(); + if (register_blkdev(MAJOR_NR,name,&cdrom_fops)) { printk("pcd: unable to get major number %d\n",MAJOR_NR); return -1; @@ -525,6 +535,16 @@ return r; } +static int pcd_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + char *un_cmd; + int unit = DEVICE_NR(cdi->dev); + + un_cmd = cgc->cmd; + return pcd_atapi(unit,un_cmd,cgc->buflen,cgc->buffer, "generic packet"); +} + #define DBMSG(msg) ((verbose>1)?(msg):NULL) static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr) @@ -667,6 +687,32 @@ return -1; } +static void pcd_probe_capabilities( void ) + +{ int unit, r; + char buffer[32]; + char cmd[12]={0x5a,1<<3,0x2a,0,0,0,0,18,0,0,0,0}; + + for (unit=0;unit> 6) == 0) + PCD.info.mask |= CDC_CLOSE_TRAY; + } +} + static int pcd_detect( void ) { char id[18]; @@ -836,63 +882,6 @@ switch (cmd) { - case CDROMPAUSE: - - { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO; - } - - case CDROMRESUME: - - { char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO; - } - - case CDROMPLAYMSF: - - { char cmd[12]={GPCMD_PLAY_AUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0}; - struct cdrom_msf* msf = (struct cdrom_msf*)arg; - - cmd[3] = msf->cdmsf_min0; - cmd[4] = msf->cdmsf_sec0; - cmd[5] = msf->cdmsf_frame0; - cmd[6] = msf->cdmsf_min1; - cmd[7] = msf->cdmsf_sec1; - cmd[8] = msf->cdmsf_frame1; - - return (pcd_atapi(unit,cmd,0,NULL,"play msf")) * EIO; - } - - case CDROMPLAYBLK: - - { char cmd[12]={GPCMD_PLAY_AUDIO_10,0,0,0,0,0,0,0,0,0,0,0}; - struct cdrom_blk* blk = (struct cdrom_blk*)arg; - - cmd[2] = blk->from >> 24; - cmd[3] = blk->from >> 16; - cmd[4] = blk->from >> 8; - cmd[5] = blk->from; - cmd[7] = blk->len >> 8; - cmd[8] = blk->len; - - return (pcd_atapi(unit,cmd,0,NULL,"play block")) * EIO; - } - - case CDROMPLAYTRKIND: - - { char cmd[12]={GPCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0}; - struct cdrom_ti* ti = (struct cdrom_ti*)arg; - - cmd[4] = ti->cdti_trk0; - cmd[5] = ti->cdti_ind0; - cmd[7] = ti->cdti_trk1; - cmd[8] = ti->cdti_ind1; - - return (pcd_atapi(unit,cmd,0,NULL,"play track")) * EIO; - } - case CDROMREADTOCHDR: { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0}; @@ -935,97 +924,6 @@ return r * EIO; } - - case CDROMSTOP: - - { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,0,0,0,0,0,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO; - } - - case CDROMSTART: - - { char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,1,0,0,0,0,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO; - } - - case CDROMVOLCTRL: - - { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0}; - char buffer[32]; - char mask[32]; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - - cmd[2] = 0xe; - cmd[4] = 28; - - if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol")) - return -EIO; - - cmd[2] = 0x4e; - - if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol mask")) - return -EIO; - - buffer[0] = 0; - - buffer[21] = volctrl->channel0 & mask[21]; - buffer[23] = volctrl->channel1 & mask[23]; - buffer[25] = volctrl->channel2 & mask[25]; - buffer[27] = volctrl->channel3 & mask[27]; - - cmd[0] = 0x55; - cmd[1] = 0x10; - - return pcd_atapi(unit,cmd,28,buffer,"mode select vol") * EIO; - } - - case CDROMVOLREAD: - - { char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0}; - char buffer[32]; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - int r; - - cmd[2] = 0xe; - cmd[4] = 28; - - r = pcd_atapi(unit,cmd,28,buffer,"mode sense vol read"); - - volctrl->channel0 = buffer[21]; - volctrl->channel1 = buffer[23]; - volctrl->channel2 = buffer[25]; - volctrl->channel3 = buffer[27]; - - return r * EIO; - } - - - case CDROMSUBCHNL: - - { char cmd[12]={GPCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0}; - struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; - char buffer[32]; - - if (pcd_atapi(unit,cmd,16,buffer,"read subchannel")) - return -EIO; - - subchnl->cdsc_audiostatus = buffer[1]; - subchnl->cdsc_format = CDROM_MSF; - subchnl->cdsc_ctrl = buffer[5] & 0xf; - subchnl->cdsc_trk = buffer[6]; - subchnl->cdsc_ind = buffer[7]; - - subchnl->cdsc_reladdr.msf.minute = buffer[13]; - subchnl->cdsc_reladdr.msf.second = buffer[14]; - subchnl->cdsc_reladdr.msf.frame = buffer[15]; - subchnl->cdsc_absaddr.msf.minute = buffer[9]; - subchnl->cdsc_absaddr.msf.second = buffer[10]; - subchnl->cdsc_absaddr.msf.frame = buffer[11]; - - return 0; - } default: diff -u --recursive --new-file v2.3.22/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c --- v2.3.22/linux/drivers/block/pdc202xx.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/block/pdc202xx.c Mon Oct 18 11:14:22 1999 @@ -1,8 +1,8 @@ /* - * linux/drivers/block/pdc202xx.c Version 0.26 May 12, 1999 + * linux/drivers/block/pdc202xx.c Version 0.27 Sept. 3, 1999 * - * Copyright (C) 1998-99 Andre Hedrick - * (hedrick@astro.dyer.vanderbilt.edu) + * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License * * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this * compiled into the kernel if you have more than one card installed. @@ -72,6 +72,12 @@ * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); */ +/* + * Portions Copyright (C) 1999 Promise Technology, Inc. + * Author: Frank Tiernan (frankt@promise.com) + * Released under terms of General Public License + */ + #include #include #include @@ -88,6 +94,8 @@ #include #include +#include "ide_modes.h" + #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 @@ -208,27 +216,78 @@ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; + unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; int err; unsigned int drive_conf; byte drive_pci; - byte test1, test2, speed; - byte AP, BP, CP, DP, EP; + byte test1, test2, speed = -1; + byte AP, BP, CP, DP, TB, TC; + unsigned short EP; + byte CLKSPD = IN_BYTE(high_16 + 0x11); int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); byte udma_66 = ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0; - byte udma_33 = ultra ? (inb((dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0; + byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0; - pci_read_config_byte(dev, 0x50, &EP); + /* + * Set the control register to use the 66Mhz system + * clock for UDMA 3/4 mode operation. If one drive on + * a channel is U66 capable but the other isn't we + * fall back to U33 mode. The BIOS INT 13 hooks turn + * the clock on then off for each read/write issued. I don't + * do that here because it would require modifying the + * kernel, seperating the fop routines from the kernel or + * somehow hooking the fops calls. It may also be possible to + * leave the 66Mhz clock on and readjust the timing + * parameters. + */ + + byte mask = hwif->channel ? 0x08 : 0x02; + unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10); + byte ultra_66 = ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0; + + pci_read_config_word(dev, 0x50, &EP); + + if ((ultra_66) && (EP & c_mask)) { +#ifdef DEBUG + printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary", "Primary"); + printk(" Switching to Ultra33 mode.\n"); +#endif /* DEBUG */ + /* Primary : zero out second bit */ + /* Secondary : zero out fourth bit */ + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); + } else { + if (ultra_66) { + /* + * check to make sure drive on same channel + * is u66 capable + */ + if (hwif->drives[!(drive_number%2)].id) { + if ((hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0010) || + (hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0008)) { + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); + } else { + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); + } + } else { /* udma4 drive by itself */ + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); + } + } + } switch(drive_number) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 1: drive_pci = 0x64; pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; pci_read_config_byte(dev, 0x60, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -236,12 +295,16 @@ break; case 2: drive_pci = 0x68; pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; pci_read_config_byte(dev, (drive_pci), &test1); if (!(test1 & SYNC_ERRDY_EN)) pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); break; case 3: drive_pci = 0x6c; pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; pci_read_config_byte(dev, 0x68, &test1); pci_read_config_byte(dev, (drive_pci), &test2); if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) @@ -251,6 +314,8 @@ return ide_dma_off; } +chipset_is_set: + if (drive->media != ide_disk) return ide_dma_off_quietly; @@ -285,127 +350,46 @@ pci_read_config_byte(dev, (drive_pci)|0x02, &CP); if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { - if (!((id->dma_ultra >> 8) & 16)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x1010; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } /* speed 8 == UDMA mode 4 == speed 6 plus cable */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01); - speed = XFER_UDMA_4; + speed = XFER_UDMA_4; TB = 0x20; TC = 0x01; } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) { - if (!((id->dma_ultra >> 8) & 8)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0808; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } /* speed 7 == UDMA mode 3 == speed 5 plus cable */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02); - speed = XFER_UDMA_3; + speed = XFER_UDMA_3; TB = 0x40; TC = 0x02; } else if ((id->dma_ultra & 0x0004) && (udma_33)) { - if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } /* speed 6 == UDMA mode 2 */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01); - speed = XFER_UDMA_2; + speed = XFER_UDMA_2; TB = 0x20; TC = 0x01; } else if ((id->dma_ultra & 0x0002) && (udma_33)) { - if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } /* speed 5 == UDMA mode 1 */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02); - speed = XFER_UDMA_1; + speed = XFER_UDMA_1; TB = 0x40; TC = 0x02; } else if ((id->dma_ultra & 0x0001) && (udma_33)) { - if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } /* speed 4 == UDMA mode 0 */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03); - speed = XFER_UDMA_0; + speed = XFER_UDMA_0; TB = 0x60; TC = 0x03; } else if (id->dma_mword & 0x0004) { - if (!((id->dma_mword >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0404; - drive->id->dma_1word &= ~0x0F00; - } /* speed 4 == DMA mode 2 multi-word */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03); - speed = XFER_MW_DMA_2; + speed = XFER_MW_DMA_2; TB = 0x60; TC = 0x03; } else if (id->dma_mword & 0x0002) { - if (!((id->dma_mword >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0202; - drive->id->dma_1word &= ~0x0F00; - } /* speed 3 == DMA mode 1 multi-word */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x04); - speed = XFER_MW_DMA_1; + speed = XFER_MW_DMA_1; TB = 0x60; TC = 0x04; } else if (id->dma_mword & 0x0001) { - if (!((id->dma_mword >> 8) & 1)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0101; - drive->id->dma_1word &= ~0x0F00; - } /* speed 2 == DMA mode 0 multi-word */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05); - speed = XFER_MW_DMA_0; + speed = XFER_MW_DMA_0; TB = 0x60; TC = 0x05; } else if (id->dma_1word & 0x0004) { - if (!((id->dma_1word >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0404; - } /* speed 2 == DMA mode 2 single-word */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05); - speed = XFER_SW_DMA_2; + speed = XFER_SW_DMA_2; TB = 0x60; TC = 0x05; } else if (id->dma_1word & 0x0002) { - if (!((id->dma_1word >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0202; - } /* speed 1 == DMA mode 1 single-word */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x80); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x06); - speed = XFER_SW_DMA_1; + speed = XFER_SW_DMA_1; TB = 0x80; TC = 0x06; } else if (id->dma_1word & 0x0001) { - if (!((id->dma_1word >> 8) & 1)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0101; - } /* speed 0 == DMA mode 0 single-word */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP|0xC0); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x0B); - speed = XFER_SW_DMA_0; + speed = XFER_SW_DMA_0; TB = 0xC0; TC = 0x0B; } else { /* restore original pci-config space */ pci_write_config_dword(dev, drive_pci, drive_conf); return ide_dma_off_quietly; } - err = ide_config_drive_speed(drive, speed); + pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); #if PDC202XX_DECODE_REGISTER_INFO pci_read_config_byte(dev, (drive_pci), &AP); @@ -418,6 +402,8 @@ 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), @@ -441,6 +427,83 @@ * 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; @@ -450,9 +513,10 @@ if (id && (id->capability & 1) && hwif->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 */ @@ -463,17 +527,31 @@ } } else if (id->field_valid & 2) { try_dma_modes: - if ((id->dma_mword & 0x0004) || - (id->dma_1word & 0x0004)) { + if ((id->dma_mword & 0x0007) || + (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)) { + if (id->eide_dma_time > 150) { + 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); } @@ -498,6 +576,26 @@ byte primary_mode = inb(high_16 + 0x001a); byte secondary_mode = inb(high_16 + 0x001b); + if (dev->device == PCI_DEVICE_ID_PROMISE_20262) { + int i = 0; + /* + * software reset - this is required because the bios + * will set UDMA timing on if the hdd supports it. The + * user may want to turn udma off. A bug in the pdc20262 + * is that it cannot handle a downgrade in timing from UDMA + * to DMA. Disk accesses after issuing a set feature command + * will result in errors. A software reset leaves the timing + * registers intact, but resets the drives. + */ + + OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); + ide_delay_50ms(); + ide_delay_50ms(); + OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); + for (i=0; i<40; i++) + ide_delay_50ms(); + } + if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(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); @@ -547,24 +645,23 @@ return dev->irq; } +unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif) +{ + unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10); + unsigned short CIS; + + pci_read_config_word(hwif->pci_dev, 0x50, &CIS); + return ((CIS & mask) ? 0 : 1); +} + void __init ide_init_pdc202xx (ide_hwif_t *hwif) { + hwif->tuneproc = &pdc202xx_tune_drive; + if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; - - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_PROMISE_20262: -#if 0 - { - unsigned long high_16 = hwif->pci_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; - hwif->udma_four = 1; - } -#endif - break; - case PCI_DEVICE_ID_PROMISE_20246: - default: - hwif->udma_four = 0; - break; - } + } else { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; } } diff -u --recursive --new-file v2.3.22/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c --- v2.3.22/linux/drivers/block/pdc4030.c Sat Jun 26 08:34:20 1999 +++ linux/drivers/block/pdc4030.c Tue Oct 19 13:47:40 1999 @@ -162,6 +162,7 @@ if (!hwif) return 0; drive = &hwif->drives[0]; + drive->timeout = HZ/100; hwif2 = &ide_hwifs[hwif->index+1]; if (hwif->chipset == ide_pdc4030) /* we've already been found ! */ return 1; @@ -169,7 +170,8 @@ if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) { return 0; } - OUT_BYTE(0x08,IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE(0x08,IDE_CONTROL_REG); if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) { return 0; } @@ -307,6 +309,9 @@ unsigned int sectors_left, sectors_avail, nsect; struct request *rq; + /* reset timeout */ + drive->timeout = HZ/100; + if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { ide_error(drive, "promise_read_intr", stat); return; @@ -361,7 +366,8 @@ if (stat & DRQ_STAT) goto read_again; if (stat & BUSY_STAT) { - ide_set_handler (drive, &promise_read_intr, WAIT_CMD); + drive->timeout = WAIT_CMD; + ide_set_handler (drive, &promise_read_intr); #ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: waiting for" "interrupt\n", drive->name); @@ -390,7 +396,7 @@ if (GET_STAT() & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { - ide_set_handler(drive, &promise_complete_pollfunc, 1); + ide_set_handler(drive, &promise_complete_pollfunc); return; /* continue polling... */ } hwgroup->poll_timeout = 0; @@ -419,7 +425,7 @@ if (IN_BYTE(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { - ide_set_handler (drive, &promise_write_pollfunc, 1); + ide_set_handler (drive, &promise_write_pollfunc); return; /* continue polling... */ } hwgroup->poll_timeout = 0; @@ -433,7 +439,7 @@ */ ide_multwrite(drive, 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler(drive, &promise_complete_pollfunc, 1); + ide_set_handler(drive, &promise_complete_pollfunc); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n", drive->name, GET_STAT()); @@ -466,7 +472,7 @@ if (rq->nr_sectors > 4) { ide_multwrite(drive, rq->nr_sectors - 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &promise_write_pollfunc, 1); + ide_set_handler (drive, &promise_write_pollfunc); } else { /* * There are 4 or fewer sectors to transfer, do them all in one go @@ -474,7 +480,7 @@ */ ide_multwrite(drive, rq->nr_sectors); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler(drive, &promise_complete_pollfunc, 1); + ide_set_handler(drive, &promise_complete_pollfunc); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, " "status = %02x\n", drive->name, GET_STAT()); @@ -517,7 +523,8 @@ printk(KERN_DEBUG "%s: read: waiting for " "interrupt\n", drive->name); #endif - ide_set_handler(drive, &promise_read_intr, WAIT_CMD); + drive->timeout = WAIT_CMD; + ide_set_handler(drive, &promise_read_intr); return; } udelay(1); diff -u --recursive --new-file v2.3.22/linux/drivers/block/piix.c linux/drivers/block/piix.c --- v2.3.22/linux/drivers/block/piix.c Thu Aug 5 18:48:45 1999 +++ linux/drivers/block/piix.c Mon Oct 18 11:14:22 1999 @@ -1,8 +1,9 @@ /* - * linux/drivers/block/piix.c Version 0.25 July 11, 1999 + * linux/drivers/block/piix.c Version 0.27 Sept. 3, 1999 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer + * Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License * * PIO mode setting function for Intel chipsets. * For use instead of BIOS settings. @@ -182,30 +183,13 @@ } } - if ((id->dma_ultra & 0x0010) && (ultra)) { - goto backspeed; - } else if ((id->dma_ultra & 0x0008) && (ultra)) { - goto backspeed; - } else if ((id->dma_ultra & 0x0004) && (ultra)) { -backspeed: - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_ultra |= 0x0404; - } + if (((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008) || (id->dma_ultra & 0x0004)) && (ultra)) { u_speed = 2 << (drive_number * 4); if (!(reg4a & u_speed)) { pci_write_config_word(dev, 0x4a, reg4a|u_speed); } speed = XFER_UDMA_2; } else if ((id->dma_ultra & 0x0002) && (ultra)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_ultra |= 0x0202; - } u_speed = 1 << (drive_number * 4); if (!(reg4a & u_speed)) { pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); @@ -213,12 +197,6 @@ } speed = XFER_UDMA_1; } else if ((id->dma_ultra & 0x0001) && (ultra)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_ultra |= 0x0101; - } u_speed = 0 << (drive_number * 4); if (!(reg4a & u_speed)) { pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); @@ -228,32 +206,14 @@ } else if (id->dma_mword & 0x0004) { if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - if (!((id->dma_mword >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0404; - } speed = XFER_MW_DMA_2; } else if (id->dma_mword & 0x0002) { if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - if (!((id->dma_mword >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0202; - } speed = XFER_MW_DMA_1; } else if (id->dma_1word & 0x0004) { if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - drive->id->dma_ultra &= ~0x0F00; - drive->id->dma_mword &= ~0x0F00; - if (!((id->dma_1word >> 8) & 4)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0404; - } speed = XFER_SW_DMA_2; } else { speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); @@ -264,10 +224,7 @@ (void) ide_config_drive_speed(drive, speed); #if PIIX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d ", - drive->name, - ide_xfer_verbose(speed), - drive_number); + printk("%s: %s drive%d ", drive->name, ide_xfer_verbose(speed), drive_number); printk("\n"); #endif /* PIIX_DEBUG_DRIVE_INFO */ @@ -291,7 +248,7 @@ } #endif /* CONFIG_BLK_DEV_PIIX_TUNING */ -void ide_init_piix (ide_hwif_t *hwif) +void __init ide_init_piix (ide_hwif_t *hwif) { hwif->tuneproc = &piix_tune_drive; diff -u --recursive --new-file v2.3.22/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.3.22/linux/drivers/block/rd.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/rd.c Thu Oct 21 13:38:12 1999 @@ -704,8 +704,9 @@ #define OF(args) args +#ifndef memzero #define memzero(s, n) memset ((s), 0, (n)) - +#endif typedef unsigned char uch; typedef unsigned short ush; diff -u --recursive --new-file v2.3.22/linux/drivers/block/sis5513.c linux/drivers/block/sis5513.c --- v2.3.22/linux/drivers/block/sis5513.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/sis5513.c Mon Oct 18 11:14:22 1999 @@ -1,11 +1,11 @@ /* - * linux/drivers/block/sis5513.c Version 0.06 July 11, 1999 + * linux/drivers/block/sis5513.c Version 0.07 Sept. 3, 1999 * - * Copyright (C) 1999 Andre Hedrick + * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License * - * drive_number - * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + * Thanks to SIS Taiwan for direct support and hardware. + * Tested and designed on the SiS620/5513 chipset. */ #include @@ -27,10 +27,178 @@ #include "ide_modes.h" +#define SIS5513_DEBUG_DRIVE_INFO 0 + +#define DISPLAY_SIS_TIMINGS + static struct pci_dev *host_dev; -#define SIS5513_DEBUG_DRIVE_INFO 0 +#if 0 +static struct _pio_mode_mapping { + byte data_active; + byte recovery; + byte pio_mode; +} pio_mode_mapping[] = { + { 8, 12, 0 }, + { 6, 7, 1 }, + { 4, 4, 2 }, + { 3, 3, 3 }, + { 3, 1, 4 } +}; + +static struct _dma_mode_mapping { + byte data_active; + byte recovery; + byte dma_mode; +} dma_mode_mapping[] = { + { 8, 8, 0 }, + { 3, 2, 1 }, + { 3, 1, 2 } +}; + +static struct _udma_mode_mapping { + byte cycle_time; + char * udma_mode; +} udma_mode_mapping[] = { + { 8, "Mode 0" }, + { 6, "Mode 1" }, + { 4, "Mode 2" }, + { 3, "Mode 3" }, + { 2, "Mode 4" }, + { 0, "Undefined" } +}; + +static __inline__ char * find_udma_mode (byte cycle_time) +{ + int n; + + for (n = 0; n <= 4; n++) + if (udma_mode_mapping[n].cycle_time <= cycle_time) + return udma_mode_mapping[n].udma_mode; + return udma_mode_mapping[4].udma_mode; +} +#endif + +#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int sis_get_info(char *, char **, off_t, int, int); +extern int (*sis_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +struct pci_dev *bmide_dev; + +static char *cable_type[] = { + "80 pins", + "40 pins" +}; + +static char *recovery_time [] ={ + "12 PCICLK", "1 PCICLK", + "2 PCICLK", "3 PCICLK", + "4 PCICLK", "5 PCICLCK", + "6 PCICLK", "7 PCICLCK", + "8 PCICLK", "9 PCICLCK", + "10 PCICLK", "11 PCICLK", + "13 PCICLK", "14 PCICLK", + "15 PCICLK", "15 PCICLK" +}; + +static char *cycle_time [] = { + "Undefined", "2 CLCK", + "3 CLK", "4 CLK", + "5 CLK", "6 CLK", + "7 CLK", "8 CLK" +}; + +static char *active_time [] = { + "8 PCICLK", "1 PCICLCK", + "2 PCICLK", "2 PCICLK", + "4 PCICLK", "5 PCICLK", + "6 PCICLK", "12 PCICLK" +}; + +static int sis_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +{ + int rc; + char *p = buffer; + byte reg,reg1; +#if 0 + byte cyc, rec, act; +#endif + u16 reg2, reg3; + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + rc = pci_read_config_byte(bmide_dev, 0x4a, ®); + p += sprintf(p, "Channel Status: %s \t \t \t \t %s \n", + (reg & 0x02) ? "On" : "Off", + (reg & 0x04) ? "On" : "Off"); + + rc = pci_read_config_byte(bmide_dev, 0x09, ®); + p += sprintf(p, "Operation Mode: %s \t \t \t %s \n", + (reg & 0x01) ? "Native" : "Compatible", + (reg & 0x04) ? "Native" : "Compatible"); + + rc = pci_read_config_byte(bmide_dev, 0x48, ®); + p += sprintf(p, "Cable Type: %s \t \t \t %s\n", + (reg & 0x10) ? cable_type[1] : cable_type[0], + (reg & 0x20) ? cable_type[1] : cable_type[0]); + + rc = pci_read_config_word(bmide_dev, 0x4c, ®2); + rc = pci_read_config_word(bmide_dev, 0x4e, ®3); + p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n", + reg2, reg3); + + rc = pci_read_config_byte(bmide_dev, 0x4b, ®); + p += sprintf(p, "Drvie 0: Postwrite %s \t \t Postwrite %s\n", + (reg & 0x10) ? "Enabled" : "Disabled", + (reg & 0x40) ? "Enabled" : "Disabled"); + p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", + (reg & 0x01) ? "Enabled" : "Disabled", + (reg & 0x04) ? "Enabled" : "Disabled"); + + rc = pci_read_config_byte(bmide_dev, 0x41, ®); + rc = pci_read_config_byte(bmide_dev, 0x45, ®1); + p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n", + (reg & 0x80) ? "Enabled" : "Disabled", + (reg1 & 0x80) ? "Enabled" : "Disabled"); + p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n", + cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]); + p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n", + active_time[(reg & 0x07)], active_time[(reg &0x07)] ); + + rc = pci_read_config_byte(bmide_dev, 0x40, ®); + rc = pci_read_config_byte(bmide_dev, 0x44, ®1); + p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", + recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]); + + + rc = pci_read_config_byte(bmide_dev, 0x4b, ®); + p += sprintf(p, "Drvie 1: Postwrite %s \t \t Postwrite %s\n", + (reg & 0x20) ? "Enabled" : "Disabled", + (reg & 0x80) ? "Enabled" : "Disabled"); + p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", + (reg & 0x02) ? "Enabled" : "Disabled", + (reg & 0x08) ? "Enabled" : "Disabled"); + + rc = pci_read_config_byte(bmide_dev, 0x43, ®); + rc = pci_read_config_byte(bmide_dev, 0x47, ®1); + p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n", + (reg & 0x80) ? "Enabled" : "Disabled", + (reg1 & 0x80) ? "Enabled" : "Disabled"); + p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n", + cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]); + p += sprintf(p, " Data Active Time %s \t Data Active Time %s\n", + active_time[(reg & 0x07)], active_time[(reg &0x07)] ); + + rc = pci_read_config_byte(bmide_dev, 0x42, ®); + rc = pci_read_config_byte(bmide_dev, 0x46, ®1); + p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", + recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]); + return p-buffer; +} +#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ +byte sis_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); /* @@ -79,36 +247,18 @@ } if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) { - if (!((id->dma_ultra >> 8) & 16)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x1010; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } if (!(test2 & 0x90)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); pci_write_config_byte(dev, drive_pci|0x01, test2|0x90); } speed = XFER_UDMA_4; } else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) { - if (!((id->dma_ultra >> 8) & 8)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0808; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } if (!(test2 & 0xA0)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0); } speed = XFER_UDMA_3; } else if ((id->dma_ultra & 0x0004) && (ultra)) { - if (!((id->dma_ultra >> 8) & 4)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } mask = (four_two) ? 0xB0 : 0xA0; if (!(test2 & mask)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); @@ -116,12 +266,6 @@ } speed = XFER_UDMA_2; } else if ((id->dma_ultra & 0x0002) && (ultra)) { - if (!((id->dma_ultra >> 8) & 2)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } mask = (four_two) ? 0xD0 : 0xC0; if (!(test2 & mask)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); @@ -129,58 +273,22 @@ } speed = XFER_UDMA_1; } else if ((id->dma_ultra & 0x0001) && (ultra)) { - if (!((id->dma_ultra >> 8) & 1)) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_ultra |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } if (!(test2 & unmask)) { pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask); pci_write_config_byte(dev, drive_pci|0x01, test2|unmask); } speed = XFER_UDMA_0; } else if (id->dma_mword & 0x0004) { - if (!((id->dma_mword >> 8) & 4)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0404; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_2; } else if (id->dma_mword & 0x0002) { - if (!((id->dma_mword >> 8) & 2)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0202; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { - if (!((id->dma_mword >> 8) & 1)) { - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_mword |= 0x0101; - drive->id->dma_1word &= ~0x0F00; - } speed = XFER_MW_DMA_0; } else if (id->dma_1word & 0x0004) { - if (!((id->dma_1word >> 8) & 4)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0404; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_2; } else if (id->dma_1word & 0x0002) { - if (!((id->dma_1word >> 8) & 2)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0202; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_1; } else if (id->dma_1word & 0x0001) { - if (!((id->dma_1word >> 8) & 1)) { - drive->id->dma_1word &= ~0x0F00; - drive->id->dma_1word |= 0x0101; - drive->id->dma_mword &= ~0x0F00; - } speed = XFER_SW_DMA_0; } else { return ((int) ide_dma_off_quietly); @@ -189,10 +297,7 @@ err = ide_config_drive_speed(drive, speed); #if SIS5513_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", - drive->name, - ide_xfer_verbose(speed), - drive_number); + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number); #endif /* SIS5513_DEBUG_DRIVE_INFO */ return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : @@ -333,10 +438,9 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) { struct pci_dev *host; - byte latency = 0, reg48h = 0; + byte latency = 0; pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); - pci_read_config_byte(dev, 0x48, ®48h); for (host = pci_devices; host; host=host->next) { if (host->vendor == PCI_VENDOR_ID_SI && @@ -344,30 +448,18 @@ if (latency != 0x10) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); host_dev = host; - printk("%s: Chipset Core ATA-66, SiS620\n", name); - printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n", - name, - (reg48h & 0x10) ? "33" : "66", - (reg48h & 0x20) ? "33" : "66"); break; } else if (host->vendor == PCI_VENDOR_ID_SI && host->device == PCI_DEVICE_ID_SI_530) { host_dev = host; - printk("%s: Chipset Core ATA-66, SiS530\n", name); - printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n", - name, - (reg48h & 0x10) ? "33" : "66", - (reg48h & 0x20) ? "33" : "66"); break; } else if (host->vendor == PCI_VENDOR_ID_SI && host->device == PCI_DEVICE_ID_SI_5600) { host_dev = host; - printk("SIS5600:%s Chipset Core ATA-33\n", name); break; } else if (host->vendor == PCI_VENDOR_ID_SI && host->device == PCI_DEVICE_ID_SI_5597) { host_dev = host; - printk("SIS5597:%s Chipset Core ATA-33\n", name); break; } } @@ -377,18 +469,38 @@ pci_read_config_byte(dev, 0x52, ®52h); if (!(reg52h & 0x04)) + /* set IDE controller to operate in Compabitility mode obly */ 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; +#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ } - return 0; } -void __init ide_init_sis5513 (ide_hwif_t *hwif) +unsigned int __init ata66_sis5513 (ide_hwif_t *hwif) { - byte reg48h = 0; + byte reg48h = 0, ata66 = 0; byte mask = hwif->channel ? 0x20 : 0x10; - pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); + + if (host_dev) { + switch(host_dev->device) { + case PCI_DEVICE_ID_SI_530: + case PCI_DEVICE_ID_SI_620: + ata66 = (reg48h & mask) ? 0 : 1; + default: + break; + } + } + return (ata66); +} + +void __init ide_init_sis5513 (ide_hwif_t *hwif) +{ + hwif->irq = hwif->channel ? 15 : 14; if (!(hwif->dma_base)) @@ -398,20 +510,15 @@ switch(host_dev->device) { case PCI_DEVICE_ID_SI_530: case PCI_DEVICE_ID_SI_620: - hwif->autodma = 1; - hwif->udma_four = (reg48h & mask) ? 0 : 1; - hwif->dmaproc = &sis5513_dmaproc; - return; case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: hwif->autodma = 1; - hwif->udma_four = 0; hwif->dmaproc = &sis5513_dmaproc; - return; + break; default: hwif->autodma = 0; - hwif->udma_four = 0; - return; + break; } } + return; } diff -u --recursive --new-file v2.3.22/linux/drivers/block/sl82c105.c linux/drivers/block/sl82c105.c --- v2.3.22/linux/drivers/block/sl82c105.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/sl82c105.c Thu Oct 21 13:38:12 1999 @@ -5,7 +5,7 @@ * * Maintainer unknown. * - * Drive tuning added from Corel Computer's kernel sources + * Drive tuning added from Rebel.com's kernel sources * -- Russell King (15/11/98) linux@arm.linux.org.uk */ diff -u --recursive --new-file v2.3.22/linux/drivers/block/trm290.c linux/drivers/block/trm290.c --- v2.3.22/linux/drivers/block/trm290.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/trm290.c Mon Oct 18 11:14:22 1999 @@ -192,7 +192,8 @@ outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); + drive->timeout = WAIT_CMD; + ide_set_handler(drive, &ide_dma_intr); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); return 0; case ide_dma_begin: diff -u --recursive --new-file v2.3.22/linux/drivers/block/via82c586.c linux/drivers/block/via82c586.c --- v2.3.22/linux/drivers/block/via82c586.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/block/via82c586.c Wed Dec 31 16:00:00 1969 @@ -1,600 +0,0 @@ -/* - * linux/drivers/block/via82c586.c Version 0.04 July 11, 1999 - * - * Copyright (C) 1998 Michel Aubry, Maintainer - * Copyright (C) 1998 Andre Hedrick, Maintainer - * - * The VIA MVP-3 is reported OK with UDMA. - * The TX Pro III is also reported OK with UDMA. - * - * VIA chips also have a single FIFO, with the same 64 bytes deep - * buffer (16 levels of 4 bytes each). - * - * However, VIA chips can have the buffer split either 8:8 levels, - * 16:0 levels or 0:16 levels between both channels. One could think - * of using this feature, as even if no level of FIFO is given to a - * given channel, one can for instance always reach ATAPI drives through - * it, or, if one channel is unused, configuration defaults to - * an even split FIFO levels. - * - * This feature is available only through a kernel command line : - * "splitfifo=Chan,Thr0,Thr1" or "splitfifo=Chan". - * where: Chan =1,2,3 or 4 and Thrx = 1,2,3,or 4. - * - * If Chan == 1: - * gives all the fifo to channel 0, - * sets its threshold to Thr0/4, - * and disables any dma access to channel 1. - * - * If chan == 2: - * gives all the fifo to channel 1, - * sets its threshold to Thr1/4, - * and disables any dma access to channel 0. - * - * If chan == 3 or 4: - * shares evenly fifo between channels, - * gives channel 0 a threshold of Thr0/4, - * and channel 1 a threshold of Thr1/4. - * - * Note that by default (if no command line is provided) and if a channel - * has been disabled in Bios, all the fifo is given to the active channel, - * and its threshold is set to 3/4. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct pci_dev *host_dev; -static struct pci_dev *isa_dev; - -#define DISPLAY_VIA_TIMINGS - -#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) -#include -#include - -static char *FIFO_str[] = { - " 1 ", - "3/4", - "1/2", - "1/4" -}; - -static char *control3_str[] = { - "No limitation", - "64", - "128", - "192" -}; - -static int via_get_info(char *, char **, off_t, int, int); -extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ -static struct pci_dev *bmide_dev; - -static char * print_apollo_drive_config (char *buf, struct pci_dev *dev) -{ - int rc; - unsigned int time; - byte tm; - char *p = buf; - - /* Drive Timing Control */ - rc = pci_read_config_dword(dev, 0x48, &time); - p += sprintf(p, "Act Pls Width: %02d %02d %02d %02d\n", - ((time & 0xf0000000)>>28) + 1, - ((time & 0xf00000)>>20) + 1, - ((time & 0xf000)>>12) + 1, - ((time & 0xf0)>>4) + 1 ); - p += sprintf(p, "Recovery Time: %02d %02d %02d %02d\n", - ((time & 0x0f000000)>>24) + 1, - ((time & 0x0f0000)>>16) + 1, - ((time & 0x0f00)>>8) + 1, - (time & 0x0f) + 1 ); - - /* Address Setup Time */ - rc = pci_read_config_byte(dev, 0x4C, &tm); - p += sprintf(p, "Add. Setup T.: %01dT %01dT %01dT %01dT\n", - ((tm & 0xc0)>>6) + 1, - ((tm & 0x30)>>4) + 1, - ((tm & 0x0c)>>2) + 1, - (tm & 0x03) + 1 ); - - /* UltraDMA33 Extended Timing Control */ - rc = pci_read_config_dword(dev, 0x50, &time); - p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n"); - p += sprintf(p, "Enable Meth.: %01d %01d %01d %01d\n", - (time & 0x80000000) ? 1 : 0, - (time & 0x800000) ? 1 : 0, - (time & 0x8000) ? 1 : 0, - (time & 0x80) ? 1 : 0 ); - p += sprintf(p, "Enable: %s %s %s %s\n", - (time & 0x40000000) ? "yes" : "no ", - (time & 0x400000) ? "yes" : "no ", - (time & 0x4000) ? "yes" : "no ", - (time & 0x40) ? "yes" : "no " ); - p += sprintf(p, "Transfer Mode: %s %s %s %s\n", - (time & 0x20000000) ? "PIO" : "DMA", - (time & 0x200000) ? "PIO" : "DMA", - (time & 0x2000) ? "PIO" : "DMA", - (time & 0x20) ? "PIO" : "DMA" ); - p += sprintf(p, "Cycle Time: %01dT %01dT %01dT %01dT\n", - ((time & 0x03000000)>>24) + 2, - ((time & 0x030000)>>16) + 2, - ((time & 0x0300)>>8) + 2, - (time & 0x03) + 2 ); - - return (char *)p; -} - -static char * print_apollo_ide_config (char *buf, struct pci_dev *dev) -{ - byte time, tmp; - unsigned short size0, size1; - int rc; - char *p = buf; - - rc = pci_read_config_byte(dev, 0x41, &time); - p += sprintf(p, "Prefetch Buffer : %s %s\n", - (time & 128) ? "on " : "off", - (time & 32) ? "on " : "off" ); - p += sprintf(p, "Post Write Buffer: %s %s\n", - (time & 64) ? "on " : "off", - (time & 16) ? "on " : "off" ); - - /* FIFO configuration */ - rc = pci_read_config_byte(dev, 0x43, &time); - tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3); - p += sprintf(p, "FIFO Conf/Chan. : %02d %02d\n", - 16 - tmp, tmp); - tmp = (time & 0x0F)>>2; - p += sprintf(p, "Threshold Prim. : %s %s\n", - FIFO_str[tmp], - FIFO_str[time & 0x03] ); - - /* chipset Control3 */ - rc = pci_read_config_byte(dev, 0x46, &time); - p += sprintf(p, "Read DMA FIFO flush: %s %s\n", - (time & 0x80) ? "on " : "off", - (time & 0x40) ? "on " : "off" ); - p += sprintf(p, "End Sect. FIFO flush: %s %s\n", - (time & 0x20) ? "on " : "off", - (time & 0x10) ? "on " : "off" ); - p += sprintf(p, "Max DRDY Pulse Width: %s %s\n", - control3_str[(time & 0x03)], - (time & 0x03) ? "PCI clocks" : "" ); - - /* Primary and Secondary sector sizes */ - rc = pci_read_config_word(dev, 0x60, &size0); - rc = pci_read_config_word(dev, 0x68, &size1); - p += sprintf(p, "Bytes Per Sector: %03d %03d\n", - size0 & 0xfff, - size1 & 0xfff ); - - return (char *)p; -} - -static char * print_apollo_chipset_control1 (char *buf, struct pci_dev *dev) -{ - byte t; - int rc; - char *p = buf; - unsigned short c; - byte l, l_max; - - rc = pci_read_config_word(dev, 0x04, &c); - rc = pci_read_config_byte(dev, 0x44, &t); - rc = pci_read_config_byte(dev, 0x0d, &l); - rc = pci_read_config_byte(dev, 0x3f, &l_max); - - p += sprintf(p, "Command register = 0x%x\n", c); - p += sprintf(p, "Master Read Cycle IRDY %d Wait State\n", - (t & 64) >>6 ); - p += sprintf(p, "Master Write Cycle IRDY %d Wait State\n", - (t & 32) >> 5 ); - p += sprintf(p, "FIFO Output Data 1/2 Clock Advance: %s\n", - (t & 16) ? "on " : "off" ); - p += sprintf(p, "Bus Master IDE Status Register Read Retry: %s\n", - (t & 8) ? "on " : "off" ); - p += sprintf(p, "Latency timer = %d (max. = %d)\n", - l, l_max); - - return (char *)p; -} - -static char * print_apollo_chipset_control2 (char *buf, struct pci_dev *dev) -{ - byte t; - int rc; - char *p = buf; - rc = pci_read_config_byte(dev, 0x45, &t); - p += sprintf(p, "Interrupt Steering Swap: %s\n", - (t & 64) ? "on ":"off" ); - - return (char *)p; -} - -static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev, - unsigned short n) -{ - /* - * at that point we can be sure that register 0x20 of the - * chipset contains the right address... - */ - unsigned int bibma; - int rc; - byte c0, c1; - char *p = buf; - - rc = pci_read_config_dword(dev, 0x20, &bibma); - bibma = (bibma & 0xfff0) ; - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb((unsigned short)bibma + 0x02); - c1 = inb((unsigned short)bibma + 0x0a); - - if (n == 0) { - /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/ - p += sprintf(p, "both channels togth: %s %s\n", - (c0&0x80) ? "no" : "yes", - (c1&0x80) ? "no" : "yes" ); - } else { - /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/ - 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 " ); - } - - return (char *)p; -} - -static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) -{ - /* - * print what /proc/via displays, - * if required from DISPLAY_APOLLO_TIMINGS - */ - char *p = buffer; - /* Parameter of chipset : */ - - /* Miscellaneous control 1 */ - p = print_apollo_chipset_control1(buffer, bmide_dev); - - /* Miscellaneous control 2 */ - p = print_apollo_chipset_control2(p, bmide_dev); - /* Parameters of drives: */ - - /* Header */ - p += sprintf(p, "------------------Primary IDE------------Secondary IDE-----\n"); - p = print_apollo_chipset_control3(p, bmide_dev, 0); - p = print_apollo_ide_config(p, bmide_dev); - p += sprintf(p, "--------------drive0------drive1-------drive0------drive1----\n"); - p = print_apollo_chipset_control3(p, bmide_dev, 1); - p = print_apollo_drive_config(p, bmide_dev); - - return p-buffer; /* hoping it is less than 4K... */ -} - -#endif /* defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) */ - -/* - * Used to set Fifo configuration via kernel command line: - */ - -byte fifoconfig = 0; -static byte newfifo = 0; - -/* Used to just intialize once Fifo configuration */ -static short int done = 0; - -/* - * Set VIA Chipset Timings for (U)DMA modes enabled. - * - * VIA Apollo chipset has complete support for - * setting up the timing parameters. - */ -static void set_via_timings (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - byte post = hwif->channel ? 0x30 : 0xc0; - byte flush = hwif->channel ? 0x50 : 0xa0; - int mask = hwif->channel ? ((newfifo & 0x60) ? 0 : 1) : - (((newfifo & 0x60) == 0x60) ? 1 : 0); - byte via_config = 0; - int rc = 0, errors = 0; - - printk("%s: VIA Bus-Master ", hwif->name); - - /* - * setting IDE read prefetch buffer and IDE post write buffer. - * (This feature allows prefetched reads and post writes). - */ - if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) - errors++; - - if (mask) { - if ((rc = pci_write_config_byte(dev, 0x41, via_config & ~post))) - errors++; - } else { - if ((rc = pci_write_config_byte(dev, 0x41, via_config | post))) - errors++; - } - - /* - * setting Channel read and End-of-sector FIFO flush. - * (This feature ensures that FIFO flush is enabled: - * - for read DMA when interrupt asserts the given channel. - * - at the end of each sector for the given channel.) - */ - if ((rc = pci_read_config_byte(dev, 0x46, &via_config))) - errors++; - - if (mask) { - if ((rc = pci_write_config_byte(dev, 0x46, via_config & ~flush))) - errors++; - } else { - if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush))) - errors++; - } - - if (!hwif->dma_base) - printk("Config %s. No DMA Enabled\n", - errors ? "ERROR":"Success"); - else - printk("(U)DMA Timing Config %s\n", - errors ? "ERROR" : "Success"); -} - -/* - * Sets VIA 82c586 FIFO configuration: - * This chipsets gets a splitable fifo. This can be driven either by command - * line option (eg "splitfifo=2,2,3" which asks this driver to switch all the - * 16 fifo levels to the second drive, and give it a threshold of 3 for (u)dma - * triggering. - */ - -static int via_set_fifoconfig(ide_hwif_t *hwif) -{ - byte fifo; - unsigned int timings; - struct pci_dev *dev = hwif->pci_dev; - - /* read port configuration */ - if (pci_read_config_dword(dev, 0x40, &timings)) - return 1; - - /* first read actual fifo config: */ - if (pci_read_config_byte(dev, 0x43, &fifo)) - return 1; - - /* keep 4 and 7 bit as they seem to differ between chipsets flavors... */ - newfifo = fifo & 0x90; - - if (fifoconfig) { - /* we received a config request from kernel command line: */ - newfifo |= fifoconfig & 0x6f; - } else { - /* If ever just one channel is unused, allocate all fifo levels to it - * and give it a 3/4 threshold for (u)dma transfers. - * Otherwise, share it evenly between channels: - */ - if ((timings & 3) == 2) { - /* only primary channel is enabled - * 16 buf. to prim. chan. thresh=3/4 - */ - newfifo |= 0x06; - } else if ((timings & 3) == 1) { - /* only secondary channel is enabled! - * 16 buffers to sec. ch. thresh=3/4 - */ - newfifo |= 0x69; - } else { - /* fifo evenly distributed: */ - newfifo |= 0x2a; - } - } - - /* write resulting configuration to chipset: */ - if (pci_write_config_byte(dev, 0x43, newfifo)) - return 1; - - /* and then reread it to get the actual one */ - if (pci_read_config_byte(dev, 0x43, &newfifo)) - return 1; - - /* print a kernel report: */ - printk("Split FIFO Configuration: %s Primary buffers, threshold = %s\n", - ((newfifo & 0x60) == 0x60) ? " 0" : - ((newfifo & 0x60) ? " 8" : "16"), - !(newfifo & 0x0c) ? "1" : - (!(newfifo & 0x08) ? "3/4" : - (newfifo & 0x04) ? "1/4" : "1/2")); - - printk(" %s Second. buffers, threshold = %s\n", - ((newfifo & 0x60) == 0x60) ? "16" : - ((newfifo & 0x60) ? " 8" : " 0"), - !(newfifo & 0x03) ? "1" : - (!(newfifo & 0x02) ? "3/4" : - (newfifo & 0x01) ? "1/4" : "1/2")); - -#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) - bmide_dev = hwif->pci_dev; - via_display_info = &via_get_info; -#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ - return 0; -} - -unsigned int __init pci_init_via82c568 (struct pci_dev *dev, const char *name) -{ - struct pci_dev *host; - struct pci_dev *isa; - - byte revision = 0; - - for (host = pci_devices; host; host=host->next) { - if (host->vendor == PCI_VENDOR_ID_VIA && - host->device == PCI_DEVICE_ID_VIA_82C585) { - host_dev = host; - printk("VT 82C585 Apollo VP1/VPX"); - for (isa = pci_devices; isa; isa=isa->next) { - if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C586_1) { - isa_dev = isa; - pci_read_config_byte(isa_dev, 0x0d, &revision); - if (revision >= 0x20) - printk(" Chipset Core ATA-33"); - break; - } - } - printk("\n"); - break; - } else if (host->vendor == PCI_VENDOR_ID_VIA && - host->device == PCI_DEVICE_ID_VIA_82C595) { - host_dev = host; - printk("VT 82C595 Apollo VP2"); - for (isa = pci_devices; isa; isa=isa->next) { - if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C586_1) { - isa_dev = isa; - pci_read_config_byte(isa_dev, 0x0d, &revision); - if (revision >= 0x20) - printk(" Chipset Core ATA-33"); - break; - } - } - printk("\n"); - break; - } else if (host->vendor == PCI_VENDOR_ID_VIA && - host->device == PCI_DEVICE_ID_VIA_82C597_0) { - host_dev = host; - printk("VT 82C597 Apollo VP3"); - for (isa = pci_devices; isa; isa=isa->next) { - if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C586_1) { - isa_dev = isa; - pci_read_config_byte(isa_dev, 0x0d, &revision); - if (revision >= 0x20) - printk(" Chipset Core ATA-33"); - break; - } - } - printk("\n"); - break; - } else if (host->vendor == PCI_VENDOR_ID_VIA && - host->device == PCI_DEVICE_ID_VIA_82C598_0) { - host_dev = host; - printk("VT 82C598 Apollo MVP3"); - for (isa = pci_devices; isa; isa=isa->next) { - if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C586_1) { - isa_dev = isa; - pci_read_config_byte(isa_dev, 0x0d, &revision); - if (revision >= 0x20) - printk(" Chipset Core ATA-33"); - break; - } else if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C596) { - isa_dev = isa; - printk(" Chipset Core ATA-33"); - break; - } - } - printk("\n"); - break; - } else if (host->vendor == PCI_VENDOR_ID_VIA && - host->device == PCI_DEVICE_ID_VIA_82C680) { - host_dev = host; - printk("VT 82C680 Apollo P6"); - for (isa = pci_devices; isa; isa=isa->next) { - if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C586_1) { - isa_dev = isa; - pci_read_config_byte(isa_dev, 0x0d, &revision); - if (revision >= 0x20) - printk(" Chipset Core ATA-33"); - break; - } - } - printk("\n"); - break; - } else if (host->vendor == PCI_VENDOR_ID_VIA && - host->device == PCI_DEVICE_ID_VIA_82C691) { - host_dev = host; - printk("VT 82C691 Apollo Pro"); - for (isa = pci_devices; isa; isa=isa->next) { - if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C596) { - isa_dev = isa; - printk(" Chipset Core ATA-33"); - break; - } - } - printk("\n"); - break; - } else if (host->vendor == PCI_VENDOR_ID_VIA && - host->device == PCI_DEVICE_ID_VIA_82C693) { - host_dev = host; - printk("VT 82C693 Apollo Pro Plus"); - for (isa = pci_devices; isa; isa=isa->next) { - if (isa->vendor == PCI_VENDOR_ID_VIA && - isa->device == PCI_DEVICE_ID_VIA_82C596) { - isa_dev = isa; - printk(" Chipset Core ATA-33"); - break; - } - } - printk("\n"); - break; - } - } - return 0; -} - -void __init ide_init_via82c586 (ide_hwif_t *hwif) -{ - set_via_timings(hwif); -} - -/* - * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) - * checks if channel "channel" of if hwif is dma - * capable or not, according to kernel command line, - * and the new fifo settings. - * It calls "ide_setup_dma" on capable mainboards, and - * bypasses the setup if not capable. - */ - -void ide_dmacapable_via82c586 (ide_hwif_t *hwif, unsigned long dmabase) -{ - if (!done) { - via_set_fifoconfig(hwif); - done = 1; - } - - /* - * check if any fifo is available for requested port: - */ - if (((hwif->channel == 0) && ((newfifo & 0x60) == 0x60)) || - ((hwif->channel == 1) && ((newfifo & 0x60) == 0x00))) { - printk(" %s: VP_IDE Bus-Master DMA disabled (FIFO setting)\n", hwif->name); - } else { - ide_setup_dma(hwif, dmabase, 8); - } -} diff -u --recursive --new-file v2.3.22/linux/drivers/block/via82cxxx.c linux/drivers/block/via82cxxx.c --- v2.3.22/linux/drivers/block/via82cxxx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/via82cxxx.c Mon Oct 18 11:14:22 1999 @@ -0,0 +1,572 @@ +/* + * linux/drivers/block/via82cxxx.c Version 0.05 Sept. 03, 1999 + * + * Copyright (C) 1998-99 Michel Aubry, Maintainer + * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@pobox.com) + * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * May be copied or modified under the terms of the GNU General Public License + * + * The VIA MVP-4 is reported OK with UDMA. + * The VIA MVP-3 is reported OK with UDMA. + * The TX Pro III is also reported OK with UDMA. + * + * VIA chips also have a single FIFO, with the same 64 bytes deep + * buffer (16 levels of 4 bytes each). + * + * However, VIA chips can have the buffer split either 8:8 levels, + * 16:0 levels or 0:16 levels between both channels. One could think + * of using this feature, as even if no level of FIFO is given to a + * given channel, one can for instance always reach ATAPI drives through + * it, or, if one channel is unused, configuration defaults to + * an even split FIFO levels. + * + * This feature is available only through a kernel command line : + * "splitfifo=Chan,Thr0,Thr1" or "splitfifo=Chan". + * where: Chan =1,2,3 or 4 and Thrx = 1,2,3,or 4. + * + * If Chan == 1: + * gives all the fifo to channel 0, + * sets its threshold to Thr0/4, + * and disables any dma access to channel 1. + * + * If chan == 2: + * gives all the fifo to channel 1, + * sets its threshold to Thr1/4, + * and disables any dma access to channel 0. + * + * If chan == 3 or 4: + * shares evenly fifo between channels, + * gives channel 0 a threshold of Thr0/4, + * and channel 1 a threshold of Thr1/4. + * + * Note that by default (if no command line is provided) and if a channel + * has been disabled in Bios, all the fifo is given to the active channel, + * and its threshold is set to 3/4. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct pci_dev *host_dev = NULL; +static struct pci_dev *isa_dev = NULL; + +static const struct { + const char *name; + unsigned short host_id; +} ApolloHostChipInfo[] = { + { "VT 82C585 Apollo VP1/VPX", PCI_DEVICE_ID_VIA_82C585, }, + { "VT 82C595 Apollo VP2", PCI_DEVICE_ID_VIA_82C595, }, + { "VT 82C597 Apollo VP3", PCI_DEVICE_ID_VIA_82C597_0, }, + { "VT 82C598 Apollo MVP3", PCI_DEVICE_ID_VIA_82C598_0, }, + { "VT 82C680 Apollo P6", PCI_DEVICE_ID_VIA_82C680, }, + { "VT 82C691 Apollo Pro", PCI_DEVICE_ID_VIA_82C691, }, + { "VT 82C693 Apollo Pro Plus", PCI_DEVICE_ID_VIA_82C693, }, + { "Apollo MVP4", PCI_DEVICE_ID_VIA_8501_0, }, +}; + +#define NUM_APOLLO_ISA_CHIP_DEVICES 2 +#define VIA_FLAG_CHECK_REV 0x00000001 +#define VIA_FLAG_ATA_66 0x00000002 + +static const struct { + unsigned short host_id; + unsigned short isa_id; + unsigned int flags; +} ApolloISAChipInfo[] = { + { PCI_DEVICE_ID_VIA_82C585, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, + { PCI_DEVICE_ID_VIA_82C595, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, + { PCI_DEVICE_ID_VIA_82C597_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, + { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, + { PCI_DEVICE_ID_VIA_82C598_0, PCI_DEVICE_ID_VIA_82C596, 0 }, + { PCI_DEVICE_ID_VIA_82C680, PCI_DEVICE_ID_VIA_82C586_1, VIA_FLAG_CHECK_REV }, + { PCI_DEVICE_ID_VIA_82C691, PCI_DEVICE_ID_VIA_82C596, 0 }, + { PCI_DEVICE_ID_VIA_82C693, PCI_DEVICE_ID_VIA_82C596, 0 }, + { PCI_DEVICE_ID_VIA_8501_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66 }, +}; + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define DISPLAY_VIA_TIMINGS + +#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static char *FIFO_str[] = { + " 1 ", + "3/4", + "1/2", + "1/4" +}; + +static char *control3_str[] = { + "No limitation", + "64", + "128", + "192" +}; + +static int via_get_info(char *, char **, off_t, int, int); +extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +static struct pci_dev *bmide_dev; + +static char * print_apollo_drive_config (char *buf, struct pci_dev *dev) +{ + int rc; + unsigned int time; + byte tm; + char *p = buf; + + /* Drive Timing Control */ + rc = pci_read_config_dword(dev, 0x48, &time); + p += sprintf(p, "Act Pls Width: %02d %02d %02d %02d\n", + ((time & 0xf0000000)>>28) + 1, + ((time & 0xf00000)>>20) + 1, + ((time & 0xf000)>>12) + 1, + ((time & 0xf0)>>4) + 1 ); + p += sprintf(p, "Recovery Time: %02d %02d %02d %02d\n", + ((time & 0x0f000000)>>24) + 1, + ((time & 0x0f0000)>>16) + 1, + ((time & 0x0f00)>>8) + 1, + (time & 0x0f) + 1 ); + + /* Address Setup Time */ + rc = pci_read_config_byte(dev, 0x4C, &tm); + p += sprintf(p, "Add. Setup T.: %01dT %01dT %01dT %01dT\n", + ((tm & 0xc0)>>6) + 1, + ((tm & 0x30)>>4) + 1, + ((tm & 0x0c)>>2) + 1, + (tm & 0x03) + 1 ); + + /* UltraDMA33 Extended Timing Control */ + rc = pci_read_config_dword(dev, 0x50, &time); + p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n"); + p += sprintf(p, "Enable Meth.: %01d %01d %01d %01d\n", + (time & 0x80000000) ? 1 : 0, + (time & 0x800000) ? 1 : 0, + (time & 0x8000) ? 1 : 0, + (time & 0x80) ? 1 : 0 ); + p += sprintf(p, "Enable: %s %s %s %s\n", + (time & 0x40000000) ? "yes" : "no ", + (time & 0x400000) ? "yes" : "no ", + (time & 0x4000) ? "yes" : "no ", + (time & 0x40) ? "yes" : "no " ); + p += sprintf(p, "Transfer Mode: %s %s %s %s\n", + (time & 0x20000000) ? "PIO" : "DMA", + (time & 0x200000) ? "PIO" : "DMA", + (time & 0x2000) ? "PIO" : "DMA", + (time & 0x20) ? "PIO" : "DMA" ); + p += sprintf(p, "Cycle Time: %01dT %01dT %01dT %01dT\n", + ((time & 0x03000000)>>24) + 2, + ((time & 0x030000)>>16) + 2, + ((time & 0x0300)>>8) + 2, + (time & 0x03) + 2 ); + + return (char *)p; +} + +static char * print_apollo_ide_config (char *buf, struct pci_dev *dev) +{ + byte time, tmp; + unsigned short size0, size1; + int rc; + char *p = buf; + + rc = pci_read_config_byte(dev, 0x41, &time); + p += sprintf(p, "Prefetch Buffer : %s %s\n", + (time & 128) ? "on " : "off", + (time & 32) ? "on " : "off" ); + p += sprintf(p, "Post Write Buffer: %s %s\n", + (time & 64) ? "on " : "off", + (time & 16) ? "on " : "off" ); + + /* FIFO configuration */ + rc = pci_read_config_byte(dev, 0x43, &time); + tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3); + p += sprintf(p, "FIFO Conf/Chan. : %02d %02d\n", + 16 - tmp, tmp); + tmp = (time & 0x0F)>>2; + p += sprintf(p, "Threshold Prim. : %s %s\n", + FIFO_str[tmp], + FIFO_str[time & 0x03] ); + + /* chipset Control3 */ + rc = pci_read_config_byte(dev, 0x46, &time); + p += sprintf(p, "Read DMA FIFO flush: %s %s\n", + (time & 0x80) ? "on " : "off", + (time & 0x40) ? "on " : "off" ); + p += sprintf(p, "End Sect. FIFO flush: %s %s\n", + (time & 0x20) ? "on " : "off", + (time & 0x10) ? "on " : "off" ); + p += sprintf(p, "Max DRDY Pulse Width: %s %s\n", + control3_str[(time & 0x03)], + (time & 0x03) ? "PCI clocks" : "" ); + + /* Primary and Secondary sector sizes */ + rc = pci_read_config_word(dev, 0x60, &size0); + rc = pci_read_config_word(dev, 0x68, &size1); + p += sprintf(p, "Bytes Per Sector: %03d %03d\n", + size0 & 0xfff, + size1 & 0xfff ); + + return (char *)p; +} + +static char * print_apollo_chipset_control1 (char *buf, struct pci_dev *dev) +{ + byte t; + int rc; + char *p = buf; + unsigned short c; + byte l, l_max; + + rc = pci_read_config_word(dev, 0x04, &c); + rc = pci_read_config_byte(dev, 0x44, &t); + rc = pci_read_config_byte(dev, 0x0d, &l); + rc = pci_read_config_byte(dev, 0x3f, &l_max); + + p += sprintf(p, "Command register = 0x%x\n", c); + p += sprintf(p, "Master Read Cycle IRDY %d Wait State\n", + (t & 64) >>6 ); + p += sprintf(p, "Master Write Cycle IRDY %d Wait State\n", + (t & 32) >> 5 ); + p += sprintf(p, "FIFO Output Data 1/2 Clock Advance: %s\n", + (t & 16) ? "on " : "off" ); + p += sprintf(p, "Bus Master IDE Status Register Read Retry: %s\n", + (t & 8) ? "on " : "off" ); + p += sprintf(p, "Latency timer = %d (max. = %d)\n", + l, l_max); + + return (char *)p; +} + +static char * print_apollo_chipset_control2 (char *buf, struct pci_dev *dev) +{ + byte t; + int rc; + char *p = buf; + rc = pci_read_config_byte(dev, 0x45, &t); + p += sprintf(p, "Interrupt Steering Swap: %s\n", + (t & 64) ? "on ":"off" ); + + return (char *)p; +} + +static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev, + unsigned short n) +{ + /* + * at that point we can be sure that register 0x20 of the + * chipset contains the right address... + */ + unsigned int bibma; + int rc; + byte c0, c1; + char *p = buf; + + rc = pci_read_config_dword(dev, 0x20, &bibma); + bibma = (bibma & 0xfff0) ; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb((unsigned short)bibma + 0x02); + c1 = inb((unsigned short)bibma + 0x0a); + + if (n == 0) { + /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/ + p += sprintf(p, "both channels togth: %s %s\n", + (c0&0x80) ? "no" : "yes", + (c1&0x80) ? "no" : "yes" ); + } else { + /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/ + 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 " ); + } + + return (char *)p; +} + +static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +{ + /* + * print what /proc/via displays, + * if required from DISPLAY_APOLLO_TIMINGS + */ + char *p = buffer; + /* Parameter of chipset : */ + + /* Miscellaneous control 1 */ + p = print_apollo_chipset_control1(buffer, bmide_dev); + + /* Miscellaneous control 2 */ + p = print_apollo_chipset_control2(p, bmide_dev); + /* Parameters of drives: */ + + /* Header */ + p += sprintf(p, "------------------Primary IDE------------Secondary IDE-----\n"); + p = print_apollo_chipset_control3(p, bmide_dev, 0); + p = print_apollo_ide_config(p, bmide_dev); + p += sprintf(p, "--------------drive0------drive1-------drive0------drive1----\n"); + p = print_apollo_chipset_control3(p, bmide_dev, 1); + p = print_apollo_drive_config(p, bmide_dev); + + return p-buffer; /* hoping it is less than 4K... */ +} + +#endif /* defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) */ + +/* + * Used to set Fifo configuration via kernel command line: + */ + +byte via_proc = 0; +byte fifoconfig = 0; +static byte newfifo = 0; + +/* Used to just intialize once Fifo configuration */ +static short int done = 0; + +/* + * Set VIA Chipset Timings for (U)DMA modes enabled. + * + * VIA Apollo chipset has complete support for + * setting up the timing parameters. + */ +static void set_via_timings (ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; + byte post = hwif->channel ? 0x30 : 0xc0; + byte flush = hwif->channel ? 0x50 : 0xa0; + int mask = hwif->channel ? ((newfifo & 0x60) ? 0 : 1) : + (((newfifo & 0x60) == 0x60) ? 1 : 0); + byte via_config = 0; + int rc = 0, errors = 0; + + printk("%s: VIA Bus-Master ", hwif->name); + + /* + * setting IDE read prefetch buffer and IDE post write buffer. + * (This feature allows prefetched reads and post writes). + */ + if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) + errors++; + + if (mask) { + if ((rc = pci_write_config_byte(dev, 0x41, via_config & ~post))) + errors++; + } else { + if ((rc = pci_write_config_byte(dev, 0x41, via_config | post))) + errors++; + } + + /* + * setting Channel read and End-of-sector FIFO flush. + * (This feature ensures that FIFO flush is enabled: + * - for read DMA when interrupt asserts the given channel. + * - at the end of each sector for the given channel.) + */ + if ((rc = pci_read_config_byte(dev, 0x46, &via_config))) + errors++; + + if (mask) { + if ((rc = pci_write_config_byte(dev, 0x46, via_config & ~flush))) + errors++; + } else { + if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush))) + errors++; + } + + if (!hwif->dma_base) + printk("Config %s. No DMA Enabled\n", + errors ? "ERROR":"Success"); + else + printk("(U)DMA Timing Config %s\n", + errors ? "ERROR" : "Success"); +} + +/* + * Sets VIA 82cxxx FIFO configuration: + * This chipsets gets a splitable fifo. This can be driven either by command + * line option (eg "splitfifo=2,2,3" which asks this driver to switch all the + * 16 fifo levels to the second drive, and give it a threshold of 3 for (u)dma + * triggering. + */ + +static int via_set_fifoconfig(ide_hwif_t *hwif) +{ + byte fifo; + unsigned int timings; + struct pci_dev *dev = hwif->pci_dev; + + /* read port configuration */ + if (pci_read_config_dword(dev, 0x40, &timings)) + return 1; + + /* first read actual fifo config: */ + if (pci_read_config_byte(dev, 0x43, &fifo)) + return 1; + + /* keep 4 and 7 bit as they seem to differ between chipsets flavors... */ + newfifo = fifo & 0x90; + + if (fifoconfig) { + /* we received a config request from kernel command line: */ + newfifo |= fifoconfig & 0x6f; + } else { + /* If ever just one channel is unused, allocate all fifo levels to it + * and give it a 3/4 threshold for (u)dma transfers. + * Otherwise, share it evenly between channels: + */ + if ((timings & 3) == 2) { + /* only primary channel is enabled + * 16 buf. to prim. chan. thresh=3/4 + */ + newfifo |= 0x06; + } else if ((timings & 3) == 1) { + /* only secondary channel is enabled! + * 16 buffers to sec. ch. thresh=3/4 + */ + newfifo |= 0x69; + } else { + /* fifo evenly distributed: */ + newfifo |= 0x2a; + } + } + + /* write resulting configuration to chipset: */ + if (pci_write_config_byte(dev, 0x43, newfifo)) + return 1; + + /* and then reread it to get the actual one */ + if (pci_read_config_byte(dev, 0x43, &newfifo)) + return 1; + + /* print a kernel report: */ + printk("Split FIFO Configuration: %s Primary buffers, threshold = %s\n", + ((newfifo & 0x60) == 0x60) ? " 0" : + ((newfifo & 0x60) ? " 8" : "16"), + !(newfifo & 0x0c) ? "1" : + (!(newfifo & 0x08) ? "3/4" : + (newfifo & 0x04) ? "1/4" : "1/2")); + + printk(" %s Second. buffers, threshold = %s\n", + ((newfifo & 0x60) == 0x60) ? "16" : + ((newfifo & 0x60) ? " 8" : " 0"), + !(newfifo & 0x03) ? "1" : + (!(newfifo & 0x02) ? "3/4" : + (newfifo & 0x01) ? "1/4" : "1/2")); + +#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) + via_proc = 1; + bmide_dev = hwif->pci_dev; + via_display_info = &via_get_info; +#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ + return 0; +} + +unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name) +{ + struct pci_dev *host; + struct pci_dev *isa; + int i, j, ata33, ata66; + + byte revision = 0; + + for (i = 0; i < arraysize (ApolloHostChipInfo) && !host_dev; i++) { + host = pci_find_device (PCI_VENDOR_ID_VIA, + ApolloHostChipInfo[i].host_id, + NULL); + if (!host) + continue; + + host_dev = host; + printk(ApolloHostChipInfo[i].name); + + for (j = 0; j < arraysize (ApolloISAChipInfo) && !isa_dev; j++) { + if (ApolloISAChipInfo[j].host_id != + ApolloHostChipInfo[i].host_id) + continue; + + isa = pci_find_device (PCI_VENDOR_ID_VIA, + ApolloISAChipInfo[i].isa_id, + NULL); + if (!isa) + continue; + + isa_dev = isa; + + ata33 = 1; + ata66 = 0; + + if (ApolloISAChipInfo[i].flags & VIA_FLAG_CHECK_REV) { + pci_read_config_byte(isa_dev, 0x0d, &revision); + ata33 = (revision >= 0x20) ? 1 : 0; + } else if (ApolloISAChipInfo[i].flags & VIA_FLAG_ATA_66) { + ata33 = 0; + ata66 = 1; + } + + if (ata33 | ata66) + printk(" Chipset Core ATA-%s", ata66 ? "66" : "33"); + } + printk("\n"); + } + + return 0; +} + +unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif) +{ + /* (Jeff Garzik) FIXME!!! for MVP4 */ + return 0; +} + +void __init ide_init_via82cxxx (ide_hwif_t *hwif) +{ + set_via_timings(hwif); +} + +/* + * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) + * checks if channel "channel" of if hwif is dma + * capable or not, according to kernel command line, + * and the new fifo settings. + * It calls "ide_setup_dma" on capable mainboards, and + * bypasses the setup if not capable. + */ + +void ide_dmacapable_via82cxxx (ide_hwif_t *hwif, unsigned long dmabase) +{ + if (!done) { + via_set_fifoconfig(hwif); + done = 1; + } + + /* + * check if any fifo is available for requested port: + */ + if (((hwif->channel == 0) && ((newfifo & 0x60) == 0x60)) || + ((hwif->channel == 1) && ((newfifo & 0x60) == 0x00))) { + printk(" %s: VP_IDE Bus-Master DMA disabled (FIFO setting)\n", hwif->name); + } else { + ide_setup_dma(hwif, dmabase, 8); + } +} diff -u --recursive --new-file v2.3.22/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.3.22/linux/drivers/cdrom/cdrom.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/cdrom/cdrom.c Tue Oct 19 13:47:40 1999 @@ -177,10 +177,15 @@ for ide-cd to handle multisession discs. -- Export cdrom_mode_sense and cdrom_mode_select. -- init_cdrom_command() for setting up a cgc command. + + 3.05 Sep 23, 1999 - Jens Axboe + -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually + impossible to send the drive data in a sensible way. + -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.04" -#define VERSION "Id: cdrom.c 3.04 1999/09/14" +#define REVISION "Revision: 3.05" +#define VERSION "Id: cdrom.c 3.05 1999/09/23" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -213,6 +218,7 @@ #include #include #include +#include #include #include #include @@ -316,7 +322,7 @@ if (cdo->open == NULL || cdo->release == NULL) return -2; if ( !banner_printed ) { - printk(KERN_INFO "Uniform CDROM driver " REVISION "\n"); + printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n"); banner_printed = 1; #ifdef CONFIG_SYSCTL cdrom_sysctl_register(); @@ -404,6 +410,8 @@ return cdi; } +static int cdrom_setup_writemode(struct cdrom_device_info *cdi); + /* We use the open-option O_NONBLOCK to indicate that the * purpose of opening is only for subsequent ioctl() calls; no device * integrity checks are performed. @@ -415,22 +423,31 @@ static int cdrom_open(struct inode *ip, struct file *fp) { + struct cdrom_device_info *cdi; kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device(dev); - int purpose = !!(fp->f_flags & O_NONBLOCK); - int ret=0; + int ret; cdinfo(CD_OPEN, "entering cdrom_open\n"); - if (cdi == NULL) + if ((cdi = cdrom_find_device(dev)) == NULL) return -ENODEV; - if (fp->f_mode & FMODE_WRITE) - return -EROFS; - purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); - if (purpose) - ret = cdi->ops->open(cdi, purpose); + + /* just CD-RW for now. DVD-RW will come soon, CD-R and DVD-R + * need to be handled differently. */ + if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_CD_RW)) + return -EROFS; + + /* if this was a O_NONBLOCK open and we should honor the flags, + * do a quick open without drive/disc integrity checks. */ + if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) + ret = cdi->ops->open(cdi, 1); else ret = open_for_data(cdi); + if (!ret) cdi->use_count++; + + if (fp->f_mode & FMODE_WRITE && !cdi->write.writeable) + cdi->write.writeable = !cdrom_setup_writemode(cdi); + cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count); /* Do this on open. Don't wait for mount, because they might not be mounting, but opening with O_NONBLOCK */ @@ -525,7 +542,7 @@ if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 1); cdinfo(CD_OPEN, "door locked.\n"); - } + } cdinfo(CD_OPEN, "device opened successfully.\n"); return ret; @@ -616,7 +633,7 @@ if (cdi->use_count > 0) cdi->use_count--; if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); - if (cdi->use_count == 0 && /* last process that closes dev*/ + if (cdi->use_count == 0 && cdo->capability & CDC_LOCK && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); @@ -1701,8 +1718,8 @@ unsigned long arg) { struct cdrom_device_ops *cdo = cdi->ops; - kdev_t dev = cdi->dev; struct cdrom_generic_command cgc; + kdev_t dev = cdi->dev; char buffer[32]; int ret = 0; @@ -1919,7 +1936,7 @@ case CDROMSTART: case CDROMSTOP: { - cdinfo(CD_DO_IOCTL, "entering audio ioctl (start/stop)\n"); + cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); cgc.cmd[0] = GPCMD_START_STOP_UNIT; cgc.cmd[1] = 1; cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; @@ -1928,7 +1945,7 @@ case CDROMPAUSE: case CDROMRESUME: { - cdinfo(CD_DO_IOCTL, "entering audio ioctl (pause/resume)\n"); + cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); cgc.cmd[0] = GPCMD_PAUSE_RESUME; cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; return cdo->generic_packet(cdi, &cgc); @@ -1938,7 +1955,7 @@ dvd_struct s; if (!CDROM_CAN(CDC_DVD)) return -ENOSYS; - cdinfo(CD_DO_IOCTL, "entering dvd_read_struct\n"); + cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); IOCTL_IN(arg, dvd_struct, s); if ((ret = dvd_read_struct(cdi, &s))) return ret; @@ -1950,7 +1967,7 @@ dvd_authinfo ai; if (!CDROM_CAN(CDC_DVD)) return -ENOSYS; - cdinfo(CD_DO_IOCTL, "entering dvd_auth\n"); + cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); IOCTL_IN(arg, dvd_authinfo, ai); if ((ret = dvd_do_auth (cdi, &ai))) return ret; @@ -1959,26 +1976,58 @@ } case CDROM_SEND_PACKET: { + __u8 *userbuf, copy = 0; if (!CDROM_CAN(CDC_GENERIC_PACKET)) return -ENOSYS; - cdinfo(CD_DO_IOCTL, "entering send_packet\n"); + cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); IOCTL_IN(arg, struct cdrom_generic_command, cgc); - cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL); + copy = !!cgc.buflen; + userbuf = cgc.buffer; + cgc.buffer = NULL; + if (userbuf != NULL && copy) { + /* usually commands just copy data one way, i.e. + * we send a buffer to the drive and the command + * specifies whether the drive will read or + * write to that buffer. usually the buffers + * are very small, so we don't loose that much + * by doing a redundant copy each time. */ + if (!access_ok(VERIFY_WRITE, userbuf, cgc.buflen)) { + printk("can't get write perms\n"); + return -EFAULT; + } + if (!access_ok(VERIFY_READ, userbuf, cgc.buflen)) { + printk("can't get read perms\n"); + return -EFAULT; + } + } + /* reasonable limits */ + if (cgc.buflen < 0 || cgc.buflen > 131072) { + printk("invalid size given\n"); + return -EINVAL; + } + if (copy) { + cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL); + if (cgc.buffer == NULL) + return -ENOMEM; + __copy_from_user(cgc.buffer, userbuf, cgc.buflen); + } ret = cdo->generic_packet(cdi, &cgc); - if (copy_to_user((void*)arg, cgc.buffer, cgc.buflen)) - ret = -EFAULT; + if (copy && !ret) + __copy_to_user(userbuf, cgc.buffer, cgc.buflen); kfree(cgc.buffer); return ret; } case CDROM_NEXT_WRITABLE: { - long next; + long next = 0; + cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); if ((ret = cdrom_get_next_writable(dev, &next))) return ret; IOCTL_OUT(arg, long, next); return 0; } case CDROM_LAST_WRITTEN: { - long last; + long last = 0; + cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); if ((ret = cdrom_get_last_written(dev, &last))) return ret; IOCTL_OUT(arg, long, last); @@ -2038,10 +2087,10 @@ track_information ti; __u32 last_track; int ret = -1; - + if (!CDROM_CAN(CDC_GENERIC_PACKET)) goto use_toc; - + if ((ret = cdrom_get_disc_info(dev, &di))) goto use_toc; @@ -2089,7 +2138,7 @@ track_information ti; __u16 last_track; int ret = -1; - + if (!CDROM_CAN(CDC_GENERIC_PACKET)) goto use_last_written; @@ -2125,6 +2174,99 @@ } } +/* return the buffer size of writeable drives */ +static int cdrom_read_buffer_capacity(struct cdrom_device_info *cdi) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + struct { + unsigned int pad; + unsigned int buffer_size; + unsigned int buffer_free; + } buf; + int ret; + + init_cdrom_command(&cgc, &buf, 12); + cgc.cmd[0] = 0x5c; + cgc.cmd[8] = 12; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + return be32_to_cpu(buf.buffer_size); +} + +/* return 0 if succesful and the disc can be considered writeable. */ +static int cdrom_setup_writemode(struct cdrom_device_info *cdi) +{ + struct cdrom_generic_command cgc; + write_param_page wp; + disc_information di; + track_information ti; + int ret, last_track; + + memset(&di, 0, sizeof(disc_information)); + memset(&ti, 0, sizeof(track_information)); + memset(&wp, 0, sizeof(write_param_page)); + memset(&cdi->write, 0, sizeof(struct cdrom_write_settings)); + + if ((ret = cdrom_get_disc_info(cdi->dev, &di))) + return ret; + + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + if ((ret = cdrom_get_track_info(cdi->dev, last_track, 1, &ti))) + return ret; + + /* if the media is erasable, then it is either CD-RW or + * DVD-RW - use fixed packets for those. non-erasable media + * indicated CD-R or DVD-R media, use varible sized packets for + * those (where the packet size is a bit less than the buffer + * capacity of the drive. */ + if (di.erasable) { + cdi->write.fpacket = 1; + /* FIXME: DVD-RW is 16, should get the packet size instead */ + cdi->write.packet_size = 32; + } else { + int buf_size; + cdi->write.fpacket = 0; + buf_size = cdrom_read_buffer_capacity(cdi); + buf_size -= 100*1024; + cdi->write.packet_size = buf_size / CD_FRAMESIZE; + } + + init_cdrom_command(&cgc, &wp, 0x3c); + if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) + return ret; + + /* sanity checks */ + if ((ti.damage && !ti.nwa_v) || ti.blank) { + cdinfo(CD_WARNING, "can't write to this disc\n"); + return 1; + } + + /* NWA is only for CD-R and DVD-R. -RW media is randomly + * writeable once it has been formatted. */ + cdi->write.nwa = ti.nwa_v ? be32_to_cpu(ti.next_writable) : 0; + + wp.fp = cdi->write.fpacket ? 1 : 0; + wp.track_mode = 0; + wp.write_type = 0; + wp.data_block_type = 8; + wp.session_format = 0; + wp.multi_session = 3; + wp.audio_pause = cpu_to_be16(0x96); + wp.packet_size = cdi->write.fpacket ? cpu_to_be32(cdi->write.packet_size) : 0; + wp.track_mode = 5; /* should be ok with both CD and DVD */ + + if ((ret = cdrom_mode_select(cdi, &cgc))) + return ret; + + cdinfo(CD_WARNING, "%s: writeable with %lu block %s packets\n", + cdi->name, cdi->write.packet_size, + cdi->write.fpacket ? "fixed" : "variable"); + return 0; +} + EXPORT_SYMBOL(cdrom_get_next_writable); EXPORT_SYMBOL(cdrom_get_last_written); EXPORT_SYMBOL(cdrom_count_tracks); @@ -2384,22 +2526,22 @@ initialized = 1; } +#endif /* endif CONFIG_SYSCTL */ + #ifdef MODULE static void cdrom_sysctl_unregister(void) { +#ifdef CONFIG_SYSCTL unregister_sysctl_table(cdrom_sysctl_header); +#endif } -#endif /* endif MODULE */ -#endif /* endif CONFIG_SYSCTL */ - -#ifdef MODULE int init_module(void) { #ifdef CONFIG_SYSCTL cdrom_sysctl_register(); -#endif /* CONFIG_SYSCTL */ +#endif return 0; } @@ -2410,5 +2552,5 @@ cdrom_sysctl_unregister(); #endif /* CONFIG_SYSCTL */ } - #endif /* endif MODULE */ + diff -u --recursive --new-file v2.3.22/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.22/linux/drivers/char/Config.in Fri Oct 15 15:25:13 1999 +++ linux/drivers/char/Config.in Fri Oct 15 23:37:34 1999 @@ -10,15 +10,15 @@ fi tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then - bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS - bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ - bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ - bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT - bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6 + bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS + bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ + bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ + bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT + bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6 fi bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then @@ -86,31 +86,31 @@ if [ "$CONFIG_QIC02_TAPE" != "n" ]; then bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then - comment ' Edit configuration parameters in ./include/linux/tpqic02.h!' + comment ' Edit configuration parameters in ./include/linux/tpqic02.h!' else - comment ' Setting runtime QIC-02 configuration is done with qic02conf' - comment ' from the tpqic02-support package. It is available at' - comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/' + comment ' Setting runtime QIC-02 configuration is done with qic02conf' + comment ' from the tpqic02-support package. It is available at' + comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/' fi dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV - dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN + dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN fi bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then mainmenu_option next_comment comment 'Watchdog Cards' - bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT - tristate ' WDT Watchdog timer' CONFIG_WDT + bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT + tristate ' WDT Watchdog timer' CONFIG_WDT if [ "$CONFIG_WDT" != "n" ]; then - bool ' WDT501 features' CONFIG_WDT_501 + bool ' WDT501 features' CONFIG_WDT_501 if [ "$CONFIG_WDT_501" = "y" ]; then - bool ' Fan Tachometer' CONFIG_WDT_501_FAN + bool ' Fan Tachometer' CONFIG_WDT_501_FAN fi fi - tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG - tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG - tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT + tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG + tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG + tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT endmenu fi diff -u --recursive --new-file v2.3.22/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.22/linux/drivers/char/Makefile Fri Sep 10 23:57:29 1999 +++ linux/drivers/char/Makefile Mon Oct 18 11:26:31 1999 @@ -117,7 +117,7 @@ endif ifeq ($(CONFIG_COMPUTONE),y) -L_OBJS += ip2.o ip2main.o +O_OBJS += ip2.o ip2main.o else ifeq ($(CONFIG_COMPUTONE),m) M_OBJS += ip2.o ip2main.o @@ -165,7 +165,7 @@ endif ifeq ($(CONFIG_SX),y) -L_OBJS += sx.o generic_serial.o +O_OBJS += sx.o generic_serial.o else ifeq ($(CONFIG_SX),m) M_OBJS += sx.o diff -u --recursive --new-file v2.3.22/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.3.22/linux/drivers/char/console.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/char/console.c Tue Oct 19 10:22:20 1999 @@ -94,6 +94,7 @@ #ifdef CONFIG_APM #include #endif +#include #include #include @@ -2286,7 +2287,7 @@ struct tty_driver console_driver; static int console_refcount; -unsigned long __init con_init(unsigned long kmem_start) +void __init con_init(void) { const char *display_desc = NULL; unsigned int currcons = 0; @@ -2295,7 +2296,7 @@ display_desc = conswitchp->con_startup(); if (!display_desc) { fg_console = 0; - return kmem_start; + return; } memset(&console_driver, 0, sizeof(struct tty_driver)); @@ -2336,19 +2337,18 @@ timer_active |= 1<con_save_screen); @@ -2376,8 +2376,6 @@ #endif init_bh(CONSOLE_BH, console_bh); - - return kmem_start; } #ifndef VT_SINGLE_DRIVER diff -u --recursive --new-file v2.3.22/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.3.22/linux/drivers/char/istallion.c Tue Sep 7 12:14:06 1999 +++ linux/drivers/char/istallion.c Mon Oct 18 11:26:31 1999 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.22/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.3.22/linux/drivers/char/mem.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/char/mem.c Thu Oct 21 13:38:12 1999 @@ -158,6 +158,9 @@ prot = (prot & _CACHEMASK040) | _PAGE_NOCACHE_S; #elif defined(__mips__) prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED; +#elif defined(__arm__) && defined(CONFIG_CPU_32) + /* Turn off caching for all I/O areas */ + prot &= ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE); #endif return prot; diff -u --recursive --new-file v2.3.22/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.3.22/linux/drivers/char/n_tty.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/char/n_tty.c Tue Oct 19 10:22:20 1999 @@ -811,7 +811,7 @@ if (!tty->read_buf) { tty->read_buf = (unsigned char *) - get_free_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + get_zeroed_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!tty->read_buf) return -ENOMEM; } diff -u --recursive --new-file v2.3.22/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.3.22/linux/drivers/char/pcxx.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/pcxx.c Mon Oct 18 11:26:31 1999 @@ -1589,8 +1589,8 @@ ch->blocked_open = 0; ch->callout_termios = pcxe_callout.init_termios; ch->normal_termios = pcxe_driver.init_termios; - init_waitqueue_head(ch->open_wait); - init_waitqueue_head(ch->close_wait); + init_waitqueue_head(&ch->open_wait); + init_waitqueue_head(&ch->close_wait); ch->asyncflags = 0; } diff -u --recursive --new-file v2.3.22/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c --- v2.3.22/linux/drivers/char/radio-cadet.c Mon Jul 5 20:07:02 1999 +++ linux/drivers/char/radio-cadet.c Mon Oct 18 11:26:31 1999 @@ -39,6 +39,7 @@ static __u8 rdsin=0,rdsout=0,rdsstat=0; static unsigned char rdsbuf[RDS_BUFFER]; static int cadet_lock=0; +static int cadet_probe(void); /* * Signal Strength Threshold Values diff -u --recursive --new-file v2.3.22/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.3.22/linux/drivers/char/serial.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/serial.c Tue Oct 19 10:22:20 1999 @@ -1127,7 +1127,7 @@ unsigned short ICP; #endif - page = get_free_page(GFP_KERNEL); + page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; @@ -2974,7 +2974,7 @@ #endif if (!tmp_buf) { - page = get_free_page(GFP_KERNEL); + page = get_zeroed_page(GFP_KERNEL); if (!page) { return -ENOMEM; } @@ -4359,10 +4359,9 @@ /* * Register console. */ -long __init serial_console_init(long kmem_start, long kmem_end) +void __init serial_console_init(void) { register_console(&sercons); - return kmem_start; } #endif diff -u --recursive --new-file v2.3.22/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.3.22/linux/drivers/char/stallion.c Tue Sep 7 12:14:06 1999 +++ linux/drivers/char/stallion.c Mon Oct 18 11:26:31 1999 @@ -28,6 +28,7 @@ #include #include +#include /* for linux/stallion.h */ #include #include #include diff -u --recursive --new-file v2.3.22/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.22/linux/drivers/char/tty_io.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/char/tty_io.c Tue Oct 19 10:22:20 1999 @@ -129,7 +129,7 @@ extern int sx_init (void); #endif #ifdef CONFIG_8xx -extern long console_8xx_init(long, long); +extern console_8xx_init(void); extern int rs_8xx_init(void); #endif /* CONFIG_8xx */ @@ -798,7 +798,7 @@ tp = o_tp = NULL; ltp = o_ltp = NULL; - tty = (struct tty_struct*) get_free_page(GFP_KERNEL); + tty = (struct tty_struct*) get_zeroed_page(GFP_KERNEL); if(!tty) goto fail_no_mem; initialize_tty_struct(tty); @@ -824,7 +824,7 @@ } if (driver->type == TTY_DRIVER_TYPE_PTY) { - o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL); + o_tty = (struct tty_struct *) get_zeroed_page(GFP_KERNEL); if (!o_tty) goto free_mem_out; initialize_tty_struct(o_tty); @@ -2062,7 +2062,7 @@ * Just do some early initializations, and do the complex setup * later. */ -long __init console_init(long kmem_start, long kmem_end) +void __init console_init(void) { /* Setup the default TTY line discipline. */ memset(ldiscs, 0, sizeof(ldiscs)); @@ -2085,16 +2085,15 @@ * inform about problems etc.. */ #ifdef CONFIG_VT - kmem_start = con_init(kmem_start); + con_init(); #endif #ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_8xx - kmem_start = console_8xx_init(kmem_start, kmem_end); + console_8xx_init(); #else - kmem_start = serial_console_init(kmem_start, kmem_end); + serial_console_init(); #endif /* CONFIG_8xx */ #endif - return kmem_start; } static struct tty_driver dev_tty_driver, dev_syscons_driver; @@ -2109,7 +2108,7 @@ * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */ -int __init tty_init(void) +void __init tty_init(void) { if (sizeof(struct tty_struct) > PAGE_SIZE) panic("size of tty structure > PAGE_SIZE!"); @@ -2220,5 +2219,4 @@ #ifdef CONFIG_VT vcs_init(); #endif - return 0; } diff -u --recursive --new-file v2.3.22/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.3.22/linux/drivers/char/vt.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/vt.c Thu Oct 21 13:38:12 1999 @@ -61,7 +61,7 @@ */ unsigned char keyboard_type = KB_101; -#ifndef __alpha__ +#if !defined(__alpha__) && !defined(__arm__) asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); #endif @@ -89,7 +89,8 @@ */ #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ - || (defined(__mips__) && !defined(CONFIG_SGI)) + || (defined(__mips__) && !defined(CONFIG_SGI)) \ + || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) static void kd_nosound(unsigned long ignored) @@ -470,7 +471,7 @@ ucval = keyboard_type; goto setchar; -#ifndef __alpha__ +#if !defined(__alpha__) && !defined(__arm__) /* * These cannot be implemented on any machine that implements * ioperm() in user level (such as Alpha PCs). diff -u --recursive --new-file v2.3.22/linux/drivers/i2o/Config.in linux/drivers/i2o/Config.in --- v2.3.22/linux/drivers/i2o/Config.in Mon Oct 4 15:49:29 1999 +++ linux/drivers/i2o/Config.in Mon Oct 18 11:26:31 1999 @@ -5,7 +5,9 @@ dep_tristate ' I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O dep_tristate ' I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O -dep_tristate ' I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O +if [ "$CONFIG_NET" = "y" ]; then + dep_tristate ' I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O +fi dep_tristate ' I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI dep_tristate ' I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O diff -u --recursive --new-file v2.3.22/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.3.22/linux/drivers/macintosh/macserial.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/macintosh/macserial.c Wed Oct 20 22:13:21 1999 @@ -5,6 +5,10 @@ * * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Receive DMA code by Takashi Oe . + * + * $Id: macserial.c,v 1.24.2.3 1999/09/10 02:05:58 paulus Exp $ */ #include @@ -26,6 +30,7 @@ #ifdef CONFIG_SERIAL_CONSOLE #include #endif +#include #include #include @@ -41,6 +46,7 @@ #ifdef CONFIG_KGDB #include #endif +#include #include "macserial.h" @@ -52,6 +58,8 @@ }; #endif +#define SUPPORT_SERIAL_DMA + /* * It would be nice to dynamically allocate everything that * depends on NUM_SERIAL, so we could support any number of @@ -127,6 +135,13 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static int set_scc_power(struct mac_serial * info, int state); static int setup_scc(struct mac_serial * info); +static void dbdma_reset(volatile struct dbdma_regs *dma); +static void dbdma_flush(volatile struct dbdma_regs *dma); +static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs); +static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs); +static void dma_init(struct mac_serial * info); +static void rxdma_start(struct mac_serial * info, int current); +static void rxdma_to_tty(struct mac_serial * info); static struct tty_struct *serial_table[NUM_CHANNELS]; static struct termios *serial_termios[NUM_CHANNELS]; @@ -288,6 +303,39 @@ } /* + * Reset a Descriptor-Based DMA channel. + */ +static void dbdma_reset(volatile struct dbdma_regs *dma) +{ + int i; + + out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16); + + /* + * Yes this looks peculiar, but apparently it needs to be this + * way on some machines. (We need to make sure the DBDMA + * engine has actually got the write above and responded + * to it. - paulus) + */ + for (i = 200; i > 0; --i) + if (ld_le32(&dma->control) & RUN) + udelay(1); +} + +/* + * Tells a DBDMA channel to stop and write any buffered data + * it might have to memory. + */ +static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma) +{ + int i = 0; + + out_le32(&dma->control, (FLUSH << 16) | FLUSH); + while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100)) + udelay(1); +} + +/* * ---------------------------------------------------------------------- * * Here starts the interrupt handling routines. All of the following @@ -310,6 +358,22 @@ mark_bh(MACSERIAL_BH); } +/* Work out the flag value for a z8530 status value. */ +static _INLINE_ int stat_to_flag(int stat) +{ + int flag; + + if (stat & Rx_OVR) { + flag = TTY_OVERRUN; + } else if (stat & FRM_ERR) { + flag = TTY_FRAME; + } else if (stat & PAR_ERR) { + flag = TTY_PARITY; + } else + flag = 0; + return flag; +} + static _INLINE_ void receive_chars(struct mac_serial *info, struct pt_regs *regs) { @@ -347,14 +411,7 @@ if (flip_max_cnt < tty->flip.count) flip_max_cnt = tty->flip.count; } - if (stat & Rx_OVR) { - flag = TTY_OVERRUN; - } else if (stat & FRM_ERR) { - flag = TTY_FRAME; - } else if (stat & PAR_ERR) { - flag = TTY_PARITY; - } else - flag = 0; + flag = stat_to_flag(stat); if (flag) /* reset the error indication */ write_zsreg(info->zs_channel, 0, ERR_RES); @@ -450,6 +507,32 @@ info->read_reg_zero = status; } +static _INLINE_ void receive_special_dma(struct mac_serial *info) +{ + unsigned char stat, flag; + volatile struct dbdma_regs *rd = &info->rx->dma; + int where = RX_BUF_SIZE; + + spin_lock(&info->rx_dma_lock); + if ((ld_le32(&rd->status) & ACTIVE) != 0) + dbdma_flush(rd); + if (in_le32(&rd->cmdptr) + == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1)) + where -= in_le16(&info->rx->res_count); + where--; + + stat = read_zsreg(info->zs_channel, R1); + + flag = stat_to_flag(stat); + if (flag) { + info->rx_flag_buf[info->rx_cbuf][where] = flag; + /* reset the error indication */ + write_zsreg(info->zs_channel, 0, ERR_RES); + } + + spin_unlock(&info->rx_dma_lock); +} + /* * This is the serial driver's generic interrupt routine */ @@ -459,6 +542,12 @@ unsigned char zs_intreg; int shift; + if (!(info->flags & ZILOG_INITIALIZED)) { + printk("rs_interrupt: irq %d, port not initialized\n", irq); + disable_irq(irq); + return; + } + /* NOTE: The read register 3, which holds the irq status, * does so for both channels on each chip. Although * the status value itself must be read from the A @@ -475,19 +564,21 @@ for (;;) { zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; #ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg); + printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", + irq, (int)zs_intreg); #endif if ((zs_intreg & CHAN_IRQMASK) == 0) break; - if (!(info->flags & ZILOG_INITIALIZED)) { - printk("rs_interrupt: irq %d, port not initialized\n", irq); - break; + if (zs_intreg & CHBRxIP) { + /* If we are doing DMA, we only ask for interrupts + on characters with errors or special conditions. */ + if (info->dma_initted) + receive_special_dma(info); + else + receive_chars(info, regs); } - - if (zs_intreg & CHBRxIP) - receive_chars(info, regs); if (zs_intreg & CHBTxIP) transmit_chars(info); if (zs_intreg & CHBEXT) @@ -495,6 +586,39 @@ } } +/* Transmit DMA interrupt - not used at present */ +static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs) +{ +} + +/* + * Receive DMA interrupt. + */ +static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mac_serial *info = (struct mac_serial *) dev_id; + volatile struct dbdma_cmd *cd; + + if (!info->dma_initted) + return; + spin_lock(&info->rx_dma_lock); + /* First, confirm that this interrupt is, indeed, coming */ + /* from Rx DMA */ + cd = info->rx_cmds[info->rx_cbuf] + 2; + if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) { + spin_unlock(&info->rx_dma_lock); + return; + } + if (info->rx_fbuf != RX_NO_FBUF) { + info->rx_cbuf = info->rx_fbuf; + if (++info->rx_fbuf == info->rx_nbuf) + info->rx_fbuf = 0; + if (info->rx_fbuf == info->rx_ubuf) + info->rx_fbuf = RX_NO_FBUF; + } + spin_unlock(&info->rx_dma_lock); +} + /* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. @@ -590,10 +714,6 @@ } } -static void rs_timer(void) -{ -} - static int startup(struct mac_serial * info, int can_sleep) { int delay; @@ -629,6 +749,10 @@ info->flags |= ZILOG_INITIALIZED; enable_irq(info->irq); + if (info->dma_initted) { +// enable_irq(info->tx_dma_irq); + enable_irq(info->rx_dma_irq); + } if (delay) { if (can_sleep) { @@ -642,6 +766,187 @@ return 0; } +static _INLINE_ void rxdma_start(struct mac_serial * info, int current) +{ + volatile struct dbdma_regs *rd = &info->rx->dma; + volatile struct dbdma_cmd *cd = info->rx_cmds[current]; + +//printk(KERN_DEBUG "SCC: rxdma_start\n"); + + st_le32(&rd->cmdptr, virt_to_bus(cd)); + out_le32(&rd->control, (RUN << 16) | RUN); +} + +static void rxdma_to_tty(struct mac_serial *info) +{ + struct tty_struct *tty = info->tty; + volatile struct dbdma_regs *rd = &info->rx->dma; + unsigned long flags; + int residue, available, space, do_queue; + + if (!tty) + return; + + do_queue = 0; + spin_lock_irqsave(&info->rx_dma_lock, flags); +more: + space = TTY_FLIPBUF_SIZE - tty->flip.count; + if (!space) { + do_queue++; + goto out; + } + residue = 0; + if (info->rx_ubuf == info->rx_cbuf) { + if ((ld_le32(&rd->status) & ACTIVE) != 0) { + dbdma_flush(rd); + if (in_le32(&rd->cmdptr) + == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1)) + residue = in_le16(&info->rx->res_count); + } + } + available = RX_BUF_SIZE - residue - info->rx_done_bytes; + if (available > space) + available = space; + if (available) { + memcpy(tty->flip.char_buf_ptr, + info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes, + available); + memcpy(tty->flip.flag_buf_ptr, + info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes, + available); + tty->flip.char_buf_ptr += available; + tty->flip.count += available; + tty->flip.flag_buf_ptr += available; + memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes, + 0, available); + info->rx_done_bytes += available; + do_queue++; + } + if (info->rx_done_bytes == RX_BUF_SIZE) { + volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf]; + + if (info->rx_ubuf == info->rx_cbuf) + goto out; + /* mark rx_char_buf[rx_ubuf] free */ + st_le16(&cd->command, DBDMA_NOP); + cd++; + st_le32(&cd->cmd_dep, 0); + st_le32((unsigned int *)&cd->res_count, 0); + cd++; + st_le16(&cd->xfer_status, 0); + + if (info->rx_fbuf == RX_NO_FBUF) { + info->rx_fbuf = info->rx_ubuf; + if (!(ld_le32(&rd->status) & ACTIVE)) { + dbdma_reset(&info->rx->dma); + rxdma_start(info, info->rx_ubuf); + info->rx_cbuf = info->rx_ubuf; + } + } + info->rx_done_bytes = 0; + if (++info->rx_ubuf == info->rx_nbuf) + info->rx_ubuf = 0; + if (info->rx_fbuf == info->rx_ubuf) + info->rx_fbuf = RX_NO_FBUF; + goto more; + } +out: + spin_unlock_irqrestore(&info->rx_dma_lock, flags); + if (do_queue) + queue_task(&tty->flip.tqueue, &tq_timer); +} + +static void poll_rxdma(void *private_) +{ + struct mac_serial *info = (struct mac_serial *) private_; + unsigned long flags; + + rxdma_to_tty(info); + spin_lock_irqsave(&info->rx_dma_lock, flags); + mod_timer(&info->poll_dma_timer, RX_DMA_TIMER); + spin_unlock_irqrestore(&info->rx_dma_lock, flags); +} + +static void dma_init(struct mac_serial * info) +{ + int i, size; + volatile struct dbdma_cmd *cd; + unsigned char *p; + +//printk(KERN_DEBUG "SCC: dma_init\n"); + + info->rx_nbuf = 8; + + /* various mem set up */ + size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2) + + (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds) + + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf)) + * info->rx_nbuf; + info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA); + if (info->dma_priv == NULL) + return; + memset(info->dma_priv, 0, size); + + info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv; + info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf); + info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf; + p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf); + for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE) + info->rx_char_buf[i] = p; + for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE) + info->rx_flag_buf[i] = p; + + /* a bit of DMA programming */ + cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p); + st_le16(&cd->command, DBDMA_NOP); + cd++; + st_le16(&cd->req_count, RX_BUF_SIZE); + st_le16(&cd->command, INPUT_MORE); + st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0])); + cd++; + st_le16(&cd->req_count, 4); + st_le16(&cd->command, STORE_WORD | INTR_ALWAYS); + st_le32(&cd->phy_addr, virt_to_bus(cd-2)); + st_le32(&cd->cmd_dep, DBDMA_STOP); + for (i = 1; i < info->rx_nbuf; i++) { + info->rx_cmds[i] = ++cd; + st_le16(&cd->command, DBDMA_NOP); + cd++; + st_le16(&cd->req_count, RX_BUF_SIZE); + st_le16(&cd->command, INPUT_MORE); + st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i])); + cd++; + st_le16(&cd->req_count, 4); + st_le16(&cd->command, STORE_WORD | INTR_ALWAYS); + st_le32(&cd->phy_addr, virt_to_bus(cd-2)); + st_le32(&cd->cmd_dep, DBDMA_STOP); + } + cd++; + st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS); + st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0])); + + /* setup DMA to our liking */ + dbdma_reset(&info->rx->dma); + st_le32(&info->rx->dma.intr_sel, 0x10001); + st_le32(&info->rx->dma.br_sel, 0x10001); + out_le32(&info->rx->dma.wait_sel, 0x10001); + + /* set various flags */ + info->rx_ubuf = 0; + info->rx_cbuf = 0; + info->rx_fbuf = info->rx_ubuf + 1; + if (info->rx_fbuf == info->rx_nbuf) + info->rx_fbuf = RX_NO_FBUF; + info->rx_done_bytes = 0; + + /* setup polling */ + init_timer(&info->poll_dma_timer); + info->poll_dma_timer.function = (void *)&poll_rxdma; + info->poll_dma_timer.data = (unsigned long)info; + + info->dma_initted = 1; +} + static int setup_scc(struct mac_serial * info) { unsigned long flags; @@ -667,6 +972,12 @@ info->xmit_fifo_size = 1; /* + * Reset DMAs + */ + if (info->has_dma) + dma_init(info); + + /* * Clear the interrupt registers. */ write_zsreg(info->zs_channel, 0, ERR_RES); @@ -680,7 +991,23 @@ /* * Finally, enable sequencing and interrupts */ - info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); + if (!info->dma_initted) { + /* interrupt on ext/status changes, all received chars, + transmit ready */ + info->curregs[1] = (info->curregs[1] & ~0x18) + | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); + } else { + /* interrupt on ext/status changes, W/Req pin is + receive DMA request */ + info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB)) + | (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN); + write_zsreg(info->zs_channel, 1, info->curregs[1]); + /* enable W/Req pin */ + info->curregs[1] |= WT_RDY_ENAB; + write_zsreg(info->zs_channel, 1, info->curregs[1]); + /* enable interrupts on transmit ready and receive errors */ + info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB; + } info->pendregs[1] = info->curregs[1]; info->curregs[3] |= (RxENABLE | Rx8); info->pendregs[3] = info->curregs[3]; @@ -706,6 +1033,14 @@ restore_flags(flags); + if (info->dma_initted) { + spin_lock_irqsave(&info->rx_dma_lock, flags); + rxdma_start(info, 0); + info->poll_dma_timer.expires = RX_DMA_TIMER; + add_timer(&info->poll_dma_timer); + spin_unlock_irqrestore(&info->rx_dma_lock, flags); + } + return 0; } @@ -727,7 +1062,14 @@ return; } - + + if (info->has_dma) { + del_timer(&info->poll_dma_timer); + dbdma_reset(info->tx_dma); + dbdma_reset(&info->rx->dma); + disable_irq(info->tx_dma_irq); + disable_irq(info->rx_dma_irq); + } disable_irq(info->irq); info->pendregs[1] = info->curregs[1] = 0; @@ -753,6 +1095,12 @@ info->xmit_buf = 0; } + if (info->has_dma && info->dma_priv) { + kfree(info->dma_priv); + info->dma_priv = NULL; + info->dma_initted = 0; + } + memset(info->curregs, 0, sizeof(info->curregs)); memset(info->curregs, 0, sizeof(info->pendregs)); @@ -795,7 +1143,7 @@ feature_set(info->dev_node, FEATURE_Modem_Reset); mdelay(5); feature_clear(info->dev_node, FEATURE_Modem_Reset); - delay = 1000; /* wait for 1s before using */ + delay = 2500; /* wait for 2.5s before using */ } #ifdef CONFIG_PMAC_PBOOK if (info->is_pwbk_ir) @@ -1050,7 +1398,6 @@ if (!tty || !info->xmit_buf || !tmp_buf) return 0; - save_flags(flags); if (from_user) { down(&tmp_buf_sem); while (1) { @@ -1066,6 +1413,7 @@ ret = -EFAULT; break; } + save_flags(flags); cli(); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); @@ -1081,6 +1429,7 @@ up(&tmp_buf_sem); } else { while (1) { + save_flags(flags); cli(); c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, @@ -1102,7 +1451,6 @@ if (info->xmit_cnt && !tty->stopped && !info->tx_stopped && !info->tx_active) transmit_chars(info); - restore_flags(flags); return ret; } @@ -1131,12 +1479,13 @@ static void rs_flush_buffer(struct tty_struct *tty) { struct mac_serial *info = (struct mac_serial *)tty->driver_data; + unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) return; - cli(); + save_flags(flags); cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); + restore_flags(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) @@ -1156,7 +1505,6 @@ struct mac_serial *info = (struct mac_serial *)tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty)); #endif @@ -1193,7 +1541,6 @@ struct mac_serial *info = (struct mac_serial *)tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty)); #endif @@ -1471,6 +1818,7 @@ save_flags(flags); cli(); if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; restore_flags(flags); return; } @@ -1496,6 +1844,7 @@ info->count = 0; } if (info->count) { + MOD_DEC_USE_COUNT; restore_flags(flags); return; } @@ -1516,8 +1865,12 @@ printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait); #endif tty->closing = 1; - if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) + if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) { + restore_flags(flags); tty_wait_until_sent(tty, info->closing_wait); + save_flags(flags); cli(); + } + /* * At this point we stop accepting input. To do this, we * disable the receiver and receive interrupts. @@ -1537,7 +1890,9 @@ #ifdef SERIAL_DEBUG_OPEN printk("waiting end of Rx...\n"); #endif + restore_flags(flags); rs_wait_until_sent(tty, info->timeout); + save_flags(flags); cli(); } shutdown(info); @@ -1563,6 +1918,7 @@ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; } /* @@ -1772,14 +2128,19 @@ int retval, line; unsigned long page; + MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; - if ((line < 0) || (line >= zs_channels_found)) + if ((line < 0) || (line >= zs_channels_found)) { + MOD_DEC_USE_COUNT; return -ENODEV; + } info = zs_soft + line; #ifdef CONFIG_KGDB - if (info->kgdb_channel) + if (info->kgdb_channel) { + MOD_DEC_USE_COUNT; return -ENODEV; + } #endif if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; @@ -1862,7 +2223,58 @@ static void show_serial_version(void) { - printk("PowerMac Z8530 serial driver version 1.01\n"); + printk("PowerMac Z8530 serial driver version 2.0\n"); +} + +/* + * Initialize one channel, both the mac_serial and mac_zschannel + * structs. We use the dev_node field of the mac_serial struct. + */ +static void +chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, + struct mac_zschannel *zs_chan_a) +{ + struct device_node *ch = zss->dev_node; + char *conn; + int len; + + zss->irq = ch->intrs[0].line; + zss->has_dma = 0; +#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA) + if (ch->n_addrs == 3 && ch->n_intrs == 3) + zss->has_dma = 1; +#endif + zss->dma_initted = 0; + + zs_chan->control = (volatile unsigned char *) + ioremap(ch->addrs[0].address, 0x1000); + zs_chan->data = zs_chan->control + 0x10; + spin_lock_init(&zs_chan->lock); + zs_chan->parent = zss; + zss->zs_channel = zs_chan; + zss->zs_chan_a = zs_chan_a; + + /* setup misc varariables */ + zss->kgdb_channel = 0; + zss->is_cobalt_modem = device_is_compatible(ch, "cobalt"); + + /* XXX tested only with wallstreet PowerBook, + should do no harm anyway */ + conn = get_property(ch, "AAPL,connector", &len); + zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0); + + if (zss->has_dma) { + zss->dma_priv = NULL; + /* it seems that the last two addresses are the + DMA controllers */ + zss->tx_dma = (volatile struct dbdma_regs *) + ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100); + zss->rx = (volatile struct mac_dma *) + ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100); + zss->tx_dma_irq = ch->intrs[1].line; + zss->rx_dma_irq = ch->intrs[2].line; + spin_lock_init(&zss->rx_dma_lock); + } } /* Ask the PROM how many Z8530s we have and initialize their zs_channels */ @@ -1871,51 +2283,63 @@ { struct device_node *dev, *ch; struct mac_serial **pp; - int n, lenp; - char *conn; + int n, chip, nchan; + struct mac_zschannel *zs_chan; + int chan_a_index; n = 0; pp = &zs_chain; + zs_chan = zs_channels; for (dev = find_devices("escc"); dev != 0; dev = dev->next) { + nchan = 0; + chip = n; if (n >= NUM_CHANNELS) { printk("Sorry, can't use %s: no more channels\n", dev->full_name); continue; } + chan_a_index = 0; for (ch = dev->child; ch != 0; ch = ch->sibling) { + if (nchan >= 2) { + printk(KERN_WARNING "SCC: Only 2 channels per " + "chip are supported\n"); + break; + } if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) { printk("Can't use %s: %d addrs %d intrs\n", ch->full_name, ch->n_addrs, ch->n_intrs); continue; } - zs_channels[n].control = (volatile unsigned char *) - ioremap(ch->addrs[0].address, 0x1000); - zs_channels[n].data = zs_channels[n].control + 0x10; - spin_lock_init(&zs_channels[n].lock); - zs_soft[n].zs_channel = &zs_channels[n]; - zs_soft[n].dev_node = ch; - zs_soft[n].irq = ch->intrs[0].line; - zs_soft[n].zs_channel->parent = &zs_soft[n]; - zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt"); - - /* XXX tested only with wallstreet PowerBook, - should do no harm anyway */ - conn = get_property(ch, "AAPL,connector", &lenp); - zs_soft[n].is_pwbk_ir = - conn && (strcmp(conn, "infrared") == 0); - - /* XXX this assumes the prom puts chan A before B */ - if (n & 1) - zs_soft[n].zs_chan_a = &zs_channels[n-1]; - else - zs_soft[n].zs_chan_a = &zs_channels[n]; + /* The channel with the higher address + will be the A side. */ + if (nchan > 0 && + ch->addrs[0].address + > zs_soft[n-1].dev_node->addrs[0].address) + chan_a_index = 1; + + /* minimal initialization for now */ + zs_soft[n].dev_node = ch; *pp = &zs_soft[n]; pp = &zs_soft[n].zs_next; + ++nchan; ++n; } + if (nchan == 0) + continue; + + /* set up A side */ + chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan); + ++zs_chan; + + /* set up B side, if it exists */ + if (nchan > 1) + chan_init(&zs_soft[chip + 1 - chan_a_index], + zs_chan, zs_chan - 1); + ++zs_chan; } *pp = 0; + zs_channels_found = n; #ifdef CONFIG_PMAC_PBOOK if (n) @@ -1932,8 +2356,6 @@ /* Setup base handler, and timer table. */ init_bh(MACSERIAL_BH, do_serial_bh); - timer_table[RS_TIMER].fn = rs_timer; - timer_table[RS_TIMER].expires = 0; /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) @@ -1945,6 +2367,18 @@ /* Register the interrupt handler for each one */ save_flags(flags); cli(); for (i = 0; i < zs_channels_found; ++i) { + if (zs_soft[i].has_dma) { + if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0, + "SCC-txdma", &zs_soft[i])) + printk(KERN_ERR "macserial: can't get irq %d\n", + zs_soft[i].tx_dma_irq); + disable_irq(zs_soft[i].tx_dma_irq); + if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0, + "SCC-rxdma", &zs_soft[i])) + printk(KERN_ERR "macserial: can't get irq %d\n", + zs_soft[i].rx_dma_irq); + disable_irq(zs_soft[i].rx_dma_irq); + } if (request_irq(zs_soft[i].irq, rs_interrupt, 0, "SCC", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", @@ -2083,6 +2517,7 @@ /* By default, disable the port */ set_scc_power(info, 0); } + tmp_buf = 0; return 0; } @@ -2103,11 +2538,26 @@ for (info = zs_chain, i = 0; info; info = info->zs_next, i++) set_scc_power(info, 0); save_flags(flags); cli(); - for (i = 0; i < zs_channels_found; ++i) + for (i = 0; i < zs_channels_found; ++i) { free_irq(zs_soft[i].irq, &zs_soft[i]); + if (zs_soft[i].has_dma) { + free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]); + free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]); + } + } restore_flags(flags); tty_unregister_driver(&callout_driver); tty_unregister_driver(&serial_driver); + + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = 0; + } + +#ifdef CONFIG_PMAC_PBOOK + if (zs_channels_found) + pmu_unregister_sleep_notifier(&serial_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ } #endif /* MODULE */ @@ -2224,6 +2674,8 @@ if (zs_chain == 0) return -1; + set_scc_power(info, 1); + /* Reset the channel */ write_zsreg(info->zs_channel, R9, CHRA); @@ -2467,14 +2919,13 @@ if (zs_chain == 0) probe_sccs(); - set_scc_power(&zs_soft[n], 1); + set_scc_power(&zs_soft[tty_num], 1); zs_kgdbchan = zs_soft[tty_num].zs_channel; zs_soft[tty_num].change_needed = 0; zs_soft[tty_num].clk_divisor = 16; zs_soft[tty_num].zs_baud = 38400; zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */ - zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */ /* Turn on transmitter/receiver at 8-bits/char */ kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400); diff -u --recursive --new-file v2.3.22/linux/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h --- v2.3.22/linux/drivers/macintosh/macserial.h Sat Oct 9 11:47:50 1999 +++ linux/drivers/macintosh/macserial.h Wed Oct 20 22:13:21 1999 @@ -92,6 +92,13 @@ struct mac_serial* parent; }; +struct mac_dma { + volatile struct dbdma_regs dma; + volatile unsigned short res_count; + volatile unsigned short command; + volatile unsigned int buf_addr; +}; + struct mac_serial { struct mac_serial *zs_next; /* For IRQ servicing chain */ struct mac_zschannel *zs_channel; /* Channel registers */ @@ -156,6 +163,28 @@ struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; + + volatile struct dbdma_regs *tx_dma; + int tx_dma_irq; + volatile struct dbdma_cmd *tx_cmds; + volatile struct mac_dma *rx; + int rx_dma_irq; + volatile struct dbdma_cmd **rx_cmds; + unsigned char **rx_char_buf; + unsigned char **rx_flag_buf; +#define RX_BUF_SIZE 256 + int rx_nbuf; + int rx_done_bytes; + int rx_ubuf; + int rx_fbuf; +#define RX_NO_FBUF (-1) + int rx_cbuf; + spinlock_t rx_dma_lock; + int has_dma; + int dma_initted; + void *dma_priv; + struct timer_list poll_dma_timer; +#define RX_DMA_TIMER (jiffies + 10*HZ/1000) }; @@ -226,9 +255,9 @@ #define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ #define INT_ERR_Rx 0x18 /* Int on error only */ -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ +#define WT_RDY_RT 0x20 /* W/Req reflects recv if 1, xmit if 0 */ +#define WT_FN_RDYFN 0x40 /* W/Req pin is DMA request if 1, wait if 0 */ +#define WT_RDY_ENAB 0x80 /* Enable W/Req pin */ /* Write Register #2 (Interrupt Vector) */ @@ -286,6 +315,9 @@ /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ +/* Write Register 7' (Some enhanced feature control) */ +#define ENEXREAD 0x40 /* Enable read of some write registers */ + /* Write Register 8 (transmit buffer) */ /* Write Register 9 (Master interrupt control) */ @@ -346,7 +378,9 @@ #define SNRZI 0xe0 /* Set NRZI mode */ /* Write Register 15 (external/status interrupt control) */ +#define EN85C30 1 /* Enable some 85c30-enhanced registers */ #define ZCIE 2 /* Zero count IE */ +#define ENSTFIFO 4 /* Enable status FIFO (SDLC) */ #define DCDIE 8 /* DCD IE */ #define SYNCIE 0x10 /* Sync/hunt IE */ #define CTSIE 0x20 /* CTS IE */ @@ -382,6 +416,15 @@ #define END_FR 0x80 /* End of Frame (SDLC) */ /* Read Register 2 (channel b only) - Interrupt vector */ +#define CHB_Tx_EMPTY 0x00 +#define CHB_EXT_STAT 0x02 +#define CHB_Rx_AVAIL 0x04 +#define CHB_SPECIAL 0x06 +#define CHA_Tx_EMPTY 0x08 +#define CHA_EXT_STAT 0x0a +#define CHA_Rx_AVAIL 0x0c +#define CHA_SPECIAL 0x0e +#define STATUS_MASK 0x06 /* Read Register 3 (interrupt pending register) ch a only */ #define CHBEXT 0x1 /* Channel B Ext/Stat IP */ diff -u --recursive --new-file v2.3.22/linux/drivers/misc/acpi.c linux/drivers/misc/acpi.c --- v2.3.22/linux/drivers/misc/acpi.c Fri Oct 15 15:25:13 1999 +++ linux/drivers/misc/acpi.c Wed Oct 20 17:57:23 1999 @@ -246,18 +246,18 @@ struct acpi_table *rsdt; u32 *rsdt_entry; int rsdt_entry_count; - u8 *i; + unsigned long i; // search BIOS memory for RSDP for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16) { - rsdp = (struct acpi_rsdp *) i; - if (readl(rsdp->signature) == ACPI_RSDP1_SIG - && readl(rsdp->signature + 1) == ACPI_RSDP2_SIG) { + rsdp = (struct acpi_rsdp *) phys_to_virt(i); + if (rsdp->signature[0] == ACPI_RSDP1_SIG && + rsdp->signature[1] == ACPI_RSDP2_SIG) { char oem[7]; int j; // strip trailing space and print OEM identifier - memcpy_fromio(oem, rsdp->oem, 6); + memcpy(oem, rsdp->oem, 6); oem[6] = '\0'; for (j = 5; j > 0 && (oem[j] == '\0' || oem[j] == ' '); @@ -275,7 +275,7 @@ return -ENODEV; } // fetch RSDT from RSDP - rsdt = acpi_map_table(readl(&rsdp->rsdt)); + rsdt = acpi_map_table(rsdp->rsdt); if (!rsdt || rsdt->signature != ACPI_RSDT_SIG) { printk(KERN_ERR "ACPI: no RSDT found\n"); acpi_unmap_table(rsdt); diff -u --recursive --new-file v2.3.22/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.22/linux/drivers/net/Makefile Fri Oct 15 15:25:13 1999 +++ linux/drivers/net/Makefile Wed Oct 20 21:33:12 1999 @@ -27,10 +27,10 @@ ifeq ($(CONFIG_PCMCIA),y) SUB_DIRS += pcmcia - MOD_SUB_DIRS += pcmcia + MOD_IN_SUB_DIRS += pcmcia else ifeq ($(CONFIG_PCMCIA),m) - MOD_SUB_DIRS += pcmcia + MOD_IN_SUB_DIRS += pcmcia endif endif @@ -825,14 +825,6 @@ else ifeq ($(CONFIG_ARIADNE2),m) M_OBJS += ariadne2.o - CONFIG_8390_MODULE = y - endif -endif - -ifeq ($(CONFIG_PCMCIA_PCNET),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_PCMCIA_PCNET),m) CONFIG_8390_MODULE = y endif endif diff -u --recursive --new-file v2.3.22/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.3.22/linux/drivers/net/eepro100.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/net/eepro100.c Tue Oct 19 10:22:20 1999 @@ -1495,7 +1495,7 @@ rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); - rxf->rx_buf_addr = virt_to_le32bus(skb->tail); + rxf->rx_buf_addr = virt_to_bus(skb->tail); } else { rxf = sp->rx_ringp[entry]; } diff -u --recursive --new-file v2.3.22/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c --- v2.3.22/linux/drivers/net/hamradio/baycom_par.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/hamradio/baycom_par.c Mon Oct 18 11:26:31 1999 @@ -572,7 +572,7 @@ static int __init baycom_par_setup(char *str) { - static unsigned __initdata nr_dev = 0; + static unsigned nr_dev = 0; int ints[2]; if (nr_dev >= NR_PORTS) diff -u --recursive --new-file v2.3.22/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c --- v2.3.22/linux/drivers/net/hamradio/soundmodem/sm.c Thu Aug 26 13:05:38 1999 +++ linux/drivers/net/hamradio/soundmodem/sm.c Mon Oct 18 11:26:31 1999 @@ -726,7 +726,7 @@ static int __init sm_setup(char *str) { - static unsigned __initdata nr_dev = 0; + static unsigned nr_dev = 0; int ints[8]; if (nr_dev >= NR_PORTS) diff -u --recursive --new-file v2.3.22/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c --- v2.3.22/linux/drivers/net/irda/w83977af_ir.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/irda/w83977af_ir.c Thu Oct 21 13:38:12 1999 @@ -10,16 +10,16 @@ * Modified by: Dag Brattli * * Copyright (c) 1998-1999 Dag Brattli - * Copyright (c) 1998 Corel Computer Corp. + * Copyright (c) 1998-1999 Rebel.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * - * Neither Paul VanderSpek nor Corel Computer Corp. admit liability - * nor provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. + * Neither Paul VanderSpek nor Rebel.com admit liability nor provide + * warranty for any of this software. This material is provided "AS-IS" + * and at no charge. * * If you find bugs in this file, its very likely that the same bug * will also be in pc87108.c since the implementations is quite diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c --- v2.3.22/linux/drivers/net/pcmcia/3c574_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/3c574_cs.c Wed Oct 20 21:33:12 1999 @@ -0,0 +1,1494 @@ +/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner". + + Written 1993-1998 by + Donald Becker, becker@cesdis.gsfc.nasa.gov, (driver core) and + David Hinds, dhinds@allegro.stanford.edu (derived from his PC card code). + + This software may be used and distributed according to the terms of + the GNU Public License, incorporated herein by reference. + + This driver derives from Donald Becker's 3c509 core, which has the + following copyright: + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + +*/ + +/* Driver author info must always be in the binary. Version too.. */ +static const char *tc574_version = +"3c574_cs.c v1.08 9/24/98 Donald Becker/David Hinds, becker@cesdis.gsfc.nasa.gov.\n"; + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the 3Com 3c574 PC card Fast Ethernet +Adapter. + +II. Board-specific settings + +None -- PC cards are autoconfigured. + +III. Driver operation + +The 3c574 uses a Boomerang-style interface, without the bus-master capability. +See the Boomerang driver and documentation for most details. + +IV. Notes and chip documentation. + +Two added registers are used to enhance PIO performance, RunnerRdCtrl and +RunnerWrCtrl. These are 11 bit down-counters that are preloaded with the +count of word (16 bits) reads or writes the driver is about to do to the Rx +or Tx FIFO. The chip is then able to hide the internal-PCI-bus to PC-card +translation latency by buffering the I/O operations with an 8 word FIFO. +Note: No other chip accesses are permitted when this buffer is used. + +A second enhancement is that both attribute and common memory space +0x0800-0x0fff can translated to the PIO FIFO. Thus memory operations (faster +with *some* PCcard bridges) may be used instead of I/O operations. +This is enabled by setting the 0x10 bit in the PCMCIA LAN COR. + +Some slow PC card bridges work better if they never see a WAIT signal. +This is configured by setting the 0x20 bit in the PCMCIA LAN COR. +Only do this after testing that it is reliable and improves performance. + +The upper five bits of RunnerRdCtrl are used to window into PCcard +configuration space registers. Window 0 is the regular Boomerang/Odie +register set, 1-5 are various PC card control registers, and 16-31 are +the (reversed!) CIS table. + +A final note: writing the InternalConfig register in window 3 with an +invalid ramWidth is Very Bad. + +V. References + +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.national.com/pf/DP/DP83840.html + +Thanks to Terry Murphy of 3Com for providing development information for +earlier 3Com products. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* A few values that may be tweaked. */ +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(full_duplex, "i"); +#ifdef BROKEN_FEATURES +MODULE_PARM(use_fifo_buffer, "i"); +MODULE_PARM(use_memory_ops, "i"); +MODULE_PARM(no_wait, "i"); +#endif + +/* Now-standard PC card module parameters. */ +static u_int irq_mask = 0xdeb8; /* IRQ3,4,5,7,9,10,11,12,14,15 */ +static int irq_list[4] = { -1 }; + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT ((800*HZ)/1000) + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 64; + +/* Force full duplex modes? */ +static int full_duplex = 0; + +#ifdef BROKEN_FEATURES +/* Performance features: best left disabled. */ +/* Set to buffer all Tx/RxFIFO accesses. */ +static int use_fifo_buffer = 0; +/* Set iff memory ops are faster than I/O ops. */ +static int use_memory_ops = 0; +/* Set iff disabling the WAIT signal is reliable and faster. */ +static int no_wait = 0; +#endif + +/* To minimize the size of the driver source and make the driver more + readable not all constants are symbolically defined. + You'll need the manual if you want to understand driver details anyway. */ +/* Offsets from base I/O address. */ +#define EL3_DATA 0x00 +#define EL3_CMD 0x0e +#define EL3_STATUS 0x0e + +#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) + +/* The top five bits written to EL3_CMD are a command, the lower + 11 bits are the parameter, if applicable. */ +enum el3_cmds { + TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, + RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11, + TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, + FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, + SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, + SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11, + StatsDisable = 22<<11, StopCoax = 23<<11, +}; + +enum elxl_status { + IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, + TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, + IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 }; + +/* The SetRxFilter command accepts the following classes: */ +enum RxFilter { + RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 +}; + +enum Window0 { + Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */ + IntrStatus=0x0E, /* Valid in all windows. */ +}; +/* These assumes the larger EEPROM. */ +enum Win0_EEPROM_cmds { + EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300, + EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ + EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ +}; + +/* Register window 1 offsets, the window used in normal operation. + On the "Odie" this window is always mapped at offsets 0x10-0x1f. + Except for TxFree, which is overlapped by RunnerWrCtrl. */ +enum Window1 { + TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14, + RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B, + TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */ + RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c, +}; + +enum Window3 { /* Window 3: MAC/config bits. */ + Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, +}; +union wn3_config { + int i; + struct w3_config_fields { + unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; + int pad8:8; + unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; + int pad24:7; + } u; +}; + +enum Window4 { /* Window 4: Xcvr/media bits. */ + Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10, +}; + +#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ + +struct el3_private { + dev_node_t node; + struct net_device_stats stats; + u16 advertising, partner; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ + unsigned int + autoselect:1, default_media:3; /* Read from the EEPROM/Wn3_Config. */ + /* for transceiver monitoring */ + struct timer_list media; + u_short media_status; + u_short fast_poll; + u_long last_irq; +}; + +/* Set iff a MII transceiver on any interface requires mdio preamble. + This only set with the original DP83840 on older 3c905 boards, so the extra + code size of a per-interface flag is not worthwhile. */ +static char mii_preamble_required = 0; + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"3c574_cs.c 1.000 1998/1/8 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n"; +#else +#define DEBUG(n, args...) +#endif + +/* Index of functions. */ + +static void tc574_config(dev_link_t *link); +static void tc574_release(u_long arg); +static int tc574_event(event_t event, int priority, + event_callback_args_t *args); + +static void mdio_sync(ioaddr_t ioaddr, int bits); +static int mdio_read(ioaddr_t ioaddr, int phy_id, int location); +static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value); +static u_short read_eeprom(ioaddr_t ioaddr, int index); +static void wait_for_completion(struct net_device *dev, int cmd); + +static void tc574_reset(struct net_device *dev); +static void media_check(u_long arg); +static int el3_open(struct net_device *dev); +static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void update_stats(ioaddr_t addr, struct net_device *dev); +static struct net_device_stats *el3_get_stats(struct net_device *dev); +static int el3_rx(struct net_device *dev, int worklimit); +static int el3_close(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); + +static dev_info_t dev_info = "3c574_cs"; + +static dev_link_t *tc574_attach(void); +static void tc574_detach(dev_link_t *); + +static dev_link_t *dev_list = NULL; + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + tc574_detach(link); + } +} + +static void cs_error(client_handle_t handle, int func, int ret) +{ +#if CS_RELEASE_CODE < 0x2911 + CardServices(ReportError, dev_info, (void *)func, (void *)ret); +#else + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +#endif +} + +/* + We never need to do anything when a tc574 device is "initialized" + by the net software, because we only register already-found cards. +*/ + +static int tc574_init(struct net_device *dev) +{ + return 0; +} + +/* + tc574_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. +*/ + +static dev_link_t *tc574_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + int i, ret; + + DEBUG(0, "3c574_attach()\n"); + flush_stale_links(); + + /* Create the PC card device object. */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &tc574_release; + link->release.data = (u_long)link; + link->io.NumPorts1 = 32; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + link->io.IOAddrLines = 5; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = &el3_interrupt; + 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; + + /* Create the network device object. */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + + /* Make up a Odie-specific data structure. */ + dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct el3_private)); + + /* The EL3-specific entries in the device structure. */ + dev->hard_start_xmit = &el3_start_xmit; + dev->get_stats = &el3_get_stats; +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = &private_ioctl; +#endif + dev->set_multicast_list = &set_rx_mode; + ether_setup(dev); + dev->name = ((struct el3_private *)dev->priv)->node.dev_name; + dev->init = &tc574_init; + dev->open = &el3_open; + dev->stop = &el3_close; + dev->tbusy = 1; + + link->priv = dev; +#if CS_RELEASE_CODE > 0x2911 + link->irq.Instance = dev; +#endif + + /* 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 = &tc574_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); + tc574_detach(link); + return NULL; + } + + return link; +} /* tc574_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 tc574_detach(dev_link_t *link) +{ + dev_link_t **linkp; + long flags; + + DEBUG(0, "3c574_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + if (link->state & DEV_CONFIG) { + tc574_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + if (link->priv) { + struct net_device *dev = link->priv; + if (link->dev != NULL) + unregister_netdev(dev); + if (dev->priv) + kfree(dev->priv); + kfree(link->priv); + } + kfree(link); + +} /* tc574_detach */ + +/* + tc574_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. +*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void tc574_config(dev_link_t *link) +{ + client_handle_t handle; + struct net_device *dev; + struct el3_private *lp; + tuple_t tuple; + cisparse_t parse; + u_short buf[32]; + int last_fn, last_ret, i, j; + ioaddr_t ioaddr; + u16 *phys_addr; + char *cardname; + + handle = link->handle; + dev = link->priv; + phys_addr = (u16 *)dev->dev_addr; + + DEBUG(0, "3c574_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + for (i = j = 0; j < 0x400; j += 0x20) { + link->io.BasePort1 = j ^ 0x300; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + dev->mem_start = 0; +#ifdef BROKEN_FEATURES + if (use_memory_ops) { + win_req_t req; + memreq_t mem; + req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | + WIN_ENABLE | WIN_USE_WAIT; + req.Base = 0; + req.Size = 0x1000; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if (i == CS_SUCCESS) { + mem.Page = mem.CardOffset = 0; + CardServices(MapMemPage, link->win, &mem); + dev->mem_start = (long)(ioremap(req.Base, 0x1000)) + 0x800; + } else + cs_error(link->handle, RequestWindow, i); + } +#endif + + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + + dev->tbusy = 0; + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); + goto failed; + } + + link->state &= ~DEV_CONFIG_PENDING; + + ioaddr = dev->base_addr; + lp = (struct el3_private *)dev->priv; + link->dev = &lp->node; + + /* The 3c574 normally uses an EEPROM for configuration info, including + the hardware address. The future products may include a modem chip + and put the address in the CIS. */ + tuple.DesiredTuple = 0x88; + if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) { + CardServices(GetTupleData, handle, &tuple); + for (i = 0; i < 3; i++) + phys_addr[i] = htons(buf[i]); + } else { + EL3WINDOW(0); + for (i = 0; i < 3; i++) + phys_addr[i] = htons(read_eeprom(ioaddr, i + 10)); + if (phys_addr[0] == 0x6060) { + printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx" + "-0x%03lx\n", dev->base_addr, dev->base_addr+15); + goto failed; + } + } + tuple.DesiredTuple = CISTPL_VERS_1; + if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS && + CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS && + CardServices(ParseTuple, handle, &tuple, &parse) == CS_SUCCESS) { + cardname = parse.version_1.str + parse.version_1.ofs[1]; + } else + cardname = "3Com 3c574"; + + printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ", + dev->name, cardname, dev->base_addr, dev->irq); + + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n")); + + if (dev->mem_start) + printk(KERN_INFO" Acceleration window at memory base %#lx.\n", + dev->mem_start); + + { + u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + union wn3_config config; + outw(2<<11, ioaddr + RunnerRdCtrl); + mcr = inb(ioaddr + 2); + outw(0<<11, ioaddr + RunnerRdCtrl); + printk(KERN_INFO " ASIC rev %d,", mcr>>3); + EL3WINDOW(3); + config.i = inl(ioaddr + Wn3_Config); + printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", + 8 << config.u.ram_size, ram_split[config.u.ram_split], + config.u.autoselect ? "autoselect " : ""); + lp->default_media = config.u.xcvr; + lp->autoselect = config.u.autoselect; + } + + { + int phy, phy_idx = 0; + + /* Roadrunner only: Turn on the MII transceiver */ + outw(0x8040, ioaddr + Wn3_Options); + udelay(1000); + outw(0xc040, ioaddr + Wn3_Options); + wait_for_completion(dev, TxReset); + wait_for_completion(dev, RxReset); + udelay(1000); + outw(0x8040, ioaddr + Wn3_Options); + + EL3WINDOW(4); + for (phy = 1; phy <= 32 && phy_idx < sizeof(lp->phys); phy++) { + int mii_status; + mdio_sync(ioaddr, 32); + mii_status = mdio_read(ioaddr, phy & 0x1f, 1); + if (mii_status != 0xffff) { + lp->phys[phy_idx++] = phy & 0x1f; + DEBUG(0, " MII transceiver at index %d, status %x.\n", + phy, mii_status); + if ((mii_status & 0x0040) == 0) + mii_preamble_required = 1; + } + } + if (phy_idx == 0) { + printk(KERN_NOTICE " No MII transceivers found!\n"); + goto failed; + } + i = mdio_read(ioaddr, lp->phys[0], 16) | 0x40; + mdio_write(ioaddr, lp->phys[0], 16, i); + lp->advertising = mdio_read(ioaddr, lp->phys[0], 4); + if (full_duplex) { + /* Only advertise the FD media types. */ + lp->advertising &= ~0x02a0; + mdio_write(ioaddr, lp->phys[0], 4, lp->advertising); + } + } + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + tc574_release((u_long)link); + return; + +} /* tc574_config */ + +/* + After a card is removed, tc574_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 tc574_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = link->priv; + + DEBUG(0, "3c574_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1, "3c574_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + if (link->win) { + iounmap((void *)(dev->mem_start - 0x800)); + CardServices(ReleaseWindow, link->win); + } + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* tc574_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. +*/ + +static int tc574_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + + DEBUG(1, "3c574_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 1; dev->start = 0; + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + tc574_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 1; dev->start = 0; + } + 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); + if (link->open) { + tc574_reset(dev); + dev->tbusy = 0; dev->start = 1; + } + } + break; + } + return 0; +} /* tc574_event */ + +static void dump_status(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + EL3WINDOW(1); + printk(KERN_INFO " irq status %04x, rx status %04x, tx status " + "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS), + inw(ioaddr+RxStatus), inb(ioaddr+TxStatus), + inw(ioaddr+TxFree)); + EL3WINDOW(4); + printk(KERN_INFO " diagnostics: fifo %04x net %04x ethernet %04x" + " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06), + inw(ioaddr+0x08), inw(ioaddr+0x0a)); + EL3WINDOW(1); +} + +/* + Use this for commands that may take time to finish +*/ +static void wait_for_completion(struct net_device *dev, int cmd) +{ + int i = 1500; + outw(cmd, dev->base_addr + EL3_CMD); + while (--i > 0) + if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; + if (i == 0) + printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n", + dev->name, cmd); +} + +/* Read a word from the EEPROM using the regular EEPROM access register. + Assume that we are in register window zero. + */ +static u_short read_eeprom(ioaddr_t ioaddr, int index) +{ + int timer; + outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 usec for the read to take place. */ + for (timer = 1620; timer >= 0; timer--) { + if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) + break; + } + return inw(ioaddr + Wn0EepromData); +} + +/* 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 maxium data clock rate is 2.5 Mhz. The timing is easily met by the + slow PC card interface. */ + +#define MDIO_SHIFT_CLK 0x01 +#define MDIO_DIR_WRITE 0x04 +#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE) +#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE) +#define MDIO_DATA_READ 0x02 +#define MDIO_ENB_IN 0x00 + +/* Generate the preamble required for initial synchronization and + a few older transceivers. */ +static void mdio_sync(ioaddr_t ioaddr, int bits) +{ + int mdio_addr = ioaddr + Wn4_PhysicalMgmt; + + /* Establish sync by sending at least 32 logic ones. */ + while (-- bits >= 0) { + outw(MDIO_DATA_WRITE1, mdio_addr); + outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + } +} + +static int mdio_read(ioaddr_t ioaddr, int phy_id, int location) +{ + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + unsigned int retval = 0; + int mdio_addr = ioaddr + Wn4_PhysicalMgmt; + + if (mii_preamble_required) + mdio_sync(ioaddr, 32); + + /* Shift the read command bits out. */ + for (i = 14; i >= 0; i--) { + int dataval = (read_cmd&(1< 0; i--) { + outw(MDIO_ENB_IN, mdio_addr); + retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value) +{ + int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; + int mdio_addr = ioaddr + Wn4_PhysicalMgmt; + int i; + + if (mii_preamble_required) + mdio_sync(ioaddr, 32); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (write_cmd&(1<= 0; i--) { + outw(MDIO_ENB_IN, mdio_addr); + outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + } + + return; +} + +/* Reset and restore all of the 3c574 registers. */ +static void tc574_reset(struct net_device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + int i, ioaddr = dev->base_addr; + + wait_for_completion(dev, TotalReset|0x10); + +#ifdef BROKEN_FEATURES + /* Set the PIO ctrl bits in the PC card LAN COR using Runner window 1. */ + if (dev->mem_start || no_wait) { + u8 lan_cor; + outw(1<<11, ioaddr + RunnerRdCtrl); + lan_cor = inw(ioaddr) & ~0x30; + if (dev->mem_start) /* Iff use_memory_ops worked! */ + lan_cor |= 0x10; + if (no_wait) + lan_cor |= 0x20; + outw(lan_cor, ioaddr); + } +#endif + /* Clear any transactions in progress. */ + outw(0, ioaddr + RunnerWrCtrl); + outw(0, ioaddr + RunnerRdCtrl); + + /* Set the station address and mask. */ + EL3WINDOW(2); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + i); + for (; i < 12; i+=2) + outw(0, ioaddr + i); + + /* Reset config options */ + EL3WINDOW(3); + outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); + outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b, + ioaddr + Wn3_Config); + + /* Roadrunner only: Turn on the MII transceiver. */ + outw(0x8040, ioaddr + Wn3_Options); + udelay(1000); + outw(0xc040, ioaddr + Wn3_Options); + wait_for_completion(dev, TxReset); + wait_for_completion(dev, RxReset); + udelay(1000); + outw(0x8040, ioaddr + Wn3_Options); + + /* Switch to the stats window, and clear all stats by reading. */ + outw(StatsDisable, ioaddr + EL3_CMD); + EL3WINDOW(6); + for (i = 0; i < 10; i++) + inb(ioaddr + i); + inw(ioaddr + 10); + inw(ioaddr + 12); + + EL3WINDOW(4); + /* New: On the Vortex/Odie we must also clear the BadSSD counter.. */ + inb(ioaddr + 12); + /* .. enable any extra statistics bits.. */ + outw(0x0040, ioaddr + Wn4_NetDiag); + /* .. re-sync MII and re-fill what NWay is advertising. */ + mdio_sync(ioaddr, 32); + mdio_write(ioaddr, lp->phys[0], 4, lp->advertising); + + /* Switch to register set 1 for normal use, just for TxFree. */ + EL3WINDOW(1); + + set_rx_mode(dev); + outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ + outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ + outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ + /* Allow status bits to be seen. */ + outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); + /* Ack all pending events, and set active indicator mask. */ + outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, + ioaddr + EL3_CMD); + outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull + | AdapterFailure | RxEarly, ioaddr + EL3_CMD); +} + +static int el3_open(struct net_device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + dev_link_t *link; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (!DEV_OK(link)) + return -ENODEV; + + link->open++; + MOD_INC_USE_COUNT; + dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + + tc574_reset(dev); + lp->media.function = &media_check; + lp->media.data = (u_long)dev; + lp->media.expires = jiffies + HZ; + add_timer(&lp->media); + + DEBUG(2, "%s: opened, status %4.4x.\n", + dev->name, inw(dev->base_addr + EL3_STATUS)); + + return 0; /* Always succeed */ +} + +static void el3_tx_timeout(struct net_device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + + printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name); + dump_status(dev); + lp->stats.tx_errors++; + dev->trans_start = jiffies; + /* Issue TX_RESET and TX_START commands. */ + wait_for_completion(dev, TxReset); + outw(TxEnable, ioaddr + EL3_CMD); + dev->tbusy = 0; +} + +static void pop_tx_status(struct net_device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int i; + + /* Clear the Tx status stack. */ + for (i = 32; i > 0; i--) { + u_char tx_status = inb(ioaddr + TxStatus); + if (!(tx_status & 0x84)) break; + /* reset transmitter on jabber error or underrun */ + if (tx_status & 0x30) + wait_for_completion(dev, TxReset); + if (tx_status & 0x38) { + DEBUG(1, "%s: transmit error: status 0x%02x\n", + dev->name, tx_status); + outw(TxEnable, ioaddr + EL3_CMD); + lp->stats.tx_aborted_errors++; + } + outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ + } +} + +static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; +#ifdef BROKEN_FEATURES + long flags = 0; +#endif + + /* Transmitter timeout, serious problems. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + if (jiffies - dev->trans_start < TX_TIMEOUT) + return 1; + el3_tx_timeout(dev); + } + + DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " + "status %4.4x.\n", dev->name, (long)skb->len, + inw(ioaddr + EL3_STATUS)); + +#ifdef BROKEN_FEATURES + if (use_fifo_buffer) { + /* Avoid other accesses to the chip while RunnerWrCtrl is non-zero. */ + save_flags(flags); + cli(); + outw((((skb->len + 7)>>2)<<1), ioaddr + RunnerWrCtrl); + DEBUG(0, "TxFree %x, tx length %x, RunnerWrCtrl is %4.4x.\n", + inw(ioaddr+TxFree), skb->len, inw(ioaddr+RunnerWrCtrl)); + } + + /* Put out the doubleword header... */ + /* ... and the packet rounded to a doubleword. */ + if (dev->mem_start) { + writew(skb->len, (void *)dev->mem_start); + writew(0, (void *)dev->mem_start); + copy_to_pc((void*)dev->mem_start, skb->data, (skb->len+3)&~3); + } else { + outw(skb->len, ioaddr + TX_FIFO); + outw(0, ioaddr + TX_FIFO); + outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2); + } + + if (use_fifo_buffer) { + DEBUG(0, " RunnerWr/RdCtrl is %4.4x/%4.4x, TxFree %x.\n", + inw(ioaddr + RunnerWrCtrl), inw(ioaddr + RunnerRdCtrl), + inw(ioaddr + TxFree)); + restore_flags(flags); + } +#else + outw(skb->len, ioaddr + TX_FIFO); + outw(0, ioaddr + TX_FIFO); + outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2); +#endif + + dev->trans_start = jiffies; + + /* TxFree appears only in Window 1, not offset 0x1c. */ + if (inw(ioaddr + TxFree) > 1536) { + dev->tbusy = 0; + } else + /* Interrupt us when the FIFO has room for max-sized packet. + The threshold is in units of dwords. */ + outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + + dev_kfree_skb (skb); + pop_tx_status(dev); + + return 0; +} + +/* The EL3 interrupt handler. */ +static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct el3_private *lp; + ioaddr_t ioaddr, status; + int work_budget = max_interrupt_work; + + if ((dev == NULL) || !dev->start) + return; + lp = (struct el3_private *)dev->priv; + ioaddr = dev->base_addr; + +#ifdef PCMCIA_DEBUG + if (test_and_set_bit(0, (void*)&dev->interrupt)) { + printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n", + dev->name); + return; + } + DEBUG(3, "%s: interrupt, status %4.4x.\n", + dev->name, inw(ioaddr + EL3_STATUS)); +#endif + + while ((status = inw(ioaddr + EL3_STATUS)) & + (IntLatch | RxComplete | RxEarly | StatsFull)) { + if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) { + DEBUG(1, "%s: Interrupt from dead card\n", dev->name); + break; + } + + if (status & RxComplete) + work_budget = el3_rx(dev, work_budget); + + if (status & TxAvailable) { + DEBUG(3, " TX room bit was handled.\n"); + /* There's room in the FIFO for a full-sized packet. */ + outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); + dev->tbusy = 0; + mark_bh(NET_BH); + } + + if (status & TxComplete) + pop_tx_status(dev); + + if (status & (AdapterFailure | RxEarly | StatsFull)) { + /* Handle all uncommon interrupts. */ + if (status & StatsFull) + update_stats(ioaddr, dev); + if (status & RxEarly) { + work_budget = el3_rx(dev, work_budget); + outw(AckIntr | RxEarly, ioaddr + EL3_CMD); + } + if (status & AdapterFailure) { + u16 fifo_diag; + EL3WINDOW(4); + fifo_diag = inw(ioaddr + Wn4_FIFODiag); + EL3WINDOW(1); + printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic" + " register %04x.\n", dev->name, fifo_diag); + if (fifo_diag & 0x0400) { + /* Tx overrun */ + wait_for_completion(dev, TxReset); + outw(TxEnable, ioaddr + EL3_CMD); + } + if (fifo_diag & 0x2000) { + /* Rx underrun */ + wait_for_completion(dev, RxReset); + set_rx_mode(dev); + outw(RxEnable, ioaddr + EL3_CMD); + } + outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); + } + } + + if (--work_budget < 0) { + DEBUG(0, "%s: Too much work in interrupt, " + "status %4.4x.\n", dev->name, status); + /* Clear all interrupts */ + outw(AckIntr | 0xFF, ioaddr + EL3_CMD); + break; + } + /* Acknowledge the IRQ. */ + outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); + } + +#ifdef PCMCIA_DEBUG + DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", + dev->name, inw(ioaddr + EL3_STATUS)); + dev->interrupt = 0; +#endif + return; +} + +/* + This timer serves two purposes: to check for missed interrupts + (and as a last resort, poll the NIC for events), and to monitor + the MII, reporting changes in cable status. +*/ +static void media_check(u_long arg) +{ + struct net_device *dev = (struct net_device *)(arg); + struct el3_private *lp = (struct el3_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + u_long flags; + u_short /* cable, */ media, partner; + + if (dev->start == 0) goto reschedule; + + /* Check for pending interrupt with expired latency timer: with + this, we can limp along even if the interrupt is blocked */ + if ((inw(ioaddr + EL3_STATUS) & IntLatch) && + (inb(ioaddr + Timer) == 0xff)) { + if (!lp->fast_poll) + printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); + el3_interrupt(dev->irq, dev, NULL); + lp->fast_poll = HZ; + } + if (lp->fast_poll) { + lp->fast_poll--; + lp->media.expires = jiffies + 2; + add_timer(&lp->media); + return; + } + + save_flags(flags); + cli(); + EL3WINDOW(4); + media = mdio_read(ioaddr, lp->phys[0], 1); + partner = mdio_read(ioaddr, lp->phys[0], 5); + EL3WINDOW(1); + restore_flags(flags); + + if (media != lp->media_status) { + if ((media ^ lp->media_status) & 0x0004) + printk(KERN_INFO "%s: %s link beat\n", dev->name, + (lp->media_status & 0x0004) ? "lost" : "found"); + if ((media ^ lp->media_status) & 0x0020) { + lp->partner = 0; + if (lp->media_status & 0x0020) { + printk(KERN_INFO "%s: autonegotiation restarted\n", + dev->name); + } else if (partner) { + partner &= lp->advertising; + lp->partner = partner; + printk(KERN_INFO "%s: autonegotiation complete: " + "%sbaseT-%cD selected\n", dev->name, + ((partner & 0x0180) ? "100" : "10"), + ((partner & 0x0140) ? 'F' : 'H')); + } else { + printk(KERN_INFO "%s: link partner did not autonegotiate\n", + dev->name); + } + + EL3WINDOW(3); + outb((partner & 0x0140 ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); + EL3WINDOW(1); + + } + if (media & 0x0010) + printk(KERN_INFO "%s: remote fault detected\n", + dev->name); + if (media & 0x0002) + printk(KERN_INFO "%s: jabber detected\n", dev->name); + lp->media_status = media; + } + +reschedule: + lp->media.expires = jiffies + HZ; + add_timer(&lp->media); +} + +static struct net_device_stats *el3_get_stats(struct net_device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + + if (dev->start) + update_stats(dev->base_addr, dev); + return &lp->stats; +} + +/* Update statistics. + Suprisingly this need not be run single-threaded, but it effectively is. + The counters clear when read, so the adds must merely be atomic. + */ +static void update_stats(ioaddr_t ioaddr, struct net_device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + u8 upper_cnt; + + DEBUG(2, "%s: updating the statistics.\n", dev->name); + + if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */ + return; + + /* Unlike the 3c509 we need not turn off stats updates while reading. */ + /* Switch to the stats window, and read everything. */ + EL3WINDOW(6); + lp->stats.tx_carrier_errors += inb(ioaddr + 0); + lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); + /* Multiple collisions. */ inb(ioaddr + 2); + lp->stats.collisions += inb(ioaddr + 3); + lp->stats.tx_window_errors += inb(ioaddr + 4); + lp->stats.rx_fifo_errors += inb(ioaddr + 5); + lp->stats.tx_packets += inb(ioaddr + 6); + upper_cnt = inb(ioaddr + 9); + lp->stats.tx_packets += (upper_cnt&0x30) << 4; + /* Rx packets */ inb(ioaddr + 7); + /* Tx deferrals */ inb(ioaddr + 8); + lp->stats.rx_bytes += inw(ioaddr + 10); + lp->stats.tx_bytes += inw(ioaddr + 12); + + /* With Vortex and later we must also clear the BadSSD counter. */ + EL3WINDOW(4); + inb(ioaddr + 12); + + EL3WINDOW(1); +} + +static int el3_rx(struct net_device *dev, int worklimit) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + short rx_status; + + DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n", + dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); + while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) && + (--worklimit >= 0)) { + if (rx_status & 0x4000) { /* Error, update stats. */ + short error = rx_status & 0x3800; + lp->stats.rx_errors++; + switch (error) { + case 0x0000: lp->stats.rx_over_errors++; break; + case 0x0800: lp->stats.rx_length_errors++; break; + case 0x1000: lp->stats.rx_frame_errors++; break; + case 0x1800: lp->stats.rx_length_errors++; break; + case 0x2000: lp->stats.rx_frame_errors++; break; + case 0x2800: lp->stats.rx_crc_errors++; break; + } + } else { + short pkt_len = rx_status & 0x7ff; + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_len+5); + + DEBUG(3, " Receiving packet size %d status %4.4x.\n", + pkt_len, rx_status); + if (skb != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); + +#ifdef BROKEN_FEATURES + if (use_fifo_buffer) { + outw(((pkt_len+3)>>2)<<1, ioaddr + RunnerRdCtrl); + DEBUG(0,"Start Rx %x -- RunnerRdCtrl is %4.4x.\n", + pkt_len, inw(ioaddr + RunnerRdCtrl)); + } + if (dev->mem_start) { + copy_from_pc(skb_put(skb, pkt_len), + (void*)dev->mem_start, (pkt_len+3)&~3); + } else { + insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), + ((pkt_len+3)>>2)); + } + if (use_fifo_buffer) { + DEBUG(0," RunnerRdCtrl is now %4.4x.\n", + inw(ioaddr + RunnerRdCtrl)); + outw(0, ioaddr + RunnerRdCtrl); + DEBUG(0, " Rx packet with data %2.2x:%2.2x:%2.2x\n", + skb->head[0], skb->head[1], skb->head[2]); + } +#else + insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), + ((pkt_len+3)>>2)); +#endif + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + lp->stats.rx_packets++; + } else { + DEBUG(1, "%s: couldn't allocate a sk_buff of" + " size %d.\n", dev->name, pkt_len); + lp->stats.rx_dropped++; + } + } + wait_for_completion(dev, RxDiscard); + } + + return worklimit; +} + +#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 el3_private *vp = (struct el3_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + int phy = vp->phys[0] & 0x1f; + + DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", + dev->name, rq->ifr_ifrn.ifrn_name, cmd, + data[0], data[1], data[2], data[3]); + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = phy; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + { + int saved_window; + long flags; + + save_flags(flags); + cli(); + saved_window = inw(ioaddr + EL3_CMD) >> 13; + EL3WINDOW(4); + data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + EL3WINDOW(saved_window); + restore_flags(flags); + return 0; + } + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + { + int saved_window; + long flags; + + if (!suser()) + return -EPERM; + save_flags(flags); + cli(); + saved_window = inw(ioaddr + EL3_CMD) >> 13; + EL3WINDOW(4); + mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + EL3WINDOW(saved_window); + restore_flags(flags); + return 0; + } + default: + return -EOPNOTSUPP; + } +} +#endif /* HAVE_PRIVATE_IOCTL */ + +/* The Odie chip has a 64 bin multicast filter, but the bit layout is not + documented. Until it is we revert to receiving all multicast frames when + any multicast reception is desired. + Note: My other drivers emit a log message whenever promiscuous mode is + entered to help detect password sniffers. This is less desirable on + typical PC card machines, so we omit the message. + */ + +static void set_rx_mode(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + + if (dev->flags & IFF_PROMISC) + outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, + ioaddr + EL3_CMD); + else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) + outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); + else + outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); +} + +static int el3_close(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + dev_link_t *link; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + DEBUG(2, "%s: shutting down ethercard.\n", dev->name); + + if (DEV_OK(link)) { + /* Turn off statistics ASAP. We update lp->stats below. */ + outw(StatsDisable, ioaddr + EL3_CMD); + + /* Disable the receiver and transmitter. */ + outw(RxDisable, ioaddr + EL3_CMD); + outw(TxDisable, ioaddr + EL3_CMD); + + /* Note: Switching to window 0 may disable the IRQ. */ + EL3WINDOW(0); + + update_stats(ioaddr, dev); + } + + link->open--; + dev->start = 0; + del_timer(&((struct el3_private *)dev->priv)->media); + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int __init init_3c574_cs(void) +{ + servinfo_t serv; + + /* Always emit the version, before any failure. */ + printk(KERN_INFO"%s", tc574_version); + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "3c574_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &tc574_attach, &tc574_detach); + return 0; +} + +static void __exit exit_3c574_cs(void) +{ + DEBUG(0, "3c574_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + tc574_detach(dev_list); +} + +module_init(init_3c574_cs); +module_exit(exit_3c574_cs); + +/* + * Local variables: + * compile-command: "make 3c574_cs.o" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c --- v2.3.22/linux/drivers/net/pcmcia/3c589_cs.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/pcmcia/3c589_cs.c Wed Oct 20 21:33:12 1999 @@ -4,7 +4,7 @@ Copyright (C) 1999 David A. Hinds -- dhinds@hyper.stanford.edu - 3c589_cs.c 1.134 1999/09/15 15:33:09 + 3c589_cs.c 1.135 1999/10/07 20:14:54 The network driver code is based on Donald Becker's 3c589 code: @@ -115,7 +115,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.134 1999/09/15 15:33:09 (David Hinds)"; +"3c589_cs.c 1.135 1999/10/07 20:14:54 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -142,14 +142,14 @@ static int tc589_event(event_t event, int priority, event_callback_args_t *args); -static ushort read_eeprom(short ioaddr, int index); +static u_short read_eeprom(ioaddr_t ioaddr, int index); static void tc589_reset(struct net_device *dev); static void media_check(u_long arg); static int el3_config(struct net_device *dev, struct ifmap *map); static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void update_stats(int addr, struct net_device *dev); +static void update_stats(ioaddr_t addr, struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev); static int el3_close(struct net_device *dev); @@ -355,14 +355,14 @@ struct net_device *dev; tuple_t tuple; cisparse_t parse; - u_short buf[32]; + u_short buf[32], *phys_addr; int last_fn, last_ret, i, j, multi = 0; - short ioaddr, *phys_addr; + ioaddr_t ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; handle = link->handle; dev = link->priv; - phys_addr = (short *)dev->dev_addr; + phys_addr = (u_short *)dev->dev_addr; DEBUG(0, "3c589_config(0x%p)\n", link); @@ -571,7 +571,7 @@ Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero. */ -static ushort read_eeprom(short ioaddr, int index) +static u_short read_eeprom(ioaddr_t ioaddr, int index) { int i; outw(EEPROM_READ + index, ioaddr + 10); @@ -589,7 +589,7 @@ static void tc589_set_xcvr(struct net_device *dev, int if_port) { struct el3_private *lp = (struct el3_private *)dev->priv; - ushort ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; EL3WINDOW(0); switch (if_port) { @@ -611,7 +611,7 @@ static void dump_status(struct net_device *dev) { - int ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; EL3WINDOW(1); printk(KERN_INFO " irq status %04x, rx status %04x, tx status " "%02x tx free %04x\n", inw(ioaddr+EL3_STATUS), @@ -627,7 +627,7 @@ /* Reset and restore all of the 3c589 registers. */ static void tc589_reset(struct net_device *dev) { - ushort ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; int i; EL3WINDOW(0); @@ -709,7 +709,7 @@ static void el3_tx_timeout(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - int ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name); dump_status(dev); @@ -724,7 +724,7 @@ static void pop_tx_status(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - int ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; int i; /* Clear the Tx status stack. */ @@ -747,7 +747,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - int ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ if (dev->tbusy) { @@ -791,7 +791,7 @@ { struct net_device *dev = (struct net_device *)dev_id; struct el3_private *lp; - int ioaddr, status; + ioaddr_t ioaddr, status; int i = 0; if ((dev == NULL) || !dev->start) @@ -885,7 +885,7 @@ { struct net_device *dev = (struct net_device *)(arg); struct el3_private *lp = (struct el3_private *)dev->priv; - int ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; u_short media, errs; u_long flags; @@ -984,7 +984,7 @@ operation, and it's simpler for the rest of the driver to assume that window 1 is always valid rather than use a special window-state variable. */ -static void update_stats(int ioaddr, struct net_device *dev) +static void update_stats(ioaddr_t ioaddr, struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; @@ -1013,7 +1013,7 @@ static int el3_rx(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - int ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; int worklimit = 32; short rx_status; @@ -1073,7 +1073,7 @@ */ static void set_multicast_list(struct net_device *dev) { - short ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; dev_link_t *link; for (link = dev_list; link; link = link->next) if (link->priv == dev) break; @@ -1099,7 +1099,7 @@ static int el3_close(struct net_device *dev) { - int ioaddr = dev->base_addr; + ioaddr_t ioaddr = dev->base_addr; dev_link_t *link; for (link = dev_list; link; link = link->next) diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.3.22/linux/drivers/net/pcmcia/Config.in Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/pcmcia/Config.in Thu Oct 21 12:34:59 1999 @@ -3,13 +3,34 @@ # mainmenu_option next_comment -comment 'PCMCIA network devices' +comment 'PCMCIA network device support' -dep_tristate 'PCMCIA ethernet cards (NE2000 compatibles: DE-650, ...)' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA -dep_tristate '3Com 3c589 PCMCIA card' CONFIG_PCMCIA_3C589 $CONFIG_PCMCIA -dep_tristate 'Aviator/Raytheon 2.4MHz wireless' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA +bool 'PCMCIA network device support' CONFIG_NET_PCMCIA +if [ "$CONFIG_NET_PCMCIA" = "y" ]; then + dep_tristate ' 3Com 3c589 PCMCIA support' CONFIG_PCMCIA_3C589 $CONFIG_PCMCIA + dep_tristate ' 3Com 3c574 PCMCIA support' CONFIG_PCMCIA_3C574 $CONFIG_PCMCIA + dep_tristate ' Fujitsu FMV-J18x PCMCIA support' CONFIG_PCMCIA_FMVJ18X $CONFIG_PCMCIA + dep_tristate ' NE2000 compatible PCMCIA support' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA + dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA + dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA + dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA -if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" ]; then + # if [ "$CONFIG_CARDBUS" = "y" ]; then + # dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 $CONFIG_PCMCIA + # dep_tristate ' DEC Tulip CardBus support' CONFIG_PCMCIA_TULIP $CONFIG_PCMCIA + # dep_tristate ' SMC EPIC CardBus support' CONFIG_PCMCIA_EPIC100 $CONFIG_PCMCIA + # fi + + dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA + dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA + dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA +fi + +if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \ + "$CONFIG_PCMCIA_FMVJ18X" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" -o \ + "$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \ + "$CONFIG_PCMCIA_XIRC2PS" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o \ + "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" ]; then define_bool CONFIG_PCMCIA_NETCARD y fi diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile --- v2.3.22/linux/drivers/net/pcmcia/Makefile Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/pcmcia/Makefile Wed Oct 20 21:33:12 1999 @@ -13,22 +13,81 @@ M_OBJS := MOD_LIST_NAME := PCMCIA_MODULES +#CFLAGS_3c575_cb.o = -DCARDBUS +#CFLAGS_tulip_cb.o = -DCARDBUS + +ifeq ($(CONFIG_PCMCIA_3C589),y) + O_OBJS += 3c589_cs.o +else + ifeq ($(CONFIG_PCMCIA_3C589),m) + M_OBJS += 3c589_cs.o + endif +endif + +ifeq ($(CONFIG_PCMCIA_3C574),y) + O_OBJS += 3c574_cs.o +else + ifeq ($(CONFIG_PCMCIA_3C574),m) + M_OBJS += 3c574_cs.o + endif +endif + +ifeq ($(CONFIG_PCMCIA_FMVJ18X),y) + O_OBJS += fmvj18x_cs.o +else + ifeq ($(CONFIG_PCMCIA_FMVJ18X),m) + M_OBJS += fmvj18x_cs.o + endif +endif + +ifeq ($(CONFIG_PCMCIA_NMCLAN),y) + O_OBJS += nmclan_cs.o +else + ifeq ($(CONFIG_PCMCIA_NMCLAN),m) + M_OBJS += nmclan_cs.o + endif +endif + ifeq ($(CONFIG_PCMCIA_PCNET),y) O_OBJS += pcnet_cs.o else ifeq ($(CONFIG_PCMCIA_PCNET),m) - MX_OBJS += pcnet_cs.o + M_OBJS += pcnet_cs.o endif endif -ifeq ($(CONFIG_PCMCIA_3C589),y) - O_OBJS += 3c589_cs.o +ifeq ($(CONFIG_PCMCIA_SMC91C92),y) + O_OBJS += smc91c92_cs.o else - ifeq ($(CONFIG_PCMCIA_3C589),m) - MX_OBJS += 3c589_cs.o + ifeq ($(CONFIG_PCMCIA_SMC91C92),m) + M_OBJS += smc91c92_cs.o endif endif +#ifeq ($(CONFIG_PCMCIA_3C575),y) +# O_OBJS += 3c575_cb.o +#else +# ifeq ($(CONFIG_PCMCIA_3C575),m) +# M_OBJS += 3c575_cb.o +# endif +#endif + +#ifeq ($(CONFIG_PCMCIA_TULIP),y) +# O_OBJS += tulip_cb.o +#else +# ifeq ($(CONFIG_PCMCIA_TULIP),m) +# M_OBJS += tulip_cb.o +# endif +#endif + +#ifeq ($(CONFIG_PCMCIA_EPIC100),y) +# O_OBJS += epic100_cb.o +#else +# ifeq ($(CONFIG_PCMCIA_EPIC100),m) +# M_OBJS += epic100_cb.o +# endif +#endif + ifeq ($(CONFIG_PCMCIA_RAYCS),y) OX_OBJS += ray_cs.o else @@ -37,4 +96,23 @@ endif endif +ifeq ($(CONFIG_PCMCIA_NETWAVE),y) + OX_OBJS += netwave_cs.o +else + ifeq ($(CONFIG_PCMCIA_NETWAVE),m) + M_OBJS += netwave_cs.o + endif +endif + +ifeq ($(CONFIG_PCMCIA_WAVELAN),y) + OX_OBJS += wavelan_cs.o +else + ifeq ($(CONFIG_PCMCIA_WAVELAN),m) + M_OBJS += wavelan_cs.o + endif +endif + include $(TOPDIR)/Rules.make + +#epic100_cb.o: ../epic100.c +# $(CC) $(CFLAGS) -DCARDBUS -c -o $@ ../epic100.c diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c --- v2.3.22/linux/drivers/net/pcmcia/fmvj18x_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/fmvj18x_cs.c Wed Oct 20 21:33:12 1999 @@ -0,0 +1,1205 @@ +/*====================================================================== + fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp + + A fmvj18x (and its compatibles) PCMCIA client driver + + Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp + + TDK LAK-CD021 and CONTEC C-NET(PC)C support added by + Nobuhiro Katayama, kata-n@po.iijnet.or.jp + + The PCMCIA client code is based on code written by David Hinds. + Network code is based on the "FMV-18x driver" by Yutaka TAMIYA + but is actually largely Donald Becker's AT1700 driver, which + carries the following attribution: + + Written 1993-94 by Donald Becker. + + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + 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 + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) +#endif + +/* + For debugging this driver you may need more information. + To enable printing registers or status, set 'fmvj18x_debug=#' option . + */ +#ifdef FMVJ18X_DEBUG +static int fmvj18x_debug = FMVJ18X_DEBUG; +#else +static int fmvj18x_debug = 2; +#endif /* FMVJ18X_DEBUG */ + +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +/* SRAM configuration */ +/* 0:4KB*2 TX buffer else:8KB*2 TX buffer */ +static int sram_config = 0; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(sram_config, "i"); + +/*====================================================================*/ +/* + driver version infomation + */ +#ifdef PCMCIA_DEBUG +static char *version = + "fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp"; +#endif + +/*====================================================================*/ +/* + PCMCIA event handlers + */ +static void fmvj18x_config(dev_link_t *link); +static void fmvj18x_release(u_long arg); +static int fmvj18x_event(event_t event, int priority, + event_callback_args_t *args); +static int fmvj18x_init(struct net_device *dev); +static dev_link_t *fmvj18x_attach(void); +static void fmvj18x_detach(dev_link_t *); + +/* + LAN controler(MBH86960A) specific routines + */ +static int fjn_config(struct net_device *dev, struct ifmap *map); +static int fjn_open(struct net_device *dev); +static int fjn_close(struct net_device *dev); +static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void fjn_rx(struct net_device *dev); +static void fjn_reset(struct net_device *dev); +static struct net_device_stats *fjn_get_stats(struct net_device *dev); +static void set_rx_mode(struct net_device *dev); + +static dev_info_t dev_info = "fmvj18x_cs"; +static dev_link_t *dev_list = NULL; + +/* + card type + */ +typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501 } cardtype_t; + +/* + driver specific data structure +*/ +typedef struct local_info_t { + dev_node_t node; + struct net_device_stats stats; + long open_time; + uint tx_started:1; + uint tx_queue; + u_short tx_queue_len; + cardtype_t cardtype; + u_short sent; + u_char mc_filter[8]; +} local_info_t; + +#define MC_FILTERBREAK 64 + +/*====================================================================*/ +/* + ioport offset from the base address + */ +#define TX_STATUS 0 /* transmit status register */ +#define RX_STATUS 1 /* receive status register */ +#define TX_INTR 2 /* transmit interrupt mask register */ +#define RX_INTR 3 /* receive interrupt mask register */ +#define TX_MODE 4 /* transmit mode register */ +#define RX_MODE 5 /* receive mode register */ +#define CONFIG_0 6 /* configuration register 0 */ +#define CONFIG_1 7 /* configuration register 1 */ + +#define NODE_ID 8 /* node ID register (bank 0) */ +#define MAR_ADR 8 /* multicast address registers (bank 1) */ + +#define DATAPORT 8 /* buffer mem port registers (bank 2) */ +#define TX_START 10 /* transmit start register */ +#define COL_CTRL 11 /* 16 collision control register */ +#define BMPR12 12 /* reserved */ +#define BMPR13 13 /* reserved */ +#define RX_SKIP 14 /* skip received packet register */ + +#define LAN_CTRL 16 /* LAN card control register */ + +#define MAC_ID 0x1a /* hardware address */ + +/* + control bits + */ +#define ENA_TMT_OK 0x80 +#define ENA_TMT_REC 0x20 +#define ENA_COL 0x04 +#define ENA_16_COL 0x02 +#define ENA_TBUS_ERR 0x01 + +#define ENA_PKT_RDY 0x80 +#define ENA_BUS_ERR 0x40 +#define ENA_LEN_ERR 0x08 +#define ENA_ALG_ERR 0x04 +#define ENA_CRC_ERR 0x02 +#define ENA_OVR_FLO 0x01 + +/* flags */ +#define F_TMT_RDY 0x80 /* can accept new packet */ +#define F_NET_BSY 0x40 /* carrier is detected */ +#define F_TMT_OK 0x20 /* send packet successfully */ +#define F_SRT_PKT 0x10 /* short packet error */ +#define F_COL_ERR 0x04 /* collision error */ +#define F_16_COL 0x02 /* 16 collision error */ +#define F_TBUS_ERR 0x01 /* bus read error */ + +#define F_PKT_RDY 0x80 /* packet(s) in buffer */ +#define F_BUS_ERR 0x40 /* bus read error */ +#define F_LEN_ERR 0x08 /* short packet */ +#define F_ALG_ERR 0x04 /* frame error */ +#define F_CRC_ERR 0x02 /* CRC error */ +#define F_OVR_FLO 0x01 /* overflow error */ + +#define F_BUF_EMP 0x40 /* receive buffer is empty */ + +#define F_SKP_PKT 0x05 /* drop packet in buffer */ + +/* default bitmaps */ +#define D_TX_INTR ( ENA_TMT_OK ) +#define D_RX_INTR ( ENA_PKT_RDY | ENA_LEN_ERR \ + | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO ) +#define TX_STAT_M ( F_TMT_RDY ) +#define RX_STAT_M ( F_PKT_RDY | F_LEN_ERR \ + | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO ) + +/* commands */ +#define D_TX_MODE 0x06 /* no tests, detect carrier */ +#define ID_MATCHED 0x02 /* (RX_MODE) */ +#define RECV_ALL 0x03 /* (RX_MODE) */ +#define CONFIG0_DFL 0x5a /* 16bit bus, 4K x 2 Tx queues */ +#define CONFIG0_DFL_1 0x5e /* 16bit bus, 8K x 2 Tx queues */ +#define CONFIG0_RST 0xda /* Data Link Controler off (CONFIG_0) */ +#define CONFIG0_RST_1 0xde /* Data Link Controler off (CONFIG_0) */ +#define BANK_0 0xa0 /* bank 0 (CONFIG_1) */ +#define BANK_1 0xa4 /* bank 1 (CONFIG_1) */ +#define BANK_2 0xa8 /* bank 2 (CONFIG_1) */ +#define CHIP_OFF 0x80 /* contrl chip power off (CONFIG_1) */ +#define DO_TX 0x80 /* do transmit packet */ +#define SEND_PKT 0x81 /* send a packet */ +#define AUTO_MODE 0x07 /* Auto skip packet on 16 col detected */ +#define MANU_MODE 0x03 /* Stop and skip packet on 16 col */ +#define TDK_AUTO_MODE 0x47 /* Auto skip packet on 16 col detected */ +#define TDK_MANU_MODE 0x43 /* Stop and skip packet on 16 col */ +#define INTR_OFF 0x0d /* LAN controler ignores interrupts */ +#define INTR_ON 0x1d /* LAN controler will catch interrupts */ + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + +======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + fmvj18x_detach(link); + } +} + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================*/ + +static dev_link_t *fmvj18x_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + int i, ret; + + DEBUG(0, "fmvj18x_attach()\n"); + flush_stale_links(); + + /* 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 = &fmvj18x_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 32; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = &fjn_interrupt; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Make up a FMVJ18x specific data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + dev->priv = kmalloc(sizeof(local_info_t), GFP_KERNEL); + memset(dev->priv, 0, sizeof(local_info_t)); + + /* The FMVJ18x specific entries in the device structure. */ + dev->hard_start_xmit = &fjn_start_xmit; + dev->set_config = &fjn_config; + dev->get_stats = &fjn_get_stats; + dev->set_multicast_list = &set_rx_mode; + ether_setup(dev); + dev->name = ((local_info_t *)dev->priv)->node.dev_name; + dev->init = &fmvj18x_init; + dev->open = &fjn_open; + dev->stop = &fjn_close; + dev->tbusy = 0xFF; + link->priv = link->irq.Instance = dev; + + /* 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 = &fmvj18x_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); + fmvj18x_detach(link); + return NULL; + } + + return link; +} /* fmvj18x_attach */ + +/*====================================================================*/ + +static void fmvj18x_detach(dev_link_t *link) +{ + dev_link_t **linkp; + long flags; + + DEBUG(0, "fmvj18x_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + if (link->state & DEV_CONFIG) { + fmvj18x_release((u_long)link); + if (link->state & DEV_STALE_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) { + struct net_device *dev = link->priv; + if (link->dev != NULL) + unregister_netdev(dev); + if (dev->priv) + kfree(dev->priv); + kfree(dev); + } + kfree(link); + +} /* fmvj18x_detach */ + +/*====================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void fmvj18x_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + struct net_device *dev; + u_short buf[32]; + int i, last_fn, last_ret; + ioaddr_t ioaddr; + cardtype_t cardtype; + char *card_name = "unknown"; + u_char *node_id; + + handle = link->handle; + dev =link->priv; + + DEBUG(0, "fmvj18x_config(0x%p)\n", link); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleData = (u_char *)buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + + /* Configure card */ + link->state |= DEV_CONFIG; + + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + tuple.DesiredTuple = CISTPL_FUNCE; + tuple.TupleOffset = 0; + if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) { + /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigIndex = parse.cftable_entry.index; + tuple.DesiredTuple = CISTPL_MANFID; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + + switch (le16_to_cpu(buf[0])) { + case MANFID_TDK: + cardtype = TDK; + break; + case MANFID_CONTEC: + cardtype = CONTEC; + break; + case MANFID_FUJITSU: + if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10302) + cardtype = MBH10302; + else if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304) + cardtype = MBH10304; + else + cardtype = LA501; + break; + default: + cardtype = MBH10304; + } + } else { + /* old type card */ + cardtype = MBH10302; + link->conf.ConfigIndex = 1; + } + CS_CHECK(RequestIO, link->handle, &link->io); + CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + dev->tbusy = 0; + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); + goto failed; + } + + ioaddr = dev->base_addr; + + /* Power On chip and select bank 0 */ + outb(BANK_0, ioaddr + CONFIG_1); + /* Reset controler */ + if( sram_config == 0 ) + outb(CONFIG0_RST, ioaddr + CONFIG_0); + else + outb(CONFIG0_RST_1, ioaddr + CONFIG_0); + + /* Set hardware address */ + switch (cardtype) { + case MBH10304: + case TDK: + case LA501: + case CONTEC: + tuple.DesiredTuple = CISTPL_FUNCE; + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleOffset = 0; + CS_CHECK(GetTupleData, handle, &tuple); + if (cardtype == MBH10304) { + /* MBH10304's CIS_FUNCE is corrupted */ + node_id = &(tuple.TupleData[5]); + card_name = "FMV-J182"; + } else { + while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) { + CS_CHECK(GetNextTuple, handle, &tuple) ; + CS_CHECK(GetTupleData, handle, &tuple) ; + } + node_id = &(tuple.TupleData[2]); + if( cardtype == TDK ) { + card_name = "TDK LAK-CD021"; + } else if( cardtype == LA501 ) { + card_name = "LA501"; + } else { + card_name = "C-NET(PC)C"; + } + } + /* Read MACID from CIS */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = node_id[i]; + break; + case MBH10302: + default: + /* Read MACID from register */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb(ioaddr + MAC_ID + i); + card_name = "FMV-J181"; + break; + } + + link->dev = &((local_info_t *)dev->priv)->node; + link->state &= ~DEV_CONFIG_PENDING; + + ((struct local_info_t *)dev->priv)->cardtype = cardtype ; + /* print current configuration */ + printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", + dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", + dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + + return; + +cs_failed: + /* All Card Services errors end up here */ + cs_error(link->handle, last_fn, last_ret); +failed: + fmvj18x_release((u_long)link); + +} /* fmvj18x_config */ + +/*====================================================================*/ + +static void fmvj18x_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "fmvj18x_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed. + */ + if (link->open) { + DEBUG(1, "fmvj18x_cs: release postponed, '%s' " + "still open\n", link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* fmvj18x_release */ + +/*====================================================================*/ + +static int fmvj18x_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + + DEBUG(1, "fmvj18x_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 0xFF; + dev->start = 0; + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + fmvj18x_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 0xFF; + dev->start = 0; + } + 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); + if (link->open) { + dev->tbusy = 0; + dev->start = 1; + fjn_reset(dev); + } + } + break; + } + return 0; +} /* fmvj18x_event */ + +static int fmvj18x_init(struct net_device *dev) +{ + return 0; +} /* fmvj18x_init */ + +/*====================================================================*/ + +static int __init init_fmvj18x_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "fmvj18x: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &fmvj18x_attach, &fmvj18x_detach); + return 0; +} + +static void __exit exit_fmvj18x_cs(void) +{ + DEBUG(0, "fmvj18x_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + fmvj18x_detach(dev_list); +} + +module_init(init_fmvj18x_cs); +module_exit(exit_fmvj18x_cs); + +/*====================================================================*/ + +static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + ioaddr_t ioaddr; + local_info_t *lp; + unsigned short tx_stat, rx_stat; + + if (dev == NULL) { + printk(KERN_NOTICE "fjn_interrupt(): irq %d for " + "unknown device.\n", irq); + return; + } + if (dev->interrupt) { + printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n", + dev->name); + return; + } + dev->interrupt = 1; + lp = (struct local_info_t *)dev->priv; + ioaddr = dev->base_addr; + + /* avoid multiple interrupts */ + outw(0x0000, ioaddr + TX_INTR); + + /* wait for a while */ + udelay(1); + + /* get status */ + tx_stat = inb(ioaddr + TX_STATUS); + rx_stat = inb(ioaddr + RX_STATUS); + + /* clear status */ + outb(tx_stat, ioaddr + TX_STATUS); + outb(rx_stat, ioaddr + RX_STATUS); + + if (fmvj18x_debug > 4) { + printk(KERN_DEBUG "%s: interrupt, rx_status %02x.\n", + dev->name, rx_stat); + printk(KERN_DEBUG " tx_status %02x.\n", + tx_stat); + } + + if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { + /* there is packet(s) in rx buffer */ + fjn_rx(dev); + } + if (tx_stat & F_TMT_RDY) { + lp->stats.tx_packets += lp->sent ; + lp->sent = 0 ; + if (lp->tx_queue) { + outb(DO_TX | lp->tx_queue, ioaddr + TX_START); + lp->sent = lp->tx_queue ; + lp->tx_queue = 0; + lp->tx_queue_len = 0; + dev->trans_start = jiffies; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } else { + lp->tx_started = 0; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + } + if (fmvj18x_debug > 4) { + printk(KERN_DEBUG "%s: exiting interrupt,\n", dev->name); + printk(KERN_DEBUG " tx_status %02x, rx_status %02x.\n", + tx_stat, rx_stat); + } + + dev->interrupt = 0; + outb(D_TX_INTR, ioaddr + TX_INTR); + outb(D_RX_INTR, ioaddr + RX_INTR); + + return; +} /* fjn_interrupt */ + +/*====================================================================*/ + +static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct local_info_t *lp = (struct local_info_t *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + + if (dev->tbusy) { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 10) + return 1; + printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n", + dev->name, htons(inw(ioaddr + TX_STATUS)), + inb(ioaddr + TX_STATUS) & F_TMT_RDY + ? "IRQ conflict" : "network cable problem"); + printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x " + "%04x %04x %04x %04x %04x.\n", + dev->name, htons(inw(ioaddr + 0)), + htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)), + htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)), + htons(inw(ioaddr +10)), htons(inw(ioaddr +12)), + htons(inw(ioaddr +14))); + lp->stats.tx_errors++; + /* ToDo: We should try to restart the adaptor... */ + cli(); + + fjn_reset(dev); + + lp->tx_started = 0; + lp->tx_queue = 0; + lp->tx_queue_len = 0; + lp->sent = 0; + lp->open_time = jiffies; + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + + sti(); + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) + printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name); + else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + + if (length > ETH_FRAME_LEN) { + if (fmvj18x_debug) + printk(KERN_NOTICE "%s: Attempting to send a large packet" + " (%d bytes).\n", dev->name, length); + return 1; + } + + if (fmvj18x_debug > 4) + printk(KERN_DEBUG "%s: Transmitting a packet of length %lu.\n", + dev->name, (unsigned long)skb->len); + lp->stats.tx_bytes += skb->len; + + /* Disable both interrupts. */ + outw(0x0000, ioaddr + TX_INTR); + + /* wait for a while */ + udelay(1); + + outw(length, ioaddr + DATAPORT); + outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); + + lp->tx_queue++; + lp->tx_queue_len += ((length+3) & ~1); + + if (lp->tx_started == 0) { + /* If the Tx is idle, always trigger a transmit. */ + outb(DO_TX | lp->tx_queue, ioaddr + TX_START); + lp->sent = lp->tx_queue ; + lp->tx_queue = 0; + lp->tx_queue_len = 0; + dev->trans_start = jiffies; + lp->tx_started = 1; + dev->tbusy = 0; + } else { + if( sram_config == 0 ) { + if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) ) + /* Yes, there is room for one more packet. */ + dev->tbusy = 0; + } else { + if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && + lp->tx_queue < 127 ) + /* Yes, there is room for one more packet. */ + dev->tbusy = 0; + } + } + + /* Re-enable interrupts */ + outb(D_TX_INTR, ioaddr + TX_INTR); + outb(D_RX_INTR, ioaddr + RX_INTR); + } + dev_kfree_skb (skb); + + return 0; +} /* fjn_start_xmit */ + +/*====================================================================*/ + +static void fjn_reset(struct net_device *dev) +{ + struct local_info_t *lp = (struct local_info_t *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int i; + + if (fmvj18x_debug > 4) { + printk(KERN_DEBUG "fjn_reset(%s) called.\n",dev->name); + } + + /* Power On chip and select bank 0 */ + outb(BANK_0, ioaddr + CONFIG_1); + /* Reset buffers */ + if( sram_config == 0 ) + outb(CONFIG0_RST, ioaddr + CONFIG_0); + else + outb(CONFIG0_RST_1, ioaddr + CONFIG_0); + + /* Set Tx modes */ + outb(D_TX_MODE, ioaddr + TX_MODE); + /* set Rx modes */ + outb(ID_MATCHED, ioaddr + RX_MODE); + + /* Set hardware address */ + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + NODE_ID + i); + + if (fmvj18x_debug > 4) { + printk(KERN_DEBUG "node id: "); + for (i = 0; i < 6; i++) + printk("%02X ",inb(ioaddr + NODE_ID + i)); + printk("\n"); + } + /* Switch to bank 1 */ + outb(BANK_1, ioaddr + CONFIG_1); + + /* set the multicast table to accept none. */ + for (i = 0; i < 6; i++) + outb(0x00, ioaddr + MAR_ADR + i); + + /* Switch to bank 2 (runtime mode) */ + outb(BANK_2, ioaddr + CONFIG_1); + + /* set 16col ctrl bits */ + if( lp->cardtype == TDK ) + outb(TDK_AUTO_MODE, ioaddr + COL_CTRL); + else + outb(AUTO_MODE, ioaddr + COL_CTRL); + + /* clear Reserved Regs */ + outb(0x00, ioaddr + BMPR12); + outb(0x00, ioaddr + BMPR13); + + /* reset Skip packet reg. */ + outb(0x01, ioaddr + RX_SKIP); + + /* Enable Tx and Rx */ + if( sram_config == 0 ) + outb(CONFIG0_DFL, ioaddr + CONFIG_0); + else + outb(CONFIG0_DFL_1, ioaddr + CONFIG_0); + + /* Init receive pointer ? */ + inw(ioaddr + DATAPORT); + inw(ioaddr + DATAPORT); + + /* Clear all status */ + outb(0xff, ioaddr + TX_STATUS); + outb(0xff, ioaddr + RX_STATUS); + + if( lp->cardtype != TDK ) + outb(INTR_OFF, ioaddr + LAN_CTRL); + + /* Turn on Rx interrupts */ + outb(D_TX_INTR, ioaddr + TX_INTR); + outb(D_RX_INTR, ioaddr + RX_INTR); + + /* Turn on interrupts from LAN card controler */ + if( lp->cardtype != TDK ) + outb(INTR_ON, ioaddr + LAN_CTRL); +} /* fjn_reset */ + +/*====================================================================*/ + +static void fjn_rx(struct net_device *dev) +{ + struct local_info_t *lp = (struct local_info_t *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int boguscount = 10; /* 5 -> 10: by agy 19940922 */ + + if (fmvj18x_debug > 4) + printk(KERN_DEBUG "%s: in rx_packet(), rx_status %02x.\n", + dev->name, inb(ioaddr + RX_STATUS)); + + while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { + u_short status = inw(ioaddr + DATAPORT); + + if (fmvj18x_debug > 4) + printk(KERN_DEBUG "%s: Rxing packet mode %02x status %04x.\n", + dev->name, inb(ioaddr + RX_MODE), status); +#ifndef final_version + if (status == 0) { + outb(F_SKP_PKT, ioaddr + RX_SKIP); + break; + } +#endif + if ((status & 0xF0) != 0x20) { /* There was an error. */ + lp->stats.rx_errors++; + if (status & F_LEN_ERR) lp->stats.rx_length_errors++; + if (status & F_ALG_ERR) lp->stats.rx_frame_errors++; + if (status & F_CRC_ERR) lp->stats.rx_crc_errors++; + if (status & F_OVR_FLO) lp->stats.rx_over_errors++; + } else { + u_short pkt_len = inw(ioaddr + DATAPORT); + /* Malloc up new buffer. */ + struct sk_buff *skb; + + if (pkt_len > 1550) { + printk(KERN_NOTICE "%s: The FMV-18x claimed a very " + "large packet, size %d.\n", dev->name, pkt_len); + outb(F_SKP_PKT, ioaddr + RX_SKIP); + lp->stats.rx_errors++; + break; + } + skb = dev_alloc_skb(pkt_len+2); + if (skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping " + "packet (len %d).\n", dev->name, pkt_len); + outb(F_SKP_PKT, ioaddr + RX_SKIP); + lp->stats.rx_dropped++; + break; + } + skb->dev = dev; + + skb_reserve(skb, 2); + insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), + (pkt_len + 1) >> 1); + skb->protocol = eth_type_trans(skb, dev); + + if (fmvj18x_debug > 5) { + int i; + printk(KERN_DEBUG "%s: Rxed packet of length %d: ", + dev->name, pkt_len); + for (i = 0; i < 14; i++) + printk(" %02x", skb->data[i]); + printk(".\n"); + } + + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + } + if (--boguscount <= 0) + break; + } + + /* If any worth-while packets have been received, dev_rint() + has done a mark_bh(NET_BH) for us and will work on them + when we get to the bottom-half routine. */ +/* + if( lp->cardtype != TDK ) { + int i; + for (i = 0; i < 20; i++) { + if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP) + break; + (void)inw(ioaddr + DATAPORT); /+ dummy status read +/ + outb(F_SKP_PKT, ioaddr + RX_SKIP); + } + + if (fmvj18x_debug > 5 && i > 0) + printk(KERN_DEBUG "%s: Exint Rx packet with mode %02x after" + " %d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); + } +*/ + + return; +} /* fjn_rx */ + +/*====================================================================*/ + +static int fjn_config(struct net_device *dev, struct ifmap *map){ + return 0; +} /* fjn_config */ + +static int fjn_open(struct net_device *dev) +{ + struct local_info_t *lp = (struct local_info_t *)dev->priv; + dev_link_t *link; + + if (fmvj18x_debug > 4) + printk(KERN_DEBUG "fjn_open('%s').\n", dev->name); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (!DEV_OK(link)) + return -ENODEV; + + link->open++; + + fjn_reset(dev); + + lp->tx_started = 0; + lp->tx_queue = 0; + lp->tx_queue_len = 0; + lp->open_time = jiffies; + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + + MOD_INC_USE_COUNT; + + return 0; +} /* fjn_open */ + +/*====================================================================*/ + +static int fjn_close(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + struct local_info_t *lp = (struct local_info_t *)dev->priv; + dev_link_t *link; + + if (fmvj18x_debug > 4) + printk(KERN_DEBUG "fjn_open('%s').\n", dev->name); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + if (fmvj18x_debug > 2) + printk(KERN_DEBUG "%s: shutting down ethercard.\n", dev->name); + + ((struct local_info_t *)dev->priv)->open_time = 0; + + dev->tbusy = 1; + dev->start = 0; + + /* Set configuration register 0 to disable Tx and Rx. */ + if( sram_config == 0 ) + outb(CONFIG0_RST ,ioaddr + CONFIG_0); + else + outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0); + + /* Update the statistics -- ToDo. */ + + /* Power-down the chip. Green, green, green! */ + outb(CHIP_OFF ,ioaddr + CONFIG_1); + + /* Set the ethernet adaptor disable IRQ */ + if( lp->cardtype != TDK ) + outb(INTR_OFF, ioaddr + LAN_CTRL); + + link->open--; + dev->start = 0; + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + MOD_DEC_USE_COUNT; + + return 0; +} /* fjn_close */ + +/*====================================================================*/ + +static struct net_device_stats *fjn_get_stats(struct net_device *dev) +{ + local_info_t *lp = (local_info_t *)dev->priv; + return &lp->stats; +} /* fjn_get_stats */ + +/*====================================================================*/ + +/* + Set the multicast/promiscuous mode for this adaptor. +*/ + +/* The little-endian AUTODIN II ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + struct local_info_t *lp = (struct local_info_t *)dev->priv; + unsigned char mc_filter[8]; /* Multicast hash filter */ + long flags; + int i; + + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + memset(mc_filter, 0xff, sizeof(mc_filter)); + outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ + } else if (dev->mc_count > MC_FILTERBREAK + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + outb(2, ioaddr + RX_MODE); /* Use normal mode. */ + } else if (dev->mc_count == 0) { + memset(mc_filter, 0x00, sizeof(mc_filter)); + outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */ + } else { + struct dev_mc_list *mclist; + int i; + + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, + mc_filter); + } + + save_flags(flags); + cli(); + if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) { + int saved_bank = inb(ioaddr + CONFIG_1); + /* Switch to bank 1 and set the multicast table. */ + outb(0xe4, ioaddr + CONFIG_1); + for (i = 0; i < 8; i++) + outb(mc_filter[i], ioaddr + 8 + i); + memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter)); + outb(saved_bank, ioaddr + CONFIG_1); + } + restore_flags(flags); +} diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/i82593.h linux/drivers/net/pcmcia/i82593.h --- v2.3.22/linux/drivers/net/pcmcia/i82593.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/i82593.h Wed Oct 20 21:33:12 1999 @@ -0,0 +1,224 @@ +/* + * Definitions for Intel 82593 CSMA/CD Core LAN Controller + * The definitions are taken from the 1992 users manual with Intel + * order number 297125-001. + * + * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp + * + * Copyright 1994, Anders Klemets + * + * This software may be freely distributed for noncommercial purposes + * as long as this notice is retained. + * + * HISTORY + * i82593.h,v + * Revision 1.1 1996/07/17 15:23:12 root + * Initial revision + * + * Revision 1.3 1995/04/05 15:13:58 adj + * Initial alpha release + * + * Revision 1.2 1994/06/16 23:57:31 klemets + * Mirrored all the fields in the configuration block. + * + * Revision 1.1 1994/06/02 20:25:34 klemets + * Initial revision + * + * + */ +#ifndef _I82593_H +#define _I82593_H + +/* Intel 82593 CSMA/CD Core LAN Controller */ + +/* Port 0 Command Register definitions */ + +/* Execution operations */ +#define OP0_NOP 0 /* CHNL = 0 */ +#define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ +#define OP0_IA_SETUP 1 +#define OP0_CONFIGURE 2 +#define OP0_MC_SETUP 3 +#define OP0_TRANSMIT 4 +#define OP0_TDR 5 +#define OP0_DUMP 6 +#define OP0_DIAGNOSE 7 +#define OP0_TRANSMIT_NO_CRC 9 +#define OP0_RETRANSMIT 12 +#define OP0_ABORT 13 +/* Reception operations */ +#define OP0_RCV_ENABLE 8 +#define OP0_RCV_DISABLE 10 +#define OP0_STOP_RCV 11 +/* Status pointer control operations */ +#define OP0_FIX_PTR 15 /* CHNL = 1 */ +#define OP0_RLS_PTR 15 /* CHNL = 0 */ +#define OP0_RESET 14 + +#define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ +#define CR0_STATUS_0 0x00 +#define CR0_STATUS_1 0x20 +#define CR0_STATUS_2 0x40 +#define CR0_STATUS_3 0x60 +#define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ + +/* Port 0 Status Register definitions */ + +#define SR0_NO_RESULT 0 /* dummy */ +#define SR0_EVENT_MASK 0x0f +#define SR0_IA_SETUP_DONE 1 +#define SR0_CONFIGURE_DONE 2 +#define SR0_MC_SETUP_DONE 3 +#define SR0_TRANSMIT_DONE 4 +#define SR0_TDR_DONE 5 +#define SR0_DUMP_DONE 6 +#define SR0_DIAGNOSE_PASSED 7 +#define SR0_TRANSMIT_NO_CRC_DONE 9 +#define SR0_RETRANSMIT_DONE 12 +#define SR0_EXECUTION_ABORTED 13 +#define SR0_END_OF_FRAME 8 +#define SR0_RECEPTION_ABORTED 10 +#define SR0_DIAGNOSE_FAILED 15 +#define SR0_STOP_REG_HIT 11 + +#define SR0_CHNL (1 << 4) +#define SR0_EXECUTION (1 << 5) +#define SR0_RECEPTION (1 << 6) +#define SR0_INTERRUPT (1 << 7) +#define SR0_BOTH_RX_TX (SR0_EXECUTION | SR0_RECEPTION) + +#define SR3_EXEC_STATE_MASK 0x03 +#define SR3_EXEC_IDLE 0 +#define SR3_TX_ABORT_IN_PROGRESS 1 +#define SR3_EXEC_ACTIVE 2 +#define SR3_ABORT_IN_PROGRESS 3 +#define SR3_EXEC_CHNL (1 << 2) +#define SR3_STP_ON_NO_RSRC (1 << 3) +#define SR3_RCVING_NO_RSRC (1 << 4) +#define SR3_RCV_STATE_MASK 0x60 +#define SR3_RCV_IDLE 0x00 +#define SR3_RCV_READY 0x20 +#define SR3_RCV_ACTIVE 0x40 +#define SR3_RCV_STOP_IN_PROG 0x60 +#define SR3_RCV_CHNL (1 << 7) + +/* Port 1 Command Register definitions */ + +#define OP1_NOP 0 +#define OP1_SWIT_TO_PORT_0 1 +#define OP1_INT_DISABLE 2 +#define OP1_INT_ENABLE 3 +#define OP1_SET_TS 5 +#define OP1_RST_TS 7 +#define OP1_POWER_DOWN 8 +#define OP1_RESET_RING_MNGMT 11 +#define OP1_RESET 14 +#define OP1_SEL_RST 15 + +#define CR1_STATUS_4 0x00 +#define CR1_STATUS_5 0x20 +#define CR1_STATUS_6 0x40 +#define CR1_STOP_REG_UPDATE (1 << 7) + +/* Receive frame status bits */ + +#define RX_RCLD (1 << 0) +#define RX_IA_MATCH (1 << 1) +#define RX_NO_AD_MATCH (1 << 2) +#define RX_NO_SFD (1 << 3) +#define RX_SRT_FRM (1 << 7) +#define RX_OVRRUN (1 << 8) +#define RX_ALG_ERR (1 << 10) +#define RX_CRC_ERR (1 << 11) +#define RX_LEN_ERR (1 << 12) +#define RX_RCV_OK (1 << 13) +#define RX_TYP_LEN (1 << 15) + +/* Transmit status bits */ + +#define TX_NCOL_MASK 0x0f +#define TX_FRTL (1 << 4) +#define TX_MAX_COL (1 << 5) +#define TX_HRT_BEAT (1 << 6) +#define TX_DEFER (1 << 7) +#define TX_UND_RUN (1 << 8) +#define TX_LOST_CTS (1 << 9) +#define TX_LOST_CRS (1 << 10) +#define TX_LTCOL (1 << 11) +#define TX_OK (1 << 13) +#define TX_COLL (1 << 15) + +struct i82593_conf_block { + u_char fifo_limit : 4, + forgnesi : 1, + fifo_32 : 1, + d6mod : 1, + throttle_enb : 1; + u_char throttle : 6, + cntrxint : 1, + contin : 1; + u_char addr_len : 3, + acloc : 1, + preamb_len : 2, + loopback : 2; + u_char lin_prio : 3, + tbofstop : 1, + exp_prio : 3, + bof_met : 1; + u_char : 4, + ifrm_spc : 4; + u_char : 5, + slottim_low : 3; + u_char slottim_hi : 3, + : 1, + max_retr : 4; + u_char prmisc : 1, + bc_dis : 1, + : 1, + crs_1 : 1, + nocrc_ins : 1, + crc_1632 : 1, + : 1, + crs_cdt : 1; + u_char cs_filter : 3, + crs_src : 1, + cd_filter : 3, + : 1; + u_char : 2, + min_fr_len : 6; + u_char lng_typ : 1, + lng_fld : 1, + rxcrc_xf : 1, + artx : 1, + sarec : 1, + tx_jabber : 1, /* why is this called max_len in the manual? */ + hash_1 : 1, + lbpkpol : 1; + u_char : 6, + fdx : 1, + : 1; + u_char dummy_6 : 6, /* supposed to be ones */ + mult_ia : 1, + dis_bof : 1; + u_char dummy_1 : 1, /* supposed to be one */ + tx_ifs_retrig : 2, + mc_all : 1, + rcv_mon : 2, + frag_acpt : 1, + tstrttrs : 1; + u_char fretx : 1, + runt_eop : 1, + hw_sw_pin : 1, + big_endn : 1, + syncrqs : 1, + sttlen : 1, + tx_eop : 1, + rx_eop : 1; + u_char rbuf_size : 5, + rcvstop : 1, + : 2; +}; + +#define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ + +#endif _I82593_H diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c --- v2.3.22/linux/drivers/net/pcmcia/netwave_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/netwave_cs.c Wed Oct 20 21:33:12 1999 @@ -0,0 +1,1709 @@ +/********************************************************************* + * + * Filename: netwave_cs.c + * Version: 0.4.1 + * Description: Netwave AirSurfer Wireless LAN PC Card driver + * Status: Experimental. + * Authors: John Markus Bjørndalen + * Dag Brattli + * David Hinds + * Created at: A long time ago! + * Modified at: Mon Nov 10 11:54:37 1997 + * Modified by: Dag Brattli + * + * Copyright (c) 1997 University of Tromsø, Norway + * + * Revision History: + * + * 08-Nov-97 15:14:47 John Markus Bjørndalen + * - Fixed some bugs in netwave_rx and cleaned it up a bit. + * (One of the bugs would have destroyed packets when receiving + * multiple packets per interrupt). + * - Cleaned up parts of newave_hw_xmit. + * - A few general cleanups. + * 24-Oct-97 13:17:36 Dag Brattli + * - Fixed netwave_rx receive function (got updated docs) + * Others: + * - Changed name from xircnw to netwave, take a look at + * http://www.netwave-wireless.com + * - Some reorganizing of the code + * - Removed possible race condition between interrupt handler and transmit + * function + * - Started to add wireless extensions, but still needs some coding + * - Added watchdog for better handling of transmission timeouts + * (hopefully this works better) + ********************************************************************/ + +/* To have statistics (just packets sent) define this */ +#undef NETWAVE_STATS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_NET_RADIO +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define NETWAVE_REGOFF 0x8000 +/* The Netwave IO registers, offsets to iobase */ +#define NETWAVE_REG_COR 0x0 +#define NETWAVE_REG_CCSR 0x2 +#define NETWAVE_REG_ASR 0x4 +#define NETWAVE_REG_IMR 0xa +#define NETWAVE_REG_PMR 0xc +#define NETWAVE_REG_IOLOW 0x6 +#define NETWAVE_REG_IOHI 0x7 +#define NETWAVE_REG_IOCONTROL 0x8 +#define NETWAVE_REG_DATA 0xf +/* The Netwave Extended IO registers, offsets to RamBase */ +#define NETWAVE_EREG_ASCC 0x114 +#define NETWAVE_EREG_RSER 0x120 +#define NETWAVE_EREG_RSERW 0x124 +#define NETWAVE_EREG_TSER 0x130 +#define NETWAVE_EREG_TSERW 0x134 +#define NETWAVE_EREG_CB 0x100 +#define NETWAVE_EREG_SPCQ 0x154 +#define NETWAVE_EREG_SPU 0x155 +#define NETWAVE_EREG_LIF 0x14e +#define NETWAVE_EREG_ISPLQ 0x156 +#define NETWAVE_EREG_HHC 0x158 +#define NETWAVE_EREG_NI 0x16e +#define NETWAVE_EREG_MHS 0x16b +#define NETWAVE_EREG_TDP 0x140 +#define NETWAVE_EREG_RDP 0x150 +#define NETWAVE_EREG_PA 0x160 +#define NETWAVE_EREG_EC 0x180 +#define NETWAVE_EREG_CRBP 0x17a +#define NETWAVE_EREG_ARW 0x166 + +/* + * Commands used in the extended command buffer + * NETWAVE_EREG_CB (0x100-0x10F) + */ +#define NETWAVE_CMD_NOP 0x00 +#define NETWAVE_CMD_SRC 0x01 +#define NETWAVE_CMD_STC 0x02 +#define NETWAVE_CMD_AMA 0x03 +#define NETWAVE_CMD_DMA 0x04 +#define NETWAVE_CMD_SAMA 0x05 +#define NETWAVE_CMD_ER 0x06 +#define NETWAVE_CMD_DR 0x07 +#define NETWAVE_CMD_TL 0x08 +#define NETWAVE_CMD_SRP 0x09 +#define NETWAVE_CMD_SSK 0x0a +#define NETWAVE_CMD_SMD 0x0b +#define NETWAVE_CMD_SAPD 0x0c +#define NETWAVE_CMD_SSS 0x11 +/* End of Command marker */ +#define NETWAVE_CMD_EOC 0x00 + +/* ASR register bits */ +#define NETWAVE_ASR_RXRDY 0x80 +#define NETWAVE_ASR_TXBA 0x01 + +#define TX_TIMEOUT 20 +#define WATCHDOG_JIFFIES 32 + +static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */ +static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */ + +static const unsigned int corConfIENA = 0x01; /* Interrupt enable */ +static const unsigned int corConfLVLREQ = 0x40; /* Keep high */ + +static const unsigned int rxConfRxEna = 0x80; /* Receive Enable */ +static const unsigned int rxConfMAC = 0x20; /* MAC host receive mode*/ +static const unsigned int rxConfPro = 0x10; /* Promiscuous */ +static const unsigned int rxConfAMP = 0x08; /* Accept Multicast Packets */ +static const unsigned int rxConfBcast = 0x04; /* Accept Broadcast Packets */ + +static const unsigned int txConfTxEna = 0x80; /* Transmit Enable */ +static const unsigned int txConfMAC = 0x20; /* Host sends MAC mode */ +static const unsigned int txConfEUD = 0x10; /* Enable Uni-Data packets */ +static const unsigned int txConfKey = 0x02; /* Scramble data packets */ +static const unsigned int txConfLoop = 0x01; /* Loopback mode */ + +/*static int netwave_debug = 0;*/ + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n"; +#else +#define DEBUG(n, args...) +#endif + +static dev_info_t dev_info = "netwave_cs"; + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Choose the domain, default is 0x100 */ +static u_int domain = 0x100; + +/* Scramble key, range from 0x0 to 0xffff. + * 0x0 is no scrambling. + */ +static u_int scramble_key = 0x0; + +/* Shared memory speed, in ns. The documentation states that + * the card should not be read faster than every 400ns. + * This timing should be provided by the HBA. If it becomes a + * problem, try setting mem_speed to 400. + */ +static int mem_speed = 0; + +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +MODULE_PARM(domain, "i"); +MODULE_PARM(scramble_key, "i"); +MODULE_PARM(mem_speed, "i"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +/* PCMCIA (Card Services) related functions */ +static void netwave_release(u_long arg); /* Card removal */ +static int netwave_event(event_t event, int priority, + event_callback_args_t *args); +static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card + insertion */ +static dev_link_t *netwave_attach(void); /* Create instance */ +static void netwave_detach(dev_link_t *); /* Destroy instance */ +static void netwave_flush_stale_links(void); /* Destroy all staled instances */ + +/* Hardware configuration */ +static void netwave_doreset(ioaddr_t iobase, u_char* ramBase); +static void netwave_reset(struct net_device *dev); + +/* Misc device stuff */ +static int netwave_open(struct net_device *dev); /* Open the device */ +static int netwave_close(struct net_device *dev); /* Close the device */ +static int netwave_config(struct net_device *dev, struct ifmap *map); + +/* Packet transmission and Packet reception */ +static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev); +static int netwave_rx( struct net_device *dev); + +/* Interrupt routines */ +static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void netwave_watchdog(u_long); /* Transmission watchdog */ + +/* Statistics */ +static void update_stats(struct net_device *dev); +static struct enet_statistics *netwave_get_stats(struct net_device *dev); + +/* Wireless extensions */ +#ifdef WIRELESS_EXT +static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); +#endif +static int netwave_ioctl(struct net_device *, struct ifreq *, int); + +static void set_multicast_list(struct net_device *dev); + +/* + 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. +*/ + +#define SIOCGIPSNAP SIOCDEVPRIVATE /* Site Survey Snapshot */ +/*#define SIOCGIPQTHR SIOCDEVPRIVATE + 1*/ + +#define MAX_ESA 10 + +typedef struct net_addr { + u_char addr48[6]; +} net_addr; + +struct site_survey { + u_short length; + u_char struct_revision; + u_char roaming_state; + + u_char sp_existsFlag; + u_char sp_link_quality; + u_char sp_max_link_quality; + u_char linkQualityGoodFairBoundary; + u_char linkQualityFairPoorBoundary; + u_char sp_utilization; + u_char sp_goodness; + u_char sp_hotheadcount; + u_char roaming_condition; + + net_addr sp; + u_char numAPs; + net_addr nearByAccessPoints[MAX_ESA]; +}; + +typedef struct netwave_private { + dev_node_t node; + u_char *ramBase; + int timeoutCounter; + int lastExec; + struct timer_list watchdog; /* To avoid blocking state */ + struct site_survey nss; + struct enet_statistics stats; +#ifdef WIRELESS_EXT + struct iw_statistics iw_stats; /* Wireless stats */ +#endif +} netwave_private; + +#ifdef NETWAVE_STATS +static struct enet_statistics *netwave_get_stats(struct net_device *dev); +#endif + +/* + * The Netwave card is little-endian, so won't work for big endian + * systems. + */ +static inline unsigned short get_uint16(u_char* staddr) +{ + return readw(staddr); /* Return only 16 bits */ +} + +static inline short get_int16(u_char* staddr) +{ + return readw(staddr); +} + +/**************************************************************************/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/* + * Wait until the WOC (Write Operation Complete) bit in the + * ASR (Adapter Status Register) is asserted. + * This should have aborted if it takes too long time. + */ +static inline void wait_WOC(unsigned int iobase) +{ + /* Spin lock */ + while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; +} + +#ifdef WIRELESS_EXT +static void netwave_snapshot(netwave_private *priv, u_char *ramBase, + ioaddr_t iobase) { + u_short resultBuffer; + + /* if time since last snapshot is > 1 sec. (100 jiffies?) then take + * new snapshot, else return cached data. This is the recommended rate. + */ + if ( jiffies - priv->lastExec > 100) { + /* Take site survey snapshot */ + /*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies - + priv->lastExec); */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + wait_WOC(iobase); + + /* Get result and copy to cach */ + resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); + copy_from_pc( &priv->nss, ramBase+resultBuffer, + sizeof(struct site_survey)); + } +} +#endif + +#ifdef WIRELESS_EXT +/* + * Function netwave_get_wireless_stats (dev) + * + * Wireless extensions statistics + * + */ +static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) +{ + unsigned long flags; + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + struct iw_statistics* wstats; + + wstats = &priv->iw_stats; + + save_flags(flags); + cli(); + + netwave_snapshot( priv, ramBase, iobase); + + wstats->status = priv->nss.roaming_state; + wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); + wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ); + wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f; + wstats->discard.nwid = 0L; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + restore_flags(flags); + + return &priv->iw_stats; +} +#endif + +/* + * Function netwave_init (dev) + * + * We never need to do anything when a device is "initialized" + * by the net software, because we only register already-found cards. + */ +int netwave_init(struct net_device *dev) +{ + /* We do all the initialization of this in netwave_attach instead */ + return 0; +} + +/* + * Function netwave_attach (void) + * + * 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 *netwave_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + netwave_private *priv; + int i, ret; + + DEBUG(0, "netwave_attach()\n"); + + /* Perform some cleanup */ + netwave_flush_stale_links(); + + /* 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 = &netwave_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_16; + /* link->io.NumPorts2 = 16; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */ + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = &netwave_interrupt; + + /* 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 */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + + dev->priv = kmalloc(sizeof(netwave_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(netwave_private)); + + /* Set the watchdog timer */ + priv = (netwave_private *) dev->priv; + priv->watchdog.function = &netwave_watchdog; + priv->watchdog.data = (unsigned long) dev; + + /* Netwave specific entries in the device structure */ + dev->hard_start_xmit = &netwave_start_xmit; + dev->set_config = &netwave_config; + dev->get_stats = &netwave_get_stats; + dev->set_multicast_list = &set_multicast_list; + /* wireless extensions */ +#ifdef WIRELESS_EXT + dev->get_wireless_stats = &netwave_get_wireless_stats; +#endif + dev->do_ioctl = &netwave_ioctl; + + ether_setup(dev); + dev->name = ((struct netwave_private *)dev->priv)->node.dev_name; + dev->init = &netwave_init; + dev->open = &netwave_open; + dev->stop = &netwave_close; + dev->tbusy = 1; + link->priv = link->irq.Instance = dev; + + /* 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 = &netwave_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); + netwave_detach(link); + return NULL; + } + + return link; +} /* netwave_attach */ + +/* + * Function netwave_detach (link) + * + * 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 netwave_detach(dev_link_t *link) +{ + dev_link_t **linkp; + long flags; + + DEBUG(0, "netwave_detach(0x%p)\n", link); + + save_flags(flags); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + cli(); + restore_flags(flags); + + /* + 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) { + netwave_release((u_long) link); + if (link->state & DEV_STALE_CONFIG) { + DEBUG(1, "netwave_cs: detach postponed, '%s' still " + "locked\n", link->dev->dev_name); + + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + { + DEBUG(1, "netwave_cs: detach fail, '%s' not in list\n", + link->dev->dev_name); + return; + } + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + struct net_device *dev = link->priv; + if (link->dev != NULL) + unregister_netdev(dev); + link->dev = NULL; + if (dev->priv) + kfree(dev->priv); + kfree(link->priv); + } + kfree(link); + +} /* netwave_detach */ + +/* + * Function netwave_flush_stale_links (void) + * + * This deletes all driver "instances" that need to be deleted. + * Sometimes, netwave_detach can't be performed following a call from + * cardmgr (device still open) and the device is put in a STALE_LINK + * state. + * This function is in charge of making the cleanup... + */ +static void netwave_flush_stale_links(void) +{ + dev_link_t * link; /* Current node in linked list */ + dev_link_t * next; /* Next node in linked list */ + + DEBUG(1, "netwave_flush_stale_links(0x%p)\n", dev_list); + + /* Go through the list */ + for (link = dev_list; link; link = next) { + next = link->next; + /* Check if in need of being removed */ + if(link->state & DEV_STALE_LINK) + netwave_detach(link); + } +} /* netwave_flush_stale_links */ + +/* + * Function netwave_ioctl (dev, rq, cmd) + * + * Perform ioctl : config & info stuff + * This is the stuff that are treated the wireless extensions (iwconfig) + * + */ +static int netwave_ioctl(struct net_device *dev, /* ioctl device */ + struct ifreq *rq, /* Data passed */ + int cmd) /* Ioctl number */ +{ + unsigned long flags; + int ret = 0; +#ifdef WIRELESS_EXT + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + struct iwreq *wrq = (struct iwreq *) rq; +#endif + + DEBUG( 0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + /* Look what is the request */ + switch(cmd) { + /* --------------- WIRELESS EXTENSIONS --------------- */ +#ifdef WIRELESS_EXT + case SIOCGIWNAME: + /* Get name */ + strcpy(wrq->u.name, "Netwave"); + break; + case SIOCSIWNWID: + /* Set domain */ +#if WIRELESS_EXT > 8 + if(!wrq->u.nwid.disabled) { + domain = wrq->u.nwid.value; +#else /* WIRELESS_EXT > 8 */ + if(wrq->u.nwid.on) { + domain = wrq->u.nwid.nwid; +#endif /* WIRELESS_EXT > 8 */ + printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", + (domain >> 8) & 0x01, domain & 0xff); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); + writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + } break; + case SIOCGIWNWID: + /* Read domain*/ +#if WIRELESS_EXT > 8 + wrq->u.nwid.value = domain; + wrq->u.nwid.disabled = 0; + wrq->u.nwid.fixed = 1; +#else /* WIRELESS_EXT > 8 */ + wrq->u.nwid.nwid = domain; + wrq->u.nwid.on = 1; +#endif /* WIRELESS_EXT > 8 */ + break; +#if WIRELESS_EXT > 8 /* Note : The API did change... */ + case SIOCGIWENCODE: + /* Get scramble key */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + char key[2]; + key[1] = scramble_key & 0xff; + key[0] = (scramble_key>>8) & 0xff; + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + wrq->u.encoding.length = 2; + if(copy_to_user(wrq->u.encoding.pointer, key, 2)) + ret = -EFAULT; + } + break; + case SIOCSIWENCODE: + /* Set scramble key */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + char key[2]; + if(copy_from_user(key, wrq->u.encoding.pointer, 2)) + { + ret = -EFAULT; + break; + } + scramble_key = (key[0] << 8) | key[1]; + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); + writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + } + break; + case SIOCGIWMODE: + /* Mode of operation */ + if(domain & 0x100) + wrq->u.mode = IW_MODE_INFRA; + else + wrq->u.mode = IW_MODE_ADHOC; + break; +#else /* WIRELESS_EXT > 8 */ + case SIOCGIWENCODE: + /* Get scramble key */ + wrq->u.encoding.code = scramble_key; + wrq->u.encoding.method = 1; + break; + case SIOCSIWENCODE: + /* Set scramble key */ + scramble_key = wrq->u.encoding.code; + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); + writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + break; +#endif /* WIRELESS_EXT > 8 */ + case SIOCGIWRANGE: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) { + struct iw_range range; + + /* Set the length (useless : its constant...) */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set information in the range struct */ + range.throughput = 450 * 1000; /* don't argue on this ! */ + range.min_nwid = 0x0000; + range.max_nwid = 0x01FF; + + range.num_channels = range.num_frequency = 0; + + range.sensitivity = 0x3F; + range.max_qual.qual = 255; + range.max_qual.level = 255; + range.max_qual.noise = 0; + +#if WIRELESS_EXT > 7 + range.num_bitrates = 1; + range.bitrate[0] = 1000000; /* 1 Mb/s */ +#endif /* WIRELESS_EXT > 7 */ + +#if WIRELESS_EXT > 8 + range.encoding_size[0] = 2; /* 16 bits scrambling */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ +#endif /* WIRELESS_EXT > 8 */ + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; + } + break; + case SIOCGIWPRIV: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) { + struct iw_priv_args priv[] = + { /* cmd, set_args, get_args, name */ + { SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, + sizeof(struct site_survey), + "getsitesurvey" }, + }; + + /* Set the number of ioctl available */ + wrq->u.data.length = 1; + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, + sizeof(priv))) + ret = -EFAULT; + } + break; + case SIOCGIPSNAP: + if(wrq->u.data.pointer != (caddr_t) 0) { + /* Take snapshot of environment */ + netwave_snapshot( priv, ramBase, iobase); + wrq->u.data.length = priv->nss.length; + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, + (u_char *) &priv->nss, + sizeof( struct site_survey))) + { + printk(KERN_DEBUG "Bad buffer!\n"); + break; + } + + priv->lastExec = jiffies; + } + break; +#endif + default: + ret = -EOPNOTSUPP; + } + + /* ReEnable interrupts & restore flags */ + restore_flags(flags); + + return ret; +} + +/* + * Function netwave_pcmcia_config (link) + * + * netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION + * event is received, to configure the PCMCIA socket, and to make the + * device available to the system. + * + */ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void netwave_pcmcia_config(dev_link_t *link) { + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + struct net_device *dev; + int i, j, last_ret, last_fn; + u_char buf[64]; + win_req_t req; + memreq_t mem; + u_char *ramBase = NULL; + /* modwin_t mod; + short iobase, *phys_addr; + */ + handle = link->handle; + dev = link->priv; + + DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* + * Try allocating IO ports. This tries a few fixed addresses. + * If you want, you can also read the card's config table to + * pick addresses -- see the serial driver for an example. + */ + for (j = 0x0; j < 0x400; j += 0x20) { + link->io.BasePort1 = j ^ 0x300; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + /* + * Now allocate an interrupt line. Note that this does not + * actually assign a handler to the interrupt. + */ + CS_CHECK(RequestIRQ, handle, &link->irq); + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + CS_CHECK(RequestConfiguration, handle, &link->conf); + + /* + * Allocate a 32K memory window. Note that the dev_link_t + * structure provides space for one window handle -- if your + * device needs several windows, you'll need to keep track of + * the handles in your private data structure, link->priv. + */ + DEBUG(1, "Setting mem speed of %d\n", mem_speed); + + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + req.Base = 0; req.Size = 0x8000; + req.AccessSpeed = mem_speed; + link->win = (window_handle_t)link->handle; + CS_CHECK(RequestWindow, &link->win, &req); + mem.CardOffset = 0x20000; mem.Page = 0; + CS_CHECK(MapMemPage, link->win, &mem); + + /* Store base address of the common window frame */ + ramBase = ioremap(req.Base, 0x8000); + ((netwave_private*)dev->priv)->ramBase = ramBase; + + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + dev->tbusy = 0; + if (register_netdev(dev) != 0) { + printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); + goto failed; + } + + link->state &= ~DEV_CONFIG_PENDING; + + link->dev = &((netwave_private *)dev->priv)->node; + + /* Reset card before reading physical address */ + netwave_doreset(dev->base_addr, ramBase); + + /* Read the ethernet address and fill in the Netwave registers. */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); + + printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id " + "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq, + (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI), + (int) readb(ramBase+NETWAVE_EREG_NI+1)); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + + /* get revision words */ + printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", + get_uint16(ramBase + NETWAVE_EREG_ARW), + get_uint16(ramBase + NETWAVE_EREG_ARW+2)); + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + netwave_release((u_long)link); + return; +} /* netwave_pcmcia_config */ + +/* + * Function netwave_release (arg) + * + * After a card is removed, netwave_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 netwave_release(u_long arg) { + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = link->priv; + + DEBUG(0, "netwave_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed. + */ + if (link->open) { + printk(KERN_DEBUG "netwave_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Don't bother checking to see if these succeed or not */ + if (link->win) { + iounmap(((netwave_private *)dev->priv)->ramBase); + CardServices(ReleaseWindow, link->win); + } + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG); + +} /* netwave_release */ + +/* + * Function netwave_event (event, priority, args) + * + * 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 netwave_event(event_t event, int priority, + event_callback_args_t *args) { + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + + DEBUG(1, "netwave_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_REGISTRATION_COMPLETE: + DEBUG(0, "netwave_cs: registration complete\n"); + break; + + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 1; dev->start = 0; + /* ((netwave_private *)link->priv)->block = 1; */ + link->release.expires = jiffies + 5; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + netwave_pcmcia_config( link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 1; dev->start = 0; + } + 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); + if (link->open) { + netwave_reset(dev); + dev->tbusy = 0; dev->start = 1; + } + } + break; + } + return 0; +} /* netwave_event */ + +/* + * Function netwave_doreset (ioBase, ramBase) + * + * Proper hardware reset of the card. + */ +static void netwave_doreset(ioaddr_t ioBase, u_char* ramBase) { + /* Reset card */ + wait_WOC(ioBase); + outb(0x80, ioBase + NETWAVE_REG_PMR); + writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */ + outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */ +} + +/* + * Function netwave_reset (dev) + * + * Reset and restore all of the netwave registers + */ +static void netwave_reset(struct net_device *dev) { + /* u_char state; */ + netwave_private *priv = (netwave_private*) dev->priv; + u_char *ramBase = priv->ramBase; + ioaddr_t iobase = dev->base_addr; + + DEBUG(0, "netwave_reset: Done with hardware reset\n"); + + priv->timeoutCounter = 0; + + /* If watchdog was activated, kill it ! */ + del_timer(&priv->watchdog); + + /* Reset card */ + netwave_doreset(iobase, ramBase); + printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n"); + + /* Write a NOP to check the card */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + + /* Set receive conf */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); + writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); + + /* Set transmit conf */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0); + writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); + + /* Now set the MU Domain */ + printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); + writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* Set scramble key */ + printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); + writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* Enable interrupts, bit 4 high to keep unused + * source from interrupting us, bit 2 high to + * set interrupt enable, 567 to enable TxDN, + * RxErr and RxRdy + */ + wait_WOC(iobase); + outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR); + + /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36 + * waitWOC + * skriv 80 til d000:3688 + * sjekk om det ble 80 + */ + + /* Enable Receiver */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + + /* Set the IENA bit in COR */ + wait_WOC(iobase); + outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR); +} + +/* + * Function netwave_config (dev, map) + * + * Configure device, this work is done by netwave_pcmcia_config when a + * card is inserted + */ +static int netwave_config(struct net_device *dev, struct ifmap *map) { + return 0; +} + +/* + * Function netwave_hw_xmit (data, len, dev) + */ +static int netwave_hw_xmit(unsigned char* data, int len, + struct net_device* dev) { + unsigned long flags; + unsigned int TxFreeList, + curBuff, + MaxData, + DataOffset; + int tmpcount; + + netwave_private *priv = (netwave_private *) dev->priv; + u_char* ramBase = priv->ramBase; + ioaddr_t iobase = dev->base_addr; + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + /* Check if there are transmit buffers available */ + wait_WOC(iobase); + if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) { + /* No buffers available */ + printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n", + dev->name); + return 1; + } + + priv->stats.tx_bytes += len; + + DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n", + readb(ramBase + NETWAVE_EREG_SPCQ), + readb(ramBase + NETWAVE_EREG_SPU), + readb(ramBase + NETWAVE_EREG_LIF), + readb(ramBase + NETWAVE_EREG_ISPLQ)); + + /* Now try to insert it into the adapters free memory */ + wait_WOC(iobase); + TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP); + MaxData = get_uint16(ramBase + NETWAVE_EREG_TDP+2); + DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4); + + DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n", + TxFreeList, MaxData, DataOffset); + + /* Copy packet to the adapter fragment buffers */ + curBuff = TxFreeList; + tmpcount = 0; + while (tmpcount < len) { + int tmplen = len - tmpcount; + copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, + (tmplen < MaxData) ? tmplen : MaxData); + tmpcount += MaxData; + + /* Advance to next buffer */ + curBuff = get_uint16(ramBase + curBuff); + } + + /* Now issue transmit list */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0); + writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* If watchdog not already active, activate it... */ + if(priv->watchdog.prev == (struct timer_list *) NULL) { + + /* set timer to expire in WATCHDOG_JIFFIES */ + priv->watchdog.expires = jiffies + WATCHDOG_JIFFIES; + add_timer(&priv->watchdog); + } + restore_flags( flags); + return 0; +} + +static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { + /* This flag indicate that the hardware can't perform a transmission. + * Theoritically, NET3 check it before sending a packet to the driver, + * but in fact it never do that and pool continuously. + * As the watchdog will abort too long transmissions, we are quite safe... + */ + + if (dev->tbusy) { + /* Handled by watchdog */ + return 1; + + /* If we get here, some higher level has decided we are broken. + There should really be a 'kick me' function call instead. + */ + /*int tickssofar = jiffies - dev->trans_start;*/ + /* printk("xmit called with busy. tickssofar %d\n", tickssofar); */ + /*if (tickssofar < TX_TIMEOUT) + return 1; + */ + /* Should also detect if the kernel tries to xmit + * on a stopped card. + */ + + /*if (netwave_debug > 0) + printk(KERN_DEBUG "%s timed out.\n", dev->name); + netwave_reset(dev); + dev->trans_start = jiffies; + dev->tbusy = 0;*/ + } + + /* Sending a NULL skb means some higher layer thinks we've missed an + * tx-done interrupt. Caution: dev_tint() handles the cli()/sti() + * itself. + */ + + /* Block a timer-based transmit from overlapping. This could + * better be done with atomic_swap(1, dev->tbusy, but set_bit() + * works as well + */ + if ( test_and_set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char* buf = skb->data; + + if (netwave_hw_xmit( buf, length, dev) == 1) { + /* Some error, let's make them call us another time? */ + dev->tbusy = 0; + } + dev->trans_start = jiffies; + } + dev_kfree_skb(skb); + + return 0; +} /* netwave_start_xmit */ + +/* + * Function netwave_interrupt (irq, dev_id, regs) + * + * This function is the interrupt handler for the Netwave card. This + * routine will be called whenever: + * 1. A packet is received. + * 2. A packet has successfully been transfered and the unit is + * ready to transmit another packet. + * 3. A command has completed execution. + */ +static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) { + ioaddr_t iobase; + u_char *ramBase; + struct net_device *dev = (struct net_device *)dev_id; + struct netwave_private *priv; + int i; + dev_link_t *link; + + if ((dev == NULL) | (!dev->start)) + return; + + priv = (netwave_private *)dev->priv; + + if (dev->interrupt) { + printk("%s: re-entering the interrupt handler.\n", dev->name); + return; + } + dev->interrupt = 1; + + /* Find the correct dev_link_t */ + for (link = dev_list; NULL != link; link = link->next) + if (dev == link->priv) break; + + iobase = dev->base_addr; + ramBase = priv->ramBase; + + /* Now find what caused the interrupt, check while interrupts ready */ + for (i = 0; i < 10; i++) { + u_char status; + + wait_WOC(iobase); + if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02)) + break; /* None of the interrupt sources asserted */ + + status = inb(iobase + NETWAVE_REG_ASR); + + if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { + DEBUG( 1, "netwave_interupt: Interrupt with status 0x%x " + "from removed or suspended card!\n", status); + break; + } + + /* RxRdy */ + if (status & 0x80) { + netwave_rx(dev); + /* wait_WOC(iobase); */ + /* RxRdy cannot be reset directly by the host */ + } + /* RxErr */ + if (status & 0x40) { + u_char rser; + + rser = readb(ramBase + NETWAVE_EREG_RSER); + + if (rser & 0x04) { + ++priv->stats.rx_dropped; + ++priv->stats.rx_crc_errors; + } + if (rser & 0x02) + ++priv->stats.rx_frame_errors; + + /* Clear the RxErr bit in RSER. RSER+4 is the + * write part. Also clear the RxCRC (0x04) and + * RxBig (0x02) bits if present */ + wait_WOC(iobase); + writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4); + + /* Write bit 6 high to ASCC to clear RxErr in ASR, + * WOC must be set first! + */ + wait_WOC(iobase); + writeb(0x40, ramBase + NETWAVE_EREG_ASCC); + + /* Remember to count up priv->stats on error packets */ + ++priv->stats.rx_errors; + } + /* TxDN */ + if (status & 0x20) { + int txStatus; + + txStatus = readb(ramBase + NETWAVE_EREG_TSER); + DEBUG(3, "Transmit done. TSER = %x id %x\n", + txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1)); + + if (txStatus & 0x20) { + /* Transmitting was okay, clear bits */ + wait_WOC(iobase); + writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4); + ++priv->stats.tx_packets; + } + + if (txStatus & 0xd0) { + if (txStatus & 0x80) { + ++priv->stats.collisions; /* Because of /proc/net/dev*/ + /* ++priv->stats.tx_aborted_errors; */ + /* printk("Collision. %ld\n", jiffies - dev->trans_start); */ + } + if (txStatus & 0x40) + ++priv->stats.tx_carrier_errors; + /* 0x80 TxGU Transmit giveup - nine times and no luck + * 0x40 TxNOAP No access point. Discarded packet. + * 0x10 TxErr Transmit error. Always set when + * TxGU and TxNOAP is set. (Those are the only ones + * to set TxErr). + */ + DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", + txStatus); + + /* Clear out TxGU, TxNOAP, TxErr and TxTrys */ + wait_WOC(iobase); + writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4); + ++priv->stats.tx_errors; + } + DEBUG(3, "New status is TSER %x ASR %x\n", + readb(ramBase + NETWAVE_EREG_TSER), + inb(iobase + NETWAVE_REG_ASR)); + + /* If watchdog was activated, kill it ! */ + del_timer(&priv->watchdog); + + dev->tbusy = 0; + mark_bh(NET_BH); + } + /* TxBA, this would trigger on all error packets received */ + /* if (status & 0x01) { + if (netwave_debug > 3) + printk(KERN_DEBUG "Transmit buffers available, %x\n", status); + } + */ + } + /* done.. */ + dev->interrupt = 0; + return; +} /* netwave_interrupt */ + +/* + * Function netwave_watchdog (a) + * + * Watchdog : when we start a transmission, we set a timer in the + * kernel. If the transmission complete, this timer is disabled. If + * it expire, we reset the card. + * + */ +static void netwave_watchdog(u_long a) { + struct net_device *dev; + ioaddr_t iobase; + + dev = (struct net_device *) a; + iobase = dev->base_addr; + + DEBUG( 1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name); + + netwave_reset(dev); + + /* We are not waiting anymore... */ + dev->tbusy = 0; + +} /* netwave_watchdog */ + +static struct enet_statistics *netwave_get_stats(struct net_device *dev) { + netwave_private *priv = (netwave_private*)dev->priv; + + update_stats(dev); + + DEBUG(2, "netwave: SPCQ %x SPU %x LIF %x ISPLQ %x MHS %x rxtx %x" + " %x tx %x %x %x %x\n", + readb(priv->ramBase + NETWAVE_EREG_SPCQ), + readb(priv->ramBase + NETWAVE_EREG_SPU), + readb(priv->ramBase + NETWAVE_EREG_LIF), + readb(priv->ramBase + NETWAVE_EREG_ISPLQ), + readb(priv->ramBase + NETWAVE_EREG_MHS), + readb(priv->ramBase + NETWAVE_EREG_EC + 0xe), + readb(priv->ramBase + NETWAVE_EREG_EC + 0xf), + readb(priv->ramBase + NETWAVE_EREG_EC + 0x18), + readb(priv->ramBase + NETWAVE_EREG_EC + 0x19), + readb(priv->ramBase + NETWAVE_EREG_EC + 0x1a), + readb(priv->ramBase + NETWAVE_EREG_EC + 0x1b)); + + return &priv->stats; +} + +static void update_stats(struct net_device *dev) { + unsigned long flags; + + save_flags(flags); + cli(); + +/* netwave_private *priv = (netwave_private*) dev->priv; + priv->stats.rx_packets = readb(priv->ramBase + 0x18e); + priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */ + + restore_flags(flags); +} + +static int netwave_rx(struct net_device *dev) { + netwave_private *priv = (netwave_private*)(dev->priv); + u_char *ramBase = priv->ramBase; + ioaddr_t iobase = dev->base_addr; + u_char rxStatus; + struct sk_buff *skb = NULL; + unsigned int curBuffer, + rcvList; + int rcvLen; + int tmpcount = 0; + int dataCount, dataOffset; + int i; + u_char *ptr; + + DEBUG(3, "xinw_rx: Receiving ... \n"); + + /* Receive max 10 packets for now. */ + for (i = 0; i < 10; i++) { + /* Any packets? */ + wait_WOC(iobase); + rxStatus = readb(ramBase + NETWAVE_EREG_RSER); + if ( !( rxStatus & 0x80)) /* No more packets */ + break; + + /* Check if multicast/broadcast or other */ + /* multicast = (rxStatus & 0x20); */ + + /* The receive list pointer and length of the packet */ + wait_WOC(iobase); + rcvLen = get_int16( ramBase + NETWAVE_EREG_RDP); + rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2); + + if (rcvLen < 0) { + printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", + rcvLen); + return 0; + } + + skb = dev_alloc_skb(rcvLen+5); + if (skb == NULL) { + DEBUG(1, "netwave_rx: Could not allocate an sk_buff of " + "length %d\n", rcvLen); + ++priv->stats.rx_dropped; + /* Tell the adapter to skip the packet */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + return 0; + } + + skb_reserve( skb, 2); /* Align IP on 16 byte */ + skb_put( skb, rcvLen); + skb->dev = dev; + + /* Copy packet fragments to the skb data area */ + ptr = (u_char*) skb->data; + curBuffer = rcvList; + tmpcount = 0; + while ( tmpcount < rcvLen) { + /* Get length and offset of current buffer */ + dataCount = get_uint16( ramBase+curBuffer+2); + dataOffset = get_uint16( ramBase+curBuffer+4); + + copy_from_pc( ptr + tmpcount, + ramBase+curBuffer+dataOffset, dataCount); + + tmpcount += dataCount; + + /* Point to next buffer */ + curBuffer = get_uint16(ramBase + curBuffer); + } + + skb->protocol = eth_type_trans(skb,dev); + /* Queue packet for network layer */ + netif_rx(skb); + + /* Got the packet, tell the adapter to skip it */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + DEBUG(3, "Packet reception ok\n"); + + priv->stats.rx_packets++; + + priv->stats.rx_bytes += skb->len; + } + return 0; +} + +static int netwave_open(struct net_device *dev) { + dev_link_t *link; + + DEBUG(1, "netwave_open: starting.\n"); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + + if (!DEV_OK(link)) + return -ENODEV; + + link->open++; + MOD_INC_USE_COUNT; + + dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + netwave_reset(dev); + + return 0; +} + +static int netwave_close(struct net_device *dev) { + dev_link_t *link; + netwave_private *priv = (netwave_private *) dev->priv; + + DEBUG(1, "netwave_close: finishing.\n"); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + /* If watchdog was activated, kill it ! */ + del_timer(&priv->watchdog); + + link->open--; + dev->start = 0; + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + 5; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + return 0; +} + +static int __init init_netwave_cs(void) { + servinfo_t serv; + + DEBUG(0, "%s\n", version); + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk("netwave_cs: Card Services release does not match!\n"); + return -1; + } + + register_pccard_driver(&dev_info, &netwave_attach, &netwave_detach); + + return 0; +} + +static void __exit exit_netwave_cs(void) { + DEBUG(1, "netwave_cs: unloading\n"); + + unregister_pccard_driver(&dev_info); + + /* Do some cleanup of the device list */ + netwave_flush_stale_links(); + if(dev_list != NULL) /* Critical situation */ + printk("netwave_cs: devices remaining when removing module\n"); +} + +module_init(init_netwave_cs); +module_exit(exit_netwave_cs); + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ +static void set_multicast_list(struct net_device *dev) +{ + ioaddr_t iobase = dev->base_addr; + u_char* ramBase = ((netwave_private*) dev->priv)->ramBase; + u_char rcvMode = 0; + +#ifdef PCMCIA_DEBUG + if (pc_debug > 2) { + static int old = 0; + if (old != dev->mc_count) { + old = dev->mc_count; + DEBUG(0, "%s: setting Rx mode to %d addresses.\n", + dev->name, dev->mc_count); + } + } +#endif + + if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { + /* Multicast Mode */ + rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast; + } else if (dev->flags & IFF_PROMISC) { + /* Promiscous mode */ + rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast; + } else { + /* Normal mode */ + rcvMode = rxConfRxEna + rxConfBcast; + } + + /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/ + /* Now set receive mode */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); + writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); +} diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c --- v2.3.22/linux/drivers/net/pcmcia/nmclan_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/nmclan_cs.c Wed Oct 20 21:33:12 1999 @@ -0,0 +1,1778 @@ +/* ---------------------------------------------------------------------------- +Linux PCMCIA ethernet adapter driver for the New Media Ethernet LAN. + nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao + + The Ethernet LAN uses the Advanced Micro Devices (AMD) Am79C940 Media + Access Controller for Ethernet (MACE). It is essentially the Am2150 + PCMCIA Ethernet card contained in the the Am2150 Demo Kit. + +Written by Roger C. Pao + Copyright 1995 Roger C. Pao + + This software may be used and distributed according to the terms of + the GNU Public License. + +Ported to Linux 1.3.* network driver environment by + Matti Aarnio + +References + + Am2150 Technical Reference Manual, Revision 1.0, August 17, 1993 + Am79C940 (MACE) Data Sheet, 1994 + Am79C90 (C-LANCE) Data Sheet, 1994 + Linux PCMCIA Programmer's Guide v1.17 + /usr/src/linux/net/inet/dev.c, Linux kernel 1.2.8 + + Eric Mears, New Media Corporation + Tom Pollard, New Media Corporation + Dean Siasoyco, New Media Corporation + Ken Lesniak, Silicon Graphics, Inc. + Donald Becker + David Hinds + + The Linux client driver is based on the 3c589_cs.c client driver by + David Hinds. + + The Linux network driver outline is based on the 3c589_cs.c driver, + the 8390.c driver, and the example skeleton.c kernel code, which are + by Donald Becker. + + The Am2150 network driver hardware interface code is based on the + OS/9000 driver for the New Media Ethernet LAN by Eric Mears. + + Special thanks for testing and help in debugging this driver goes + to Ken Lesniak. + +------------------------------------------------------------------------------- +Driver Notes and Issues +------------------------------------------------------------------------------- + +1. Developed on a Dell 320SLi + PCMCIA Card Services 2.6.2 + Linux dell 1.2.10 #1 Thu Jun 29 20:23:41 PDT 1995 i386 + +2. rc.pcmcia may require loading pcmcia_core with io_speed=300: + 'insmod pcmcia_core.o io_speed=300'. + This will avoid problems with fast systems which causes rx_framecnt + to return random values. + +3. If hot extraction does not work for you, use 'ifconfig eth0 down' + before extraction. + +4. There is a bad slow-down problem in this driver. + +5. Future: Multicast processing. In the meantime, do _not_ compile your + kernel with multicast ip enabled. + +------------------------------------------------------------------------------- +History +------------------------------------------------------------------------------- +Log: nmclan_cs.c,v + * Revision 0.16 1995/07/01 06:42:17 rpao + * Bug fix: nmclan_reset() called CardServices incorrectly. + * + * Revision 0.15 1995/05/24 08:09:47 rpao + * Re-implement MULTI_TX dev->tbusy handling. + * + * Revision 0.14 1995/05/23 03:19:30 rpao + * Added, in nmclan_config(), "tuple.Attributes = 0;". + * Modified MACE ID check to ignore chip revision level. + * Avoid tx_free_frames race condition between _start_xmit and _interrupt. + * + * Revision 0.13 1995/05/18 05:56:34 rpao + * Statistics changes. + * Bug fix: nmclan_reset did not enable TX and RX: call restore_multicast_list. + * Bug fix: mace_interrupt checks ~MACE_IMR_DEFAULT. Fixes driver lockup. + * + * Revision 0.12 1995/05/14 00:12:23 rpao + * Statistics overhaul. + * + +95/05/13 rpao V0.10a + Bug fix: MACE statistics counters used wrong I/O ports. + Bug fix: mace_interrupt() needed to allow statistics to be + processed without RX or TX interrupts pending. +95/05/11 rpao V0.10 + Multiple transmit request processing. + Modified statistics to use MACE counters where possible. +95/05/10 rpao V0.09 Bug fix: Must use IO_DATA_PATH_WIDTH_AUTO. + *Released +95/05/10 rpao V0.08 + Bug fix: Make all non-exported functions private by using + static keyword. + Bug fix: Test IntrCnt _before_ reading MACE_IR. +95/05/10 rpao V0.07 Statistics. +95/05/09 rpao V0.06 Fix rx_framecnt problem by addition of PCIC wait states. + +---------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------------- +Conditional Compilation Options +---------------------------------------------------------------------------- */ + +#define MULTI_TX 0 +#define TIMEOUT_TX 1 +#define RESET_ON_TIMEOUT 1 +#define TX_INTERRUPTABLE 1 +#define RESET_XILINX 0 + +/* ---------------------------------------------------------------------------- +Include Files +---------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------------------- +Defines +---------------------------------------------------------------------------- */ + +#define ETHER_ADDR_LEN ETH_ALEN + /* 6 bytes in an Ethernet Address */ +#define MACE_LADRF_LEN 8 + /* 8 bytes in Logical Address Filter */ + +/* Transmitter Busy Bit Index Defines */ +#define TBUSY_UNSPECIFIED 0 +#define TBUSY_PARTIAL_TX_FRAME 0 +#define TBUSY_NO_FREE_TX_FRAMES 1 + +/* Loop Control Defines */ +#define MACE_MAX_IR_ITERATIONS 10 +#define MACE_MAX_RX_ITERATIONS 12 + /* + TBD: Dean brought this up, and I assumed the hardware would + handle it: + + If MACE_MAX_RX_ITERATIONS is > 1, rx_framecnt may still be + non-zero when the isr exits. We may not get another interrupt + to process the remaining packets for some time. + */ + +/* +The Am2150 has a Xilinx XC3042 field programmable gate array (FPGA) +which manages the interface between the MACE and the PCMCIA bus. It +also includes buffer management for the 32K x 8 SRAM to control up to +four transmit and 12 receive frames at a time. +*/ +#define AM2150_MAX_TX_FRAMES 4 +#define AM2150_MAX_RX_FRAMES 12 + +/* Am2150 Ethernet Card I/O Mapping */ +#define AM2150_RCV 0x00 +#define AM2150_XMT 0x04 +#define AM2150_XMT_SKIP 0x09 +#define AM2150_RCV_NEXT 0x0A +#define AM2150_RCV_FRAME_COUNT 0x0B +#define AM2150_MACE_BANK 0x0C +#define AM2150_MACE_BASE 0x10 + +/* MACE Registers */ +#define MACE_RCVFIFO 0 +#define MACE_XMTFIFO 1 +#define MACE_XMTFC 2 +#define MACE_XMTFS 3 +#define MACE_XMTRC 4 +#define MACE_RCVFC 5 +#define MACE_RCVFS 6 +#define MACE_FIFOFC 7 +#define MACE_IR 8 +#define MACE_IMR 9 +#define MACE_PR 10 +#define MACE_BIUCC 11 +#define MACE_FIFOCC 12 +#define MACE_MACCC 13 +#define MACE_PLSCC 14 +#define MACE_PHYCC 15 +#define MACE_CHIPIDL 16 +#define MACE_CHIPIDH 17 +#define MACE_IAC 18 +/* Reserved */ +#define MACE_LADRF 20 +#define MACE_PADR 21 +/* Reserved */ +/* Reserved */ +#define MACE_MPC 24 +/* Reserved */ +#define MACE_RNTPC 26 +#define MACE_RCVCC 27 +/* Reserved */ +#define MACE_UTR 29 +#define MACE_RTR1 30 +#define MACE_RTR2 31 + +/* MACE Bit Masks */ +#define MACE_XMTRC_EXDEF 0x80 +#define MACE_XMTRC_XMTRC 0x0F + +#define MACE_XMTFS_XMTSV 0x80 +#define MACE_XMTFS_UFLO 0x40 +#define MACE_XMTFS_LCOL 0x20 +#define MACE_XMTFS_MORE 0x10 +#define MACE_XMTFS_ONE 0x08 +#define MACE_XMTFS_DEFER 0x04 +#define MACE_XMTFS_LCAR 0x02 +#define MACE_XMTFS_RTRY 0x01 + +#define MACE_RCVFS_RCVSTS 0xF000 +#define MACE_RCVFS_OFLO 0x8000 +#define MACE_RCVFS_CLSN 0x4000 +#define MACE_RCVFS_FRAM 0x2000 +#define MACE_RCVFS_FCS 0x1000 + +#define MACE_FIFOFC_RCVFC 0xF0 +#define MACE_FIFOFC_XMTFC 0x0F + +#define MACE_IR_JAB 0x80 +#define MACE_IR_BABL 0x40 +#define MACE_IR_CERR 0x20 +#define MACE_IR_RCVCCO 0x10 +#define MACE_IR_RNTPCO 0x08 +#define MACE_IR_MPCO 0x04 +#define MACE_IR_RCVINT 0x02 +#define MACE_IR_XMTINT 0x01 + +#define MACE_MACCC_PROM 0x80 +#define MACE_MACCC_DXMT2PD 0x40 +#define MACE_MACCC_EMBA 0x20 +#define MACE_MACCC_RESERVED 0x10 +#define MACE_MACCC_DRCVPA 0x08 +#define MACE_MACCC_DRCVBC 0x04 +#define MACE_MACCC_ENXMT 0x02 +#define MACE_MACCC_ENRCV 0x01 + +#define MACE_PHYCC_LNKFL 0x80 +#define MACE_PHYCC_DLNKTST 0x40 +#define MACE_PHYCC_REVPOL 0x20 +#define MACE_PHYCC_DAPC 0x10 +#define MACE_PHYCC_LRT 0x08 +#define MACE_PHYCC_ASEL 0x04 +#define MACE_PHYCC_RWAKE 0x02 +#define MACE_PHYCC_AWAKE 0x01 + +#define MACE_IAC_ADDRCHG 0x80 +#define MACE_IAC_PHYADDR 0x04 +#define MACE_IAC_LOGADDR 0x02 + +#define MACE_UTR_RTRE 0x80 +#define MACE_UTR_RTRD 0x40 +#define MACE_UTR_RPA 0x20 +#define MACE_UTR_FCOLL 0x10 +#define MACE_UTR_RCVFCSE 0x08 +#define MACE_UTR_LOOP_INCL_MENDEC 0x06 +#define MACE_UTR_LOOP_NO_MENDEC 0x04 +#define MACE_UTR_LOOP_EXTERNAL 0x02 +#define MACE_UTR_LOOP_NONE 0x00 +#define MACE_UTR_RESERVED 0x01 + +/* Switch MACE register bank (only 0 and 1 are valid) */ +#define MACEBANK(win_num) outb((win_num), ioaddr + AM2150_MACE_BANK) + +#define MACE_IMR_DEFAULT \ + (0xFF - \ + ( \ + MACE_IR_CERR | \ + MACE_IR_RCVCCO | \ + MACE_IR_RNTPCO | \ + MACE_IR_MPCO | \ + MACE_IR_RCVINT | \ + MACE_IR_XMTINT \ + ) \ + ) +#undef MACE_IMR_DEFAULT +#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */ + +/* ---------------------------------------------------------------------------- +Type Definitions +---------------------------------------------------------------------------- */ + +typedef struct _mace_statistics { + /* MACE_XMTFS */ + int xmtsv; + int uflo; + int lcol; + int more; + int one; + int defer; + int lcar; + int rtry; + + /* MACE_XMTRC */ + int exdef; + int xmtrc; + + /* RFS1--Receive Status (RCVSTS) */ + int oflo; + int clsn; + int fram; + int fcs; + + /* RFS2--Runt Packet Count (RNTPC) */ + int rfs_rntpc; + + /* RFS3--Receive Collision Count (RCVCC) */ + int rfs_rcvcc; + + /* MACE_IR */ + int jab; + int babl; + int cerr; + int rcvcco; + int rntpco; + int mpco; + + /* MACE_MPC */ + int mpc; + + /* MACE_RNTPC */ + int rntpc; + + /* MACE_RCVCC */ + int rcvcc; +} mace_statistics; + +typedef struct _mace_private { + dev_node_t node; + struct net_device_stats linux_stats; /* Linux statistics counters */ + mace_statistics mace_stats; /* MACE chip statistics counters */ + + /* restore_multicast_list() state variables */ + int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */ + int multicast_num_addrs; + + char tx_free_frames; /* Number of free transmit frame buffers */ + char tx_irq_disabled; /* MACE TX interrupt disabled */ +} mace_private; + +/* ---------------------------------------------------------------------------- +Private Global Variables +---------------------------------------------------------------------------- */ + +#ifdef PCMCIA_DEBUG +static char rcsid[] = +"nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao"; +static char *version = +"nmclan_cs 0.16 (Roger C. Pao)"; +#endif + +static dev_info_t dev_info="nmclan_cs"; +static dev_link_t *dev_list=NULL; + +static char *if_names[]={ + "Auto", + "10baseT", + "BNC", +}; + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) +#endif + +/* ---------------------------------------------------------------------------- +Parameters + These are the parameters that can be set during loading with + 'insmod'. +---------------------------------------------------------------------------- */ + +static int if_port=0; /* default=auto */ + /* + * 0=auto + * 1=10base-T (twisted pair) + * 2=10base-2 (BNC) + */ + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +MODULE_PARM(if_port, "i"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/* ---------------------------------------------------------------------------- +Function Prototypes +---------------------------------------------------------------------------- */ + +static void nmclan_config(dev_link_t *link); +static void nmclan_release(u_long arg); +static int nmclan_event(event_t event, int priority, + event_callback_args_t *args); + +static void nmclan_reset(struct net_device *dev); +static int mace_config(struct net_device *dev, struct ifmap *map); +static int mace_open(struct net_device *dev); +static int mace_close(struct net_device *dev); +static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats *mace_get_stats(struct net_device *dev); +static int mace_rx(struct net_device *dev, unsigned char RxCnt); +static void restore_multicast_list(struct net_device *dev); + +static void set_multicast_list(struct net_device *dev); + +static dev_link_t *nmclan_attach(void); +static void nmclan_detach(dev_link_t *); + +/* ---------------------------------------------------------------------------- +flush_stale_links + Clean up stale device structures +---------------------------------------------------------------------------- */ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + nmclan_detach(link); + } +} + +/* ---------------------------------------------------------------------------- +cs_error + Report a Card Services related error. +---------------------------------------------------------------------------- */ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/* ---------------------------------------------------------------------------- +nmclan_init + We never need to do anything when a nmclan device is "initialized" + by the net software, because we only register already-found cards. +---------------------------------------------------------------------------- */ +static int nmclan_init(struct net_device *dev) +{ + return 0; +} /* nmclan_init */ + +/* ---------------------------------------------------------------------------- +nmclan_attach + Creates an "instance" of the driver, allocating local data + structures for one device. The device is registered with Card + Services. +---------------------------------------------------------------------------- */ +static dev_link_t *nmclan_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + int i, ret; + + DEBUG(0, "nmclan_attach()\n"); + DEBUG(1, "%s\n", rcsid); + flush_stale_links(); + + /* Create new ethernet device */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &nmclan_release; + link->release.data = (u_long)link; + link->io.NumPorts1 = 32; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 5; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = &mace_interrupt; + 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; + + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + + /* Allocate private data area for this device. */ + dev->priv = kmalloc(sizeof(mace_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(mace_private)); + ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES; + + dev->hard_start_xmit = &mace_start_xmit; + dev->set_config = &mace_config; + dev->get_stats = &mace_get_stats; + dev->set_multicast_list = &set_multicast_list; + ether_setup(dev); + dev->name = ((mace_private *)dev->priv)->node.dev_name; + dev->init = &nmclan_init; + dev->open = &mace_open; + dev->stop = &mace_close; + dev->tbusy = 0xFF; + link->priv = link->irq.Instance = dev; + + /* 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 = &nmclan_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); + nmclan_detach(link); + return NULL; + } + + return link; +} /* nmclan_attach */ + +/* ---------------------------------------------------------------------------- +nmclan_detach + 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 nmclan_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "nmclan_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) { + nmclan_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + if (link->priv) { + struct net_device *dev = link->priv; + if (link->dev != NULL) + unregister_netdev(dev); + if (dev->priv) + kfree(dev->priv); + kfree(link->priv); + } + kfree(link); + +} /* nmclan_detach */ + +/* ---------------------------------------------------------------------------- +mace_read + Reads a MACE register. This is bank independent; however, the + caller must ensure that this call is not interruptable. We are + assuming that during normal operation, the MACE is always in + bank 0. +---------------------------------------------------------------------------- */ +static int mace_read(ioaddr_t ioaddr, int reg) +{ + int data = 0xFF; + unsigned long flags; + + switch (reg >> 4) { + case 0: /* register 0-15 */ + data = inb(ioaddr + AM2150_MACE_BASE + reg); + break; + case 1: /* register 16-31 */ + save_flags(flags); + cli(); + MACEBANK(1); + data = inb(ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); + MACEBANK(0); + restore_flags(flags); + break; + } + return (data & 0xFF); +} /* mace_read */ + +/* ---------------------------------------------------------------------------- +mace_write + Writes to a MACE register. This is bank independent; however, + the caller must ensure that this call is not interruptable. We + are assuming that during normal operation, the MACE is always in + bank 0. +---------------------------------------------------------------------------- */ +static void mace_write(ioaddr_t ioaddr, int reg, int data) +{ + unsigned long flags; + + switch (reg >> 4) { + case 0: /* register 0-15 */ + outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + reg); + break; + case 1: /* register 16-31 */ + save_flags(flags); + cli(); + MACEBANK(1); + outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + (reg & 0x0F)); + MACEBANK(0); + restore_flags(flags); + break; + } +} /* mace_write */ + +/* ---------------------------------------------------------------------------- +mace_init + Resets the MACE chip. +---------------------------------------------------------------------------- */ +static void mace_init(ioaddr_t ioaddr, char *enet_addr) +{ + int i; + + /* MACE Software reset */ + mace_write(ioaddr, MACE_BIUCC, 1); + while (mace_read(ioaddr, MACE_BIUCC) & 0x01) { + /* Wait for reset bit to be cleared automatically after <= 200ns */; + } + mace_write(ioaddr, MACE_BIUCC, 0); + + /* The Am2150 requires that the MACE FIFOs operate in burst mode. */ + mace_write(ioaddr, MACE_FIFOCC, 0x0F); + + mace_write(ioaddr, MACE_RCVFC, 0); /* Disable Auto Strip Receive */ + mace_write(ioaddr, MACE_IMR, 0xFF); /* Disable all interrupts until _open */ + + /* + * Bit 2-1 PORTSEL[1-0] Port Select. + * 00 AUI/10Base-2 + * 01 10Base-T + * 10 DAI Port (reserved in Am2150) + * 11 GPSI + * For this card, only the first two are valid. + * So, PLSCC should be set to + * 0x00 for 10Base-2 + * 0x02 for 10Base-T + * Or just set ASEL in PHYCC below! + */ + switch (if_port) { + case 1: + mace_write(ioaddr, MACE_PLSCC, 0x02); + break; + case 2: + mace_write(ioaddr, MACE_PLSCC, 0x00); + break; + default: + mace_write(ioaddr, MACE_PHYCC, /* ASEL */ 4); + /* ASEL Auto Select. When set, the PORTSEL[1-0] bits are overridden, + and the MACE device will automatically select the operating media + interface port. */ + break; + } + + mace_write(ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_PHYADDR); + /* Poll ADDRCHG bit */ + while (mace_read(ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG) + ; + /* Set PADR register */ + for (i = 0; i < ETHER_ADDR_LEN; i++) + mace_write(ioaddr, MACE_PADR, enet_addr[i]); + + /* MAC Configuration Control Register should be written last */ + /* Let set_multicast_list set this. */ + /* mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */ + mace_write(ioaddr, MACE_MACCC, 0x00); +} /* mace_init */ + +/* ---------------------------------------------------------------------------- +nmclan_config + This routine 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. +---------------------------------------------------------------------------- */ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void nmclan_config(dev_link_t *link) +{ + client_handle_t handle; + struct net_device *dev; + tuple_t tuple; + cisparse_t parse; + u_char buf[64]; + int i, last_ret, last_fn; + ioaddr_t ioaddr; + u_short *phys_addr; + + handle = link->handle; + dev = link->priv; + phys_addr = (u_short *)dev->dev_addr; + + DEBUG(0, "nmclan_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + + /* Configure card */ + link->state |= DEV_CONFIG; + + CS_CHECK(RequestIO, handle, &link->io); + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + dev->tbusy = 0; + i = register_netdev(dev); + if (i != 0) { + printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n"); + goto failed; + } + + ioaddr = dev->base_addr; + + /* Read the ethernet address from the CIS. */ + tuple.DesiredTuple = 0x80 /* CISTPL_CFTABLE_ENTRY_MISC */; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN); + + /* Verify configuration by reading the MACE ID. */ + { + char sig[2]; + + sig[0] = mace_read(ioaddr, MACE_CHIPIDL); + sig[1] = mace_read(ioaddr, MACE_CHIPIDH); + if ((sig[0] == 0x40) && ((sig[1] & 0x0F) == 0x09)) { + DEBUG(0, "nmclan_cs configured: mace id=%x %x\n", + sig[0], sig[1]); + } else { + printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should" + " be 0x40 0x?9\n", sig[0], sig[1]); + link->state &= ~DEV_CONFIG_PENDING; + return; + } + } + + mace_init(ioaddr, dev->dev_addr); + + /* The if_port symbol can be set when the module is loaded */ + if (if_port <= 2) + dev->if_port = if_port; + else + printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n"); + + link->dev = &((mace_private *)dev->priv)->node; + link->state &= ~DEV_CONFIG_PENDING; + + printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ", + dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + nmclan_release((u_long)link); + return; + +} /* nmclan_config */ + +/* ---------------------------------------------------------------------------- +nmclan_release + After a card is removed, nmclan_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 nmclan_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "nmclan_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1, "nmclan_cs: release postponed, '%s' " + "still open\n", link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* nmclan_release */ + +/* ---------------------------------------------------------------------------- +nmclan_event + 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. +---------------------------------------------------------------------------- */ +static int nmclan_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + + DEBUG(1, "nmclan_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 0xFF; dev->start = 0; + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + nmclan_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 0xFF; dev->start = 0; + } + 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); + if (link->open) { + dev->tbusy = 0; + dev->start = 1; + nmclan_reset(dev); + } + } + break; + case CS_EVENT_RESET_REQUEST: + return 1; + break; + } + return 0; +} /* nmclan_event */ + +/* ------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------------- +nmclan_reset + Reset and restore all of the Xilinx and MACE registers. +---------------------------------------------------------------------------- */ +static void nmclan_reset(struct net_device *dev) +{ + +#if RESET_XILINX + dev_link_t *link; + conf_reg_t reg; + u_long OrigCorValue; + + /* Find our client handle. */ + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) { + printk(KERN_NOTICE "nmclan_cs: bad device pointer!\n"); + return; + } + + /* Save original COR value */ + reg.Function = 0; + reg.Action = CS_READ; + reg.Offset = CISREG_COR; + reg.Value = 0; + CardServices(AccessConfigurationRegister, link->handle, ®); + OrigCorValue = reg.Value; + + /* Reset Xilinx */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_COR; + DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n", + OrigCorValue); + reg.Value = COR_SOFT_RESET; + CardServices(AccessConfigurationRegister, link->handle, ®); + /* Need to wait for 20 ms for PCMCIA to finish reset. */ + + /* Restore original COR configuration index */ + reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK); + CardServices(AccessConfigurationRegister, link->handle, ®); + /* Xilinx is now completely reset along with the MACE chip. */ + ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES; + +#endif /* #if RESET_XILINX */ + + /* Xilinx is now completely reset along with the MACE chip. */ + ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES; + + /* Reinitialize the MACE chip for operation. */ + mace_init(dev->base_addr, dev->dev_addr); + mace_write(dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT); + + /* Restore the multicast list and enable TX and RX. */ + restore_multicast_list(dev); +} /* nmclan_reset */ + +/* ---------------------------------------------------------------------------- +mace_config + [Someone tell me what this is supposed to do? Is if_port a defined + standard? If so, there should be defines to indicate 1=10Base-T, + 2=10Base-2, etc. including limited automatic detection.] +---------------------------------------------------------------------------- */ +static int mace_config(struct net_device *dev, struct ifmap *map) +{ + if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { + if (map->port <= 2) { + dev->if_port = map->port; + printk(KERN_INFO "%s: switched to %s port\n", dev->name, + if_names[dev->if_port]); + } + else + return -EINVAL; + } + return 0; +} /* mace_config */ + +/* ---------------------------------------------------------------------------- +mace_open + Open device driver. +---------------------------------------------------------------------------- */ +static int mace_open(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + dev_link_t *link; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (!DEV_OK(link)) + return -ENODEV; + + link->open++; + MOD_INC_USE_COUNT; + + MACEBANK(0); + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + + nmclan_reset(dev); + + return 0; /* Always succeed */ +} /* mace_open */ + +/* ---------------------------------------------------------------------------- +mace_close + Closes device driver. +---------------------------------------------------------------------------- */ +static int mace_close(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + dev_link_t *link; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + DEBUG(2, "%s: shutting down ethercard.\n", dev->name); + + /* Mask off all interrupts from the MACE chip. */ + outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR); + + link->open--; + dev->start = 0; + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + + return 0; +} /* mace_close */ + +/* ---------------------------------------------------------------------------- +mace_start_xmit + This routine begins the packet transmit function. When completed, + it will generate a transmit interrupt. + + According to /usr/src/linux/net/inet/dev.c, if _start_xmit + returns 0, the "packet is now solely the responsibility of the + driver." If _start_xmit returns non-zero, the "transmission + failed, put skb back into a list." +---------------------------------------------------------------------------- */ +static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + mace_private *lp = (mace_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + dev_link_t *link; + +#if TIMEOUT_TX + /* Transmitter timeout. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar < (HZ/5)) + return 1; + printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name); +#if RESET_ON_TIMEOUT + printk("resetting card\n"); + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link) + CardServices(ResetCard, link->handle); +#else /* #if RESET_ON_TIMEOUT */ + printk("NOT resetting card\n"); +#endif /* #if RESET_ON_TIMEOUT */ + dev->trans_start = jiffies; + return 1; + } +#else /* #if TIMEOUT_TX */ + if (dev->tbusy) + return 1; +#endif /* #if TIMEOUT_TX */ + + DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n", + dev->name, (long)skb->len); + + /* Avoid timer-based retransmission conflicts. */ + if (test_and_set_bit(TBUSY_UNSPECIFIED, (void*)&dev->tbusy) != 0) { + printk(KERN_NOTICE "%s: transmitter access conflict.\n", + dev->name); + return 1; + } + +#if (!TX_INTERRUPTABLE) + /* Disable MACE TX interrupts. */ + outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT, + ioaddr + AM2150_MACE_BASE + MACE_IMR); + lp->tx_irq_disabled=1; +#endif /* #if (!TX_INTERRUPTABLE) */ + + { + /* This block must not be interrupted by another transmit request! + dev->tbusy will take care of timer-based retransmissions from + the upper layers. The interrupt handler is guaranteed never to + service a transmit interrupt while we are in here. + */ + set_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy); + + lp->linux_stats.tx_bytes += skb->len; + lp->tx_free_frames--; + set_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy); + + /* WARNING: Write the _exact_ number of bytes written in the header! */ + /* Put out the word header [must be an outw()] . . . */ + outw(skb->len, ioaddr + AM2150_XMT); + /* . . . and the packet [may be any combination of outw() and outb()] */ + outsw(ioaddr + AM2150_XMT, skb->data, skb->len >> 1); + if (skb->len & 1) { + /* Odd byte transfer */ + outb(skb->data[skb->len-1], ioaddr + AM2150_XMT); + } + + dev->trans_start = jiffies; + + if (lp->tx_free_frames > 0) { +#if MULTI_TX + clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy); +#endif /* #if MULTI_TX */ + } + + clear_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy); + } + +#if (!TX_INTERRUPTABLE) + /* Re-enable MACE TX interrupts. */ + lp->tx_irq_disabled=0; + outb(MACE_IMR_DEFAULT, ioaddr + AM2150_MACE_BASE + MACE_IMR); +#endif /* #if (!TX_INTERRUPTABLE) */ + + dev_kfree_skb(skb); + + return 0; +} /* mace_start_xmit */ + +/* ---------------------------------------------------------------------------- +mace_interrupt + The interrupt handler. +---------------------------------------------------------------------------- */ +static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + mace_private *lp = (mace_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int status; + int IntrCnt = MACE_MAX_IR_ITERATIONS; + + if (dev == NULL) { + DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n", + irq); + return; + } + + if (dev->interrupt || lp->tx_irq_disabled) { + sti(); + printk( + (lp->tx_irq_disabled? + KERN_NOTICE "%s: Interrupt with tx_irq_disabled " + "[isr=%02X, imr=%02X]\n": + KERN_NOTICE "%s: Re-entering the interrupt handler " + "[isr=%02X, imr=%02X]\n"), + dev->name, + inb(ioaddr + AM2150_MACE_BASE + MACE_IR), + inb(ioaddr + AM2150_MACE_BASE + MACE_IMR) + ); + /* WARNING: MACE_IR has been read! */ + return; + } + dev->interrupt = 1; + sti(); + + if (dev->start == 0) { + DEBUG(2, "%s: interrupt from dead card\n", dev->name); + goto exception; + } + + do { + /* WARNING: MACE_IR is a READ/CLEAR port! */ + status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); + + DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); + + if (status & MACE_IR_RCVINT) { + mace_rx(dev, MACE_MAX_RX_ITERATIONS); + } + + if (status & MACE_IR_XMTINT) { + unsigned char fifofc; + unsigned char xmtrc; + unsigned char xmtfs; + + fifofc = inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC); + if ((fifofc & MACE_FIFOFC_XMTFC)==0) { + lp->linux_stats.tx_errors++; + outb(0xFF, ioaddr + AM2150_XMT_SKIP); + } + + /* Transmit Retry Count (XMTRC, reg 4) */ + xmtrc = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC); + if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++; + lp->mace_stats.xmtrc += (xmtrc & MACE_XMTRC_XMTRC); + + if ( + (xmtfs = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) & + MACE_XMTFS_XMTSV /* Transmit Status Valid */ + ) { + lp->mace_stats.xmtsv++; + + if (xmtfs & ~MACE_XMTFS_XMTSV) { + if (xmtfs & MACE_XMTFS_UFLO) { + /* Underflow. Indicates that the Transmit FIFO emptied before + the end of frame was reached. */ + lp->mace_stats.uflo++; + } + if (xmtfs & MACE_XMTFS_LCOL) { + /* Late Collision */ + lp->mace_stats.lcol++; + } + if (xmtfs & MACE_XMTFS_MORE) { + /* MORE than one retry was needed */ + lp->mace_stats.more++; + } + if (xmtfs & MACE_XMTFS_ONE) { + /* Exactly ONE retry occurred */ + lp->mace_stats.one++; + } + if (xmtfs & MACE_XMTFS_DEFER) { + /* Transmission was defered */ + lp->mace_stats.defer++; + } + if (xmtfs & MACE_XMTFS_LCAR) { + /* Loss of carrier */ + lp->mace_stats.lcar++; + } + if (xmtfs & MACE_XMTFS_RTRY) { + /* Retry error: transmit aborted after 16 attempts */ + lp->mace_stats.rtry++; + } + } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */ + + } /* if (xmtfs & MACE_XMTFS_XMTSV) */ + + lp->linux_stats.tx_packets++; + lp->tx_free_frames++; + clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy); + mark_bh(NET_BH); + } /* if (status & MACE_IR_XMTINT) */ + + if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) { + if (status & MACE_IR_JAB) { + /* Jabber Error. Excessive transmit duration (20-150ms). */ + lp->mace_stats.jab++; + } + if (status & MACE_IR_BABL) { + /* Babble Error. >1518 bytes transmitted. */ + lp->mace_stats.babl++; + } + if (status & MACE_IR_CERR) { + /* Collision Error. CERR indicates the absence of the + Signal Quality Error Test message after a packet + transmission. */ + lp->mace_stats.cerr++; + } + if (status & MACE_IR_RCVCCO) { + /* Receive Collision Count Overflow; */ + lp->mace_stats.rcvcco++; + } + if (status & MACE_IR_RNTPCO) { + /* Runt Packet Count Overflow */ + lp->mace_stats.rntpco++; + } + if (status & MACE_IR_MPCO) { + /* Missed Packet Count Overflow */ + lp->mace_stats.mpco++; + } + } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) */ + + } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt)); + +exception: + dev->interrupt = 0; + return; +} /* mace_interrupt */ + +/* ---------------------------------------------------------------------------- +mace_rx + Receives packets. +---------------------------------------------------------------------------- */ +static int mace_rx(struct net_device *dev, unsigned char RxCnt) +{ + mace_private *lp = (mace_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + unsigned char rx_framecnt; + unsigned short rx_status; + + while ( + ((rx_framecnt = inb(ioaddr + AM2150_RCV_FRAME_COUNT)) > 0) && + (rx_framecnt <= 12) && /* rx_framecnt==0xFF if card is extracted. */ + (RxCnt--) + ) { + rx_status = inw(ioaddr + AM2150_RCV); + + DEBUG(3, "%s: in mace_rx(), framecnt 0x%X, rx_status" + " 0x%X.\n", dev->name, rx_framecnt, rx_status); + + if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */ + lp->linux_stats.rx_errors++; + if (rx_status & MACE_RCVFS_OFLO) { + lp->mace_stats.oflo++; + } + if (rx_status & MACE_RCVFS_CLSN) { + lp->mace_stats.clsn++; + } + if (rx_status & MACE_RCVFS_FRAM) { + lp->mace_stats.fram++; + } + if (rx_status & MACE_RCVFS_FCS) { + lp->mace_stats.fcs++; + } + } else { + short pkt_len = (rx_status & ~MACE_RCVFS_RCVSTS) - 4; + /* Auto Strip is off, always subtract 4 */ + struct sk_buff *skb; + + lp->mace_stats.rfs_rntpc += inb(ioaddr + AM2150_RCV); + /* runt packet count */ + lp->mace_stats.rfs_rcvcc += inb(ioaddr + AM2150_RCV); + /* rcv collision count */ + + DEBUG(3, " receiving packet size 0x%X rx_status" + " 0x%X.\n", pkt_len, rx_status); + + skb = dev_alloc_skb(pkt_len+2); + + if (skb != NULL) { + skb->dev = dev; + + skb_reserve(skb, 2); + insw(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1); + if (pkt_len & 1) + *(skb->tail-1) = inb(ioaddr + AM2150_RCV); + skb->protocol = eth_type_trans(skb, dev); + + netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ + + lp->linux_stats.rx_packets++; + lp->linux_stats.rx_bytes += skb->len; + outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ + continue; + } else { + DEBUG(1, "%s: couldn't allocate a sk_buff of size" + " %d.\n", dev->name, pkt_len); + lp->linux_stats.rx_dropped++; + } + } + outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ + } /* while */ + + return 0; +} /* mace_rx */ + +/* ---------------------------------------------------------------------------- +pr_linux_stats +---------------------------------------------------------------------------- */ +static void pr_linux_stats(struct net_device_stats *pstats) +{ + DEBUG(2, "pr_linux_stats\n"); + DEBUG(2, " rx_packets=%-7ld tx_packets=%ld\n", + (long)pstats->rx_packets, (long)pstats->tx_packets); + DEBUG(2, " rx_errors=%-7ld tx_errors=%ld\n", + (long)pstats->rx_errors, (long)pstats->tx_errors); + DEBUG(2, " rx_dropped=%-7ld tx_dropped=%ld\n", + (long)pstats->rx_dropped, (long)pstats->tx_dropped); + DEBUG(2, " multicast=%-7ld collisions=%ld\n", + (long)pstats->multicast, (long)pstats->collisions); + + DEBUG(2, " rx_length_errors=%-7ld rx_over_errors=%ld\n", + (long)pstats->rx_length_errors, (long)pstats->rx_over_errors); + DEBUG(2, " rx_crc_errors=%-7ld rx_frame_errors=%ld\n", + (long)pstats->rx_crc_errors, (long)pstats->rx_frame_errors); + DEBUG(2, " rx_fifo_errors=%-7ld rx_missed_errors=%ld\n", + (long)pstats->rx_fifo_errors, (long)pstats->rx_missed_errors); + + DEBUG(2, " tx_aborted_errors=%-7ld tx_carrier_errors=%ld\n", + (long)pstats->tx_aborted_errors, (long)pstats->tx_carrier_errors); + DEBUG(2, " tx_fifo_errors=%-7ld tx_heartbeat_errors=%ld\n", + (long)pstats->tx_fifo_errors, (long)pstats->tx_heartbeat_errors); + DEBUG(2, " tx_window_errors=%ld\n", + (long)pstats->tx_window_errors); +} /* pr_linux_stats */ + +/* ---------------------------------------------------------------------------- +pr_mace_stats +---------------------------------------------------------------------------- */ +static void pr_mace_stats(mace_statistics *pstats) +{ + DEBUG(2, "pr_mace_stats\n"); + + DEBUG(2, " xmtsv=%-7d uflo=%d\n", + pstats->xmtsv, pstats->uflo); + DEBUG(2, " lcol=%-7d more=%d\n", + pstats->lcol, pstats->more); + DEBUG(2, " one=%-7d defer=%d\n", + pstats->one, pstats->defer); + DEBUG(2, " lcar=%-7d rtry=%d\n", + pstats->lcar, pstats->rtry); + + /* MACE_XMTRC */ + DEBUG(2, " exdef=%-7d xmtrc=%d\n", + pstats->exdef, pstats->xmtrc); + + /* RFS1--Receive Status (RCVSTS) */ + DEBUG(2, " oflo=%-7d clsn=%d\n", + pstats->oflo, pstats->clsn); + DEBUG(2, " fram=%-7d fcs=%d\n", + pstats->fram, pstats->fcs); + + /* RFS2--Runt Packet Count (RNTPC) */ + /* RFS3--Receive Collision Count (RCVCC) */ + DEBUG(2, " rfs_rntpc=%-7d rfs_rcvcc=%d\n", + pstats->rfs_rntpc, pstats->rfs_rcvcc); + + /* MACE_IR */ + DEBUG(2, " jab=%-7d babl=%d\n", + pstats->jab, pstats->babl); + DEBUG(2, " cerr=%-7d rcvcco=%d\n", + pstats->cerr, pstats->rcvcco); + DEBUG(2, " rntpco=%-7d mpco=%d\n", + pstats->rntpco, pstats->mpco); + + /* MACE_MPC */ + DEBUG(2, " mpc=%d\n", pstats->mpc); + + /* MACE_RNTPC */ + DEBUG(2, " rntpc=%d\n", pstats->rntpc); + + /* MACE_RCVCC */ + DEBUG(2, " rcvcc=%d\n", pstats->rcvcc); + +} /* pr_mace_stats */ + +/* ---------------------------------------------------------------------------- +update_stats + Update statistics. We change to register window 1, so this + should be run single-threaded if the device is active. This is + expected to be a rare operation, and it's simpler for the rest + of the driver to assume that window 0 is always valid rather + than use a special window-state variable. + + oflo & uflo should _never_ occur since it would mean the Xilinx + was not able to transfer data between the MACE FIFO and the + card's SRAM fast enough. If this happens, something is + seriously wrong with the hardware. +---------------------------------------------------------------------------- */ +static void update_stats(ioaddr_t ioaddr, struct net_device *dev) +{ + mace_private *lp = (mace_private *)dev->priv; + + lp->mace_stats.rcvcc += mace_read(ioaddr, MACE_RCVCC); + lp->mace_stats.rntpc += mace_read(ioaddr, MACE_RNTPC); + lp->mace_stats.mpc += mace_read(ioaddr, MACE_MPC); + /* At this point, mace_stats is fully updated for this call. + We may now update the linux_stats. */ + + /* The MACE has no equivalent for linux_stats field which are commented + out. */ + + /* lp->linux_stats.multicast; */ + lp->linux_stats.collisions = + lp->mace_stats.rcvcco * 256 + lp->mace_stats.rcvcc; + /* Collision: The MACE may retry sending a packet 15 times + before giving up. The retry count is in XMTRC. + Does each retry constitute a collision? + If so, why doesn't the RCVCC record these collisions? */ + + /* detailed rx_errors: */ + lp->linux_stats.rx_length_errors = + lp->mace_stats.rntpco * 256 + lp->mace_stats.rntpc; + /* lp->linux_stats.rx_over_errors */ + lp->linux_stats.rx_crc_errors = lp->mace_stats.fcs; + lp->linux_stats.rx_frame_errors = lp->mace_stats.fram; + lp->linux_stats.rx_fifo_errors = lp->mace_stats.oflo; + lp->linux_stats.rx_missed_errors = + lp->mace_stats.mpco * 256 + lp->mace_stats.mpc; + + /* detailed tx_errors */ + lp->linux_stats.tx_aborted_errors = lp->mace_stats.rtry; + lp->linux_stats.tx_carrier_errors = lp->mace_stats.lcar; + /* LCAR usually results from bad cabling. */ + lp->linux_stats.tx_fifo_errors = lp->mace_stats.uflo; + lp->linux_stats.tx_heartbeat_errors = lp->mace_stats.cerr; + /* lp->linux_stats.tx_window_errors; */ + + return; +} /* update_stats */ + +/* ---------------------------------------------------------------------------- +mace_get_stats + Gathers ethernet statistics from the MACE chip. +---------------------------------------------------------------------------- */ +static struct net_device_stats *mace_get_stats(struct net_device *dev) +{ + mace_private *lp = (mace_private *)dev->priv; + + update_stats(dev->base_addr, dev); + + DEBUG(1, "%s: updating the statistics.\n", dev->name); + pr_linux_stats(&lp->linux_stats); + pr_mace_stats(&lp->mace_stats); + + return &lp->linux_stats; +} /* net_device_stats */ + +/* ---------------------------------------------------------------------------- +updateCRC + Modified from Am79C90 data sheet. +---------------------------------------------------------------------------- */ + +#if BROKEN_MULTICAST + +static void updateCRC(int *CRC, int bit) +{ + int poly[]={ + 1,1,1,0, 1,1,0,1, + 1,0,1,1, 1,0,0,0, + 1,0,0,0, 0,0,1,1, + 0,0,1,0, 0,0,0,0 + }; /* CRC polynomial. poly[n] = coefficient of the x**n term of the + CRC generator polynomial. */ + + int j; + + /* shift CRC and control bit (CRC[32]) */ + for (j = 32; j > 0; j--) + CRC[j] = CRC[j-1]; + CRC[0] = 0; + + /* If bit XOR(control bit) = 1, set CRC = CRC XOR polynomial. */ + if (bit ^ CRC[32]) + for (j = 0; j < 32; j++) + CRC[j] ^= poly[j]; +} /* updateCRC */ + +/* ---------------------------------------------------------------------------- +BuildLAF + Build logical address filter. + Modified from Am79C90 data sheet. + +Input + ladrf: logical address filter (contents initialized to 0) + adr: ethernet address +---------------------------------------------------------------------------- */ +static void BuildLAF(int *ladrf, int *adr) +{ + int CRC[33]={1}; /* CRC register, 1 word/bit + extra control bit */ + + int i, byte; /* temporary array indices */ + int hashcode; /* the output object */ + + CRC[32]=0; + + for (byte = 0; byte < 6; byte++) + for (i = 0; i < 8; i++) + updateCRC(CRC, (adr[byte] >> i) & 1); + + hashcode = 0; + for (i = 0; i < 6; i++) + hashcode = (hashcode << 1) + CRC[i]; + + byte = hashcode >> 3; + ladrf[byte] |= (1 << (hashcode & 7)); + +#ifdef PCMCIA_DEBUG + if (pc_debug > 2) { + printk(KERN_DEBUG " adr ="); + for (i = 0; i < 6; i++) + printk(" %02X", adr[i]); + printk("\n" KERN_DEBUG " hashcode = %d(decimal), ladrf[0:63]" + " =", hashcode); + for (i = 0; i < 8; i++) + printk(" %02X", ladrf[i]); + printk("\n"); + } +#endif +} /* BuildLAF */ + +/* ---------------------------------------------------------------------------- +restore_multicast_list + Restores the multicast filter for MACE chip to the last + set_multicast_list() call. + +Input + multicast_num_addrs + multicast_ladrf[] +---------------------------------------------------------------------------- */ +static void restore_multicast_list(struct net_device *dev) +{ + mace_private *lp = (mace_private *)dev->priv; + int num_addrs = lp->multicast_num_addrs; + int *ladrf = lp->multicast_ladrf; + ioaddr_t ioaddr = dev->base_addr; + int i; + + DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", + dev->name, num_addrs); + + if (num_addrs > 0) { + + DEBUG(1, "Attempt to restore multicast list detected.\n"); + + mace_write(ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_LOGADDR); + /* Poll ADDRCHG bit */ + while (mace_read(ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG) + ; + /* Set LADRF register */ + for (i = 0; i < MACE_LADRF_LEN; i++) + mace_write(ioaddr, MACE_LADRF, ladrf[i]); + + mace_write(ioaddr, MACE_UTR, MACE_UTR_RCVFCSE | MACE_UTR_LOOP_EXTERNAL); + mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); + + } else if (num_addrs < 0) { + + /* Promiscuous mode: receive all packets */ + mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); + mace_write(ioaddr, MACE_MACCC, + MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV + ); + + } else { + + /* Normal mode */ + mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); + mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); + + } +} /* restore_multicast_list */ + +/* ---------------------------------------------------------------------------- +set_multicast_list + Set or clear the multicast filter for this adaptor. + +Input + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. +Output + multicast_num_addrs + multicast_ladrf[] +---------------------------------------------------------------------------- */ + +static void set_multicast_list(struct net_device *dev) +{ + mace_private *lp = (mace_private *)dev->priv; + int adr[ETHER_ADDR_LEN] = {0}; /* Ethernet address */ + int i; + struct dev_mc_list *dmi = dev->mc_list; + +#ifdef PCMCIA_DEBUG + if (pc_debug > 1) { + static int old = 0; + if (dev->mc_count != old) { + old = dev->mc_count; + DEBUG(0, "%s: setting Rx mode to %d addresses.\n", + dev->name, old); + } + } +#endif + + /* Set multicast_num_addrs. */ + lp->multicast_num_addrs = dev->mc_count; + + /* Set multicast_ladrf. */ + if (num_addrs > 0) { + /* Calculate multicast logical address filter */ + memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN); + for (i = 0; i < dev->mc_count; i++) { + memcpy(adr, dmi->dmi_addr, ETHER_ADDR_LEN); + dmi = dmi->next; + BuildLAF(lp->multicast_ladrf, adr); + } + } + + restore_multicast_list(dev); + +} /* set_multicast_list */ + +#endif /* BROKEN_MULTICAST */ + +static void restore_multicast_list(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + + DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name, + ((mace_private *)(dev->priv))->multicast_num_addrs); + + if (dev->flags & IFF_PROMISC) { + /* Promiscuous mode: receive all packets */ + mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); + mace_write(ioaddr, MACE_MACCC, + MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV + ); + } else { + /* Normal mode */ + mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL); + mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); + } +} /* restore_multicast_list */ + +static void set_multicast_list(struct net_device *dev) +{ + mace_private *lp = (mace_private *)dev->priv; + +#ifdef PCMCIA_DEBUG + if (pc_debug > 1) { + static int old = 0; + if (dev->mc_count != old) { + old = dev->mc_count; + DEBUG(0, "%s: setting Rx mode to %d addresses.\n", + dev->name, old); + } + } +#endif + + lp->multicast_num_addrs = dev->mc_count; + restore_multicast_list(dev); + +} /* set_multicast_list */ + +/* ---------------------------------------------------------------------------- +init_nmclan_cs +---------------------------------------------------------------------------- */ + +static int __init init_nmclan_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "nmclan_cs: Card Services release does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &nmclan_attach, &nmclan_detach); + return 0; +} + +/* ---------------------------------------------------------------------------- +exit_nmclan_cs +---------------------------------------------------------------------------- */ + +static void __exit exit_nmclan_cs(void) +{ + DEBUG(0, "nmclan_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + nmclan_detach(dev_list); +} + +module_init(init_nmclan_cs); +module_exit(exit_nmclan_cs); diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/ositech.h linux/drivers/net/pcmcia/ositech.h --- v2.3.22/linux/drivers/net/pcmcia/ositech.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/ositech.h Wed Oct 20 21:33:12 1999 @@ -0,0 +1,358 @@ +/* + This file contains the firmware of Seven of Diamonds from OSITECH. + (Special thanks to Kevin MacPherson of OSITECH) + + This software may be used and distributed according to the terms of + the GNU Public License, incorporated herein by reference. +*/ + + static const u_char __Xilinx7OD[] = { + 0xFF, 0x04, 0xA0, 0x36, 0xF3, 0xEC, 0xFF, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF, + 0xF3, 0xFF, 0xFF, 0xFF, + 0xEF, 0x3F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F, 0xFE, 0xFF, + 0xCE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xDE, 0xBD, 0xDD, 0xFD, 0xFF, 0xFD, 0xCF, 0xF7, 0xBF, 0x7F, 0xFF, + 0x7F, 0x3F, 0xFE, 0xBF, + 0xFF, 0xFF, 0xFF, 0xBC, 0xFF, 0xFF, 0xBD, 0xB5, 0x7F, 0x7F, 0xBF, 0xBF, + 0x7F, 0xFF, 0xEF, 0xFF, + 0xFF, 0xFF, 0xFB, 0xFF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDE, + 0xFE, 0xFE, 0xFA, 0xDE, + 0xBD, 0xFD, 0xED, 0xFD, 0xFD, 0xCF, 0xEF, 0xEF, 0xEF, 0xEF, 0xC7, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, + 0xFF, 0x7E, 0xFE, 0xFD, 0x7D, 0x6D, 0xEE, 0xFE, 0x7C, 0xFB, 0xF4, 0xFB, + 0xCF, 0xDB, 0xDF, 0xFF, + 0xFF, 0xBB, 0x7F, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0x9E, 0xBF, 0x3B, 0xBF, + 0xBF, 0x7F, 0x7F, 0x7F, + 0x7E, 0x6F, 0xDF, 0xEF, 0xF5, 0xF6, 0xFD, 0xF6, 0xF5, 0xED, 0xEB, 0xFF, + 0xEF, 0xEF, 0xEF, 0x7E, + 0x7F, 0x7F, 0x6F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xEF, 0xBF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0x1F, 0x1F, 0xEE, 0xFF, 0xBC, + 0xB7, 0xFF, 0xDF, 0xFF, + 0xDF, 0xEF, 0x3B, 0xE3, 0xD3, 0xFF, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, + 0xFF, 0xBA, 0xBF, 0x2D, + 0xDB, 0xBD, 0xFD, 0xDB, 0xDF, 0xFA, 0xFB, 0xFF, 0xEF, 0xFB, 0xDB, 0xF3, + 0xFF, 0xDF, 0xFD, 0x7F, + 0xEF, 0xFB, 0xFF, 0xFF, 0xBE, 0xBF, 0x27, 0xBA, 0xFE, 0xFB, 0xDF, 0xFF, + 0xF6, 0xFF, 0xFF, 0xEF, + 0xFB, 0xDB, 0xF3, 0xD9, 0x9A, 0x3F, 0xFF, 0xAF, 0xBF, 0xFF, 0xFF, 0xBE, + 0x3F, 0x37, 0xBD, 0x96, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE, 0xFB, 0xF3, 0xF3, 0xEB, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF7, 0xFA, 0xBC, 0xAE, 0xFE, 0xBE, 0xFE, 0xBB, 0x7F, 0xFD, 0xFF, + 0x7F, 0xEF, 0xF7, 0xFB, + 0xBB, 0xD7, 0xF7, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xBC, 0xED, 0xFD, + 0xBD, 0x9D, 0x7D, 0x7B, + 0xFB, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF7, + 0xAA, 0xB9, 0xBF, 0x8F, 0xBF, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xCF, + 0xFB, 0xEB, 0xCB, 0xEB, + 0xEE, 0xFF, 0xFF, 0xD7, 0xFF, 0xFF, 0xFF, 0x3E, 0x33, 0x3F, 0x1C, 0x7C, + 0xFC, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xCF, 0xD3, 0xF3, 0xE3, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEB, 0xFE, 0x35, + 0x3F, 0x3D, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0x6F, 0xE3, + 0xE3, 0xE3, 0xEF, 0xFF, + 0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0xFE, 0x3E, 0x5E, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFD, 0xFF, 0xFF, + 0xAF, 0xCF, 0xF2, 0xCB, 0xCF, 0x8E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, + 0xFC, 0x3E, 0x1F, 0x9E, + 0xAD, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xB3, 0xF7, 0xE7, + 0xF7, 0xFA, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEE, 0xEB, 0xAB, 0xAF, 0x9F, 0xE3, 0x7F, 0xFF, 0xDE, + 0xFF, 0x7F, 0xEE, 0xFF, + 0xFF, 0xFB, 0x3A, 0xFA, 0xFF, 0xF2, 0x77, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF, + 0xFE, 0xBD, 0xAE, 0xDE, + 0x7D, 0x7D, 0xFD, 0xFF, 0xBF, 0xEE, 0xFF, 0xFD, 0xFF, 0xDB, 0xFB, 0xFF, + 0xF7, 0xEF, 0xFB, 0xFF, + 0xFF, 0xFE, 0xFF, 0x2D, 0xAF, 0xB9, 0xFD, 0x79, 0xFB, 0xFA, 0xFF, 0xBF, + 0xEF, 0xFF, 0xFF, 0x91, + 0xFA, 0xFB, 0xDF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF, 0x37, 0xBF, + 0xBF, 0xFF, 0x7F, 0x7F, + 0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xF3, 0xFB, 0xFB, 0xFF, 0xF5, 0xEF, + 0xFF, 0xFF, 0xF7, 0xFA, + 0xFF, 0xFF, 0xEE, 0xFA, 0xFE, 0xFB, 0x55, 0xDD, 0xFF, 0x7F, 0xAF, 0xFE, + 0xFF, 0xFB, 0xFB, 0xF5, + 0xFF, 0xF7, 0xEF, 0xFF, 0xFF, 0xFF, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, + 0x7B, 0x7B, 0x7B, 0x7B, + 0xFB, 0xAE, 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0xDA, 0xB7, 0x61, + 0xFF, 0xB9, 0x59, 0xF3, 0x73, 0xF3, 0xDF, 0x7F, 0x6F, 0xDF, 0xEF, 0xF7, + 0xEB, 0xEB, 0xD7, 0xFF, + 0xD7, 0xFF, 0xFF, 0xF7, 0xFE, 0x7F, 0xFB, 0x3E, 0x38, 0x73, 0xF6, 0x7F, + 0xFC, 0xFF, 0xFF, 0xCF, + 0xFF, 0xB7, 0xFB, 0xB3, 0xB3, 0x67, 0xFF, 0xE7, 0xFD, 0xFF, 0xEF, 0xF6, + 0x7F, 0xB7, 0xBC, 0xF5, + 0x7B, 0xF6, 0xF7, 0xF5, 0xFF, 0xFF, 0xEF, 0xFF, 0xF7, 0xFF, 0xF7, 0xCE, + 0xE7, 0xFF, 0x9F, 0xFF, + 0xFF, 0xF5, 0xFE, 0x7D, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEF, 0xFF, 0xF6, + 0xCB, 0xDB, 0xEE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xBE, + 0x1E, 0x3E, 0xFE, 0xFF, + 0x7D, 0xFE, 0xFF, 0xFF, 0xEF, 0xBF, 0xE7, 0xFF, 0xE3, 0xE3, 0xFF, 0xDF, + 0xE7, 0xFF, 0xFF, 0xFF, + 0xB8, 0xEF, 0xB7, 0x2F, 0xEE, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0x7F, 0xEF, + 0xEB, 0xBF, 0xA3, 0xD3, + 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xFD, 0x3F, 0xCF, 0xFD, + 0xFB, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xAF, 0xFB, 0xBF, 0xBB, 0xBF, 0xDB, 0xFD, 0xFB, 0xFF, 0xFF, + 0xFF, 0xFF, 0x3E, 0xFE, + 0x3F, 0xBA, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xEF, 0xC3, 0x7F, + 0xB2, 0x9B, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0x3C, 0xFF, 0x3F, 0x3C, 0xFF, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xAF, 0xF3, 0xFE, 0xF3, 0xE3, 0xEB, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xF7, + 0x9A, 0xFE, 0xAF, 0x9E, + 0xBE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0x7B, 0xEF, 0xF7, 0xBF, 0xFB, 0xFB, + 0xFB, 0xFF, 0xFF, 0x7F, + 0xFF, 0xFF, 0xFF, 0xBC, 0xBD, 0xFD, 0xBD, 0xDD, 0x7D, 0x7B, 0x7B, 0x7B, + 0x7B, 0xFB, 0xAE, 0xFF, + 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0x9A, 0xFF, + 0x9F, 0xFF, 0xAF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xCF, 0xF3, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF, + 0xFF, 0xBF, 0xFF, 0xFF, + 0xEF, 0xFE, 0xFF, 0x37, 0xFC, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xCF, 0xEF, 0xFD, 0xF3, + 0xFF, 0xEE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0xFD, 0x2F, 0xFD, + 0xFF, 0xFD, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEF, 0xCF, 0xFF, 0xF3, 0xBF, 0x69, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, + 0xFB, 0x9F, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x87, + 0xFE, 0xDA, 0xEF, 0xCF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xBF, 0xEF, 0xEF, 0xFD, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEF, 0xFD, 0xFF, 0x7B, 0xFF, 0xEB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEB, 0xF8, 0xFF, 0xEF, + 0xAF, 0xFF, 0xFF, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F, 0xEE, 0x7F, 0xEF, 0xFF, + 0xBB, 0xFF, 0xBF, 0xFB, + 0xFF, 0xFF, 0xFF, 0xF7, 0xF6, 0xFB, 0xBD, 0xFD, 0xDD, 0xF5, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xAF, + 0xFF, 0x5F, 0xF5, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, + 0xF3, 0xFF, 0xDE, 0xFE, + 0xEF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xDE, 0xDF, 0x5F, 0xDF, + 0xFD, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, + 0xFF, 0xAF, 0xFF, 0xFF, + 0xEF, 0xED, 0xFF, 0xDF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xDA, 0xBD, 0xBE, + 0xAE, 0xFE, 0x7F, 0xFD, + 0xDF, 0xFF, 0xFF, 0x7F, 0xEF, 0xFF, 0xFB, 0xFB, 0xFB, 0x7F, 0xF7, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF7, + 0xBC, 0xFD, 0xBD, 0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE, + 0xFF, 0xFF, 0xFD, 0xFF, + 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x9F, 0xBF, 0xBF, 0xCF, + 0x7F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xAF, 0xFF, 0xEB, 0xEB, 0xEB, 0xFF, 0xD7, 0xFE, 0xFF, 0xFF, + 0xBF, 0xE7, 0xFE, 0xBF, + 0x7F, 0xFC, 0xFF, 0xFF, 0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFB, + 0xFB, 0xFF, 0xFF, 0xDD, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBD, 0xDF, 0x9D, 0xFD, 0xDF, 0xB9, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFB, 0xEF, 0xEB, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF6, 0x9F, 0xFF, 0xFC, + 0xFE, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xDF, 0xFA, 0xCD, 0xCF, + 0xBF, 0x9F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF7, 0xFE, 0xBF, 0xFF, 0xDF, 0xEF, 0x5F, 0xFF, 0xFF, 0xFF, + 0xFF, 0x7F, 0x6F, 0xFF, + 0xBB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0xFF, + 0x5F, 0xFF, 0xBF, 0xBF, + 0xF9, 0xFF, 0xFF, 0xFF, 0x7F, 0x6E, 0x7B, 0xFF, 0xEF, 0xFD, 0xEB, 0xDF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0xB6, 0x3E, 0xFC, 0xFD, 0xBF, 0x7E, 0xFB, 0xFF, 0xFF, 0xFF, 0xF7, + 0xEF, 0xF7, 0xF3, 0xF7, + 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0x35, 0x79, 0xFF, + 0xBF, 0xFC, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0x53, 0xDF, 0xFF, 0xEB, 0xBF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xBC, + 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF5, + 0xFF, 0xF7, 0xFF, 0xFB, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xAA, 0xEE, 0xFE, 0x3F, 0x7D, + 0xFD, 0xFF, 0xFF, 0xFF, + 0x7F, 0xAF, 0x77, 0xFB, 0xFB, 0xFF, 0xFB, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0xBE, 0xBD, 0xBD, + 0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE, 0xFF, 0xEF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFC, + 0xFF, 0xFF, 0xFF, 0xFF, 0x9A, 0xD9, 0xB8, 0xFF, 0xFF, 0x79, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xCF, + 0xFB, 0xFF, 0xEB, 0xFF, 0xEB, 0xD7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xDE, + 0xF8, 0xFB, 0xFE, 0x3F, + 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xAD, 0xBF, 0xFA, 0xFF, 0x73, + 0xDF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x3A, 0xF5, 0xB7, 0xFC, 0x3F, 0xF9, 0xFD, 0xFF, 0xFF, 0xFF, + 0x7F, 0xEF, 0xF3, 0xFF, + 0xBF, 0xFE, 0xF3, 0x9F, 0xFE, 0xFF, 0xFF, 0xFF, 0xF7, 0x3E, 0xFF, 0xFF, + 0xFF, 0xBF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xD3, 0xFE, 0xDB, 0xFF, 0xDB, 0xDF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x3E, 0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, + 0xF3, 0xFF, 0xED, 0xFF, + 0xF7, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF6, 0x3C, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x9F, 0xEF, 0xEF, 0xD1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x7E, 0xBF, + 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBB, 0xEF, 0xDF, 0xF1, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x3E, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xBF, + 0xEF, 0xFD, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, + 0xFC, 0x3E, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2E, 0xEF, 0xF3, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF7, 0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x7F, 0xAF, 0xFB, + 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xF2, 0xD6, 0xED, + 0xBD, 0xBD, 0xBD, 0x7D, + 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x92, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, + 0xAF, 0xEB, 0xEB, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFE, 0x2E, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x4F, 0xEF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, + 0x3C, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xCE, + 0xC3, 0xFD, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEF, 0xCF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0xEE, 0x3E, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xDF, 0xE2, 0xFF, + 0xFF, 0xFF, 0xFB, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0xBE, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x7F, 0xEE, + 0x5F, 0xE6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, + 0x7D, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xBF, 0xF7, 0x36, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEF, 0xD3, 0xF6, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x7F, 0xEE, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xEF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, + 0xFB, 0xFA, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xD6, 0xFD, 0xBD, 0xBD, 0xBD, + 0x7D, 0x7B, 0x7B, 0x7B, + 0x7B, 0xFB, 0xAE, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF7, 0xBA, 0xBF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xEB, 0x6B, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x4F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, + 0x3E, 0x6E, 0xFC, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xC3, 0xC9, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3E, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEF, 0xFB, + 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, + 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0xEF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFB, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF6, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, + 0xEF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFE, 0xFF, 0xF7, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x7F, 0xFA, 0xEF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE7, 0xFF, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xEF, 0xBF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xA7, 0xFF, 0xFC, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, + 0xFE, 0xAE, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, + 0xF7, 0xFA, 0xFF, 0xFD, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, + 0x7B, 0x7B, 0xFB, 0xAF, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xCF, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE7, 0xF2, 0xFC, + 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAE, 0xEF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7E, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, + 0xFE, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0xDD, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xAF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xF6, 0x9C, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, + 0xAE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7A, 0xFF, 0xFF, 0xFF, + 0xFF, 0xDF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x6F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF7, 0xFE, + 0xFE, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xEB, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x9E, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xCB, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFD, + 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEF, + 0xEF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0xAF, 0x7F, 0xFF, + 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xBF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x7F, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF7, 0xBC, 0xBD, + 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, + 0xAF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, + 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, + 0xFF, 0xFF, 0xEF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xBF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFE, 0xFF, 0x9F, 0x9F, + 0x9F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0xFF, 0xEF, 0xDF, 0xDF, 0xDF, 0xDF, 0xCF, 0xB7, 0xBF, 0xBF, + 0xBF, 0xBF, 0xFF, 0xBC, + 0xB9, 0x9D, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xEF, 0xD7, + 0xF5, 0xF3, 0xF1, 0xD1, + 0x65, 0xE3, 0xE3, 0xE3, 0xA3, 0xFF, 0xFE, 0x7F, 0xFE, 0xDE, 0xDE, 0xFF, + 0xBD, 0xBD, 0xBD, 0xBD, + 0xDF, 0xEF, 0xFB, 0xF7, 0xF3, 0xF3, 0xF3, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xFB, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + + }; diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c --- v2.3.22/linux/drivers/net/pcmcia/pcnet_cs.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/pcmcia/pcnet_cs.c Wed Oct 20 21:33:12 1999 @@ -11,7 +11,7 @@ Copyright (C) 1999 David A. Hinds -- dhinds@hyper.stanford.edu - pcnet_cs.c 1.99 1999/09/15 15:33:09 + pcnet_cs.c 1.101 1999/10/21 00:56:19 The network driver code is based on Donald Becker's NE2000 code: @@ -72,7 +72,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.99 1999/09/15 15:33:09 (David Hinds)"; +"pcnet_cs.c 1.101 1999/10/21 00:56:19 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -477,7 +477,8 @@ { struct net_device *dev = link->priv; unsigned char prom[32]; - int i, j, ioaddr; + ioaddr_t ioaddr; + int i, j; /* This is lifted straight from drivers/net/ne.c */ struct { @@ -851,7 +852,7 @@ static void set_misc_reg(struct net_device *dev) { - int nic_base = dev->base_addr; + ioaddr_t nic_base = dev->base_addr; pcnet_dev_t *info = (pcnet_dev_t *)dev; u_char tmp; @@ -889,7 +890,7 @@ int i; for (i = 0; i < 20; i++) { if ((inb(dev->base_addr+0x1c) & 0x01) == 0) break; - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); } } @@ -941,7 +942,7 @@ static void pcnet_reset_8390(struct net_device *dev) { - int nic_base = dev->base_addr; + ioaddr_t nic_base = dev->base_addr; int i; ei_status.txing = ei_status.dmaing = 0; @@ -996,7 +997,7 @@ { pcnet_dev_t *info = (pcnet_dev_t *)(arg); struct net_device *dev = &info->dev; - int nic_base = dev->base_addr; + ioaddr_t nic_base = dev->base_addr; if (dev->start == 0) goto reschedule; @@ -1027,7 +1028,7 @@ struct e8390_pkt_hdr *hdr, int ring_page) { - int nic_base = dev->base_addr; + ioaddr_t nic_base = dev->base_addr; if (ei_status.dmaing) { printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input." @@ -1059,7 +1060,7 @@ static void dma_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { - int nic_base = dev->base_addr; + ioaddr_t nic_base = dev->base_addr; int xfer_count = count; char *buf = skb->data; @@ -1116,7 +1117,7 @@ const unsigned char *buf, const int start_page) { - int nic_base = dev->base_addr; + ioaddr_t nic_base = dev->base_addr; pcnet_dev_t *info = (pcnet_dev_t *)dev; #ifdef PCMCIA_DEBUG int retries = 0; diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c --- v2.3.22/linux/drivers/net/pcmcia/smc91c92_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/smc91c92_cs.c Wed Oct 20 21:33:12 1999 @@ -0,0 +1,2013 @@ +/*====================================================================== + + A PCMCIA ethernet driver for SMC91c92-based cards. + + This driver supports Megahertz PCMCIA ethernet cards; and + Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem + multifunction cards. + + Copyright (C) 1999 David A. Hinds -- dhinds@hyper.stanford.edu + + smc91c92_cs.c 1.79 1999/10/19 00:38:29 + + This driver contains code written by Donald Becker + (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au), + David Hinds (dhinds@hyper.stanford.edu), and Erik Stahlman + (erik@vt.edu). Donald wrote the SMC 91c92 code using parts of + Erik's SMC 91c94 driver. Rowan wrote a similar driver, and I've + incorporated some parts of his driver here. I (Dave) wrote most + of the PCMCIA glue code, and the Ositech support code. Kelly + Stephens (kstephen@holli.com) added support for the Motorola + Mariner, with help from Allen Brost. + + This software may be used and distributed according to the terms of + the GNU Public License, incorporated herein by reference. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Ositech Seven of Diamonds firmware */ +#include "ositech.h" + +/*====================================================================*/ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +static const char *version = +"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n"; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) +#endif + +static char *if_names[] = { "auto", "10baseT", "10base2"}; + +/* Parameters that can be set with 'insmod' */ + +/* + Transceiver/media type. + 0 = auto + 1 = 10baseT (and autoselect if #define AUTOSELECT), + 2 = AUI/10base2, +*/ +static int if_port = 0; + +/* Bit map of interrupts to choose from. */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +MODULE_PARM(if_port, "i"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/* Operational parameter that usually are not changed. */ + +/* Do you want to use 32 bit xfers? This should work on all chips, + but could cause trouble with some PCMCIA controllers... */ +#define USE_32_BIT 1 + +/* Time in jiffies before concluding Tx hung */ +#define TX_TIMEOUT ((400*HZ)/1000) + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +#define INTR_WORK 4 + +/* Times to check the check the chip before concluding that it doesn't + currently have room for another Tx packet. */ +#define MEMORY_WAIT_TIME 8 + +/* Values that should be specific lengths */ +typedef unsigned short uint16; + +static dev_info_t dev_info = "smc91c92_cs"; + +static dev_link_t *dev_list = NULL; + +struct smc_private { + u_short manfid; + u_short cardid; + struct net_device_stats stats; + dev_node_t node; + struct sk_buff *saved_skb; + int packets_waiting; + caddr_t base; + u_short cfg; + struct timer_list media; + int watchdog, tx_err; + u_short media_status; + u_short fast_poll; + u_long last_rx; +}; + +/* Special definitions for Megahertz multifunction cards */ +#define MEGAHERTZ_ISR 0x0380 + +/* Special function registers for Motorola Mariner */ +#define MOT_LAN 0x0000 +#define MOT_UART 0x0020 +#define MOT_EEPROM 0x20 + +#define MOT_NORMAL \ +(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA) + +/* Special function registers for Ositech cards */ +#define OSITECH_AUI_CTL 0x0c +#define OSITECH_PWRDOWN 0x0d +#define OSITECH_RESET 0x0e +#define OSITECH_ISR 0x0f +#define OSITECH_AUI_PWR 0x0c +#define OSITECH_RESET_ISR 0x0e + +#define OSI_AUI_PWR 0x40 +#define OSI_LAN_PWRDOWN 0x02 +#define OSI_MODEM_PWRDOWN 0x01 +#define OSI_LAN_RESET 0x02 +#define OSI_MODEM_RESET 0x01 + +/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */ +#define BANK_SELECT 14 /* Window select register. */ +#define SMC_SELECT_BANK(x) { outw( x, ioaddr + BANK_SELECT); } + +/* Bank 0 registers. */ +#define TCR 0 /* transmit control register */ +#define TCR_CLEAR 0 /* do NOTHING */ +#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */ +#define TCR_PAD_EN 0x0080 /* pads short packets to 64 bytes */ +#define TCR_MONCSN 0x0400 /* Monitor Carrier. */ +#define TCR_FDUPLX 0x0800 /* Full duplex mode. */ +#define TCR_NORMAL TCR_ENABLE | TCR_PAD_EN + +#define EPH 2 /* Ethernet Protocol Handler report. */ +#define EPH_TX_SUC 0x0001 +#define EPH_SNGLCOL 0x0002 +#define EPH_MULCOL 0x0004 +#define EPH_LTX_MULT 0x0008 +#define EPH_16COL 0x0010 +#define EPH_SQET 0x0020 +#define EPH_LTX_BRD 0x0040 +#define EPH_TX_DEFR 0x0080 +#define EPH_LAT_COL 0x0200 +#define EPH_LOST_CAR 0x0400 +#define EPH_EXC_DEF 0x0800 +#define EPH_CTR_ROL 0x1000 +#define EPH_RX_OVRN 0x2000 +#define EPH_LINK_OK 0x4000 +#define EPH_TX_UNRN 0x8000 +#define MEMINFO 8 /* Memory Information Register */ +#define MEMCFG 10 /* Memory Configuration Register */ + +/* Bank 1 registers. */ +#define CONFIG 0 +#define CFG_MII_SELECT 0x8000 /* 91C100 only */ +#define CFG_NO_WAIT 0x1000 +#define CFG_FULL_STEP 0x0400 +#define CFG_SET_SQLCH 0x0200 +#define CFG_AUI_SELECT 0x0100 +#define CFG_16BIT 0x0080 +#define CFG_DIS_LINK 0x0040 +#define CFG_STATIC 0x0030 +#define CFG_IRQ_SEL_1 0x0004 +#define CFG_IRQ_SEL_0 0x0002 +#define BASE_ADDR 2 +#define ADDR0 4 +#define GENERAL 10 +#define CONTROL 12 +#define CTL_STORE 0x0001 +#define CTL_RELOAD 0x0002 +#define CTL_EE_SELECT 0x0004 +#define CTL_TE_ENABLE 0x0020 +#define CTL_CR_ENABLE 0x0040 +#define CTL_LE_ENABLE 0x0080 +#define CTL_AUTO_RELEASE 0x0800 +#define CTL_POWERDOWN 0x2000 + +/* Bank 2 registers. */ +#define MMU_CMD 0 +#define MC_ALLOC 0x20 /* or with number of 256 byte packets */ +#define MC_RESET 0x40 +#define MC_RELEASE 0x80 /* remove and release the current rx packet */ +#define MC_FREEPKT 0xA0 /* Release packet in PNR register */ +#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */ +#define PNR_ARR 2 +#define FIFO_PORTS 4 +#define FP_RXEMPTY 0x8000 +#define POINTER 6 +#define PTR_AUTO_INC 0x0040 +#define PTR_READ 0x2000 +#define PTR_AUTOINC 0x4000 +#define PTR_RCV 0x8000 +#define DATA_1 8 +#define INTERRUPT 12 +#define IM_RCV_INT 0x1 +#define IM_TX_INT 0x2 +#define IM_TX_EMPTY_INT 0x4 +#define IM_ALLOC_INT 0x8 +#define IM_RX_OVRN_INT 0x10 +#define IM_EPH_INT 0x20 + +#define RCR 4 +enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002, + RxEnable = 0x0100, RxStripCRC = 0x0200}; +#define RCR_SOFTRESET 0x8000 /* resets the chip */ +#define RCR_STRIP_CRC 0x200 /* strips CRC */ +#define RCR_ENABLE 0x100 /* IFF this is set, we can recieve packets */ +#define RCR_ALMUL 0x4 /* receive all multicast packets */ +#define RCR_PROMISC 0x2 /* enable promiscuous mode */ + +/* the normal settings for the RCR register : */ +#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE) +#define RCR_CLEAR 0x0 /* set it to a base state */ +#define COUNTER 6 + +/* BANK 3 -- not the same values as in smc9194! */ +#define MULTICAST0 0 +#define MULTICAST2 2 +#define MULTICAST4 4 +#define MULTICAST6 6 +#define REVISION 0x0a + +/* Transmit status bits. */ +#define TS_SUCCESS 0x0001 +#define TS_16COL 0x0010 +#define TS_LATCOL 0x0200 +#define TS_LOSTCAR 0x0400 + +/* Receive status bits. */ +#define RS_ALGNERR 0x8000 +#define RS_BADCRC 0x2000 +#define RS_ODDFRAME 0x1000 +#define RS_TOOLONG 0x0800 +#define RS_TOOSHORT 0x0400 +#define RS_MULTICAST 0x0001 +#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) + +#define set_bits(v, p) outw(inw(p)|(v), (p)) +#define mask_bits(v, p) outw(inw(p)&(v), (p)) + +/*====================================================================*/ + +static dev_link_t *smc91c92_attach(void); +static void smc91c92_detach(dev_link_t *); +static void smc91c92_config(dev_link_t *link); +static void smc91c92_release(u_long arg); +static int smc91c92_event(event_t event, int priority, + event_callback_args_t *args); + +static int smc91c92_open(struct net_device *dev); +static int smc91c92_close(struct net_device *dev); +static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void smc_rx(struct net_device *dev); +static struct net_device_stats *smc91c92_get_stats(struct net_device *dev); +static void set_rx_mode(struct net_device *dev); +static int s9k_config(struct net_device *dev, struct ifmap *map); +static void smc_set_xcvr(struct net_device *dev, int if_port); +static void smc_reset(struct net_device *dev); +static void media_check(u_long arg); + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + +======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + smc91c92_detach(link); + } +} + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================*/ + +static int smc91c92_init(struct net_device *dev) +{ + DEBUG(0, "%s: smc91c92_init called!\n", dev->name); + return 0; +} + +/*====================================================================== + + smc91c92_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +======================================================================*/ + +static dev_link_t *smc91c92_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + int i, ret; + + DEBUG(0, "smc91c92_attach()\n"); + flush_stale_links(); + + /* Create new ethernet device */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &smc91c92_release; + link->release.data = (u_long)link; + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 4; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = &smc_interrupt; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + + /* Make up a SMC91-specific-data structure. */ + dev->priv = kmalloc(sizeof(struct smc_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct smc_private)); + + /* The SMC91c92-specific entries in the device structure. */ + dev->hard_start_xmit = &smc_start_xmit; + dev->get_stats = &smc91c92_get_stats; + dev->set_config = &s9k_config; + dev->set_multicast_list = &set_rx_mode; + ether_setup(dev); + dev->name = ((struct smc_private *)dev->priv)->node.dev_name; + dev->init = &smc91c92_init; + dev->open = &smc91c92_open; + dev->stop = &smc91c92_close; + dev->tbusy = 1; + link->priv = link->irq.Instance = dev; + + /* 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 = &smc91c92_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); + smc91c92_detach(link); + return NULL; + } + + return link; +} /* smc91c92_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 smc91c92_detach(dev_link_t *link) +{ + dev_link_t **linkp; + long flags; + + DEBUG(0, "smc91c92_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + if (link->state & DEV_CONFIG) { + smc91c92_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + if (link->priv) { + struct net_device *dev = link->priv; + if (link->dev != NULL) + unregister_netdev(dev); + if (dev->priv) + kfree(dev->priv); + kfree(link->priv); + } + kfree(link); + +} /* smc91c92_detach */ + +/*====================================================================*/ + +static int cvt_ascii_address(struct net_device *dev, char *s) +{ + int i, j, da, c; + + if (strlen(s) != 12) + return -1; + for (i = 0; i < 6; i++) { + da = 0; + for (j = 0; j < 2; j++) { + c = *s++; + da <<= 4; + da += ((c >= '0') && (c <= '9')) ? + (c - '0') : ((c & 0x0f) + 9); + } + dev->dev_addr[i] = da; + } + return 0; +} + +/*====================================================================*/ + +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) + +/*====================================================================== + + Configuration stuff for Megahertz cards + + mhz_3288_power() is used to power up a 3288's ethernet chip. + mhz_mfc_config() handles socket setup for multifunction (1144 + and 3288) cards. mhz_setup() gets a card's hardware ethernet + address. + +======================================================================*/ + +static int mhz_3288_power(dev_link_t *link) +{ + struct net_device *dev = link->priv; + struct smc_private *lp = dev->priv; + u_char tmp; + + /* Read the ISR twice... */ + readb(lp->base+MEGAHERTZ_ISR); + udelay(5); + readb(lp->base+MEGAHERTZ_ISR); + + /* Pause 200ms... */ + mdelay(200); + + /* Now read and write the COR... */ + tmp = readb(lp->base + link->conf.ConfigBase + CISREG_COR); + udelay(5); + writeb(tmp, lp->base + link->conf.ConfigBase + CISREG_COR); + + return 0; +} + +static int mhz_mfc_config(dev_link_t *link) +{ + struct net_device *dev = link->priv; + struct smc_private *lp = dev->priv; + tuple_t tuple; + cisparse_t parse; + u_char buf[255]; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + win_req_t req; + memreq_t mem; + int i, k; + + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + link->irq.Attributes = + IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts2 = 8; + + tuple.Attributes = tuple.TupleOffset = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + i = first_tuple(link->handle, &tuple, &parse); + /* The Megahertz combo cards have modem-like CIS entries, so + we have to explicitly try a bunch of port combinations. */ + while (i == CS_SUCCESS) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort2 = cf->io.win[0].base; + for (k = 0; k < 0x400; k += 0x10) { + if (k & 0x80) continue; + link->io.BasePort1 = k ^ 0x300; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + if (i == CS_SUCCESS) break; + i = next_tuple(link->handle, &tuple, &parse); + } + if (i != CS_SUCCESS) + return i; + dev->base_addr = link->io.BasePort1; + + /* Allocate a memory window, for accessing the ISR */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = 0; + req.Size = 0x1000; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if (i != CS_SUCCESS) + return i; + lp->base = ioremap(req.Base, 0x1000); + mem.CardOffset = mem.Page = 0; + if (lp->manfid == MANFID_MOTOROLA) + mem.CardOffset = link->conf.ConfigBase; + i = CardServices(MapMemPage, link->win, &mem); + + if ((i == CS_SUCCESS) + && (lp->manfid == MANFID_MEGAHERTZ) + && (lp->cardid == PRODID_MEGAHERTZ_EM3288)) + mhz_3288_power(link); + + return i; +} + +static int mhz_setup(dev_link_t *link) +{ + client_handle_t handle = link->handle; + struct net_device *dev = link->priv; + tuple_t tuple; + cisparse_t parse; + u_char buf[255], *station_addr; + + tuple.Attributes = tuple.TupleOffset = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + + /* Read the station address from the CIS. It is stored as the last + (fourth) string in the Version 1 Version/ID tuple. */ + tuple.DesiredTuple = CISTPL_VERS_1; + if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS) + return -1; + /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ + if (next_tuple(handle, &tuple, &parse) != CS_SUCCESS) + first_tuple(handle, &tuple, &parse); + if (parse.version_1.ns > 3) { + station_addr = parse.version_1.str + parse.version_1.ofs[3]; + if (cvt_ascii_address(dev, station_addr) == 0) + return 0; + } + + /* Another possibility: for the EM3288, in a special tuple */ + tuple.DesiredTuple = 0x81; + if (CardServices(GetFirstTuple, handle, &tuple) != CS_SUCCESS) + return -1; + if (CardServices(GetTupleData, handle, &tuple) != CS_SUCCESS) + return -1; + buf[12] = '\0'; + if (cvt_ascii_address(dev, buf) == 0) + return 0; + + return -1; +} + +/*====================================================================== + + Configuration stuff for the Motorola Mariner + + mot_config() writes directly to the Mariner configuration + registers because the CIS is just bogus. + +======================================================================*/ + +static void mot_config(dev_link_t *link) +{ + struct net_device *dev = link->priv; + struct smc_private *lp = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + ioaddr_t iouart = link->io.BasePort2; + + /* Set UART base address and force map with COR bit 1 */ + writeb(iouart & 0xff, lp->base + MOT_UART + CISREG_IOBASE_0); + writeb((iouart >> 8) & 0xff, lp->base + MOT_UART + CISREG_IOBASE_1); + writeb(MOT_NORMAL, lp->base + MOT_UART + CISREG_COR); + + /* Set SMC base address and force map with COR bit 1 */ + writeb(ioaddr & 0xff, lp->base + MOT_LAN + CISREG_IOBASE_0); + writeb((ioaddr >> 8) & 0xff, lp->base + MOT_LAN + CISREG_IOBASE_1); + writeb(MOT_NORMAL, lp->base + MOT_LAN + CISREG_COR); + + /* Wait for things to settle down */ + mdelay(100); +} + +static int mot_setup(dev_link_t *link) { + struct net_device *dev = link->priv; + ioaddr_t ioaddr = dev->base_addr; + int i, wait, loop; + unsigned int addr; + + /* Read Ethernet address from Serial EEPROM */ + + for (i = 0; i < 3; i++) { + SMC_SELECT_BANK( 2 ); + outw(MOT_EEPROM + i, ioaddr + POINTER); + SMC_SELECT_BANK( 1 ); + outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL); + + for (loop = 0; loop < 200; loop++) { + udelay(10); + wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL)); + if (wait == 0) break; + } + + if (wait) + return -1; + + addr = inw(ioaddr + GENERAL); + dev->dev_addr[2*i] = addr & 0xff; + dev->dev_addr[2*i+1] = (addr >> 8) & 0xff; + } + + return 0; +} + +/*====================================================================*/ + +static int smc_config(dev_link_t *link) +{ + struct net_device *dev = link->priv; + tuple_t tuple; + cisparse_t parse; + u_char buf[255]; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + int i; + + tuple.Attributes = tuple.TupleOffset = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + link->io.NumPorts1 = 16; + i = first_tuple(link->handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if (i == CS_SUCCESS) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + i = next_tuple(link->handle, &tuple, &parse); + } + if (i == CS_SUCCESS) + dev->base_addr = link->io.BasePort1; + return i; +} + +static int smc_setup(dev_link_t *link) +{ + client_handle_t handle = link->handle; + struct net_device *dev = link->priv; + tuple_t tuple; + cisparse_t parse; + cistpl_lan_node_id_t *node_id; + u_char buf[255], *station_addr; + int i; + + tuple.Attributes = tuple.TupleOffset = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + + /* Check for a LAN function extension tuple */ + tuple.DesiredTuple = CISTPL_FUNCE; + i = first_tuple(handle, &tuple, &parse); + while (i == CS_SUCCESS) { + if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID) + break; + i = next_tuple(handle, &tuple, &parse); + } + if (i == CS_SUCCESS) { + node_id = (cistpl_lan_node_id_t *)parse.funce.data; + if (node_id->nb == 6) { + for (i = 0; i < 6; i++) + dev->dev_addr[i] = node_id->id[i]; + return 0; + } + } + + /* Try the third string in the Version 1 Version/ID tuple. */ + tuple.DesiredTuple = CISTPL_VERS_1; + if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS) + return -1; + station_addr = parse.version_1.str + parse.version_1.ofs[2]; + if (cvt_ascii_address(dev, station_addr) == 0) + return 0; + + return -1; +} + +/*====================================================================*/ + +static int osi_config(dev_link_t *link) +{ + struct net_device *dev = link->priv; + static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; + int i, j; + + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + link->irq.Attributes = + IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; + link->io.NumPorts1 = 64; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts2 = 8; + + /* Enable Hard Decode, LAN, Modem */ + link->conf.ConfigIndex = 0x23; + + for (j = 0; j < 4; j++) { + link->io.BasePort2 = com[j]; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) break; + } + if (i != CS_SUCCESS) { + /* Fallback: turn off hard decode */ + link->conf.ConfigIndex = 0x03; + link->io.NumPorts2 = 0; + i = CardServices(RequestIO, link->handle, &link->io); + } + dev->base_addr = link->io.BasePort1 + 0x10; + return i; +} + +static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid) +{ + client_handle_t handle = link->handle; + struct net_device *dev = link->priv; + tuple_t tuple; + u_char buf[255]; + int i; + + tuple.Attributes = TUPLE_RETURN_COMMON; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + /* Read the station address from tuple 0x90, subtuple 0x04 */ + tuple.DesiredTuple = 0x90; + i = CardServices(GetFirstTuple, handle, &tuple); + while (i == CS_SUCCESS) { + i = CardServices(GetTupleData, handle, &tuple); + if ((i != CS_SUCCESS) || (buf[0] == 0x04)) + break; + i = CardServices(GetNextTuple, handle, &tuple); + } + if (i != CS_SUCCESS) + return -1; + for (i = 0; i < 6; i++) + dev->dev_addr[i] = buf[i+2]; + + if (manfid != MANFID_OSITECH) return 0; + + if (cardid == PRODID_OSITECH_SEVEN) { + /* Download the Seven of Diamonds firmware */ + for (i = 0; i < sizeof(__Xilinx7OD); i++) { + outb(__Xilinx7OD[i], link->io.BasePort1+2); + udelay(50); + } + } else { + /* Make sure both functions are powered up */ + set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR); + /* Now, turn on the interrupt for both card functions */ + set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR); + DEBUG(2, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n", + inw(link->io.BasePort1 + OSITECH_AUI_PWR), + inw(link->io.BasePort1 + OSITECH_RESET_ISR)); + } + + return 0; +} + +/*====================================================================== + + This verifies that the chip is some SMC91cXX variant, and returns + the revision code if successful. Otherwise, it returns -ENODEV. + +======================================================================*/ + +static int check_sig(dev_link_t *link) +{ + struct net_device *dev = link->priv; + ioaddr_t ioaddr = dev->base_addr; + int width; + u_short s; + + SMC_SELECT_BANK(1); + if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) { + /* Try powering up the chip */ + outw(0, ioaddr + CONTROL); + mdelay(55); + } + + /* Try setting bus width */ + width = (link->io.Attributes1 == IO_DATA_PATH_WIDTH_AUTO); + s = inb(ioaddr + CONFIG); + if (width) + s |= CFG_16BIT; + else + s &= ~CFG_16BIT; + outb(s, ioaddr + CONFIG); + + /* Check Base Address Register to make sure bus width is OK */ + s = inw(ioaddr + BASE_ADDR); + if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) && + ((s >> 8) != (s & 0xff))) { + SMC_SELECT_BANK(3); + s = inw(ioaddr + REVISION); + return (s & 0xff); + } + + if (width) { + event_callback_args_t args; + printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); + args.client_data = link; + smc91c92_event(CS_EVENT_RESET_PHYSICAL, 0, &args); + CardServices(ReleaseIO, link->handle, &link->io); + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + CardServices(RequestIO, link->handle, &link->io); + smc91c92_event(CS_EVENT_CARD_RESET, 0, &args); + return check_sig(link); + } + return -ENODEV; +} + +/*====================================================================== + + smc91c92_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. + +======================================================================*/ + +#define CS_EXIT_TEST(ret, svc, label) \ +if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; } + +static void smc91c92_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + struct net_device *dev = link->priv; + struct smc_private *lp = dev->priv; + tuple_t tuple; + cisparse_t parse; + u_short buf[32]; + char *name; + int i, rev; + + DEBUG(0, "smc91c92_config(0x%p)\n", link); + + tuple.Attributes = tuple.TupleOffset = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + + tuple.DesiredTuple = CISTPL_CONFIG; + i = first_tuple(handle, &tuple, &parse); + CS_EXIT_TEST(i, ParseTuple, config_failed); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + tuple.DesiredTuple = CISTPL_MANFID; + tuple.Attributes = TUPLE_RETURN_COMMON; + if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + lp->manfid = parse.manfid.manf; + lp->cardid = parse.manfid.card; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + + if (lp->manfid == MANFID_OSITECH) { + i = osi_config(link); + } else if (lp->manfid == MANFID_MOTOROLA + || ((lp->manfid == MANFID_MEGAHERTZ) + && ((lp->cardid == PRODID_MEGAHERTZ_VARIOUS) + || (lp->cardid == PRODID_MEGAHERTZ_EM3288)))) { + i = mhz_mfc_config(link); + } else { + i = smc_config(link); + } + CS_EXIT_TEST(i, RequestIO, config_failed); + + i = CardServices(RequestIRQ, link->handle, &link->irq); + CS_EXIT_TEST(i, RequestIRQ, config_failed); + i = CardServices(RequestConfiguration, link->handle, &link->conf); + CS_EXIT_TEST(i, RequestConfiguration, config_failed); + + if (lp->manfid == MANFID_MOTOROLA) + mot_config(link); + + dev->irq = link->irq.AssignedIRQ; + + if ((if_port >= 0) && (if_port <= 2)) + dev->if_port = if_port; + else + printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n"); + dev->tbusy = 0; + + if (register_netdev(dev) != 0) { + printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); + goto config_undo; + } + + switch (lp->manfid) { + case MANFID_OSITECH: + case MANFID_PSION: + i = osi_setup(link, lp->manfid, lp->cardid); break; + case MANFID_SMC: + case MANFID_NEW_MEDIA: + i = smc_setup(link); break; + case 0x128: /* For broken Megahertz cards */ + case MANFID_MEGAHERTZ: + i = mhz_setup(link); break; + case MANFID_MOTOROLA: + default: /* get the hw address from EEPROM */ + i = mot_setup(link); break; + } + + if (i != 0) { + printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n"); + link->state &= ~DEV_CONFIG_PENDING; + goto config_undo; + } + + link->dev = &lp->node; + link->state &= ~DEV_CONFIG_PENDING; + + rev = check_sig(link); + name = "???"; + if (rev > 0) + switch (rev >> 4) { + case 3: name = "92"; break; + case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break; + case 5: name = "95"; break; + case 7: name = "100"; break; + case 8: name = "100-FD"; break; + } + printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " + "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr, + dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + if (rev > 0) { + u_long mir, mcr, mii; + ioaddr_t ioaddr = dev->base_addr; + SMC_SELECT_BANK(0); + mir = inw(ioaddr + MEMINFO) & 0xff; + if (mir == 0xff) mir++; + /* Get scale factor for memory size */ + mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200; + mir *= 128 * (1<<((mcr >> 9) & 7)); + if (mir & 0x3ff) + printk(KERN_INFO " %lu byte", mir); + else + printk(KERN_INFO " %lu kb", mir>>10); + SMC_SELECT_BANK(1); + mii = inw(ioaddr + CONFIG) & CFG_MII_SELECT; + printk(" buffer, %s xcvr\n", mii ? "MII" : if_names[dev->if_port]); + } + + return; + +config_undo: + unregister_netdev(dev); +config_failed: /* CS_EXIT_TEST() calls jump to here... */ + smc91c92_release((u_long)link); + +} /* smc91c92_config */ + +/*====================================================================== + + After a card is removed, smc91c92_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 smc91c92_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = link->priv; + + DEBUG(0, "smc91c92_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n", + dev->name); + link->state |= DEV_STALE_CONFIG; + return; + } + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + if (link->win) { + struct smc_private *lp = dev->priv; + iounmap(lp->base); + CardServices(ReleaseWindow, link->win); + } + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* smc91c92_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. + +======================================================================*/ + +static int smc91c92_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + + DEBUG(1, "smc91c92_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 1; + dev->start = 0; + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT; + smc91c92_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 1; dev->start = 0; + } + 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) { + struct smc_private *lp = dev->priv; + if ((lp->manfid == MANFID_MEGAHERTZ) && + (lp->cardid == PRODID_MEGAHERTZ_EM3288)) + mhz_3288_power(link); + CardServices(RequestConfiguration, link->handle, &link->conf); + if (lp->manfid == MANFID_MOTOROLA) + mot_config(link); + if ((lp->manfid == MANFID_OSITECH) && + (lp->cardid != PRODID_OSITECH_SEVEN)) { + /* Power up the card and enable interrupts */ + set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); + set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); + } + if (link->open) { + smc_reset(dev); + dev->tbusy = 0; dev->start = 1; + } + } + break; + } + return 0; +} /* smc91c92_event */ + +/*====================================================================== + + The driver core code, most of which should be common with a + non-PCMCIA implementation. + +======================================================================*/ + +#ifdef PCMCIA_DEBUG +static void smc_dump(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + u_short i, w, save; + save = inw(ioaddr + BANK_SELECT); + for (w = 0; w < 4; w++) { + SMC_SELECT_BANK(w); + printk(KERN_DEBUG "bank %d: ", w); + for (i = 0; i < 14; i += 2) + printk(" %04x", inw(ioaddr + i)); + printk("\n"); + } + outw(save, ioaddr + BANK_SELECT); +} +#endif + +static int smc91c92_open(struct net_device *dev) +{ + struct smc_private *lp = (struct smc_private *)dev->priv; + dev_link_t *link; + +#ifdef PCMCIA_DEBUG + DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n", + dev->name, dev, inw(dev->base_addr + BANK_SELECT)); + if (pc_debug > 1) smc_dump(dev); +#endif + + /* Check that the PCMCIA card is still here. */ + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + /* Physical device present signature. */ + if (!DEV_OK(link)) + return -ENODEV; + if (check_sig(link) < 0) { + printk("smc91c92_cs: Yikes! Bad chip signature!\n"); + return -ENODEV; + } + link->open++; + MOD_INC_USE_COUNT; + + dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + lp->saved_skb = 0; + lp->packets_waiting = 0; + + smc_reset(dev); + lp->media.function = &media_check; + lp->media.data = (u_long)dev; + lp->media.expires = jiffies + HZ; + add_timer(&lp->media); + + return 0; +} /* smc91c92_open */ + +/*====================================================================*/ + +static int smc91c92_close(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + dev_link_t *link; + + DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n", + dev->name, inw(ioaddr + BANK_SELECT)); + + dev->tbusy = 1; + dev->start = 0; + + /* Shut off all interrupts, and turn off the Tx and Rx sections. + Don't bother to check for chip present. */ + SMC_SELECT_BANK( 2 ); /* Nominally paranoia, but do no assume... */ + outw(0, ioaddr + INTERRUPT); + SMC_SELECT_BANK( 0 ); + mask_bits(0xff00, ioaddr + RCR); + mask_bits(0xff00, ioaddr + TCR); + + /* Put the chip into power-down mode. */ + SMC_SELECT_BANK( 1 ); + outw(CTL_POWERDOWN, ioaddr + CONTROL ); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + link->open--; dev->start = 0; + del_timer(&((struct smc_private *)dev->priv)->media); + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + + return 0; +} /* smc91c92_close */ + +/*====================================================================== + + Transfer a packet to the hardware and trigger the packet send. + This may be called at either from either the Tx queue code + or the interrupt handler. + +======================================================================*/ + +static void smc_hardware_send_packet( struct net_device * dev ) +{ + struct smc_private *lp = (struct smc_private *)dev->priv; + struct sk_buff *skb = lp->saved_skb; + ioaddr_t ioaddr = dev->base_addr; + unsigned char packet_no; + + if ( !skb ) { + printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name); + return; + } + + /* There should be a packet slot waiting. */ + packet_no = inw(ioaddr + PNR_ARR) >> 8; + if ( packet_no & 0x80 ) { + /* If not, there is a hardware problem! Likely an ejected card. */ + printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation" + " failed, status %#2.2x.\n", dev->name, packet_no); + dev_kfree_skb (skb); + lp->saved_skb = NULL; + dev->tbusy = 0; + return; + } + + lp->stats.tx_bytes += skb->len; + /* The card should use the just-allocated buffer. */ + outw( packet_no, ioaddr + PNR_ARR ); + /* point to the beginning of the packet */ + outw( PTR_AUTOINC , ioaddr + POINTER ); + + /* Send the packet length ( +6 for status, length and ctl byte ) + and the status word ( set to zeros ). */ + { + unsigned char *buf = skb->data; + int length = skb->len; /* The chip will pad to ethernet min length. */ + + DEBUG(2, "%s: Trying to xmit packet of length %d.\n", + dev->name, length); + +#ifdef USE_32_BIT + outl((length+6) << 16, ioaddr + DATA_1); + if (length & 0x2) { + outsl(ioaddr + DATA_1, buf, length >> 2 ); + outw( *((uint16 *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); + } else + outsl(ioaddr + DATA_1, buf, length >> 2 ); +#else + /* send the packet length: +6 for status words, length, and ctl */ + outw( 0, ioaddr + DATA_1 ); + outw(length + 6, ioaddr + DATA_1 ); + outsw(ioaddr + DATA_1 , buf, length >> 1); +#endif + + /* The odd last byte, if there is one, goes in the control word. */ + outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1 ); + } + + /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */ + outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) | + (inw(ioaddr + INTERRUPT) & 0xff00), + ioaddr + INTERRUPT); + + /* The chip does the rest of the work. */ + outw( MC_ENQUEUE , ioaddr + MMU_CMD ); + + lp->saved_skb = NULL; + dev_kfree_skb (skb); + dev->trans_start = jiffies; + dev->tbusy = 0; + return; +} + +/*====================================================================*/ + +static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct smc_private *lp = (struct smc_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + unsigned short num_pages; + short time_out, ir; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < TX_TIMEOUT) + return 1; + printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, " + "Tx_status %2.2x status %4.4x.\n", + dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2)); + lp->stats.tx_errors++; + smc_reset(dev); + dev->trans_start = jiffies; + dev->tbusy = 0; + lp->saved_skb = NULL; + } + + DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called," + " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2)); + + /* Avoid timer-based retransmission conflicts. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk(KERN_ERR "%s: transmitter access conflict.\n", dev->name); + return 1; + } + + if ( lp->saved_skb) { + /* THIS SHOULD NEVER HAPPEN. */ + lp->stats.tx_aborted_errors++; + printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n", + dev->name); + return 1; + } + lp->saved_skb = skb; + + num_pages = skb->len >> 8; + + if (num_pages > 7) { + printk(KERN_ERR "%s: Far too big packet error.\n", dev->name); + dev_kfree_skb (skb); + lp->saved_skb = NULL; + lp->stats.tx_dropped++; + return 0; /* Do not re-queue this packet. */ + } + /* A packet is now waiting. */ + lp->packets_waiting++; + + SMC_SELECT_BANK( 2 ); /* Paranoia, we should always be in window 2 */ + + /* Allocate the memory; send the packet now if we win. */ + outw( MC_ALLOC | num_pages, ioaddr + MMU_CMD ); + for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) { + ir = inw(ioaddr+INTERRUPT); + if (ir & IM_ALLOC_INT) { + /* Acknowledge the interrupt, send the packet. */ + outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT); + smc_hardware_send_packet(dev); /* Send the packet now.. */ + return 0; + } + } + + /* Otherwise defer until the Tx-space-allocated interrupt. */ + DEBUG(2, "%s: memory allocation deferred.\n", dev->name); + outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); + + return 0; +} + +/*====================================================================== + + Handle a Tx anomolous event. Entered while in Window 2. + +======================================================================*/ + +static void smc_tx_err( struct net_device * dev ) +{ + struct smc_private *lp = (struct smc_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int saved_packet = inw(ioaddr + PNR_ARR) & 0xff; + int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f; + int tx_status; + + /* select this as the packet to read from */ + outw( packet_no, ioaddr + PNR_ARR ); + + /* read the first word from this packet */ + outw( PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER ); + + tx_status = inw(ioaddr + DATA_1); + + lp->stats.tx_errors++; + if (tx_status & TS_LOSTCAR) lp->stats.tx_carrier_errors++; + if (tx_status & TS_LATCOL) lp->stats.tx_window_errors++; + if (tx_status & TS_16COL) { + lp->stats.tx_aborted_errors++; + lp->tx_err++; + } + + if ( tx_status & TS_SUCCESS ) { + printk(KERN_NOTICE "%s: Successful packet caused error " + "interrupt?\n", dev->name); + } + /* re-enable transmit */ + SMC_SELECT_BANK( 0 ); + outw( inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR); + SMC_SELECT_BANK( 2 ); + + outw( MC_FREEPKT, ioaddr + MMU_CMD ); /* Free the packet memory. */ + + /* one less packet waiting for me */ + lp->packets_waiting--; + + outw( saved_packet, ioaddr + PNR_ARR ); + return; +} + +/*====================================================================*/ + +static void smc_eph_irq(struct net_device *dev) +{ + struct smc_private *lp = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + unsigned short card_stats, ephs; + + SMC_SELECT_BANK(0); + ephs = inw(ioaddr + EPH); + DEBUG(2, "%s: Ethernet protocol handler interrupt, status" + " %4.4x.\n", dev->name, ephs); + /* Could be a counter roll-over warning: update stats. */ + card_stats = inw( ioaddr + COUNTER ); + /* single collisions */ + lp->stats.collisions += card_stats & 0xF; + card_stats >>= 4; + /* multiple collisions */ + lp->stats.collisions += card_stats & 0xF; +#if 0 /* These are for when linux supports these statistics */ + card_stats >>= 4; /* deferred */ + card_stats >>= 4; /* excess deferred */ +#endif + /* If we had a transmit error we must re-enable the transmitter. */ + outw( inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR); + + /* Clear a link error interrupt. */ + SMC_SELECT_BANK(1); + outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL); + outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, + ioaddr + CONTROL); + SMC_SELECT_BANK(2); +} + +/*====================================================================*/ + +static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct smc_private *lp; + ioaddr_t ioaddr; + u_short saved_bank, saved_pointer, mask, status; + char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ + + if ((dev == NULL) || !dev->start) + return; + ioaddr = dev->base_addr; + +#ifdef PCMCIA_DEBUG + if (dev->interrupt) { + printk(KERN_ERR "%s: re-entering the interrupt handler.\n", + dev->name); + return; + } + dev->interrupt = 1; + + DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name, + irq, ioaddr); +#endif + + lp = (struct smc_private *)dev->priv; + lp->watchdog = 0; + saved_bank = inw(ioaddr + BANK_SELECT); + if ((saved_bank & 0xff00) != 0x3300) { + /* The device does not exist -- the card could be off-line, or + maybe it has been ejected. */ +#ifdef PCMCIA_DEBUG + if (dev->start) + DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent" + "/ejected device.\n", dev->name, irq); + dev->interrupt = 0; +#endif + goto irq_done; + } + + SMC_SELECT_BANK(2); + saved_pointer = inw(ioaddr + POINTER); + mask = inw(ioaddr + INTERRUPT) >> 8; + /* clear all interrupts */ + outw( 0, ioaddr + INTERRUPT ); + + do { /* read the status flag, and mask it */ + status = inw(ioaddr + INTERRUPT) & 0xff; + DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name, + status, mask); + if ((status & mask) == 0) + break; + + if (status & IM_RCV_INT) { + /* Got a packet(s). */ + smc_rx(dev); + lp->last_rx = jiffies; + } + if (status & IM_TX_INT) { + smc_tx_err(dev); + outw(IM_TX_INT, ioaddr + INTERRUPT); + } + status &= mask; + if (status & IM_TX_EMPTY_INT) { + outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT); + mask &= ~IM_TX_EMPTY_INT; + lp->stats.tx_packets += lp->packets_waiting; + lp->packets_waiting = 0; + } + if (status & IM_ALLOC_INT) { + /* Clear this interrupt so it doesn't happen again */ + mask &= ~IM_ALLOC_INT; + + smc_hardware_send_packet(dev); + + /* enable xmit interrupts based on this */ + mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); + + /* and let the card send more packets to me */ + mark_bh( NET_BH ); + } + if (status & IM_RX_OVRN_INT) { + lp->stats.rx_errors++; + lp->stats.rx_fifo_errors++; + outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT); + } + if (status & IM_EPH_INT) + smc_eph_irq(dev); + } while ( --bogus_cnt); + + DEBUG(3, " Restoring saved registers mask %2.2x bank %4.4x" + " pointer %4.4x.\n", mask, saved_bank, saved_pointer); + + /* restore state register */ + outw((mask<<8), ioaddr + INTERRUPT); + outw(saved_pointer, ioaddr + POINTER); + SMC_SELECT_BANK( saved_bank ); + +#ifdef PCMCIA_DEBUG + dev->interrupt = 0; + DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq); +#endif + +irq_done: + + if ((lp->manfid == MANFID_OSITECH) && + (lp->cardid != PRODID_OSITECH_SEVEN)) { + /* Retrigger interrupt if needed */ + mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR); + set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR); + } + if (lp->manfid == MANFID_MOTOROLA) { + u_char cor; + cor = readb(lp->base + MOT_UART + CISREG_COR); + writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_UART + CISREG_COR); + writeb(cor, lp->base + MOT_UART + CISREG_COR); + cor = readb(lp->base + MOT_LAN + CISREG_COR); + writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_LAN + CISREG_COR); + writeb(cor, lp->base + MOT_LAN + CISREG_COR); + } +#ifdef DOES_NOT_WORK + if (lp->base != NULL) { /* Megahertz MFC's */ + readb(lp->base+MEGAHERTZ_ISR); + readb(lp->base+MEGAHERTZ_ISR); + } +#endif +} + +/*====================================================================*/ + +static void smc_rx(struct net_device *dev) +{ + struct smc_private *lp = (struct smc_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int rx_status; + int packet_length; /* Caution: not frame length, rather words + to transfer from the chip. */ + + /* Assertion: we are in Window 2. */ + + if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) { + printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n", + dev->name); + return; + } + + /* Reset the read pointer, and read the status and packet length. */ + outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER ); + rx_status = inw(ioaddr + DATA_1); + packet_length = inw(ioaddr + DATA_1) & 0x07ff; + + DEBUG(2, "%s: Receive status %4.4x length %d.\n", + dev->name, rx_status, packet_length); + + if ( !(rx_status & RS_ERRORS )) { + /* do stuff to make a new packet */ + struct sk_buff *skb; + + /* Note: packet_length adds 5 or 6 extra bytes here! */ + skb = dev_alloc_skb(packet_length+2); + + if ( skb == NULL ) { + DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name); + lp->stats.rx_dropped++; + outw( MC_RELEASE, ioaddr + MMU_CMD ); + return; + } + + packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6); + skb_reserve(skb, 2); + insw(ioaddr+DATA_1, skb_put(skb, packet_length), + (packet_length+1)>>1); + skb->protocol = eth_type_trans(skb, dev); + + skb->dev = dev; + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + if (rx_status & RS_MULTICAST) + lp->stats.multicast++; + } else { + /* error ... */ + lp->stats.rx_errors++; + + if (rx_status & RS_ALGNERR) lp->stats.rx_frame_errors++; + if (rx_status & (RS_TOOSHORT | RS_TOOLONG)) + lp->stats.rx_length_errors++; + if (rx_status & RS_BADCRC) lp->stats.rx_crc_errors++; + } + /* Let the MMU free the memory of this packet. */ + outw(MC_RELEASE, ioaddr + MMU_CMD); + + return; +} + +/*====================================================================*/ + +static struct net_device_stats *smc91c92_get_stats(struct net_device *dev) +{ + struct smc_private *lp = (struct smc_private *)dev->priv; + /* Nothing to update - the 91c92 is a pretty primative chip. */ + return &lp->stats; +} + +/*====================================================================== + + Compute the AUTODIN polynomial "CRC32" for ethernet packets. + +======================================================================*/ + +static unsigned const ethernet_polynomial = 0x04c11db7U; + +static unsigned ether_crc(int length, unsigned char *data) +{ + int crc = 0xffffffff; /* Initial value. */ + + 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); + } + } + /* The hash index is the either the upper or lower bits of the CRC, so + * we return the entire CRC. + */ + return crc; +} + +/*====================================================================== + + Calculate values for the hardware multicast filter hash table. + +======================================================================*/ + +static void fill_multicast_tbl(int count, struct dev_mc_list *addrs, + unsigned char *multicast_table) +{ + struct dev_mc_list *mc_addr; + + for (mc_addr = addrs; mc_addr && --count > 0; mc_addr = mc_addr->next) { + unsigned int position = ether_crc(6, mc_addr->dmi_addr); +#ifndef final_version /* Verify multicast address. */ + if ( (mc_addr->dmi_addr[0] & 1) == 0) + continue; +#endif + multicast_table[position >> 29] |= 1 << ((position >> 26) & 7); + } +} + +/*====================================================================== + + Set the receive mode. + + This routine is used by both the protocol level to notify us of + promiscuous/multicast mode changes, and by the open/reset code to + initialize the Rx registers. We always set the multicast list and + leave the receiver running. + +======================================================================*/ + +static void set_rx_mode(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + unsigned int multicast_table[ 2 ] = { 0, }; + long flags; + uint16 rx_cfg_setting; + + if (dev->flags & IFF_PROMISC) { + printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name); + rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti; + } else if (dev->flags & IFF_ALLMULTI) + rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti; + else { + if (dev->mc_count) { + fill_multicast_tbl(dev->mc_count, dev->mc_list, + (unsigned char *)multicast_table); + } + rx_cfg_setting = RxStripCRC | RxEnable; + } + + /* Load MC table and Rx setting into the chip without interrupts. */ + save_flags(flags); + cli(); + SMC_SELECT_BANK( 3 ); + outl(multicast_table[0], ioaddr + MULTICAST0); + outl(multicast_table[1], ioaddr + MULTICAST4); + SMC_SELECT_BANK(0); + outw(rx_cfg_setting, ioaddr + RCR); + SMC_SELECT_BANK(2); + restore_flags(flags); + + return; +} + +/*====================================================================== + + Senses when a card's config changes. Here, it's coax or TP. + +======================================================================*/ + +static int s9k_config(struct net_device *dev, struct ifmap *map) +{ + if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { + if (map->port <= 2) { + dev->if_port = map->port; + printk(KERN_INFO "%s: switched to %s port\n", + dev->name, if_names[dev->if_port]); + } else + return -EINVAL; + } + smc_reset(dev); + return 0; +} + +/*====================================================================== + + Reset the chip, reloading every register that might be corrupted. + +======================================================================*/ + +/* + Set transceiver type, perhaps to something other than what the user + specified in dev->if_port. +*/ +static void smc_set_xcvr(struct net_device *dev, int if_port) +{ + struct smc_private *lp = (struct smc_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + u_short saved_bank; + + saved_bank = inw(ioaddr + BANK_SELECT); + SMC_SELECT_BANK(1); + if (if_port == 2) { + outw(lp->cfg | CFG_AUI_SELECT, ioaddr + CONFIG); + if ((lp->manfid == MANFID_OSITECH) && + (lp->cardid != PRODID_OSITECH_SEVEN)) + set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); + lp->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002); + } else { + outw(lp->cfg, ioaddr + CONFIG); + if ((lp->manfid == MANFID_OSITECH) && + (lp->cardid != PRODID_OSITECH_SEVEN)) + mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); + lp->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001); + } + SMC_SELECT_BANK(saved_bank); +} + +static void smc_reset(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + struct smc_private *lp = dev->priv; + int i; + + DEBUG(0, "%s: smc91c92 reset called.\n", dev->name); + + /* The first interaction must be a write to bring the chip out + of sleep mode. */ + SMC_SELECT_BANK( 0 ); + /* Reset the chip. */ + outw( RCR_SOFTRESET, ioaddr + RCR ); + udelay(10); + + /* Clear the transmit and receive configuration registers. */ + outw( RCR_CLEAR, ioaddr + RCR ); + outw( TCR_CLEAR, ioaddr + TCR ); + + /* Set the Window 1 control, configuration and station addr registers. + No point in writing the I/O base register ;-> */ + SMC_SELECT_BANK(1); + /* Automatically release succesfully transmitted packets, + Accept link errors, counter and Tx error interrupts. */ + outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, + ioaddr + CONTROL); + lp->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; + lp->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC | + (lp->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0); + smc_set_xcvr(dev, dev->if_port); + if ((lp->manfid == MANFID_OSITECH) && + (lp->cardid != PRODID_OSITECH_SEVEN)) + outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) | + (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00), + ioaddr - 0x10 + OSITECH_AUI_PWR); + + /* Fill in the physical address. The databook is wrong about the order! */ + for (i = 0; i < 6; i += 2) + outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i], + ioaddr + ADDR0 + i); + + /* Reset the MMU */ + SMC_SELECT_BANK(2); + outw(MC_RESET, ioaddr + MMU_CMD ); + outw(0, ioaddr + INTERRUPT ); + + /* Re-enable the chip. */ + SMC_SELECT_BANK(0); + outw(((lp->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) | + TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR); + set_rx_mode(dev); + + /* Enable interrupts. */ + SMC_SELECT_BANK( 2 ); + outw( (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8, + ioaddr + INTERRUPT ); +} + +/*====================================================================== + + Media selection timer routine + +======================================================================*/ + +static void media_check(u_long arg) +{ + struct net_device *dev = (struct net_device *)(arg); + struct smc_private *lp = (struct smc_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; + u_short i, media, saved_bank; + + if (dev->start == 0) goto reschedule; + + lp = (struct smc_private *)dev->priv; + saved_bank = inw(ioaddr + BANK_SELECT); + SMC_SELECT_BANK(2); + i = inw(ioaddr + INTERRUPT); + SMC_SELECT_BANK(0); + media = inw(ioaddr + EPH) & EPH_LINK_OK; + SMC_SELECT_BANK(1); + media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1; + SMC_SELECT_BANK(saved_bank); + + /* Check for pending interrupt with watchdog flag set: with + this, we can limp along even if the interrupt is blocked */ + if (lp->watchdog++ && ((i>>8) & i)) { + if (!lp->fast_poll) + printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); + smc_interrupt(dev->irq, dev, NULL); + lp->fast_poll = HZ; + } + if (lp->fast_poll) { + lp->fast_poll--; + lp->media.expires = jiffies + 1; + add_timer(&lp->media); + return; + } + + if (lp->cfg & CFG_MII_SELECT) + goto reschedule; + + /* Ignore collisions unless we've had no rx's recently */ + if (jiffies - lp->last_rx > HZ) { + if (lp->tx_err || (lp->media_status & EPH_16COL)) + media |= EPH_16COL; + } + lp->tx_err = 0; + + if (media != lp->media_status) { + if ((media & lp->media_status & 1) && + ((lp->media_status ^ media) & EPH_LINK_OK)) + printk(KERN_INFO "%s: %s link beat\n", dev->name, + (lp->media_status & EPH_LINK_OK ? "lost" : "found")); + else if ((media & lp->media_status & 2) && + ((lp->media_status ^ media) & EPH_16COL)) + printk(KERN_INFO "%s: coax cable %s\n", dev->name, + (media & EPH_16COL ? "problem" : "ok")); + if (dev->if_port == 0) { + if (media & 1) { + if (media & EPH_LINK_OK) + printk(KERN_INFO "%s: flipped to 10baseT\n", + dev->name); + else + smc_set_xcvr(dev, 2); + } else { + if (media & EPH_16COL) + smc_set_xcvr(dev, 1); + else + printk(KERN_INFO "%s: flipped to 10base2\n", + dev->name); + } + } + lp->media_status = media; + } + +reschedule: + lp->media.expires = jiffies + HZ; + add_timer(&lp->media); +} + +/*====================================================================*/ + +static int __init init_smc91c92_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_ERR + "smc91c92_cs: Card Services release does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &smc91c92_attach, &smc91c92_detach); + return 0; +} + +static void __exit exit_smc91c92_cs(void) +{ + DEBUG(0, "smc91c92_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + smc91c92_detach(dev_list); +} + +module_init(init_smc91c92_cs); +module_exit(exit_smc91c92_cs); diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h --- v2.3.22/linux/drivers/net/pcmcia/wavelan.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/wavelan.h Wed Oct 20 21:33:12 1999 @@ -0,0 +1,383 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganization and extension of the driver. + * Original copyright follow. See wavelan_cs.h for details. + * + * This file contain the declarations of the Wavelan hardware. Note that + * the Pcmcia Wavelan include a i82593 controler (see definitions in + * file i82593.h). + * + * The main difference between the pcmcia hardware and the ISA one is + * the Ethernet Controler (i82593 instead of i82586). The i82593 allow + * only one send buffer. The PSA (Parameter Storage Area : EEprom for + * permanent storage of various info) is memory mapped, but not the + * MMI (Modem Management Interface). + */ + +/* + * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: + * An Ethernet-like radio transceiver controlled by an Intel 82593 + * coprocessor. + * + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + * + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for + * providing extremely useful information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + */ + +#ifndef _WAVELAN_H +#define _WAVELAN_H + +/************************** MAGIC NUMBERS ***************************/ + +/* The detection of the wavelan card is made by reading the MAC address + * from the card and checking it. If you have a non AT&T product (OEM, + * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this + * part to accomodate your hardware... + */ +const unsigned char MAC_ADDRESSES[][3] = +{ + { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ + { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ + /* Add your card here and send me the patch ! */ +}; + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + +/*************************** PC INTERFACE ****************************/ + +/* WaveLAN host interface definitions */ + +#define LCCR(base) (base) /* LAN Controller Command Register */ +#define LCSR(base) (base) /* LAN Controller Status Register */ +#define HACR(base) (base+0x1) /* Host Adapter Command Register */ +#define HASR(base) (base+0x1) /* Host Adapter Status Register */ +#define PIORL(base) (base+0x2) /* Program I/O Register Low */ +#define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ +#define PIORH(base) (base+0x3) /* Program I/O Register High */ +#define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ +#define PIOP(base) (base+0x4) /* Program I/O Port */ +#define MMR(base) (base+0x6) /* MMI Address Register */ +#define MMD(base) (base+0x7) /* MMI Data Register */ + +/* Host Adaptor Command Register bit definitions */ + +#define HACR_LOF (1 << 3) /* Lock Out Flag, toggle every 250ms */ +#define HACR_PWR_STAT (1 << 4) /* Power State, 1=active, 0=sleep */ +#define HACR_TX_DMA_RESET (1 << 5) /* Reset transmit DMA ptr on high */ +#define HACR_RX_DMA_RESET (1 << 6) /* Reset receive DMA ptr on high */ +#define HACR_ROM_WEN (1 << 7) /* EEPROM write enabled when true */ + +#define HACR_RESET (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET) +#define HACR_DEFAULT (HACR_PWR_STAT) + +/* Host Adapter Status Register bit definitions */ + +#define HASR_MMI_BUSY (1 << 2) /* MMI is busy when true */ +#define HASR_LOF (1 << 3) /* Lock out flag status */ +#define HASR_NO_CLK (1 << 4) /* active when modem not connected */ + +/* Miscellaneous bit definitions */ + +#define PIORH_SEL_TX (1 << 5) /* PIOR points to 0=rx/1=tx buffer */ +#define MMR_MMI_WR (1 << 0) /* Next MMI cycle is 0=read, 1=write */ +#define PIORH_MASK 0x1f /* only low 5 bits are significant */ +#define RPLH_MASK 0x1f /* only low 5 bits are significant */ +#define MMI_ADDR_MASK 0x7e /* Bits 1-6 of MMR are significant */ + +/* Attribute Memory map */ + +#define CIS_ADDR 0x0000 /* Card Information Status Register */ +#define PSA_ADDR 0x0e00 /* Parameter Storage Area address */ +#define EEPROM_ADDR 0x1000 /* EEPROM address (unused ?) */ +#define COR_ADDR 0x4000 /* Configuration Option Register */ + +/* Configuration Option Register bit definitions */ + +#define COR_CONFIG (1 << 0) /* Config Index, 0 when unconfigured */ +#define COR_SW_RESET (1 << 7) /* Software Reset on true */ +#define COR_LEVEL_IRQ (1 << 6) /* Level IRQ */ + +/* Local Memory map */ + +#define RX_BASE 0x0000 /* Receive memory, 8 kB */ +#define TX_BASE 0x2000 /* Transmit memory, 2 kB */ +#define UNUSED_BASE 0x2800 /* Unused, 22 kB */ +#define RX_SIZE (TX_BASE-RX_BASE) /* Size of receive area */ +#define RX_SIZE_SHIFT 6 /* Bits to shift in stop register */ + +#define TRUE 1 +#define FALSE 0 + +#define MOD_ENAL 1 +#define MOD_PROM 2 + +/* Size of a MAC address */ +#define WAVELAN_ADDR_SIZE 6 + +/* Maximum size of Wavelan packet */ +#define WAVELAN_MTU 1500 + +#define MAXDATAZ (6 + 6 + 2 + WAVELAN_MTU) + +/********************** PARAMETER STORAGE AREA **********************/ + +/* + * Parameter Storage Area (PSA). + */ +typedef struct psa_t psa_t; +struct psa_t +{ + /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */ + unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ + unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ + unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ + unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ + unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ + unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ + unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ + unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ + unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ + unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ + + unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ + unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ + unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ +#define PSA_UNIVERSAL 0 /* Universal (factory) */ +#define PSA_LOCAL 1 /* Local */ + unsigned char psa_comp_number; /* [0x1D] Compatability Number: */ +#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ +#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ +#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ +#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ +#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ + unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ + unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ +#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ + unsigned char psa_subband; /* [0x20] Subband */ +#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ +#define PSA_SUBBAND_2425 1 /* 2425 MHz */ +#define PSA_SUBBAND_2460 2 /* 2460 MHz */ +#define PSA_SUBBAND_2484 3 /* 2484 MHz */ +#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ + unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ + unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ + unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ + unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */ + unsigned char psa_encryption_select; /* [0x26] Encryption On Off */ + unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ + unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ + unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ + unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ + unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ + unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ + unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ + unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ +}; + +/* Size for structure checking (if padding is correct) */ +#define PSA_SIZE 64 + +/* Calculate offset of a field in the above structure + * Warning : only even addresses are used */ +#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) + +/******************** MODEM MANAGEMENT INTERFACE ********************/ + +/* + * Modem Management Controller (MMC) write structure. + */ +typedef struct mmw_t mmw_t; +struct mmw_t +{ + unsigned char mmw_encr_key[8]; /* encryption key */ + unsigned char mmw_encr_enable; /* enable/disable encryption */ +#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ +#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ + unsigned char mmw_unused0[1]; /* unused */ + unsigned char mmw_des_io_invert; /* Encryption option */ +#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */ +#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */ + unsigned char mmw_unused1[5]; /* unused */ + unsigned char mmw_loopt_sel; /* looptest selection */ +#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */ +#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */ +#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */ +#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ +#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ +#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ +#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ + unsigned char mmw_jabber_enable; /* jabber timer enable */ + /* Abort transmissions > 200 ms */ + unsigned char mmw_freeze; /* freeze / unfreeeze signal level */ + /* 0 : signal level & qual updated for every new message, 1 : frozen */ + unsigned char mmw_anten_sel; /* antenna selection */ +#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ +#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ + unsigned char mmw_ifs; /* inter frame spacing */ + /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ + unsigned char mmw_mod_delay; /* modem delay (synchro) */ + unsigned char mmw_jam_time; /* jamming time (after collision) */ + unsigned char mmw_unused2[1]; /* unused */ + unsigned char mmw_thr_pre_set; /* level threshold preset */ + /* Discard all packet with signal < this value (4) */ + unsigned char mmw_decay_prm; /* decay parameters */ + unsigned char mmw_decay_updat_prm; /* decay update parameterz */ + unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ + /* Discard all packet with quality < this value (3) */ + unsigned char mmw_netw_id_l; /* NWID low order byte */ + unsigned char mmw_netw_id_h; /* NWID high order byte */ + /* Network ID or Domain : create virtual net on the air */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmw_mode_select; /* for analog tests (set to 0) */ + unsigned char mmw_unused3[1]; /* unused */ + unsigned char mmw_fee_ctrl; /* frequency eeprom control */ +#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */ +#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */ +#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */ +#define MMW_FEE_CTRL_READ 0x06 /* Read */ +#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ +#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */ +#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */ +#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ +#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ +#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ +#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */ +#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */ +#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ + /* Never issue this command (PRDS) : it's irreversible !!! */ + + unsigned char mmw_fee_addr; /* EEprom address */ +#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */ +#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ +#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ +#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ +#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ +#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ + + unsigned char mmw_fee_data_l; /* Write data to EEprom */ + unsigned char mmw_fee_data_h; /* high octet */ + unsigned char mmw_ext_ant; /* Setting for external antenna */ +#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ +#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ +#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ +#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ +#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ +}; + +/* Size for structure checking (if padding is correct) */ +#define MMW_SIZE 37 + +/* Calculate offset of a field in the above structure */ +#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + +/* + * Modem Management Controller (MMC) read structure. + */ +typedef struct mmr_t mmr_t; +struct mmr_t +{ + unsigned char mmr_unused0[8]; /* unused */ + unsigned char mmr_des_status; /* encryption status */ + unsigned char mmr_des_avail; /* encryption available (0x55 read) */ +#define MMR_DES_AVAIL_DES 0x55 /* DES available */ +#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ + unsigned char mmr_des_io_invert; /* des I/O invert register */ + unsigned char mmr_unused1[5]; /* unused */ + unsigned char mmr_dce_status; /* DCE status */ +#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ +#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ +#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ +#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ + unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */ + unsigned char mmr_unused2[2]; /* unused */ + unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */ + unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */ + /* Warning : Read high order octet first !!! */ + unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */ + unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */ + unsigned char mmr_thr_pre_set; /* level threshold preset */ +#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ +#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ + unsigned char mmr_signal_lvl; /* signal level */ +#define MMR_SIGNAL_LVL 0x3F /* signal level */ +#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_silence_lvl; /* silence level (noise) */ +#define MMR_SILENCE_LVL 0x3F /* silence level */ +#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_sgnl_qual; /* signal quality */ +#define MMR_SGNL_QUAL 0x0F /* signal quality */ +#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ + unsigned char mmr_netw_id_l; /* NWID low order byte ??? */ + unsigned char mmr_unused3[3]; /* unused */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmr_fee_status; /* Status of frequency eeprom */ +#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */ +#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ +#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */ + unsigned char mmr_unused4[1]; /* unused */ + unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */ + unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */ +}; + +/* Size for structure checking (if padding is correct) */ +#define MMR_SIZE 36 + +/* Calculate offset of a field in the above structure */ +#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + +/* Make the two above structures one */ +typedef union mm_t +{ + struct mmw_t w; /* Write to the mmc */ + struct mmr_t r; /* Read from the mmc */ +} mm_t; + +#endif /* _WAVELAN_H */ diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c --- v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/wavelan_cs.c Wed Oct 20 21:33:12 1999 @@ -0,0 +1,4856 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follow. See wavelan_cs.h for details. + * + * This code is derived from Anthony D. Joseph's code and all the changes here + * are also under the original copyright below. + * + * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and + * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services + * + * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added + * critical code in the routine to initialize the Modem Management Controller. + * + * Thanks to Alan Cox and Bruce Janson for their advice. + * + * -- Yunzhou Li (scip4166@nus.sg) + * +#ifdef WAVELAN_ROAMING + * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) + * based on patch by Joe Finney from Lancaster University. +#endif :-) + * + * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An + * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. + * + * A non-shared memory PCMCIA ethernet driver for linux + * + * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu) + * + * + * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu) + * + * Apr 2 '98 made changes to bring the i82593 control/int handling in line + * with offical specs... + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + */ + +#include "wavelan_cs.h" /* Private header */ + +/************************* MISC SUBROUTINES **************************/ +/* + * Subroutines which won't fit in one of the following category + * (wavelan modem or i82593) + */ + +/*------------------------------------------------------------------*/ +/* + * Wrapper for disabling interrupts. + */ +static inline unsigned long +wv_splhi(void) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + return(flags); +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts. + */ +static inline void +wv_splx(unsigned long flags) +{ + restore_flags(flags); +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for reporting error to cardservices + */ +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +#ifdef STRUCT_CHECK +/*------------------------------------------------------------------*/ +/* + * Sanity routine to verify the sizes of the various WaveLAN interface + * structures. + */ +static char * +wv_structuct_check(void) +{ +#define SC(t,s,n) if (sizeof(t) != s) return(n); + + SC(psa_t, PSA_SIZE, "psa_t"); + SC(mmw_t, MMW_SIZE, "mmw_t"); + SC(mmr_t, MMR_SIZE, "mmr_t"); + +#undef SC + + return((char *) NULL); +} /* wv_structuct_check */ +#endif /* STRUCT_CHECK */ + +/******************* MODEM MANAGEMENT SUBROUTINES *******************/ +/* + * Usefull subroutines to manage the modem of the wavelan + */ + +/*------------------------------------------------------------------*/ +/* + * Read from card's Host Adaptor Status Register. + */ +static inline u_char +hasr_read(u_long base) +{ + return(inb(HASR(base))); +} /* hasr_read */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. + */ +static inline void +hacr_write(u_long base, + u_char hacr) +{ + outb(hacr, HACR(base)); +} /* hacr_write */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. Include a delay for + * those times when it is needed. + */ +static inline void +hacr_write_slow(u_long base, + u_char hacr) +{ + hacr_write(base, hacr); + /* delay might only be needed sometimes */ + udelay(1000L); +} /* hacr_write_slow */ + +/*------------------------------------------------------------------*/ +/* + * Read the Parameter Storage Area from the WaveLAN card's memory + */ +static void +psa_read(device * dev, + int o, /* offset in PSA */ + u_char * b, /* buffer to fill */ + int n) /* size to read */ +{ + u_char * ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1); + + while(n-- > 0) + { + *b++ = readb(ptr); + /* Due to a lack of address decode pins, the WaveLAN PCMCIA card + * only supports reading even memory addresses. That means the + * increment here MUST be two. + * Because of that, we can't use memcpy_fromio()... + */ + ptr += 2; + } +} /* psa_read */ + +/*------------------------------------------------------------------*/ +/* + * Write the Paramter Storage Area to the WaveLAN card's memory + */ +static void +psa_write(device * dev, + int o, /* Offset in psa */ + u_char * b, /* Buffer in memory */ + int n) /* Length of buffer */ +{ + u_char * ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1); + int count = 0; + ioaddr_t base = dev->base_addr; + /* As there seem to have no flag PSA_BUSY as in the ISA model, we are + * oblige to verify this address to know when the PSA is ready... */ + volatile u_char * verify = ((u_char *) dev->mem_start) + PSA_ADDR + + (psaoff(0, psa_comp_number) << 1); + + /* Authorize writting to PSA */ + hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN); + + while(n-- > 0) + { + /* write to PSA */ + writeb(*b++, ptr); + ptr += 2; + + /* I don't have the spec, so I don't know what the correct + * sequence to write is. This hack seem to work for me... */ + count = 0; + while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100)) + udelay(1000); + } + + /* Put the host interface back in standard state */ + hacr_write(base, HACR_DEFAULT); +} /* psa_write */ + +#ifdef SET_PSA_CRC +/*------------------------------------------------------------------*/ +/* + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code + * NOTE: By specifying a length including the CRC position the + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. + */ +static u_short +psa_crc(unsigned char * psa, /* The PSA */ + int size) /* Number of short for CRC */ +{ + int byte_cnt; /* Loop on the PSA */ + u_short crc_bytes = 0; /* Data in the PSA */ + int bit_cnt; /* Loop on the bits of the short */ + + for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) + { + crc_bytes ^= psa[byte_cnt]; /* Its an xor */ + + for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) + { + if(crc_bytes & 0x0001) + crc_bytes = (crc_bytes >> 1) ^ 0xA001; + else + crc_bytes >>= 1 ; + } + } + + return crc_bytes; +} /* psa_crc */ +#endif /* SET_PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void +update_psa_checksum(device * dev) +{ +#ifdef SET_PSA_CRC + psa_t psa; + u_short crc; + + /* read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(dev, (char *)&psa.psa_crc - (char *)&psa, + (unsigned char *)&psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if(crc != 0) + printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ + +/*------------------------------------------------------------------*/ +/* + * Write 1 byte to the MMC. + */ +static inline void +mmc_out(u_long base, + u_short o, + u_char d) +{ + /* Wait for MMC to go idle */ + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + + outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); + outb(d, MMD(base)); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to write bytes to the Modem Management Controller. + * We start by the end because it is the way it should be ! + */ +static inline void +mmc_write(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0 ) + mmc_out(base, --o, *(--b)); +} /* mmc_write */ + +/*------------------------------------------------------------------*/ +/* + * Read 1 byte from the MMC. + * Optimised version for 1 byte, avoid using memory... + */ +static inline u_char +mmc_in(u_long base, + u_short o) +{ + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + outb(o << 1, MMR(base)); /* Set the read address */ + + outb(0, MMD(base)); /* Required dummy write */ + + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + return (u_char) (inb(MMD(base))); /* Now do the actual read */ +} + +/*------------------------------------------------------------------*/ +/* + * Routine to read bytes from the Modem Management Controller. + * The implementation is complicated by a lack of address lines, + * which prevents decoding of the low-order bit. + * (code has just been moved in the above function) + * We start by the end because it is the way it should be ! + */ +static inline void +mmc_read(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0) + *(--b) = mmc_in(base, --o); +} /* mmc_read */ + +/*------------------------------------------------------------------*/ +/* + * Get the type of encryption available... + */ +static inline int +mmc_encr(u_long base) /* i/o port of the card */ +{ + int temp; + + temp = mmc_in(base, mmroff(0, mmr_des_avail)); + if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) + return 0; + else + return temp; +} + +/*------------------------------------------------------------------*/ +/* + * Wait for the frequency EEprom to complete a command... + * I hope this one will be optimally inlined... + */ +static inline void +fee_wait(u_long base, /* i/o port of the card */ + int delay, /* Base delay to wait for */ + int number) /* Number of time to wait */ +{ + int count = 0; /* Wait only a limited time */ + + while((count++ < number) && + (mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) + udelay(delay); +} + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the Frequency EEprom (frequency select cards). + */ +static void +fee_read(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + + /* Write the address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the read command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); + + /* Wait until EEprom is ready (should be quick !) */ + fee_wait(base, 10, 100); + + /* Read the value */ + *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) | + mmc_in(base, mmroff(0, mmr_fee_data_l))); + } +} + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Write bytes from the Frequency EEprom (frequency select cards). + * This is a bit complicated, because the frequency eeprom has to + * be unprotected and the write enabled. + * Jean II + */ +static void +fee_write(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + +#ifdef EEPROM_IS_PROTECTED /* disabled */ +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Ask to read the protected register */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); + + fee_wait(base, 10, 100); + + /* Read the protected register */ + printk("Protected 2 : %02X-%02X\n", + mmc_in(base, mmroff(0, mmr_fee_data_h)), + mmc_in(base, mmroff(0, mmr_fee_data_l))); +#endif /* DOESNT_SEEM_TO_WORK */ + + /* Enable protected register */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); + + fee_wait(base, 10, 100); + + /* Unprotect area */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Or use : */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); +#endif /* DOESNT_SEEM_TO_WORK */ + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ + + /* Write enable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); + + fee_wait(base, 10, 100); + + /* Write the EEprom address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the value */ + mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); + mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF); + + /* Write the write command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); + + /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ + udelay(10000); + fee_wait(base, 10, 100); + } + + /* Write disable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); + + fee_wait(base, 10, 100); + +#ifdef EEPROM_IS_PROTECTED /* disabled */ + /* Reprotect EEprom */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ +} +#endif /* WIRELESS_EXT */ + +/******************* WaveLAN Roaming routines... ********************/ + +#ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ + +unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00}; + +void wv_roam_init(struct net_device *dev) +{ + net_local *lp= (net_local *)dev->priv; + + /* Do not remove this unless you have a good reason */ + printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" + " device %s !\n", dev->name, dev->name); + printk(KERN_NOTICE "Roaming is currently an experimental unsuported feature" + " of the Wavelan driver.\n"); + printk(KERN_NOTICE "It may work, but may also make the driver behave in" + " erratic ways or crash.\n"); + + lp->wavepoint_table.head=NULL; /* Initialise WavePoint table */ + lp->wavepoint_table.num_wavepoints=0; + lp->wavepoint_table.locked=0; + lp->curr_point=NULL; /* No default WavePoint */ + lp->cell_search=0; + + lp->cell_timer.data=(int)lp; /* Start cell expiry timer */ + lp->cell_timer.function=wl_cell_expiry; + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); + + wv_nwid_filter(NWID_PROMISC,lp) ; /* Enter NWID promiscuous mode */ + /* to build up a good WavePoint */ + /* table... */ + printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); +} + +void wv_roam_cleanup(struct net_device *dev) +{ + wavepoint_history *ptr,*old_ptr; + net_local *lp= (net_local *)dev->priv; + + printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name); + + /* Fixme : maybe we should check that the timer exist before deleting it */ + del_timer(&lp->cell_timer); /* Remove cell expiry timer */ + ptr=lp->wavepoint_table.head; /* Clear device's WavePoint table */ + while(ptr!=NULL) + { + old_ptr=ptr; + ptr=ptr->next; + wl_del_wavepoint(old_ptr,lp); + } +} + +/* Enable/Disable NWID promiscuous mode on a given device */ +void wv_nwid_filter(unsigned char mode, net_local *lp) +{ + mm_t m; + unsigned long x; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + x = wv_splhi(); + + m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; + mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); + + /* ReEnable interrupts & restore flags */ + wv_splx(x); + + if(mode==NWID_PROMISC) + lp->cell_search=1; + else + lp->cell_search=0; +} + +/* Find a record in the WavePoint table matching a given NWID */ +wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) +{ + wavepoint_history *ptr=lp->wavepoint_table.head; + + while(ptr!=NULL){ + if(ptr->nwid==nwid) + return ptr; + ptr=ptr->next; + } + return NULL; +} + +/* Create a new wavepoint table entry */ +wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) +{ + wavepoint_history *new_wavepoint; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid); +#endif + + if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS) + return NULL; + + new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC); + if(new_wavepoint==NULL) + return NULL; + + new_wavepoint->nwid=nwid; /* New WavePoints NWID */ + new_wavepoint->average_fast=0; /* Running Averages..*/ + new_wavepoint->average_slow=0; + new_wavepoint->qualptr=0; /* Start of ringbuffer */ + new_wavepoint->last_seq=seq-1; /* Last sequence no.seen */ + memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */ + + new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */ + new_wavepoint->prev=NULL; + + if(lp->wavepoint_table.head!=NULL) + lp->wavepoint_table.head->prev=new_wavepoint; + + lp->wavepoint_table.head=new_wavepoint; + + lp->wavepoint_table.num_wavepoints++; /* no. of visible wavepoints */ + + return new_wavepoint; +} + +/* Remove a wavepoint entry from WavePoint table */ +void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) +{ + if(wavepoint==NULL) + return; + + if(lp->curr_point==wavepoint) + lp->curr_point=NULL; + + if(wavepoint->prev!=NULL) + wavepoint->prev->next=wavepoint->next; + + if(wavepoint->next!=NULL) + wavepoint->next->prev=wavepoint->prev; + + if(lp->wavepoint_table.head==wavepoint) + lp->wavepoint_table.head=wavepoint->next; + + lp->wavepoint_table.num_wavepoints--; + kfree(wavepoint); +} + +/* Timer callback function - checks WavePoint table for stale entries */ +void wl_cell_expiry(unsigned long data) +{ + net_local *lp=(net_local *)data; + wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name); +#endif + + if(lp->wavepoint_table.locked) + { +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n"); +#endif + + lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */ + add_timer(&lp->cell_timer); + return; + } + + while(wavepoint!=NULL) + { + if(wavepoint->last_seen < jiffies-CELL_TIMEOUT) + { +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid); +#endif + + old_point=wavepoint; + wavepoint=wavepoint->next; + wl_del_wavepoint(old_point,lp); + } + else + wavepoint=wavepoint->next; + } + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); +} + +/* Update SNR history of a wavepoint */ +void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) +{ + int i=0,num_missed=0,ptr=0; + int average_fast=0,average_slow=0; + + num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed + any beacons? */ + if(num_missed) + for(i=0;isigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */ + wavepoint->qualptr %=WAVEPOINT_HISTORY; /* in the ringbuffer. */ + } + wavepoint->last_seen=jiffies; /* Add beacon to history */ + wavepoint->last_seq=seq; + wavepoint->sigqual[wavepoint->qualptr++]=sigqual; + wavepoint->qualptr %=WAVEPOINT_HISTORY; + ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY; + + for(i=0;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + average_slow=average_fast; + for(i=WAVEPOINT_FAST_HISTORY;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY; + wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY; +} + +/* Perform a handover to a new WavePoint */ +void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) +{ + ioaddr_t base = lp->dev->base_addr; + mm_t m; + unsigned long x; + + if(wavepoint==lp->curr_point) /* Sanity check... */ + { + wv_nwid_filter(!NWID_PROMISC,lp); + return; + } + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + x = wv_splhi(); + + m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; + m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; + + mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); + + /* ReEnable interrupts & restore flags */ + wv_splx(x); + + wv_nwid_filter(!NWID_PROMISC,lp); + lp->curr_point=wavepoint; +} + +/* Called when a WavePoint beacon is received */ +static inline void wl_roam_gather(device * dev, + u_char * hdr, /* Beacon header */ + u_char * stats) /* SNR, Signal quality + of packet */ +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ + unsigned short nwid=ntohs(beacon->nwid); + unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */ + wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ + net_local *lp=(net_local *)dev->priv; /* Device info */ + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); + printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); +#endif + + lp->wavepoint_table.locked=1; /* */ + + wavepoint=wl_roam_check(nwid,lp); /* Find WavePoint table entry */ + if(wavepoint==NULL) /* If no entry, Create a new one... */ + { + wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp); + if(wavepoint==NULL) + goto out; + } + if(lp->curr_point==NULL) /* If this is the only WavePoint, */ + wv_roam_handover(wavepoint, lp); /* Jump on it! */ + + wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history + stats. */ + + if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */ + if(!lp->cell_search) /* WavePoint is getting faint, */ + wv_nwid_filter(NWID_PROMISC,lp); /* start looking for a new one */ + + if(wavepoint->average_slow > + lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA) + wv_roam_handover(wavepoint, lp); /* Handover to a better WavePoint */ + + if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */ + if(lp->cell_search) /* getting better, drop out of cell search mode */ + wv_nwid_filter(!NWID_PROMISC,lp); + +out: + lp->wavepoint_table.locked=0; /* :-) */ +} + +/* Test this MAC frame a WavePoint beacon */ +static inline int WAVELAN_BEACON(unsigned char *data) +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)data; + static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; + + if(memcmp(beacon,&beacon_template,9)==0) + return 1; + else + return 0; +} +#endif /* WAVELAN_ROAMING */ + +/************************ I82593 SUBROUTINES *************************/ +/* + * Usefull subroutines to manage the Ethernet controler + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to synchronously send a command to the i82593 chip. + * Should be called with interrupts enabled. + */ +static int +wv_82593_cmd(device * dev, + char * str, + int cmd, + int result) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *)dev->priv; + int status; + long spin; + u_long opri; + + /* Spin until the chip finishes executing its current command (if any) */ + do + { + opri = wv_splhi(); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + wv_splx(opri); + } + while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); + + /* We are waiting for command completion */ + wv_wait_completed = TRUE; + + /* Issue the command to the controler */ + outb(cmd, LCCR(base)); + + /* If we don't have to check the result of the command */ + if(result == SR0_NO_RESULT) + { + wv_wait_completed = FALSE; + return(TRUE); + } + + /* Busy wait while the LAN controller executes the command. + * Note : wv_wait_completed should be volatile */ + spin = 0; + while(wv_wait_completed && (spin++ < 1000)) + udelay(10); + + /* If the interrupt handler hasn't be called */ + if(wv_wait_completed) + { + outb(OP0_NOP, LCCR(base)); + status = inb(LCSR(base)); + if(status & SR0_INTERRUPT) + { + /* There was an interrupt : call the interrupt handler */ +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n"); +#endif + + wavelan_interrupt(dev->irq, (void *) dev, + (struct pt_regs *) NULL); + } + else + { + wv_wait_completed = 0; /* XXX */ +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n", + str, status); +#endif + /* We probably should reset the controller here */ + return(FALSE); + } + } + + /* Check the return code provided by the interrupt handler against + * the expected return code provided by the caller */ + if((lp->status & SR0_EVENT_MASK) != result) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n", + str, lp->status); +#endif + return(FALSE); + } + + return(TRUE); +} /* wv_82593_cmd */ + +/*------------------------------------------------------------------*/ +/* + * This routine does a 593 op-code number 7, and obtains the diagnose + * status for the WaveLAN. + */ +static inline int +wv_diag(device * dev) +{ + if(wv_82593_cmd(dev, "wv_diag(): diagnose", + OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)) + return(TRUE); + +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n"); +#endif + return(FALSE); +} /* wv_diag */ + +/*------------------------------------------------------------------*/ +/* + * Routine to read len bytes from the i82593's ring buffer, starting at + * chip address addr. The results read from the chip are stored in buf. + * The return value is the address to use for next the call. + */ +static int +read_ringbuf(device * dev, + int addr, + char * buf, + int len) +{ + ioaddr_t base = dev->base_addr; + int ring_ptr = addr; + int chunk_len; + char * buf_ptr = buf; + +#ifdef OLDIES + /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem + * quite safe to remove this... */ + + /* If buf is NULL, just increment the ring buffer pointer */ + if(buf == NULL) + return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE); +#endif + + /* Get all the buffer */ + while(len > 0) + { + /* Position the Program I/O Register at the ring buffer pointer */ + outb(ring_ptr & 0xff, PIORL(base)); + outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base)); + + /* First, determine how much we can read without wrapping around the + ring buffer */ + if((addr + len) < (RX_BASE + RX_SIZE)) + chunk_len = len; + else + chunk_len = RX_BASE + RX_SIZE - addr; + insb(PIOP(base), buf_ptr, chunk_len); + buf_ptr += chunk_len; + len -= chunk_len; + ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; + } + return(ring_ptr); +} /* read_ringbuf */ + +/*------------------------------------------------------------------*/ +/* + * Reconfigure the i82593, or at least ask for it... + * Because wv_82593_config use the transmission buffer, we must do it + * when we are sure that there is no transmission, so we do it now + * or in wavelan_packet_xmit() (I can't find any better place, + * wavelan_interrupt is not an option...), so you may experience + * some delay sometime... + */ +static inline void +wv_82593_reconfig(device * dev) +{ + net_local * lp = (net_local *)dev->priv; + dev_link_t * link = ((net_local *) dev->priv)->link; + + /* Check if we can do it now ! */ + if(!(link->open) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0)) + { + lp->reconfig_82593 = TRUE; +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "%s: wv_82593_reconfig(): delayed (busy = %ld, link = %d)\n", + dev->name, dev->tbusy, link->open); +#endif + } + else + { + lp->reconfig_82593 = FALSE; + wv_82593_config(dev); + dev->tbusy = 0; + } +} + +#ifdef OLDIES +/*------------------------------------------------------------------*/ +/* + * Dumps the current i82593 receive buffer to the console. + */ +static void wavelan_dump(device *dev) +{ + ioaddr_t base = dev->base_addr; + int i, c; + + /* disable receiver so we can use channel 1 */ + outb(OP0_RCV_DISABLE, LCCR(base)); + + /* reset receive DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + + /* dump into receive buffer */ + wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE); + + /* set read pointer to start of receive buffer */ + outb(0, PIORL(base)); + outb(0, PIORH(base)); + + printk(KERN_DEBUG "wavelan_cs: dump:\n"); + printk(KERN_DEBUG " 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); + for(i = 0; i < 73; i++){ + if((i % 16) == 0) { + printk("\n0x%02x:", i); + if (!i) { + printk(" "); + continue; + } + } + c = inb(PIOP(base)); + printk("%02x ", c); + } + printk("\n"); + + /* enable the receiver again */ + wv_ru_start(dev); +} +#endif + +/********************* DEBUG & INFO SUBROUTINES *********************/ +/* + * This routines are used in the code to show debug informations. + * Most of the time, it dump the content of hardware structures... + */ + +#ifdef DEBUG_PSA_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted contents of the Parameter Storage Area. + */ +static void +wv_psa_show(psa_t * p) +{ + printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); + printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", + p->psa_io_base_addr_1, + p->psa_io_base_addr_2, + p->psa_io_base_addr_3, + p->psa_io_base_addr_4); + printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", + p->psa_rem_boot_addr_1, + p->psa_rem_boot_addr_2, + p->psa_rem_boot_addr_3); + printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); + printk("psa_int_req_no: %d\n", p->psa_int_req_no); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_unused0[0], + p->psa_unused0[1], + p->psa_unused0[2], + p->psa_unused0[3], + p->psa_unused0[4], + p->psa_unused0[5], + p->psa_unused0[6]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_univ_mac_addr[0], + p->psa_univ_mac_addr[1], + p->psa_univ_mac_addr[2], + p->psa_univ_mac_addr[3], + p->psa_univ_mac_addr[4], + p->psa_univ_mac_addr[5]); + printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_local_mac_addr[0], + p->psa_local_mac_addr[1], + p->psa_local_mac_addr[2], + p->psa_local_mac_addr[3], + p->psa_local_mac_addr[4], + p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); + printk("psa_comp_number: %d, ", p->psa_comp_number); + printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); + printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", + p->psa_feature_select); + printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); + printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); + printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); + printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); + printk("psa_nwid_select: %d\n", p->psa_nwid_select); + printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); + printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_encryption_key[0], + p->psa_encryption_key[1], + p->psa_encryption_key[2], + p->psa_encryption_key[3], + p->psa_encryption_key[4], + p->psa_encryption_key[5], + p->psa_encryption_key[6], + p->psa_encryption_key[7]); + printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); + printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", + p->psa_call_code[0]); + printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_call_code[0], + p->psa_call_code[1], + p->psa_call_code[2], + p->psa_call_code[3], + p->psa_call_code[4], + p->psa_call_code[5], + p->psa_call_code[6], + p->psa_call_code[7]); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", + p->psa_reserved[0], + p->psa_reserved[1], + p->psa_reserved[2], + p->psa_reserved[3]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); + printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); + printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); +} /* wv_psa_show */ +#endif /* DEBUG_PSA_SHOW */ + +#ifdef DEBUG_MMC_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the Modem Management Controller. + * This function need to be completed... + */ +static void +wv_mmc_show(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *)dev->priv; + mmr_t m; + + /* Basic check */ + if(hasr_read(base) & HASR_NO_CLK) + { + printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", + dev->name); + return; + } + + /* Read the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + mmc_read(base, 0, (u_char *)&m, sizeof(m)); + mmc_out(base, mmwoff(0, mmw_freeze), 0); + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + /* Don't forget to update statistics */ + lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; +#endif /* WIRELESS_EXT */ + + printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused0[0], + m.mmr_unused0[1], + m.mmr_unused0[2], + m.mmr_unused0[3], + m.mmr_unused0[4], + m.mmr_unused0[5], + m.mmr_unused0[6], + m.mmr_unused0[7]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n", + m.mmr_des_avail, m.mmr_des_status); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused1[0], + m.mmr_unused1[1], + m.mmr_unused1[2], + m.mmr_unused1[3], + m.mmr_unused1[4]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", + m.mmr_dce_status, + (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", + (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? + "loop test indicated," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? + "jabber timer expired," : ""); + printk(KERN_DEBUG "Dsp ID: %02X\n", + m.mmr_dsp_id); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", + m.mmr_unused2[0], + m.mmr_unused2[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", + (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); + printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", + m.mmr_thr_pre_set & MMR_THR_PRE_SET, + (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); + printk(KERN_DEBUG "signal_lvl: %d [%s], ", + m.mmr_signal_lvl & MMR_SIGNAL_LVL, + (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); + printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, + (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); + printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, + (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); +#endif /* DEBUG_SHOW_UNUSED */ +} /* wv_mmc_show */ +#endif /* DEBUG_MMC_SHOW */ + +#ifdef DEBUG_I82593_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the i82593's receive unit. + */ +static void +wv_ru_show(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + + printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n"); + printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_ru_show */ +#endif /* DEBUG_I82593_SHOW */ + +#ifdef DEBUG_DEVICE_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver. + */ +static void +wv_dev_show(device * dev) +{ + printk(KERN_DEBUG "dev:"); + printk(" start=%d,", dev->start); + printk(" tbusy=%ld,", dev->tbusy); + printk(" interrupt=%d,", dev->interrupt); + printk(" trans_start=%ld,", dev->trans_start); + printk(" flags=0x%x,", dev->flags); + printk("\n"); +} /* wv_dev_show */ + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver's + * private information. + */ +static void +wv_local_show(device * dev) +{ + net_local *lp; + + lp = (net_local *)dev->priv; + + printk(KERN_DEBUG "local:"); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_local_show */ +#endif /* DEBUG_DEVICE_SHOW */ + +#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) +/*------------------------------------------------------------------*/ +/* + * Dump packet header (and content if necessary) on the screen + */ +static inline void +wv_packet_info(u_char * p, /* Packet to dump */ + int length, /* Length of the packet */ + char * msg1, /* Name of the device */ + char * msg2) /* Name of the function */ +{ + int i; + int maxi; + + printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", + msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); + printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", + msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); + +#ifdef DEBUG_PACKET_DUMP + + printk(KERN_DEBUG "data=\""); + + if((maxi = length) > DEBUG_PACKET_DUMP) + maxi = DEBUG_PACKET_DUMP; + for(i = 14; i < maxi; i++) + if(p[i] >= ' ' && p[i] <= '~') + printk(" %c", p[i]); + else + printk("%02X", p[i]); + if(maxi < length) + printk(".."); + printk("\"\n"); + printk(KERN_DEBUG "\n"); +#endif /* DEBUG_PACKET_DUMP */ +} +#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ + +/*------------------------------------------------------------------*/ +/* + * This is the information which is displayed by the driver at startup + * There is a lot of flag to configure it at your will... + */ +static inline void +wv_init_info(device * dev) +{ + ioaddr_t base = dev->base_addr; + psa_t psa; + int i; + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef DEBUG_PSA_SHOW + wv_psa_show(&psa); +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + +#ifdef DEBUG_BASIC_SHOW + /* Now, let's go for the basic stuff */ + printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr", + dev->name, base, dev->irq); + for(i = 0; i < WAVELAN_ADDR_SIZE; i++) + printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); + + /* Print current network id */ + if(psa.psa_nwid_select) + printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); + else + printk(", nwid off"); + + /* If 2.00 card */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + unsigned short freq; + + /* Ask the EEprom to read the frequency from the first area */ + fee_read(base, 0x00 /* 1st area - frequency... */, + &freq, 1); + + /* Print frequency */ + printk(", 2.00, %ld", (freq >> 6) + 2400L); + + /* Hack !!! */ + if(freq & 0x20) + printk(".5"); + } + else + { + printk(", PCMCIA, "); + switch (psa.psa_subband) + { + case PSA_SUBBAND_915: + printk("915"); + break; + case PSA_SUBBAND_2425: + printk("2425"); + break; + case PSA_SUBBAND_2460: + printk("2460"); + break; + case PSA_SUBBAND_2484: + printk("2484"); + break; + case PSA_SUBBAND_2430_5: + printk("2430.5"); + break; + default: + printk("???"); + } + } + + printk(" MHz\n"); +#endif /* DEBUG_BASIC_SHOW */ + +#ifdef DEBUG_VERSION_SHOW + /* Print version information */ + printk(KERN_NOTICE "%s", version); +#endif +} /* wv_init_info */ + +/********************* IOCTL, STATS & RECONFIG *********************/ +/* + * We found here routines that are called by Linux on differents + * occasions after the configuration and not for transmitting data + * These may be called when the user use ifconfig, /proc/net/dev + * or wireless extensions + */ + +/*------------------------------------------------------------------*/ +/* + * Get the current ethernet statistics. This may be called with the + * card open or closed. + * Used when the user read /proc/net/dev + */ +static en_stats * +wavelan_get_stats(device * dev) +{ +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); +#endif + + return(&((net_local *) dev->priv)->stats); +} + +/*------------------------------------------------------------------*/ +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ + +static void +wavelan_set_multicast_list(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); +#endif + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", + dev->name, dev->flags, dev->mc_count); +#endif + + if(dev->flags & IFF_PROMISC) + { + /* + * Enable promiscuous mode: receive all packets. + */ + if(!lp->promiscuous) + { + lp->promiscuous = 1; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job... */ + dev->flags |= IFF_PROMISC; + } + } + else + /* If all multicast addresses + * or too much multicast addresses for the hardware filter */ + if((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) + { + /* + * Disable promiscuous mode, but active the all multicast mode + */ + if(!lp->allmulticast) + { + lp->promiscuous = 0; + lp->allmulticast = 1; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job... */ + dev->flags |= IFF_ALLMULTI; + } + } + else + /* If there is some multicast addresses to send */ + if(dev->mc_list != (struct dev_mc_list *) NULL) + { + /* + * Disable promiscuous mode, but receive all packets + * in multicast list + */ +#ifdef MULTICAST_AVOID + if(lp->promiscuous || lp->allmulticast || + (dev->mc_count != lp->mc_count)) +#endif + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = dev->mc_count; + + wv_82593_reconfig(dev); + } + } + else + { + /* + * Switch to normal mode: disable promiscuous mode and + * clear the multicast list. + */ + if(lp->promiscuous || lp->mc_count == 0) + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + } + } +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This function doesn't exist... + * (Note : it was a nice way to test the reconfigure stuff...) + */ +#ifdef SET_MAC_ADDRESS +static int +wavelan_set_mac_address(device * dev, + void * addr) +{ + struct sockaddr * mac = addr; + + /* Copy the address */ + memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); + + /* Reconfig the beast */ + wv_82593_reconfig(dev); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Frequency setting (for hardware able of it) + * It's a bit complicated and you don't really want to look into it... + * (called in wavelan_ioctl) + */ +static inline int +wv_set_frequency(u_long base, /* i/o port of the card */ + iw_freq * frequency) +{ + const int BAND_NUM = 10; /* Number of bands */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ +#ifdef DEBUG_IOCTL_INFO + int i; +#endif + + /* Setting by frequency */ + /* Theoritically, you may set any frequency between + * the two limits with a 0.5 MHz precision. In practice, + * I don't want you to have trouble with local + * regulations... */ + if((frequency->e == 1) && + (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) + { + freq = ((frequency->m / 10000) - 24000L) / 5; + } + + /* Setting by channel (same as wfreqsel) */ + /* Warning : each channel is 22MHz wide, so some of the channels + * will interfere... */ + if((frequency->e == 0) && + (frequency->m >= 0) && (frequency->m < BAND_NUM)) + { + /* Get frequency offset. */ + freq = channel_bands[frequency->m] >> 1; + } + + /* Verify if the frequency is allowed */ + if(freq != 0L) + { + u_short table[10]; /* Authorized frequency table */ + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Frequency table :"); + for(i = 0; i < 10; i++) + { + printk(" %04X", + table[i]); + } + printk("\n"); +#endif + + /* Look in the table if the frequency is allowed */ + if(!(table[9 - ((freq - 24) / 16)] & + (1 << ((freq - 24) % 16)))) + return -EINVAL; /* not allowed */ + } + else + return -EINVAL; + + /* If we get a usable frequency */ + if(freq != 0L) + { + unsigned short area[16]; + unsigned short dac[2]; + unsigned short area_verify[16]; + unsigned short dac_verify[2]; + /* Corresponding gain (in the power adjust value table) + * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8 + * & WCIN062D.DOC, page 6.2.9 */ + unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; + int power_band = 0; /* Selected band */ + unsigned short power_adjust; /* Correct value */ + + /* Search for the gain */ + power_band = 0; + while((freq > power_limit[power_band]) && + (power_limit[++power_band] != 0)) + ; + + /* Read the first area */ + fee_read(base, 0x00, + area, 16); + + /* Read the DAC */ + fee_read(base, 0x60, + dac, 2); + + /* Read the new power adjust value */ + fee_read(base, 0x6B - (power_band >> 1), + &power_adjust, 1); + if(power_band & 0x1) + power_adjust >>= 8; + else + power_adjust &= 0xFF; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac[0], dac[1]); +#endif + + /* Frequency offset (for info only...) */ + area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); + + /* Receiver Principle main divider coefficient */ + area[3] = (freq >> 1) + 2400L - 352L; + area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Transmitter Main divider coefficient */ + area[13] = (freq >> 1) + 2400L; + area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Others part of the area are flags, bit streams or unused... */ + + /* Set the value in the DAC */ + dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); + dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); + + /* Write the first area */ + fee_write(base, 0x00, + area, 16); + + /* Write the DAC */ + fee_write(base, 0x60, + dac, 2); + + /* We now should verify here that the EEprom writting was ok */ + + /* ReRead the first area */ + fee_read(base, 0x00, + area_verify, 16); + + /* ReRead the DAC */ + fee_read(base, 0x60, + dac_verify, 2); + + /* Compare */ + if(memcmp(area, area_verify, 16 * 2) || + memcmp(dac, dac_verify, 2 * 2)) + { +#ifdef DEBUG_IOCTL_ERROR + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n"); +#endif + return -EOPNOTSUPP; + } + + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_IOCTL_INFO + /* Verification of what we have done... */ + + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area_verify[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac_verify[0], dac_verify[1]); +#endif + + return 0; + } + else + return -EINVAL; /* Bah, never get there... */ +} + +/*------------------------------------------------------------------*/ +/* + * Give the list of available frequencies + */ +static inline int +wv_frequency_list(u_long base, /* i/o port of the card */ + iw_freq * list, /* List of frequency to fill */ + int max) /* Maximum number of frequencies */ +{ + u_short table[10]; /* Authorized frequency table */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ + int i; /* index in the table */ +#if WIRELESS_EXT > 7 + const int BAND_NUM = 10; /* Number of bands */ + int c = 0; /* Channel number */ +#endif WIRELESS_EXT + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + + /* Look all frequencies */ + i = 0; + for(freq = 0; freq < 150; freq++) + /* Look in the table if the frequency is allowed */ + if(table[9 - (freq / 16)] & (1 << (freq % 16))) + { +#if WIRELESS_EXT > 7 + /* Compute approximate channel number */ + while((((channel_bands[c] >> 1) - 24) < freq) && + (c < BAND_NUM)) + c++; + list[i].i = c; /* Set the list index */ +#endif WIRELESS_EXT + + /* put in the list */ + list[i].m = (((freq + 24) * 5) + 24000L) * 10000; + list[i++].e = 1; + + /* Check number */ + if(i >= max) + return(i); + } + + return(i); +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Gather wireless spy statistics : for each packet, compare the source + * address with out list, and if match, get the stats... + * Sorry, but this function really need wireless extensions... + */ +static inline void +wl_spy_gather(device * dev, + u_char * mac, /* MAC address */ + u_char * stats) /* Statistics to gather */ +{ + net_local * lp = (net_local *) dev->priv; + int i; + + /* Look all addresses */ + for(i = 0; i < lp->spy_number; i++) + /* If match */ + if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) + { + /* Update statistics */ + lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; + lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; + lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; + lp->spy_stat[i].updated = 0x7; + } +} +#endif /* WIRELESS_SPY */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * This function calculate an histogram on the signal level. + * As the noise is quite constant, it's like doing it on the SNR. + * We have defined a set of interval (lp->his_range), and each time + * the level goes in that interval, we increment the count (lp->his_sum). + * With this histogram you may detect if one wavelan is really weak, + * or you may also calculate the mean and standard deviation of the level... + */ +static inline void +wl_his_gather(device * dev, + u_char * stats) /* Statistics to gather */ +{ + net_local * lp = (net_local *) dev->priv; + u_char level = stats[0] & MMR_SIGNAL_LVL; + int i; + + /* Find the correct interval */ + i = 0; + while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) + ; + + /* Increment interval counter */ + (lp->his_sum[i])++; +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Perform ioctl : config & info stuff + * This is here that are treated the wireless extensions (iwconfig) + */ +static int +wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ + struct ifreq * rq, /* Data passed */ + int cmd) /* Ioctl number */ +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *)dev->priv; /* lp is not unused */ + struct iwreq * wrq = (struct iwreq *) rq; + psa_t psa; + mm_t m; + unsigned long x; + int ret = 0; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); +#endif + + /* Disable interrupts & save flags */ + x = wv_splhi(); + + /* Look what is the request */ + switch(cmd) + { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + strcpy(wrq->u.name, "Wavelan"); + break; + + case SIOCSIWNWID: + /* Set NWID in wavelan */ +#if WIRELESS_EXT > 8 + if(!wrq->u.nwid.disabled) + { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; +#else /* WIRELESS_EXT > 8 */ + if(wrq->u.nwid.on) + { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; +#endif /* WIRELESS_EXT > 8 */ + psa.psa_nwid_select = 0x01; + psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 3); + + /* Set NWID in mmc */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, + (unsigned char *)&m.w.mmw_netw_id_l, 2); + mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); + } + else + { + /* Disable nwid in the psa */ + psa.psa_nwid_select = 0x00; + psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa, + (unsigned char *)&psa.psa_nwid_select, 1); + + /* Disable nwid in the mmc (no filtering) */ + mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + break; + + case SIOCGIWNWID: + /* Read the NWID */ + psa_read(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 3); +#if WIRELESS_EXT > 8 + wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.disabled = !(psa.psa_nwid_select); + wrq->u.nwid.fixed = 1; /* Superfluous */ +#else /* WIRELESS_EXT > 8 */ + wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.on = psa.psa_nwid_select; +#endif /* WIRELESS_EXT > 8 */ + break; + + case SIOCSIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(base, &(wrq->u.freq)); + else + ret = -EOPNOTSUPP; + break; + + case SIOCGIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * (does it work for everybody ??? - especially old cards...) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + unsigned short freq; + + /* Ask the EEprom to read the frequency from the first area */ + fee_read(base, 0x00 /* 1st area - frequency... */, + &freq, 1); + wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrq->u.freq.e = 1; + } + else + { + psa_read(dev, (char *)&psa.psa_subband - (char *)&psa, + (unsigned char *)&psa.psa_subband, 1); + + if(psa.psa_subband <= 4) + { + wrq->u.freq.m = fixed_bands[psa.psa_subband]; + wrq->u.freq.e = (psa.psa_subband != 0); + } + else + ret = -EOPNOTSUPP; + } + break; + + case SIOCSIWSENS: + /* Set the level threshold */ +#if WIRELESS_EXT > 7 + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; +#else /* WIRELESS_EXT > 7 */ + psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; +#endif /* WIRELESS_EXT > 7 */ + psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); + break; + + case SIOCGIWSENS: + /* Read the level threshold */ + psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); +#if WIRELESS_EXT > 7 + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; +#else /* WIRELESS_EXT > 7 */ + wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; +#endif /* WIRELESS_EXT > 7 */ + break; + +#if WIRELESS_EXT > 8 + case SIOCSIWENCODE: + /* Set encryption key */ + if(!mmc_encr(base)) + { + ret = -EOPNOTSUPP; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + /* Check the size of the key */ + if(wrq->u.encoding.length != 8) + { + ret = -EINVAL; + break; + } + + /* Copy the key in the driver */ + if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, + wrq->u.encoding.length)) + { + ret = -EFAULT; + break; + } + + psa.psa_encryption_select = 1; + psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 8+1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(base, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa.psa_encryption_key, 8); + } + + if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) + { /* disable encryption */ + psa.psa_encryption_select = 0; + psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + break; + + case SIOCGIWENCODE: + /* Read the encryption key */ + if(!mmc_encr(base)) + { + ret = -EOPNOTSUPP; + break; + } + + /* only super-user can see encryption key */ + if(!suser()) + { + ret = -EPERM; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 1+8); + + /* encryption is enabled ? */ + if(psa.psa_encryption_select) + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + else + wrq->u.encoding.flags = IW_ENCODE_DISABLED; + wrq->u.encoding.flags |= mmc_encr(base); + + /* Copy the key to the user buffer */ + wrq->u.encoding.length = 8; + if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) + ret = -EFAULT; + } + break; +#endif /* WIRELESS_EXT > 8 */ + +#ifdef WAVELAN_ROAMING_EXT +#if WIRELESS_EXT > 5 + case SIOCSIWESSID: + /* Check if disable */ + if(wrq->u.data.flags == 0) + lp->filter_domains = 0; + else + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + char * endp; + + /* Check the size of the string */ + if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) + { + ret = -E2BIG; + break; + } + + /* Copy the string in the driver */ + if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length)) + { + ret = -EFAULT; + break; + } + essid[IW_ESSID_MAX_SIZE] = '\0'; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); +#endif /* DEBUG_IOCTL_INFO */ + + /* Convert to a number (note : Wavelan specific) */ + lp->domain_id = simple_strtoul(essid, &endp, 16); + /* Has it worked ? */ + if(endp > essid) + lp->filter_domains = 1; + else + { + lp->filter_domains = 0; + ret = -EINVAL; + } + } + break; + + case SIOCGIWESSID: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + + /* Is the domain ID active ? */ + wrq->u.data.flags = lp->filter_domains; + + /* Copy Domain ID into a string (Wavelan specific) */ + /* Sound crazy, be we can't have a snprintf in the kernel !!! */ + sprintf(essid, "%lX", lp->domain_id); + essid[IW_ESSID_MAX_SIZE] = '\0'; + + /* Set the length */ + wrq->u.data.length = strlen(essid) + 1; + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)) + ret = -EFAULT; + } + break; + + case SIOCSIWAP: +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", + wrq->u.ap_addr.sa_data[0], + wrq->u.ap_addr.sa_data[1], + wrq->u.ap_addr.sa_data[2], + wrq->u.ap_addr.sa_data[3], + wrq->u.ap_addr.sa_data[4], + wrq->u.ap_addr.sa_data[5]); +#endif /* DEBUG_IOCTL_INFO */ + + ret = -EOPNOTSUPP; /* Not supported yet */ + break; + + case SIOCGIWAP: + /* Should get the real McCoy instead of own Ethernet address */ + memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + + ret = -EOPNOTSUPP; /* Not supported yet */ + break; +#endif /* WIRELESS_EXT > 5 */ +#endif /* WAVELAN_ROAMING_EXT */ + +#if WIRELESS_EXT > 8 +#ifdef WAVELAN_ROAMING + case SIOCSIWMODE: + switch(wrq->u.mode) + { + case IW_MODE_ADHOC: + if(do_roaming) + { + wv_roam_cleanup(dev); + do_roaming = 0; + } + break; + case IW_MODE_INFRA: + if(!do_roaming) + { + wv_roam_init(dev); + do_roaming = 1; + } + break; + default: + ret = -EINVAL; + } + break; + + case SIOCGIWMODE: + if(do_roaming) + wrq->u.mode = IW_MODE_INFRA; + else + wrq->u.mode = IW_MODE_ADHOC; + break; +#endif /* WAVELAN_ROAMING */ +#endif /* WIRELESS_EXT > 8 */ + + case SIOCGIWRANGE: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + struct iw_range range; + + /* Set the length (useless : its constant...) */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set information in the range struct */ + range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ + range.min_nwid = 0x0000; + range.max_nwid = 0xFFFF; + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + range.num_channels = 10; + range.num_frequency = wv_frequency_list(base, range.freq, + IW_MAX_FREQUENCIES); + } + else + range.num_channels = range.num_frequency = 0; + + range.sensitivity = 0x3F; + range.max_qual.qual = MMR_SGNL_QUAL; + range.max_qual.level = MMR_SIGNAL_LVL; + range.max_qual.noise = MMR_SILENCE_LVL; + +#if WIRELESS_EXT > 7 + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ +#endif /* WIRELESS_EXT > 7 */ + +#if WIRELESS_EXT > 8 + /* Encryption supported ? */ + if(mmc_encr(base)) + { + range.encoding_size[0] = 8; /* DES = 64 bits key */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ + } + else + { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } +#endif /* WIRELESS_EXT > 8 */ + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; + } + break; + + case SIOCGIWPRIV: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + struct iw_priv_args priv[] = + { /* cmd, set_args, get_args, name */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, + { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" }, + { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, + }; + + /* Set the number of ioctl available */ + wrq->u.data.length = 6; + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, + sizeof(priv))) + ret = -EFAULT; + } + break; + +#ifdef WIRELESS_SPY + case SIOCSIWSPY: + /* Set the spy list */ + + /* Check the number of addresses */ + if(wrq->u.data.length > IW_MAX_SPY) + { + ret = -E2BIG; + break; + } + lp->spy_number = wrq->u.data.length; + + /* If there is some addresses to copy */ + if(lp->spy_number > 0) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses to the driver */ + if(copy_from_user(address, wrq->u.data.pointer, + sizeof(struct sockaddr) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Copy addresses to the lp structure */ + for(i = 0; i < lp->spy_number; i++) + { + memcpy(lp->spy_address[i], address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure... */ + memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); + for(i = 0; i < wrq->u.data.length; i++) + printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + break; + + case SIOCGIWSPY: + /* Get the spy list and spy stats */ + + /* Set the number of addresses */ + wrq->u.data.length = lp->spy_number; + + /* If the user want to have the addresses back... */ + if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses from the lp structure */ + for(i = 0; i < lp->spy_number; i++) + { + memcpy(address[i].sa_data, lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = ARPHRD_ETHER; + } + + /* Copy addresses to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, address, + sizeof(struct sockaddr) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Copy stats to the user buffer (just after) */ + if(copy_to_user(wrq->u.data.pointer + + (sizeof(struct sockaddr) * lp->spy_number), + lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Reset updated flags */ + for(i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + } /* if(pointer != NULL) */ + + break; +#endif /* WIRELESS_SPY */ + + /* ------------------ PRIVATE IOCTL ------------------ */ + + case SIOCSIPQTHR: + if(!suser()) + { + ret = -EPERM; + break; + } + psa.psa_quality_thr = *(wrq->u.name) & 0x0F; + psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); + break; + + case SIOCGIPQTHR: + psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + break; + +#ifdef WAVELAN_ROAMING + case SIOCSIPROAM: + /* Note : should check if user == root */ + if(do_roaming && (*wrq->u.name)==0) + wv_roam_cleanup(dev); + else if(do_roaming==0 && (*wrq->u.name)!=0) + wv_roam_init(dev); + + do_roaming = (*wrq->u.name); + + break; + + case SIOCGIPROAM: + *(wrq->u.name) = do_roaming; + break; +#endif /* WAVELAN_ROAMING */ + +#ifdef HISTOGRAM + case SIOCSIPHISTO: + /* Verif if the user is root */ + if(!suser()) + { + ret = -EPERM; + } + + /* Check the number of intervals */ + if(wrq->u.data.length > 16) + { + ret = -E2BIG; + break; + } + lp->his_number = wrq->u.data.length; + + /* If there is some addresses to copy */ + if(lp->his_number > 0) + { + /* Copy interval ranges to the driver */ + if(copy_from_user(lp->his_range, wrq->u.data.pointer, + sizeof(char) * lp->his_number)) + { + ret = -EFAULT; + break; + } + + /* Reset structure... */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + break; + + case SIOCGIPHISTO: + /* Set the number of intervals */ + wrq->u.data.length = lp->his_number; + + /* Give back the distribution statistics */ + if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + { + /* Copy data to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, lp->his_sum, + sizeof(long) * lp->his_number)) + ret = -EFAULT; + + } /* if(pointer != NULL) */ + break; +#endif /* HISTOGRAM */ + + /* ------------------- OTHER IOCTL ------------------- */ + + default: + ret = -EOPNOTSUPP; + } + + /* ReEnable interrupts & restore flags */ + wv_splx(x); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Get wireless statistics + * Called by /proc/net/wireless... + */ +static iw_stats * +wavelan_get_wireless_stats(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + mmr_t m; + iw_stats * wstats; + unsigned long x; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); +#endif + + /* Disable interrupts & save flags */ + x = wv_splhi(); + + if(lp == (net_local *) NULL) + return (iw_stats *) NULL; + wstats = &lp->wstats; + + /* Get data from the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + + mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); + mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); + mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); + + mmc_out(base, mmwoff(0, mmw_freeze), 0); + + /* Copy data to wireless stuff */ + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; + wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; + wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; + wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; + wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | + ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | + ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); + wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + /* ReEnable interrupts & restore flags */ + wv_splx(x); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); +#endif + return &lp->wstats; +} +#endif /* WIRELESS_EXT */ + +/************************* PACKET RECEPTION *************************/ +/* + * This part deal with receiving the packets. + * The interrupt handler get an interrupt when a packet has been + * successfully received and called this part... + */ + +/*------------------------------------------------------------------*/ +/* + * Calculate the starting address of the frame pointed to by the receive + * frame pointer and verify that the frame seem correct + * (called by wv_packet_rcv()) + */ +static inline int +wv_start_of_frame(device * dev, + int rfp, /* end of frame */ + int wrap) /* start of buffer */ +{ + ioaddr_t base = dev->base_addr; + int rp; + int len; + + rp = (rfp - 5 + RX_SIZE) % RX_SIZE; + outb(rp & 0xff, PIORL(base)); + outb(((rp >> 8) & PIORH_MASK), PIORH(base)); + len = inb(PIOP(base)); + len |= inb(PIOP(base)) << 8; + + /* Sanity checks on size */ + /* Frame too big */ + if(len > MAXDATAZ + 100) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Frame too short */ + if(len < 7) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Wrap around buffer */ + if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) /* magic formula ! */ + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n", + dev->name, wrap, rfp, len); +#endif + return(-1); + } + + return((rp - len + RX_SIZE) % RX_SIZE); +} /* wv_start_of_frame */ + +/*------------------------------------------------------------------*/ +/* + * This routine does the actual copy of data (including the ethernet + * header structure) from the WaveLAN card to an sk_buff chain that + * will be passed up to the network interface layer. NOTE: We + * currently don't handle trailer protocols (neither does the rest of + * the network interface), so if that is needed, it will (at least in + * part) be added here. The contents of the receive ring buffer are + * copied to a message chain that is then passed to the kernel. + * + * Note: if any errors occur, the packet is "dropped on the floor" + * (called by wv_packet_rcv()) + */ +static inline void +wv_packet_read(device * dev, + int fd_p, + int sksize) +{ + net_local * lp = (net_local *) dev->priv; + struct sk_buff * skb; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", + dev->name, fd_p, sksize); +#endif + + /* Allocate some buffer for the new packet */ + if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n", + dev->name, sksize); +#endif + lp->stats.rx_dropped++; + /* + * Not only do we want to return here, but we also need to drop the + * packet on the floor to clear the interrupt. + */ + return; + } + + skb->dev = dev; + + skb_reserve(skb, 2); + fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); + skb->protocol = eth_type_trans(skb, dev); + +#ifdef DEBUG_RX_INFO + /* Another glitch : Due to the way the GET_PACKET macro is written, + * we are not sure to have the same thing in skb->data. On the other + * hand, skb->mac.raw is not defined everywhere... + * For versions between 1.2.13 and those where skb->mac.raw appear, + * I don't have a clue... + */ + wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); +#endif /* DEBUG_RX_INFO */ + + /* Statistics gathering & stuff associated. + * It seem a bit messy with all the define, but it's really simple... */ + if( +#ifdef WIRELESS_SPY + (lp->spy_number > 0) || +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + (lp->his_number > 0) || +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + (do_roaming) || +#endif /* WAVELAN_ROAMING */ + 0) + { + u_char stats[3]; /* Signal level, Noise level, Signal quality */ + + /* read signal level, silence level and signal quality bytes */ + fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE, + stats, 3); +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", + dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); +#endif + +#ifdef WAVELAN_ROAMING + if(do_roaming) + if(WAVELAN_BEACON(skb->data)) + wl_roam_gather(dev, skb->data, stats); +#endif /* WAVELAN_ROAMING */ + + /* Spying stuff */ +#ifdef WIRELESS_SPY + /* Same as above */ + wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + wl_his_gather(dev, stats); +#endif /* HISTOGRAM */ + } + + /* + * Hand the packet to the Network Module + */ + netif_rx(skb); + + /* Keep stats up to date */ + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); +#endif + return; +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called by the interrupt handler to initiate a + * packet transfer from the card to the network interface layer above + * this driver. This routine checks if a buffer has been successfully + * received by the WaveLAN card. If so, the routine wv_packet_read is + * called to do the actual transfer of the card's data including the + * ethernet header into a packet consisting of an sk_buff chain. + * (called by wavelan_interrupt()) + */ +static inline void +wv_packet_rcv(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + int newrfp; + int rp; + int len; + int f_start; + int status; + int i593_rfp; + int stat_ptr; + u_char c[4]; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name); +#endif + + /* Get the new receive frame pointer from the i82593 chip */ + outb(CR0_STATUS_2 | OP0_NOP, LCCR(base)); + i593_rfp = inb(LCSR(base)); + i593_rfp |= inb(LCSR(base)) << 8; + i593_rfp %= RX_SIZE; + + /* Get the new receive frame pointer from the WaveLAN card. + * It is 3 bytes more than the increment of the i82593 receive + * frame pointer, for each packet. This is because it includes the + * 3 roaming bytes added by the mmc. + */ + newrfp = inb(RPLL(base)); + newrfp |= inb(RPLH(base)) << 8; + newrfp %= RX_SIZE; + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + +#ifdef DEBUG_RX_ERROR + /* If no new frame pointer... */ + if(lp->overrunning || newrfp == lp->rfp) + printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + + /* Read all frames (packets) received */ + while(newrfp != lp->rfp) + { + /* A frame is composed of the packet, followed by a status word, + * the length of the frame (word) and the mmc info (SNR & qual). + * It's because the length is at the end that we can only scan + * frames backward. */ + + /* Find the first frame by skipping backwards over the frames */ + rp = newrfp; /* End of last frame */ + while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) && + (f_start != -1)) + rp = f_start; + + /* If we had a problem */ + if(f_start == -1) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "wavelan_cs: cannot find start of frame "); + printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + lp->rfp = rp; /* Get to the last usable frame */ + continue; + } + + /* f_start point to the beggining of the first frame received + * and rp to the beggining of the next one */ + + /* Read status & length of the frame */ + stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; + stat_ptr = read_ringbuf(dev, stat_ptr, c, 4); + status = c[0] | (c[1] << 8); + len = c[2] | (c[3] << 8); + + /* Check status */ + if((status & RX_RCV_OK) != RX_RCV_OK) + { + lp->stats.rx_errors++; + if(status & RX_NO_SFD) + lp->stats.rx_frame_errors++; + if(status & RX_CRC_ERR) + lp->stats.rx_crc_errors++; + if(status & RX_OVRRUN) + lp->stats.rx_over_errors++; + +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n", + dev->name, status); +#endif + } + else + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, f_start, len - 2); + + /* One frame has been processed, skip it */ + lp->rfp = rp; + } + + /* + * Update the frame stop register, but set it to less than + * the full 8K to allow space for 3 bytes of signal strength + * per packet. + */ + lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name); +#endif +} + +/*********************** PACKET TRANSMISSION ***********************/ +/* + * This part deal with sending packet through the wavelan + * We copy the packet to the send buffer and then issue the send + * command to the i82593. The result of this operation will be + * checked in wavelan_interrupt() + */ + +/*------------------------------------------------------------------*/ +/* + * This routine fills in the appropriate registers and memory + * locations on the WaveLAN card and starts the card off on + * the transmit. + * (called in wavelan_packet_xmit()) + */ +static inline void +wv_packet_write(device * dev, + void * buf, + short length) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long x; + int clen = length; + register u_short xmtdata_base = TX_BASE; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); +#endif + + x = wv_splhi(); + + /* Check if we need some padding */ + if(clen < ETH_ZLEN) + clen = ETH_ZLEN; + + /* Write the length of data buffer followed by the buffer */ + outb(xmtdata_base & 0xff, PIORL(base)); + outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(clen & 0xff, PIOP(base)); /* lsb */ + outb(clen >> 8, PIOP(base)); /* msb */ + + /* Send the data */ + outsb(PIOP(base), buf, clen); + + /* Indicate end of transmit chain */ + outb(OP0_NOP, PIOP(base)); + /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */ + outb(OP0_NOP, PIOP(base)); + + /* Reset the transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + /* Send the transmit command */ + wv_82593_cmd(dev, "wv_packet_write(): transmit", + OP0_TRANSMIT, SR0_NO_RESULT); + + /* Keep stats up to date */ + lp->stats.tx_bytes += length; + + /* If watchdog not already active, activate it... */ + if(lp->watchdog.prev == (timer_list *) NULL) + { + /* set timer to expire in WATCHDOG_JIFFIES */ + lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; + add_timer(&lp->watchdog); + } + + wv_splx(x); + +#ifdef DEBUG_TX_INFO + wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); +#endif /* DEBUG_TX_INFO */ + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called when we want to send a packet (NET3 callback) + * In this routine, we check if the the harware is ready to accept + * the packet. We also prevent reentrance. Then, we call the function + * to send the packet... + */ +static int +wavelan_packet_xmit(struct sk_buff * skb, + device * dev) +{ + net_local * lp = (net_local *)dev->priv; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); +#endif + + /* This flag indicate that the hardware can't perform a transmission. + * Theoritically, NET3 check it before sending a packet to the driver, + * but in fact it never do that and pool continuously. + * As the watchdog will abort too long transmissions, we are quite safe... + */ + if(dev->tbusy) + return(1); + + /* + * For ethernet, fill in the header. + */ + + /* + * Block a timer-based transmit from overlapping a previous transmit. + * In other words, prevent reentering this routine. + */ + if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name); +#endif + else + { + /* If somebody has asked to reconfigure the controler, we can do it now */ + if(lp->reconfig_82593) + { + lp->reconfig_82593 = FALSE; + wv_82593_config(dev); + } + +#ifdef DEBUG_TX_ERROR + if(skb->next) + printk(KERN_INFO "skb has next\n"); +#endif + + wv_packet_write(dev, skb->data, skb->len); + } + + dev_kfree_skb(skb); + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); +#endif + return(0); +} + +/********************** HARDWARE CONFIGURATION **********************/ +/* + * This part do the real job of starting and configuring the hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to initialize the Modem Management Controller. + * (called by wv_hw_config()) + */ +static inline int +wv_mmc_init(device * dev) +{ + ioaddr_t base = dev->base_addr; + psa_t psa; + mmw_t m; + int configured; + int i; /* Loop counter */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); +#endif + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* + * Check the first three octets of the MAC addr for the manufacturer's code. + * Note: If you get the error message below, you've got a + * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on + * how to configure your card... + */ + for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) + if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && + (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && + (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) + break; + + /* If we have not found it... */ + if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3)) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", + dev->name, psa.psa_univ_mac_addr[0], + psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]); +#endif + return FALSE; + } + + /* Get the MAC address */ + memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE); + +#ifdef USE_PSA_CONFIG + configured = psa.psa_conf_status & 1; +#else + configured = 0; +#endif + + /* Is the PSA is not configured */ + if(!configured) + { + /* User will be able to configure NWID after (with iwconfig) */ + psa.psa_nwid[0] = 0; + psa.psa_nwid[1] = 0; + + /* As NWID is not set : no NWID checking */ + psa.psa_nwid_select = 0; + + /* Disable encryption */ + psa.psa_encryption_select = 0; + + /* Set to standard values + * 0x04 for AT, + * 0x01 for MCA, + * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) + */ + if (psa.psa_comp_number & 1) + psa.psa_thr_pre_set = 0x01; + else + psa.psa_thr_pre_set = 0x04; + psa.psa_quality_thr = 0x03; + + /* It is configured */ + psa.psa_conf_status |= 1; + +#ifdef USE_PSA_CONFIG + /* Write the psa */ + psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 4); + psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); + psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa, + (unsigned char *)&psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); +#endif /* USE_PSA_CONFIG */ + } + + /* Zero the mmc structure */ + memset(&m, 0x00, sizeof(m)); + + /* Copy PSA info to the mmc */ + m.mmw_netw_id_l = psa.psa_nwid[1]; + m.mmw_netw_id_h = psa.psa_nwid[0]; + + if(psa.psa_nwid_select & 1) + m.mmw_loopt_sel = 0x00; + else + m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; + + memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, + sizeof(m.mmw_encr_key)); + + if(psa.psa_encryption_select) + m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; + else + m.mmw_encr_enable = 0; + + m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; + m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + + m.mmw_des_io_invert = 0; + m.mmw_freeze = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + + /* Write all info to mmc */ + mmc_write(base, 0, (u_char *)&m, sizeof(m)); + + /* The following code start the modem of the 2.00 frequency + * selectable cards at power on. It's not strictly needed for the + * following boots... + * The original patch was by Joe Finney for the PCMCIA driver, but + * I've cleaned it a bit and add documentation. + * Thanks to Loeke Brederveld from Lucent for the info. + */ + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * (does it work for everybody ??? - especially old cards...) */ + /* Note : WFREQSEL verify that it is able to read from EEprom + * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID + * is 0xA (Xilinx version) or 0xB (Ariadne version). + * My test is more crude but do work... */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + m.mmw_fee_addr = 0x0F; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_CONFIG_INFO + /* The frequency was in the last word downloaded... */ + mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m, + (unsigned char *)&m.mmw_fee_data_l, 2); + + /* Print some info for the user */ + printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n", + dev->name, + ((m.mmw_fee_data_h << 4) | + (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); +#endif + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + m.mmw_fee_addr = 0x61; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + } /* if 2.00 card */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * Routine to gracefully turn off reception, and wait for any commands + * to complete. + * (called in wv_ru_start() and wavelan_close() and wavelan_event()) + */ +static int +wv_ru_stop(device * dev) +{ + ioaddr_t base = dev->base_addr; + unsigned long opri; + int status; + int spin; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); +#endif + + /* First, send the LAN controller a stop receive command */ + wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", + OP0_STOP_RCV, SR0_NO_RESULT); + + /* Then, spin until the receive unit goes idle */ + spin = 0; + do + { + udelay(10); + opri = wv_splhi(); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + wv_splx(opri); + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300)); + + /* Now, spin until the chip finishes executing its current command */ + do + { + udelay(10); + opri = wv_splhi(); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + wv_splx(opri); + } + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300)); + + /* If there was a problem */ + if(spin > 300) + { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", + dev->name); +#endif + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name); +#endif + return TRUE; +} /* wv_ru_stop */ + +/*------------------------------------------------------------------*/ +/* + * This routine starts the receive unit running. First, it checks if + * the card is actually ready. Then the card is instructed to receive + * packets again. + * (called in wv_hw_reset() & wavelan_open()) + */ +static int +wv_ru_start(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); +#endif + + /* + * We need to start from a quiescent state. To do so, we could check + * if the card is already running, but instead we just try to shut + * it down. First, we disable reception (in case it was already enabled). + */ + if(!wv_ru_stop(dev)) + return FALSE; + + /* Now we know that no command is being executed. */ + + /* Set the receive frame pointer and stop pointer */ + lp->rfp = 0; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + + /* Reset ring management. This sets the receive frame pointer to 1 */ + outb(OP1_RESET_RING_MNGMT, LCCR(base)); + + /* but I set it to 3 bytes per packet less than 8K */ + lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_INT_ENABLE, LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + + /* Reset receive DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write_slow(base, HACR_DEFAULT); + + /* Receive DMA on channel 1 */ + wv_82593_cmd(dev, "wv_ru_start(): rcv-enable", + CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); + +#ifdef DEBUG_I82593_SHOW + { + int status; + int opri; + int i = 0; + + /* spin until the chip starts receiving */ + do + { + opri = wv_splhi(); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + wv_splx(opri); + if(i++ > 10000) + break; + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && + ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY)); + printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n", + (status & SR3_RCV_STATE_MASK), i); + } +#endif +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard config of the WaveLAN controler (i82593). + * In the ISA driver, this is integrated in wavelan_hardware_reset() + * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) + */ +static int +wv_82593_config(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + struct i82593_conf_block cfblk; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); +#endif + + /* Create & fill i82593 config block + * + * Now conform to Wavelan document WCIN085B + */ + memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); + cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ + cfblk.fifo_limit = 5; /* = 56 B rx and 40 B tx fifo thresholds */ + cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + cfblk.fifo_32 = 1; + cfblk.throttle_enb = FALSE; + cfblk.contin = TRUE; /* enable continuous mode */ + cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ + cfblk.addr_len = WAVELAN_ADDR_SIZE; + cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ + cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ + cfblk.loopback = FALSE; + cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ + cfblk.exp_prio = 5; /* conform to 802.3 backoff algoritm */ + cfblk.bof_met = 1; /* conform to 802.3 backoff algoritm */ + cfblk.ifrm_spc = 0x20; /* 32 bit times interframe spacing */ + cfblk.slottim_low = 0x20; /* 32 bit times slot time */ + cfblk.slottim_hi = 0x0; + cfblk.max_retr = 15; + cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE); /* Promiscuous mode */ + cfblk.bc_dis = FALSE; /* Enable broadcast reception */ + cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ + cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + cfblk.cs_filter = 0; /* CS is recognized immediately */ + cfblk.crs_src = FALSE; /* External carrier sense */ + cfblk.cd_filter = 0; /* CD is recognized immediately */ + cfblk.min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length 64 bytes */ + cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + cfblk.artx = TRUE; /* Disable automatic retransmission */ + cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + cfblk.fdx = FALSE; /* Disable full duplex operation */ + cfblk.dummy_6 = 0x3f; /* all ones */ + cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + cfblk.dummy_1 = TRUE; /* set to 1 */ + cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ +#ifdef MULTICAST_ALL + cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE); /* Allow all multicasts */ +#else + cfblk.mc_all = FALSE; /* No multicast all mode */ +#endif + cfblk.rcv_mon = 0; /* Monitor mode disabled */ + cfblk.frag_acpt = TRUE; /* Do not accept fragments */ + cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + cfblk.syncrqs = FALSE; /* Synchronous DRQ deassertion... */ + cfblk.sttlen = TRUE; /* 6 byte status registers */ + cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ + cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + +#ifdef DEBUG_I82593_SHOW + { + u_char *c = (u_char *) &cfblk; + int i; + printk(KERN_DEBUG "wavelan_cs: config block:"); + for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++) + { + if((i % 16) == 0) printk("\n" KERN_DEBUG); + printk("%02x ", *c); + } + printk("\n"); + } +#endif + + /* Copy the config block to the i82593 */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base)); /* lsb */ + outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base)); /* msb */ + outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block)); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): configure", + OP0_CONFIGURE, SR0_CONFIGURE_DONE)) + return(FALSE); + + /* Initialize adapter's ethernet MAC address */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(WAVELAN_ADDR_SIZE, PIOP(base)); /* byte count lsb */ + outb(0, PIOP(base)); /* byte count msb */ + outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", + OP0_IA_SETUP, SR0_IA_SETUP_DONE)) + return(FALSE); + +#ifdef WAVELAN_ROAMING + /* If roaming is enabled, join the "Beacon Request" multicast group... */ + /* But only if it's not in there already! */ + if(do_roaming) + dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1); +#endif /* WAVELAN_ROAMING */ + + /* If any multicast address to set */ + if(lp->mc_count) + { + struct dev_mc_list * dmi; + int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", + dev->name, lp->mc_count); + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); +#endif + + /* Initialize adapter's ethernet multicast addresses */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */ + outb((addrs_len >> 8), PIOP(base)); /* byte count msb */ + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", + OP0_MC_SETUP, SR0_MC_SETUP_DONE)) + return(FALSE); + lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); +#endif + return(TRUE); +} + +/*------------------------------------------------------------------*/ +/* + * Read the Access Configuration Register, perform a software reset, + * and then re-enable the card's software. + * + * If I understand correctly : reset the pcmcia interface of the + * wavelan. + * (called by wv_config()) + */ +static inline int +wv_pcmcia_reset(device * dev) +{ + int i; + conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; + dev_link_t * link = ((net_local *) dev->priv)->link; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); +#endif + + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", + dev->name, (u_int) reg.Value); +#endif + + reg.Action = CS_WRITE; + reg.Value = reg.Value | COR_SW_RESET; + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + + reg.Action = CS_WRITE; + reg.Value = COR_LEVEL_IRQ | COR_CONFIG; + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * wavelan_hw_config() is called after a CARD_INSERTION event is + * received, to configure the wavelan hardware. + * Note that the reception will be enabled in wavelan->open(), so the + * device is configured but idle... + * Performs the following actions: + * 1. A pcmcia software reset (using wv_pcmcia_reset()) + * 2. A power reset (reset DMA) + * 3. Reset the LAN controller + * 4. Initialize the radio modem (using wv_mmc_init) + * 5. Configure LAN controller (using wv_82593_config) + * 6. Perform a diagnostic on the LAN controller + * (called by wavelan_event() & wv_hw_reset()) + */ +static int +wv_hw_config(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); +#endif + +#ifdef STRUCT_CHECK + if(wv_structuct_check() != (char *) NULL) + { + printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n", + dev->name, wv_structuct_check()); + return FALSE; + } +#endif /* STRUCT_CHECK == 1 */ + + /* Reset the pcmcia interface */ + if(wv_pcmcia_reset(dev) == FALSE) + return FALSE; + + /* Power UP the module + reset the modem + reset host adapter + * (in fact, reset DMA channels) */ + hacr_write_slow(base, HACR_RESET); + hacr_write(base, HACR_DEFAULT); + + /* Check if the the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", + dev->name); +#endif + return FALSE; + } + + /* initialize the modem */ + if(wv_mmc_init(dev) == FALSE) + return FALSE; + + /* reset the LAN controller (i82593) */ + outb(OP0_RESET, LCCR(base)); + udelay(1000L); /* A bit crude ! */ + + /* Initialize the LAN controler */ + if((wv_82593_config(dev) == FALSE) || + (wv_diag(dev) == FALSE)) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name); +#endif + return FALSE; + } + + /* + * insert code for loopback test here + */ + + /* The device is now configured */ + lp->configured = 1; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * Totally reset the wavelan and restart it. + * Performs the following actions: + * 1. Call wv_hw_config() + * 2. Start the LAN controller's receive unit + * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) + */ +static inline void +wv_hw_reset(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); +#endif + + /* If watchdog was activated, kill it ! */ + if(lp->watchdog.prev != (timer_list *) NULL) + del_timer(&lp->watchdog); + + lp->nresets++; + lp->configured = 0; + + /* Call wv_hw_config() for most of the reset & init stuff */ + if(wv_hw_config(dev) == FALSE) + return; + + /* start receive unit */ + wv_ru_start(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * wv_pcmcia_config() is called after a CARD_INSERTION event is + * received, to configure the PCMCIA socket, and to make the ethernet + * device available to the system. + * (called by wavelan_event()) + */ +static inline int +wv_pcmcia_config(dev_link_t * link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + struct net_device * dev; + int i; + u_char buf[64]; + win_req_t req; + memreq_t mem; + + handle = link->handle; + dev = (device *) link->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); +#endif + + /* + * This reads the card's CONFIG tuple to find its configuration + * registers. + */ + do + { + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + i = CardServices(GetFirstTuple, handle, &tuple); + if(i != CS_SUCCESS) + break; + tuple.TupleData = (cisdata_t *)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; + link->conf.Present = parse.config.rmask[0]; + } + while(0); + if(i != CS_SUCCESS) + { + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; + return FALSE; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + do + { + i = CardServices(RequestIO, link->handle, &link->io); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestIO, i); + break; + } + + /* + * Now allocate an interrupt line. Note that this does not + * actually assign a handler to the interrupt. + */ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestIRQ, i); + break; + } + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + link->conf.ConfigIndex = 1; + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestConfiguration, i); + break; + } + + /* + * Allocate a 4K memory window. Note that the dev_link_t + * structure provides space for one window handle -- if your + * device needs several windows, you'll need to keep track of + * the handles in your private data structure, link->priv. + */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = 0; req.Size = 0x1000; + req.AccessSpeed = mem_speed; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestWindow, i); + break; + } + + dev->rmem_start = dev->mem_start = + (u_long)ioremap(req.Base, 0x1000); + dev->rmem_end = dev->mem_end = dev->mem_start + req.Size; + + mem.CardOffset = 0; mem.Page = 0; + i = CardServices(MapMemPage, link->win, &mem); + if(i != CS_SUCCESS) + { + cs_error(link->handle, MapMemPage, i); + break; + } + + /* Feed device with this info... */ + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + dev->tbusy = 0; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n", + (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr); +#endif + + i = register_netdev(dev); + if(i != 0) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n"); +#endif + break; + } + } + while(0); /* Humm... Disguised goto !!! */ + + link->state &= ~DEV_CONFIG_PENDING; + /* If any step failed, release any partially configured state */ + if(i != 0) + { + wv_pcmcia_release((u_long) link); + return FALSE; + } + + /* ???? Could you explain me this, Dave ? */ + link->dev = &((net_local *) dev->priv)->node; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * After a card is removed, wv_pcmcia_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 +wv_pcmcia_release(u_long arg) /* Address of the interface struct */ +{ + dev_link_t * link = (dev_link_t *) arg; + device * dev = (device *) link->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); +#endif + + /* If the device is currently in use, we won't release until it is + * actually closed. */ + if(link->open) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wv_pcmcia_release: release postponed, device still open\n", + dev->name); +#endif + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Don't bother checking to see if these succeed or not */ + iounmap((u_char *)dev->mem_start); + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); +#endif +} /* wv_pcmcia_release */ + +/*------------------------------------------------------------------*/ +/* + * Sometimes, netwave_detach can't be performed following a call from + * cardmgr (device still open, pcmcia_release not done) and the device + * is put in a STALE_LINK state and remains in memory. + * + * This function run through our current list of device and attempt + * another time to remove them. We hope that since last time the + * device has properly been closed. + * + * (called by wavelan_attach() & cleanup_module()) + */ +static void +wv_flush_stale_links(void) +{ + dev_link_t * link; /* Current node in linked list */ + dev_link_t * next; /* Next node in linked list */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "-> wv_flush_stale_links(0x%p)\n", dev_list); +#endif + + /* Go through the list */ + for (link = dev_list; link; link = next) + { + next = link->next; + + /* Check if in need of being removed */ + if((link->state & DEV_STALE_LINK) || + (! (link->state & DEV_PRESENT))) + wavelan_detach(link); + + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "<- wv_flush_stale_links()\n"); +#endif +} + +/************************ INTERRUPT HANDLING ************************/ + +/* + * This function is the interrupt handler for the WaveLAN card. This + * routine will be called whenever: + * 1. A packet is received. + * 2. A packet has successfully been transfered and the unit is + * ready to transmit another packet. + * 3. A command has completed execution. + */ +static void +wavelan_interrupt(int irq, + void * dev_id, + struct pt_regs * regs) +{ + device * dev; + net_local * lp; + ioaddr_t base; + int status0; + u_int tx_status; + + if((dev = (device *)dev_id) == (device *) NULL) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", + irq); +#endif + return; + } + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); +#endif + + lp = (net_local *) dev->priv; + base = dev->base_addr; + + /* Prevent reentrance. What should we do here ? */ +#ifdef DEBUG_INTERRUPT_ERROR + if(dev->interrupt) + printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n", + dev->name); +#endif + dev->interrupt = 1; + + /* Treat all pending interrupts */ + while(1) + { + /* ---------------- INTERRUPT CHECKING ---------------- */ + /* + * Look for the interrupt and verify the validity + */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); + status0 = inb(LCSR(base)); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, + (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT); + if(status0&SR0_INTERRUPT) + { + printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" : + ((status0 & SR0_EXECUTION) ? "cmd" : + ((status0 & SR0_RECEPTION) ? "recv" : "unknown")), + (status0 & SR0_EVENT_MASK)); + } + else + printk("\n"); +#endif + + /* Return if no actual interrupt from i82593 (normal exit) */ + if(!(status0 & SR0_INTERRUPT)) + break; + + /* If interrupt is both Rx and Tx or none... + * This code in fact is there to catch the spurious interrupt + * when you remove the wavelan pcmcia card from the socket */ + if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) || + ((status0 & SR0_BOTH_RX_TX) == 0x0)) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n", + dev->name, status0); +#endif + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + break; + } + + lp->status = status0; /* Save current status (for commands) */ + + /* ----------------- RECEIVING PACKET ----------------- */ + /* + * When the wavelan signal the reception of a new packet, + * we call wv_packet_rcv() to copy if from the buffer and + * send it to NET3 + */ + if(status0 & SR0_RECEPTION) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name); +#endif + + if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n", + dev->name); +#endif + lp->stats.rx_over_errors++; + lp->overrunning = 1; + } + + /* Get the packet */ + wv_packet_rcv(dev); + lp->overrunning = 0; + + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + continue; + } + + /* ---------------- COMMAND COMPLETION ---------------- */ + /* + * Interrupts issued when the i82593 has completed a command. + * Most likely : transmission done + */ + + /* If we are already waiting elsewhere for the command to complete */ + if(wv_wait_completed) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n", + dev->name); +#endif + + /* Signal command completion */ + wv_wait_completed = 0; + + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + continue; + } + + /* If a transmission has been done */ + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + { +#ifdef DEBUG_TX_ERROR + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n", + dev->name); +#endif + + /* If watchdog was activated, kill it ! */ + if(lp->watchdog.prev != (timer_list *) NULL) + del_timer(&lp->watchdog); + + /* Get transmission status */ + tx_status = inb(LCSR(base)); + tx_status |= (inb(LCSR(base)) << 8); +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n", + dev->name); + { + u_int rcv_bytes; + u_char status3; + rcv_bytes = inb(LCSR(base)); + rcv_bytes |= (inb(LCSR(base)) << 8); + status3 = inb(LCSR(base)); + printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n", + tx_status, rcv_bytes, (u_int) status3); + } +#endif + /* Check for possible errors */ + if((tx_status & TX_OK) != TX_OK) + { + lp->stats.tx_errors++; + + if(tx_status & TX_FRTL) + { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_interrupt(): frame too long\n", + dev->name); +#endif + } + if(tx_status & TX_UND_RUN) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n", + dev->name); +#endif + lp->stats.tx_aborted_errors++; + } + if(tx_status & TX_LOST_CTS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name); +#endif + lp->stats.tx_carrier_errors++; + } + if(tx_status & TX_LOST_CRS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n", + dev->name); +#endif + lp->stats.tx_carrier_errors++; + } + if(tx_status & TX_HRT_BEAT) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name); +#endif + lp->stats.tx_heartbeat_errors++; + } + if(tx_status & TX_DEFER) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n", + dev->name); +#endif + } + /* Ignore late collisions since they're more likely to happen + * here (the WaveLAN design prevents the LAN controller from + * receiving while it is transmitting). We take action only when + * the maximum retransmit attempts is exceeded. + */ + if(tx_status & TX_COLL) + { + if(tx_status & TX_MAX_COL) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n", + dev->name); +#endif + if(!(tx_status & TX_NCOL_MASK)) + { + lp->stats.collisions += 0x10; + } + } + } + } /* if(!(tx_status & TX_OK)) */ + + lp->stats.collisions += (tx_status & TX_NCOL_MASK); + lp->stats.tx_packets++; + + dev->tbusy = FALSE; + mark_bh(NET_BH); + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + else /* if interrupt = transmit done or retransmit done */ + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n", + status0); +#endif + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + } + dev->interrupt = FALSE; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); +#endif +} /* wv_interrupt */ + +/*------------------------------------------------------------------*/ +/* + * Watchdog : when we start a transmission, we set a timer in the + * kernel. If the transmission complete, this timer is disabled. If + * it expire, it try to unlock the hardware. + * + * Note : this watchdog doesn't work on the same principle as the + * watchdog in the ISA driver. I make it this way because the overhead + * of add_timer() and del_timer() is nothing and that it avoid calling + * the watchdog, saving some CPU... If you want to apply the same + * watchdog to the ISA driver, you should be a bit carefull, because + * of the many transmit buffers... + * This watchdog is also move clever, it try to abort the current + * command before reseting everything... + */ +static void +wavelan_watchdog(u_long a) +{ + device * dev; + net_local * lp; + ioaddr_t base; + int spin; + + dev = (device *) a; + base = dev->base_addr; + lp = (net_local *) dev->priv; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); +#endif + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", + dev->name); +#endif + + /* We are waiting for command completion */ + wv_wait_completed = TRUE; + + /* Ask to abort the current command */ + outb(OP0_ABORT, LCCR(base)); + + /* Busy wait while the LAN controller executes the command. + * Note : wv_wait_completed should be volatile */ + spin = 0; + while(wv_wait_completed && (spin++ < 250)) + udelay(10); + + /* If the interrupt handler hasn't be called or invalid status */ + if((wv_wait_completed) || + ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED)) + { + /* It seem that it wasn't enough */ +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n", + dev->name); +#endif + wv_hw_reset(dev); + } + +#ifdef DEBUG_PSA_SHOW + { + psa_t psa; + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + wv_psa_show(&psa); + } +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + + /* We are no more waiting for something... */ + dev->tbusy = 0; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); +#endif +} + +/********************* CONFIGURATION CALLBACKS *********************/ +/* + * Here are the functions called by the pcmcia package (cardmgr) and + * linux networking (NET3) for initialization, configuration and + * deinstallations of the Wavelan Pcmcia Hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Configure and start up the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "open" the device. + */ +static int +wavelan_open(device * dev) +{ + dev_link_t * link = ((net_local *) dev->priv)->link; + net_local * lp = (net_local *)dev->priv; + ioaddr_t base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Check if the modem is powered up (wavelan_close() power it down */ + if(hasr_read(base) & HASR_NO_CLK) + { + /* Power up (power up time is 250us) */ + hacr_write(base, HACR_DEFAULT); + + /* Check if the the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n", + dev->name); +#endif + return FALSE; + } + } + + /* Start reception and declare the driver ready */ + if(!lp->configured) + return FALSE; + if(!wv_ru_start(dev)) + wv_hw_reset(dev); /* If problem : reset */ + dev->interrupt = 0; + dev->start = 1; + dev->tbusy = 0; + + /* Mark the device as used */ + link->open++; + MOD_INC_USE_COUNT; + +#ifdef WAVELAN_ROAMING + if(do_roaming) + wv_roam_init(dev); +#endif /* WAVELAN_ROAMING */ + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Shutdown the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "close" the device. + */ +static int +wavelan_close(device * dev) +{ + dev_link_t * link = ((net_local *) dev->priv)->link; + net_local * lp = (net_local *)dev->priv; + ioaddr_t base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* If the device isn't open, then nothing to do */ + if(!link->open) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name); +#endif + return 0; + } + +#ifdef WAVELAN_ROAMING + /* Cleanup of roaming stuff... */ + if(do_roaming) + wv_roam_cleanup(dev); +#endif /* WAVELAN_ROAMING */ + + /* If watchdog was activated, kill it ! */ + if(lp->watchdog.prev != (timer_list *) NULL) + del_timer(&lp->watchdog); + + link->open--; + MOD_DEC_USE_COUNT; + + /* If the card is still present */ + if(dev->start) + { + dev->tbusy = 1; + dev->start = 0; + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + /* Power down the module */ + hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT)); + } + else + /* The card is no more there (flag is activated in wv_pcmcia_release) */ + if(link->state & DEV_STALE_CONFIG) + wv_pcmcia_release((u_long)link); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * We never need to do anything when a wavelan device is "initialized" + * by the net software, because we only register already-found cards. + */ +static int +wavelan_init(device * dev) +{ +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<>wavelan_init()\n"); +#endif + + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * wavelan_attach() creates an "instance" of the driver, allocating + * local data structures for one device (one interface). 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 * +wavelan_attach(void) +{ + client_reg_t client_reg; /* Register with cardmgr */ + dev_link_t * link; /* Info for cardmgr */ + device * dev; /* Interface generic data */ + net_local * lp; /* Interface specific data */ + int i, ret; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_attach()\n"); +#endif + + /* Perform some cleanup */ + wv_flush_stale_links(); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + + /* Unused for the Wavelan */ + link->release.function = &wv_pcmcia_release; + link->release.data = (u_long) link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 8; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 3; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = wavelan_interrupt; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Chain drivers */ + link->next = dev_list; + dev_list = link; + + /* Allocate the generic data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0x00, sizeof(struct net_device)); + link->priv = link->irq.Instance = dev; + + /* Allocate the wavelan-specific data structure. */ + dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); + memset(lp, 0x00, sizeof(net_local)); + + /* Init specific data */ + wv_wait_completed = 0; + lp->status = FALSE; + lp->configured = 0; + lp->reconfig_82593 = FALSE; + lp->nresets = 0; + + /* Set the watchdog timer */ + lp->watchdog.function = wavelan_watchdog; + lp->watchdog.data = (unsigned long) dev; + + /* back links */ + lp->link = link; + lp->dev = dev; + + /* Standard setup for generic data */ + ether_setup(dev); + + /* wavelan NET3 callbacks */ + dev->init = &wavelan_init; + dev->open = &wavelan_open; + dev->stop = &wavelan_close; + dev->hard_start_xmit = &wavelan_packet_xmit; + dev->get_stats = &wavelan_get_stats; + dev->set_multicast_list = &wavelan_set_multicast_list; +#ifdef SET_MAC_ADDRESS + dev->set_mac_address = &wavelan_set_mac_address; +#endif /* SET_MAC_ADDRESS */ + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ + dev->get_wireless_stats = wavelan_get_wireless_stats; +#endif + + /* Other specific data */ + /* Provide storage area for device name */ + dev->name = ((net_local *)dev->priv)->node.dev_name; + dev->tbusy = 1; + dev->mtu = WAVELAN_MTU; + + /* Register with Card Services */ + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_REGISTRATION_COMPLETE | + 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 = &wavelan_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n"); +#endif + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if(ret != 0) + { + cs_error(link->handle, RegisterClient, ret); + wavelan_detach(link); + return NULL; + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_attach()\n"); +#endif + + return link; +} + +/*------------------------------------------------------------------*/ +/* + * 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 +wavelan_detach(dev_link_t * link) +{ +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); +#endif + + /* + * 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) + { + /* Some others haven't done their job : give them another chance */ + wv_pcmcia_release((u_long) link); + if(link->state & DEV_STALE_CONFIG) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_detach: detach postponed," + " '%s' still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if(link->handle) + CardServices(DeregisterClient, link->handle); + + /* Remove the interface data from the linked list */ + if(dev_list == link) + dev_list = link->next; + else + { + dev_link_t * prev = dev_list; + + while((prev != (dev_link_t *) NULL) && (prev->next != link)) + prev = prev->next; + + if(prev == (dev_link_t *) NULL) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n"); +#endif + return; + } + + prev->next = link->next; + } + + /* Free pieces */ + if(link->priv) + { + device * dev = (device *) link->priv; + + /* Remove ourselves from the kernel list of ethernet devices */ + /* Warning : can't be called from interrupt, timer or wavelan_close() */ + if(link->dev != NULL) + unregister_netdev(dev); + link->dev = NULL; + + if(dev->priv) + { + /* Sound strange, but safe... */ + ((net_local *) dev->priv)->link = (dev_link_t *) NULL; + ((net_local *) dev->priv)->dev = (device *) NULL; + kfree(dev->priv); + } + kfree(link->priv); + } + kfree(link); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_detach()\n"); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * 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. + */ +static int +wavelan_event(event_t event, /* The event received */ + int priority, + event_callback_args_t * args) +{ + dev_link_t * link = (dev_link_t *) args->client_data; + device * dev = (device *) link->priv; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "->wavelan_event(): %s\n", + ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" : + ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" : + ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" : + ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" : + ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" : + ((event == CS_EVENT_PM_RESUME) ? "pm resume" : + ((event == CS_EVENT_CARD_RESET) ? "card reset" : + "unknown")))))))); +#endif + + switch(event) + { + case CS_EVENT_REGISTRATION_COMPLETE: +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_cs: registration complete\n"); +#endif + break; + + case CS_EVENT_CARD_REMOVAL: + /* Oups ! The card is no more there */ + link->state &= ~DEV_PRESENT; + if(link->state & DEV_CONFIG) + { + /* Accept no more transmissions */ + dev->tbusy = 1; dev->start = 0; + + /* Release the card */ + wv_pcmcia_release((u_long) link); + } + break; + + case CS_EVENT_CARD_INSERTION: + /* Reset and configure the card */ + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + if(wv_pcmcia_config(link) && + wv_hw_config(dev)) + wv_init_info(dev); + else + dev->irq = 0; + break; + + case CS_EVENT_PM_SUSPEND: + /* NB: wavelan_close will be called, but too late, so we are + * obliged to close nicely the wavelan here. David, could you + * close the device before suspending them ? And, by the way, + * could you, on resume, add a "route add -net ..." after the + * ifconfig up ??? Thanks... */ + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + /* Power down the module */ + hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); + + /* The card is now suspended */ + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if(link->state & DEV_CONFIG) + { + if(link->open) + { + dev->tbusy = 1; + dev->start = 0; + } + 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); + if(link->open) /* If RESET -> True, If RESUME -> False ??? */ + { + wv_hw_reset(dev); + dev->tbusy = 0; + dev->start = 1; + } + } + break; + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<-wavelan_event()\n"); +#endif + return 0; +} + +/****************************** MODULE ******************************/ +/* + * Module entry points : insertion & removal + */ + +/*------------------------------------------------------------------*/ +/* + * Module insertion : initialisation of the module. + * Register the card with cardmgr... + */ +static int __init +init_wavelan_cs(void) +{ + servinfo_t serv; + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> init_wavelan_cs()\n"); +#ifdef DEBUG_VERSION_SHOW + printk(KERN_DEBUG "%s", version); +#endif +#endif + + CardServices(GetCardServicesInfo, &serv); + if(serv.Revision != CS_RELEASE_CODE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "init_wavelan_cs: Card Services release does not match!\n"); +#endif + return -1; + } + + register_pccard_driver(&dev_info, &wavelan_attach, &wavelan_detach); + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- init_wavelan_cs()\n"); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Module removal + */ +static void __exit +exit_wavelan_cs(void) +{ +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> cleanup_module()\n"); +#endif +#ifdef DEBUG_BASIC_SHOW + printk(KERN_NOTICE "wavelan_cs: unloading\n"); +#endif + + /* Do some cleanup of the device list */ + wv_flush_stale_links(); + + /* If there remain some devices... */ +#ifdef DEBUG_CONFIG_ERRORS + if(dev_list != NULL) + { + /* Honestly, if this happen we are in a deep s**t */ + printk(KERN_INFO "wavelan_cs: devices remaining when removing module\n"); + printk(KERN_INFO "Please flush your disks and reboot NOW !\n"); + } +#endif + + unregister_pccard_driver(&dev_info); + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- cleanup_module()\n"); +#endif +} + +module_init(init_wavelan_cs); +module_exit(exit_wavelan_cs); diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h --- v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/wavelan_cs.h Wed Oct 20 21:33:12 1999 @@ -0,0 +1,773 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * + * This file contain all definition and declarations necessary for the + * wavelan pcmcia driver. This file is a private header, so it should + * be included only on wavelan_cs.c !!! + */ + +#ifndef WAVELAN_CS_H +#define WAVELAN_CS_H + +/************************** DOCUMENTATION **************************/ +/* + * This driver provide a Linux interface to the Wavelan Pcmcia hardware + * The Wavelan is a product of Lucent (http://www.wavelan.com/). + * This division was formerly part of NCR and then AT&T. + * Wavelan are also distributed by DEC (RoamAbout DS)... + * + * To know how to use this driver, read the PCMCIA HOWTO. + * If you want to exploit the many other fonctionalities, look comments + * in the code... + * + * This driver is the result of the effort of many peoples (see below). + */ + +/* ------------------------ SPECIFIC NOTES ------------------------ */ +/* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * The main options are : + * o WAVELAN_ROAMING, for the experimental roaming support. + * o SET_PSA_CRC, to have your card correctly recognised by + * an access point and the Point-to-Point diagnostic tool. + * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) + * (otherwise we always start afresh with some defaults) + * + * wavelan_cs.o is darn too big + * ------------------------- + * That's true ! There is a very simple way to reduce the driver + * object by 33% (yes !). Comment out the following line : + * #include + * Other compile options can also reduce the size of it... + * + * MAC address and hardware detection : + * ---------------------------------- + * The detection code of the wavelan chech that the first 3 + * octets of the MAC address fit the company code. This type of + * detection work well for AT&T cards (because the AT&T code is + * hardcoded in wavelan.h), but of course will fail for other + * manufacturer. + * + * If you are sure that your card is derived from the wavelan, + * here is the way to configure it : + * 1) Get your MAC address + * a) With your card utilities (wfreqsel, instconf, ...) + * b) With the driver : + * o compile the kernel with DEBUG_CONFIG_INFO enabled + * o Boot and look the card messages + * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) + * 3) Compile & verify + * 4) Send me the MAC code - I will include it in the next version... + * + */ + +/* --------------------- WIRELESS EXTENSIONS --------------------- */ +/* + * This driver is the first one to support "wireless extensions". + * This set of extensions provide you some way to control the wireless + * caracteristics of the hardware in a standard way and support for + * applications for taking advantage of it (like Mobile IP). + * + * You will need to enable the CONFIG_NET_RADIO define in the kernel + * configuration to enable the wireless extensions (this is the one + * giving access to the radio network device choice). + * + * It might also be a good idea as well to fetch the wireless tools to + * configure the device and play a bit. + */ + +/* ---------------------------- FILES ---------------------------- */ +/* + * wavelan_cs.c : The actual code for the driver - C functions + * + * wavelan_cs.h : Private header : local types / vars for the driver + * + * wavelan.h : Description of the hardware interface & structs + * + * i82593.h : Description if the Ethernet controler + */ + +/* --------------------------- HISTORY --------------------------- */ +/* + * The history of the Wavelan drivers is as complicated as history of + * the Wavelan itself (NCR -> AT&T -> Lucent). + * + * All started with Anders Klemets , + * writting a Wavelan ISA driver for the MACH microkernel. Girish + * Welling had also worked on it. + * Keith Moore modify this for the Pcmcia hardware. + * + * Robert Morris port these two drivers to BSDI + * and add specific Pcmcia support (there is currently no equivalent + * of the PCMCIA package under BSD...). + * + * Jim Binkley port both BSDI drivers to FreeBSD. + * + * Bruce Janson port the BSDI ISA driver to Linux. + * + * Anthony D. Joseph started modify Bruce driver + * (with help of the BSDI PCMCIA driver) for PCMCIA. + * Yunzhou Li finished is work. + * Joe Finney patched the driver to start + * correctly 2.00 cards (2.4 GHz with frequency selection). + * David Hinds integrated the whole in his + * Pcmcia package (+ bug corrections). + * + * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some + * patchs to the Pcmcia driver. After, I added code in the ISA driver + * for Wireless Extensions and full support of frequency selection + * cards. Now, I'm doing the same to the Pcmcia driver + some + * reorganisation. + * Loeke Brederveld from Lucent has given me + * much needed informations on the Wavelan hardware. + */ + +/* By the way : for the copyright & legal stuff : + * Almost everybody wrote code under GNU or BSD license (or alike), + * and want that their original copyright remain somewhere in the + * code (for myself, I go with the GPL). + * Nobody want to take responsibility for anything, except the fame... + */ + +/* --------------------------- CREDITS --------------------------- */ +/* + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and + * Loeke Brederveld of Lucent for providing extremely useful + * information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + * + * Additional Credits: + * + * This software was originally developed under Linux 1.2.3 + * (Slackware 2.0 distribution). + * And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with + * HP OmniBook 4000 & 5500. + * + * It is based on other device drivers and information either written + * or supplied by: + * James Ashton (jaa101@syseng.anu.edu.au), + * Ajay Bakre (bakre@paul.rutgers.edu), + * Donald Becker (becker@super.org), + * Jim Binkley , + * Loeke Brederveld , + * Allan Creighton (allanc@cs.su.oz.au), + * Brent Elphick , + * Joe Finney , + * Matthew Geier (matthew@cs.su.oz.au), + * Remo di Giovanni (remo@cs.su.oz.au), + * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), + * David Hinds , + * Jan Hoogendoorn (c/o marteijn@lucent.com), + * Bruce Janson , + * Anthony D. Joseph , + * Anders Klemets (klemets@paul.rutgers.edu), + * Yunzhou Li , + * Marc Meertens (mmeertens@lucent.com), + * Keith Moore, + * Robert Morris (rtm@das.harvard.edu), + * Ian Parkin (ian@cs.su.oz.au), + * John Rosenberg (johnr@cs.su.oz.au), + * George Rossi (george@phm.gov.au), + * Arthur Scott (arthur@cs.su.oz.au), + * Stanislav Sinyagin + * Peter Storey, + * Jean Tourrilhes , + * Girish Welling (welling@paul.rutgers.edu) + * Clark Woodworth + * Yongguang Zhang ... + */ + +/* ------------------------- IMPROVEMENTS ------------------------- */ +/* + * I proudly present : + * + * Changes made in 2.8.22 : + * ---------------------- + * - improved wv_set_multicast_list + * - catch spurious interrupt + * - correct release of the device + * + * Changes mades in release : + * ------------------------ + * - Reorganisation of the code, function name change + * - Creation of private header (wavelan_cs.h) + * - Reorganised debug messages + * - More comments, history, ... + * - Configure earlier (in "insert" instead of "open") + * and do things only once + * - mmc_init : configure the PSA if not done + * - mmc_init : 2.00 detection better code for 2.00 init + * - better info at startup + * - Correct a HUGE bug (volatile & uncalibrated busy loop) + * in wv_82593_cmd => config speedup + * - Stop receiving & power down on close (and power up on open) + * use "ifconfig down" & "ifconfig up ; route add -net ..." + * - Send packets : add watchdog instead of pooling + * - Receive : check frame wrap around & try to recover some frames + * - wavelan_set_multicast_list : avoid reset + * - add wireless extensions (ioctl & get_wireless_stats) + * get/set nwid/frequency on fly, info for /proc/net/wireless + * - Supress useless stuff from lp (net_local), but add link + * - More inlines + * - Lot of others minor details & cleanups + * + * Changes made in second release : + * ------------------------------ + * - Optimise wv_85893_reconfig stuff, fix potential problems + * - Change error values for ioctl + * - Non blocking wv_ru_stop() + call wv_reset() in case of problems + * - Remove development printk from wavelan_watchdog() + * - Remove of the watchdog to wavelan_close instead of wavelan_release + * fix potential problems... + * - Start debugging suspend stuff (but it's still a bit weird) + * - Debug & optimize dump header/packet in Rx & Tx (debug) + * - Use "readb" and "writeb" to be kernel 2.1 compliant + * - Better handling of bogus interrupts + * - Wireless extension : SETSPY and GETSPY + * - Remove old stuff (stats - for those needing it, just ask me...) + * - Make wireless extensions optional + * + * Changes made in third release : + * ----------------------------- + * - cleanups & typos + * - modif wireless ext (spy -> only one pointer) + * - new private ioctl to set/get quality & level threshold + * - Init : correct default value of level threshold for pcmcia + * - kill watchdog in hw_reset + * - more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) + * - Add message level (debug stuff in /var/adm/debug & errors not + * displayed at console and still in /var/adm/messages) + * + * Changes made in fourth release : + * ------------------------------ + * - multicast support (yes !) thanks to Yongguang Zhang. + * + * Changes made in fifth release (2.9.0) : + * ------------------------------------- + * - Revisited multicast code (it was mostly wrong). + * - protect code in wv_82593_reconfig with dev->tbusy (oups !) + * + * Changes made in sixth release (2.9.1a) : + * -------------------------------------- + * - Change the detection code for multi manufacturer code support + * - Correct bug (hang kernel) in init when we were "rejecting" a card + * + * Changes made in seventh release (2.9.1b) : + * ---------------------------------------- + * - Update to wireless extensions changes + * - Silly bug in card initial configuration (psa_conf_status) + * + * Changes made in eigth release : + * ----------------------------- + * - Small bug in debug code (probably not the last one...) + * - 1.2.13 support (thanks to Clark Woodworth) + * + * Changes made for release in 2.9.2b : + * ---------------------------------- + * - Level threshold is now a standard wireless extension (version 4 !) + * - modules parameters types for kernel > 2.1.17 + * - updated man page + * - Others cleanup from David Hinds + * + * Changes made for release in 2.9.5 : + * --------------------------------- + * - byte count stats (courtesy of David Hinds) + * - Remove dev_tint stuff (courtesy of David Hinds) + * - Others cleanup from David Hinds + * - Encryption setting from Brent Elphick (thanks a lot !) + * - 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) + * + * Changes made for release in 2.9.6 : + * --------------------------------- + * - fix bug : no longuer disable watchdog in case of bogus interrupt + * - increase timeout in config code for picky hardware + * - mask unused bits in status (Wireless Extensions) + * + * Changes integrated by Justin Seger & David Hinds : + * ----------------------------------------------------------------- + * - Roaming "hack" from Joe Finney + * - PSA CRC code from Bob Gray + * - Better initialisation of the i82593 controller + * from Joseph K. O'Sullivan + * + * Changes made for release in 3.0.10 : + * ---------------------------------- + * - Fix eject "hang" of the driver under 2.2.X : + * o create wv_flush_stale_links() + * o Rename wavelan_release to wv_pcmcia_release & move up + * o move unregister_netdev to wavelan_detach() + * o wavelan_release() no longer call wavelan_detach() + * o Supress "release" timer + * o Other cleanups & fixes + * - New MAC address in the probe + * - Reorg PSA_CRC code (endian neutral & cleaner) + * - Correct initialisation of the i82593 from Lucent manual + * - Put back the watchdog, with larger timeout + * - TRANSMIT_NO_CRC is a "normal" error, so recover from it + * from Derrick J Brashear + * - Better handling of TX and RX normal failure conditions + * - #ifdef out all the roaming code + * - Add ESSID & "AP current address" ioctl stubs + * - General cleanup of the code + * + * Changes made for release in 3.0.13 : + * ---------------------------------- + * - Re-enable compilation of roaming code by default, but with + * do_roaming = 0 + * - Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather + * at the demand of John Carol Langford + * - Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff. + * + * Changes made for release in 3.0.15 : + * ---------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * + * Changes made for release in 3.1.2 : + * --------------------------------- + * - Fix check for root permission (break instead of exit) + * - New nwid & encoding setting (Wireless Extension 9) + * + * Wishes & dreams: + * ---------------- + * - Cleanup and integrate the roaming code + * (std debug, set DomainID, decay avg and co...) + */ + +/***************************** INCLUDES *****************************/ + +/* Linux headers that we need */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_NET_RADIO +#include /* Wireless extensions */ +#endif + +/* Pcmcia headers that we need */ +#include +#include +#include +#include +#include +#include + +/* Wavelan declarations */ +#include "i82593.h" /* Definitions for the Intel chip */ + +#include "wavelan.h" /* Others bits of the hardware */ + +/************************** DRIVER OPTIONS **************************/ +/* + * `#define' or `#undef' the following constant to change the behaviour + * of the driver... + */ +#define WAVELAN_ROAMING /* Include experimental roaming code */ +#undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ +#undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ +#define USE_PSA_CONFIG /* Use info from the PSA */ +#undef STRUCT_CHECK /* Verify padding of structures */ +#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ +#undef SET_MAC_ADDRESS /* Experimental */ + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ +/* Warning : these stuff will slow down the driver... */ +#define WIRELESS_SPY /* Enable spying addresses */ +#undef HISTOGRAM /* Enable histogram of sig level... */ +#endif + +/****************************** DEBUG ******************************/ + +#undef DEBUG_MODULE_TRACE /* Module insertion/removal */ +#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ +#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ +#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ +#define DEBUG_INTERRUPT_ERROR /* problems */ +#undef DEBUG_CONFIG_TRACE /* Trace the config functions */ +#undef DEBUG_CONFIG_INFO /* What's going on... */ +#define DEBUG_CONFIG_ERRORS /* Errors on configuration */ +#undef DEBUG_TX_TRACE /* Transmission calls */ +#undef DEBUG_TX_INFO /* Header of the transmited packet */ +#undef DEBUG_TX_FAIL /* Normal failure conditions */ +#define DEBUG_TX_ERROR /* Unexpected conditions */ +#undef DEBUG_RX_TRACE /* Transmission calls */ +#undef DEBUG_RX_INFO /* Header of the transmited packet */ +#undef DEBUG_RX_FAIL /* Normal failure conditions */ +#define DEBUG_RX_ERROR /* Unexpected conditions */ +#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */ +#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ +#undef DEBUG_IOCTL_INFO /* Various debug info */ +#define DEBUG_IOCTL_ERROR /* What's going wrong */ +#define DEBUG_BASIC_SHOW /* Show basic startup info */ +#undef DEBUG_VERSION_SHOW /* Print version info */ +#undef DEBUG_PSA_SHOW /* Dump psa to screen */ +#undef DEBUG_MMC_SHOW /* Dump mmc to screen */ +#undef DEBUG_SHOW_UNUSED /* Show also unused fields */ +#undef DEBUG_I82593_SHOW /* Show i82593 status */ +#undef DEBUG_DEVICE_SHOW /* Show device parameters */ + +/************************ CONSTANTS & MACROS ************************/ + +#ifdef DEBUG_VERSION_SHOW +static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n"; +#endif + +/* Watchdog temporisation */ +#define WATCHDOG_JIFFIES (256*HZ/100) + +/* Fix a bug in some old wireless extension definitions */ +#ifndef IW_ESSID_MAX_SIZE +#define IW_ESSID_MAX_SIZE 32 +#endif + +/* ------------------------ PRIVATE IOCTL ------------------------ */ + +#define SIOCSIPQTHR SIOCDEVPRIVATE /* Set quality threshold */ +#define SIOCGIPQTHR SIOCDEVPRIVATE + 1 /* Get quality threshold */ +#define SIOCSIPROAM SIOCDEVPRIVATE + 2 /* Set roaming state */ +#define SIOCGIPROAM SIOCDEVPRIVATE + 3 /* Get roaming state */ + +#define SIOCSIPHISTO SIOCDEVPRIVATE + 6 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCDEVPRIVATE + 7 /* Get histogram values */ + +/*************************** WaveLAN Roaming **************************/ +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ + +#define WAVELAN_ROAMING_DEBUG 0 /* 1 = Trace of handover decisions */ + /* 2 = Info on each beacon rcvd... */ +#define MAX_WAVEPOINTS 7 /* Max visible at one time */ +#define WAVEPOINT_HISTORY 5 /* SNR sample history slow search */ +#define WAVEPOINT_FAST_HISTORY 2 /* SNR sample history fast search */ +#define SEARCH_THRESH_LOW 10 /* SNR to enter cell search */ +#define SEARCH_THRESH_HIGH 13 /* SNR to leave cell search */ +#define WAVELAN_ROAMING_DELTA 1 /* Hysteresis value (+/- SNR) */ +#define CELL_TIMEOUT 2*HZ /* in jiffies */ + +#define FAST_CELL_SEARCH 1 /* Boolean values... */ +#define NWID_PROMISC 1 /* for code clarity. */ + +typedef struct wavepoint_beacon +{ + unsigned char dsap, /* Unused */ + ssap, /* Unused */ + ctrl, /* Unused */ + O,U,I, /* Unused */ + spec_id1, /* Unused */ + spec_id2, /* Unused */ + pdu_type, /* Unused */ + seq; /* WavePoint beacon sequence number */ + unsigned short domain_id, /* WavePoint Domain ID */ + nwid; /* WavePoint NWID */ +} wavepoint_beacon; + +typedef struct wavepoint_history +{ + unsigned short nwid; /* WavePoint's NWID */ + int average_slow; /* SNR running average */ + int average_fast; /* SNR running average */ + unsigned char sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */ + unsigned char qualptr; /* Index into ringbuffer */ + unsigned char last_seq; /* Last seq. no seen for WavePoint */ + struct wavepoint_history *next; /* Next WavePoint in table */ + struct wavepoint_history *prev; /* Previous WavePoint in table */ + unsigned long last_seen; /* Time of last beacon recvd, jiffies */ +} wavepoint_history; + +struct wavepoint_table +{ + wavepoint_history *head; /* Start of ringbuffer */ + int num_wavepoints; /* No. of WavePoints visible */ + unsigned char locked; /* Table lock */ +}; + +#endif /* WAVELAN_ROAMING */ + +/****************************** TYPES ******************************/ + +/* Shortcuts */ +typedef struct net_device device; +typedef struct net_device_stats en_stats; +typedef struct iw_statistics iw_stats; +typedef struct iw_quality iw_qual; +typedef struct iw_freq iw_freq; +typedef struct net_local net_local; +typedef struct timer_list timer_list; + +/* Basic types */ +typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ + +/* + * Static specific data for the interface. + * + * For each network interface, Linux keep data in two structure. "device" + * keep the generic data (same format for everybody) and "net_local" keep + * the additional specific data. + * Note that some of this specific data is in fact generic (en_stats, for + * example). + */ +struct net_local +{ + dev_node_t node; /* ???? What is this stuff ???? */ + device * dev; /* Reverse link... */ + dev_link_t * link; /* pcmcia structure */ + en_stats stats; /* Ethernet interface statistics */ + int nresets; /* Number of hw resets */ + u_char configured; /* If it is configured */ + u_char reconfig_82593; /* Need to reconfigure the controler */ + u_char promiscuous; /* Promiscuous mode */ + u_char allmulticast; /* All Multicast mode */ + int mc_count; /* Number of multicast addresses */ + timer_list watchdog; /* To avoid blocking state */ + + u_char status; /* Current i82593 status */ + int stop; /* Current i82593 Stop Hit Register */ + int rfp; /* Last DMA machine receive pointer */ + int overrunning; /* Receiver overrun flag */ + +#ifdef WIRELESS_EXT + iw_stats wstats; /* Wireless specific stats */ +#endif + +#ifdef WIRELESS_SPY + int spy_number; /* Number of addresses to spy */ + mac_addr spy_address[IW_MAX_SPY]; /* The addresses to spy */ + iw_qual spy_stat[IW_MAX_SPY]; /* Statistics gathered */ +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + int his_number; /* Number of intervals */ + u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ + u_long his_sum[16]; /* Sum in interval */ +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + u_long domain_id; /* Domain ID we lock on for roaming */ + int filter_domains; /* Check Domain ID of beacon found */ + struct wavepoint_table wavepoint_table; /* Table of visible WavePoints*/ + wavepoint_history * curr_point; /* Current wavepoint */ + int cell_search; /* Searching for new cell? */ + struct timer_list cell_timer; /* Garbage collection */ +#endif /* WAVELAN_ROAMING */ +}; + +/**************************** PROTOTYPES ****************************/ + +#ifdef WAVELAN_ROAMING +/* ---------------------- ROAMING SUBROUTINES -----------------------*/ + +wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp); +wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp); +void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp); +void wl_cell_expiry(unsigned long data); +wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp); +void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq); +void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp); +void wv_nwid_filter(unsigned char mode, net_local *lp); +void wv_roam_init(struct net_device *dev); +void wv_roam_cleanup(struct net_device *dev); +#endif /* WAVELAN_ROAMING */ + +/* ----------------------- MISC SUBROUTINES ------------------------ */ +static inline unsigned long /* flags */ + wv_splhi(void); /* Disable interrupts */ +static inline void + wv_splx(unsigned long); /* ReEnable interrupts : flags */ +static void + cs_error(client_handle_t, /* Report error to cardmgr */ + int, + int); +/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ +static inline u_char /* data */ + hasr_read(u_long); /* Read the host interface : base address */ +static inline void + hacr_write(u_long, /* Write to host interface : base address */ + u_char), /* data */ + hacr_write_slow(u_long, + u_char); +static void + psa_read(device *, /* Read the Parameter Storage Area */ + int, /* offset in PSA */ + u_char *, /* buffer to fill */ + int), /* size to read */ + psa_write(device *, /* Write to the PSA */ + int, /* Offset in psa */ + u_char *, /* Buffer in memory */ + int); /* Length of buffer */ +static inline void + mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ + u_short, + u_char), + mmc_write(u_long, /* Write n bytes to the MMC */ + u_char, + u_char *, + int); +static inline u_char /* Read 1 byte from the MMC */ + mmc_in(u_long, + u_short); +static inline void + mmc_read(u_long, /* Read n bytes from the MMC */ + u_char, + u_char *, + int), + fee_wait(u_long, /* Wait for frequency EEprom : base address */ + int, /* Base delay to wait for */ + int); /* Number of time to wait */ +static void + fee_read(u_long, /* Read the frequency EEprom : base address */ + u_short, /* destination offset */ + u_short *, /* data buffer */ + int); /* number of registers */ +/* ---------------------- I82593 SUBROUTINES ----------------------- */ +static int + wv_82593_cmd(device *, /* synchronously send a command to i82593 */ + char *, + int, + int); +static inline int + wv_diag(device *); /* Diagnostique the i82593 */ +static int + read_ringbuf(device *, /* Read a receive buffer */ + int, + char *, + int); +static inline void + wv_82593_reconfig(device *); /* Reconfigure the controler */ +/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ +static inline void + wv_init_info(device *); /* display startup info */ +/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ +static en_stats * + wavelan_get_stats(device *); /* Give stats /proc/net/dev */ +/* ----------------------- PACKET RECEPTION ----------------------- */ +static inline int + wv_start_of_frame(device *, /* Seek beggining of current frame */ + int, /* end of frame */ + int); /* start of buffer */ +static inline void + wv_packet_read(device *, /* Read a packet from a frame */ + int, + int), + wv_packet_rcv(device *); /* Read all packets waiting */ +/* --------------------- PACKET TRANSMISSION --------------------- */ +static inline void + wv_packet_write(device *, /* Write a packet to the Tx buffer */ + void *, + short); +static int + wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ + device *); +/* -------------------- HARDWARE CONFIGURATION -------------------- */ +static inline int + wv_mmc_init(device *); /* Initialize the modem */ +static int + wv_ru_stop(device *), /* Stop the i82593 receiver unit */ + wv_ru_start(device *); /* Start the i82593 receiver unit */ +static int + wv_82593_config(device *); /* Configure the i82593 */ +static inline int + wv_pcmcia_reset(device *); /* Reset the pcmcia interface */ +static int + wv_hw_config(device *); /* Reset & configure the whole hardware */ +static inline void + wv_hw_reset(device *); /* Same, + start receiver unit */ +static inline int + wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ +static void + wv_pcmcia_release(u_long), /* Remove a device */ + wv_flush_stale_links(void); /* "detach" all possible devices */ +/* ---------------------- INTERRUPT HANDLING ---------------------- */ +static void +wavelan_interrupt(int, /* Interrupt handler */ + void *, + struct pt_regs *); +static void + wavelan_watchdog(u_long); /* Transmission watchdog */ +/* ------------------- CONFIGURATION CALLBACKS ------------------- */ +static int + wavelan_open(device *), /* Open the device */ + wavelan_close(device *), /* Close the device */ + wavelan_init(device *); /* Do nothing */ +static dev_link_t * + wavelan_attach(void); /* Create a new device */ +static void + wavelan_detach(dev_link_t *); /* Destroy a removed device */ +static int + wavelan_event(event_t, /* Manage pcmcia events */ + int, + event_callback_args_t *); + +/**************************** VARIABLES ****************************/ + +static dev_info_t dev_info = "wavelan_cs"; +static dev_link_t *dev_list = NULL; /* Linked list of devices */ + +/* WARNING : the following variable MUST be volatile + * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ +static volatile int wv_wait_completed = 0; + +/* + * Parameters that can be set with 'insmod' + * The exact syntax is 'insmod wavelan_cs.o =' + */ + +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4 and 3 */ +static int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +/* Shared memory speed, in ns */ +static int mem_speed = 0; + +/* New module interface */ +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(mem_speed, "i"); + +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ +/* Enable roaming mode ? No ! Please keep this to 0 */ +static int do_roaming = 0; +MODULE_PARM(do_roaming, "i"); +#endif /* WAVELAN_ROAMING */ + +#endif /* WAVELAN_CS_H */ + diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c --- v2.3.22/linux/drivers/net/pcmcia/xirc2ps_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/xirc2ps_cs.c Wed Oct 20 21:33:12 1999 @@ -0,0 +1,2364 @@ +/* [xirc2ps_cs.c wk 14.04.97] (1.31 1998/12/09 19:32:55) + * Xircom Creditcard Ethernet Adapter IIps driver + * + * This driver works for the CE2, CEM28, CEM33, CE3 and CEM56 cards. + * The CEM56 has some problems, but it works. + * The CEII card with the 14k4 modem and other old cards do not work. + * + * Written by Werner Koch (werner.koch@guug.de), + * based on David Hinds skeleton driver. + * + * You can get the latest driver revision from + * "http://www.d.shuttle.de/isil/xircom/xirc2ps.html" + * + * Please report bugs to: "xircom-bugs@isil.d.shuttle.de" + * + * A bug fix for the CEM56 to use modem and ethernet simultaneously + * was provided by Koen Van Herck (Koen.Van.Herck@xircom.com). + * + * If your card locks up you should use the option "lockup_hack=1"; + * this may solve the problem but violates a kernel timing convention + * (Thanks to David Luyer). + * + * Thanks to David Hinds for the PCMCIA package, Donald Becker for some + * advice, Xircom for providing specs and help, 4PC GmbH Duesseldorf for + * providing some hardware and last not least to all folks who helped to + * develop this driver. + * + * For those, who are willing to do alpha testing of drivers, I have setup + * the mailing list "xircom-devel@isil.d.shuttle.de" (To subscribe send a + * message containing the word "subscribe" in the subject or somewhere at + * the beginning of a line to "xircom-devel-request@isil.d.shuttle.de"). + * + ************************************************************************ + * Copyright (c) 1997,1998 Werner Koch (dd9jn) + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * ALTERNATIVELY, this driver may be distributed under the terms of + * the following license, in which case the provisions of this license + * are required INSTEAD OF the GNU General Public License. (This clause + * is necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Enable the bug fix for CEM56 to use modem and ethernet simultaneously */ +#define CEM56_FIX + +#if !defined(PCMCIA_DEBUG) && 0 + #define PCMCIA_DEBUG 4 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef MANFID_XIRCOM + #define MANFID_XIRCOM 0x0105 +#endif +#ifndef MANFID_COMPAQ + #define MANFID_COMPAQ 0x0138 + #define MANFID_COMPAQ2 0x0183 /* is this correct? */ +#endif +#ifndef MANFID_INTEL + #define MANFID_INTEL 0x0089 +#endif + +#include + +/* Time in jiffies before concluding Tx hung */ +#define TX_TIMEOUT ((400*HZ)/1000) + +/**************** + * Some constants used to access the hardware + */ + +/* Register offsets and value constans */ +#define XIRCREG_CR 0 /* Command register (wr) */ +enum xirc_cr { + TransmitPacket = 0x01, + SoftReset = 0x02, + EnableIntr = 0x04, + ForceIntr = 0x08, + ClearTxFIFO = 0x10, + ClearRxOvrun = 0x20, + RestartTx = 0x40 +}; +#define XIRCREG_ESR 0 /* Ethernet status register (rd) */ +enum xirc_esr { + FullPktRcvd = 0x01, /* full packet in receive buffer */ + PktRejected = 0x04, /* a packet has been rejected */ + TxPktPend = 0x08, /* TX Packet Pending */ + IncorPolarity = 0x10, + MediaSelect = 0x20 /* set if TP, clear if AUI */ +}; +#define XIRCREG_PR 1 /* Page Register select */ +#define XIRCREG_EDP 4 /* Ethernet Data Port Register */ +#define XIRCREG_ISR 6 /* Ethernet Interrupt Status Register */ +enum xirc_isr { + TxBufOvr = 0x01, /* TX Buffer Overflow */ + PktTxed = 0x02, /* Packet Transmitted */ + MACIntr = 0x04, /* MAC Interrupt occured */ + TxResGrant = 0x08, /* Tx Reservation Granted */ + RxFullPkt = 0x20, /* Rx Full Packet */ + RxPktRej = 0x40, /* Rx Packet Rejected */ + ForcedIntr= 0x80 /* Forced Interrupt */ +}; +#define XIRCREG1_IMR0 12 /* Ethernet Interrupt Mask Register (on page 1)*/ +#define XIRCREG1_IMR1 13 +#define XIRCREG0_TSO 8 /* Transmit Space Open Register (on page 0)*/ +#define XIRCREG0_TRS 10 /* Transmit reservation Size Register (page 0)*/ +#define XIRCREG0_DO 12 /* Data Offset Register (page 0) (wr) */ +#define XIRCREG0_RSR 12 /* Receive Status Register (page 0) (rd) */ +enum xirc_rsr { + PhyPkt = 0x01, /* set:physical packet, clear: multicast packet */ + BrdcstPkt = 0x02, /* set if it is a broadcast packet */ + PktTooLong = 0x04, /* set if packet length > 1518 */ + AlignErr = 0x10, /* incorrect CRC and last octet not complete */ + CRCErr = 0x20, /* incorrect CRC and last octet is complete */ + PktRxOk = 0x80 /* received ok */ +}; +#define XIRCREG0_PTR 13 /* packets transmitted register (rd) */ +#define XIRCREG0_RBC 14 /* receive byte count regsister (rd) */ +#define XIRCREG1_ECR 14 /* ethernet configurationn register */ +enum xirc_ecr { + FullDuplex = 0x04, /* enable full duplex mode */ + LongTPMode = 0x08, /* adjust for longer lengths of TP cable */ + DisablePolCor = 0x10,/* disable auto polarity correction */ + DisableLinkPulse = 0x20, /* disable link pulse generation */ + DisableAutoTx = 0x40, /* disable auto-transmit */ +}; +#define XIRCREG2_RBS 8 /* receive buffer start register */ +#define XIRCREG2_LED 10 /* LED Configuration register */ +/* values for the leds: Bits 2-0 for led 1 + * 0 disabled Bits 5-3 for led 2 + * 1 collision + * 2 noncollision + * 3 link_detected + * 4 incor_polarity + * 5 jabber + * 6 auto_assertion + * 7 rx_tx_activity + */ +#define XIRCREG2_MSR 12 /* Mohawk specific register */ + +#define XIRCREG4_GPR0 8 /* General Purpose Register 0 */ +#define XIRCREG4_GPR1 9 /* General Purpose Register 1 */ +#define XIRCREG2_GPR2 13 /* General Purpose Register 2 (page2!)*/ +#define XIRCREG4_BOV 10 /* Bonding Version Register */ +#define XIRCREG4_LMA 12 /* Local Memory Address Register */ +#define XIRCREG4_LMD 14 /* Local Memory Data Port */ +/* MAC register can only by accessed with 8 bit operations */ +#define XIRCREG40_CMD0 8 /* Command Register (wr) */ +enum xirc_cmd { /* Commands */ + Transmit = 0x01, + EnableRecv = 0x04, + DisableRecv = 0x08, + Abort = 0x10, + Online = 0x20, + IntrAck = 0x40, + Offline = 0x80 +}; +#define XIRCREG5_RHSA0 10 /* Rx Host Start Address */ +#define XIRCREG40_RXST0 9 /* Receive Status Register */ +#define XIRCREG40_TXST0 11 /* Transmit Status Register 0 */ +#define XIRCREG40_TXST1 12 /* Transmit Status Register 10 */ +#define XIRCREG40_RMASK0 13 /* Receive Mask Register */ +#define XIRCREG40_TMASK0 14 /* Transmit Mask Register 0 */ +#define XIRCREG40_TMASK1 15 /* Transmit Mask Register 0 */ +#define XIRCREG42_SWC0 8 /* Software Configuration 0 */ +#define XIRCREG42_SWC1 9 /* Software Configuration 1 */ +#define XIRCREG42_BOC 10 /* Back-Off Configuration */ +#define XIRCREG44_TDR0 8 /* Time Domain Reflectometry 0 */ +#define XIRCREG44_TDR1 9 /* Time Domain Reflectometry 1 */ +#define XIRCREG44_RXBC_LO 10 /* Rx Byte Count 0 (rd) */ +#define XIRCREG44_RXBC_HI 11 /* Rx Byte Count 1 (rd) */ +#define XIRCREG45_REV 15 /* Revision Register (rd) */ +#define XIRCREG50_IA 8 /* Individual Address (8-13) */ + +static char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" }; + +/**************** + * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + * you do not define PCMCIA_DEBUG at all, all the debug code will be + * left out. If you compile with PCMCIA_DEBUG=0, the debug code will + * be present but disabled -- but it can then be enabled for specific + * modules at load time with a 'pc_debug=#' option to insmod. + */ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#endif +static char *version = +"xirc2ps_cs.c 1.31 1998/12/09 19:32:55 (dd9jn+kvh)"; + /* !--- CVS revision */ +#define KDBG_XIRC KERN_DEBUG "xirc2ps_cs: " +#define KERR_XIRC KERN_ERR "xirc2ps_cs: " +#define KWRN_XIRC KERN_WARNING "xirc2ps_cs: " +#define KNOT_XIRC KERN_NOTICE "xirc2ps_cs: " +#define KINF_XIRC KERN_INFO "xirc2ps_cs: " + +/* card types */ +#define XIR_UNKNOWN 0 /* unknown: not supported */ +#define XIR_CE 1 /* (prodid 1) different hardware: not supported */ +#define XIR_CE2 2 /* (prodid 2) */ +#define XIR_CE3 3 /* (prodid 3) */ +#define XIR_CEM 4 /* (prodid 1) different hardware: not supported */ +#define XIR_CEM2 5 /* (prodid 2) */ +#define XIR_CEM3 6 /* (prodid 3) */ +#define XIR_CEM33 7 /* (prodid 4) */ +#define XIR_CEM56M 8 /* (prodid 5) */ +#define XIR_CEM56 9 /* (prodid 6) */ +#define XIR_CM28 10 /* (prodid 3) modem only: not supported here */ +#define XIR_CM33 11 /* (prodid 4) modem only: not supported here */ +#define XIR_CM56 12 /* (prodid 5) modem only: not supported here */ +#define XIR_CG 13 /* (prodid 1) GSM modem only: not supported */ +#define XIR_CBE 14 /* (prodid 1) cardbus ethernet: not supported */ +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ +static int if_port = 0; +MODULE_PARM(if_port, "i"); + +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_long irq_mask = 0xdeb8; +MODULE_PARM(irq_mask, "i"); + +static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); + +static int do_sound = 1; +MODULE_PARM(do_sound, "i"); + +static int card_type = 0; +MODULE_PARM(card_type, "i"); /* dummy, not used anymore */ + +static int lockup_hack = 0; +MODULE_PARM(lockup_hack, "i"); /* anti lockup hack */ + +/*====================================================================*/ + +/* We do not process more than these number of bytes during one + * interrupt. (Of course we receive complete packets, so this is not + * an exact value). + * Something between 2000..22000; first value gives best interrupt latency, + * the second enables the usage of the complete on-chip buffer. We use the + * high value as the initial value. + */ +static unsigned maxrx_bytes = 22000; + +/* MII management prototypes */ +static void mii_idle(ioaddr_t ioaddr); +static void mii_putbit(ioaddr_t ioaddr, unsigned data); +static int mii_getbit( ioaddr_t ioaddr ); +static void mii_wbits(ioaddr_t ioaddr, unsigned data, int len); +static unsigned mii_rd(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg); +static void mii_wr(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg, + unsigned data, int len); + +/* + * 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 event handler. + */ + +static int has_ce2_string(dev_link_t * link); +static void xirc2ps_config(dev_link_t * link); +static void xirc2ps_release(u_long arg); +static int xirc2ps_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 *xirc2ps_attach(void); +static void xirc2ps_detach(dev_link_t *); + +/**************** + * You'll also need to prototype all the functions that will actually + * be used to talk to your device. See 'pcmem_cs' for a good example + * of a fully self-sufficient driver; the other drivers rely more or + * less on other parts of the kernel. + */ + +static void xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* + * 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 = "xirc2ps_cs"; + +/**************** + * A linked list of "instances" of the 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; + struct enet_statistics stats; + int card_type; + int probe_port; + int silicon; /* silicon revision. 0=old CE2, 1=Scipper, 4=Mohawk */ + int mohawk; /* a CE3 type card */ + int dingo; /* a CEM56 type card */ + int modem; /* is a multi function card (i.e with a modem) */ + caddr_t dingo_ccr; /* only used for CEM56 cards */ + int suspended; + unsigned last_ptr_value; /* last packets transmitted value */ + const char *manf_str; +} local_info_t; + +/**************** + * Some more prototypes + */ +static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); +static struct enet_statistics *do_get_stats(struct net_device *dev); +static void set_addresses(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static int do_init(struct net_device *dev); +static int set_card_type( dev_link_t *link, const void *s ); +static int do_config(struct net_device *dev, struct ifmap *map); +static int do_open(struct net_device *dev); +static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void hardreset(struct net_device *dev); +static void do_reset(struct net_device *dev, int full); +static int init_mii(struct net_device *dev); +static void do_powerdown(struct net_device *dev); +static int do_stop(struct net_device *dev); + +/*=============== Helper functions =========================*/ +static void +flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + xirc2ps_detach(link); + } +} + +static void +cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +static int +get_tuple_data(int fn, client_handle_t handle, tuple_t *tuple ) +{ + int err; + + if( (err=CardServices(fn, handle, tuple)) ) + return err; + return CardServices(GetTupleData, handle, tuple); +} + +static int +get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + int err; + + if( (err=get_tuple_data(fn, handle, tuple)) ) + return err; + 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) + +#define SelectPage(pgnr) outb((pgnr), ioaddr + XIRCREG_PR) +#define GetByte(reg) ((unsigned)inb(ioaddr + (reg))) +#define GetWord(reg) ((unsigned)inw(ioaddr + (reg))) +#define PutByte(reg,value) outb((value), ioaddr+(reg)) +#define PutWord(reg,value) outw((value), ioaddr+(reg)) + +static void +busy_loop(u_long len) +{ + u_long timeout = jiffies + len; + u_long flags; + + save_flags(flags); + sti(); + while(timeout >= jiffies) + ; + restore_flags(flags); +} + +/*====== Functions used for debugging =================================*/ +#if defined(PCMCIA_DEBUG) && 0 /* reading regs may change system status */ +static void +PrintRegisters(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + + if(pc_debug > 1) { + int i, page; + + printk(KDBG_XIRC "Register common: "); + for(i = 0; i < 8; i++ ) + printk(" %2.2x", GetByte(i) ); + printk("\n"); + for(page = 0; page <= 8; page++) { + printk(KDBG_XIRC "Register page %2x: ", page); + SelectPage(page); + for(i = 8; i < 16; i++) + printk(" %2.2x", GetByte(i)); + printk("\n"); + } + for(page=0x40 ; page <= 0x5f; page++) { + if( page == 0x43 || (page >= 0x46 && page <= 0x4f) + || (page >= 0x51 && page <=0x5e) ) + continue; + printk(KDBG_XIRC "Register page %2x: ", page); + SelectPage(page); + for(i = 8; i < 16; i++) + printk(" %2.2x", GetByte(i)); + printk("\n"); + } + } +} +#endif /* PCMCIA_DEBUG */ + +/*============== MII Management functions ===============*/ + +/**************** + * Turn around for read + */ +static void +mii_idle(ioaddr_t ioaddr) +{ + PutByte(XIRCREG2_GPR2, 0x04|0 ); /* drive MDCK low */ + udelay(1); + PutByte(XIRCREG2_GPR2, 0x04|1 ); /* and drive MDCK high */ + udelay(1); +} + +/**************** + * Write a bit to MDI/O + */ +static void +mii_putbit(ioaddr_t ioaddr, unsigned data) +{ + #if 1 + if( data ) { + PutByte(XIRCREG2_GPR2, 0x0c|2|0 ); /* set MDIO */ + udelay(1); + PutByte(XIRCREG2_GPR2, 0x0c|2|1 ); /* and drive MDCK high */ + udelay(1); + } + else { + PutByte(XIRCREG2_GPR2, 0x0c|0|0 ); /* clear MDIO */ + udelay(1); + PutByte(XIRCREG2_GPR2, 0x0c|0|1 ); /* and drive MDCK high */ + udelay(1); + } + #else + if( data ) { + PutWord(XIRCREG2_GPR2-1, 0x0e0e ); + udelay(1); + PutWord(XIRCREG2_GPR2-1, 0x0f0f ); + udelay(1); + } + else { + PutWord(XIRCREG2_GPR2-1, 0x0c0c ); + udelay(1); + PutWord(XIRCREG2_GPR2-1, 0x0d0d ); + udelay(1); + } + #endif +} + +/**************** + * Get a bit from MDI/O + */ +static int +mii_getbit( ioaddr_t ioaddr ) +{ + unsigned d; + + PutByte(XIRCREG2_GPR2, 4|0 ); /* drive MDCK low */ + udelay(1); + d = GetByte(XIRCREG2_GPR2); /* read MDIO */ + PutByte(XIRCREG2_GPR2, 4|1 ); /* drive MDCK high again */ + udelay(1); + return d & 0x20; /* read MDIO */ +} + +static void +mii_wbits(ioaddr_t ioaddr, unsigned data, int len) +{ + unsigned m = 1 << (len-1); + for( ; m; m >>= 1) + mii_putbit( ioaddr, data & m ); +} + +static unsigned +mii_rd(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg) +{ + int i; + unsigned data=0, m; + + SelectPage(2); + for( i=0; i < 32; i++ ) /* 32 bit preamble */ + mii_putbit(ioaddr, 1); + mii_wbits(ioaddr, 0x06, 4); /* Start and opcode for read */ + mii_wbits(ioaddr, phyaddr, 5); /* PHY address to be accessed */ + mii_wbits(ioaddr, phyreg, 5); /* PHY register to read */ + mii_idle(ioaddr); /* turn around */ + mii_getbit( ioaddr); + + for( m = 1<<15; m; m >>= 1 ) + if( mii_getbit( ioaddr ) ) + data |= m; + mii_idle(ioaddr); + return data; +} + +static void +mii_wr(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len) +{ + int i; + + SelectPage(2); + for( i=0; i < 32; i++ ) /* 32 bit preamble */ + mii_putbit(ioaddr, 1); + mii_wbits(ioaddr, 0x05, 4); /* Start and opcode for write */ + mii_wbits(ioaddr, phyaddr, 5); /* PHY address to be accessed */ + mii_wbits(ioaddr, phyreg, 5); /* PHY Register to write */ + mii_putbit(ioaddr, 1); /* turn around */ + mii_putbit(ioaddr, 0); + mii_wbits(ioaddr, data, len); /* And write the data */ + mii_idle(ioaddr); +} + +#ifdef PCMCIA_DEBUG +static void +mii_dump(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + int i; + + /* Note that registers 14, 1d,1e and 1f are reserved and should + * not be read according to the DP83840A specs. + */ + printk(KERN_DEBUG "%s: MII register dump:\n", dev->name); + for(i=0; i < 32; i++ ) { + if( !(i % 8) ) { + if( i ) + printk("\n"); + printk(KERN_DEBUG "%s:", dev->name ); + } + printk(" %04x", mii_rd(ioaddr, 0, i) ); + } + printk("\n"); +} +#endif + +/*============= Main bulk of functions =========================*/ + +/**************** + * xirc2ps_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 * +xirc2ps_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + local_info_t *local; + int err; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "attach()\n"); + #endif + flush_stale_links(); + + /* 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 = &xirc2ps_release; + link->release.data = (u_long) link; + + /* 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 a device structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + memset(local, 0, sizeof(local_info_t)); + dev->priv = local; + + /* Fill in card specific entries */ + dev->hard_start_xmit = &do_start_xmit; + dev->set_config = &do_config; + dev->get_stats = &do_get_stats; + dev->do_ioctl = &do_ioctl; + dev->set_multicast_list = &set_multicast_list; + ether_setup(dev); + dev->name = local->node.dev_name; + dev->init = &do_init; + dev->open = &do_open; + dev->stop = &do_stop; + dev->tbusy = 1; + link->priv = dev; + + /* 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 = &xirc2ps_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + if( (err = CardServices(RegisterClient, &link->handle, &client_reg)) ) { + cs_error(link->handle, RegisterClient, err); + xirc2ps_detach(link); + return NULL; + } + + return link; +} /* xirc2ps_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 +xirc2ps_detach(dev_link_t * link) +{ + dev_link_t **linkp; + long flags; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "detach(0x%p)\n", link); + #endif + + /* Locate device structure */ + for( linkp = &dev_list; *linkp; linkp = &(*linkp)->next ) + if( *linkp == link) + break; + if( !*linkp ) { + #ifdef PCMCIA_DEBUG + printk(KDBG_XIRC "detach(0x%p): dev_link lost\n", link ); + #endif + return; + } + + save_flags(flags); + cli(); + if( link->state & DEV_RELEASE_PENDING ) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + /* + * 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) { + #ifdef PCMCIA_DEBUG + printk(KDBG_XIRC "detach postponed, '%s' " + "still locked\n", link->dev->dev_name); + #endif + 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) { + struct net_device *dev = link->priv; + if (link->dev != NULL) + unregister_netdev(dev); + if( dev->priv ) + kfree(dev->priv); + kfree(link->priv); + } + kfree(link); + +} /* xirc2ps_detach */ + +/**************** + * Detect the type of the card. s is the buffer with the data of tuple 0x20 + * Returns: 0 := not supported + * mediaid=11 and prodid=47 + * Media-Id bits: + * Ethernet 0x01 + * Tokenring 0x02 + * Arcnet 0x04 + * Wireless 0x08 + * Modem 0x10 + * GSM only 0x20 + * Prod-Id bits: + * Pocket 0x10 + * External 0x20 + * Creditcard 0x40 + * Cardbus 0x80 + * + */ +static int +set_card_type( dev_link_t *link, const void *s ) +{ + struct net_device *dev = link->priv; + local_info_t *local = dev->priv; + #ifdef PCMCIA_DEBUG + unsigned cisrev = ((const unsigned char *)s)[2]; + #endif + unsigned mediaid= ((const unsigned char *)s)[3]; + unsigned prodid = ((const unsigned char *)s)[4]; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "cisrev=%02x mediaid=%02x prodid=%02x\n", + cisrev, mediaid, prodid ); + #endif + + local->mohawk = 0; + local->dingo = 0; + local->modem = 0; + local->card_type = XIR_UNKNOWN; + if( !(prodid & 0x40) ) { + printk(KNOT_XIRC "Ooops: Not a creditcard\n"); + return 0; + } + if( !(mediaid & 0x01) ) { + printk(KNOT_XIRC "Not an Ethernet card\n"); + return 0; + } + if( mediaid & 0x10 ) { + local->modem = 1; + switch( prodid & 15 ) { + case 1: local->card_type = XIR_CEM ; break; + case 2: local->card_type = XIR_CEM2 ; break; + case 3: local->card_type = XIR_CEM3 ; break; + case 4: local->card_type = XIR_CEM33 ; break; + case 5: local->card_type = XIR_CEM56M; + local->mohawk = 1; + break; + case 6: + case 7: /* 7 is the RealPort 10/56 */ + local->card_type = XIR_CEM56 ; + local->mohawk = 1; + local->dingo = 1; + break; + } + } + else { + switch( prodid & 15 ) { + case 1: local->card_type = has_ce2_string(link)? XIR_CE2 : XIR_CE ; + break; + case 2: local->card_type = XIR_CE2; break; + case 3: local->card_type = XIR_CE3; + local->mohawk = 1; + break; + } + } + if( local->card_type == XIR_CE || local->card_type == XIR_CEM ) { + printk(KNOT_XIRC "Sorry, this is an old CE card\n"); + return 0; + } + if( local->card_type == XIR_UNKNOWN ) + printk(KNOT_XIRC "Warning: Unknown card (mediaid=%02x prodid=%02x)\n", + mediaid, prodid ); + + return 1; +} + +/**************** + * There are some CE2 cards out which claim to be a CE card. + * This function looks for a "CE2" in the 3rd version field. + * Returns: true if this is a CE2 + */ +static int +has_ce2_string(dev_link_t * link) +{ + client_handle_t handle = link->handle; + tuple_t tuple; + cisparse_t parse; + u_char buf[256]; + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 254; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_VERS_1; + if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 2 ) { + if( strstr(parse.version_1.str + parse.version_1.ofs[2], "CE2") ) + return 1; + } + return 0; +} + +/**************** + * xirc2ps_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 void +xirc2ps_config(dev_link_t * link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + struct net_device *dev; + local_info_t *local; + ioaddr_t ioaddr; + int err, i; + u_char buf[64]; + cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + + handle = link->handle; + dev = link->priv; + local = dev->priv; + local->dingo_ccr = 0; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "config(0x%p)\n", link); + #endif + + /* + * This reads the card's CONFIG tuple to find its configuration + * registers. + */ + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + + /* Is this a valid card */ + tuple.DesiredTuple = CISTPL_MANFID; + if( (err=first_tuple(handle, &tuple, &parse))) { + printk(KNOT_XIRC "manfid not found in CIS\n"); + goto failure; + } + + switch( parse.manfid.manf ) { + case MANFID_XIRCOM: + local->manf_str = "Xircom"; + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "found xircom card\n"); + #endif + break; + case MANFID_ACCTON: + local->manf_str = "Accton"; + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "found Accton card\n"); + #endif + break; + case MANFID_COMPAQ: + case MANFID_COMPAQ2: + local->manf_str = "Compaq"; + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "found Compaq card\n"); + #endif + break; + case MANFID_INTEL: + local->manf_str = "Intel"; + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "found Intel card\n"); + #endif + break; + default: + printk(KNOT_XIRC "Unknown Card Manufacturer ID: 0x%04x\n", + (unsigned)parse.manfid.manf); + goto failure; + } + + if( !set_card_type(link, buf ) ) { + printk(KNOT_XIRC "this card is not supported\n"); + goto failure; + } + + /* get configuration stuff */ + tuple.DesiredTuple = CISTPL_CONFIG; + if( (err=first_tuple(handle, &tuple, &parse))) + goto cis_error; + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* get the ethernet address from the CIS */ + tuple.DesiredTuple = CISTPL_FUNCE; + for( err = first_tuple(handle, &tuple, &parse); !err; + err = next_tuple(handle, &tuple, &parse) ) { + /* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries: + * the first one with a length of zero the second correct - + * so I skip all entries with length 0 */ + if( parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID + && ((cistpl_lan_node_id_t *)parse.funce.data)->nb ) + break; + } + if( err ) { /* not found: try to get the node-id from tuple 0x89 */ + tuple.DesiredTuple = 0x89; /* data layout looks like tuple 0x22 */ + if( !(err = get_tuple_data(GetFirstTuple, handle, &tuple )) ) { + if( tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID ) + memcpy( &parse, buf, 8 ); + else + err = -1; + } + } + if( err ) { /* another try (James Lehmer's CE2 version 4.1)*/ + tuple.DesiredTuple = CISTPL_FUNCE; + for( err = first_tuple(handle, &tuple, &parse); !err; + err = next_tuple(handle, &tuple, &parse) ) { + if( parse.funce.type == 0x02 && parse.funce.data[0] == 1 + && parse.funce.data[1] == 6 && tuple.TupleDataLen == 13 ) { + buf[1] = 4; + memcpy( &parse, buf+1, 8 ); + break; + } + } + } + if( err ) { + printk(KNOT_XIRC "node-id not found in CIS\n"); + goto failure; + } + node_id = (cistpl_lan_node_id_t *)parse.funce.data; + if( node_id->nb != 6 ) { + printk(KNOT_XIRC "malformed node-id in CIS\n"); + goto failure; + } + for( i=0; i < 6; i++ ) + dev->dev_addr[i] = node_id->id[i]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + link->io.IOAddrLines =10; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + link->irq.Attributes = IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if( irq_list[0] == -1 ) + link->irq.IRQInfo2 = irq_mask; + else { + for( i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } + link->irq.Handler = xirc2ps_interrupt; + link->irq.Instance = dev; + if( local->modem ) { + int pass; + + if( do_sound ) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status |= CCSR_AUDIO_ENA; + } + link->irq.Attributes |= IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED ; + link->io.NumPorts2 = 8; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + if( local->dingo ) { + /* Take the Modem IO port from the CIS and scan for a free + * Ethernet port */ + link->io.NumPorts1 = 16; /* no Mako stuff anymore */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + for( err = first_tuple(handle, &tuple, &parse); !err; + err = next_tuple(handle, &tuple, &parse) ) { + if( cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8 ) { + for(ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { + link->conf.ConfigIndex = cf->index ; + link->io.BasePort2 = cf->io.win[0].base; + link->io.BasePort1 = ioaddr; + if( !(err=CardServices(RequestIO, link->handle, + &link->io)) ) + goto port_found; + } + } + } + } + else { + link->io.NumPorts1 = 18; + /* We do 2 passes here: The first one uses the regular mapping and + * the second tries again, thereby considering that the 32 ports are + * mirrored every 32 bytes. Actually we use a mirrored port for + * the Mako if (on the first pass) the COR bit 5 is set. + */ + for( pass=0; pass < 2; pass++ ) { + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + for( err = first_tuple(handle, &tuple, &parse); !err; + err = next_tuple(handle, &tuple, &parse) ){ + if( cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8 ){ + link->conf.ConfigIndex = cf->index ; + link->io.BasePort2 = cf->io.win[0].base; + link->io.BasePort1 = link->io.BasePort2 + + (pass ? ( cf->index & 0x20 ? -24:8 ) + : ( cf->index & 0x20 ? 8:-24) ); + if( !(err=CardServices(RequestIO, link->handle, + &link->io))) + goto port_found; + } + } + } + /* if special option: + * try to configure as Ethernet only. + * .... */ + } + printk(KNOT_XIRC "no ports available\n"); + } + else { + link->irq.Attributes |= IRQ_TYPE_EXCLUSIVE; + link->io.NumPorts1 = 16; + for(ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { + link->io.BasePort1 = ioaddr; + if( !(err=CardServices(RequestIO, link->handle, &link->io)) ) + goto port_found; + } + link->io.BasePort1 = 0; /* let CS decide */ + if( (err=CardServices(RequestIO, link->handle, &link->io)) ) { + cs_error(link->handle, RequestIO, err); + goto config_error; + } + } + port_found: + if( err ) + goto config_error; + + /**************** + * Now allocate an interrupt line. Note that this does not + * actually assign a handler to the interrupt. + */ + if( (err=CardServices(RequestIRQ, link->handle, &link->irq))) { + cs_error(link->handle, RequestIRQ, err); + goto config_error; + } + + /**************** + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + if( (err=CardServices(RequestConfiguration, + link->handle, &link->conf)) ) { + cs_error(link->handle, RequestConfiguration, err); + goto config_error; + } + + if( local->dingo ) { + #ifdef CEM56_FIX + conf_reg_t reg; + #endif + win_req_t req; + memreq_t mem; + + #ifdef CEM56_FIX + /* Reset the modem's BAR to the correct value + * This is necessary because in the RequestConfiguration call, + * the base address of the ethernet port (BasePort1) is written + * to the BAR registers of the modem. + */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_IOBASE_0; + reg.Value = link->io.BasePort2 & 0xff; + if( (err = CardServices(AccessConfigurationRegister, link->handle, + ® )) ) { + cs_error(link->handle, AccessConfigurationRegister, err); + goto config_error; + } + reg.Action = CS_WRITE; + reg.Offset = CISREG_IOBASE_1; + reg.Value = (link->io.BasePort2 >> 8) & 0xff; + if( (err = CardServices(AccessConfigurationRegister, link->handle, + ® )) ) { + cs_error(link->handle, AccessConfigurationRegister, err); + goto config_error; + } + #endif + + /* There is no config entry for the Ethernet part which + * is at 0x0800. So we allocate a window into the attribute + * memory and write direct to the CIS registers + */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = 0; + req.Size = 0x1000; /* 4k window */ + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + if( (err = CardServices(RequestWindow, &link->win, &req )) ) { + cs_error(link->handle, RequestWindow, err); + goto config_error; + } + local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; + mem.CardOffset = 0x0; + mem.Page = 0; + if( (err = CardServices(MapMemPage, link->win, &mem) ) ) { + cs_error(link->handle, MapMemPage, err); + goto config_error; + } + + /* Setup the CCRs; there are no infos in the CIS about the Ethernet + * part. + */ + writeb(0x47, local->dingo_ccr + CISREG_COR ); + ioaddr = link->io.BasePort1; + writeb( ioaddr & 0xff , local->dingo_ccr + CISREG_IOBASE_0 ); + writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1 ); + + #if 0 + { + u_char tmp; + printk(KERN_INFO "ECOR:" ); + for(i=0; i < 7; i++ ) { + tmp = readb(local->dingo_ccr + i*2 ); + printk(" %02x", tmp ); + } + printk("\n" ); + printk(KERN_INFO "DCOR:" ); + for(i=0; i < 4; i++ ) { + tmp = readb(local->dingo_ccr + 0x20 + i*2 ); + printk(" %02x", tmp ); + } + printk("\n" ); + printk(KERN_INFO "SCOR:" ); + for(i=0; i < 10; i++ ) { + tmp = readb(local->dingo_ccr + 0x40 + i*2 ); + printk(" %02x", tmp ); + } + printk("\n" ); + } + #endif + + writeb( 0x01 , local->dingo_ccr + 0x20 ); + writeb( 0x0c , local->dingo_ccr + 0x22 ); + writeb( 0x00 , local->dingo_ccr + 0x24 ); + writeb( 0x00 , local->dingo_ccr + 0x26 ); + writeb( 0x00 , local->dingo_ccr + 0x28 ); + } + + /* The if_port symbol can be set when the module is loaded */ + local->probe_port=0; + if( !if_port ) { + local->probe_port=1; + dev->if_port = 1; + } + else if( (if_port >= 1 && if_port <= 2) || (local->mohawk && if_port==4) ) + dev->if_port = if_port; + else + printk(KERN_NOTICE "xirc2ps_cs: invalid if_port requested\n"); + + /* we can now register the device with the net subsystem */ + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + dev->tbusy = 0; + if( (err=register_netdev(dev)) ) { + printk(KERN_NOTICE "xirc2ps_cs: register_netdev() failed\n"); + goto config_error; + } + + link->state &= ~DEV_CONFIG_PENDING; + link->dev = &local->node; + + if( local->dingo ) + do_reset(dev, 1); /* a kludge to make the cem56 work */ + + /* give some infos about the hardware */ + printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr", + dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq ); + for(i = 0; i < 6; i++) + printk("%c%02X", i?':':' ', dev->dev_addr[i]); + printk("\n"); + + return; + + config_error: + link->state &= ~DEV_CONFIG_PENDING; + xirc2ps_release((u_long)link); + return; + + cis_error: + printk(KERN_NOTICE "xirc2ps_cs: unable to parse CIS\n"); + failure: + link->state &= ~DEV_CONFIG_PENDING; +} /* xirc2ps_config */ + +/**************** + * After a card is removed, xirc2ps_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 +xirc2ps_release( u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + struct net_device *dev = link->priv; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "release(0x%p)\n", link); + #endif + + /* + * If the device is currently in use, we won't release until it + * is actually closed. + */ + if(link->open) { + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "release postponed, '%s' " + "still open\n", link->dev->dev_name); + #endif + link->state |= DEV_STALE_CONFIG; + return; + } + + if( link->win ) { + local_info_t *local = dev->priv; + if( local->dingo ) + iounmap( local->dingo_ccr - 0x0800 ); + CardServices(ReleaseWindow, link->win ); + } + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* xirc2ps_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 +xirc2ps_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + local_info_t *lp = dev? dev->priv : NULL; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "event(%d)\n", (int)event ); + #endif + + switch (event) { + case CS_EVENT_REGISTRATION_COMPLETE: + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "registration complete\n"); + #endif + break; + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if(link->state & DEV_CONFIG) { + dev->tbusy = 1; dev->start = 0; + link->release.expires = jiffies + HZ / 20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + xirc2ps_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if(link->state & DEV_CONFIG) { + if(link->open) { + dev->tbusy = 1; dev->start = 0; + lp->suspended=1; + do_powerdown(dev); + } + 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); + if( link->open) { + do_reset(dev,1); + lp->suspended=0; + dev->tbusy = 0; dev->start = 1; + } + } + break; + } + return 0; +} /* xirc2ps_event */ + +/*====================================================================*/ + +/**************** + * This is the Interrupt service route. + */ +static void +xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + local_info_t *lp; + ioaddr_t ioaddr; + u_char saved_page; + unsigned bytes_rcvd; + unsigned int_status, eth_status, rx_status, tx_status; + unsigned rsr, pktlen; + ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days + * is this something to worry about? + * -- on a laptop? + */ + + if( !dev->start ) + return; + + if( dev->interrupt ) { + printk(KERR_XIRC "re-entering isr on irq %d (dev=%p)\n", irq, dev); + return; + } + dev->interrupt = 1; + lp = dev->priv; + ioaddr = dev->base_addr; + if( lp->mohawk ) { /* must disable the interrupt */ + PutByte(XIRCREG_CR, 0 ); + } + + #ifdef PCMCIA_DEBUG + if(pc_debug > 6 ) + printk(KERN_DEBUG "%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr); + #endif + + saved_page = GetByte(XIRCREG_PR); + /* Read the ISR to see whats the cause for the interrupt. + * This also clears the interrupt flags on CE2 cards + */ + int_status = GetByte(XIRCREG_ISR); + bytes_rcvd = 0; + loop_entry: + if( int_status == 0xff ) { /* card may be ejected */ + #ifdef PCMCIA_DEBUG + if( pc_debug > 3 ) + printk(KERN_DEBUG "%s: interrupt %d for dead card\n", dev->name, irq ); + #endif + goto leave; + } + eth_status = GetByte(XIRCREG_ESR); + + SelectPage(0x40); + rx_status = GetByte(XIRCREG40_RXST0); + PutByte(XIRCREG40_RXST0, (~rx_status & 0xff) ); + tx_status = GetByte(XIRCREG40_TXST0); + tx_status |= GetByte(XIRCREG40_TXST1) << 8; + PutByte(XIRCREG40_TXST0, 0 ); + PutByte(XIRCREG40_TXST1, 0 ); + + #ifdef PCMCIA_DEBUG + if( pc_debug > 3 ) + printk(KERN_DEBUG "%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n", + dev->name, int_status, eth_status, rx_status, tx_status ); + #endif + + /***** receive section ******/ + SelectPage(0); + while( eth_status & FullPktRcvd ) { + rsr = GetByte(XIRCREG0_RSR); + if( bytes_rcvd > maxrx_bytes && (rsr & PktRxOk) ) { + /* too many bytes received during this int, drop the rest of the + * packets */ + lp->stats.rx_dropped++; + #ifdef PCMCIA_DEBUG + if( pc_debug > 3 ) + printk(KNOT_XIRC "%s: RX drop, too much done\n", dev->name); + #endif + PutWord(XIRCREG0_DO, 0x8000 ); /* issue cmd: skip_rx_packet */ + } + else if( rsr & PktRxOk ) { + struct sk_buff *skb; + + pktlen = GetWord(XIRCREG0_RBC); + bytes_rcvd += pktlen; + + #ifdef PCMCIA_DEBUG + if( pc_debug > 5 ) + printk(KDBG_XIRC "rsr=%#02x packet_length=%u\n", rsr, pktlen ); + #endif + + skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */ + if( !skb ) { + #ifdef PCMCIA_DEBUG + if( pc_debug ) + printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n", + pktlen ); + #endif + lp->stats.rx_dropped++; + } + else { /* okay get the packet */ + skb_reserve(skb, 2); + if( lp->silicon == 0 ) { /* work around a hardware bug */ + unsigned rhsa; /* receive start address */ + + SelectPage(5); + rhsa = GetWord(XIRCREG5_RHSA0); + SelectPage(0); + rhsa += 3; /* skip control infos */ + if( rhsa >= 0x8000 ) + rhsa = 0; + if( rhsa + pktlen > 0x8000 ) { + unsigned i; + u_char *buf = skb_put(skb, pktlen); + for(i=0; i < pktlen ; i++, rhsa++ ) { + buf[i] = GetByte(XIRCREG_EDP); + if( rhsa == 0x8000 ) { + rhsa = 0; + i--; + } + } + } else { + insw(ioaddr+XIRCREG_EDP, + skb_put(skb, pktlen), (pktlen+1)>>1 ); + } + } + #if 0 + else if( lp->mohawk ) { + /* To use this 32 bit access we should use + * a manual optimized loop + * Also the words are swapped, we can get more + * performance by using 32 bit access and swapping + * the words in a register. Will need this for cardbus + * + * Note: don't forget to change the ALLOC_SKB to .. +3 + */ + unsigned i; + u_long *p = skb_put(skb, pktlen); + register u_long a; + ioaddr_t edpreg = ioaddr+XIRCREG_EDP-2; + for(i=0; i < len ; i += 4, p++ ) { + a = inl(edpreg); + __asm__("rorl $16,%0\n\t" + :"=q" (a) + : "0" (a)); + *p = a; + } + } + #endif + else { + insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen), + (pktlen+1)>>1 ); + } + skb->protocol = eth_type_trans(skb, dev); + skb->dev = dev; + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes += pktlen; + if( !(rsr & PhyPkt) ) + lp->stats.multicast++; + } + PutWord(XIRCREG0_DO, 0x8000 ); /* issue cmd: skip_rx_packet */ + } + else { + #ifdef PCMCIA_DEBUG + if( pc_debug > 5 ) + printk("rsr=%#02x\n", rsr ); + #endif + } + if( rsr & PktTooLong ) { + lp->stats.rx_frame_errors++; + #ifdef PCMCIA_DEBUG + if( pc_debug > 3 ) + printk(KNOT_XIRC "%s: Packet too long\n", dev->name); + #endif + } + if( rsr & CRCErr ) { + lp->stats.rx_crc_errors++; + #ifdef PCMCIA_DEBUG + if( pc_debug > 3 ) + printk(KNOT_XIRC "%s: CRC error\n", dev->name); + #endif + } + if( rsr & AlignErr ) { + lp->stats.rx_fifo_errors++; /* okay ? */ + #ifdef PCMCIA_DEBUG + if( pc_debug > 3 ) + printk(KNOT_XIRC "%s: Alignment error\n", dev->name); + #endif + } + + /* get the new ethernet status */ + eth_status = GetByte(XIRCREG_ESR); + } + if( rx_status & 0x10 ) { /* Receive overrun */ + lp->stats.rx_over_errors++; + PutByte(XIRCREG_CR, ClearRxOvrun); + #ifdef PCMCIA_DEBUG + if( pc_debug > 3 ) + printk(KDBG_XIRC "receive overrun cleared\n" ); + #endif + } + + /***** transmit section ******/ + if( int_status & PktTxed ) { + unsigned n, nn; + + n = lp->last_ptr_value; + nn = GetByte(XIRCREG0_PTR); + lp->last_ptr_value = nn; + if( nn < n ) /* rollover */ + lp->stats.tx_packets += 256 - n; + else if( n == nn ) { /* happens sometimes - don't know why */ + #ifdef PCMCIA_DEBUG + if( pc_debug ) + printk(KDBG_XIRC "PTR not changed?\n" ); + #endif + } + else + lp->stats.tx_packets += lp->last_ptr_value - n; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + if( tx_status & 0x0002 ) { /* Execessive collissions */ + #ifdef PCMCIA_DEBUG + if( pc_debug ) + printk(KDBG_XIRC "tx restarted due to execssive collissions\n" ); + #endif + PutByte(XIRCREG_CR, RestartTx ); /* restart transmitter process */ + } + if( tx_status & 0x0040 ) + lp->stats.tx_aborted_errors++; + + /* recalculate our work chunk so that we limit the duration of this + * ISR to about 1/10 of a second. + * Calculate only if we received a reasonable amount of bytes. + */ + if( bytes_rcvd > 1000 ) { + u_long duration = jiffies - start_ticks; + + if( duration >= HZ/10 ) { /* if more than about 1/10 second */ + maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration; + if( maxrx_bytes < 2000 ) + maxrx_bytes = 2000; + else if( maxrx_bytes > 22000 ) + maxrx_bytes = 22000; + #ifdef PCMCIA_DEBUG + if( pc_debug > 1) + printk(KDBG_XIRC "set maxrx=%u (rcvd=%u ticks=%lu)\n", + maxrx_bytes, bytes_rcvd, duration ); + #endif + } + else if( !duration && maxrx_bytes < 22000 ) { /* now much faster*/ + maxrx_bytes += 2000; + if( maxrx_bytes > 22000 ) + maxrx_bytes = 22000; + #ifdef PCMCIA_DEBUG + if( pc_debug > 1 ) + printk(KDBG_XIRC "set maxrx=%u\n", maxrx_bytes ); + #endif + } + } + + leave: + if( lockup_hack ) { + if( int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0 ) + goto loop_entry; + } + SelectPage(saved_page); + dev->interrupt = 0; + PutByte(XIRCREG_CR, EnableIntr ); /* re-enable interrupts */ + /* Instead of dropping packets during a receive, we could + * force an interrupt with this command: + * PutByte(XIRCREG_CR, EnableIntr|ForceIntr ); + */ +} /* xirc2ps_interrupt */ + +/*====================================================================*/ + +static int +do_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + local_info_t *lp = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int okay; + unsigned freespace; + unsigned pktlen = skb? skb->len : 0; + + #ifdef PCMCIA_DEBUG + if(pc_debug>1 ) + printk(KDBG_XIRC "do_start_xmit(skb=%p, dev=%p) len=%u\n", + skb, dev, pktlen ); + #endif + + /* Transmitter timeout, serious problems */ + if( dev->tbusy ) { + int tickssofar = jiffies - dev->trans_start; + + if( lp->suspended ) { + dev_kfree_skb (skb); + dev->trans_start = jiffies; + lp->stats.tx_dropped++; + return 0; + } + if( tickssofar < TX_TIMEOUT ) + return 1; + + printk(KERN_NOTICE "%s: transmit timed out\n", dev->name ); + lp->stats.tx_errors++; + /* reset the card */ + do_reset(dev,1); + dev->trans_start = jiffies; + dev->tbusy = 0; + } + + if( test_and_set_bit(0, (void*)&dev->tbusy ) ) { + printk(KWRN_XIRC "transmitter access conflict\n"); + dev_kfree_skb (skb); + return 0; + } + + /* adjust the packet length to min. required + * and hope that the buffer is large enough + * to provide some random data. + * fixme: For Mohawk we can change this by sending + * a larger packetlen than we actually have; the chip will + * pad this in his buffer with random bytes + */ + if( pktlen < ETH_ZLEN ) + pktlen = ETH_ZLEN; + + SelectPage(0); + PutWord(XIRCREG0_TRS, (u_short)pktlen+2 ); + freespace = GetWord(XIRCREG0_TSO); + okay = freespace & 0x8000; + freespace &= 0x7fff; + /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */ + okay = pktlen +2 < freespace; + #ifdef PCMCIA_DEBUG + if(pc_debug > 2 + ( okay ? 2 : 0) ) + printk(KERN_DEBUG "%s: avail. tx space=%u%s\n", dev->name, freespace, + okay? " (okay)":" (not enough)" ); + #endif + if( !okay ) { /* not enough space */ + dev->tbusy = 1; + return 1; /* upper layer may decide to requeue this packet */ + } + /* send the packet */ + PutWord(XIRCREG_EDP, (u_short)pktlen ); + outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1 ); + if( pktlen & 1 ) + PutByte(XIRCREG_EDP, skb->data[pktlen-1] ); + + if( lp->mohawk ) + PutByte(XIRCREG_CR, TransmitPacket|EnableIntr ); + + dev_kfree_skb (skb); + dev->trans_start = jiffies; + dev->tbusy = 0; + lp->stats.tx_bytes += pktlen; + return 0; +} + +static struct enet_statistics * +do_get_stats(struct net_device *dev) +{ + local_info_t *lp = dev->priv; + + /* lp->stats.rx_missed_errors = GetByte(?) */ + return &lp->stats; +} + +/**************** + * Set all addresses: This first one is the individual address, + * the next 9 addresses are taken from the multicast list and + * the rest is filled with the individual address. + */ +static void +set_addresses(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + local_info_t *lp = dev->priv; + struct dev_mc_list *dmi = dev->mc_list; + char *addr; + int i,j,k,n; + + SelectPage(k=0x50); + for(i=0,j=8,n=0; ; i++, j++) { + if( i > 5 ) { + if( ++n > 9 ) + break; + i = 0; + } + if( j > 15 ) { + j = 8; + k++; + SelectPage(k); + } + + if( n && n <= dev->mc_count && dmi ) { + addr = dmi->dmi_addr; + dmi = dmi->next; + } + else + addr = dev->dev_addr; + + if( lp->mohawk ) + PutByte( j, addr[5-i] ); + else + PutByte( j, addr[i] ); + } + SelectPage(0); +} + +/**************** + * Set or clear the multicast filter for this adaptor. + * We can filter up to 9 addresses, if more are requested we set + * multicast promiscuous mode. + */ + +static void +set_multicast_list(struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + + SelectPage(0x42); + if( dev->flags & IFF_PROMISC ) { /* snoop */ + PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */ + } + else if( dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI) ) { + PutByte(XIRCREG42_SWC1, 0x06); /* set MPE */ + } + else if( dev->mc_count ) { /* the chip can filter 9 addresses perfectly */ + PutByte(XIRCREG42_SWC1, 0x00); + SelectPage(0x40); + PutByte(XIRCREG40_CMD0, Offline ); + set_addresses(dev); + SelectPage(0x40); + PutByte(XIRCREG40_CMD0, EnableRecv | Online ); + } + else { /* standard usage */ + PutByte(XIRCREG42_SWC1, 0x00); + } + SelectPage(0); +} + +/**************** + * We never need to do anything when a IIps device is "initialized" + * by the net software, because we only register already-found cards. + */ +static int +do_init(struct net_device *dev) +{ + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "do_init(%p)\n", dev ); + #endif + return 0; +} + +static int +do_config(struct net_device *dev, struct ifmap *map) +{ + local_info_t *local = dev->priv; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "do_config(%p)\n", dev ); + #endif + + if( map->port != 255 && map->port != dev->if_port ) { + if( map->port <= 4 ) { + if( !map->port ) { + local->probe_port = 1; + dev->if_port = 1; + } + else { + local->probe_port = 0; + dev->if_port = map->port; + } + printk(KERN_INFO "%s: switching to %s port\n", + dev->name, if_names[dev->if_port]); + do_reset(dev,1); /* not the fine way :-) */ + } + else + return -EINVAL; + } + #ifdef PCMCIA_DEBUG + else if( map->port == dev->if_port && local->mohawk ) { + /* kludge to print the mii regsiters */ + mii_dump(dev); + } + #endif + return 0; +} + +/**************** + * Open the driver + */ +static int +do_open(struct net_device *dev) +{ + local_info_t *lp = dev->priv; + dev_link_t *link; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "do_open(%p)\n", dev ); + #endif + + /* Check that the PCMCIA card is still here. */ + for( link = dev_list; link; link = link->next ) + if( link->priv == dev ) + break; + /* Physical device present signature. */ + if( !DEV_OK(link) ) + return -ENODEV; + + /* okay */ + link->open++; + MOD_INC_USE_COUNT; + + dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + lp->suspended = 0; + do_reset(dev,1); + + return 0; +} + +static int +do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + local_info_t *local = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + + #ifdef PCMCIA_DEBUG + if(pc_debug > 1) + printk(KERN_DEBUG "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", + dev->name, rq->ifr_ifrn.ifrn_name, cmd, + data[0], data[1], data[2], data[3] ); + #endif + + if( !local->mohawk ) + return -EOPNOTSUPP; + + switch( cmd ) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = 0; /* we have only this address */ + /* fall trough */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mii_rd( ioaddr, data[0] & 0x1f, data[1] & 0x1f); + break; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if( !suser() ) + return -EPERM; + mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static void +hardreset(struct net_device *dev) +{ + local_info_t *local = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + + SelectPage(4); + udelay(1); + PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ + busy_loop(HZ/25); /* wait 40 msec */ + if( local->mohawk ) + PutByte(XIRCREG4_GPR1, 1); /* set bit 0: power up */ + else + PutByte(XIRCREG4_GPR1, 1 | 4); /* set bit 0: power up, bit 2: AIC */ + busy_loop(HZ/50); /* wait 20 msec */ +} + +static void +do_reset(struct net_device *dev, int full) +{ + local_info_t *local = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + unsigned value; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KERN_DEBUG "%s: do_reset(%p,%d)\n", + dev? dev->name:"eth?", dev, full ); + #endif + + hardreset(dev); + PutByte(XIRCREG_CR, SoftReset ); /* set */ + busy_loop(HZ/50); /* wait 20 msec */ + PutByte(XIRCREG_CR, 0 ); /* clear */ + busy_loop(HZ/25); /* wait 40 msec */ + if( local->mohawk ) { + SelectPage(4); + /* set pin GP1 and GP2 to output (0x0c) + * set GP1 to low to power up the ML6692 (0x00) + * set GP2 to high to power up the 10Mhz chip (0x02) + */ + PutByte(XIRCREG4_GPR0, 0x0e); + } + + /* give the circuits some time to power up */ + busy_loop(HZ/2); /* about 500ms */ + + local->last_ptr_value = 0; + local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4 + : (GetByte(XIRCREG4_BOV) & 0x30) >> 4; + + if( local->probe_port ) { + if( !local->mohawk ) { + SelectPage(4); + PutByte(XIRCREG4_GPR0, 4); + local->probe_port = 0; + } + } + else if( dev->if_port == 2 ) { /* enable 10Base2 */ + SelectPage(0x42); + PutByte(XIRCREG42_SWC1, 0xC0); + } + else { /* enable 10BaseT */ + SelectPage(0x42); + PutByte(XIRCREG42_SWC1, 0x80); + } + busy_loop(HZ/25); /* wait 40 msec to let it complete */ + + #ifdef PCMCIA_DEBUG + if(pc_debug) { + SelectPage(0); + value = GetByte(XIRCREG_ESR); /* read the ESR */ + printk(KERN_DEBUG "%s: ESR is: %#02x\n", dev->name, value); + } + #endif + + /* setup the ECR */ + SelectPage(1); + PutByte(XIRCREG1_IMR0, 0xff ); /* allow all ints */ + PutByte(XIRCREG1_IMR1, 1 ); /* and Set TxUnderrunDetect */ + value = GetByte(XIRCREG1_ECR); + #if 0 + if( local->mohawk ) + value |= DisableLinkPulse; + PutByte(XIRCREG1_ECR, value); + #endif + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KERN_DEBUG "%s: ECR is: %#02x\n", dev->name, value); + #endif + + SelectPage(0x42); + PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */ + + if( local->silicon != 1 ) { + /* set the local memory dividing line. + * The comments in the sample code say that this is only + * settable with the scipper version 2 which is revision 0. + * Always for CE3 cards + */ + SelectPage(2); + PutWord(XIRCREG2_RBS, 0x2000 ); + } + + if( full ) + set_addresses(dev); + + /* Hardware workaround: + * The receive byte pointer after reset is off by 1 so we need + * to move the offset pointer back to 0. + */ + SelectPage(0); + PutWord(XIRCREG0_DO, 0x2000 ); /* change offset command, off=0 */ + + /* setup MAC IMRs and clear status registers */ + SelectPage(0x40); /* Bit 7 ... bit 0 */ + PutByte(XIRCREG40_RMASK0, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, MP */ + PutByte(XIRCREG40_TMASK0, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */ + PutByte(XIRCREG40_TMASK1, 0xb0); /* rsv, rsv, PTD, EXT, rsv,rsv,rsv, rsv*/ + PutByte(XIRCREG40_RXST0, 0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, MP */ + PutByte(XIRCREG40_TXST0, 0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */ + PutByte(XIRCREG40_TXST1, 0x00); /* TEN, rsv, PTD, EXT, retry_counter:4 */ + + if( full && local->mohawk && init_mii(dev) ) { + if( dev->if_port == 4 || local->dingo ) { /* and use it */ + SelectPage(2); + value = GetByte(XIRCREG2_MSR); + value |= 0x08; /* Select MII */ + PutByte(XIRCREG2_MSR, value); + busy_loop(HZ/50); /* wait 20 msec */ + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KERN_DEBUG "%s: MII selected\n", dev->name); + #endif + } + else { + SelectPage(2); + PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08); + busy_loop(HZ/50); + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KERN_DEBUG "%s: MII detected; using 10mbs\n", + dev->name); + #endif + SelectPage(0x42); + if( dev->if_port == 2 ) /* enable 10Base2 */ + PutByte(XIRCREG42_SWC1, 0xC0); + else /* enable 10BaseT */ + PutByte(XIRCREG42_SWC1, 0x80); + busy_loop(HZ/25); /* wait 40 msec to let it complete */ + } + } + else { /* No MII */ + SelectPage(0); + value = GetByte(XIRCREG_ESR); /* read the ESR */ + dev->if_port = (value & MediaSelect) ? 1 : 2; + } + + /* configure the LEDs */ + SelectPage(2); + if( dev->if_port == 1 || dev->if_port == 4 ) /* TP: Link and Activity */ + PutByte(XIRCREG2_LED, 0x3b ); + else /* Coax: Not-Collision and Activity */ + PutByte(XIRCREG2_LED, 0x3a ); + + if (local->dingo) + PutByte( 0x0b, 0x04 ); /* 100 Mbit LED */ + + /* enable receiver and put the mac online */ + if( full ) { + SelectPage(0x40); + PutByte(XIRCREG40_CMD0, EnableRecv | Online ); + } + + /* setup Ethernet IMR and enable interrupts */ + SelectPage(1); + PutByte(XIRCREG1_IMR0, 0xff ); + udelay(1); + SelectPage(0); + PutByte(XIRCREG_CR, EnableIntr ); + if( local->modem && !local->dingo ) { /* do some magic */ + if( !(GetByte( 0x10 ) & 0x01 ) ) + PutByte( 0x10, 0x11 ); /* unmask master-int bit */ + } + + if( full ) + printk(KERN_INFO "%s: media %s, silicon revision %d\n", dev->name, + if_names[dev->if_port], local->silicon); + /* We should switch back to page 0 to avoid a bug in revision 0 + * where regs with offset below 8 can't be read after an access + * to the MAC registers */ + SelectPage(0); +} + +/**************** + * Initialize the Media-Independent-Interface + * Returns: True if we have a good MII + */ +static int +init_mii(struct net_device *dev) +{ + local_info_t *local = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + unsigned control, status, linkpartner; + int i; + + #ifdef PCMCIA_DEBUG + if(pc_debug>1) { + mii_dump(dev); + } + #endif + + status = mii_rd(ioaddr, 0, 1 ); + if( (status & 0xff00) != 0x7800 ) + return 0; /* No MII */ + + if( local->probe_port ) + control = 0x1000; /* auto neg */ + else if( dev->if_port == 4 ) + control = 0x2000; /* no auto neg, 100mbs mode */ + else + control = 0x0000; /* no auto neg, 10mbs mode */ + mii_wr(ioaddr, 0, 0, control, 16 ); + udelay(100); + control = mii_rd(ioaddr, 0, 0 ); + + if( control & 0x0400 ) { + printk(KERN_NOTICE "%s can't take PHY out of isolation mode\n", + dev->name); + local->probe_port = 0; + return 0; + } + + if( local->probe_port ) { + /* according to the DP83840A specs the auto negotation process + * may take up to 3.5 sec, so we use this also for our ML6692 + * Fixme: Better to use a timer here! + */ + for(i=0; i < 35; i++ ) { + busy_loop(HZ/10); /* wait 100 msec */ + status = mii_rd(ioaddr, 0, 1 ); + if( (status & 0x0020) && (status & 0x0004) ) + break; + } + + if( !(status & 0x0020) ) { + printk(KERN_NOTICE "%s: auto negotation failed;" + " using 10mbs\n", dev->name ); + control = 0x0000; + mii_wr(ioaddr, 0, 0, control, 16 ); + udelay(100); + SelectPage(0); + dev->if_port = (GetByte(XIRCREG_ESR) & MediaSelect) ? 1 : 2; + } + else { + linkpartner = mii_rd(ioaddr, 0, 5 ); + printk(KERN_INFO "%s: MII link partner: %04x\n", dev->name, + linkpartner ); + if( linkpartner & 0x0080 ) { /* 100BaseTx capability */ + dev->if_port = 4; + } + else + dev->if_port = 1; + } + local->probe_port = 0; + } + + #ifdef PCMCIA_DEBUG + if( pc_debug ) + mii_dump(dev); + #endif + + return 1; +} + +static void +do_powerdown(struct net_device *dev) +{ + + ioaddr_t ioaddr = dev->base_addr; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "do_powerdown(%p)\n", dev ); + #endif + + SelectPage(4); + PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ + SelectPage(0); +} + +static int +do_stop( struct net_device *dev) +{ + ioaddr_t ioaddr = dev->base_addr; + dev_link_t *link; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "do_stop(%p)\n", dev ); + #endif + + for(link = dev_list; link; link = link->next) + if(link->priv == dev) + break; + if( !link ) + return -ENODEV; + + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "shutting down\n"); + #endif + dev->tbusy = 1; + dev->start = 0; + + SelectPage(0); + PutByte(XIRCREG_CR, 0 ); /* disable interrupts */ + SelectPage(0x01); + PutByte(XIRCREG1_IMR0, 0x00 ); /* forbid all ints */ + SelectPage(4); + PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ + SelectPage(0); + + link->open--; dev->start = 0; + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int __init +init_xirc2ps_cs(void) +{ + servinfo_t serv; + + printk(KERN_INFO "%s\n", version); + if( card_type ) + printk(KINF_XIRC "option card_type is obsolete\n"); + if( lockup_hack ) + printk(KINF_XIRC "lockup hack is enabled\n"); + CardServices(GetCardServicesInfo, &serv); + if( serv.Revision != CS_RELEASE_CODE ) { + printk(KNOT_XIRC "Card Services release does not match!\n"); + return -1; + } + #ifdef PCMCIA_DEBUG + if( pc_debug ) + printk(KDBG_XIRC "pc_debug=%d\n", pc_debug); + #endif + register_pccard_driver(&dev_info, &xirc2ps_attach, &xirc2ps_detach); + return 0; +} + +static void __exit +exit_xirc2ps_cs(void) +{ + #ifdef PCMCIA_DEBUG + if(pc_debug) + printk(KDBG_XIRC "unloading\n"); + #endif + unregister_pccard_driver(&dev_info); + while( dev_list ) { + if( dev_list->state & DEV_CONFIG ) + xirc2ps_release( (u_long)dev_list ); + if( dev_list ) /* xirc2ps_release() might already have detached... */ + xirc2ps_detach( dev_list ); + } +} + +module_init(init_xirc2ps_cs); +module_exit(exit_xirc2ps_cs); + diff -u --recursive --new-file v2.3.22/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.3.22/linux/drivers/net/slhc.c Thu Aug 5 14:35:52 1999 +++ linux/drivers/net/slhc.c Mon Oct 18 11:26:31 1999 @@ -758,12 +758,6 @@ #endif /* MODULE */ #else /* CONFIG_INET */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); int slhc_toss(struct slcompress *comp) @@ -804,5 +798,11 @@ printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); return NULL; } +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); #endif /* CONFIG_INET */ diff -u --recursive --new-file v2.3.22/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.3.22/linux/drivers/net/starfire.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/net/starfire.c Tue Oct 19 10:32:24 1999 @@ -81,6 +81,7 @@ #endif #include +#include #include #include #include diff -u --recursive --new-file v2.3.22/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.22/linux/drivers/net/via-rhine.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/via-rhine.c Tue Oct 19 10:32:24 1999 @@ -111,11 +111,6 @@ #ifdef MODULE char kernel_version[] = UTS_RELEASE; -#else -#ifndef __alpha__ -#define ioremap vremap -#define iounmap vfree -#endif #endif #if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Donald Becker "); diff -u --recursive --new-file v2.3.22/linux/drivers/pci/helper.c linux/drivers/pci/helper.c --- v2.3.22/linux/drivers/pci/helper.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/pci/helper.c Tue Oct 19 13:48:24 1999 @@ -57,7 +57,7 @@ if (match_limit && match_limit == matches) return matches; - ent++; + break; /* stop list search on first match */ } dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, dev); diff -u --recursive --new-file v2.3.22/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.22/linux/drivers/pci/pci.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/pci/pci.c Fri Oct 15 18:55:26 1999 @@ -140,6 +140,64 @@ return best; } +/* + * 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. + */ +int +pci_set_power_state(struct pci_dev *dev, int new_state) +{ + u32 base[5], romaddr; + u16 pci_command, pwr_command; + u8 pci_latency, pci_cacheline; + int i, old_state; + int pm = pci_find_capability(dev, PCI_CAP_ID_PM); + + if (!pm) + return 0; + pci_read_config_word(dev, pm + PCI_PM_CTRL, &pwr_command); + old_state = pwr_command & PCI_PM_CTRL_STATE_MASK; + if (old_state == new_state) + return old_state; + DBG("PCI: %s goes from D%d to D%d\n", dev->slot_name, old_state, new_state); + if (old_state == 3) { + pci_read_config_word(dev, PCI_COMMAND, &pci_command); + pci_write_config_word(dev, PCI_COMMAND, pci_command & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + for (i = 0; i < 5; i++) + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, &base[i]); + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &romaddr); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &pci_cacheline); + pci_write_config_word(dev, pm + PCI_PM_CTRL, new_state); + for (i = 0; i < 5; i++) + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, base[i]); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, romaddr); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cacheline); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, pci_latency); + pci_write_config_word(dev, PCI_COMMAND, pci_command); + } else + pci_write_config_word(dev, pm + PCI_PM_CTRL, (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | new_state); + return old_state; +} + +/* + * 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. + */ +int +pci_enable_device(struct pci_dev *dev) +{ + int err; + + if ((err = pcibios_enable_device(dev)) < 0) + return err; + pci_set_power_state(dev, 0); + return 0; +} + /* * This interrupt-safe spinlock protects all accesses to PCI diff -u --recursive --new-file v2.3.22/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.3.22/linux/drivers/pci/quirks.c Fri Oct 15 15:25:14 1999 +++ linux/drivers/pci/quirks.c Mon Oct 18 11:34:30 1999 @@ -128,6 +128,7 @@ */ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton }, diff -u --recursive --new-file v2.3.22/linux/drivers/pci/setup.c linux/drivers/pci/setup.c --- v2.3.22/linux/drivers/pci/setup.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/pci/setup.c Fri Oct 15 18:55:26 1999 @@ -323,3 +323,9 @@ for (dev = pci_devices; dev; dev = dev->next) pdev_fixup_irq(dev, swizzle, map_irq); } + +int +pcibios_enable_device(struct pci_dev *dev) +{ + return 0; +} diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/Config.in linux/drivers/pcmcia/Config.in --- v2.3.22/linux/drivers/pcmcia/Config.in Mon Oct 4 15:49:29 1999 +++ linux/drivers/pcmcia/Config.in Wed Oct 20 21:33:12 1999 @@ -2,13 +2,15 @@ # PCMCIA bus subsystem configuration # mainmenu_option next_comment -comment 'PCMCIA/Cardbus support' +comment 'PCMCIA/CardBus support' -tristate 'PCMCIA/Cardbus support' CONFIG_PCMCIA +tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA if [ "$CONFIG_PCMCIA" != "n" ]; then if [ "$CONFIG_PCI" != "n" ]; then bool ' CardBus support' CONFIG_CARDBUS fi + bool ' i82365/Yenta compatible bridge support' CONFIG_I82365 + bool ' Databook TCIC host bridge support' CONFIG_TCIC fi endmenu diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile --- v2.3.22/linux/drivers/pcmcia/Makefile Mon Oct 4 15:49:29 1999 +++ linux/drivers/pcmcia/Makefile Wed Oct 20 21:33:12 1999 @@ -15,20 +15,34 @@ MOD_LIST_NAME := PCMCIA_MODULES ifeq ($(CONFIG_PCMCIA),y) - O_OBJS := i82365.o tcic.o cistpl.o rsrc_mgr.o bulkmem.o + O_OBJS := cistpl.o rsrc_mgr.o bulkmem.o OX_OBJS := ds.o cs.o O_TARGET := pcmcia.o + ifeq ($(CONFIG_I82365),y) + O_OBJS += i82365.o + endif + ifeq ($(CONFIG_TCIC),y) + O_OBJS += tcic.o + endif ifeq ($(CONFIG_CARDBUS),y) O_OBJS += cardbus.o + OX_OBJS += cb_enabler.o endif else ifeq ($(CONFIG_PCMCIA),m) - M_OBJS := i82365.o tcic.o pcmcia_core.o + M_OBJS := pcmcia_core.o MX_OBJS := ds.o MIX_OBJS := cs.o CORE_OBJS := cistpl.o rsrc_mgr.o bulkmem.o cs.o + ifeq ($(CONFIG_I82365),y) + M_OBJS += i82365.o + endif + ifeq ($(CONFIG_TCIC),y) + M_OBJS += tcic.o + endif ifeq ($(CONFIG_CARDBUS),y) CORE_OBJS += cardbus.o + MX_OBJS += cb_enabler.o endif endif endif diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c --- v2.3.22/linux/drivers/pcmcia/cardbus.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/pcmcia/cardbus.c Wed Oct 20 21:33:12 1999 @@ -2,7 +2,7 @@ Cardbus device configuration - cardbus.c 1.59 1999/09/15 15:32:19 + cardbus.c 1.61 1999/10/20 22:36:57 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -325,9 +325,9 @@ pci_readl(bus, i, PCI_CLASS_REVISION, &c[i].dev.class); c[i].dev.class >>= 8; c[i].dev.hdr_type = hdr; -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS pci_proc_attach_device(&c[i].dev); -#endif +#endif } return CS_SUCCESS; @@ -344,9 +344,9 @@ if (*p == &c[0].dev) break; for (q = *p; q; q = q->next) { if (q->bus != (*p)->bus) break; -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS pci_proc_detach_device(q); -#endif +#endif } if (*p) *p = q; s->cap.cb_bus->devices = NULL; @@ -496,7 +496,8 @@ s->irq.AssignedIRQ = irq; } } - c[0].dev.irq = irq; + for (i = 0; i < fn; i++) + c[i].dev.irq = irq; return CS_SUCCESS; diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/cb_enabler.c linux/drivers/pcmcia/cb_enabler.c --- v2.3.22/linux/drivers/pcmcia/cb_enabler.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/pcmcia/cb_enabler.c Wed Oct 20 21:33:12 1999 @@ -2,7 +2,7 @@ Cardbus device enabler - cb_enabler.c 1.23 1999/09/15 15:32:19 + cb_enabler.c 1.24 1999/10/20 00:19:09 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -58,7 +58,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"cb_enabler.c 1.23 1999/09/15 15:32:19 (David Hinds)"; +"cb_enabler.c 1.24 1999/10/20 00:19:09 (David Hinds)"; #else #define DEBUG(n, args...) do { } while (0) #endif @@ -371,6 +371,9 @@ } /*====================================================================*/ + +EXPORT_SYMBOL(register_driver); +EXPORT_SYMBOL(unregister_driver); static int __init init_cb_enabler(void) { diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.3.22/linux/drivers/pcmcia/cs.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/pcmcia/cs.c Wed Oct 20 21:33:12 1999 @@ -2,7 +2,7 @@ PCMCIA Card Services -- core services - cs.c 1.228 1999/09/15 15:32:19 + cs.c 1.232 1999/10/20 22:17:24 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -70,7 +70,7 @@ int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"cs.c 1.228 1999/09/15 15:32:19 (David Hinds)"; +"cs.c 1.232 1999/10/20 22:17:24 (David Hinds)"; #endif static const char *release = "Linux PCMCIA Card Services " CS_RELEASE; @@ -353,41 +353,40 @@ socket_info_t *s = NULL; client_t *client; +#ifdef CONFIG_PROC_FS + for (i = 0; i < sockets; i++) { + s = socket_table[i]; + if (s->ss_entry != ss_entry) continue; + if (proc_pccard) { + char name[3]; + sprintf(name, "%02d", i); +#ifdef PCMCIA_DEBUG + remove_proc_entry("clients", s->proc); +#endif + } + } +#endif + for (;;) { for (i = 0; i < sockets; i++) { s = socket_table[i]; if (s->ss_entry == ss_entry) break; } - if (i == sockets) { + if (i == sockets) break; - } else { -#ifdef CONFIG_PROC_FS - if (proc_pccard) { - char name[3]; - sprintf(name, "%02d", i); -#ifdef PCMCIA_DEBUG - remove_proc_entry("clients", s->proc); -#endif - remove_proc_entry(name, proc_pccard); - } -#endif - while (s->clients) { - client = s->clients; - s->clients = s->clients->next; - kfree(client); - } - init_socket(s); - release_cis_mem(s); -#ifdef CONFIG_CARDBUS - cb_release_cis_mem(s); -#endif - s->ss_entry = NULL; - kfree(s); - socket_table[i] = NULL; - for (j = i; j < sockets-1; j++) - socket_table[j] = socket_table[j+1]; - sockets--; - } + shutdown_socket(i); + release_cis_mem(s); + while (s->clients) { + client = s->clients; + s->clients = s->clients->next; + kfree(client); + } + s->ss_entry = NULL; + kfree(s); + socket_table[i] = NULL; + for (j = i; j < sockets-1; j++) + socket_table[j] = socket_table[j+1]; + sockets--; } } /* unregister_ss_entry */ @@ -1808,7 +1807,7 @@ { socket_info_t *s; window_t *win; - int w; + int w, align; if (CHECK_HANDLE(*handle)) return CS_BAD_HANDLE; @@ -1835,9 +1834,10 @@ win->sock = s; win->base = req->Base; win->size = req->Size; + align = ((s->cap.features & SS_CAP_MEM_ALIGN) || + (req->Attributes & WIN_STRICT_ALIGN)); if (find_mem_region(&win->base, win->size, (*handle)->dev_info, - ((s->cap.features & SS_CAP_MEM_ALIGN) ? - req->Size : s->cap.map_size), + (align ? req->Size : s->cap.map_size), (req->Attributes & WIN_MAP_BELOW_1MB) || !(s->cap.features & SS_CAP_PAGE_REGS))) return CS_IN_USE; diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c --- v2.3.22/linux/drivers/pcmcia/i82365.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/pcmcia/i82365.c Wed Oct 20 21:33:12 1999 @@ -3,7 +3,7 @@ Device driver for Intel 82365 and compatible PC Card controllers, and Yenta-compatible PCI-to-CardBus controllers. - i82365.c 1.254 1999/09/15 15:32:19 + i82365.c 1.260 1999/10/21 00:56:07 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -76,7 +76,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static const char *version = -"i82365.c 1.254 1999/09/15 15:32:19 (David Hinds)"; +"i82365.c 1.260 1999/10/21 00:56:07 (David Hinds)"; #else #define DEBUG(n, args...) do { } while (0) #endif @@ -189,7 +189,7 @@ #ifdef CONFIG_ISA #ifdef CONFIG_PCI /* PCI card status change interrupts? */ -static int pci_csc = 0; +static int pci_csc = 1; /* PCI IO card functional interrupts? */ static int pci_int = 0; MODULE_PARM(pci_csc, "i"); @@ -240,7 +240,7 @@ typedef struct socket_info_t { u_short type, flags; socket_cap_t cap; - u_short ioaddr; + ioaddr_t ioaddr; u_short psock; u_char cs_irq, intr; void (*handler)(void *info, u_int events); @@ -278,18 +278,18 @@ /* Default ISA interrupt mask */ #define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */ -static void pcic_interrupt_wrapper(u_long); -static void pcic_interrupt(int irq, void *dev, - struct pt_regs *regs); -static int pcic_service(u_int sock, u_int cmd, void *arg); -#ifdef CONFIG_PROC_FS -static void pcic_proc_remove(u_short sock); -#endif - #ifdef CONFIG_ISA static int grab_irq; static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED; +#define ISA_LOCK(n, f) \ + if (!(socket[n].flags & IS_CARDBUS)) spin_lock_irqsave(&isa_lock, f) +#define ISA_UNLOCK(n, f) \ + if (!(socket[n].flags & IS_CARDBUS)) spin_unlock_irqrestore(&isa_lock, f) +#else +#define ISA_LOCK(n, f) do { } while (0) +#define ISA_UNLOCK(n, f) do { } while (0) #endif + static struct timer_list poll_timer; /*====================================================================*/ @@ -322,7 +322,7 @@ #ifdef CONFIG_PCI IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730, IS_I82092AA, IS_OM82C092G, - IS_PD6832, IS_OZ6832, IS_OZ6836, + IS_PD6832, IS_OZ6832, IS_OZ6836, IS_OZ6812, IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478, IS_SMC34C90, IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210, @@ -388,6 +388,8 @@ PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 }, { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 }, + { "O2Micro OZ6812", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, + PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6812 }, { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR, PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 }, { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR, @@ -441,8 +443,6 @@ /* Some PCI shortcuts */ -#ifdef CONFIG_PCI - #define pci_readb pcibios_read_config_byte #define pci_writeb pcibios_write_config_byte #define pci_readw pcibios_read_config_word @@ -457,7 +457,6 @@ static void cb_get_power(u_short sock, socket_state_t *state); static void cb_set_power(u_short sock, socket_state_t *state); -#endif /*====================================================================*/ @@ -469,7 +468,7 @@ else #endif { - u_short port = socket[sock].ioaddr; + ioaddr_t port = socket[sock].ioaddr; u_char val; reg = I365_REG(socket[sock].psock, reg); outb(reg, port); val = inb(port+1); @@ -485,7 +484,7 @@ else #endif { - u_short port = socket[sock].ioaddr; + ioaddr_t port = socket[sock].ioaddr; u_char val = I365_REG(socket[sock].psock, reg); outb(val, port); outb(data, port+1); } @@ -954,6 +953,8 @@ p->mode_e &= ~O2_MODE_E_MHPG_DMA; p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA; p->mhpg &= ~O2_MHPG_CHANNEL; + if (t->revision == 0x34) + p->mode_c = 0x20; } else { if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000; } @@ -1125,7 +1126,7 @@ ======================================================================*/ -static void get_host_state(u_short s) +static void get_bridge_state(u_short s) { socket_info_t *t = &socket[s]; if (t->flags & IS_CIRRUS) @@ -1148,7 +1149,7 @@ #endif } -static void set_host_state(u_short s) +static void set_bridge_state(u_short s) { socket_info_t *t = &socket[s]; #ifdef CONFIG_PCI @@ -1178,7 +1179,7 @@ #endif } -static u_int __init set_host_opts(u_short s, u_short ns) +static u_int __init set_bridge_opts(u_short s, u_short ns) { u_short i; u_int m = 0xffff; @@ -1190,7 +1191,7 @@ continue; } buf[0] = '\0'; - get_host_state(i); + get_bridge_state(i); if (socket[i].flags & IS_CIRRUS) m = cirrus_set_opts(i, buf); #ifdef CONFIG_ISA @@ -1209,7 +1210,7 @@ if (socket[i].flags & IS_CARDBUS) cb_set_opts(i, buf+strlen(buf)); #endif - set_host_state(i); + set_bridge_state(i); printk(KERN_INFO " host opts [%d]:%s\n", i, (*buf) ? buf : " none"); } @@ -1255,7 +1256,7 @@ if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0) return 1; irq_hits = 0; irq_sock = sock; - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/100); if (irq_hits) { free_irq(irq, NULL); @@ -1310,7 +1311,7 @@ (cb_set_irq_mode(sock, 0, 0) == 0)) #endif if (do_scan) { - set_host_state(sock); + set_bridge_state(sock); i365_set(sock, I365_CSCINT, 0); for (i = 0; i < 16; i++) if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0)) @@ -1351,7 +1352,7 @@ u_int i; cb_set_irq_mode(sock, 1, 0); - set_host_state(sock); + set_bridge_state(sock); i365_set(sock, I365_CSCINT, 0); /* Only probe irq's 9..11, to be conservative */ for (i = 9; i < 12; i++) { @@ -1371,7 +1372,7 @@ static int to_cycles(int ns) { return ns/cycle_time; -} /* speed_convert */ +} static int to_ns(int cycles) { @@ -1517,7 +1518,7 @@ for (i = mask = 0; i < 16; i++) mask |= (1<cb_virt = ioremap(s->cb_phys, 0x1000); pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, s->cb_phys); /* Simple sanity checks */ - if (((readb(s->cb_virt+0x800+I365_IDENT) & 0xf0) - == 0x80) && + if (!(readb(s->cb_virt+0x800+I365_IDENT) & 0x70) && !(readb(s->cb_virt+0x800+I365_CSC) && readb(s->cb_virt+0x800+I365_CSC) && readb(s->cb_virt+0x800+I365_CSC))) @@ -1712,7 +1712,7 @@ /* Re-do card type & voltage detection */ cb_writel(sockets-ns, CB_SOCKET_FORCE, CB_SF_CVSTEST); - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/5); /* Set up PCI bus bridge structures if needed */ @@ -1762,9 +1762,8 @@ static void __init isa_probe(void) { - int i, j, sock, k; - int ns, id; - u_short port; + int i, j, sock, k, ns, id; + ioaddr_t port; if (check_region(i365_base, 2) != 0) { if (sockets == 0) @@ -1812,115 +1811,6 @@ /*====================================================================*/ -static int __init init_i82365(void) -{ - servinfo_t serv; - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "i82365: Card Services release " - "does not match!\n"); - return -1; - } - DEBUG(0, "%s\n", version); - printk(KERN_INFO "Intel PCIC probe: "); - sockets = 0; - -#ifdef CONFIG_PCI - if (do_pci_probe && pcibios_present()) { - pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge); - pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge); - } -#endif - -#ifdef CONFIG_ISA - isa_probe(); -#endif - - if (sockets == 0) { - printk("not found.\n"); - return -ENODEV; - } - - /* Set up interrupt handler(s) */ -#ifdef CONFIG_ISA - if (grab_irq != 0) - request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL); -#endif -#ifdef CONFIG_PCI - if (pci_csc) { - u_int i, irq, mask = 0; - for (i = 0; i < sockets; i++) { - irq = socket[i].cap.pci_irq; - if (irq && !(mask & (1<cap.pci_irq == state->io_irq)); t->bcr &= ~CB_BCR_CB_RESET; #endif - set_host_state(sock); + set_bridge_state(sock); /* IO card, RESET flag, IO interrupt */ reg = t->intr; @@ -2250,6 +2145,13 @@ } i365_set(sock, I365_CSCINT, reg); i365_get(sock, I365_CSC); +#ifdef CONFIG_PCI + if (t->flags & IS_CARDBUS) { + if (t->cs_irq || (pci_csc && t->cap.pci_irq)) + cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD); + cb_writel(sock, CB_SOCKET_EVENT, -1); + } +#endif return 0; } /* i365_set_socket */ @@ -2428,7 +2330,7 @@ case CB_SC_VCC_3V: state->Vcc = 33; break; case CB_SC_VCC_5V: state->Vcc = 50; break; } - switch (reg & CB_SC_VCC_MASK) { + switch (reg & CB_SC_VPP_MASK) { case CB_SC_VPP_3V: state->Vpp = 33; break; case CB_SC_VPP_5V: state->Vpp = 50; break; case CB_SC_VPP_12V: state->Vpp = 120; break; @@ -2509,12 +2411,12 @@ (s->cap.pci_irq == state->io_irq)); s->bcr &= ~CB_BCR_CB_RESET; s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0; - set_host_state(sock); + set_bridge_state(sock); cb_set_power(sock, state); /* Handle IO interrupt using ISA routing */ - reg = i365_get(sock, I365_INTCTL) & ~I365_IRQ_MASK; + reg = s->intr; if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq; i365_set(sock, I365_INTCTL, reg); @@ -2523,6 +2425,9 @@ if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; i365_set(sock, I365_CSCINT, reg); i365_get(sock, I365_CSC); + if (s->cs_irq || (pci_csc && s->cap.pci_irq)) + cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD); + cb_writel(sock, CB_SOCKET_EVENT, -1); return 0; } /* cb_set_socket */ @@ -2623,9 +2528,8 @@ #ifdef CONFIG_ISA u_long flags = 0; - if (!(socket[sock].flags & IS_CARDBUS)) - spin_lock_irqsave(&isa_lock, flags); #endif + ISA_LOCK(sock, flags); top = 0x40; if (socket[sock].flags & IS_CARDBUS) top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50; @@ -2639,10 +2543,7 @@ i365_get(sock,i+2), i365_get(sock,i+3), ((i % 16) == 12) ? "\n" : " "); } -#ifdef CONFIG_ISA - if (!(socket[sock].flags & IS_CARDBUS)) - spin_unlock_irqrestore(&isa_lock, flags); -#endif + ISA_UNLOCK(sock, flags); return (p - buf); } @@ -2672,13 +2573,15 @@ int count, int *eof, void *data) { u_short sock = (socket_info_t *)data - socket; - int len; - - len = sprintf(buf, "%08x %08x %08x %08x %08x %08x\n", - cb_readl(sock,0), cb_readl(sock,4), - cb_readl(sock,8), cb_readl(sock,12), - cb_readl(sock,16), cb_readl(sock,32)); - return len; + char *p = buf; + int i, top; + + top = (socket[sock].flags & IS_O2MICRO) ? 0x30 : 0x20; + for (i = 0; i < top; i += 0x10) + p += sprintf(p, "%08x %08x %08x %08x\n", + cb_readl(sock,i+0x00), cb_readl(sock,i+0x04), + cb_readl(sock,i+0x08), cb_readl(sock,i+0x0c)); + return (p - buf); } #endif @@ -2757,7 +2660,11 @@ static int pcic_service(u_int sock, u_int cmd, void *arg) { subfn_t fn; - + int ret; +#ifdef CONFIG_ISA + u_long flags = 0; +#endif + DEBUG(2, "pcic_ioctl(%d, %d, 0x%p)\n", sock, cmd, arg); if (cmd >= NFUNC) @@ -2782,20 +2689,114 @@ } #endif + ISA_LOCK(sock, flags); + ret = (fn == NULL) ? -EINVAL : fn(sock, arg); + ISA_UNLOCK(sock, flags); + return ret; +} /* pcic_service */ + +/*====================================================================*/ + +static int __init init_i82365(void) +{ + servinfo_t serv; + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "i82365: Card Services release " + "does not match!\n"); + return -1; + } + DEBUG(0, "%s\n", version); + printk(KERN_INFO "Intel PCIC probe: "); + sockets = 0; + +#ifdef CONFIG_PCI + if (do_pci_probe && pcibios_present()) { + pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge); + pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge); + } +#endif + #ifdef CONFIG_ISA - if (!(socket[sock].flags & IS_CARDBUS)) { - int ret; - u_long flags; - spin_lock_irqsave(&isa_lock, flags); - ret = (fn == NULL) ? -EINVAL : fn(sock, arg); - spin_unlock_irqrestore(&isa_lock, flags); - return ret; + isa_probe(); +#endif + + if (sockets == 0) { + printk("not found.\n"); + return -ENODEV; } + + /* Set up interrupt handler(s) */ +#ifdef CONFIG_ISA + if (grab_irq != 0) + request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL); #endif - return (fn == NULL) ? -EINVAL : fn(sock, arg); -} /* pcic_service */ +#ifdef CONFIG_PCI + if (pci_csc) { + u_int i, irq, mask = 0; + for (i = 0; i < sockets; i++) { + irq = socket[i].cap.pci_irq; + if (irq && !(mask & (1<base > entry->base+entry->num-1) - return NULL; - for (p = root; ; p = p->next) { - if ((p != root) && (p->base+p->num-1 >= entry->base)) { - p = NULL; - break; - } - if ((p->next == NULL) || - (p->next->base > entry->base+entry->num-1)) - break; - } - return p; -} - -static int register_my_resource(resource_entry_t *list, - u_long base, u_long num, char *name) -{ - u_long flags; - resource_entry_t *p, *entry; - - entry = kmalloc(sizeof(resource_entry_t), GFP_ATOMIC); - entry->base = base; - entry->num = num; - entry->name = name; - - spin_lock_irqsave(&rsrc_lock, flags); - p = find_gap(list, entry); - if (p == NULL) { - spin_unlock_irqrestore(&rsrc_lock, flags); - kfree(entry); - return -EBUSY; - } - entry->next = p->next; - p->next = entry; - spin_unlock_irqrestore(&rsrc_lock, flags); - return 0; -} - -static void release_my_resource(resource_entry_t *list, - u_long base, u_long num) -{ - u_long flags; - resource_entry_t *p, *q; - - spin_lock_irqsave(&rsrc_lock, flags); - for (p = list; ; p = q) { - q = p->next; - if (q == NULL) break; - if ((q->base == base) && (q->num == num)) { - p->next = q->next; - kfree(q); - spin_unlock_irqrestore(&rsrc_lock, flags); - return; - } - } - spin_unlock_irqrestore(&rsrc_lock, flags); - return; -} +static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED; -static int check_my_resource(resource_entry_t *list, - u_long base, u_long num) -{ - if (register_my_resource(list, base, num, NULL) != 0) - return -EBUSY; - release_my_resource(list, base, num); - return 0; -} - -int check_io_region(u_long base, u_long num) -{ - return check_my_resource(&io_list, base, num); -} -void request_io_region(u_long base, u_long num, char *name) -{ - register_my_resource(&io_list, base, num, name); -} -void release_io_region(u_long base, u_long num) -{ - release_my_resource(&io_list, base, num); -} -#ifdef CONFIG_PROC_FS -int proc_read_io(char *buf, char **start, off_t pos, - int count, int *eof, void *data) -{ - resource_entry_t *r; - u_long flags; - char *p = buf; - - spin_lock_irqsave(&rsrc_lock, flags); - for (r = io_list.next; r; r = r->next) - p += sprintf(p, "%04lx-%04lx : %s\n", r->base, - r->base+r->num-1, r->name); - spin_unlock_irqrestore(&rsrc_lock, flags); - return (p - buf); -} -#endif +#define check_io_region(b,n) (0) /*====================================================================== @@ -773,7 +664,6 @@ void release_resource_db(void) { resource_map_t *p, *q; - resource_entry_t *u, *v; for (p = mem_db.next; p != &mem_db; p = q) { q = p->next; @@ -782,9 +672,5 @@ for (p = io_db.next; p != &io_db; p = q) { q = p->next; kfree(p); - } - for (u = io_list.next; u; u = v) { - v = u->next; - kfree(u); } } diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/rsrc_mgr.h linux/drivers/pcmcia/rsrc_mgr.h --- v2.3.22/linux/drivers/pcmcia/rsrc_mgr.h Tue Sep 7 12:14:06 1999 +++ linux/drivers/pcmcia/rsrc_mgr.h Wed Oct 20 21:33:12 1999 @@ -30,10 +30,4 @@ #ifndef _RSRC_MGR_H #define _RSRC_MGR_H -#ifdef __BEOS__ -int check_resource(int type, u_long base, u_long num); -int register_resource(int type, u_long base, u_long num); -int release_resource(int type, u_long base, u_long num); -#endif - #endif /* _RSRC_MGR_H */ diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c --- v2.3.22/linux/drivers/scsi/atp870u.c Fri Sep 10 23:57:31 1999 +++ linux/drivers/scsi/atp870u.c Mon Oct 18 11:35:54 1999 @@ -1,7 +1,7 @@ /* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $ * linux/kernel/atp870u.c * - * Copyright (C) 1997 Wu Ching Chen + * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski * * Marcelo Tosatti : SMP fixes @@ -30,745 +30,620 @@ #include -struct proc_dir_entry proc_scsi_atp870u = { - PROC_SCSI_ATP870U, 7, "atp870u", - S_IFDIR | S_IRUGO | S_IXUGO, 2 +struct proc_dir_entry proc_scsi_atp870u = +{ + PROC_SCSI_ATP870U, 7, "atp870u", + S_IFDIR | S_IRUGO | S_IXUGO, 2 }; void mydlyu(unsigned int); + /* -static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $"; -*/ + * static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $"; + */ + +static unsigned char admaxu = 1, host_idu[2], chip_veru[2], scam_on[2], global_map[2]; +static unsigned short int active_idu[2], wide_idu[2], sync_idu, ultra_map[2]; +static int workingu[2] = {0, 0}; + +static Scsi_Cmnd *querequ[2][qcnt], *curr_req[2][16]; + +static unsigned char devspu[2][16] = { + {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20} +}; -static unsigned char admaxu=1,host_idu[2],chip_veru[2],scam_on[2],global_map[2]; -static unsigned short int active_idu[2],wide_idu[2],sync_idu,ultra_map[2]; -static int workingu[2]={0,0}; -static Scsi_Cmnd *querequ[2][qcnt],*curr_req[2][16]; -static unsigned char devspu[2][16] = {{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}, - {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}}; -static unsigned char dirctu[2][16],last_cmd[2],in_snd[2],in_int[2]; +static unsigned char dirctu[2][16], last_cmd[2], in_snd[2], in_int[2]; static unsigned char ata_cdbu[2][16]; -static unsigned int ioportu[2]={0,0}; -static unsigned int irqnumu[2]={0,0}; +static unsigned int ioportu[2] = {0, 0}; +static unsigned int irqnumu[2] = {0, 0}; static unsigned short int pciportu[2]; -static unsigned long prdaddru[2][16],tran_lenu[2][16],last_lenu[2][16]; +static unsigned long prdaddru[2][16], tran_lenu[2][16], last_lenu[2][16]; static unsigned char prd_tableu[2][16][1024]; static unsigned char *prd_posu[2][16]; -static unsigned char quhdu[2],quendu[2]; -static unsigned char devtypeu[2][16] = {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; -static struct Scsi_Host * atp_host[2]={NULL,NULL}; +static unsigned char quhdu[2], quendu[2]; + +static unsigned char devtypeu[2][16] = +{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +static struct Scsi_Host *atp_host[2] = {NULL, NULL}; static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { - unsigned long flags; - unsigned short int tmpcip,id; - unsigned char i,j,h,tarid,lun; - unsigned char *prd; - Scsi_Cmnd *workrequ; - unsigned int workportu,tmport; - unsigned long adrcntu,k; - int errstus; - - for ( h=0; h < 2; h++ ) - { - if ( ( irq & 0x0f ) == irqnumu[h] ) - { - goto irq_numok; + unsigned long flags; + unsigned short int tmpcip, id; + unsigned char i, j, h, tarid, lun; + unsigned char *prd; + Scsi_Cmnd *workrequ; + unsigned int workportu, tmport; + unsigned long adrcntu, k; + int errstus; + + for (h = 0; h < 2; h++) { + if (irq == irqnumu[h]) { + goto irq_numok; + } } - } - return; + return; irq_numok: - in_int[h]=1; - workportu=ioportu[h]; - tmport=workportu; - - if ( workingu[h] != 0 ) - { - tmport += 0x1f; - j=inb(tmport); - tmpcip=pciportu[h]; - if ((inb(tmpcip) & 0x08) != 0) - { - tmpcip += 0x2; - while((inb(tmpcip) & 0x08) != 0); - } - tmpcip=pciportu[h]; - outb(0x00,tmpcip); - tmport -=0x08; - i=inb(tmport); - if ((j & 0x40) == 0) - { - if ((last_cmd[h] & 0x40) == 0) - { - last_cmd[h]=0xff; - } - } - else - { - last_cmd[h] |= 0x40; - } - tmport -= 0x02; - tarid=inb(tmport); - tmport += 0x02; - if ((tarid & 0x40) != 0) - { - tarid=(tarid & 0x07) | 0x08; - } - else - { - tarid &= 0x07; - } - if ( i == 0x85 ) - { - if (wide_idu[h] != 0) - { - tmport=workportu+0x1b; - j=inb(tmport) & 0x0e; - j |= 0x01; - outb(j,tmport); - } - if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) && - (in_snd[h] == 0)) - { - send_s870(h); - } - in_int[h]=0; - return; - } - if ( i == 0x21 ) - { - tmport -= 0x05; - adrcntu=0; - ((unsigned char *)&adrcntu)[2]=inb(tmport++); - ((unsigned char *)&adrcntu)[1]=inb(tmport++); - ((unsigned char *)&adrcntu)[0]=inb(tmport); - k=last_lenu[h][tarid]; - k -= adrcntu; - tran_lenu[h][tarid]= k; - last_lenu[h][tarid]=adrcntu; - tmport -= 0x04; - outb(0x41,tmport); - tmport += 0x08; - outb(0x08,tmport); - in_int[h]=0; - return ; - } - - if ((i == 0x80) || (i == 0x8f)) - { - lun=0; - tmport -= 0x07; - j=inb(tmport); - if ( j == 0x44 ) - { - tmport += 0x0d; - lun=inb(tmport) & 0x07; - } - else - { - if ( j == 0x41 ) - { + in_int[h] = 1; + workportu = ioportu[h]; + tmport = workportu; + + if (workingu[h] != 0) + { + tmport += 0x1f; + j = inb(tmport); + + tmpcip = pciportu[h]; + if ((inb(tmpcip) & 0x08) != 0) + { + tmpcip += 0x2; + while ((inb(tmpcip) & 0x08) != 0); + } + tmpcip = pciportu[h]; + outb(0x00, tmpcip); + tmport -= 0x08; + + i = inb(tmport); + if ((j & 0x40) == 0) + { + if ((last_cmd[h] & 0x40) == 0) + { + last_cmd[h] = 0xff; + } + } + else last_cmd[h] |= 0x40; + + tmport -= 0x02; + tarid = inb(tmport); tmport += 0x02; - adrcntu=0; - ((unsigned char *)&adrcntu)[2]=inb(tmport++); - ((unsigned char *)&adrcntu)[1]=inb(tmport++); - ((unsigned char *)&adrcntu)[0]=inb(tmport); - k=last_lenu[h][tarid]; - k -= adrcntu; - tran_lenu[h][tarid]= k; - last_lenu[h][tarid]=adrcntu; - tmport += 0x04; - outb(0x08,tmport); - in_int[h]=0; - return ; - } - else - { - outb(0x46,tmport); - dirctu[h][tarid]=0x00; + + if ((tarid & 0x40) != 0) { + tarid = (tarid & 0x07) | 0x08; + } else { + tarid &= 0x07; + } + if (i == 0x85) + { + if (wide_idu[h] != 0) + { + tmport = workportu + 0x1b; + j = inb(tmport) & 0x0e; + j |= 0x01; + outb(j, tmport); + } + if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) && + (in_snd[h] == 0)) + { + send_s870(h); + } + in_int[h] = 0; + return; + } + if (i == 0x21) + { + tmport -= 0x05; + adrcntu = 0; + ((unsigned char *) &adrcntu)[2] = inb(tmport++); + ((unsigned char *) &adrcntu)[1] = inb(tmport++); + ((unsigned char *) &adrcntu)[0] = inb(tmport); + k = last_lenu[h][tarid]; + k -= adrcntu; + tran_lenu[h][tarid] = k; + last_lenu[h][tarid] = adrcntu; + tmport -= 0x04; + outb(0x41, tmport); + tmport += 0x08; + outb(0x08, tmport); + in_int[h] = 0; + return; + } + if ((i == 0x80) || (i == 0x8f)) + { + lun = 0; + tmport -= 0x07; + j = inb(tmport); + if (j == 0x44) { + tmport += 0x0d; + lun = inb(tmport) & 0x07; + } else { + if (j == 0x41) + { + tmport += 0x02; + adrcntu = 0; + ((unsigned char *) &adrcntu)[2] = inb(tmport++); + ((unsigned char *) &adrcntu)[1] = inb(tmport++); + ((unsigned char *) &adrcntu)[0] = inb(tmport); + k = last_lenu[h][tarid]; + k -= adrcntu; + tran_lenu[h][tarid] = k; + last_lenu[h][tarid] = adrcntu; + tmport += 0x04; + outb(0x08, tmport); + in_int[h] = 0; + return; + } + else + { + outb(0x46, tmport); + dirctu[h][tarid] = 0x00; + tmport += 0x02; + outb(0x00, tmport++); + outb(0x00, tmport++); + outb(0x00, tmport++); + tmport += 0x03; + outb(0x08, tmport); + in_int[h] = 0; + return; + } + } + tmport = workportu + 0x10; + outb(0x45, tmport); + tmport += 0x06; + tarid = inb(tmport); + if ((tarid & 0x10) != 0) + { + tarid = (tarid & 0x07) | 0x08; + } else { + tarid &= 0x07; + } + workrequ = curr_req[h][tarid]; + tmport = workportu + 0x0f; + outb(lun, tmport); + tmport += 0x02; + outb(devspu[h][tarid], tmport++); + adrcntu = tran_lenu[h][tarid]; + k = last_lenu[h][tarid]; + outb(((unsigned char *) &k)[2], tmport++); + outb(((unsigned char *) &k)[1], tmport++); + outb(((unsigned char *) &k)[0], tmport++); + j = tarid; + if (tarid > 7) { + j = (j & 0x07) | 0x40; + } + j |= dirctu[h][tarid]; + outb(j, tmport++); + outb(0x80, tmport); + tmport = workportu + 0x1b; + j = inb(tmport) & 0x0e; + id = 1; + id = id << tarid; + if ((id & wide_idu[h]) != 0) { + j |= 0x01; + } + outb(j, tmport); + if (last_lenu[h][tarid] == 0) { + tmport = workportu + 0x18; + outb(0x08, tmport); + in_int[h] = 0; + return; + } + prd = prd_posu[h][tarid]; + while (adrcntu != 0) + { + id = ((unsigned short int *) (prd))[2]; + if (id == 0) { + k = 0x10000; + } else { + k = id; + } + if (k > adrcntu) { + ((unsigned short int *) (prd))[2] = (unsigned short int) + (k - adrcntu); + ((unsigned long *) (prd))[0] += adrcntu; + adrcntu = 0; + prd_posu[h][tarid] = prd; + } else { + adrcntu -= k; + prdaddru[h][tarid] += 0x08; + prd += 0x08; + if (adrcntu == 0) { + prd_posu[h][tarid] = prd; + } + } + } + tmpcip = pciportu[h] + 0x04; + outl(prdaddru[h][tarid], tmpcip); + tmpcip -= 0x02; + outb(0x06, tmpcip); + outb(0x00, tmpcip); + tmpcip -= 0x02; + tmport = workportu + 0x18; + if (dirctu[h][tarid] != 0) { + outb(0x08, tmport); + outb(0x01, tmpcip); + in_int[h] = 0; + return; + } + outb(0x08, tmport); + outb(0x09, tmpcip); + in_int[h] = 0; + return; + } + workrequ = curr_req[h][tarid]; + if (i == 0x42) { + errstus = 0x02; + workrequ->result = errstus; + goto go_42; + } + if (i == 0x16) + { + errstus = 0; + tmport -= 0x08; + errstus = inb(tmport); + workrequ->result = errstus; +go_42: + spin_lock_irqsave(&io_request_lock, flags); + (*workrequ->scsi_done) (workrequ); + spin_unlock_irqrestore(&io_request_lock, flags); + + curr_req[h][tarid] = 0; + workingu[h]--; + if (wide_idu[h] != 0) { + tmport = workportu + 0x1b; + j = inb(tmport) & 0x0e; + j |= 0x01; + outb(j, tmport); + } + if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) && + (in_snd[h] == 0)) + { + send_s870(h); + } + in_int[h] = 0; + return; + } + if (i == 0x4f) { + i = 0x89; + } + i &= 0x0f; + if (i == 0x09) { + tmpcip = tmpcip + 4; + outl(prdaddru[h][tarid], tmpcip); + tmpcip = tmpcip - 2; + outb(0x06, tmpcip); + outb(0x00, tmpcip); + tmpcip = tmpcip - 2; + tmport = workportu + 0x10; + outb(0x41, tmport); + dirctu[h][tarid] = 0x00; + tmport += 0x08; + outb(0x08, tmport); + outb(0x09, tmpcip); + in_int[h] = 0; + return; + } + if (i == 0x08) { + tmpcip = tmpcip + 4; + outl(prdaddru[h][tarid], tmpcip); + tmpcip = tmpcip - 2; + outb(0x06, tmpcip); + outb(0x00, tmpcip); + tmpcip = tmpcip - 2; + tmport = workportu + 0x10; + outb(0x41, tmport); + tmport += 0x05; + outb((unsigned char) (inb(tmport) | 0x20), tmport); + dirctu[h][tarid] = 0x20; + tmport += 0x03; + outb(0x08, tmport); + outb(0x01, tmpcip); + in_int[h] = 0; + return; + } + tmport -= 0x07; + if (i == 0x0a) { + outb(0x30, tmport); + } else { + outb(0x46, tmport); + } + dirctu[h][tarid] = 0x00; tmport += 0x02; - outb(0x00,tmport++); - outb(0x00,tmport++); - outb(0x00,tmport++); - tmport+=0x03; - outb(0x08,tmport); - in_int[h]=0; + outb(0x00, tmport++); + outb(0x00, tmport++); + outb(0x00, tmport++); + tmport += 0x03; + outb(0x08, tmport); + in_int[h] = 0; return; - } - } - tmport=workportu + 0x10; - outb(0x45,tmport); - tmport += 0x06; - tarid=inb(tmport); - if ((tarid & 0x10) != 0) - { - tarid=(tarid & 0x07) | 0x08; - } - else - { - tarid &= 0x07; - } - workrequ=curr_req[h][tarid]; - tmport=workportu + 0x0f; - outb(lun,tmport); - tmport += 0x02; - outb(devspu[h][tarid],tmport++); - adrcntu=tran_lenu[h][tarid]; - k=last_lenu[h][tarid]; - outb(((unsigned char *)&k)[2],tmport++); - outb(((unsigned char *)&k)[1],tmport++); - outb(((unsigned char *)&k)[0],tmport++); - j=tarid; - if ( tarid > 7 ) - { - j = (j & 0x07) | 0x40; - } - j |= dirctu[h][tarid]; - outb(j,tmport++); - outb(0x80,tmport); - tmport=workportu + 0x1b; - j=inb(tmport) & 0x0e; - id=1; - id=id << tarid; - if ((id & wide_idu[h]) != 0) - { - j |= 0x01; - } - outb(j,tmport); - if ( last_lenu[h][tarid] == 0 ) - { - tmport=workportu + 0x18; - outb(0x08,tmport); - in_int[h]=0; - return ; - } - prd=prd_posu[h][tarid]; - while ( adrcntu != 0 ) - { - id=((unsigned short int *)(prd))[2]; - if ( id == 0 ) - { - k=0x10000; - } - else - { - k=id; - } - if ( k > adrcntu ) - { - ((unsigned short int *)(prd))[2] =(unsigned short int) - (k - adrcntu); - ((unsigned long *)(prd))[0] += adrcntu; - adrcntu=0; - prd_posu[h][tarid]=prd; - } - else - { - adrcntu -= k; - prdaddru[h][tarid] += 0x08; - prd += 0x08; - if ( adrcntu == 0 ) - { - prd_posu[h][tarid]=prd; - } - } - } - tmpcip=pciportu[h] + 0x04; - outl(prdaddru[h][tarid],tmpcip); - tmpcip -= 0x02; - outb(0x06,tmpcip); - outb(0x00,tmpcip); - tmpcip -= 0x02; - tmport=workportu + 0x18; - if ( dirctu[h][tarid] != 0 ) - { - outb(0x08,tmport); - outb(0x01,tmpcip); - in_int[h]=0; - return; - } - outb(0x08,tmport); - outb(0x09,tmpcip); - in_int[h]=0; - return; - } - - workrequ=curr_req[h][tarid]; - if ( i == 0x42 ) - { - errstus=0x02; - workrequ->result=errstus; - goto go_42; - } - if ( i == 0x16 ) - { - errstus=0; - tmport -= 0x08; - errstus=inb(tmport); - workrequ->result=errstus; -/* if ( errstus == 0x02 ) - { - tmport +=0x10; - if ((inb(tmport) & 0x80) != 0) - { - printk(" autosense "); - } - tmport -=0x09; - outb(0,tmport); - tmport=workportu+0x3a; - outb((unsigned char)(inb(tmport) | 0x10),tmport); - tmport -= 0x39; - - outb(0x08,tmport++); - outb(0x7f,tmport++); - outb(0x03,tmport++); - outb(0x00,tmport++); - outb(0x00,tmport++); - outb(0x00,tmport++); - outb(0x0e,tmport++); - outb(0x00,tmport); - tmport+=0x07; - outb(0x00,tmport++); - tmport++; - outb(devspu[h][workrequ->target],tmport++); - outb(0x00,tmport++); - outb(0x00,tmport++); - outb(0x0e,tmport++); - tmport+=0x03; - outb(0x09,tmport); - tmport+=0x07; - i=0; - adrcntu=(unsigned long)(&workrequ->sense_buffer[0]); -get_sens: - j=inb(tmport); - if ((j & 0x01) != 0) - { - tmport-=0x06; - (unsigned char)(((caddr_t) adrcntu)[i++])=inb(tmport); - tmport+=0x06; - goto get_sens; - } - if ((j & 0x80) == 0) - { - goto get_sens; - } - if ((j & 0x40) == 0) - { - tmport-=0x08; - i=inb(tmport); - } - tmport=workportu+0x3a; - outb((unsigned char)(inb(tmport) & 0xef),tmport); - tmport=workportu+0x01; - outb(0x2c,tmport); - tmport += 0x15; - outb(0x80,tmport); - } */ -go_42: - spin_lock_irqsave(&io_request_lock, flags); - (*workrequ->scsi_done)(workrequ); - spin_unlock_irqrestore(&io_request_lock, flags); - - curr_req[h][tarid]=0; - workingu[h]--; - if (wide_idu[h] != 0) - { - tmport=workportu+0x1b; - j=inb(tmport) & 0x0e; - j |= 0x01; - outb(j,tmport); - } - if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) && - (in_snd[h] == 0)) - { - send_s870(h); - } - in_int[h]=0; - return; - } - if ( i == 0x4f ) - { - i=0x89; - } - i &= 0x0f; - if ( i == 0x09 ) - { - tmpcip=tmpcip+4; - outl(prdaddru[h][tarid],tmpcip); - tmpcip=tmpcip-2; - outb(0x06,tmpcip); - outb(0x00,tmpcip); - tmpcip=tmpcip-2; - tmport=workportu+0x10; - outb(0x41,tmport); - dirctu[h][tarid]=0x00; - tmport += 0x08; - outb(0x08,tmport); - outb(0x09,tmpcip); - in_int[h]=0; - return; - } - if ( i == 0x08 ) - { - tmpcip=tmpcip+4; - outl(prdaddru[h][tarid],tmpcip); - tmpcip=tmpcip-2; - outb(0x06,tmpcip); - outb(0x00,tmpcip); - tmpcip=tmpcip-2; - tmport=workportu+0x10; - outb(0x41,tmport); - tmport += 0x05; - outb((unsigned char)(inb(tmport) | 0x20),tmport); - dirctu[h][tarid]=0x20; - tmport += 0x03; - outb(0x08,tmport); - outb(0x01,tmpcip); - in_int[h]=0; - return; - } - tmport -= 0x07; - if ( i == 0x0a ) - { - outb(0x30,tmport); - } - else - { - outb(0x46,tmport); - } - dirctu[h][tarid]=0x00; - tmport += 0x02; - outb(0x00,tmport++); - outb(0x00,tmport++); - outb(0x00,tmport++); - tmport+=0x03; - outb(0x08,tmport); - in_int[h]=0; - return; - } - else - { - tmport=workportu+0x17; - inb(tmport); - workingu[h]=0; - in_int[h]=0; - return; - } + } else { + tmport = workportu + 0x17; + inb(tmport); + workingu[h] = 0; + in_int[h] = 0; + return; + } } -int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done)(Scsi_Cmnd *)) +int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *)) { - unsigned char i,h; - unsigned long flags; - unsigned short int m; - unsigned int tmport; - - for( h=0; h <= admaxu; h++ ) - { - if ( req_p->host == atp_host[h] ) - { - goto host_ok; - } - } - return 0; + unsigned char i, h; + unsigned long flags; + unsigned short int m; + unsigned int tmport; + + for (h = 0; h <= admaxu; h++) { + if (req_p->host == atp_host[h]) { + goto host_ok; + } + } + return 0; host_ok: - if ( req_p->channel != 0 ) - { - req_p->result = 0x00040000; - done(req_p); - return 0; - } - m=1; - m= m << req_p->target; - if ( ( m & active_idu[h] ) == 0 ) - { - req_p->result = 0x00040000; - done(req_p); - return 0; - } - if (done) - { - req_p->scsi_done = done; - } - else - { - printk("atp870u_queuecommand: done can't be NULL\n"); - req_p->result = 0; - done(req_p); - return 0; - } - quendu[h]++; - if ( quendu[h] >= qcnt ) - { - quendu[h]=0; - } - wait_que_empty: - if ( quhdu[h] == quendu[h] ) - { - goto wait_que_empty; - } - save_flags(flags); - cli(); - querequ[h][quendu[h]]=req_p; - if ( quendu[h] == 0 ) - { - i=qcnt-1; - } - else - { - i=quendu[h]-1; - } - tmport = ioportu[h]+0x1c; - restore_flags(flags); - if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0)) - { - send_s870(h); - } - return 0; + if (req_p->channel != 0) { + req_p->result = 0x00040000; + done(req_p); + return 0; + } + m = 1; + m = m << req_p->target; + if ((m & active_idu[h]) == 0) { + req_p->result = 0x00040000; + done(req_p); + return 0; + } + if (done) { + req_p->scsi_done = done; + } else { + printk("atp870u_queuecommand: done can't be NULL\n"); + req_p->result = 0; + done(req_p); + return 0; + } + quendu[h]++; + if (quendu[h] >= qcnt) { + quendu[h] = 0; + } +wait_que_empty: + if (quhdu[h] == quendu[h]) { + goto wait_que_empty; + } + save_flags(flags); + cli(); + querequ[h][quendu[h]] = req_p; + if (quendu[h] == 0) { + i = qcnt - 1; + } else { + i = quendu[h] - 1; + } + tmport = ioportu[h] + 0x1c; + restore_flags(flags); + if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0)) { + send_s870(h); + } + return 0; } -void mydlyu(unsigned int dlycnt ) +void mydlyu(unsigned int dlycnt) { - unsigned int i ; - for ( i = 0 ; i < dlycnt ; i++ ) - { - inb(0x80); - } + unsigned int i; + for (i = 0; i < dlycnt; i++) { + inb(0x80); + } } void send_s870(unsigned char h) { - unsigned int tmport; - Scsi_Cmnd *workrequ; - unsigned long flags; - unsigned int i; - unsigned char j,tarid; - unsigned char *prd; - unsigned short int tmpcip,w; - unsigned long l,bttl; - unsigned int workportu; - struct scatterlist * sgpnt; + unsigned int tmport; + Scsi_Cmnd *workrequ; + unsigned long flags; + unsigned int i; + unsigned char j, tarid; + unsigned char *prd; + unsigned short int tmpcip, w; + unsigned long l, bttl; + unsigned int workportu; + struct scatterlist *sgpnt; save_flags(flags); cli(); - if ( in_snd[h] != 0 ) - { - restore_flags(flags); - return; + if (in_snd[h] != 0) { + restore_flags(flags); + return; } - in_snd[h]=1; - if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0)) - { - last_cmd[h] &= 0x0f; - workrequ=curr_req[h][last_cmd[h]]; - goto cmd_subp; + in_snd[h] = 1; + if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0)) { + last_cmd[h] &= 0x0f; + workrequ = curr_req[h][last_cmd[h]]; + goto cmd_subp; } workingu[h]++; - j=quhdu[h]; + j = quhdu[h]; quhdu[h]++; - if ( quhdu[h] >= qcnt ) - { - quhdu[h]=0; + if (quhdu[h] >= qcnt) { + quhdu[h] = 0; } - workrequ=querequ[h][quhdu[h]]; - if ( curr_req[h][workrequ->target] == 0 ) - { - curr_req[h][workrequ->target]=workrequ; - last_cmd[h]=workrequ->target; - goto cmd_subp; + workrequ = querequ[h][quhdu[h]]; + if (curr_req[h][workrequ->target] == 0) { + curr_req[h][workrequ->target] = workrequ; + last_cmd[h] = workrequ->target; + goto cmd_subp; } - quhdu[h]=j; + quhdu[h] = j; workingu[h]--; - in_snd[h]=0; + in_snd[h] = 0; restore_flags(flags); - return ; + return; cmd_subp: - workportu=ioportu[h]; - tmport=workportu+0x1f; - if ((inb(tmport) & 0xb0) != 0) - { - goto abortsnd; - } - tmport=workportu+0x1c; - if ( inb(tmport) == 0 ) - { - goto oktosend; - } + workportu = ioportu[h]; + tmport = workportu + 0x1f; + if ((inb(tmport) & 0xb0) != 0) { + goto abortsnd; + } + tmport = workportu + 0x1c; + if (inb(tmport) == 0) { + goto oktosend; + } abortsnd: - last_cmd[h] |= 0x40; - in_snd[h]=0; - restore_flags(flags); - return; -oktosend: - memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len); - if ( ata_cdbu[h][0] == 0x25 ) - { - if ( workrequ->request_bufflen > 8 ) - { - workrequ->request_bufflen=0x08; - } - } - if ( ata_cdbu[h][0] == 0x12 ) - { - if ( workrequ->request_bufflen > 0x24 ) - { - workrequ->request_bufflen = 0x24; - ata_cdbu[h][4]=0x24; - } - } - - tmport=workportu+0x1b; - j=inb(tmport) & 0x0e; - tarid=workrequ->target; - w=1; - w = w << tarid; - if ((w & wide_idu[h]) != 0) - { - j |= 0x01; - } - outb(j,tmport); - tmport=workportu; - outb(workrequ->cmd_len,tmport++); - outb(0x2c,tmport++); - outb(0xcf,tmport++); - for ( i=0 ; i < workrequ->cmd_len ; i++ ) - { - outb(ata_cdbu[h][i],tmport++); - } - tmport=workportu+0x0f; - outb(0x00,tmport); - tmport+=0x02; - outb(devspu[h][tarid],tmport++); - if (workrequ->use_sg) - { - - l=0; - sgpnt = (struct scatterlist *) workrequ->request_buffer; - for(i=0; iuse_sg; i++) - { - if(sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) - { - panic("Foooooooood fight!"); - } - l += sgpnt[i].length; - } - } - else - { - l=workrequ->request_bufflen; - } - outb((unsigned char)(((unsigned char *)(&l))[2]),tmport++); - outb((unsigned char)(((unsigned char *)(&l))[1]),tmport++); - outb((unsigned char)(((unsigned char *)(&l))[0]),tmport++); - j=tarid; - last_lenu[h][j]=l; - tran_lenu[h][j]=0; - if ((j & 0x08) != 0) - { - j=(j & 0x07) | 0x40; - } - if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) || - (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) - { - outb((unsigned char)(j | 0x20),tmport++); - } - else - { - outb(j,tmport++); - } - outb(0x80,tmport); - tmport=workportu + 0x1c; - dirctu[h][tarid]=0; - if ( l == 0 ) - { - if ( inb(tmport) == 0 ) - { - tmport=workportu+0x18; - outb(0x08,tmport); - } - else - { last_cmd[h] |= 0x40; - } - in_snd[h]=0; - restore_flags(flags); - return; - } - tmpcip=pciportu[h]; - prd=&prd_tableu[h][tarid][0]; - prd_posu[h][tarid]=prd; - if (workrequ->use_sg) - { - sgpnt = (struct scatterlist *) workrequ->request_buffer; - i=0; - for(j=0; juse_sg; j++) - { - (unsigned long)(((unsigned long *)(prd))[i >> 1])=(unsigned long)sgpnt[j].address; - (unsigned short int)(((unsigned short int *)(prd))[i+2])=sgpnt[j].length; - (unsigned short int)(((unsigned short int *)(prd))[i+3])=0; - i +=0x04; - } - (unsigned short int)(((unsigned short int *)(prd))[i-1])=0x8000; - } - else - { - bttl=(unsigned long)workrequ->request_buffer; - l=workrequ->request_bufflen; - i=0; - while ( l > 0x10000 ) - { - (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x0000; - (unsigned short int)(((unsigned short int *)(prd))[i+2])=0x0000; - (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl; - l -= 0x10000; - bttl += 0x10000; - i += 0x04; - } - (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x8000; - (unsigned short int)(((unsigned short int *)(prd))[i+2])=l; - (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl; - } - tmpcip=tmpcip+4; - prdaddru[h][tarid]=(unsigned long)&prd_tableu[h][tarid][0]; - outl(prdaddru[h][tarid],tmpcip); - tmpcip=tmpcip-2; - outb(0x06,tmpcip); - outb(0x00,tmpcip); - tmpcip=tmpcip-2; - if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) || - (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) - { - dirctu[h][tarid]=0x20; - if ( inb(tmport) == 0 ) - { - tmport=workportu+0x18; - outb(0x08,tmport); - outb(0x01,tmpcip); - } - else - { - last_cmd[h] |= 0x40; - } - in_snd[h]=0; - restore_flags(flags); - return; - } - if ( inb(tmport) == 0 ) - { - tmport=workportu+0x18; - outb(0x08,tmport); - outb(0x09,tmpcip); - } - else - { - last_cmd[h] |= 0x40; - } - in_snd[h]=0; - restore_flags(flags); - return; + in_snd[h] = 0; + restore_flags(flags); + return; +oktosend: + memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len); + if (ata_cdbu[h][0] == 0x25) { + if (workrequ->request_bufflen > 8) { + workrequ->request_bufflen = 0x08; + } + } + if (ata_cdbu[h][0] == 0x12) { + if (workrequ->request_bufflen > 0x24) { + workrequ->request_bufflen = 0x24; + ata_cdbu[h][4] = 0x24; + } + } + tmport = workportu + 0x1b; + j = inb(tmport) & 0x0e; + tarid = workrequ->target; + w = 1; + w = w << tarid; + if ((w & wide_idu[h]) != 0) { + j |= 0x01; + } + outb(j, tmport); + tmport = workportu; + outb(workrequ->cmd_len, tmport++); + outb(0x2c, tmport++); + outb(0xcf, tmport++); + for (i = 0; i < workrequ->cmd_len; i++) { + outb(ata_cdbu[h][i], tmport++); + } + tmport = workportu + 0x0f; + outb(0x00, tmport); + tmport += 0x02; + outb(devspu[h][tarid], tmport++); + if (workrequ->use_sg) + { + l = 0; + sgpnt = (struct scatterlist *) workrequ->request_buffer; + for (i = 0; i < workrequ->use_sg; i++) + { + if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) + { + panic("Foooooooood fight!"); + } + l += sgpnt[i].length; + } + } else { + l = workrequ->request_bufflen; + } + outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++); + outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++); + outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++); + j = tarid; + last_lenu[h][j] = l; + tran_lenu[h][j] = 0; + if ((j & 0x08) != 0) { + j = (j & 0x07) | 0x40; + } + if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) || + (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) { + outb((unsigned char) (j | 0x20), tmport++); + } else { + outb(j, tmport++); + } + outb(0x80, tmport); + tmport = workportu + 0x1c; + dirctu[h][tarid] = 0; + if (l == 0) { + if (inb(tmport) == 0) { + tmport = workportu + 0x18; + outb(0x08, tmport); + } else { + last_cmd[h] |= 0x40; + } + in_snd[h] = 0; + restore_flags(flags); + return; + } + tmpcip = pciportu[h]; + prd = &prd_tableu[h][tarid][0]; + prd_posu[h][tarid] = prd; + if (workrequ->use_sg) + { + sgpnt = (struct scatterlist *) workrequ->request_buffer; + i = 0; + for (j = 0; j < workrequ->use_sg; j++) { + (unsigned long) (((unsigned long *) (prd))[i >> 1]) = virt_to_bus(sgpnt[j].address); + (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = sgpnt[j].length; + (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0; + i += 0x04; + } + (unsigned short int) (((unsigned short int *) (prd))[i - 1]) = 0x8000; + } else { + bttl = virt_to_bus(workrequ->request_buffer); + l = workrequ->request_bufflen; + i = 0; + while (l > 0x10000) { + (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x0000; + (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = 0x0000; + (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl; + l -= 0x10000; + bttl += 0x10000; + i += 0x04; + } + (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x8000; + (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = l; + (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl; + } + tmpcip = tmpcip + 4; + prdaddru[h][tarid] = virt_to_bus(&prd_tableu[h][tarid][0]); + outl(prdaddru[h][tarid], tmpcip); + tmpcip = tmpcip - 2; + outb(0x06, tmpcip); + outb(0x00, tmpcip); + tmpcip = tmpcip - 2; + if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) || + (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) + { + dirctu[h][tarid] = 0x20; + if (inb(tmport) == 0) { + tmport = workportu + 0x18; + outb(0x08, tmport); + outb(0x01, tmpcip); + } else { + last_cmd[h] |= 0x40; + } + in_snd[h] = 0; + restore_flags(flags); + return; + } + if (inb(tmport) == 0) + { + tmport = workportu + 0x18; + outb(0x08, tmport); + outb(0x09, tmpcip); + } else { + last_cmd[h] |= 0x40; + } + in_snd[h] = 0; + restore_flags(flags); + return; } @@ -780,1101 +655,964 @@ int atp870u_command(Scsi_Cmnd * SCpnt) { - atp870u_queuecommand(SCpnt, internal_done); + atp870u_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; + SCpnt->SCp.Status = 0; + while (!SCpnt->SCp.Status) + barrier(); + return SCpnt->result; } -unsigned char fun_scam ( unsigned char host,unsigned short int * val ) +unsigned char fun_scam(unsigned char host, unsigned short int *val) { - unsigned int tmport ; - unsigned short int i,k; - unsigned char j; + unsigned int tmport; + unsigned short int i, k; + unsigned char j; - tmport = ioportu[host]+0x1c; - outw(*val,tmport); + tmport = ioportu[host] + 0x1c; + outw(*val, tmport); FUN_D7: - for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */ - { - k=inw(tmport); - j= (unsigned char)(k >> 8); - if ((k & 0x8000) != 0) /* DB7 all release? */ - { - goto FUN_D7; + for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ + k = inw(tmport); + j = (unsigned char) (k >> 8); + if ((k & 0x8000) != 0) { /* DB7 all release? */ + goto FUN_D7; + } } - } - *val |= 0x4000; /* assert DB6 */ - outw(*val,tmport); - *val &= 0xdfff; /* assert DB5 */ - outw(*val,tmport); + *val |= 0x4000; /* assert DB6 */ + outw(*val, tmport); + *val &= 0xdfff; /* assert DB5 */ + outw(*val, tmport); FUN_D5: - for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */ - { - if ((inw(tmport) & 0x2000) != 0) /* DB5 all release? */ - { - goto FUN_D5; - } - } - *val |= 0x8000; /* no DB4-0, assert DB7 */ - *val &= 0xe0ff; - outw(*val,tmport); - *val &= 0xbfff; /* release DB6 */ - outw(*val,tmport); -FUN_D6: - for ( i=0; i < 10; i++ ) /* stable >= bus settle delay(400 ns) */ - { - if ((inw(tmport) & 0x4000) != 0) /* DB6 all release? */ - { - goto FUN_D6; - } - } + for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ + if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */ + goto FUN_D5; + } + } + *val |= 0x8000; /* no DB4-0, assert DB7 */ + *val &= 0xe0ff; + outw(*val, tmport); + *val &= 0xbfff; /* release DB6 */ + outw(*val, tmport); + FUN_D6: + for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ + if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */ + goto FUN_D6; + } + } - return j; + return j; } -void tscam( unsigned char host ) +void tscam(unsigned char host) { - unsigned int tmport ; - unsigned char i,j,k; - unsigned long n; - unsigned short int m,assignid_map,val; - unsigned char mbuf[33],quintet[2]; - static unsigned char g2q_tab[8]={ 0x38,0x31,0x32,0x2b,0x34,0x2d,0x2e,0x27 }; + unsigned int tmport; + unsigned char i, j, k; + unsigned long n; + unsigned short int m, assignid_map, val; + unsigned char mbuf[33], quintet[2]; + static unsigned char g2q_tab[8] = + {0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27}; - for ( i=0; i < 0x10; i++ ) - { - mydlyu(0xffff); - } + for (i = 0; i < 0x10; i++) { + mydlyu(0xffff); + } - tmport = ioportu[host]+1; - outb(0x08,tmport++); - outb(0x7f,tmport); - tmport = ioportu[host]+0x11; - outb(0x20,tmport); - - if ((scam_on[host] & 0x40) == 0) - { - return; - } - - m=1; - m <<= host_idu[host]; - j=16; - if ( chip_veru[host] < 4 ) - { - m |= 0xff00; - j=8; - } - assignid_map=m; - tmport = ioportu[host]+0x02; - outb(0x02,tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */ - outb(0,tmport++); - outb(0,tmport++); - outb(0,tmport++); - outb(0,tmport++); - outb(0,tmport++); - outb(0,tmport++); - - for ( i = 0 ; i < j ; i ++ ) - { - m=1; - m=m< 7 ) - { - k=(i & 0x07) | 0x40; - } - else - { - k=i; - } - outb(k,tmport++); - tmport = ioportu[host]+0x1b; - if ( chip_veru[host] == 4 ) - { - outb((unsigned char)((inb(tmport) & 0x0e) | 0x01),tmport); - } - else - { - outb((unsigned char)(inb(tmport) & 0x0e),tmport); - } + assignid_map = m; + tmport = ioportu[host] + 0x02; + outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */ + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + + for (i = 0; i < j; i++) { + m = 1; + m = m << i; + if ((m & assignid_map) != 0) { + continue; + } + tmport = ioportu[host] + 0x0f; + outb(0, tmport++); + tmport += 0x02; + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + if (i > 7) { + k = (i & 0x07) | 0x40; + } else { + k = i; + } + outb(k, tmport++); + tmport = ioportu[host] + 0x1b; + if (chip_veru[host] == 4) { + outb((unsigned char) ((inb(tmport) & 0x0e) | 0x01), tmport); + } else { + outb((unsigned char) (inb(tmport) & 0x0e), tmport); + } wait_rdyok: - tmport = ioportu[host]+0x18; - outb(0x09,tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00); - tmport -= 0x08; - k=inb(tmport); - if ( k != 0x16 ) - { - if ((k == 0x85) || (k == 0x42)) - { - continue; - } - tmport = ioportu[host]+0x10; - outb(0x41,tmport); - goto wait_rdyok; - } - assignid_map |= m; - - } - tmport = ioportu[host]+0x02; - outb(0x7f,tmport); - tmport = ioportu[host]+0x1b; - outb(0x02,tmport); - - outb(0,0x80); - - val=0x0080; /* bsy */ - tmport = ioportu[host]+0x1c; - outw(val,tmport); - val |=0x0040; /* sel */ - outw(val,tmport); - val |=0x0004; /* msg */ - outw(val,tmport); - inb(0x80); /* 2 deskew delay(45ns*2=90ns) */ - val &=0x007f; /* no bsy */ - outw(val,tmport); - mydlyu(0xffff); /* recommanded SCAM selection response time */ - mydlyu(0xffff); - val &=0x00fb; /* after 1ms no msg */ - outw(val,tmport); + tmport = ioportu[host] + 0x18; + outb(0x09, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + k = inb(tmport); + if (k != 0x16) { + if ((k == 0x85) || (k == 0x42)) { + continue; + } + tmport = ioportu[host] + 0x10; + outb(0x41, tmport); + goto wait_rdyok; + } + assignid_map |= m; + + } + tmport = ioportu[host] + 0x02; + outb(0x7f, tmport); + tmport = ioportu[host] + 0x1b; + outb(0x02, tmport); + + outb(0, 0x80); + + val = 0x0080; /* bsy */ + tmport = ioportu[host] + 0x1c; + outw(val, tmport); + val |= 0x0040; /* sel */ + outw(val, tmport); + val |= 0x0004; /* msg */ + outw(val, tmport); + inb(0x80); /* 2 deskew delay(45ns*2=90ns) */ + val &= 0x007f; /* no bsy */ + outw(val, tmport); + mydlyu(0xffff); /* recommanded SCAM selection response time */ + mydlyu(0xffff); + val &= 0x00fb; /* after 1ms no msg */ + outw(val, tmport); wait_nomsg: - if ((inb(tmport) & 0x04) != 0) - { - goto wait_nomsg; - } - outb(1,0x80); - mydlyu(100); - for ( n=0; n < 0x30000; n++ ) - { - if ((inb(tmport) & 0x80) != 0) /* bsy ? */ - { - goto wait_io; + if ((inb(tmport) & 0x04) != 0) { + goto wait_nomsg; + } + outb(1, 0x80); + mydlyu(100); + for (n = 0; n < 0x30000; n++) { + if ((inb(tmport) & 0x80) != 0) { /* bsy ? */ + goto wait_io; + } } - } - goto TCM_SYNC; + goto TCM_SYNC; wait_io: - for ( n=0; n < 0x30000; n++ ) - { - if ((inb(tmport) & 0x81) == 0x0081) - { - goto wait_io1; + for (n = 0; n < 0x30000; n++) { + if ((inb(tmport) & 0x81) == 0x0081) { + goto wait_io1; + } } - } - goto TCM_SYNC; + goto TCM_SYNC; wait_io1: - inb(0x80); - val |=0x8003; /* io,cd,db7 */ - outw(val,tmport); - inb(0x80); - val &=0x00bf; /* no sel */ - outw(val,tmport); - outb(2,0x80); + inb(0x80); + val |= 0x8003; /* io,cd,db7 */ + outw(val, tmport); + inb(0x80); + val &= 0x00bf; /* no sel */ + outw(val, tmport); + outb(2, 0x80); TCM_SYNC: - mydlyu(0x800); - if ((inb(tmport) & 0x80) == 0x00) /* bsy ? */ - { - outw(0,tmport--); - outb(0,tmport); - tmport=ioportu[host] + 0x15; - outb(0,tmport); - tmport += 0x03; - outb(0x09,tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0); - tmport -= 0x08; - inb(tmport); - return; - } - - val &= 0x00ff; /* synchronization */ - val |= 0x3f00; - fun_scam(host,&val); - outb(3,0x80); - val &= 0x00ff; /* isolation */ - val |= 0x2000; - fun_scam(host,&val); - outb(4,0x80); - i=8; - j=0; + mydlyu(0x800); + if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */ + outw(0, tmport--); + outb(0, tmport); + tmport = ioportu[host] + 0x15; + outb(0, tmport); + tmport += 0x03; + outb(0x09, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + return; + } + val &= 0x00ff; /* synchronization */ + val |= 0x3f00; + fun_scam(host, &val); + outb(3, 0x80); + val &= 0x00ff; /* isolation */ + val |= 0x2000; + fun_scam(host, &val); + outb(4, 0x80); + i = 8; + j = 0; TCM_ID: - if ((inw(tmport) & 0x2000) == 0) - { - goto TCM_ID; - } - outb(5,0x80); - val &= 0x00ff; /* get ID_STRING */ - val |= 0x2000; - k=fun_scam(host,&val); - if ((k & 0x03) == 0) - { - goto TCM_5; - } - mbuf[j] <<= 0x01; - mbuf[j] &= 0xfe; - if ((k & 0x02) != 0) - { - mbuf[j] |= 0x01; - } - i--; - if ( i > 0 ) - { - goto TCM_ID; - } - j++; - i=8; - goto TCM_ID; + if ((inw(tmport) & 0x2000) == 0) { + goto TCM_ID; + } + outb(5, 0x80); + val &= 0x00ff; /* get ID_STRING */ + val |= 0x2000; + k = fun_scam(host, &val); + if ((k & 0x03) == 0) { + goto TCM_5; + } + mbuf[j] <<= 0x01; + mbuf[j] &= 0xfe; + if ((k & 0x02) != 0) { + mbuf[j] |= 0x01; + } + i--; + if (i > 0) { + goto TCM_ID; + } + j++; + i = 8; + goto TCM_ID; -TCM_5: /* isolation complete.. */ +TCM_5: /* isolation complete.. */ /* mbuf[32]=0; - printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */ - i=15; - j=mbuf[0]; - if ((j & 0x20) != 0) /* bit5=1:ID upto 7 */ - { - i=7; - } - if ((j & 0x06) == 0) /* IDvalid? */ - { - goto G2Q5; - } - k=mbuf[1]; + printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */ + i = 15; + j = mbuf[0]; + if ((j & 0x20) != 0) { /* bit5=1:ID upto 7 */ + i = 7; + } + if ((j & 0x06) == 0) { /* IDvalid? */ + goto G2Q5; + } + k = mbuf[1]; small_id: - m=1; - m <<= k; - if ((m & assignid_map) == 0) - { - goto G2Q_QUIN; - } - if ( k > 0 ) - { - k--; - goto small_id; - } -G2Q5: /* srch from max acceptable ID# */ - k=i; /* max acceptable ID# */ + m = 1; + m <<= k; + if ((m & assignid_map) == 0) { + goto G2Q_QUIN; + } + if (k > 0) { + k--; + goto small_id; + } +G2Q5: /* srch from max acceptable ID# */ + k = i; /* max acceptable ID# */ G2Q_LP: - m=1; - m <<= k; - if ((m & assignid_map) == 0) - { - goto G2Q_QUIN; - } - if ( k > 0 ) - { - k--; - goto G2Q_LP; - } -G2Q_QUIN: /* k=binID#, */ - assignid_map |= m; - if ( k < 8 ) - { - quintet[0]=0x38; /* 1st dft ID<8 */ - } - else - { - quintet[0]=0x31; /* 1st ID>=8 */ - } - k &= 0x07; - quintet[1]=g2q_tab[k]; - - val &= 0x00ff; /* AssignID 1stQuintet,AH=001xxxxx */ - m=quintet[0] << 8; - val |= m; - fun_scam(host,&val); - val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */ - m=quintet[1] << 8; - val |= m; - fun_scam(host,&val); + m = 1; + m <<= k; + if ((m & assignid_map) == 0) { + goto G2Q_QUIN; + } + if (k > 0) { + k--; + goto G2Q_LP; + } +G2Q_QUIN: /* k=binID#, */ + assignid_map |= m; + if (k < 8) { + quintet[0] = 0x38; /* 1st dft ID<8 */ + } else { + quintet[0] = 0x31; /* 1st ID>=8 */ + } + k &= 0x07; + quintet[1] = g2q_tab[k]; - goto TCM_SYNC; + val &= 0x00ff; /* AssignID 1stQuintet,AH=001xxxxx */ + m = quintet[0] << 8; + val |= m; + fun_scam(host, &val); + val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */ + m = quintet[1] << 8; + val |= m; + fun_scam(host, &val); + + goto TCM_SYNC; } -void is870(unsigned long host,unsigned int wkport ) +void is870(unsigned long host, unsigned int wkport) { - unsigned int tmport ; - unsigned char i,j,k,rmb; - unsigned short int m; - static unsigned char mbuf[512]; - static unsigned char satn[9] = { 0,0,0,0,0,0,0,6,6 }; - static unsigned char inqd[9] = { 0x12,0,0,0,0x24,0,0,0x24,6 }; - static unsigned char synn[6] = { 0x80,1,3,1,0x19,0x0e }; - static unsigned char synu[6] = { 0x80,1,3,1,0x0c,0x0e }; - static unsigned char synw[6] = { 0x80,1,3,1,0x0c,0x07 }; - static unsigned char wide[6] = { 0x80,1,2,3,1,0 }; - - sync_idu=0; - tmport=wkport+0x3a; - outb((unsigned char)(inb(tmport) | 0x10),tmport); - - for ( i = 0 ; i < 16 ; i ++ ) - { - if ((chip_veru[host] != 4) && (i > 7)) - { - break; - } - m=1; - m=m< 7)) { + break; + } + m = 1; + m = m << i; + if ((m & active_idu[host]) != 0) { + continue; + } + if (i == host_idu[host]) { + printk(" ID: %2d Host Adapter\n", host_idu[host]); + continue; + } + if (chip_veru[host] == 4) { + tmport = wkport + 0x1b; + j = (inb(tmport) & 0x0e) | 0x01; + outb(j, tmport); + } + tmport = wkport + 1; + outb(0x08, tmport++); + outb(0x7f, tmport++); + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(devspu[host][i], tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + j = i; + if ((j & 0x08) != 0) { + j = (j & 0x07) | 0x40; + } + outb(j, tmport); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); + active_idu[host] |= m; + + tmport = wkport + 0x10; + outb(0x30, tmport); + tmport = wkport + 0x04; + outb(0x00, tmport); phase_cmd: - tmport=wkport+0x18; - outb(0x08,tmport); - tmport+=0x07; - while ((inb(tmport) & 0x80) == 0x00); - tmport-=0x08; - j=inb(tmport); - if ( j != 0x16 ) - { - tmport=wkport+0x10; - outb(0x41,tmport); - goto phase_cmd; - } + tmport = wkport + 0x18; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + tmport = wkport + 0x10; + outb(0x41, tmport); + goto phase_cmd; + } sel_ok: - tmport=wkport+3; - outb(inqd[0],tmport++); - outb(inqd[1],tmport++); - outb(inqd[2],tmport++); - outb(inqd[3],tmport++); - outb(inqd[4],tmport++); - outb(inqd[5],tmport); - tmport+=0x07; - outb(0,tmport); - tmport+=0x02; - outb(devspu[host][i],tmport++); - outb(0,tmport++); - outb(inqd[6],tmport++); - outb(inqd[7],tmport++); - tmport+=0x03; - outb(inqd[8],tmport); - tmport+=0x07; - while ((inb(tmport) & 0x80) == 0x00); - tmport-=0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) - { - continue; - } - while ( inb(tmport) != 0x8e ); - if ( chip_veru[host] == 4 ) - { - tmport=wkport+0x1b; - j=inb(tmport) & 0x0e; - outb(j,tmport); - } - tmport=wkport+0x18; - outb(0x08,tmport); - tmport += 0x07; - j=0; + tmport = wkport + 3; + outb(inqd[0], tmport++); + outb(inqd[1], tmport++); + outb(inqd[2], tmport++); + outb(inqd[3], tmport++); + outb(inqd[4], tmport++); + outb(inqd[5], tmport); + tmport += 0x07; + outb(0, tmport); + tmport += 0x02; + outb(devspu[host][i], tmport++); + outb(0, tmport++); + outb(inqd[6], tmport++); + outb(inqd[7], tmport++); + tmport += 0x03; + outb(inqd[8], tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); + if (chip_veru[host] == 4) { + tmport = wkport + 0x1b; + j = inb(tmport) & 0x0e; + outb(j, tmport); + } + tmport = wkport + 0x18; + outb(0x08, tmport); + tmport += 0x07; + j = 0; rd_inq_data: - k=inb(tmport); - if ((k & 0x01) != 0 ) - { - tmport-=0x06; - mbuf[j++]=inb(tmport); - tmport+=0x06; - goto rd_inq_data; - } - if ((k & 0x80) == 0 ) - { - goto rd_inq_data; - } - tmport-=0x08; - j=inb(tmport); - if ( j == 0x16 ) - { - goto inq_ok; - } - tmport=wkport+0x10; - outb(0x46,tmport); - tmport+=0x02; - outb(0,tmport++); - outb(0,tmport++); - outb(0,tmport++); - tmport+=0x03; - outb(0x08,tmport); - tmport+=0x07; - while ((inb(tmport) & 0x80) == 0x00); - tmport-=0x08; - if (inb(tmport) != 0x16) - { - goto sel_ok; - } + k = inb(tmport); + if ((k & 0x01) != 0) { + tmport -= 0x06; + mbuf[j++] = inb(tmport); + tmport += 0x06; + goto rd_inq_data; + } + if ((k & 0x80) == 0) { + goto rd_inq_data; + } + tmport -= 0x08; + j = inb(tmport); + if (j == 0x16) { + goto inq_ok; + } + tmport = wkport + 0x10; + outb(0x46, tmport); + tmport += 0x02; + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + tmport += 0x03; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if (inb(tmport) != 0x16) { + goto sel_ok; + } inq_ok: - mbuf[36]=0; - printk(" ID: %2d %s\n",i,&mbuf[8]); - devtypeu[host][i]=mbuf[0]; - rmb=mbuf[1]; - if ( chip_veru[host] != 4 ) - { - goto not_wide; - } - if ((mbuf[7] & 0x60) == 0) - { - goto not_wide; - } - if ((global_map[host] & 0x20) == 0) - { - goto not_wide; - } - tmport=wkport+0x1b; - j=(inb(tmport) & 0x0e) | 0x01; - outb(j,tmport); - tmport=wkport+3; - outb(satn[0],tmport++); - outb(satn[1],tmport++); - outb(satn[2],tmport++); - outb(satn[3],tmport++); - outb(satn[4],tmport++); - outb(satn[5],tmport++); - tmport+=0x06; - outb(0,tmport); - tmport+=0x02; - outb(devspu[host][i],tmport++); - outb(0,tmport++); - outb(satn[6],tmport++); - outb(satn[7],tmport++); - tmport+=0x03; - outb(satn[8],tmport); - tmport+=0x07; - - while ((inb(tmport) & 0x80) == 0x00); - tmport-=0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) - { - continue; - } - while ( inb(tmport) != 0x8e ); + mbuf[36] = 0; + printk(" ID: %2d %s\n", i, &mbuf[8]); + devtypeu[host][i] = mbuf[0]; + rmb = mbuf[1]; + if (chip_veru[host] != 4) { + goto not_wide; + } + if ((mbuf[7] & 0x60) == 0) { + goto not_wide; + } + if ((global_map[host] & 0x20) == 0) { + goto not_wide; + } + tmport = wkport + 0x1b; + j = (inb(tmport) & 0x0e) | 0x01; + outb(j, tmport); + tmport = wkport + 3; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(devspu[host][i], tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); try_wide: - j=0; - tmport=wkport+0x14; - outb(0x05,tmport); - tmport += 0x04; - outb(0x20,tmport); - tmport+=0x07; - - while ((inb(tmport) & 0x80) == 0 ) - { - if ((inb(tmport) & 0x01) != 0 ) - { - tmport-=0x06; - outb(wide[j++],tmport); - tmport+=0x06; - } - } - tmport-=0x08; - while ((inb(tmport) & 0x80) == 0x00); - j=inb(tmport) & 0x0f; - if ( j == 0x0f ) - { - goto widep_in; - } - if ( j == 0x0a ) - { - goto widep_cmd; - } - if ( j == 0x0e ) - { - goto try_wide; - } - continue; + j = 0; + tmport = wkport + 0x14; + outb(0x05, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(wide[j++], tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto try_wide; + } + continue; widep_out: - tmport=wkport+0x18; - outb(0x20,tmport); - tmport+=0x07; - while ((inb(tmport) & 0x80) == 0 ) - { - if ((inb(tmport) & 0x01) != 0 ) - { - tmport-=0x06; - outb(0,tmport); - tmport+=0x06; - } - } - tmport-=0x08; - j=inb(tmport) & 0x0f; - if ( j == 0x0f ) - { - goto widep_in; - } - if ( j == 0x0a ) - { - goto widep_cmd; - } - if ( j == 0x0e ) - { - goto widep_out; - } - continue; + tmport = wkport + 0x18; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(0, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto widep_out; + } + continue; widep_in: - tmport=wkport+0x14; - outb(0xff,tmport); - tmport += 0x04; - outb(0x20,tmport); - tmport+=0x07; - k=0; + tmport = wkport + 0x14; + outb(0xff, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; widep_in1: - j=inb(tmport); - if ((j & 0x01) != 0) - { - tmport-=0x06; - mbuf[k++]=inb(tmport); - tmport+=0x06; - goto widep_in1; - } - if ((j & 0x80) == 0x00) - { - goto widep_in1; - } - tmport-=0x08; - j=inb(tmport) & 0x0f; - if ( j == 0x0f ) - { - goto widep_in; - } - if ( j == 0x0a ) - { - goto widep_cmd; - } - if ( j == 0x0e ) - { - goto widep_out; - } - continue; + j = inb(tmport); + if ((j & 0x01) != 0) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto widep_in1; + } + if ((j & 0x80) == 0x00) { + goto widep_in1; + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto widep_out; + } + continue; widep_cmd: - tmport=wkport+0x10; - outb(0x30,tmport); - tmport=wkport+0x14; - outb(0x00,tmport); - tmport+=0x04; - outb(0x08,tmport); - tmport+=0x07; - while ((inb(tmport) & 0x80) == 0x00); - tmport-=0x08; - j=inb(tmport); - if ( j != 0x16 ) - { - if ( j == 0x4e ) - { - goto widep_out; - } - continue; - } - if ( mbuf[0] != 0x01 ) - { - goto not_wide; - } - if ( mbuf[1] != 0x02 ) - { - goto not_wide; - } - if ( mbuf[2] != 0x03 ) - { - goto not_wide; - } - if ( mbuf[3] != 0x01 ) - { - goto not_wide; - } - m=1; - m = m << i; - wide_idu[host] |= m; + tmport = wkport + 0x10; + outb(0x30, tmport); + tmport = wkport + 0x14; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + if (j == 0x4e) { + goto widep_out; + } + continue; + } + if (mbuf[0] != 0x01) { + goto not_wide; + } + if (mbuf[1] != 0x02) { + goto not_wide; + } + if (mbuf[2] != 0x03) { + goto not_wide; + } + if (mbuf[3] != 0x01) { + goto not_wide; + } + m = 1; + m = m << i; + wide_idu[host] |= m; not_wide: - if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07)) - { - goto set_sync; - } - continue; + if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07)) { + goto set_sync; + } + continue; set_sync: - tmport=wkport+0x1b; - j=inb(tmport) & 0x0e; - if ((m & wide_idu[host]) != 0 ) - { - j |= 0x01; - } - outb(j,tmport); - tmport=wkport+3; - outb(satn[0],tmport++); - outb(satn[1],tmport++); - outb(satn[2],tmport++); - outb(satn[3],tmport++); - outb(satn[4],tmport++); - outb(satn[5],tmport++); - tmport+=0x06; - outb(0,tmport); - tmport+=0x02; - outb(devspu[host][i],tmport++); - outb(0,tmport++); - outb(satn[6],tmport++); - outb(satn[7],tmport++); - tmport+=0x03; - outb(satn[8],tmport); - tmport+=0x07; - - while ((inb(tmport) & 0x80) == 0x00); - tmport-=0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) - { - continue; - } - while ( inb(tmport) != 0x8e); + tmport = wkport + 0x1b; + j = inb(tmport) & 0x0e; + if ((m & wide_idu[host]) != 0) { + j |= 0x01; + } + outb(j, tmport); + tmport = wkport + 3; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(devspu[host][i], tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); try_sync: - j=0; - tmport=wkport+0x14; - outb(0x06,tmport); - tmport += 0x04; - outb(0x20,tmport); - tmport+=0x07; - - while ((inb(tmport) & 0x80) == 0 ) - { - if ((inb(tmport) & 0x01) != 0 ) - { - tmport-=0x06; - if ( rmb != 0 ) - { - outb(synn[j++],tmport); - } - else - { - if ((m & wide_idu[host]) != 0) - { - outb(synw[j++],tmport); - } - else - { - if ((m & ultra_map[host]) != 0) - { - outb(synu[j++],tmport); + j = 0; + tmport = wkport + 0x14; + outb(0x06, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + if (rmb != 0) { + outb(synn[j++], tmport); + } else { + if ((m & wide_idu[host]) != 0) { + outb(synw[j++], tmport); + } else { + if ((m & ultra_map[host]) != 0) { + outb(synu[j++], tmport); + } else { + outb(synn[j++], tmport); + } + } + } + tmport += 0x06; + } } - else - { - outb(synn[j++],tmport); + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto phase_ins; } - } - } - tmport+=0x06; - } - } - tmport-=0x08; - while ((inb(tmport) & 0x80) == 0x00); - j=inb(tmport) & 0x0f; - if ( j == 0x0f ) - { - goto phase_ins; - } - if ( j == 0x0a ) - { - goto phase_cmds; - } - if ( j == 0x0e ) - { - goto try_sync; - } - continue; + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto try_sync; + } + continue; phase_outs: - tmport=wkport+0x18; - outb(0x20,tmport); - tmport+=0x07; - while ((inb(tmport) & 0x80) == 0x00) - { - if ((inb(tmport) & 0x01) != 0x00) - { - tmport-=0x06; - outb(0x00,tmport); - tmport+=0x06; - } - } - tmport-=0x08; - j=inb(tmport); - if ( j == 0x85 ) - { - goto tar_dcons; - } - j &= 0x0f; - if ( j == 0x0f ) - { - goto phase_ins; - } - if ( j == 0x0a ) - { - goto phase_cmds; - } - if ( j == 0x0e ) - { - goto phase_outs; - } - continue; + tmport = wkport + 0x18; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00) { + if ((inb(tmport) & 0x01) != 0x00) { + tmport -= 0x06; + outb(0x00, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport); + if (j == 0x85) { + goto tar_dcons; + } + j &= 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto phase_outs; + } + continue; phase_ins: - tmport=wkport+0x14; - outb(0xff,tmport); - tmport += 0x04; - outb(0x20,tmport); - tmport+=0x07; - k=0; + tmport = wkport + 0x14; + outb(0xff, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; phase_ins1: - j=inb(tmport); - if ((j & 0x01) != 0x00) - { - tmport-=0x06; - mbuf[k++]=inb(tmport); - tmport+=0x06; - goto phase_ins1; - } - if ((j & 0x80) == 0x00) - { - goto phase_ins1; - } - tmport-=0x08; - while ((inb(tmport) & 0x80) == 0x00); - j=inb(tmport); - if ( j == 0x85 ) - { - goto tar_dcons; - } - j &= 0x0f; - if ( j == 0x0f ) - { - goto phase_ins; - } - if ( j == 0x0a ) - { - goto phase_cmds; - } - if ( j == 0x0e ) - { - goto phase_outs; - } - continue; + j = inb(tmport); + if ((j & 0x01) != 0x00) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto phase_ins1; + } + if ((j & 0x80) == 0x00) { + goto phase_ins1; + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport); + if (j == 0x85) { + goto tar_dcons; + } + j &= 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto phase_outs; + } + continue; phase_cmds: - tmport=wkport+0x10; - outb(0x30,tmport); + tmport = wkport + 0x10; + outb(0x30, tmport); tar_dcons: - tmport=wkport+0x14; - outb(0x00,tmport); - tmport+=0x04; - outb(0x08,tmport); - tmport+=0x07; - while ((inb(tmport) & 0x80) == 0x00); - tmport-=0x08; - j=inb(tmport); - if ( j != 0x16 ) - { - continue; - } - if ( mbuf[0] != 0x01 ) - { - continue; - } - if ( mbuf[1] != 0x03 ) - { - continue; - } - if ( mbuf[4] == 0x00 ) - { - continue; - } - if ( mbuf[3] > 0x64 ) - { - continue; - } - if ( mbuf[4] > 0x0c ) - { - mbuf[4]=0x0c; - } - devspu[host][i] = mbuf[4]; - if ((mbuf[3] < 0x0d) && (rmb == 0)) - { - j=0xa0; - goto set_syn_ok; - } - if ( mbuf[3] < 0x1a ) - { - j=0x20; - goto set_syn_ok; - } - if ( mbuf[3] < 0x33 ) - { - j=0x40; - goto set_syn_ok; - } - if ( mbuf[3] < 0x4c ) - { - j=0x50; - goto set_syn_ok; - } - j=0x60; -set_syn_ok: - devspu[host][i] = (devspu[host][i] & 0x0f) | j; - } - tmport=wkport+0x3a; - outb((unsigned char)(inb(tmport) & 0xef),tmport); + tmport = wkport + 0x14; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + continue; + } + if (mbuf[0] != 0x01) { + continue; + } + if (mbuf[1] != 0x03) { + continue; + } + if (mbuf[4] == 0x00) { + continue; + } + if (mbuf[3] > 0x64) { + continue; + } + if (mbuf[4] > 0x0c) { + mbuf[4] = 0x0c; + } + devspu[host][i] = mbuf[4]; + if ((mbuf[3] < 0x0d) && (rmb == 0)) { + j = 0xa0; + goto set_syn_ok; + } + if (mbuf[3] < 0x1a) { + j = 0x20; + goto set_syn_ok; + } + if (mbuf[3] < 0x33) { + j = 0x40; + goto set_syn_ok; + } + if (mbuf[3] < 0x4c) { + j = 0x50; + goto set_syn_ok; + } + j = 0x60; + set_syn_ok: + devspu[host][i] = (devspu[host][i] & 0x0f) | j; + } + tmport = wkport + 0x3a; + outb((unsigned char) (inb(tmport) & 0xef), tmport); } /* return non-zero on detection */ int atp870u_detect(Scsi_Host_Template * tpnt) { - unsigned char irq,h,k; - unsigned long flags; - unsigned int base_io,error,tmport; - unsigned short index = 0; - unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3],host_id; - struct Scsi_Host * shpnt = NULL; - int count = 0; - static unsigned short devid[7]={0x8002,0x8010,0x8020,0x8030,0x8040,0x8050,0}; - static struct pci_dev *pdev = NULL, *acard_pdev[3]; - - printk("aec671x_detect: \n"); - if (!pci_present()) - { - printk(" NO BIOS32 SUPPORT.\n"); - return count; - } - - tpnt->proc_dir = &proc_scsi_atp870u; - - for ( h = 0 ; h < 2 ; h++ ) - { - active_idu[h]=0; - wide_idu[h]=0; - host_idu[h]=0x07; - quhdu[h]=0; - quendu[h]=0; - pci_bus[h]=0; - pci_device_fn[h]=0xff; - chip_ver[h]=0; - last_cmd[h]=0xff; - in_snd[h]=0; - in_int[h]=0; - for ( k = 0 ; k < qcnt ; k++ ) - { - querequ[h][k]=0; - } - for ( k = 0 ; k < 16 ; k++ ) - { - curr_req[h][k]=0; - } - } - h=0; - while ( devid[h] != 0 ) - { - pdev = pci_find_device(0x1191,devid[h],pdev); - if (pdev == NULL) { - h++; - index=0; - continue; - } - chip_ver[2]=0; - - /* To avoid messing with the things below... */ - acard_pdev[2] = pdev; - pci_device_fn[2] = pdev->devfn; - pci_bus[2] = pdev->bus->number; - - if ( devid[h] == 0x8002 ) - { - error = pci_read_config_byte(pdev,0x08,&chip_ver[2]); - if ( chip_ver[2] < 2 ) - { - goto nxt_devfn; - } - } - if ( devid[h] == 0x8010 ) - { - chip_ver[2]=0x04; - } - if ( pci_device_fn[2] < pci_device_fn[0] ) - { - acard_pdev[1]=acard_pdev[0]; - pci_bus[1]=pci_bus[0]; - pci_device_fn[1]=pci_device_fn[0]; - chip_ver[1]=chip_ver[0]; - acard_pdev[0]=acard_pdev[2]; - pci_bus[0]=pci_bus[2]; - pci_device_fn[0]=pci_device_fn[2]; - chip_ver[0]=chip_ver[2]; - } - else if ( pci_device_fn[2] < pci_device_fn[1] ) - { - acard_pdev[1]=acard_pdev[2]; - pci_bus[1]=pci_bus[2]; - pci_device_fn[1]=pci_device_fn[2]; - chip_ver[1]=chip_ver[2]; - } -nxt_devfn: - index++; - if ( index > 3 ) - { - index=0; - h++; - } - } - for ( h=0; h < 2; h++ ) - { - if ( pci_device_fn[h] == 0xff ) - { - return count; - } - - pdev = acard_pdev[h]; - pdev->devfn = pci_device_fn[h]; - pdev->bus->number = pci_bus[h]; - - /* Found an atp870u/w. */ - error = pci_read_config_dword(pdev,0x10,&base_io); - error += pci_read_config_byte(pdev,0x3c,&irq); - error += pci_read_config_byte(pdev,0x49,&host_id); - - base_io &= 0xfffffff8; - printk(" ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n" - ,h,base_io,irq); - ioportu[h]=base_io; - pciportu[h]=base_io + 0x20; - irqnumu[h]=irq; - host_id &= 0x07; - host_idu[h]=host_id; - chip_veru[h]=chip_ver[h]; - - tmport=base_io+0x22; - scam_on[h]=inb(tmport); - tmport += 0x0b; - global_map[h]=inb(tmport++); - ultra_map[h]=inw(tmport); - if ( ultra_map[h] == 0 ) - { - scam_on[h]=0x00; - global_map[h]=0x20; - ultra_map[h]=0xffff; - } - - shpnt = scsi_register(tpnt,4); - - save_flags(flags); - cli(); - if (request_irq(irq,atp870u_intr_handle, 0, "atp870u", NULL)) - { - printk("Unable to allocate IRQ for Acard controller.\n"); - goto unregister; - } - - tmport=base_io+0x3a; - k=(inb(tmport) & 0xf3) | 0x10; - outb(k,tmport); - outb((k & 0xdf),tmport); - mydlyu(0x8000); - outb(k,tmport); - mydlyu(0x8000); - tmport=base_io; - outb((host_id | 0x08),tmport); - tmport += 0x18; - outb(0,tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0); - tmport -= 0x08; - inb(tmport); - tmport = base_io +1; - outb(8,tmport++); - outb(0x7f,tmport); - tmport = base_io + 0x11; - outb(0x20,tmport); - - tscam(h); - is870(h,base_io); - tmport=base_io+0x3a; - outb((inb(tmport) & 0xef),tmport); - - atp_host[h] = shpnt; - if ( chip_ver[h] == 4 ) - { - shpnt->max_id = 16; - } - shpnt->this_id = host_id; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ - shpnt->irq = irq; - restore_flags(flags); - request_region(base_io, 0x40,"atp870u"); /* Register the IO ports that we use */ - count++; - index++; - continue; + unsigned char irq, h, k; + unsigned long flags; + unsigned int base_io, error, tmport; + unsigned short index = 0; + unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3], host_id; + struct Scsi_Host *shpnt = NULL; + int count = 0; + static unsigned short devid[7] = + {0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0}; + static struct pci_dev *pdev = NULL, *acard_pdev[3]; + + printk("aec671x_detect: \n"); + if (!pci_present()) { + printk(" NO BIOS32 SUPPORT.\n"); + return count; + } + tpnt->proc_dir = &proc_scsi_atp870u; + + for (h = 0; h < 2; h++) { + active_idu[h] = 0; + wide_idu[h] = 0; + host_idu[h] = 0x07; + quhdu[h] = 0; + quendu[h] = 0; + pci_bus[h] = 0; + pci_device_fn[h] = 0xff; + chip_ver[h] = 0; + last_cmd[h] = 0xff; + in_snd[h] = 0; + in_int[h] = 0; + for (k = 0; k < qcnt; k++) { + querequ[h][k] = 0; + } + for (k = 0; k < 16; k++) { + curr_req[h][k] = 0; + } + } + h = 0; + while (devid[h] != 0) { + pdev = pci_find_device(0x1191, devid[h], pdev); + if (pdev == NULL) { + h++; + index = 0; + continue; + } + chip_ver[2] = 0; + + /* To avoid messing with the things below... */ + acard_pdev[2] = pdev; + pci_device_fn[2] = pdev->devfn; + pci_bus[2] = pdev->bus->number; + + if (devid[h] == 0x8002) { + error = pci_read_config_byte(pdev, 0x08, &chip_ver[2]); + if (chip_ver[2] < 2) { + goto nxt_devfn; + } + } + if (devid[h] == 0x8010) { + chip_ver[2] = 0x04; + } + if (pci_device_fn[2] < pci_device_fn[0]) { + acard_pdev[1] = acard_pdev[0]; + pci_bus[1] = pci_bus[0]; + pci_device_fn[1] = pci_device_fn[0]; + chip_ver[1] = chip_ver[0]; + acard_pdev[0] = acard_pdev[2]; + pci_bus[0] = pci_bus[2]; + pci_device_fn[0] = pci_device_fn[2]; + chip_ver[0] = chip_ver[2]; + } else if (pci_device_fn[2] < pci_device_fn[1]) { + acard_pdev[1] = acard_pdev[2]; + pci_bus[1] = pci_bus[2]; + pci_device_fn[1] = pci_device_fn[2]; + chip_ver[1] = chip_ver[2]; + } + nxt_devfn: + index++; + if (index > 3) { + index = 0; + h++; + } + } + for (h = 0; h < 2; h++) { + if (pci_device_fn[h] == 0xff) { + return count; + } + pdev = acard_pdev[h]; + pdev->devfn = pci_device_fn[h]; + pdev->bus->number = pci_bus[h]; + + /* Found an atp870u/w. */ + error = pci_read_config_dword(pdev, 0x10, &base_io); + error += pci_read_config_byte(pdev, 0x3c, &irq); + error += pci_read_config_byte(pdev, 0x49, &host_id); + + base_io &= 0xfffffff8; + printk(" ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n" + ,h, base_io, irq); + ioportu[h] = base_io; + pciportu[h] = base_io + 0x20; + irqnumu[h] = irq; + host_id &= 0x07; + host_idu[h] = host_id; + chip_veru[h] = chip_ver[h]; + + tmport = base_io + 0x22; + scam_on[h] = inb(tmport); + tmport += 0x0b; + global_map[h] = inb(tmport++); + ultra_map[h] = inw(tmport); + if (ultra_map[h] == 0) { + scam_on[h] = 0x00; + global_map[h] = 0x20; + ultra_map[h] = 0xffff; + } + shpnt = scsi_register(tpnt, 4); + + save_flags(flags); + cli(); + if (request_irq(irq, atp870u_intr_handle, 0, "atp870u", NULL)) { + printk("Unable to allocate IRQ for Acard controller.\n"); + goto unregister; + } + tmport = base_io + 0x3a; + k = (inb(tmport) & 0xf3) | 0x10; + outb(k, tmport); + outb((k & 0xdf), tmport); + mydlyu(0x8000); + outb(k, tmport); + mydlyu(0x8000); + tmport = base_io; + outb((host_id | 0x08), tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + tmport = base_io + 1; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0x11; + outb(0x20, tmport); + + tscam(h); + is870(h, base_io); + tmport = base_io + 0x3a; + outb((inb(tmport) & 0xef), tmport); + + atp_host[h] = shpnt; + if (chip_ver[h] == 4) { + shpnt->max_id = 16; + } + shpnt->this_id = host_id; + shpnt->unique_id = base_io; + shpnt->io_port = base_io; + shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ + shpnt->irq = irq; + restore_flags(flags); + request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */ + count++; + index++; + continue; unregister: - scsi_unregister(shpnt); - restore_flags(flags); - index++; - continue; - } + scsi_unregister(shpnt); + restore_flags(flags); + index++; + continue; + } - return count; + return count; } /* The abort command does not leave the device in a clean state where @@ -1883,162 +1621,147 @@ int atp870u_abort(Scsi_Cmnd * SCpnt) { - unsigned char h,j; - unsigned int tmport; + unsigned char h, j; + unsigned int tmport; /* printk(" atp870u_abort: \n"); */ - for ( h=0; h <= admaxu; h++ ) - { - if ( SCpnt->host == atp_host[h] ) - { - goto find_adp; + for (h = 0; h <= admaxu; h++) { + if (SCpnt->host == atp_host[h]) { + goto find_adp; + } } - } - panic("Abort host not found !"); + panic("Abort host not found !"); find_adp: - printk(" workingu=%x last_cmd=%x ",workingu[h],last_cmd[h]); - printk(" quhdu=%x quendu=%x ",quhdu[h],quendu[h]); - tmport=ioportu[h]; - for ( j=0; j < 0x17; j++) - { - printk(" r%2x=%2x",j,inb(tmport++)); - } - tmport += 0x05; - printk(" r1c=%2x",inb(tmport)); - tmport += 0x03; - printk(" r1f=%2x in_snd=%2x ",inb(tmport),in_snd[h]); - tmport++; - printk(" r20=%2x",inb(tmport)); - tmport += 0x02; - printk(" r22=%2x \n",inb(tmport)); - return (SCSI_ABORT_SNOOZE); + printk(" workingu=%x last_cmd=%x ", workingu[h], last_cmd[h]); + printk(" quhdu=%x quendu=%x ", quhdu[h], quendu[h]); + tmport = ioportu[h]; + for (j = 0; j < 0x17; j++) { + printk(" r%2x=%2x", j, inb(tmport++)); + } + tmport += 0x05; + printk(" r1c=%2x", inb(tmport)); + tmport += 0x03; + printk(" r1f=%2x in_snd=%2x ", inb(tmport), in_snd[h]); + tmport++; + printk(" r20=%2x", inb(tmport)); + tmport += 0x02; + printk(" r22=%2x \n", inb(tmport)); + return (SCSI_ABORT_SNOOZE); } int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) { - unsigned char h; - /* - * See if a bus reset was suggested. - */ -/* printk("atp870u_reset: \n"); */ - for( h=0; h <= admaxu; h++ ) - { - if ( SCpnt->host == atp_host[h] ) - { - goto find_host; - } - } - panic("Reset bus host not found !"); + unsigned char h; + /* + * See if a bus reset was suggested. + */ +/* printk("atp870u_reset: \n"); */ + for (h = 0; h <= admaxu; h++) { + if (SCpnt->host == atp_host[h]) { + goto find_host; + } + } + panic("Reset bus host not found !"); find_host: -/* SCpnt->result = 0x00080000; - SCpnt->scsi_done(SCpnt); - workingu[h]=0; - quhdu[h]=0; - quendu[h]=0; - return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); */ - return (SCSI_RESET_SNOOZE); +/* SCpnt->result = 0x00080000; + SCpnt->scsi_done(SCpnt); + workingu[h]=0; + quhdu[h]=0; + quendu[h]=0; + return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); */ + return (SCSI_RESET_SNOOZE); } -const char * -atp870u_info(struct Scsi_Host *notused) +const char *atp870u_info(struct Scsi_Host *notused) { - static char buffer[128]; + static char buffer[128]; - strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 "); + strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 "); - return buffer; + return buffer; } -int -atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) +int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) { - return (-ENOSYS); /* Currently this is a no-op */ + return (-ENOSYS); /* Currently this is a no-op */ } #define BLS buffer + len + size -int -atp870u_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +int atp870u_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout) { - struct Scsi_Host *HBAptr; - static u8 buff[512]; - int i; - int size = 0; - int len = 0; - off_t begin = 0; - off_t pos = 0; - - HBAptr = NULL; - for (i = 0; i < 2; i++) - { - if ((HBAptr = atp_host[i]) != NULL) - { - if (HBAptr->host_no == hostno) - { - break; - } - HBAptr = NULL; - } - } - - if (HBAptr == NULL) - { - size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno); - len += size; pos = begin + len; size = 0; - goto stop_output; - } - - if (inout == TRUE) /* Has data been written to the file? */ - { - return (atp870u_set_info(buffer, length, HBAptr)); - } - - if (offset == 0) - { - memset(buff, 0, sizeof(buff)); - } - - size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n"); - len += size; pos = begin + len; size = 0; - - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Adapter Configuration:\n"); - size += sprintf(BLS, " Base IO: %#.4lx\n", HBAptr->io_port); - size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - len += size; pos = begin + len; size = 0; - -stop_output: - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - { - len = length; /* Ending slop */ - } + struct Scsi_Host *HBAptr; + static u8 buff[512]; + int i; + int size = 0; + int len = 0; + off_t begin = 0; + off_t pos = 0; + + HBAptr = NULL; + for (i = 0; i < 2; i++) { + if ((HBAptr = atp_host[i]) != NULL) { + if (HBAptr->host_no == hostno) { + break; + } + HBAptr = NULL; + } + } - return (len); + if (HBAptr == NULL) { + size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno); + len += size; + pos = begin + len; + size = 0; + goto stop_output; + } + if (inout == TRUE) { /* Has data been written to the file? */ + return (atp870u_set_info(buffer, length, HBAptr)); + } + if (offset == 0) { + memset(buff, 0, sizeof(buff)); + } + size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n"); + len += size; + pos = begin + len; + size = 0; + + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Adapter Configuration:\n"); + size += sprintf(BLS, " Base IO: %#.4lx\n", HBAptr->io_port); + size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); + len += size; + pos = begin + len; + size = 0; + + stop_output: + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) { + len = length; /* Ending slop */ + } + return (len); } #include "sd.h" -int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip) +int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip) { - int heads, sectors, cylinders; + int heads, sectors, cylinders; - heads = 64; - sectors = 32; - cylinders = disk->capacity / (heads * sectors); - - if ( cylinders > 1024 ) - { - heads = 255; - sectors = 63; - cylinders = disk->capacity / (heads * sectors); - } - - ip[0] = heads; - ip[1] = sectors; - ip[2] = cylinders; + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + if (cylinders > 1024) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + ip[0] = heads; + ip[1] = sectors; + ip[2] = cylinders; - return 0; + return 0; } #ifdef MODULE @@ -2046,4 +1769,3 @@ #include "scsi_module.c" #endif - diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/atp870u.h linux/drivers/scsi/atp870u.h --- v2.3.22/linux/drivers/scsi/atp870u.h Sun Dec 27 22:19:20 1998 +++ linux/drivers/scsi/atp870u.h Mon Oct 18 11:35:54 1999 @@ -1,7 +1,7 @@ #ifndef _ATP870U_H /* $Id: atp870u.h,v 1.0 1997/05/07 15:09:00 root Exp root $ - * + * Header file for the ACARD 870U/W driver for Linux * * $Log: atp870u.h,v $ @@ -20,10 +20,10 @@ int atp870u_detect(Scsi_Host_Template *); int atp870u_command(Scsi_Cmnd *); -int atp870u_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int atp870u_abort(Scsi_Cmnd *); int atp870u_reset(Scsi_Cmnd *, unsigned int); -int atp870u_biosparam(Disk *, kdev_t, int*); +int atp870u_biosparam(Disk *, kdev_t, int *); void send_s870(unsigned char); #define qcnt 32 @@ -31,7 +31,7 @@ #define ATP870U_CMDLUN 1 #ifndef NULL - #define NULL 0 +#define NULL 0 #endif extern struct proc_dir_entry proc_scsi_atp870u; diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.3.22/linux/drivers/scsi/ide-scsi.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/scsi/ide-scsi.c Mon Oct 18 11:14:22 1999 @@ -299,11 +299,6 @@ scsi->pc = NULL; } -static inline unsigned long get_timeout(idescsi_pc_t *pc) -{ - return IDE_MAX(WAIT_CMD, pc->timeout - jiffies); -} - /* * Our interrupt handler. */ @@ -364,7 +359,8 @@ pc->actually_transferred += temp; pc->current_position += temp; idescsi_discard_data (drive,bcount - temp); - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); + drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); + ide_set_handler(drive, &idescsi_pc_intr); return; } #if IDESCSI_DEBUG_LOG @@ -388,7 +384,8 @@ pc->actually_transferred+=bcount; /* Update the current position */ pc->current_position+=bcount; - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* And set the interrupt handler again */ + drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); + ide_set_handler(drive, &idescsi_pc_intr); /* And set the interrupt handler again */ } static void idescsi_transfer_pc (ide_drive_t *drive) @@ -407,7 +404,8 @@ ide_do_reset (drive); return; } - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* Set the interrupt routine */ + drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); + ide_set_handler(drive, &idescsi_pc_intr); /* Set the interrupt routine */ atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */ } @@ -441,7 +439,8 @@ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { - ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc)); + drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); + ide_set_handler (drive, &idescsi_transfer_pc); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); @@ -488,7 +487,7 @@ /* * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function */ - ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL); diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h --- v2.3.22/linux/drivers/scsi/inia100.h Tue Sep 7 12:14:06 1999 +++ linux/drivers/scsi/inia100.h Fri Oct 22 12:48:21 1999 @@ -349,8 +349,8 @@ #define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */ /* Status of ORCSCB_Status */ -#define SCB_COMPLETE 0x00 /* SCB request completed */ -#define SCB_POST 0x01 /* SCB is posted by the HOST */ +#define ORCSCB_COMPLETE 0x00 /* SCB request completed */ +#define ORCSCB_POST 0x01 /* SCB is posted by the HOST */ /* Bit Definition for ORCSCB_Flags */ #define SCF_DISINT 0x01 /* Disable HOST interrupt */ diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.3.22/linux/drivers/scsi/ips.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/scsi/ips.c Mon Oct 18 11:26:31 1999 @@ -1840,10 +1840,10 @@ } if ((scb->scsi_cmd->request.cmd == READ) && (SC->request_bufflen)) - scb->dcdb.cmd_attribute |= DATA_IN; + scb->dcdb.cmd_attribute |= IPS_DATA_IN; if ((scb->scsi_cmd->request.cmd == WRITE) && (SC->request_bufflen)) - scb->dcdb.cmd_attribute |= DATA_OUT; + scb->dcdb.cmd_attribute |= IPS_DATA_OUT; if (scb->data_len >= IPS_MAX_XFER) { scb->dcdb.cmd_attribute |= TRANSFER_64K; @@ -2274,10 +2274,10 @@ } if ((scb->scsi_cmd->request.cmd == READ) && (scb->data_len)) - scb->dcdb.cmd_attribute |= DATA_IN; + scb->dcdb.cmd_attribute |= IPS_DATA_IN; if ((scb->scsi_cmd->request.cmd == WRITE) && (scb->data_len)) - scb->dcdb.cmd_attribute |= DATA_OUT; + scb->dcdb.cmd_attribute |= IPS_DATA_OUT; if (scb->data_len >= IPS_MAX_XFER) { scb->dcdb.cmd_attribute |= TRANSFER_64K; diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/ips.h linux/drivers/scsi/ips.h --- v2.3.22/linux/drivers/scsi/ips.h Mon Oct 4 15:49:29 1999 +++ linux/drivers/scsi/ips.h Fri Oct 22 12:47:50 1999 @@ -237,8 +237,8 @@ #define NO_DISCONNECT 0x00 #define DISCONNECT_ALLOWED 0x80 #define NO_AUTO_REQUEST_SENSE 0x40 - #define DATA_IN 0x01 - #define DATA_OUT 0x02 + #define IPS_DATA_IN 0x01 + #define IPS_DATA_OUT 0x02 #define TRANSFER_64K 0x08 #define NOTIMEOUT 0x00 #define TIMEOUT10 0x10 diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.22/linux/drivers/scsi/st.c Fri Sep 10 23:57:32 1999 +++ linux/drivers/scsi/st.c Tue Oct 19 11:57:45 1999 @@ -11,7 +11,7 @@ Copyright 1992 - 1999 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sat Aug 7 13:54:31 1999 by makisara@kai.makisara.local + Last modified: Tue Oct 19 21:39:15 1999 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 */ @@ -36,10 +36,17 @@ is defined and non-zero. */ #define DEBUG 0 +#if DEBUG /* The message level for the debug messages is currently set to KERN_NOTICE so that people can easily see the messages. Later when the debugging messages in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ #define ST_DEB_MSG KERN_NOTICE +#define DEB(a) a +#define DEBC(a) if (debugging) { a ; } +#else +#define DEB(a) +#define DEBC(a) +#endif #define MAJOR_NR SCSI_TAPE_MAJOR #include @@ -100,9 +107,7 @@ #error "Buffer size should not exceed (2 << 24 - 1) bytes!" #endif -#if DEBUG -static int debugging = 1; -#endif +DEB( static int debugging = DEBUG; ) #define MAX_RETRIES 0 #define MAX_WRITE_RETRIES 0 @@ -164,9 +169,7 @@ int dev = TAPE_NR(SCpnt->request.rq_dev); int result = SCpnt->result; unsigned char *sense = SCpnt->sense_buffer, scode; -#if DEBUG - const char *stp; -#endif + DEB(const char *stp;) if (!result /* && SCpnt->sense_buffer[0] == 0 */ ) return 0; @@ -178,35 +181,35 @@ scode = 0; } -#if DEBUG - if (debugging) { - printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", + DEB( + if (debugging) { + printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", dev, result, SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2], SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5], SCpnt->request_bufflen); if (driver_byte(result) & DRIVER_SENSE) print_sense("st", SCpnt); - } else -#endif + } else ) /* end DEB */ if (!(driver_byte(result) & DRIVER_SENSE) || ((sense[0] & 0x70) == 0x70 && scode != NO_SENSE && scode != RECOVERED_ERROR && -/* scode != UNIT_ATTENTION && */ + /* scode != UNIT_ATTENTION && */ scode != BLANK_CHECK && scode != VOLUME_OVERFLOW && SCpnt->data_cmnd[0] != MODE_SENSE && - SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ + SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (driver_byte(result) & DRIVER_SENSE) { printk(KERN_WARNING "st%d: Error with sense data: ", dev); print_sense("st", SCpnt); } else printk(KERN_WARNING "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK, - host_byte(result)); + dev, result, suggestion(result), + driver_byte(result) & DRIVER_MASK, host_byte(result)); } + if ((sense[0] & 0x70) == 0x70 && scode == RECOVERED_ERROR #if ST_RECOVERED_WRITE_FATAL @@ -216,7 +219,8 @@ ) { scsi_tapes[dev].recover_count++; scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT); -#if DEBUG + + DEB( if (debugging) { if (SCpnt->data_cmnd[0] == READ_6) stp = "read"; @@ -226,8 +230,8 @@ stp = "ioctl"; printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp, scsi_tapes[dev].recover_count); - } -#endif + } ) /* end DEB */ + if ((sense[2] & 0xe0) == 0) return 0; } @@ -250,8 +254,9 @@ /* EOM at write-behind, has all been written? */ if ((SCpnt->sense_buffer[0] & 0x80) != 0) remainder = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; else remainder = 0; if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW || @@ -263,16 +268,14 @@ (STp->buffer)->last_result = SCpnt->result; SCpnt->request.rq_status = RQ_SCSI_DONE; (STp->buffer)->last_SCpnt = SCpnt; + DEB( STp->write_pending = 0; ) -#if DEBUG - STp->write_pending = 0; -#endif up(SCpnt->request.sem); } -#if DEBUG + DEB( else if (debugging) printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr); -#endif + ) /* end DEB */ } @@ -289,10 +292,12 @@ spin_lock_irqsave(&io_request_lock, flags); if (SCpnt == NULL) if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) { - printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt)); + printk(KERN_ERR "st%d: Can't get SCSI request.\n", + TAPE_NR(STp->devt)); spin_unlock_irqrestore(&io_request_lock, flags); return NULL; } + cmd[1] |= (SCpnt->lun << 5) & 0xe0; init_MUTEX_LOCKED(&STp->sem); SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ? @@ -314,7 +319,6 @@ if (do_wait) { down(SCpnt->request.sem); - (STp->buffer)->last_result_fatal = st_chk_result(SCpnt); } return SCpnt; @@ -329,12 +333,12 @@ STbuffer = STp->buffer; -#if DEBUG + DEB( if (STp->write_pending) STp->nbr_waits++; else STp->nbr_finished++; -#endif + ) /* end DEB */ down(&(STp->sem)); @@ -347,7 +351,8 @@ STbuffer->b_data + STbuffer->writing, STbuffer->buffer_bytes - STbuffer->writing); #else - printk(KERN_WARNING "st: write_behind_check: something left in buffer!\n"); + printk(KERN_WARNING + "st: write_behind_check: something left in buffer!\n"); #endif STbuffer->buffer_bytes -= STbuffer->writing; STps = &(STp->ps[STp->partition]); @@ -378,11 +383,9 @@ } else cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */ cmd[5] = 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n", - TAPE_NR(STp->devt), forward ? "forward" : "backward"); -#endif + + DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n", + TAPE_NR(STp->devt), forward ? "forward" : "backward")); SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE); if (!SCpnt) @@ -411,11 +414,9 @@ if ((STp->buffer)->writing) { write_behind_check(STp); if ((STp->buffer)->last_result_fatal) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n", - TAPE_NR(STp->devt), (STp->buffer)->last_result); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Async write error (flush) %x.\n", + TAPE_NR(STp->devt), (STp->buffer)->last_result)) if ((STp->buffer)->last_result == INT_MAX) return (-ENOSPC); return (-EIO); @@ -430,10 +431,9 @@ offset = (STp->buffer)->buffer_bytes; transfer = ((offset + STp->block_size - 1) / STp->block_size) * STp->block_size; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", + TAPE_NR(STp->devt), transfer)); + memset((STp->buffer)->b_data + offset, 0, transfer - offset); memset(cmd, 0, 10); @@ -444,8 +444,8 @@ cmd[3] = blks >> 8; cmd[4] = blks; - SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, - TRUE); + SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, + MAX_WRITE_RETRIES, TRUE); if (!SCpnt) return (-EBUSY); @@ -458,7 +458,8 @@ (STp->buffer)->buffer_bytes = 0; result = (-ENOSPC); } else { - printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt)); + printk(KERN_ERR "st%d: Error on flush.\n", + TAPE_NR(STp->devt)); result = (-EIO); } STps->drv_block = (-1); @@ -514,7 +515,7 @@ result = 0; if (!seek_next) { if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, FALSE); /* Back over the EOF hit */ + result = cross_eof(STp, FALSE); /* Back over the EOF hit */ if (!result) STps->eof = ST_NOEOF; else { @@ -590,19 +591,14 @@ } STp = &(scsi_tapes[dev]); if (STp->in_use) { -#if DEBUG - printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); -#endif + DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) return (-EBUSY); } STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0; if (mode != STp->current_mode) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", - dev, STp->current_mode, mode); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", + dev, STp->current_mode, mode)); new_session = TRUE; STp->current_mode = mode; } @@ -646,9 +642,7 @@ } STp->ready = ST_READY; STp->recover_count = 0; -#if DEBUG - STp->nbr_waits = STp->nbr_finished = 0; -#endif + DEB( STp->nbr_waits = STp->nbr_finished = 0; ) if (scsi_tapes[dev].device->host->hostt->module) __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); @@ -667,18 +661,26 @@ __MOD_DEC_USE_COUNT(st_template.module); return (-EBUSY); } + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ - memset((void *) &cmd[0], 0, 10); - cmd[0] = TEST_UNIT_READY; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES, - TRUE); + /* Flush the queued UNIT ATTENTION sense data */ + for (i=0; i < 10; i++) { + memset((void *) &cmd[0], 0, 10); + cmd[0] = TEST_UNIT_READY; + SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, + MAX_READY_RETRIES, TRUE); + if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || + (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION) + break; + } (STp->device)->was_reset = 0; STp->partition = STp->new_partition = 0; if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ + STp->nbr_partitions = 1; /* This guess will be updated later + if necessary */ for (i = 0; i < ST_NBR_PARTITIONS; i++) { STps = &(STp->ps[i]); STps->rw = ST_IDLE; @@ -690,6 +692,7 @@ } new_session = TRUE; } + if ((STp->buffer)->last_result_fatal != 0) { if ((STp->device)->scsi_level >= SCSI_2 && (SCpnt->sense_buffer[0] & 0x70) == 0x70 && @@ -709,30 +712,29 @@ STp->in_use = 1; return 0; } + if (STp->omit_blklims) STp->min_block = STp->max_block = (-1); else { memset((void *) &cmd[0], 0, 10); cmd[0] = READ_BLOCK_LIMITS; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, TRUE); + SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, + TRUE); if (!SCpnt->result && !SCpnt->sense_buffer[0]) { STp->max_block = ((STp->buffer)->b_data[1] << 16) | ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; STp->min_block = ((STp->buffer)->b_data[4] << 8) | (STp->buffer)->b_data[5]; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block, - STp->max_block); -#endif + if ( DEB( debugging || ) !STp->inited) + printk(KERN_WARNING + "st%d: Block limits %d - %d bytes.\n", dev, + STp->min_block, STp->max_block); } else { STp->min_block = STp->max_block = (-1); -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Can't read block limits.\n", + dev)); } } @@ -743,40 +745,33 @@ SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE); if ((STp->buffer)->last_result_fatal != 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev)); STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ (STp->buffer)->last_result_fatal = 0; /* Prevent error propagation */ STp->drv_write_prot = 0; } else { - -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", - dev, - (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], - (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", + dev, + (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], + (STp->buffer)->b_data[2], (STp->buffer)->b_data[3])); if ((STp->buffer)->b_data[3] >= 8) { STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7; STp->density = (STp->buffer)->b_data[4]; STp->block_size = (STp->buffer)->b_data[9] * 65536 + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Density %x, tape length: %x, drv buffer: %d\n", - dev, STp->density, (STp->buffer)->b_data[5] * 65536 + - (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], - STp->drv_buffer); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Density %x, tape length: %x, drv buffer: %d\n", + dev, STp->density, (STp->buffer)->b_data[5] * 65536 + + (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], + STp->drv_buffer)); } + if (STp->block_size > (STp->buffer)->buffer_size && !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { - printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev, - STp->block_size); + printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", + dev, STp->block_size); scsi_release_command(SCpnt); (STp->buffer)->in_use = 0; STp->buffer = NULL; @@ -790,26 +785,25 @@ } scsi_release_command(SCpnt); SCpnt = NULL; + STp->inited = TRUE; if (STp->block_size > 0) - (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size; + (STp->buffer)->buffer_blocks = + (STp->buffer)->buffer_size / STp->block_size; else (STp->buffer)->buffer_blocks = 1; (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, + DEBC(printk(ST_DEB_MSG + "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, STp->block_size, (STp->buffer)->buffer_size, - (STp->buffer)->buffer_blocks); -#endif + (STp->buffer)->buffer_blocks)); if (STp->drv_write_prot) { STp->write_prot = 1; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Write protected\n", dev); -#endif + + DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev)); + if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { (STp->buffer)->in_use = 0; STp->buffer = NULL; @@ -820,14 +814,13 @@ return (-EROFS); } } + if (STp->can_partitions && STp->nbr_partitions < 1) { /* This code is reached when the device is opened for the first time after the driver has been initialized with tape in the drive and the partition support has been enabled. */ -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Updating partition number in status.\n", dev)); if ((STp->partition = find_partition(inode)) < 0) { (STp->buffer)->in_use = 0; STp->buffer = NULL; @@ -838,8 +831,9 @@ return STp->partition; } STp->new_partition = STp->partition; - STp->nbr_partitions = 1; /* This guess will be updated when necessary */ + STp->nbr_partitions = 1; /* This guess will be updated when necessary */ } + if (new_session) { /* Change the drive parameters for the new mode */ STp->density_changed = STp->blksize_changed = FALSE; STp->compression_changed = FALSE; @@ -853,9 +847,11 @@ __MOD_DEC_USE_COUNT(st_template.module); return i; } + if (STp->default_drvbuffer != 0xff) { if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer)) - printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n", + printk(KERN_WARNING + "st%d: Can't set default drive buffering to %d.\n", dev, STp->default_drvbuffer); } } @@ -889,24 +885,20 @@ if (STp->can_partitions && (result = update_partition(inode)) < 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: update_partition at close failed.\n", dev)); goto out; } + if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { result = flush_write_buffer(STp); -#if DEBUG - if (debugging) { - printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", - dev, (long) (filp->f_pos)); - printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n", - dev, STp->nbr_waits, STp->nbr_finished); - } -#endif + DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", + dev, (long) (filp->f_pos)); + printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n", + dev, STp->nbr_waits, STp->nbr_finished); + ) if (result == 0 || result == (-ENOSPC)) { @@ -914,8 +906,8 @@ cmd[0] = WRITE_FILEMARKS; cmd[4] = 1 + STp->two_fm; - SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES, - TRUE); + SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, + MAX_WRITE_RETRIES, TRUE); if (!SCpnt) goto out; @@ -943,11 +935,9 @@ STps->eof = ST_FM; } } -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n", - dev, cmd[4]); -#endif + + DEBC(printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n", + dev, cmd[4])); } else if (!STp->rew_at_close) { STps = &(STp->ps[STp->partition]); if (!STm->sysv || STps->rw != ST_READING) { @@ -972,6 +962,7 @@ STps->eof = ST_FM; } } + out: if (STp->rew_at_close) { result2 = st_int_ioctl(inode, MTREW, 1); @@ -1001,6 +992,7 @@ normalize_buffer(STp->buffer); (STp->buffer)->in_use = 0; } + STp->in_use = 0; if (scsi_tapes[dev].device->host->hostt->module) __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); @@ -1039,16 +1031,19 @@ if (!scsi_block_when_processing_errors(STp->device)) { return -ENXIO; } + if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */ return -ENXIO; } + if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) return (-ENOMEDIUM); else return (-EIO); } + STm = &(STp->modes[STp->current_mode]); if (!STm->defined) return (-ENXIO); @@ -1062,12 +1057,11 @@ if (STp->device->was_reset) return (-EIO); -#if DEBUG + DEB( if (!STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); return (-EIO); - } -#endif + } ) /* end DEB */ /* Write must be integral number of blocks */ if (STp->block_size != 0 && (count % STp->block_size) != 0) { @@ -1075,6 +1069,7 @@ dev); return (-EIO); } + if (STp->can_partitions && (retval = update_partition(inode)) < 0) return retval; @@ -1111,20 +1106,19 @@ } } } + if ((STp->buffer)->writing) { write_behind_check(STp); if ((STp->buffer)->last_result_fatal) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev, - (STp->buffer)->last_result); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", + dev, (STp->buffer)->last_result)); if ((STp->buffer)->last_result == INT_MAX) STps->eof = ST_EOM_OK; else STps->eof = ST_EOM_ERROR; } } + if (STps->eof == ST_EOM_OK) return (-ENOSPC); else if (STps->eof == ST_EOM_ERROR) @@ -1178,6 +1172,7 @@ } return i; } + if (STp->block_size == 0) blks = transfer = do_count; else { @@ -1195,18 +1190,18 @@ return (-EBUSY); if ((STp->buffer)->last_result_fatal != 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Error on write:\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev)); if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x40)) { - if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0) + if (STp->block_size != 0 && + (SCpnt->sense_buffer[0] & 0x80) != 0) transfer = (SCpnt->sense_buffer[3] << 24) | (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; else if (STp->block_size == 0 && - (SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) + (SCpnt->sense_buffer[2] & 0x0f) == + VOLUME_OVERFLOW) transfer = do_count; else transfer = 0; @@ -1216,26 +1211,26 @@ filp->f_pos += do_count - transfer; count -= do_count - transfer; if (STps->drv_block >= 0) { - if (STp->block_size == 0 && transfer < do_count) + if (STp->block_size == 0 && + transfer < do_count) STps->drv_block++; else if (STp->block_size != 0) - STps->drv_block += (do_count - transfer) / STp->block_size; + STps->drv_block += + (do_count - transfer) / + STp->block_size; } STps->eof = ST_EOM_OK; - retval = (-ENOSPC); /* EOM within current request */ -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n", - dev, transfer); -#endif + retval = (-ENOSPC); /* EOM within current request */ + DEBC(printk(ST_DEB_MSG + "st%d: EOM with %d bytes unwritten.\n", + dev, transfer)); } else { STps->eof = ST_EOM_ERROR; - STps->drv_block = (-1); /* Too cautious? */ + STps->drv_block = (-1); /* Too cautious? */ retval = (-EIO); /* EOM for old data */ -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: EOM with lost data.\n", + dev)); } } else { STps->drv_block = (-1); /* Too cautious? */ @@ -1276,11 +1271,13 @@ filp->f_pos += count; count = 0; } + if (doing_write && (STp->buffer)->last_result_fatal != 0) { scsi_release_command(SCpnt); SCpnt = NULL; return (STp->buffer)->last_result_fatal; } + if (STm->do_async_writes && (((STp->buffer)->buffer_bytes >= STp->write_threshold && (STp->buffer)->buffer_bytes >= STp->block_size) || @@ -1301,9 +1298,7 @@ cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; -#if DEBUG - STp->write_pending = 1; -#endif + DEB( STp->write_pending = 1; ) SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout, MAX_WRITE_RETRIES, FALSE); @@ -1376,21 +1371,18 @@ /* Something to check */ if ((STp->buffer)->last_result_fatal) { retval = 1; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - dev, - SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], - SCpnt->sense_buffer[2], SCpnt->sense_buffer[3], - SCpnt->sense_buffer[4], SCpnt->sense_buffer[5], - SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", + dev, + SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], + SCpnt->sense_buffer[2], SCpnt->sense_buffer[3], + SCpnt->sense_buffer[4], SCpnt->sense_buffer[5], + SCpnt->sense_buffer[6], SCpnt->sense_buffer[7])); if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) - SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ + SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ - if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ + if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ /* Compute the residual count */ if ((SCpnt->sense_buffer[0] & 0x80) != 0) transfer = (SCpnt->sense_buffer[3] << 24) | @@ -1410,7 +1402,7 @@ } else { scsi_release_command(SCpnt); SCpnt = *aSCpnt = NULL; - if (transfer == blks) { /* We did not get anything, error */ + if (transfer == blks) { /* We did not get anything, error */ printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev); if (STps->drv_block >= 0) STps->drv_block += blks - transfer + 1; @@ -1420,12 +1412,9 @@ /* We have some data, deliver it */ (STp->buffer)->buffer_bytes = (blks - transfer) * STp->block_size; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st%d: ILI but enough data received %ld %d.\n", - dev, count, (STp->buffer)->buffer_bytes); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: ILI but enough data received %ld %d.\n", + dev, count, (STp->buffer)->buffer_bytes)); if (STps->drv_block >= 0) STps->drv_block += 1; if (st_int_ioctl(inode, MTBSR, 1)) @@ -1441,12 +1430,9 @@ else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st%d: EOF detected (%d bytes read).\n", - dev, (STp->buffer)->buffer_bytes); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: EOF detected (%d bytes read).\n", + dev, (STp->buffer)->buffer_bytes)); } else if (SCpnt->sense_buffer[2] & 0x40) { if (STps->eof == ST_FM) STps->eof = ST_EOD_1; @@ -1457,28 +1443,21 @@ else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", - dev, (STp->buffer)->buffer_bytes); -#endif + + DEBC(printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", + dev, (STp->buffer)->buffer_bytes)); } } /* end of EOF, EOM, ILI test */ else { /* nonzero sense key */ -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Tape error while reading.\n", dev)); STps->drv_block = (-1); if (STps->eof == ST_FM && (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st%d: Zero returned for first BLANK CHECK after EOF.\n", - dev); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Zero returned for first BLANK CHECK after EOF.\n", + dev)); STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ } else /* Some other extended sense code */ retval = (-EIO); @@ -1529,10 +1508,12 @@ if (!scsi_block_when_processing_errors(STp->device)) { return -ENXIO; } + if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */ return -ENXIO; } + if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) return (-ENOMEDIUM); @@ -1542,12 +1523,11 @@ STm = &(STp->modes[STp->current_mode]); if (!STm->defined) return (-ENXIO); -#if DEBUG + DEB( if (!STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); return (-EIO); - } -#endif + } ) /* end DEB */ if (STp->can_partitions && (total = update_partition(inode)) < 0) @@ -1573,11 +1553,12 @@ return transfer; STps->rw = ST_READING; } -#if DEBUG + DEB( if (debugging && STps->eof != ST_NOEOF) printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev, STps->eof, (STp->buffer)->buffer_bytes); -#endif + ) /* end DEB */ + if ((STp->buffer)->buffer_bytes == 0 && STps->eof >= ST_EOD_1) { if (STps->eof < ST_EOD) { @@ -1586,6 +1567,7 @@ } return (-EIO); /* EOM or Blank Check */ } + /* Check the buffer writability before any tape movement. Don't alter buffer data. */ if (copy_from_user(&i, buf, 1) != 0 || @@ -1610,13 +1592,16 @@ return special; } } + /* Move the data from driver buffer to user buffer */ if ((STp->buffer)->buffer_bytes > 0) { -#if DEBUG + DEB( if (debugging && STps->eof != ST_NOEOF) - printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev, - STps->eof, (STp->buffer)->buffer_bytes, count - total); -#endif + printk(ST_DEB_MSG + "st%d: EOF up (%d). Left %d, needed %d.\n", dev, + STps->eof, (STp->buffer)->buffer_bytes, + count - total); + ) /* end DEB */ transfer = (STp->buffer)->buffer_bytes < count - total ? (STp->buffer)->buffer_bytes : count - total; i = from_buffer(STp->buffer, buf, transfer); @@ -1631,15 +1616,18 @@ buf += transfer; total += transfer; } + if (STp->block_size == 0) break; /* Read only one variable length block */ - } /* for (total = 0, special = 0; total < count && !special; ) */ + } /* for (total = 0, special = 0; + total < count && !special; ) */ if (SCpnt != NULL) { scsi_release_command(SCpnt); SCpnt = NULL; } + /* Change the eof state if no data from tape or buffer */ if (total == 0) { if (STps->eof == ST_FM_HIT) { @@ -1678,11 +1666,9 @@ STp->scsi2_logical); printk(KERN_INFO "st%d: sysv: %d\n", dev, STm->sysv); -#if DEBUG - printk(KERN_INFO - "st%d: debugging: %d\n", - dev, debugging); -#endif + DEB(printk(KERN_INFO + "st%d: debugging: %d\n", + dev, debugging);) } @@ -1699,12 +1685,11 @@ if (!STm->defined) { memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); modes_defined = TRUE; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n", - dev, STp->current_mode); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Initialized mode %d definition from mode 0\n", + dev, STp->current_mode)); } + code = options & MT_ST_OPTIONS; if (code == MT_ST_BOOLEANS) { STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; @@ -1720,9 +1705,7 @@ STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; -#if DEBUG - debugging = (options & MT_ST_DEBUGGING) != 0; -#endif + DEB( debugging = (options & MT_ST_DEBUGGING) != 0; ) st_log_options(STp, STm, dev); } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { value = (code == MT_ST_SETBOOLEANS); @@ -1751,15 +1734,15 @@ STp->scsi2_logical = value; if ((options & MT_ST_SYSV) != 0) STm->sysv = value; -#if DEBUG + DEB( if ((options & MT_ST_DEBUGGING) != 0) - debugging = value; -#endif + debugging = value; ) st_log_options(STp, STm, dev); } else if (code == MT_ST_WRITE_THRESHOLD) { value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; if (value < 1 || value > st_buffer_size) { - printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n", + printk(KERN_WARNING + "st%d: Write threshold %d too small or too large.\n", dev, value); return (-EIO); } @@ -1784,8 +1767,8 @@ (value & ~MT_ST_SET_LONG_TIMEOUT)); } else { STp->timeout = value * HZ; - printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev, - value); + printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", + dev, value); } } else if (code == MT_ST_DEF_OPTIONS) { code = (options & ~MT_ST_CLEAR_DEFAULT); @@ -1793,7 +1776,8 @@ if (code == MT_ST_DEF_DENSITY) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_density = (-1); - printk(KERN_INFO "st%d: Density default disabled.\n", dev); + printk(KERN_INFO "st%d: Density default disabled.\n", + dev); } else { STm->default_density = value & 0xff; printk(KERN_INFO "st%d: Density default set to %x\n", @@ -1802,16 +1786,19 @@ } else if (code == MT_ST_DEF_DRVBUFFER) { if (value == MT_ST_CLEAR_DEFAULT) { STp->default_drvbuffer = 0xff; - printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev); + printk(KERN_INFO + "st%d: Drive buffer default disabled.\n", dev); } else { STp->default_drvbuffer = value & 7; - printk(KERN_INFO "st%d: Drive buffer default set to %x\n", + printk(KERN_INFO + "st%d: Drive buffer default set to %x\n", dev, STp->default_drvbuffer); } } else if (code == MT_ST_DEF_COMPRESSION) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_compression = ST_DONT_TOUCH; - printk(KERN_INFO "st%d: Compression default disabled.\n", dev); + printk(KERN_INFO + "st%d: Compression default disabled.\n", dev); } else { STm->default_compression = (value & 1 ? ST_YES : ST_NO); printk(KERN_INFO "st%d: Compression default set to %x\n", @@ -1858,30 +1845,23 @@ dev = TAPE_NR(SCpnt->request.rq_dev); if ((STp->buffer)->last_result_fatal != 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", + dev)); scsi_release_command(SCpnt); SCpnt = NULL; return (-EIO); } -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev, - ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0)); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev, + ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0))); /* Check if compression can be changed */ if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; return (-EIO); } + /* Do the change */ if (state) (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK; @@ -1899,19 +1879,13 @@ SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); if ((STp->buffer)->last_result_fatal != 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; return (-EIO); } -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n", - dev, state); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n", + dev, state)); scsi_release_command(SCpnt); SCpnt = NULL; @@ -1959,11 +1933,8 @@ cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n", - dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n", + dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4])); if (fileno >= 0) fileno += arg; blkno = 0; @@ -1978,15 +1949,14 @@ cmd[2] = (ltmp >> 16); cmd[3] = (ltmp >> 8); cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n", - dev, (-ltmp)); - } -#endif + DEBC( + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk(ST_DEB_MSG + "st%d: Spacing tape backward over %ld filemarks.\n", + dev, (-ltmp)); + ) if (fileno >= 0) fileno -= arg; blkno = (-1); /* We can't know the block number */ @@ -1998,11 +1968,8 @@ cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4])); if (blkno >= 0) blkno += arg; at_sm &= (arg == 0); @@ -2014,14 +1981,13 @@ cmd[2] = (ltmp >> 16); cmd[3] = (ltmp >> 8); cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp)); - } -#endif + DEBC( + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk(ST_DEB_MSG + "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp)); + ) if (blkno >= 0) blkno -= arg; at_sm &= (arg == 0); @@ -2032,11 +1998,8 @@ cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4])); if (arg != 0) { blkno = fileno = (-1); at_sm = 1; @@ -2049,15 +2012,13 @@ cmd[2] = (ltmp >> 16); cmd[3] = (ltmp >> 8); cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) + DEBC( + if (cmd[2] & 0x80) ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n", - dev, (-ltmp)); - } -#endif + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n", + dev, (-ltmp)); + ) if (arg != 0) { blkno = fileno = (-1); at_sm = 1; @@ -2074,16 +2035,14 @@ cmd[3] = (arg >> 8); cmd[4] = arg; timeout = STp->timeout; -#if DEBUG - if (debugging) { - if (cmd_in == MTWEOF) - printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev, + DEBC( + if (cmd_in == MTWEOF) + printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - else + else printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - } -#endif + ) if (fileno >= 0) fileno += arg; blkno = 0; @@ -2095,10 +2054,7 @@ cmd[1] = 1; /* Don't wait for completion */ timeout = STp->timeout; #endif -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev)); fileno = blkno = at_sm = 0; break; case MTOFFL: @@ -2113,14 +2069,10 @@ if (cmd_in != MTOFFL && arg >= 1 + MT_ST_HPLOADER_OFFSET && arg <= 6 + MT_ST_HPLOADER_OFFSET) { -#if DEBUG - if (debugging) { - printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", - dev, (cmd[4]) ? "" : "un", - arg - MT_ST_HPLOADER_OFFSET); - } -#endif - cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ + DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", + dev, (cmd[4]) ? "" : "un", + arg - MT_ST_HPLOADER_OFFSET)); + cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ } #if ST_NOWAIT cmd[1] = 1; /* Don't wait for completion */ @@ -2128,21 +2080,16 @@ #else timeout = STp->long_timeout; #endif -#if DEBUG - if (debugging) { + DEBC( if (cmd_in != MTLOAD) printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); else printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); - } -#endif + ) fileno = blkno = at_sm = 0; break; case MTNOP: -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: No op on tape.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: No op on tape.\n", dev)); return 0; /* Should do something ? */ break; case MTRETEN: @@ -2152,10 +2099,7 @@ timeout = STp->timeout; #endif cmd[4] = 3; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev)); fileno = blkno = at_sm = 0; break; case MTEOM: @@ -2173,10 +2117,8 @@ fileno = (-1); cmd[0] = SPACE; cmd[1] = 3; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", + dev)); blkno = 0; at_sm = 0; break; @@ -2191,29 +2133,20 @@ #else timeout = STp->long_timeout * 8; #endif -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev)); fileno = blkno = at_sm = 0; break; case MTLOCK: chg_eof = FALSE; cmd[0] = ALLOW_MEDIUM_REMOVAL; cmd[4] = SCSI_REMOVAL_PREVENT; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev); -#endif /* ; */ + DEBC(printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev)); break; case MTUNLOCK: chg_eof = FALSE; cmd[0] = ALLOW_MEDIUM_REMOVAL; cmd[4] = SCSI_REMOVAL_ALLOW; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev); -#endif /* ; */ + DEBC(printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev)); break; case MTSETBLK: /* Set block length */ case MTSETDENSITY: /* Set tape density */ @@ -2250,28 +2183,29 @@ if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { ltmp = arg & MT_ST_BLKSIZE_MASK; if (cmd_in == MTSETBLK) - STp->blksize_changed = TRUE; /* At least we tried ;-) */ + STp->blksize_changed = TRUE; /* At least we tried ;-) */ } else ltmp = STp->block_size; (STp->buffer)->b_data[9] = (ltmp >> 16); (STp->buffer)->b_data[10] = (ltmp >> 8); (STp->buffer)->b_data[11] = ltmp; timeout = STp->timeout; -#if DEBUG - if (debugging) { + DEBC( if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) - printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev, + printk(ST_DEB_MSG + "st%d: Setting block size to %d bytes.\n", dev, (STp->buffer)->b_data[9] * 65536 + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]); if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK) - printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev, + printk(ST_DEB_MSG + "st%d: Setting density code to %x.\n", dev, (STp->buffer)->b_data[4]); if (cmd_in == MTSETDRVBUFFER) - printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev, + printk(ST_DEB_MSG + "st%d: Setting drive buffer code to %d.\n", dev, ((STp->buffer)->b_data[2] >> 4) & 7); - } -#endif + ) break; default: return (-ENOSYS); @@ -2331,8 +2265,8 @@ } STp->partition = 0; } - } else { /* SCSI command was not completely successful. Don't return - from this block without releasing the SCSI command block! */ + } else { /* SCSI command was not completely successful. Don't return + from this block without releasing the SCSI command block! */ if (SCpnt->sense_buffer[2] & 0x40) { if (cmd_in != MTBSF && cmd_in != MTBSFM && @@ -2340,6 +2274,7 @@ STps->eof = ST_EOM_OK; STps->drv_block = 0; } + undone = ( (SCpnt->sense_buffer[3] << 24) + (SCpnt->sense_buffer[4] << 16) + @@ -2446,10 +2381,7 @@ (STp->device->scsi_level >= SCSI_2 && ((STp->buffer)->b_data[0] & 4) != 0)) { *block = *partition = 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev)); result = (-EIO); } else { result = 0; @@ -2468,12 +2400,8 @@ (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */ STp->ps[0].drv_block = STp->ps[0].drv_file = 0; } -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev, - *block, *partition); -#endif - + DEBC(printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev, + *block, *partition)); } scsi_release_command(SCpnt); SCpnt = NULL; @@ -2502,13 +2430,10 @@ timeout = STp->long_timeout; STps = &(STp->ps[STp->partition]); -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n", - dev, block, partition); - if (partition < 0) - return (-EIO); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n", + dev, block, partition)); + DEB(if (partition < 0) + return (-EIO); ) /* Update the location at the partition we are leaving */ if ((!STp->can_partitions && partition != 0) || @@ -2520,13 +2445,12 @@ else { STps->last_block_valid = TRUE; STps->last_block_visited = blk; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Visited block %d for partition %d saved.\n", - dev, blk, STp->partition); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Visited block %d for partition %d saved.\n", + dev, blk, STp->partition)); } } + memset(scmd, 0, 10); if ((STp->device)->scsi_level < SCSI_2) { scmd[0] = QFA_SEEK_BLOCK; @@ -2545,11 +2469,9 @@ if (STp->partition != partition) { scmd[1] |= 2; scmd[8] = partition; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Trying to change partition from %d to %d\n", - dev, STp->partition, partition); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Trying to change partition from %d to %d\n", + dev, STp->partition, partition)); } } #if ST_NOWAIT @@ -2655,17 +2577,12 @@ SCpnt = NULL; if ((STp->buffer)->last_result_fatal != 0) { -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", + dev)); result = (-EIO); } else { result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result)); } return result; @@ -2691,20 +2608,16 @@ if (size <= 0) { length = 8; bp[MODE_HEADER_LENGTH + 3] = 0; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev); -#endif + DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", + dev)); } else { length = 10; bp[MODE_HEADER_LENGTH + 3] = 1; bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff; bp[MODE_HEADER_LENGTH + 9] = size & 0xff; -#if DEBUG - if (debugging) - printk(ST_DEB_MSG "st%d: Formatting tape with two partition (1 = %d MB).\n", - dev, size); -#endif + DEBC(printk(ST_DEB_MSG + "st%d: Formatting tape with two partition (1 = %d MB).\n", + dev, size)); } bp[MODE_HEADER_LENGTH + 6] = 0; bp[MODE_HEADER_LENGTH + 7] = 0; @@ -2752,12 +2665,12 @@ int dev = TAPE_NR(inode->i_rdev); STp = &(scsi_tapes[dev]); -#if DEBUG + DEB( if (debugging && !STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); return (-EIO); - } -#endif + } ) /* end DEB */ + STm = &(STp->modes[STp->current_mode]); STps = &(STp->ps[STp->partition]); @@ -2782,7 +2695,8 @@ return (-EFAULT); if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { - printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); + printk(KERN_WARNING + "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); return (-EPERM); } if (!STm->defined && @@ -2792,7 +2706,8 @@ if (!(STp->device)->was_reset) { if (STps->eof == ST_FM_HIT) { - if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || mtc.mt_op == MTEOM) { + if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || + mtc.mt_op == MTEOM) { mtc.mt_count -= 1; if (STps->drv_file >= 0) STps->drv_file += 1; @@ -2802,8 +2717,10 @@ STps->drv_file += 1; } } + if (mtc.mt_op == MTSEEK) { - /* Old position must be restored if partition will be changed */ + /* Old position must be restored if partition will be + changed */ i = !STp->can_partitions || (STp->new_partition != STp->partition); } else { @@ -2832,7 +2749,8 @@ if (STp->door_locked != ST_UNLOCKED && STp->door_locked != ST_LOCK_FAILS) { if (st_int_ioctl(inode, MTLOCK, 0)) { - printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n", + printk(KERN_NOTICE + "st%d: Could not relock door after bus reset.\n", dev); STp->door_locked = ST_UNLOCKED; } @@ -2850,6 +2768,7 @@ if (mtc.mt_op == MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) != 0) return st_set_options(inode, mtc.mt_count); + if (mtc.mt_op == MTSETPART) { if (!STp->can_partitions || mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) @@ -2862,6 +2781,7 @@ STp->new_partition = mtc.mt_count; return 0; } + if (mtc.mt_op == MTMKPART) { if (!STp->can_partitions) return (-EINVAL); @@ -2878,15 +2798,18 @@ STps->drv_block = STps->drv_file = 0; return 0; } + if (mtc.mt_op == MTSEEK) { i = set_location(inode, mtc.mt_count, STp->new_partition, 0); if (!STp->can_partitions) STp->ps[0].rw = ST_IDLE; return i; } + if (STp->can_partitions && STp->ready == ST_READY && (i = update_partition(inode)) < 0) return i; + if (mtc.mt_op == MTCOMPRESSION) return st_compression(STp, (mtc.mt_count & 1)); else @@ -2916,9 +2839,11 @@ (STp->mt_status)->mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size; else if (STps->rw == ST_READING) - (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes + - STp->block_size - 1) / STp->block_size; + (STp->mt_status)->mt_blkno -= + ((STp->buffer)->buffer_bytes + + STp->block_size - 1) / STp->block_size; } + (STp->mt_status)->mt_gstat = 0; if (STp->drv_write_prot) (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff); @@ -2945,7 +2870,8 @@ (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff); if (STps->at_sm) (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff); - if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || + if (STm->do_async_writes || + (STm->do_buffer_writes && STp->block_size != 0) || STp->drv_buffer != 0) (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff); @@ -3014,7 +2940,8 @@ } else { /* Got something, continue */ for (b_size = PAGE_SIZE; - st_buffer_size > tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;) + st_buffer_size > + tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;) b_size *= 2; for (segs = 1, got = tb->sg[0].length; @@ -3024,11 +2951,13 @@ if (tb->sg[segs].address == NULL) { if (st_buffer_size - got <= (ST_FIRST_SG - segs) * b_size / 2) { - b_size /= 2; /* Large enough for the rest of the buffers */ + b_size /= 2; /* Large enough for the + rest of the buffers */ continue; } for (i = 0; i < segs - 1; i++) - scsi_init_free(tb->sg[i].address, tb->sg[i].length); + scsi_init_free(tb->sg[i].address, + tb->sg[i].length); scsi_init_free((char *) tb, tb->this_size); tb = NULL; break; @@ -3040,6 +2969,7 @@ } } } + if (!tb) { printk(KERN_NOTICE "st: Can't allocate new tape buffer (nbr %d).\n", st_nbr_buffers); @@ -3048,16 +2978,13 @@ tb->sg_segs = tb->orig_sg_segs = segs; tb->b_data = tb->sg[0].address; -#if DEBUG - if (debugging) { - printk(ST_DEB_MSG - "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n", - st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data); - printk(ST_DEB_MSG - "st: segment sizes: first %d, last %d bytes.\n", - tb->sg[0].length, tb->sg[segs - 1].length); - } -#endif + DEBC(printk(ST_DEB_MSG + "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n", + st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data); + printk(ST_DEB_MSG + "st: segment sizes: first %d, last %d bytes.\n", + tb->sg[0].length, tb->sg[segs - 1].length); + ) tb->in_use = 0; tb->dma = need_dma; tb->buffer_size = got; @@ -3094,7 +3021,7 @@ (unsigned char *) scsi_init_malloc(b_size, priority); if (STbuffer->sg[segs].address == NULL) { if (new_size - got <= (max_segs - segs) * b_size / 2) { - b_size /= 2; /* Large enough for the rest of the buffers */ + b_size /= 2; /* Large enough for the rest of the buffers */ continue; } printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n", @@ -3109,12 +3036,9 @@ STbuffer->buffer_size = got; segs++; } -#if DEBUG - if (debugging) - printk(ST_DEB_MSG - "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n", - got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size); -#endif + DEBC(printk(ST_DEB_MSG + "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n", + got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size)); return TRUE; } @@ -3129,11 +3053,11 @@ scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length); STbuffer->buffer_size -= STbuffer->sg[i].length; } -#if DEBUG + DEB( if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n", STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); -#endif + ) /* end DEB */ STbuffer->sg_segs = STbuffer->orig_sg_segs; } @@ -3244,7 +3168,8 @@ len = strlen(parms[i].name); if (!strncmp(stp, parms[i].name, len) && (*(stp + len) == ':' || *(stp + len) == '=')) { - *parms[i].val = simple_strtoul(stp + len + 1, NULL, 0); + *parms[i].val = + simple_strtoul(stp + len + 1, NULL, 0); break; } } @@ -3296,6 +3221,7 @@ SDp->attached--; return 1; } + for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++) if (!tpnt->device) break; @@ -3309,6 +3235,7 @@ else scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2; + tpnt->inited = 0; tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i); tpnt->dirty = 0; tpnt->in_use = 0; @@ -3392,7 +3319,8 @@ if (!st_registered) { if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) { - printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR); + printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", + MAJOR_NR); return 1; } st_registered++; @@ -3412,10 +3340,9 @@ unregister_chrdev(SCSI_TAPE_MAJOR, "st"); return 1; } -#if DEBUG - printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n", - st_buffer_size, st_write_threshold); -#endif + + DEB(printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n", + st_buffer_size, st_write_threshold)); memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape)); for (i = 0; i < st_template.dev_max; ++i) { @@ -3447,7 +3374,8 @@ for (i = st_nbr_buffers = 0; i < target_nbr; i++) { if (!new_tape_buffer(TRUE, TRUE)) { if (i == 0) { - printk(KERN_INFO "No tape buffers allocated at initialization.\n"); + printk(KERN_INFO + "No tape buffers allocated at initialization.\n"); break; } printk(KERN_INFO "Number of tape buffers adjusted.\n"); @@ -3509,10 +3437,12 @@ for (j = 0; j < st_buffers[i]->sg_segs; j++) scsi_init_free((char *) st_buffers[i]->sg[j].address, st_buffers[i]->sg[j].length); - scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size); + scsi_init_free((char *) st_buffers[i], + st_buffers[i]->this_size); } } - scsi_init_free((char *) st_buffers, st_template.dev_max * sizeof(ST_buffer *)); + scsi_init_free((char *) st_buffers, + st_template.dev_max * sizeof(ST_buffer *)); } } st_template.dev_max = 0; diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.3.22/linux/drivers/scsi/st.h Tue Sep 7 12:14:06 1999 +++ linux/drivers/scsi/st.h Tue Oct 19 11:57:45 1999 @@ -104,6 +104,7 @@ unsigned char density; unsigned char door_locked; unsigned char rew_at_close; + unsigned char inited; int block_size; int min_block; int max_block; diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h --- v2.3.22/linux/drivers/scsi/u14-34f.h Mon Oct 4 15:49:30 1999 +++ linux/drivers/scsi/u14-34f.h Fri Oct 22 12:47:52 1999 @@ -18,7 +18,9 @@ #define U14_34F_VERSION "5.11.00" +#ifndef LinuxVersionCode #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#endif #define ULTRASTOR_14_34F { \ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ diff -u --recursive --new-file v2.3.22/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c --- v2.3.22/linux/drivers/sgi/char/sgiserial.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/sgi/char/sgiserial.c Sat Oct 16 10:50:48 1999 @@ -408,6 +408,7 @@ show_state(); return; } else if (ch == 2) { + show_buffers(); return; } /* It is a 'keyboard interrupt' ;-) */ diff -u --recursive --new-file v2.3.22/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.3.22/linux/drivers/sound/dev_table.h Tue Aug 31 17:29:14 1999 +++ linux/drivers/sound/dev_table.h Thu Oct 21 13:38:12 1999 @@ -33,7 +33,7 @@ #define SNDCARD_WAVEFRONT 41 #define SNDCARD_OPL3SA2 42 #define SNDCARD_OPL3SA2_MPU 43 -#define SNDCARD_WAVEARTIST 44 /* Rebel Waveartist */ +#define SNDCARD_WAVEARTIST 44 /* Waveartist */ #define SNDCARD_OPL3SA2_MSS 45 /* Originally missed */ #define SNDCARD_AD1816 88 diff -u --recursive --new-file v2.3.22/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.3.22/linux/drivers/sound/maestro.c Fri Oct 15 15:25:14 1999 +++ linux/drivers/sound/maestro.c Mon Oct 18 11:26:31 1999 @@ -847,7 +847,7 @@ __maestro_write(ess->card,reg,data); - spin_unlock_irqrestore(&card->lock,flags); + spin_unlock_irqrestore(&ess->card->lock,flags); } static u16 __maestro_read(struct ess_card *card, u16 reg) diff -u --recursive --new-file v2.3.22/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.3.22/linux/drivers/sound/sound_core.c Thu Aug 26 13:05:39 1999 +++ linux/drivers/sound/sound_core.c Mon Oct 18 11:26:31 1999 @@ -58,6 +58,9 @@ #ifdef CONFIG_SOUND_MSNDPIN extern int msnd_pinnacle_init(void); #endif +#ifdef CONFIG_SOUND_CMPCI +extern init_cmpci(void); +#endif /* * Low level list operator. Scan the ordered list, find a hole and diff -u --recursive --new-file v2.3.22/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c --- v2.3.22/linux/drivers/sound/waveartist.c Thu Jun 17 01:11:35 1999 +++ linux/drivers/sound/waveartist.c Thu Oct 21 13:38:12 1999 @@ -1,14 +1,15 @@ /* - * drivers/sound/waveartist.c + * linux/drivers/sound/waveartist.c * * The low level driver for the RWA010 Rockwell Wave Artist - * codec chip used in the Corel Computer NetWinder. + * codec chip used in the Rebel.com NetWinder. * * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) + * and Pat Beirne (patb@corel.ca) */ /* - * Copyright (C) by Corel Computer 1998 + * Copyright (C) by Rebel.com 1998-1999 * * RWA010 specs received under NDA from Rockwell * @@ -29,19 +30,17 @@ #define debug_flg (0) -#define DEB(x) -#define DDB(x) -#define DEB1(x) - #include #include #include #include #include #include +#include #include #include +#include #include "soundmodule.h" #include "sound_config.h" @@ -54,45 +53,24 @@ #define _ISA_IRQ(x) (x) #endif -#define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec - -#define MIXER_PRIVATE3_RESET 0x53570000 -#define MIXER_PRIVATE3_READ 0x53570001 -#define MIXER_PRIVATE3_WRITE 0x53570002 - -#define VNC_INTERNAL_SPKR 0x01 //the sw mute on/off control bit -#define VNC_INTERNAL_MIC 0x10 //the hw internal/handset mic bit - -/* Use RECSRC = speaker to mark the internal microphone - * - * Some cheating involved here: there is no way to relay - * to the system, which microphone in in use - * (left = handset, or right = internal) - * - * So while I do not flag SPEAKER in the Recording Devices - * Mask, when on internal - * - * mike - I set the speaker bit hi. Some mixers can be - * confused a bit... - */ - -#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_LINE |\ - SOUND_MASK_MIC |\ - SOUND_MASK_LINE1) //Line1 = analog phone - -#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH |\ - SOUND_MASK_PCM |\ - SOUND_MASK_LINE |\ - SOUND_MASK_MIC | \ - SOUND_MASK_LINE1 |\ - SOUND_MASK_RECLEV |\ - SOUND_MASK_VOLUME) +#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_LINE |\ + SOUND_MASK_MIC |\ + SOUND_MASK_LINE1) + +#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH |\ + SOUND_MASK_PCM |\ + SOUND_MASK_LINE |\ + SOUND_MASK_MIC |\ + SOUND_MASK_LINE1 |\ + SOUND_MASK_RECLEV |\ + SOUND_MASK_VOLUME |\ + SOUND_MASK_IMIX) static unsigned short levels[SOUND_MIXER_NRDEVICES] = { 0x5555, /* Master Volume */ 0x0000, /* Bass */ 0x0000, /* Treble */ - 0x5555, /* Synth (FM) */ + 0x2323, /* Synth (FM) */ 0x4b4b, /* PCM */ 0x0000, /* PC Speaker */ 0x0000, /* Ext Line */ @@ -129,15 +107,20 @@ int dev_no; /* Mixer parameters */ - unsigned short *levels; - int handset_state; - signed int slider_vol; /* hardware slider volume */ + unsigned short *levels; /* cache of volume settings */ int recmask; /* currently enabled recording device! */ - int supported_devices; /* SUPPORTED_MIXER_DEVICES */ + int supported_devices; /* SUPPORTED_MIXER_DEVICES */ int rec_devices; /* POSSIBLE_RECORDING_DEVICES */ - int handset_mute_sw :1;/* 1 - handset controlled in sw */ - int use_slider :1;/* use slider setting for o/p vol */ - int mute_state :1; + +#ifdef CONFIG_ARCH_NETWINDER + signed int slider_vol; /* hardware slider volume */ + unsigned int handset_detect :1; + unsigned int telephone_detect:1; + unsigned int no_autoselect :1;/* handset/telephone autoselects a path */ + unsigned int spkr_mute_state :1;/* set by ioctl or autoselect */ + unsigned int line_mute_state :1;/* set by ioctl or autoselect */ + unsigned int use_slider :1;/* use slider setting for o/p vol */ +#endif } wavnc_info; typedef struct wavnc_port_info { @@ -147,271 +130,18 @@ int audio_format; } wavnc_port_info; -static int nr_waveartist_devs; -static wavnc_info adev_info[MAX_AUDIO_DEV]; - -static int waveartist_mixer_set(wavnc_info *devc, int whichDev, unsigned int level); - -/* - * Corel Netwinder specifics... - */ -static struct timer_list vnc_timer; -extern spinlock_t gpio_lock; - -static void -vnc_mute(wavnc_info *devc, int mute) -{ - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - cpld_modify(CPLD_UNMUTE, mute ? 0 : CPLD_UNMUTE); - spin_unlock_irqrestore(&gpio_lock, flags); - - devc->mute_state = mute; -} - -static int -vnc_volume_slider(wavnc_info *devc) -{ - static signed int old_slider_volume; - unsigned long flags; - signed int volume = 255; - - *CSR_TIMER1_LOAD = 0x00ffffff; - - save_flags(flags); - cli(); - - outb(0xFF, 0x201); - *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1; - - while (volume && (inb(0x201) & 0x01)) - volume--; - - *CSR_TIMER1_CNTL = 0; - - restore_flags(flags); - - volume = 0x00ffffff - *CSR_TIMER1_VALUE; - +static int nr_waveartist_devs; +static wavnc_info adev_info[MAX_AUDIO_DEV]; +static spinlock_t waveartist_lock = SPIN_LOCK_UNLOCKED; -#ifndef REVERSE - volume = 150 - (volume >> 5); -#else - volume = (volume >> 6) - 25; +#ifndef machine_is_netwinder +#define machine_is_netwinder() 0 #endif - if (volume < 0) - volume = 0; - - if (volume > 100) - volume = 100; - - /* - * slider quite often reads +-8, so debounce this random noise - */ - if ((volume - old_slider_volume) > 7 || - (old_slider_volume - volume) > 7) { - old_slider_volume = volume; - - DEB(printk("Slider volume: %d.\n", old_slider_volume)); - } - - return old_slider_volume; -} - -static int -vnc_slider(wavnc_info *devc) -{ - signed int slider_volume; - unsigned int temp; - - /* - * read the "buttons" state. - * Bit 4 = handset present, - * Bit 5 = offhook - */ - // the state should be "querable" via a private IOCTL call - temp = inb(0x201) & 0x30; - - if (!devc->handset_mute_sw && - (temp ^ devc->handset_state) & VNC_INTERNAL_MIC) { - devc->handset_state = temp; - devc->handset_mute_sw = 0; - - vnc_mute(devc, (temp & VNC_INTERNAL_MIC) ? 1 : 0); - } - - slider_volume = vnc_volume_slider(devc); - - /* - * If we're using software controlled volume, and - * the slider moves by more than 20%, then we - * switch back to slider controlled volume. - */ - if (devc->slider_vol > slider_volume) { - if (devc->slider_vol - slider_volume > 20) - devc->use_slider = 1; - } else { - if (slider_volume - devc->slider_vol > 20) - devc->use_slider = 1; - } - - /* - * use only left channel - */ - temp = levels[SOUND_MIXER_VOLUME] & 0xFF; - - if (slider_volume != temp && devc->use_slider) { - devc->slider_vol = slider_volume; - - waveartist_mixer_set(devc, SOUND_MIXER_VOLUME, - slider_volume | slider_volume << 8); - - return 1; - } - - return 0; -} - -static void -vnc_slider_tick(unsigned long data) -{ - int next_timeout; - - if (vnc_slider(adev_info + data)) - next_timeout = 5; // mixer reported change - else - next_timeout = VNC_TIMER_PERIOD; - - mod_timer(&vnc_timer, jiffies + next_timeout); -} - -static int -vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg) -{ - wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; - int val, temp; - - if (cmd == SOUND_MIXER_PRIVATE1) { - /* - * Use this call to override the automatic handset - * behaviour - ignore handset. - * bit 7 = total control over handset - do not - * to plug/unplug - * bit 4 = internal mic - * bit 0 = mute internal speaker - */ - if (get_user(val, (int *)arg)) - return -EFAULT; - - devc->handset_mute_sw = val; - - temp = val & VNC_INTERNAL_SPKR; - if (devc->mute_state != temp) - vnc_mute(devc, temp); - - devc->handset_state = val & VNC_INTERNAL_MIC; - waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC); - return 0; - } -#if 0 - if (cmd == SOUND_MIXER_PRIVATE2) { -#define VNC_SOUND_PAUSE 0x53 //to pause the DSP -#define VNC_SOUND_RESUME 0x57 //to unpause the DSP - int val; - - val = *(int *) arg; - - printk("MIXER_PRIVATE2: passed parameter = 0x%X.\n",val); - - if (val == VNC_SOUND_PAUSE) { - wa_sendcmd(0x16); //PAUSE the ADC - } else if (val == VNC_SOUND_RESUME) { - wa_sendcmd(0x18); //RESUME the ADC - } else { - return -EINVAL; //invalid parameters... - } - return 0; - } - - if (cmd == SOUND_MIXER_PRIVATE3) { - long unsigned flags; - int mixer_reg[15]; //reg 14 is actually a command: read,write,reset - - int val; - int i; - - val = *(int *) arg; - - if (verify_area(VERIFY_READ, (void *) val, sizeof(mixer_reg) == -EFAULT)) - return (-EFAULT); - - memcpy_fromfs(&mixer_reg, (void *) val, sizeof(mixer_reg)); - - if (mixer_reg[0x0E] == MIXER_PRIVATE3_RESET) { //reset command?? - wavnc_mixer_reset(devc); - return (0); - } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_WRITE) { //write command?? -// printk("WaveArtist Mixer: Private write command.\n"); - - wa_sendcmd(0x32); //Pair1 - word 1 and 5 - wa_sendcmd(mixer_reg[0]); - wa_sendcmd(mixer_reg[4]); - - wa_sendcmd(0x32); //Pair2 - word 2 and 6 - wa_sendcmd(mixer_reg[1]); - wa_sendcmd(mixer_reg[5]); - - wa_sendcmd(0x32); //Pair3 - word 3 and 7 - wa_sendcmd(mixer_reg[2]); - wa_sendcmd(mixer_reg[6]); - - wa_sendcmd(0x32); //Pair4 - word 4 and 8 - wa_sendcmd(mixer_reg[3]); - wa_sendcmd(mixer_reg[7]); - - wa_sendcmd(0x32); //Pair5 - word 9 and 10 - wa_sendcmd(mixer_reg[8]); - wa_sendcmd(mixer_reg[9]); - - wa_sendcmd(0x0031); //set left and right PCM - wa_sendcmd(mixer_reg[0x0A]); - wa_sendcmd(mixer_reg[0x0B]); - - wa_sendcmd(0x0131); //set left and right FM - wa_sendcmd(mixer_reg[0x0C]); - wa_sendcmd(mixer_reg[0x0D]); - - return 0; - } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_READ) { //read command? -// printk("WaveArtist Mixer: Private read command.\n"); - - //first read all current values... - save_flags(flags); - cli(); - - for (i = 0; i < 14; i++) { - wa_sendcmd((i << 8) + 0x30); // get ready for command nn30H - - while (!(inb(STATR) & CMD_RF)) { - }; //wait for response ready... - - mixer_reg[i] = inw(CMDR); - } - restore_flags(flags); - - if (verify_area(VERIFY_WRITE, (void *) val, sizeof(mixer_reg) == -EFAULT)) - return (-EFAULT); - - memcpy_tofs((void *) val, &mixer_reg, sizeof(mixer_reg)); - return 0; - } else - return -EINVAL; - } -#endif - return -EINVAL; -} +static struct timer_list vnc_timer; +static void vnc_configure_mixer(wavnc_info *devc); +static int vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg); +static void vnc_slider_tick(unsigned long data); static inline void waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set) @@ -472,7 +202,7 @@ } while (timeout--); if (timeout == 0) { - printk("WaveArtist: reset timeout "); + printk(KERN_WARNING "WaveArtist: reset timeout "); if (res != (unsigned int)-1) printk("(res=%04X)", res); printk("\n"); @@ -481,6 +211,10 @@ return 0; } +/* Helper function to send and receive words + * from WaveArtist. It handles all the handshaking + * and can send or receive multiple words. + */ static int waveartist_cmd(wavnc_info *devc, int nr_cmd, unsigned int *cmd, @@ -554,6 +288,32 @@ return timed_out ? 1 : 0; } +/* + * Send one command word + */ +static inline int +waveartist_cmd1(wavnc_info *devc, unsigned int cmd) +{ + return waveartist_cmd(devc, 1, &cmd, 0, NULL); +} + +/* + * Send one command, receive one word + */ +static inline unsigned int +waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd) +{ + unsigned int ret; + + waveartist_cmd(devc, 1, &cmd, 1, &ret); + + return ret; +} + +/* + * Send a double command, receive one + * word (and throw it away) + */ static inline int waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg) { @@ -562,11 +322,12 @@ vals[0] = cmd; vals[1] = arg; - waveartist_cmd(devc, 2, vals, 1, vals); - - return 0; + return waveartist_cmd(devc, 2, vals, 1, vals); } +/* + * Send a triple command + */ static inline int waveartist_cmd3(wavnc_info *devc, unsigned int cmd, unsigned int arg1, unsigned int arg2) @@ -581,72 +342,18 @@ } static int -waveartist_sendcmd(struct address_info *hw, unsigned int cmd) -{ - int count; - - if (debug_flg & DEBUG_CMD) - printk("waveartist_sendcmd: cmd=0x%04X...", cmd); - - udelay(10); - - if (inb(hw->io_base + STATR) & CMD_RF) { - /* - * flush the port - */ - count = inw(hw->io_base + CMDR); - - udelay(10); - - if (debug_flg & DEBUG_CMD) - printk(" flushed %04X...", count); - } - - /* - * preset timeout at 5000 loops - */ - count = 5000; - - while (count --) - if (inb(hw->io_base + STATR) & CMD_WE) { - /* wait till CMD_WE is high - * then output the command - */ - outw(cmd, hw->io_base + CMDR); - break; - } - - /* ready BEFORE timeout? - */ - if (debug_flg & DEBUG_CMD) - printk(" %s\n", count ? "Done OK." : "Error!"); - - udelay(10); - - return count ? 0 : 1; -} - -static int -waveartist_getrev(struct address_info *hw, char *rev) +waveartist_getrev(wavnc_info *devc, char *rev) { - int temp; + unsigned int temp[2]; + unsigned int cmd = WACMD_GETREV; - waveartist_sendcmd(hw, 0); - udelay(20); - temp = inw(hw->io_base + CMDR); - udelay(20); - inw(hw->io_base + CMDR); // discard second word == 0 + waveartist_cmd(devc, 1, &cmd, 2, temp); - rev[0] = temp >> 8; - rev[1] = temp & 255; + rev[0] = temp[0] >> 8; + rev[1] = temp[0] & 255; rev[2] = '\0'; - return temp; -} - -inline void -waveartist_mute(wavnc_info *devc, int mute) -{ + return temp[0]; } static void waveartist_halt_output(int dev); @@ -667,10 +374,9 @@ devc = (wavnc_info *) audio_devs[dev]->devc; portc = (wavnc_port_info *) audio_devs[dev]->portc; - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); if (portc->open_mode || (devc->open_mode & mode)) { - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); return -EBUSY; } @@ -683,13 +389,7 @@ devc->record_dev = dev; if (mode & OPEN_WRITE) devc->playback_dev = dev; - restore_flags(flags); - - /* - * Mute output until the playback really starts. This - * decreases clicking (hope so). - */ - waveartist_mute(devc, 1); + spin_unlock_irqrestore(&waveartist_lock, flags); return 0; } @@ -701,8 +401,7 @@ wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); waveartist_halt(dev); @@ -710,9 +409,7 @@ devc->open_mode &= ~portc->open_mode; portc->open_mode = 0; - waveartist_mute(devc, 1); - - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); } static void @@ -747,18 +444,17 @@ */ } - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); /* * set sample count */ - waveartist_cmd2(devc, 0x0024, count); + waveartist_cmd2(devc, WACMD_OUTPUTSIZE, count); devc->xfer_count = count; devc->audio_mode |= PCM_ENABLE_OUTPUT; - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); } static void @@ -791,19 +487,17 @@ */ } - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); /* * set sample count */ - waveartist_cmd2(devc, 0x0014, count); - waveartist_mute(devc, 0); + waveartist_cmd2(devc, WACMD_INPUTSIZE, count); devc->xfer_count = count; devc->audio_mode |= PCM_ENABLE_INPUT; - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); } static int @@ -869,40 +563,42 @@ speed = waveartist_get_speed(portc); bits = waveartist_get_bits(portc); - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", - portc->audio_format); + printk(KERN_WARNING "waveartist: error setting the " + "record format to %d\n", portc->audio_format); if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) - printk("waveartist: error setting record to %d channels\n", - portc->channels); + printk(KERN_WARNING "waveartist: error setting record " + "to %d channels\n", portc->channels); /* * write cmd SetSampleSpeedTimeConstant */ if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) - printk("waveartist: error setting the record speed " - "to %dHz.\n", portc->speed); + printk(KERN_WARNING "waveartist: error setting the record " + "speed to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) - printk("waveartist: error setting the record data path " - "to 0x%X\n", 1); + printk(KERN_WARNING "waveartist: error setting the record " + "data path to 0x%X\n", 1); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", - portc->audio_format); + printk(KERN_WARNING "waveartist: error setting the record " + "format to %d\n", portc->audio_format); devc->xfer_count = 0; - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); waveartist_halt_input(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk("WA CTLR reg: 0x%02X.\n", + inb(devc->hw.io_base + CTLR)); + printk("WA STAT reg: 0x%02X.\n", + inb(devc->hw.io_base + STATR)); + printk("WA IRQS reg: 0x%02X.\n", + inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -922,28 +618,27 @@ speed = waveartist_get_speed(portc); bits = waveartist_get_bits(portc); - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) - printk("waveartist: error setting the playback speed " - "to %dHz.\n", portc->speed); + printk(KERN_WARNING "waveartist: error setting the playback " + "speed to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) - printk("waveartist: error setting the playback to" - " %d channels\n", portc->channels); + printk(KERN_WARNING "waveartist: error setting the playback " + "to %d channels\n", portc->channels); if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) - printk("waveartist: error setting the playback data path " - "to 0x%X\n", 0); + printk(KERN_WARNING "waveartist: error setting the playback " + "data path to 0x%X\n", 0); if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) - printk("waveartist: error setting the playback format to %d\n", - portc->audio_format); + printk(KERN_WARNING "waveartist: error setting the playback " + "format to %d\n", portc->audio_format); devc->xfer_count = 0; - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); waveartist_halt_output(dev); if (debug_flg & DEBUG_INTR) { @@ -961,7 +656,6 @@ wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; wavnc_info *devc; - if (portc->open_mode & OPEN_WRITE) waveartist_halt_output(dev); @@ -978,19 +672,13 @@ wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; unsigned long flags; - save_flags(flags); - cli(); - - waveartist_mute(devc, 1); - -//RMK disable_dma(audio_devs[dev]->dmap_in->dma); + spin_lock_irqsave(&waveartist_lock, flags); /* * Stop capture */ - waveartist_sendcmd(&devc->hw, 0x17); + waveartist_cmd1(devc, WACMD_INPUTSTOP); -//RMK enable_dma(audio_devs[dev]->dmap_in->dma); devc->audio_mode &= ~PCM_ENABLE_INPUT; /* @@ -1002,7 +690,7 @@ // devc->audio_mode &= ~PCM_ENABLE_INPUT; - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); } static void @@ -1011,16 +699,9 @@ wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; unsigned long flags; - save_flags(flags); - cli(); - - waveartist_mute(devc, 1); - -//RMK disable_dma(audio_devs[dev]->dmap_out->dma); - - waveartist_sendcmd(&devc->hw, 0x27); + spin_lock_irqsave(&waveartist_lock, flags); -//RMK enable_dma(audio_devs[dev]->dmap_out->dma); + waveartist_cmd1(devc, WACMD_OUTPUTSTOP); devc->audio_mode &= ~PCM_ENABLE_OUTPUT; @@ -1033,7 +714,7 @@ // devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); } static void @@ -1052,8 +733,7 @@ printk("\n"); } - save_flags(flags); - cli(); + spin_lock_irqsave(&waveartist_lock, flags); state &= devc->audio_mode; @@ -1062,18 +742,16 @@ /* * enable ADC Data Transfer to PC */ - waveartist_sendcmd(&devc->hw, 0x15); + waveartist_cmd1(devc, WACMD_INPUTSTART); if (portc->open_mode & OPEN_WRITE && state & PCM_ENABLE_OUTPUT) /* * enable DAC data transfer from PC */ - waveartist_sendcmd(&devc->hw, 0x25); + waveartist_cmd1(devc, WACMD_OUTPUTSTART); - waveartist_mute(devc, 0); - - restore_flags(flags); + spin_unlock_irqrestore(&waveartist_lock, flags); } static int @@ -1158,7 +836,7 @@ if (status & IRQ_REQ) /* Clear interrupt */ waveartist_iack(devc); else - printk("waveartist: unexpected interrupt\n"); + printk(KERN_WARNING "waveartist: unexpected interrupt\n"); #ifdef CONFIG_AUDIO if (irqstatus & 0x01) { @@ -1175,12 +853,12 @@ temp = 0; } if (temp) //default: - printk("WaveArtist: Unknown interrupt\n"); + printk(KERN_WARNING "waveartist: Unknown interrupt\n"); } #endif if (irqstatus & 0x2) // We do not use SB mode natively... - printk("WaveArtist: Unexpected SB interrupt...\n"); + printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n"); } /* ------------------------------------------------------------------------- @@ -1198,6 +876,9 @@ #define SCALE(lev,max) ((lev) * (max) / 100) + if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT) + whichDev = SOUND_MIXER_VOLUME; + switch(whichDev) { case SOUND_MIXER_VOLUME: mask = 0x000e; @@ -1208,6 +889,8 @@ break; case SOUND_MIXER_LINE: + if ((devc->recmask & SOUND_MASK_LINE) == 0) + return; mask = 0x07c0; reg_l = 0x000; reg_r = 0x400; @@ -1216,6 +899,8 @@ break; case SOUND_MIXER_MIC: + if ((devc->recmask & SOUND_MASK_MIC) == 0) + return; mask = 0x0030; reg_l = 0x200; reg_r = 0x600; @@ -1232,6 +917,8 @@ break; case SOUND_MIXER_LINE1: + if ((devc->recmask & SOUND_MASK_LINE1) == 0) + return; mask = 0x003e; reg_l = 0x000; reg_r = 0x400; @@ -1240,12 +927,14 @@ break; case SOUND_MIXER_PCM: - waveartist_cmd3(devc, 0x0031, SCALE(lev_left, 32767), + waveartist_cmd3(devc, WACMD_SET_LEVEL, + SCALE(lev_left, 32767), SCALE(lev_right, 32767)); return; case SOUND_MIXER_SYNTH: - waveartist_cmd3(devc, 0x0131, SCALE(lev_left, 32767), + waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL, + SCALE(lev_left, 32767), SCALE(lev_right, 32767)); return; @@ -1254,7 +943,7 @@ } /* read left setting */ - vals[0] = reg_l + 0x30; + vals[0] = reg_l + WACMD_GET_LEVEL; waveartist_cmd(devc, 1, vals, 1, vals + 1); /* read right setting */ @@ -1265,7 +954,7 @@ vals[2] = (vals[2] & ~mask) | (lev_right & mask); /* write left,right back */ - vals[0] = 0x32; + vals[0] = WACMD_SET_MIXER; waveartist_cmd(devc, 3, vals, 0, NULL); } @@ -1273,20 +962,6 @@ waveartist_select_input(wavnc_info *devc, unsigned int input) { unsigned int vals[3]; -#if 1 - /* New mixer programming - switch recording source - * using R/L_ADC_Mux_Select. We are playing with - * left/right mux bit fields in reg 9. - * - * We can not switch Mux_Select while recording, so - * for microphones, enable both left and right and - * play with levels only! - * - * Unfortunately, we need to select the src of mono - * recording (left or right) before starting the - * recording - so can not dynamically switch between - * handset amd internal microphones... - */ /* * Get reg 9 @@ -1304,48 +979,14 @@ printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1] & 0x07, (vals[1] >> 3) & 0x07); - vals[1] &= ~0x03F; //kill current left/right mux input select + /* + * kill current left/right mux input select + */ + vals[1] &= ~0x03F; switch (input) { - /* - * Handset or internal MIC - */ case SOUND_MASK_MIC: /* - * handset not plugged in? - */ - if (devc->handset_state & VNC_INTERNAL_MIC) { - /* - * set mono recording from right mic - */ - waveartist_sendcmd(&devc->hw, 0x0134); -#if 0 - /* - * right=mic, left=none - */ - vals[1] |= 0x0028; - /* - * pretend int mic - */ - devc->rec_devices |= SOUND_MASK_SPEAKER; -#endif - } else { - /* - * set mono rec from left mic - */ - waveartist_sendcmd(&devc->hw, 0x0034); -#if 0 - /* - * right=none, left=mic - */ - vals[1] |= 0x0005; - /* - * show no int mic - */ - devc->rec_devices &= ~SOUND_MASK_SPEAKER; -#endif - } - /* * right=mic, left=mic */ vals[1] |= 0x002D; @@ -1353,10 +994,6 @@ case SOUND_MASK_LINE1: /* - * set mono rec from left aux1 - */ - waveartist_sendcmd(&devc->hw, 0x0034); - /* * right=none, left=Aux1; */ vals[1] |= 0x0004; @@ -1364,10 +1001,6 @@ case SOUND_MASK_LINE: /* - * set mono rec from left (default) - */ - waveartist_sendcmd(&devc->hw, 0x0034); - /* * right=Line, left=Line; */ vals[1] |= 0x0012; @@ -1378,101 +1011,10 @@ printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input, vals[1] & 0x07, (vals[1] >> 3) & 0x07); -#else - /* This part is good, if input connected to - * a mixer, so can be used for record-only modes... - */ - - /* - * get reg 4 - */ - vals[0] = 0x0330; - waveartist_cmd(devc, 1, vals, 1, vals + 1); - - /* - * get reg 8 - */ - vals[0] = 0x0730; - waveartist_cmd(devc, 1, vals, 1, vals + 2); - - if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", - vals[1], vals[2]); - - /* - * kill current left/right mux input select - */ - vals[1] &= ~0x07F8; - vals[2] &= ~0x07F8; - - switch (input) { - /* - * handset or internal mic - */ - case SOUND_MASK_MIC: - /* - * handset not plugged in? - */ - if (devc->handset_state & VNC_INTERNAL_MIC) { - /* - * set mono recording from right mic - */ - waveartist_sendcmd(&devc->hw, 0x0134); - /* - * left = none, right = mic, RX filter gain - */ - vals[1] |= 0x0C00; - vals[2] |= 0x0C88; - /* - * pretend int mic - */ - devc->rec_devices |= SOUND_MASK_SPEAKER; - } else { - /* - * set mono rec from left mic - */ - waveartist_sendcmd(&devc->hw, 0x0034); - /* - * left = mic, RX filter gain, right = none; - */ - vals[1] |= 0x0C88; - vals[2] |= 0x0C00; - /* - * show no int mic - */ - devc->rec_devices &= ~SOUND_MASK_SPEAKER; - } - break; - - case SOUND_MASK_LINE1: - /* - * set mono rec from left aux1 - */ - waveartist_sendcmd(&devc->hw, 0x0034); - /* - * left = Aux1, right = none - */ - vals[1] |= 0x0C40; - vals[2] |= 0x0C00; - break; - - case SOUND_MASK_LINE: - /* - * left = Line, right = Line - */ - vals[1] |= 0x0C10; - vals[2] |= 0x0C10; - break; - } - - if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", - level, vals[1], vals[2]); -#endif /* * and finally - write the reg pair back.... */ - vals[0] = 0x32; + vals[0] = WACMD_SET_MIXER; waveartist_cmd(devc, 3, vals, 0, NULL); } @@ -1482,8 +1024,7 @@ { unsigned int lev_left = level & 0x007f; unsigned int lev_right = (level & 0x7f00) >> 8; - - int left, right, devmask, changed, i; + int left, right, devmask; left = level & 0x7f; right = (level & 0x7f00) >> 8; @@ -1493,85 +1034,38 @@ whichDev, level); switch (whichDev) { - /* Master volume (0-7) - * We have 3 bits on the Left/Right Mixer Gain, - * bits 3,2,1 on 3 and 7 - */ - case SOUND_MIXER_VOLUME: + case SOUND_MIXER_VOLUME: /* master volume (0-7) */ + case SOUND_MIXER_LINE: /* external line (0-31) */ + case SOUND_MIXER_MIC: /* mono mic (0-3) */ + case SOUND_MIXER_RECLEV: /* recording level (0-7) */ + case SOUND_MIXER_LINE1: /* mono external aux1 (0-31) */ + case SOUND_MIXER_PCM: /* Waveartist PCM (0-32767) */ + case SOUND_MIXER_SYNTH: /* internal synth (0-31) */ + case SOUND_MIXER_IMIX: /* recording feedback */ devc->levels[whichDev] = lev_left | lev_right << 8; waveartist_mixer_update(devc, whichDev); break; - - /* External line (0-31) - * use LOUT/ROUT bits 10...6, reg 1 and 5 - */ - case SOUND_MIXER_LINE: - devc->levels[whichDev] = lev_left | lev_right << 8; - waveartist_mixer_update(devc, whichDev); - break; - - /* Mono microphone (0-3) mute, - * 0db,10db,20db - */ - case SOUND_MIXER_MIC: -#if 1 - devc->levels[whichDev] = lev_left | lev_right << 8; -#else - /* we do not need to mute volume of - * an unused mic - it is simply unused... - */ - if (devc->handset_state & VNC_INTERNAL_MIC) - devc->levels[whichDev] = lev_right << 8; - else - levels[whichDev] = lev_left; -#endif - waveartist_mixer_update(devc, whichDev); - break; - - /* Recording level (0-7) - */ - case SOUND_MIXER_RECLEV: - devc->levels[whichDev] = lev_left | lev_right << 8; - waveartist_mixer_update(devc, whichDev); - break; - - /* Mono External Aux1 (0-31) - * use LINE1 bits 5...1, reg 1 and 5 - */ - case SOUND_MIXER_LINE1: - devc->levels[whichDev] = lev_left | lev_right << 8; - waveartist_mixer_update(devc, whichDev); - break; - - /* WaveArtist PCM (0-32767) - */ - case SOUND_MIXER_PCM: - devc->levels[whichDev] = lev_left | lev_right << 8; - waveartist_mixer_update(devc, whichDev); - break; - - /* Internal synthesizer (0-31) - */ - case SOUND_MIXER_SYNTH: - devc->levels[whichDev] = lev_left | lev_right << 8; - waveartist_mixer_update(devc, whichDev); - break; - - /* Select recording input source */ case SOUND_MIXER_RECSRC: - devmask = level & POSSIBLE_RECORDING_DEVICES; + devmask = level & devc->rec_devices; - changed = devmask ^ devc->recmask; - devc->recmask = devmask; +#ifdef CONFIG_ARCH_NETWINDER + if (machine_is_netwinder()) + vnc_configure_mixer(devc); + else +#endif + { + waveartist_select_input(devc, level); - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (changed & (1 << i)) - waveartist_mixer_update(devc, i); + /* + * if record monitoring is on, make sure the bit is set + */ + if (devc->levels[SOUND_MIXER_IMIX]) + waveartist_mixer_update(devc, SOUND_MIXER_IMIX); + } - waveartist_select_input(devc, level); /* * do not save in "levels", return current setting */ @@ -1595,53 +1089,54 @@ /* * reset mixer cmd */ - waveartist_sendcmd(&devc->hw, 0x33); + waveartist_cmd1(devc, WACMD_RST_MIXER); /* - * set input for ADC to come from - * a mux (left and right) == reg 9, - * initially none + * set input for ADC to come from 'quiet' + * turn on default modes */ - waveartist_cmd3(devc, 0x0032, 0x9800, 0xa836); + waveartist_cmd3(devc, WACMD_SET_MIXER, 0x9800, 0xa836); /* * set mixer input select to none, RX filter gains 0 db */ - waveartist_cmd3(devc, 0x0032, 0x4c00, 0x8c00); + waveartist_cmd3(devc, WACMD_SET_MIXER, 0x4c00, 0x8c00); /* * set bit 0 reg 2 to 1 - unmute MonoOut */ - waveartist_cmd3(devc, 0x0032, 0x2801, 0x6800); - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - waveartist_mixer_update(devc, i); + waveartist_cmd3(devc, WACMD_SET_MIXER, 0x2801, 0x6800); /* set default input device = internal mic * current recording device = none - * no handset */ devc->recmask = 0; - devc->handset_state = VNC_INTERNAL_MIC; -// waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC); - /* - * start from enabling the hw setting - */ - devc->handset_mute_sw = 0; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + waveartist_mixer_update(devc, i); + devc->supported_devices = SUPPORTED_MIXER_DEVICES; devc->rec_devices = POSSIBLE_RECORDING_DEVICES; + + if (machine_is_netwinder()) { + devc->supported_devices |= SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT; + devc->rec_devices |= SOUND_MASK_PHONEIN; + } } static int waveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; + int ret; - if (cmd == SOUND_MIXER_PRIVATE1 || - cmd == SOUND_MIXER_PRIVATE2 || - cmd == SOUND_MIXER_PRIVATE3) - return vnc_private_ioctl(dev, cmd, arg); +#ifdef CONFIG_ARCH_NETWINDER + if (machine_is_netwinder()) { + ret = vnc_private_ioctl(dev, cmd, arg); + if (ret != -ENOIOCTLCMD) + return ret; + } +#endif if (((cmd >> 8) & 0xff) == 'M') { if (_SIOC_DIR(cmd) & _SIOC_WRITE) { @@ -1650,30 +1145,14 @@ if (get_user(val, (int *)arg)) return -EFAULT; - /* - * special case for master volume: if we - * received this call - switch from hw - * volume control to a software volume - * control, till the hw volume is modified - * to signal that user wants to be back in - * hardware... - */ - if ((cmd & 0xff) == SOUND_MIXER_VOLUME) - devc->use_slider = 0; - return waveartist_mixer_set(devc, cmd & 0xff, val); } else { - int ret; - /* * Return parameters */ switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: ret = devc->recmask; - - if (devc->handset_state & VNC_INTERNAL_MIC) - ret |= SOUND_MASK_SPEAKER; break; case SOUND_MIXER_DEVMASK: @@ -1700,7 +1179,7 @@ return -EINVAL; } - return put_user(ret, (int *)arg) ? -EINVAL : 0; + return put_user(ret, (int *)arg) ? -EFAULT : 0; } } @@ -1725,7 +1204,7 @@ sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name); - if (waveartist_getrev(&devc->hw, rev)) { + if (waveartist_getrev(devc, rev)) { strcat(dev_name, " rev. "); strcat(dev_name, rev); } @@ -1758,20 +1237,20 @@ waveartist_iack(devc); if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { - printk("%s: IRQ %d in use\n", + printk(KERN_ERR "%s: IRQ %d in use\n", devc->hw.name, devc->hw.irq); goto uninstall; } if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { - printk("%s: Can't allocate DMA%d\n", + printk(KERN_ERR "%s: Can't allocate DMA%d\n", devc->hw.name, devc->hw.dma); goto uninstall_irq; } if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { - printk("%s: can't allocate DMA%d\n", + printk(KERN_ERR "%s: can't allocate DMA%d\n", devc->hw.name, devc->hw.dma2); goto uninstall_dma; } @@ -1809,22 +1288,24 @@ wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { - printk("waveartist: too many audio devices\n"); + printk(KERN_WARNING "waveartist: too many audio devices\n"); return 0; } if (check_region(hw_config->io_base, 15)) { - printk("WaveArtist: I/O port conflict\n"); + printk(KERN_WARNING "WaveArtist: I/O port conflict\n"); return 0; } if (hw_config->irq > _ISA_IRQ(15) || hw_config->irq < _ISA_IRQ(0)) { - printk("WaveArtist: Bad IRQ %d\n", hw_config->irq); + printk(KERN_WARNING "WaveArtist: Bad IRQ %d\n", + hw_config->irq); return 0; } if (hw_config->dma != _ISA_DMA(3)) { - printk("WaveArtist: Bad DMA %d\n", hw_config->dma); + printk(KERN_WARNING "WaveArtist: Bad DMA %d\n", + hw_config->dma); return 0; } @@ -1864,15 +1345,18 @@ if (devc->dev_no < 0) release_region(hw->io_base, 15); else { - init_timer(&vnc_timer); - vnc_timer.function = vnc_slider_tick; - vnc_timer.expires = jiffies; - vnc_timer.data = nr_waveartist_devs; - add_timer(&vnc_timer); +#ifdef CONFIG_ARCH_NETWINDER + if (machine_is_netwinder()) { + init_timer(&vnc_timer); + vnc_timer.function = vnc_slider_tick; + vnc_timer.expires = jiffies; + vnc_timer.data = nr_waveartist_devs; + add_timer(&vnc_timer); + vnc_configure_mixer(devc); + } +#endif nr_waveartist_devs += 1; - - vnc_mute(devc, 0); } } @@ -1891,6 +1375,11 @@ if (devc != NULL) { int mixer; +#ifdef CONFIG_ARCH_NETWINDER + if (machine_is_netwinder()) + del_timer(&vnc_timer); +#endif + release_region(devc->hw.io_base, 15); waveartist_set_ctlr(&devc->hw, DMA1_IE|DMA0_IE, 0); @@ -1904,8 +1393,6 @@ devc->hw.dma2 != NO_DMA) sound_free_dma(devc->hw.dma2); - del_timer(&vnc_timer); - mixer = audio_devs[devc->dev_no]->mixer_dev; if (mixer >= 0) @@ -1919,7 +1406,356 @@ for (; i < nr_waveartist_devs; i++) adev_info[i] = adev_info[i + 1]; } else - printk("waveartist: can't find device to unload\n"); + printk(KERN_WARNING "waveartist: can't find device " + "to unload\n"); +} + +/* + * Rebel.com Netwinder specifics... + */ + +#define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec + +#define MIXER_PRIVATE3_RESET 0x53570000 +#define MIXER_PRIVATE3_READ 0x53570001 +#define MIXER_PRIVATE3_WRITE 0x53570002 + +#define VNC_MUTE_INTERNAL_SPKR 0x01 //the sw mute on/off control bit +#define VNC_MUTE_LINE_OUT 0x10 +#define VNC_PHONE_DETECT 0x20 +#define VNC_HANDSET_DETECT 0x40 +#define VNC_DISABLE_AUTOSWITCH 0x80 + +extern spinlock_t gpio_lock; + +static inline void +vnc_update_spkr_mute(wavnc_info *devc) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE); + spin_unlock_irqrestore(&gpio_lock, flags); +} + +static void +vnc_mute_lout(wavnc_info *devc, int mute) +{ +} + +static int +vnc_volume_slider(wavnc_info *devc) +{ + static signed int old_slider_volume; + unsigned long flags; + signed int volume = 255; + + *CSR_TIMER1_LOAD = 0x00ffffff; + + save_flags(flags); + cli(); + + outb(0xFF, 0x201); + *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1; + + while (volume && (inb(0x201) & 0x01)) + volume--; + + *CSR_TIMER1_CNTL = 0; + + restore_flags(flags); + + volume = 0x00ffffff - *CSR_TIMER1_VALUE; + + +#ifndef REVERSE + volume = 150 - (volume >> 5); +#else + volume = (volume >> 6) - 25; +#endif + + if (volume < 0) + volume = 0; + + if (volume > 100) + volume = 100; + + /* + * slider quite often reads +-8, so debounce this random noise + */ + if (abs(volume - old_slider_volume) > 7) { + old_slider_volume = volume; + + if (debug_flg & DEBUG_MIXER) + printk(KERN_DEBUG "Slider volume: %d.\n", volume); + } + + return old_slider_volume; +} + +static void +vnc_configure_mixer(wavnc_info *devc) +{ + u_int vals[3]; + + if (!devc->no_autoselect) { + if (devc->handset_detect) { + devc->recmask = SOUND_MASK_LINE1; + devc->spkr_mute_state = devc->line_mute_state = 1; + } else if (devc->telephone_detect) { + devc->recmask = SOUND_MASK_PHONEIN; + devc->spkr_mute_state = devc->line_mute_state = 1; + } else { + /* unless someone has asked for LINE-IN, + * we default to MIC + */ + if ((devc->recmask & SOUND_MASK_LINE) == 0) + devc->recmask = SOUND_MASK_MIC; + devc->spkr_mute_state = devc->line_mute_state = 0; + } + vnc_update_spkr_mute(devc); + vnc_mute_lout(devc, devc->spkr_mute_state); + } + + /* Ok. At this point, we have done the autoswitch logic, or we + * have had a command from an ioctl. We have a valid devc->recmask. + * Now we have to connect up the hardware to reflect the recmask. + */ + vals[1] = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x800); + vals[2] = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x900); + + vals[1] &= ~0x3f; + + switch(devc->recmask) { + case SOUND_MASK_MIC: /* builtin mic */ + waveartist_cmd1(devc, WACMD_SET_MONO | 0x100); /* right */ + vals[1] |= 0x28; + break; + + case SOUND_MASK_LINE1: /* out handset */ + waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ + vals[1] |= 0x05; + break; + + case SOUND_MASK_PHONEIN: /* our telephone mic */ + waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ + vals[1] |= 0x04; + break; + + case SOUND_MASK_LINE: /* stereo line in */ + vals[1] |= 12; + break; + + default: + return; + } + + vals[0] = WACMD_SET_MIXER; + waveartist_cmd(devc, 3, vals, 0, NULL); + + waveartist_mixer_update(devc, SOUND_MIXER_IMIX); +} + +static int +vnc_slider(wavnc_info *devc) +{ + signed int slider_volume; + unsigned int temp, old_hs, old_td; + + /* + * read the "buttons" state. + * Bit 4 = handset present, + * Bit 5 = offhook + */ + temp = inb(0x201) & 0x30; + + old_hs = devc->handset_detect; + old_td = devc->telephone_detect; + + devc->handset_detect = !(temp & 0x10); + devc->telephone_detect = !!(temp & 0x20); + + if (!devc->no_autoselect && + (old_hs != devc->handset_detect || + old_td != devc->telephone_detect)) + vnc_configure_mixer(devc); + + slider_volume = vnc_volume_slider(devc); + + /* + * If we're using software controlled volume, and + * the slider moves by more than 20%, then we + * switch back to slider controlled volume. + */ + if (abs(devc->slider_vol - slider_volume) > 20) + devc->use_slider = 1; + + /* + * use only left channel + */ + temp = levels[SOUND_MIXER_VOLUME] & 0xFF; + + if (slider_volume != temp && devc->use_slider) { + devc->slider_vol = slider_volume; + + waveartist_mixer_set(devc, SOUND_MIXER_VOLUME, + slider_volume | slider_volume << 8); + + return 1; + } + + return 0; +} + +static void +vnc_slider_tick(unsigned long data) +{ + int next_timeout; + + if (vnc_slider(adev_info + data)) + next_timeout = 5; // mixer reported change + else + next_timeout = VNC_TIMER_PERIOD; + + mod_timer(&vnc_timer, jiffies + next_timeout); +} + +static int +vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; + int val; + + switch (cmd) { + case SOUND_MIXER_PRIVATE1: + { + u_int prev_spkr_mute, prev_line_mute, prev_auto_state; + int val; + + get_user_ret(val, (int *)arg, -EFAULT); + + /* check if parameter is logical */ + if (val & ~(VNC_MUTE_INTERNAL_SPKR | + VNC_MUTE_LINE_OUT | + VNC_DISABLE_AUTOSWITCH)) + return -EINVAL; + + prev_auto_state = devc->no_autoselect; + prev_spkr_mute = devc->spkr_mute_state; + prev_line_mute = devc->line_mute_state; + + devc->no_autoselect = (val & VNC_DISABLE_AUTOSWITCH) ? 1 : 0; + devc->spkr_mute_state = (val & VNC_MUTE_INTERNAL_SPKR) ? 1 : 0; + devc->line_mute_state = (val & VNC_MUTE_LINE_OUT) ? 1 : 0; + + if (prev_spkr_mute != devc->spkr_mute_state) + vnc_update_spkr_mute(devc); + + if (prev_line_mute != devc->line_mute_state) + vnc_mute_lout(devc, devc->line_mute_state); + + if (prev_auto_state != devc->no_autoselect) + vnc_configure_mixer(devc); + waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC); + return 0; + } + + case SOUND_MIXER_PRIVATE2: + get_user_ret(val, (int *)arg, -EFAULT); + + switch (val) { +#define VNC_SOUND_PAUSE 0x53 //to pause the DSP +#define VNC_SOUND_RESUME 0x57 //to unpause the DSP + case VNC_SOUND_PAUSE: + waveartist_cmd1(devc, 0x16); + break; + + case VNC_SOUND_RESUME: + waveartist_cmd1(devc, 0x18); + break; + + default: + return -EINVAL; + } + return 0; + + /* private ioctl to allow bulk access to waveartist */ + case SOUND_MIXER_PRIVATE3: + { + unsigned long flags; + int mixer_reg[15], i, val; + + get_user_ret(val, (int *)arg, -EFAULT); + copy_from_user_ret(mixer_reg, (void *)val, sizeof(mixer_reg), -EFAULT); + + switch (mixer_reg[14]) { + case MIXER_PRIVATE3_RESET: + waveartist_mixer_reset(devc); + break; + + case MIXER_PRIVATE3_WRITE: + waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[0], mixer_reg[4]); + waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[1], mixer_reg[5]); + waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[2], mixer_reg[6]); + waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[3], mixer_reg[7]); + waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[8], mixer_reg[9]); + + waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[10], mixer_reg[11]); + waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[12], mixer_reg[13]); + break; + + case MIXER_PRIVATE3_READ: + spin_lock_irqsave(&waveartist_lock, flags); + + for (i = 0x30; i < 14 << 8; i += 1 << 8) + waveartist_cmd(devc, 1, &i, 1, mixer_reg + (i >> 8)); + + spin_unlock_irqrestore(&waveartist_lock, flags); + + copy_to_user_ret((void *)val, mixer_reg, sizeof(mixer_reg), -EFAULT); + break; + + default: + return -EINVAL; + } + return 0; + } + + /* read back the state from PRIVATE1 */ + case SOUND_MIXER_PRIVATE4: + val = (devc->spkr_mute_state ? VNC_MUTE_INTERNAL_SPKR : 0) | + (devc->line_mute_state ? VNC_MUTE_LINE_OUT : 0) | + (devc->handset_detect ? VNC_HANDSET_DETECT : 0) | + (devc->telephone_detect ? VNC_PHONE_DETECT : 0) | + (devc->no_autoselect ? VNC_DISABLE_AUTOSWITCH : 0); + + return put_user(val, (int *)arg) ? -EFAULT : 0; + } + + if (((cmd >> 8) & 0xff) == 'M') { + if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + /* + * special case for master volume: if we + * received this call - switch from hw + * volume control to a software volume + * control, till the hw volume is modified + * to signal that user wants to be back in + * hardware... + */ + if ((cmd & 0xff) == SOUND_MIXER_VOLUME) + devc->use_slider = 0; + } else if ((cmd & 0xff) == SOUND_MIXER_STEREODEVS) { + val = devc->supported_devices & + ~(SOUND_MASK_IMIX | + SOUND_MASK_MIC | + SOUND_MASK_LINE1 | + SOUND_MASK_PHONEIN | + SOUND_MASK_PHONEOUT); + return put_user(val, (int *)arg) ? -EFAULT : 0; + } + } + + return -ENOIOCTLCMD; } #ifdef MODULE diff -u --recursive --new-file v2.3.22/linux/drivers/sound/waveartist.h linux/drivers/sound/waveartist.h --- v2.3.22/linux/drivers/sound/waveartist.h Thu Jun 17 01:11:35 1999 +++ linux/drivers/sound/waveartist.h Thu Oct 21 13:38:12 1999 @@ -1,5 +1,8 @@ - -// def file for Rockwell RWA010 chip set, as installed in Corel NetWinder +/* + * linux/drivers/sound/waveartist.h + * + * def file for Rockwell RWA010 chip set, as installed in Rebel.com NetWinder + */ //registers #define CMDR 0 @@ -33,7 +36,8 @@ //commands -#define WACMD_SYSTEMID 0 +#define WACMD_SYSTEMID 0x00 +#define WACMD_GETREV 0x00 #define WACMD_INPUTFORMAT 0x10 //0-8S, 1-16S, 2-8U #define WACMD_INPUTCHANNELS 0x11 //1-Mono, 2-Stereo #define WACMD_INPUTSPEED 0x12 //sampling rate @@ -56,8 +60,11 @@ #define WACMD_OUTPUTRESUME 0x28 //resume ADC #define WACMD_OUTPUTPIO 0x29 //PIO ADC +#define WACMD_GET_LEVEL 0x30 +#define WACMD_SET_LEVEL 0x31 +#define WACMD_SET_MIXER 0x32 +#define WACMD_RST_MIXER 0x33 +#define WACMD_SET_MONO 0x34 - - -int wa_sendcmd(unsigned int cmd); -int wa_writecmd(unsigned int cmd, unsigned int arg); +int wa_sendcmd(unsigned int cmd); +int wa_writecmd(unsigned int cmd, unsigned int arg); diff -u --recursive --new-file v2.3.22/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c --- v2.3.22/linux/drivers/usb/cpia.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/usb/cpia.c Sat Oct 16 19:15:32 1999 @@ -356,7 +356,7 @@ int i; int y, u, y1, v, r, g, b; - /* We want atleast 2 bytes for the length */ + /* We want at least 2 bytes for the length */ if (scratch_left(data) < 2) goto out; @@ -536,8 +536,9 @@ return totlen; } -static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id) +static int cpia_isoc_irq(int status, void *__buffer, int len, void *isocdesc) { + void *dev_id = ((struct usb_isoc_desc *)isocdesc)->context; struct usb_cpia *cpia = (struct usb_cpia *)dev_id; struct cpia_sbuf *sbuf; int i; @@ -584,6 +585,12 @@ cpia->cursbuf = 0; cpia->scratchlen = 0; + /* Alternate interface 3 is is the biggest frame size */ + if (usb_set_interface(cpia->dev, 1, 3) < 0) { + printk("usb_set_interface error\n"); + return -EBUSY; + } + /* We double buffer the Iso lists */ err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC, cpia, &cpia->sbuf[0].isodesc); @@ -618,7 +625,7 @@ for (fx = 0; fx < FRAMES_PER_DESC; fx++) id->frames[fx].frame_length = FRAME_SIZE_PER_DESC; - /* and the desc. [1] */ + /* and for desc. [1] */ id = cpia->sbuf[1].isodesc; id->start_type = 0; /* will follow the first desc. */ id->callback_frames = 10; /* on every 10th frame */ @@ -628,17 +635,16 @@ for (fx = 0; fx < FRAMES_PER_DESC; fx++) id->frames[fx].frame_length = FRAME_SIZE_PER_DESC; - usb_run_isoc(cpia->sbuf[0].isodesc, NULL); - usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc); + err = usb_run_isoc(cpia->sbuf[0].isodesc, NULL); + if (err) + printk(KERN_ERR "CPiA USB driver error (%d) on usb_run_isoc\n", err); + err = usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc); + if (err) + printk(KERN_ERR "CPiA USB driver error (%d) on usb_run_isoc\n", err); #ifdef CPIA_DEBUG printk("done scheduling\n"); #endif - /* Alternate interface 3 is is the biggest frame size */ - if (usb_set_interface(cpia->dev, 1, 3) < 0) { - printk("usb_set_interface error\n"); - return -EBUSY; - } #if 0 if (usb_cpia_grab_frame(dev, 120) < 0) { @@ -915,11 +921,8 @@ p.brightness = 180 << 8; /* XXX */ p.contrast = 192 << 8; /* XXX */ p.whiteness = 105 << 8; /* XXX */ -#if 0 p.depth = 24; -#endif - p.depth = 16; - p.palette = VIDEO_PALETTE_YUYV; + p.palette = VIDEO_PALETTE_RGB24; if (copy_to_user(arg, &p, sizeof(p))) return -EFAULT; @@ -940,6 +943,8 @@ #ifdef CPIA_DEBUG printk("Attempting to set palette %d, depth %d\n", p.palette, p.depth); + printk("SPICT: brightness=%d, hue=%d, colour=%d, contrast=%d, whiteness=%d\n", + p.brightness, p.hue, p.colour, p.contrast, p.whiteness); #endif return 0; @@ -1009,7 +1014,6 @@ { struct video_mmap vm; - if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) return -EFAULT; @@ -1090,11 +1094,26 @@ return cpia_new_frame(cpia, -1); } + case VIDIOCGFBUF: + { + struct video_buffer vb; + +#ifdef CPIA_DEBUG + printk("GFBUF\n"); +#endif + + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; /* frame buffer not supported, not used */ + + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; + + return 0; + } case VIDIOCKEY: return 0; case VIDIOCCAPTURE: return -EINVAL; - case VIDIOCGFBUF: case VIDIOCSFBUF: return -EINVAL; case VIDIOCGTUNER: @@ -1333,4 +1352,3 @@ usb_cpia_cleanup(); } #endif - diff -u --recursive --new-file v2.3.22/linux/drivers/usb/hp_scanner.c linux/drivers/usb/hp_scanner.c --- v2.3.22/linux/drivers/usb/hp_scanner.c Fri Oct 15 15:25:14 1999 +++ linux/drivers/usb/hp_scanner.c Sat Oct 16 19:15:32 1999 @@ -192,7 +192,7 @@ if (partial) { count = this_read = partial; - } else if (result == USB_ST_TIMEOUT || result == 15) { + } else if (result == USB_ST_TIMEOUT || result == 15) { /* FIXME: 15 ??? */ if(!maxretry--) { printk(KERN_DEBUG "read_scanner: maxretry timeout\n"); return -ETIME; diff -u --recursive --new-file v2.3.22/linux/drivers/usb/inits.h linux/drivers/usb/inits.h --- v2.3.22/linux/drivers/usb/inits.h Sat Oct 9 11:47:50 1999 +++ linux/drivers/usb/inits.h Sat Oct 16 19:15:32 1999 @@ -1,13 +1,14 @@ -int usb_kbd_init(void); +int usb_acm_init(void); int usb_audio_init(void); int usb_hub_init(void); -int usb_acm_init(void); -int usb_printer_init(void); void usb_hub_cleanup(void); +int usb_kbd_init(void); +void usb_major_init(void); void usb_mouse_cleanup(void); -int usb_scsi_init(void); int usb_hp_scanner_init(void); void usb_hp_scanner_cleanup(void); +int usb_printer_init(void); int proc_usb_init (void); void proc_usb_cleanup (void); +int usb_scsi_init(void); int usb_serial_init (void); diff -u --recursive --new-file v2.3.22/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.3.22/linux/drivers/usb/printer.c Fri Oct 15 15:25:14 1999 +++ linux/drivers/usb/printer.c Tue Oct 19 10:27:12 1999 @@ -25,37 +25,47 @@ #define NAK_TIMEOUT (HZ) /* stall wait for printer */ #define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT) /* should not take 1 minute a page! */ +#define BIG_BUF_SIZE 8192 + +/* + * USB Printer Requests + */ +#define USB_PRINTER_REQ_GET_DEVICE_ID 0 +#define USB_PRINTER_REQ_GET_PORT_STATUS 1 +#define USB_PRINTER_REQ_SOFT_RESET 2 + #define MAX_PRINTERS 8 struct pp_usb_data { struct usb_device *pusb_dev; - __u8 isopen; /* nz if open */ - __u8 noinput; /* nz if no input stream */ + __u8 isopen; /* True if open */ + __u8 noinput; /* True if no input stream */ __u8 minor; /* minor number of device */ __u8 status; /* last status from device */ int maxin, maxout; /* max transfer size in and out */ char *obuf; /* transfer buffer (out only) */ wait_queue_head_t wait_q; /* for timeouts */ unsigned int last_error; /* save for checking */ + int bulk_in_ep; /* Bulk IN endpoint */ + int bulk_out_ep; /* Bulk OUT endpoint */ + int bulk_in_index; /* endpoint[bulk_in_index] */ + int bulk_out_index; /* endpoint[bulk_out_index] */ }; static struct pp_usb_data *minor_data[MAX_PRINTERS]; #define PPDATA(x) ((struct pp_usb_data *)(x)) -unsigned char printer_read_status(struct pp_usb_data *p) +static unsigned char printer_read_status(struct pp_usb_data *p) { __u8 status; - devrequest dr; struct usb_device *dev = p->pusb_dev; - dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80; - dr.request = 1; - dr.value = 0; - dr.index = 0; - dr.length = 1; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1, HZ)) { - return 0; + if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0), + USB_PRINTER_REQ_GET_PORT_STATUS, + USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN, + 0, 0, &status, 1, HZ)) { + return 0; } return status; } @@ -90,24 +100,21 @@ return status; } -void printer_reset(struct pp_usb_data *p) +static void printer_reset(struct pp_usb_data *p) { - devrequest dr; struct usb_device *dev = p->pusb_dev; - dr.requesttype = USB_TYPE_CLASS | USB_RECIP_OTHER; - dr.request = 2; - dr.value = 0; - dr.index = 0; - dr.length = 0; - dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0, HZ); + usb_control_msg(dev, usb_sndctrlpipe(dev,0), + USB_PRINTER_REQ_SOFT_RESET, + USB_TYPE_CLASS | USB_RECIP_OTHER, + 0, 0, NULL, 0, HZ); } static int open_printer(struct inode * inode, struct file * file) { struct pp_usb_data *p; - if(MINOR(inode->i_rdev) >= MAX_PRINTERS || + if (MINOR(inode->i_rdev) >= MAX_PRINTERS || !minor_data[MINOR(inode->i_rdev)]) { return -ENODEV; } @@ -141,7 +148,7 @@ p->isopen = 0; file->private_data = NULL; /* free the resources if the printer is no longer around */ - if(!p->pusb_dev) { + if (!p->pusb_dev) { minor_data[p->minor] = NULL; kfree(p); } @@ -158,12 +165,7 @@ unsigned long partial; int result = USB_ST_NOERROR; int maxretry; - int endpoint_num; - struct usb_interface_descriptor *interface; - interface = p->pusb_dev->config->interface->altsetting; - endpoint_num = (interface->endpoint[1].bEndpointAddress & 0x0f); - do { char *obuf = p->obuf; unsigned long thistime; @@ -179,7 +181,7 @@ return bytes_written ? bytes_written : -EINTR; } result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev, - usb_sndbulkpipe(p->pusb_dev, endpoint_num), + usb_sndbulkpipe(p->pusb_dev, p->bulk_out_ep), obuf, thistime, &partial, HZ*20); if (partial) { obuf += partial; @@ -187,7 +189,7 @@ maxretry = MAX_RETRY_COUNT; } if (result == USB_ST_TIMEOUT) { /* NAK - so hold for a while */ - if(!maxretry--) + if (!maxretry--) return -ETIME; interruptible_sleep_on_timeout(&p->wait_q, NAK_TIMEOUT); continue; @@ -214,21 +216,15 @@ char * buffer, size_t count, loff_t *ppos) { struct pp_usb_data *p = file->private_data; - int read_count; + int read_count = 0; int this_read; char buf[64]; unsigned long partial; int result; - int endpoint_num; - struct usb_interface_descriptor *interface; - interface = p->pusb_dev->config->interface->altsetting; - endpoint_num = (interface->endpoint[0].bEndpointAddress & 0x0f); - if (p->noinput) return -EINVAL; - read_count = 0; while (count) { if (signal_pending(current)) { return read_count ? read_count : -EINTR; @@ -238,7 +234,7 @@ this_read = (count > sizeof(buf)) ? sizeof(buf) : count; result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev, - usb_rcvbulkpipe(p->pusb_dev, endpoint_num), + usb_rcvbulkpipe(p->pusb_dev, p->bulk_in_ep), buf, this_read, &partial, HZ*20); /* unlike writes, we don't retry a NAK, just stop now */ @@ -266,8 +262,8 @@ /* * FIXME - this will not cope with combined printer/scanners */ - if ((dev->descriptor.bDeviceClass != 7 && - dev->descriptor.bDeviceClass != 0) || + if ((dev->descriptor.bDeviceClass != USB_CLASS_PRINTER && + dev->descriptor.bDeviceClass != 0) || dev->descriptor.bNumConfigurations != 1 || dev->config[0].bNumInterfaces != 1) { return -1; @@ -275,34 +271,50 @@ interface = &dev->config[0].interface[0].altsetting[0]; - /* Lets be paranoid (for the moment)*/ - if (interface->bInterfaceClass != 7 || + /* Let's be paranoid (for the moment). */ + if (interface->bInterfaceClass != USB_CLASS_PRINTER || interface->bInterfaceSubClass != 1 || - (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1)|| + (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1) || interface->bNumEndpoints > 2) { return -1; } - if ((interface->endpoint[0].bEndpointAddress & 0xf0) != 0x00 || - interface->endpoint[0].bmAttributes != 0x02 || - (interface->bNumEndpoints > 1 && ( - (interface->endpoint[1].bEndpointAddress & 0xf0) != 0x80 || - interface->endpoint[1].bmAttributes != 0x02))) { + /* Does this (these) interface(s) support bulk transfers? */ + if ((interface->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_BULK) { + return -1; + } + if ((interface->bNumEndpoints > 1) && + ((interface->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_BULK)) { return -1; } + /* + * Does this interface have at least one OUT endpoint + * that we can write to: endpoint index 0 or 1? + */ + if ((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) + != USB_DIR_OUT && + (interface->bNumEndpoints > 1 && + (interface->endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) + != USB_DIR_OUT)) { + return -1; + } + for (i=0; i= MAX_PRINTERS) { + printk("No minor table space available for USB Printer\n"); return -1; } printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum); if (!(dev->private = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) { - printk( KERN_DEBUG "usb_printer: no memory!\n"); + printk(KERN_DEBUG "usb_printer: no memory!\n"); return -1; } @@ -310,48 +322,63 @@ minor_data[i] = PPDATA(dev->private); minor_data[i]->minor = i; minor_data[i]->pusb_dev = dev; - /* The max packet size can't be more than 64 (& will be 64 for - * any decent bulk device); this calculation was silly. -greg - * minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16; - */ - minor_data[i]->maxout = 8192; - if (minor_data[i]->maxout > PAGE_SIZE) { - minor_data[i]->maxout = PAGE_SIZE; - } - if (interface->bInterfaceProtocol != 2) + minor_data[i]->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE; + if (interface->bInterfaceProtocol != 2) /* if not bidirectional */ minor_data[i]->noinput = 1; - else { - minor_data[i]->maxin = interface->endpoint[1].wMaxPacketSize; + + minor_data[i]->bulk_out_index = + ((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_OUT) ? 0 : 1; + minor_data[i]->bulk_in_index = minor_data[i]->noinput ? -1 : + (minor_data[i]->bulk_out_index == 0) ? 1 : 0; + minor_data[i]->bulk_in_ep = minor_data[i]->noinput ? -1 : + interface->endpoint[minor_data[i]->bulk_in_index].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + minor_data[i]->bulk_out_ep = + interface->endpoint[minor_data[i]->bulk_out_index].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + if (interface->bInterfaceProtocol == 2) { /* if bidirectional */ + minor_data[i]->maxin = + interface->endpoint[minor_data[i]->bulk_in_index].wMaxPacketSize; } if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { printk(KERN_INFO " Failed usb_set_configuration: printer\n"); return -1; } + + printk(KERN_INFO "USB Printer Summary:\n"); + printk(KERN_INFO "index=%d, maxout=%d, noinput=%d\n", + i, minor_data[i]->maxout, minor_data[i]->noinput); + printk(KERN_INFO "bulk_in_ix=%d, bulk_in_ep=%d, bulk_out_ix=%d, bulk_out_ep=%d\n", + minor_data[i]->bulk_in_index, + minor_data[i]->bulk_in_ep, + minor_data[i]->bulk_out_index, + minor_data[i]->bulk_out_ep); + #if 0 { __u8 status; __u8 ieee_id[64]; - devrequest dr; - /* Lets get the device id if possible */ - dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80; - dr.request = 0; - dr.value = 0; - dr.index = 0; - dr.length = sizeof(ieee_id) - 1; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1, HZ) == 0) { + /* Let's get the device id if possible. */ + if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0), + USB_PRINTER_REQ_GET_DEVICE_ID, + USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN, + 0, 0, ieee_id, + sizeof(ieee_id)-1, HZ) == 0) { if (ieee_id[1] < sizeof(ieee_id) - 1) ieee_id[ieee_id[1]+2] = '\0'; else ieee_id[sizeof(ieee_id)-1] = '\0'; - printk(KERN_INFO " Printer ID is %s\n", &ieee_id[2]); + printk(KERN_INFO " USB Printer ID is %s\n", + &ieee_id[2]); } status = printer_read_status(PPDATA(dev->private)); printk(KERN_INFO " Status is %s,%s,%s\n", - (status & 0x10) ? "Selected" : "Not Selected", - (status & 0x20) ? "No Paper" : "Paper", - (status & 0x08) ? "No Error" : "Error"); + (status & LP_PSELECD) ? "Selected" : "Not Selected", + (status & LP_POUTPA) ? "No Paper" : "Paper", + (status & LP_PERRORP) ? "No Error" : "Error"); } #endif return 0; @@ -397,7 +424,13 @@ int usb_printer_init(void) { - usb_register(&printer_driver); + if (usb_register(&printer_driver)) { + printk(KERN_ERR "USB Printer driver cannot register: " + "minor number %d already in use\n", + printer_driver.minor); + return 1; + } + printk(KERN_INFO "USB Printer support registered.\n"); return 0; } diff -u --recursive --new-file v2.3.22/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.22/linux/drivers/usb/uhci.c Fri Oct 15 15:25:14 1999 +++ linux/drivers/usb/uhci.c Fri Oct 22 10:48:19 1999 @@ -91,7 +91,7 @@ /* * Map status to standard result codes * - * is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status) + * is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)] * is True for output TDs and False for input TDs. */ static int uhci_map_status(int status, int dir_out) @@ -127,7 +127,7 @@ { unsigned int status; struct uhci_td *tmp; - int count = 1000, bytesreceived = 0; + int count = 1000, actlength, explength; if (rval) *rval = 0; @@ -147,29 +147,26 @@ if (status) break; -#if 0 - if (debug) { - /* Must reset the toggle on first error */ - if (uhci_debug) { - printk(KERN_DEBUG "Set toggle from %x rval %ld\n", - (unsigned int)tmp, rval ? *rval : 0); - } - usb_settoggle(dev->usb, uhci_endpoint(tmp->info), - uhci_packetout(tmp->info) ^ 1, - uhci_toggle(tmp->info)); - break; - } - } else { - if (rval && ((tmp->info & 0xFF) == USB_PID_IN)) - *rval += uhci_actual_length(tmp->status); - } -#endif /* The length field is only valid if the TD was completed */ if (!(tmp->status & TD_CTRL_ACTIVE) && uhci_packetin(tmp->info)) { - bytesreceived += uhci_actual_length(tmp->status); + explength = uhci_expected_length(tmp->info); + actlength = uhci_actual_length(tmp->status); if (rval) - *rval += uhci_actual_length(tmp->status); + *rval += actlength; + if (explength != actlength) { + /* Reset the data toggle on error. */ + if (debug || uhci_debug) + printk(KERN_DEBUG "Set toggle from %p rval %ld%c for status=%x to %d, exp=%d, act=%d\n", + tmp, rval ? *rval : 0, + rval ? '*' : '/', tmp->status, + uhci_toggle(tmp->info) ^ 1, + explength, actlength); + usb_settoggle(dev->usb, uhci_endpoint(tmp->info), + uhci_packetout(tmp->info), + uhci_toggle(tmp->info) ^ 1); + break; // Short packet + } } if ((tmp->link & UHCI_PTR_TERM) || @@ -190,26 +187,24 @@ if (!status) return USB_ST_NOERROR; - /* XXX FIXME APC BackUPS Pro kludge */ + /* APC BackUPS Pro kludge */ /* It tries to send all of the descriptor instead of */ /* the amount we requested */ if (tmp->status & TD_CTRL_IOC && tmp->status & TD_CTRL_ACTIVE && - tmp->status & TD_CTRL_NAK /* && its a control TD */) + tmp->status & TD_CTRL_NAK && + tmp->pipetype == PIPE_CONTROL) return USB_ST_NOERROR; -#if 0 /* We got to an error, but the controller hasn't finished */ - /* with it, yet */ + /* with it yet. */ if (tmp->status & TD_CTRL_ACTIVE) return USB_ST_NOCHANGE; -#endif /* If this wasn't the last TD and SPD is set, ACTIVE */ /* is not and NAK isn't then we received a short */ /* packet */ - if (tmp->status & TD_CTRL_SPD && - !(tmp->status & TD_CTRL_NAK)) + if (tmp->status & TD_CTRL_SPD && !(tmp->status & TD_CTRL_NAK)) return USB_ST_NOERROR; } @@ -516,7 +511,7 @@ * bit set. Maybe it could be extended to handle the QH's also, * but it doesn't seem necessary right now. * The layout looks as follows: - * frame list pointer -> iso td's (if any) -> + * frame list pointer -> iso td's (if any) -> * periodic interrupt td (if framelist 0) -> irq qh -> control qh -> bulk qh */ @@ -532,7 +527,7 @@ td->backptr = &uhci->fl->frame[framenum]; td->link = uhci->fl->frame[framenum]; if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { - nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15); + nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link); nexttd->backptr = &td->link; } wmb(); @@ -550,7 +545,7 @@ spin_lock_irqsave(&framelist_lock, flags); *(td->backptr) = td->link; if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { - nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15); + nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link); nexttd->backptr = td->backptr; } spin_unlock_irqrestore(&framelist_lock, flags); @@ -568,7 +563,7 @@ unsigned frn = inw(uhci->io_addr + USBFRNUM); __u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES]; if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { - struct uhci_td *tdl = (struct uhci_td *)bus_to_virt(link & ~15); + struct uhci_td *tdl = (struct uhci_td *)uhci_ptr_to_virt(link); for (;;) { if (tdl == td) { printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n"); @@ -576,9 +571,9 @@ } if (tdl->link & (UHCI_PTR_TERM | UHCI_PTR_QH)) break; - tdl = (struct uhci_td *)bus_to_virt(tdl->link & ~15); + tdl = (struct uhci_td *)uhci_ptr_to_virt(tdl->link); } - } + } } } @@ -603,6 +598,7 @@ /* Remove it from the skeleton */ uhci_remove_qh(td->qh->skel, td->qh); uhci_qh_free(td->qh); + do { nextlink = curtd->link; @@ -612,10 +608,11 @@ uhci_remove_td(curtd); uhci_td_free(curtd); + if (nextlink & UHCI_PTR_TERM) /* Tail? */ break; - curtd = bus_to_virt(nextlink & ~UHCI_PTR_BITS); + curtd = (struct uhci_td *)uhci_ptr_to_virt(nextlink); if (!--maxcount) { printk(KERN_ERR "runaway td's!?\n"); break; @@ -624,7 +621,7 @@ } /* - * Request a interrupt handler.. + * Request an interrupt handler.. * * Returns 0 (success) or negative (failure). * Also returns/sets a "handle pointer" that release_irq can use to stop this @@ -665,9 +662,8 @@ td->bandwidth_alloc = bustime; /* if period 0, set _REMOVE flag */ - if (period == 0) { + if (!period) td->flags |= UHCI_TD_REMOVE; - } qh->skel = &dev->uhci->skelqh[__interval_to_skel(period)]; @@ -690,7 +686,7 @@ * * This function can NOT be called from an interrupt. */ -int uhci_release_irq(struct usb_device *usb, void *handle) +static int uhci_release_irq(struct usb_device *usb, void *handle) { struct uhci_td *td; struct uhci_qh *qh; @@ -699,12 +695,13 @@ if (!td) return USB_ST_INTERNALERROR; + qh = td->qh; + /* Remove it from the internal irq_list */ uhci_remove_irq_list(td); /* Remove the interrupt TD and QH */ uhci_remove_td(td); - qh = td->qh; uhci_remove_qh(qh->skel, qh); if (td->completed != NULL) @@ -744,7 +741,7 @@ */ static int uhci_init_isoc (struct usb_device *usb_dev, unsigned int pipe, - int frame_count, /* bandwidth % = 100 * this / 1000 */ + int frame_count, /* bandwidth % = 100 * this / 1024 */ void *context, struct usb_isoc_desc **isocdesc) { @@ -896,7 +893,7 @@ } } /* end START_RELATIVE */ else - if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */ + if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */ ix = USB_WRAP_FRAMENR(isocdesc->start_frame - cur_frame); if (ix < START_FRAME_FUDGE || /* too small */ ix > CAN_SCHEDULE_FRAMES) { /* too large */ @@ -999,6 +996,7 @@ td->completed = isocdesc->callback_fn; uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc); /* TBD: D.K. ??? */ } + return 0; } /* end uhci_run_isoc */ @@ -1028,6 +1026,7 @@ } for (ix = 0, td = isocdesc->td; ix < isocdesc->frame_count; ix++, td++) { + /* Deactivate and unlink */ uhci_remove_frame_list(uhci, td); td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC); } /* end for ix */ @@ -1044,9 +1043,9 @@ if (isocdesc->start_frame >= 0) uhci_kill_isoc(isocdesc); - /* Remove all td's from the IRQ list. */ - for(i = 0; i < isocdesc->frame_count; i++) - uhci_remove_irq_list(((struct uhci_td *)(isocdesc->td))+i); + /* Remove all TD's from the IRQ list. */ + for (i = 0; i < isocdesc->frame_count; i++) + uhci_remove_irq_list(((struct uhci_td *)isocdesc->td) + i); /* Free the associate memory. */ if (isocdesc->td) @@ -1137,7 +1136,8 @@ * there is no restriction on length of transfers * anymore */ -static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout) +static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, + void *data, int len, int timeout) { struct uhci_device *dev = usb_to_uhci(usb_dev); struct uhci_td *first, *td, *prevtd; @@ -1147,6 +1147,9 @@ __u32 nextlink; unsigned long bytesrequested = len; unsigned long bytesread = 0; +#ifdef DUMP_RAW + unsigned char *orig_data = (unsigned char *) data; +#endif first = td = uhci_td_alloc(dev); if (!td) @@ -1176,8 +1179,10 @@ prevtd = td; td = uhci_td_alloc(dev); - if (!td) - return -ENOMEM; + if (!td) { + uhci_td_free(prevtd); + return -ENOMEM; + } prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH; @@ -1261,9 +1266,29 @@ if (uhci_debug && ret) { __u8 *p = (__u8 *)cmd; + printk("dev %d, pipe %X requested %ld bytes, got %ld, status=%d:\n", + usb_dev->devnum, pipe, bytesrequested, bytesread, ret); printk(KERN_DEBUG "Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } + +#ifdef DUMP_RAW + if (!ret && usb_pipein(pipe)) { /* good Input control msg */ + int i; + + printk (KERN_CRIT "ctrl msg [%02x %02x %04x %04x %04x] on pipe %x returned:\n", + cmd->requesttype, cmd->request, + cmd->value, cmd->index, cmd->length, pipe); + for (i = 0; i < bytesrequested; ) { + printk(" %02x", orig_data[i]); + if (++i % 16 == 0) + printk("\n"); + } + if (i % 16 != 0) + printk("\n"); + } +#endif + return ret; } @@ -1344,7 +1369,7 @@ if (!td) return -ENOMEM; - prevtd = first; //This is fake, but at least it's not NULL + prevtd = first; // This is fake, but at least it's not NULL while (len > 0) { /* Build the TD for control status */ int pktsze = len; @@ -1376,7 +1401,7 @@ usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); } - td->link = 1; /* Terminate */ + td->link = UHCI_PTR_TERM; /* Terminate */ td->status |= TD_CTRL_IOC; /* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */ @@ -1619,7 +1644,6 @@ } while (nr < maxchild); } -#if 0 static int fixup_isoc_desc (struct uhci_td *td) { struct usb_isoc_desc *isocdesc = td->dev_id; @@ -1647,7 +1671,7 @@ if ((frm->frame_status = uhci_map_status (uhci_status_bits (prtd->status), uhci_packetout (prtd->info)))) isocdesc->error_count++; - + prtd++; frm++; if (++fx >= isocdesc->frame_count) { /* wrap fx, prtd, and frm */ @@ -1671,8 +1695,106 @@ return 0; } -#endif /* 0 */ +int uhci_isoc_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval) +{ + struct usb_isoc_desc *isocdesc = td->dev_id; + int ret; + + /* + * Fixup the isocdesc for the driver: total_completed_frames, + * error_count, total_length, frames array. + * + * ret = callback_fn (int error_count, void *buffer, + * int len, void *isocdesc); + */ + + fixup_isoc_desc (td); + + ret = td->completed (isocdesc->error_count, bus_to_virt (td->buffer), + isocdesc->total_length, isocdesc); + + /* + * Isoc. handling of return value from td->completed (callback function) + */ + + switch (ret) { + case CB_CONTINUE: /* similar to the REMOVE condition below */ + /* TBD */ + uhci_td_free (td); + break; + + case CB_REUSE: /* similar to the re-add condition below, + * but Not ACTIVE */ + /* TBD */ + /* usb_dev = td->dev->usb; */ + + list_add(&td->irq_list, &uhci->interrupt_list); + + td->status = (td->status & (TD_CTRL_SPD | TD_CTRL_C_ERR_MASK | + TD_CTRL_LS | TD_CTRL_IOS | TD_CTRL_IOC)) | + TD_CTRL_IOC; + + /* The HC removes it, so re-add it */ + /* Insert into a QH? */ + uhci_insert_td_in_qh(td->qh, td); + break; + + case CB_RESTART: /* similar to re-add, but mark ACTIVE */ + /* TBD */ + /* usb_dev = td->dev->usb; */ + + list_add(&td->irq_list, &uhci->interrupt_list); + + td->status = (td->status & (TD_CTRL_SPD | TD_CTRL_C_ERR_MASK | + TD_CTRL_LS | TD_CTRL_IOS | TD_CTRL_IOC)) | + TD_CTRL_ACTIVE | TD_CTRL_IOC; + + /* The HC removes it, so re-add it */ + uhci_insert_td_in_qh(td->qh, td); + break; + + case CB_ABORT: /* kill/abort */ + /* TBD */ + uhci_kill_isoc (isocdesc); + break; + } /* end isoc. TD switch */ + + return 0; +} + +int uhci_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval) +{ + if (td->completed(status, bus_to_virt(td->buffer), rval, td->dev_id)) { + struct usb_device *usb_dev = td->dev->usb; + + list_add(&td->irq_list, &uhci->interrupt_list); + + usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); + td->info &= ~(1 << TD_TOKEN_TOGGLE); /* clear data toggle */ + td->info |= usb_gettoggle(usb_dev, uhci_endpoint(td->info), + uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */ + td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; + /* The HC only removes it when it completed */ + /* successfully, so force remove and re-add it. */ + uhci_remove_td(td); + uhci_insert_td_in_qh(td->qh, td); + } else if (td->flags & UHCI_TD_REMOVE) { + struct usb_device *usb_dev = td->dev->usb; + + /* marked for removal */ + td->flags &= ~UHCI_TD_REMOVE; + usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); + uhci_remove_qh(td->qh->skel, td->qh); + uhci_qh_free(td->qh); + if (td->pipetype == PIPE_INTERRUPT) + usb_release_bandwidth(usb_dev, td->bandwidth_alloc); + uhci_td_free(td); + } + + return 0; +} + static void uhci_interrupt_notify(struct uhci *uhci) { struct list_head *tmp, *head = &uhci->interrupt_list; @@ -1690,39 +1812,18 @@ /* TD's completed successfully */ status = uhci_td_result(td->dev, td, &rval, 0); - if ((status == USB_ST_NOERROR) && (td->status & TD_CTRL_ACTIVE)) + if (status == USB_ST_NOCHANGE) continue; /* remove from IRQ list */ list_del(&td->irq_list); INIT_LIST_HEAD(&td->irq_list); - if (td->completed(status, bus_to_virt(td->buffer), rval, - td->dev_id)) { - struct usb_device *usb_dev = td->dev->usb; - - list_add(&td->irq_list, &uhci->interrupt_list); - - usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1); - td->info &= ~(1 << 19); /* clear data toggle */ - td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info), - uhci_packetout(td->info)) << 19; /* toggle between data0 and data1 */ - td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; - /* The HC only removes it when it completed */ - /* successfully, so force remove and re-add it */ - uhci_remove_td(td); - uhci_insert_td_in_qh(td->qh, td); - } else if (td->flags & UHCI_TD_REMOVE) { - struct usb_device *usb_dev = td->dev->usb; - - /* marked for removal */ - td->flags &= ~UHCI_TD_REMOVE; - usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), uhci_packetout(td->info)); - uhci_remove_qh(td->qh->skel, td->qh); - uhci_qh_free(td->qh); - uhci_td_free(td); - if (td->pipetype == PIPE_INTERRUPT) - usb_release_bandwidth(usb_dev, td->bandwidth_alloc); + if (td->pipetype == PIPE_ISOCHRONOUS) { + uhci_isoc_callback(uhci, td, status, rval); + } + else { + uhci_callback(uhci, td, status, rval); } /* If completed does not wants to reactivate, then */ @@ -1800,7 +1901,8 @@ td->link = uhci->fl->frame[0]; td->backptr = &uhci->fl->frame[0]; td->status = TD_CTRL_IOC; - td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN; /* (ignored) input packet, 16 bytes, device 127 */ + td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN; + /* (ignored) input packet, 16 bytes, device 127 */ td->buffer = 0; td->qh = NULL; td->pipetype = -1; @@ -1843,7 +1945,8 @@ } /* Turn on all interrupts */ - outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR); + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, + io_addr + USBINTR); /* Start at frame 0 */ outw(0, io_addr + USBFRNUM); @@ -2168,6 +2271,8 @@ /* disable legacy emulation */ pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); + + pci_enable_device(dev); return found_uhci(dev->irq, io_addr, io_size); } diff -u --recursive --new-file v2.3.22/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h --- v2.3.22/linux/drivers/usb/uhci.h Fri Oct 15 15:25:14 1999 +++ linux/drivers/usb/uhci.h Fri Oct 22 10:48:19 1999 @@ -125,6 +125,7 @@ #define TD_TOKEN_TOGGLE 19 #define uhci_maxlen(token) ((token) >> 21) +#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ #define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) #define uhci_endpoint(token) (((token) >> 15) & 0xf) #define uhci_devaddr(token) (((token) >> 8) & 0x7f) @@ -181,12 +182,6 @@ */ struct uhci; -#if 0 -#define UHCI_MAXTD 64 - -#define UHCI_MAXQH 16 -#endif - /* The usb device part must be first! Not anymore -jerdfelt */ struct uhci_device { struct usb_device *usb; @@ -194,10 +189,6 @@ atomic_t refcnt; struct uhci *uhci; -#if 0 - struct uhci_qh qh[UHCI_MAXQH]; /* These are the "common" qh's for each device */ - struct uhci_td td[UHCI_MAXTD]; -#endif unsigned long data[16]; }; @@ -278,7 +269,7 @@ * and we should meet that frequency when requested to do so. * This will require some change(s) to the UHCI skeleton. */ -static inline int __interval_to_skel(interval) +static inline int __interval_to_skel(int interval) { if (interval < 16) { if (interval < 4) { diff -u --recursive --new-file v2.3.22/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.22/linux/drivers/usb/usb.c Fri Oct 15 15:25:14 1999 +++ linux/drivers/usb/usb.c Sat Oct 16 19:15:32 1999 @@ -789,10 +789,7 @@ dr.index = 1; dr.length = 0; - if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ)) - return -1; - - return 0; + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ); } /* keyboards want a nonzero duration according to HID spec, but @@ -807,10 +804,7 @@ dr.index = 1; dr.length = 0; - if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ)) - return -1; - - return 0; + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ); } static void usb_set_maxpacket(struct usb_device *dev) @@ -873,8 +867,8 @@ if (result) return result; - if (status & 1) - return 1; /* still halted */ + if (status & 1) /* endpoint status is Halted */ + return USB_ST_STALL; /* still halted */ #endif usb_endpoint_running(dev, endp & 0x0f, usb_endpoint_out(endp)); @@ -888,6 +882,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) { devrequest dr; + int err; dr.requesttype = 1; dr.request = USB_REQ_SET_INTERFACE; @@ -895,8 +890,9 @@ dr.index = interface; dr.length = 0; - if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ)) - return -1; + err = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ); + if (err) + return err; dev->ifnum = interface; dev->actconfig->interface[interface].act_altsetting = alternate; @@ -946,10 +942,7 @@ dr.index = index; dr.length = size; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ)) - return -1; - - return 0; + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ); } int usb_get_configuration(struct usb_device *dev) @@ -1056,10 +1049,13 @@ * By the time we get here, the device has gotten a new device ID * and is in the default state. We need to identify the thing and * get the ball rolling.. + * + * Returns 0 for success, != 0 for error. */ int usb_new_device(struct usb_device *dev) { int addr; + int err; printk(KERN_INFO "USB new device connect, assigned device number %d\n", dev->devnum); @@ -1073,8 +1069,10 @@ dev->devnum = 0; /* Slow devices */ - if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) { - printk(KERN_ERR "usbcore: USB device not responding, giving up\n"); + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); + if (err) { + printk(KERN_ERR "usbcore: USB device not responding, giving up (error=%d)\n", + err); dev->devnum = -1; return 1; } @@ -1090,16 +1088,20 @@ dev->devnum = addr; - if (usb_set_address(dev)) { - printk(KERN_ERR "usbcore: USB device not accepting new address\n"); + err = usb_set_address(dev); + if (err) { + printk(KERN_ERR "usbcore: USB device not accepting new address (error=%d)\n", + err); dev->devnum = -1; return 1; } wait_ms(10); /* Let the SET_ADDRESS settle */ - if (usb_get_device_descriptor(dev)) { - printk(KERN_ERR "usbcore: unable to get device descriptor\n"); + err = usb_get_device_descriptor(dev); + if (err) { + printk(KERN_ERR "usbcore: unable to get device descriptor (error=%d)\n", + err); dev->devnum = -1; return 1; } @@ -1324,7 +1326,6 @@ if (register_chrdev(180,"usb",&usb_fops)) { printk("unable to get major %d for usb devices\n", MISC_MAJOR); - return -EIO; } } diff -u --recursive --new-file v2.3.22/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.22/linux/drivers/usb/usb.h Fri Oct 15 15:25:14 1999 +++ linux/drivers/usb/usb.h Fri Oct 22 10:48:19 1999 @@ -199,31 +199,32 @@ } devrequest __attribute__ ((packed)); /* - * Status codes (these follow OHCI controllers condition codes) + * Status codes (these [used to] follow OHCI controllers condition codes) */ -#define USB_ST_NOERROR 0x0 -#define USB_ST_CRC 0x1 -#define USB_ST_BITSTUFF 0x2 -#define USB_ST_DTMISMATCH 0x3 /* data toggle mismatch */ -#define USB_ST_STALL 0x4 -#define USB_ST_NORESPONSE 0x5 /* device not responding/handshaking */ -#define USB_ST_PIDCHECK 0x6 /* Check bits on PID failed */ -#define USB_ST_PIDUNDEF 0x7 /* PID unexpected/undefined */ -#define USB_ST_DATAOVERRUN 0x8 -#define USB_ST_DATAUNDERRUN 0x9 -#define USB_ST_RESERVED1 0xA -#define USB_ST_RESERVED2 0xB -#define USB_ST_BUFFEROVERRUN 0xC -#define USB_ST_BUFFERUNDERRUN 0xD -#define USB_ST_RESERVED3 0xE -#define USB_ST_RESERVED4 0xF +#define USB_ST_NOERROR 0 +#define USB_ST_CRC -1 +#define USB_ST_BITSTUFF -2 +#define USB_ST_DTMISMATCH -3 /* data toggle mismatch */ +#define USB_ST_STALL -4 +#define USB_ST_NORESPONSE -5 /* device not responding/handshaking */ +#define USB_ST_PIDCHECK -6 /* Check bits on PID failed */ +#define USB_ST_PIDUNDEF -7 /* PID unexpected/undefined */ +#define USB_ST_DATAOVERRUN -8 +#define USB_ST_DATAUNDERRUN -9 +#define USB_ST_RESERVED1 -10 +#define USB_ST_RESERVED2 -11 +#define USB_ST_BUFFEROVERRUN -12 +#define USB_ST_BUFFERUNDERRUN -13 +#define USB_ST_RESERVED3 -14 +#define USB_ST_RESERVED4 -15 /* internal errors */ -#define USB_ST_REMOVED 0x100 -#define USB_ST_TIMEOUT 0x110 -#define USB_ST_INTERNALERROR -1 -#define USB_ST_NOTSUPPORTED -2 -#define USB_ST_BANDWIDTH_ERROR -3 +#define USB_ST_REMOVED -100 +#define USB_ST_TIMEOUT -101 +#define USB_ST_INTERNALERROR -200 +#define USB_ST_NOTSUPPORTED -201 +#define USB_ST_BANDWIDTH_ERROR -202 +#define USB_ST_NOCHANGE -203 /* @@ -684,7 +685,6 @@ int usb_set_protocol(struct usb_device *dev, int protocol); int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_idle(struct usb_device *dev, int duration, int report_id); -int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_configuration(struct usb_device *dev, int configuration); int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size); char *usb_string(struct usb_device *dev, int index); @@ -722,7 +722,7 @@ void usb_show_string(struct usb_device *dev, char *id, int index); #ifdef USB_DEBUG -#define PRINTD(format, args...) printk("usb: " format "\n" , ## args); +#define PRINTD(format, args...) printk(KERN_DEBUG "usb: " format "\n" , ## args); #else /* NOT DEBUGGING */ #define PRINTD(fmt, arg...) do {} while (0) #endif /* USB_DEBUG */ diff -u --recursive --new-file v2.3.22/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.22/linux/drivers/video/Config.in Mon Oct 11 15:38:15 1999 +++ linux/drivers/video/Config.in Mon Oct 18 18:05:08 1999 @@ -96,6 +96,7 @@ bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY + bool ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX fi fi diff -u --recursive --new-file v2.3.22/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.22/linux/drivers/video/Makefile Mon Oct 11 15:38:15 1999 +++ linux/drivers/video/Makefile Mon Oct 18 18:05:08 1999 @@ -113,6 +113,10 @@ endif endif +ifeq ($(CONFIG_FB_ATY128),y) +L_OBJS += aty128fb.o +endif + ifeq ($(CONFIG_FB_IGA),y) L_OBJS += igafb.o endif diff -u --recursive --new-file v2.3.22/linux/drivers/video/aty128.h linux/drivers/video/aty128.h --- v2.3.22/linux/drivers/video/aty128.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/aty128.h Mon Oct 18 11:37:43 1999 @@ -0,0 +1,594 @@ +/* $Id: aty128.h,v 1.1 1999/10/12 11:00:40 geert Exp $ + * linux/drivers/video/aty128.h + * Register definitions for ATI Rage128 boards + * + * Anthony Tong , 1999 + */ + +#ifndef REG_RAGE128_H +#define REG_RAGE128_H + +#define MM_INDEX 0x0000 +#define MM_DATA 0x0004 +#define CLOCK_CNTL_INDEX 0x0008 +#define CLOCK_CNTL_DATA 0x000c +#define BIOS_0_SCRATCH 0x0010 +#define BIOS_1_SCRATCH 0x0014 +#define BIOS_2_SCRATCH 0x0018 +#define BIOS_3_SCRATCH 0x001c +#define BUS_CNTL 0x0030 +#define BUS_CNTL1 0x0034 +#define MEM_VGA_WP_SEL 0x0038 +#define MEM_VGA_RP_SEL 0x003c +#define GEN_INT_CNTL 0x0040 +#define GEN_INT_STATUS 0x0044 +#define CRTC_GEN_CNTL 0x0050 +#define CRTC_EXT_CNTL 0x0054 +#define DAC_CNTL 0x0058 +#define CRTC_STATUS 0x005c +#define GPIO_MONID 0x0068 +#define I2C_CNTL_1 0x0094 +#define PALETTE_INDEX 0x00b0 +#define PALETTE_DATA 0x00b4 +#define CONFIG_CNTL 0x00e0 +#define CONFIG_XSTRAP 0x00e4 +#define CONFIG_BONDS 0x00e8 +#define GEN_RESET_CNTL 0x00f0 +#define GEN_STATUS 0x00f4 +#define CONFIG_MEMSIZE 0x00f8 +#define CONFIG_APER_0_BASE 0x0100 +#define CONFIG_APER_1_BASE 0x0104 +#define CONFIG_APER_SIZE 0x0108 +#define CONFIG_REG_1_BASE 0x010c +#define CONFIG_REG_APER_SIZE 0x0110 +#define CONFIG_MEMSIZE_EMBEDDED 0x0114 +#define TEST_DEBUG_CNTL 0x0120 +#define TEST_DEBUG_MUX 0x0124 +#define HW_DEBUG 0x0128 +#define TEST_DEBUG_OUT 0x012c +#define HOST_PATH_CNTL 0x0130 +#define SW_SEMAPHORE 0x013c +#define MEM_CNTL 0x0140 +#define EXT_MEM_CNTL 0x0144 +#define MEM_ADDR_CONFIG 0x0148 +#define MEM_INTF_CNTL 0x014c +#define MEM_STR_CNTL 0x0150 +#define MEM_INIT_LAT_TIMER 0x0154 +#define MEM_SDRAM_MODE_REG 0x0158 +#define AGP_BASE 0x0170 +#define AGP_CNTL 0x0174 +#define AGP_APER_OFFSET 0x0178 +#define PCI_GART_PAGE 0x017c +#define PC_NGUI_MODE 0x0180 +#define PC_NGUI_CTLSTAT 0x0184 +#define VIDEOMUX_CNTL 0x0190 +#define MPP_TB_CONFIG 0x01C0 +#define MPP_GP_CONFIG 0x01C8 +#define VIPH_CONTROL 0x01D0 +#define CRTC_H_TOTAL_DISP 0x0200 +#define CRTC_H_SYNC_STRT_WID 0x0204 +#define CRTC_V_TOTAL_DISP 0x0208 +#define CRTC_V_SYNC_STRT_WID 0x020c +#define CRTC_VLINE_CRNT_VLINE 0x0210 +#define CRTC_CRNT_FRAME 0x0214 +#define CRTC_GUI_TRIG_VLINE 0x0218 +#define CRTC_DEBUG 0x021c +#define CRTC_OFFSET 0x0224 +#define CRTC_OFFSET_CNTL 0x0228 +#define CRTC_PITCH 0x022c +#define OVR_CLR 0x0230 +#define OVR_WID_LEFT_RIGHT 0x0234 +#define OVR_WID_TOP_BOTTOM 0x0238 +#define SNAPSHOT_VH_COUNTS 0x0240 +#define SNAPSHOT_F_COUNT 0x0244 +#define N_VIF_COUNT 0x0248 +#define SNAPSHOT_VIF_COUNT 0x024c +#define CUR_OFFSET 0x0260 +#define CUR_HORZ_VERT_POSN 0x0264 +#define CUR_HORZ_VERT_OFF 0x0268 +#define CUR_CLR0 0x026c +#define CUR_CLR1 0x0270 +#define DAC_CRC_SIG 0x02cc +#define DDA_CONFIG 0x02e0 +#define DDA_ON_OFF 0x02e4 +#define VGA_DDA_CONFIG 0x02e8 +#define VGA_DDA_ON_OFF 0x02ec +#define OV0_Y_X_START 0x0400 +#define OV0_Y_X_END 0x0404 +#define OV0_EXCLUSIVE_HORZ 0x0408 +#define OV0_EXCLUSIVE_VERT 0x040c +#define OV0_REG_LOAD_CNTL 0x0410 +#define OV0_SCALE_CNTL 0x0420 +#define OV0_V_INC 0x0424 +#define OV0_P1_V_ACCUM_INIT 0x0428 +#define OV0_P23_V_ACCUM_INIT 0x042c +#define OV0_P1_BLANK_LINES_AT_TOP 0x0430 +#define OV0_P23_BLANK_LINES_AT_TOP 0x0434 +#define OV0_VID_BUF0_BASE_ADRS 0x0440 +#define OV0_VID_BUF1_BASE_ADRS 0x0444 +#define OV0_VID_BUF2_BASE_ADRS 0x0448 +#define OV0_VID_BUF3_BASE_ADRS 0x044c +#define OV0_VID_BUF4_BASE_ADRS 0x0450 +#define OV0_VID_BUF5_BASE_ADRS 0x0454 +#define OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define OV0_OCTWORDS_PER_LINE_M1 0x046c +#define OV0_AUTO_FLIP_CNTRL 0x0470 +#define OV0_DEINTERLACE_PATTERN 0x0474 +#define OV0_H_INC 0x0480 +#define OV0_STEP_BY 0x0484 +#define OV0_P1_H_ACCUM_INIT 0x0488 +#define OV0_P23_H_ACCUM_INIT 0x048c +#define OV0_P1_X_START_END 0x0494 +#define OV0_P2_X_START_END 0x0498 +#define OV0_P3_X_START_END 0x049c +#define OV0_FILTER_CNTL 0x04a0 +#define OV0_FOUR_TAP_COEF_0 0x04b0 +#define OV0_FOUR_TAP_COEF_1 0x04b4 +#define OV0_FOUR_TAP_COEF_2 0x04b8 +#define OV0_FOUR_TAP_COEF_3 0x04bc +#define OV0_FOUR_TAP_COEF_4 0x04c0 +#define OV0_COLOR_CNTL 0x04e0 +#define OV0_VIDEO_KEY_CLR 0x04e4 +#define OV0_VIDEO_KEY_MASK 0x04e8 +#define OV0_GRAPHICS_KEY_CLR 0x04ec +#define OV0_GRAPHICS_KEY_MASK 0x04f0 +#define OV0_KEY_CNTL 0x04f4 +#define OV0_TEST 0x04f8 +#define SUBPIC_CNTL 0x0540 +#define PM4_BUFFER_OFFSET 0x0700 +#define PM4_BUFFER_CNTL 0x0704 +#define PM4_BUFFER_WM_CNTL 0x0708 +#define PM4_BUFFER_DL_RPTR_ADDR 0x070c +#define PM4_BUFFER_DL_RPTR 0x0710 +#define PM4_BUFFER_DL_WPTR 0x0714 +#define PM4_VC_FPU_SETUP 0x071c +#define PM4_FPU_CNTL 0x0720 +#define PM4_VC_FORMAT 0x0724 +#define PM4_VC_CNTL 0x0728 +#define PM4_VC_I01 0x072c +#define PM4_VC_VLOFF 0x0730 +#define PM4_VC_VLSIZE 0x0734 +#define PM4_IW_INDOFF 0x0738 +#define PM4_IW_INDSIZE 0x073c +#define PM4_FPU_FPX0 0x0740 +#define CRC_CMDFIFO_ADDR 0x0740 +#define PM4_FPU_FPY0 0x0744 +#define CRC_CMDFIFO_DOUT 0x0744 +#define PM4_FPU_FPX1 0x0748 +#define PM4_FPU_FPY1 0x074c +#define PM4_FPU_FPX2 0x0750 +#define PM4_FPU_FPY2 0x0754 +#define PM4_FPU_FPY3 0x0758 +#define PM4_FPU_FPY4 0x075c +#define PM4_FPU_FPY5 0x0760 +#define PM4_FPU_FPY6 0x0764 +#define PM4_FPU_FPR 0x0768 +#define PM4_FPU_FPG 0x076c +#define PM4_FPU_FPB 0x0770 +#define PM4_FPU_FPA 0x0774 +#define PM4_FPU_INTXY0 0x0780 +#define PM4_FPU_INTXY1 0x0784 +#define PM4_FPU_INTXY2 0x0788 +#define PM4_FPU_INTARGB 0x078c +#define PM4_FPU_FPTWICEAREA 0x0790 +#define PM4_FPU_DMAJOR01 0x0794 +#define PM4_FPU_DMAJOR12 0x0798 +#define PM4_FPU_DMAJOR02 0x079c +#define PM4_FPU_STAT 0x07a0 +#define PM4_STAT 0x07b8 +#define PM4_TEST_CNTL 0x07d0 +#define PM4_MICROCODE_ADDR 0x07d4 +#define PM4_MICROCODE_RADDR 0x07d8 +#define PM4_MICROCODE_DATAH 0x07dc +#define PM4_MICROCODE_DATAL 0x07e0 +#define PM4_CMDFIFO_ADDR 0x07e4 +#define PM4_CMDFIFO_DATAH 0x07e8 +#define PM4_CMDFIFO_DATAL 0x07ec +#define PM4_BUFFER_ADDR 0x07f0 +#define PM4_BUFFER_DATAH 0x07f4 +#define PM4_BUFFER_DATAL 0x07f8 +#define PM4_MICRO_CNTL 0x07fc +#define VID_BUFFER_CONTROL 0x0900 +#define CAP_INT_CNTL 0x0908 +#define CAP_INT_STATUS 0x090c +#define CAP0_BUF0_OFFSET 0x0920 +#define CAP0_BUF1_OFFSET 0x0924 +#define CAP0_BUF0_EVEN_OFFSET 0x0928 +#define CAP0_BUF1_EVEN_OFFSET 0x092c +#define CAP0_BUF_PITCH 0x0930 +#define CAP0_V_WINDOW 0x0934 +#define CAP0_H_WINDOW 0x0938 +#define CAP0_VBI_ODD_OFFSET 0x093c +#define CAP0_VBI_EVEN_OFFSET 0x0940 +#define CAP0_VBI_V_WINDOW 0x0944 +#define CAP0_VBI_H_WINDOW 0x0948 +#define CAP0_PORT_MODE_CNTL 0x094c +#define CAP0_TRIG_CNTL 0x0950 +#define CAP0_DEBUG 0x0954 +#define CAP0_CONFIG 0x0958 +#define CAP0_ANC_ODD_OFFSET 0x095c +#define CAP0_ANC_EVEN_OFFSET 0x0960 +#define CAP0_ANC_H_WINDOW 0x0964 +#define CAP0_VIDEO_SYNC_TEST 0x0968 +#define CAP0_ONESHOT_BUF_OFFSET 0x096c +#define CAP0_BUF_STATUS 0x0970 +#define CAP0_DWNSC_XRATIO 0x0978 +#define CAP0_XSHARPNESS 0x097c +#define CAP1_BUF0_OFFSET 0x0990 +#define CAP1_BUF1_OFFSET 0x0994 +#define CAP1_BUF0_EVEN_OFFSET 0x0998 +#define CAP1_BUF1_EVEN_OFFSET 0x099c +#define CAP1_BUF_PITCH 0x09a0 +#define CAP1_V_WINDOW 0x09a4 +#define CAP1_H_WINDOW 0x09a8 +#define CAP1_VBI_ODD_OFFSET 0x09ac +#define CAP1_VBI_EVEN_OFFSET 0x09b0 +#define CAP1_VBI_V_WINDOW 0x09b4 +#define CAP1_VBI_H_WINDOW 0x09b8 +#define CAP1_PORT_MODE_CNTL 0x09bc +#define CAP1_TRIG_CNTL 0x09c0 +#define CAP1_DEBUG 0x09c4 +#define CAP1_CONFIG 0x09c8 +#define CAP1_ANC_ODD_OFFSET 0x09cc +#define CAP1_ANC_EVEN_OFFSET 0x09d0 +#define CAP1_ANC_H_WINDOW 0x09d4 +#define CAP1_VIDEO_SYNC_TEST 0x09d8 +#define CAP1_ONESHOT_BUF_OFFSET 0x09dc +#define CAP1_BUF_STATUS 0x09e0 +#define CAP1_DWNSC_XRATIO 0x09e8 +#define CAP1_XSHARPNESS 0x09ec +#define BM_FRAME_BUF_OFFSET 0x0a00 +#define BM_SYSTEM_MEM_ADDR 0x0a04 +#define BM_COMMAND 0x0a08 +#define BM_STATUS 0x0a0c +#define BM_QUEUE_STATUS 0x0a10 +#define BM_QUEUE_FREE_STATUS 0x0A14 +#define BM_CHUNK_0_VAL 0x0a18 +#define BM_CHUNK_1_VAL 0x0a1C +#define BM_VIP0_BUF 0x0A20 +#define BM_VIP0_ACTIVE 0x0A24 +#define BM_VIP1_BUF 0x0A30 +#define BM_VIP1_ACTIVE 0x0A34 +#define BM_VIP2_BUF 0x0A40 +#define BM_VIP2_ACTIVE 0x0A44 +#define BM_VIP3_BUF 0x0A50 +#define BM_VIP3_ACTIVE 0x0A54 +#define BM_VIDCAP_BUF0 0x0a60 +#define BM_VIDCAP_BUF1 0x0a64 +#define BM_VIDCAP_BUF2 0x0a68 +#define BM_VIDCAP_ACTIVE 0x0a6c +#define BM_GUI 0x0a80 +#define SURFACE_DELAY 0x0b00 + +/****************************************************************************** + * GUI Block Memory Mapped Registers * + * These registers are FIFOed. * + *****************************************************************************/ +#define PM4_FIFO_DATA_EVEN 0x1000 +#define PM4_FIFO_DATA_ODD 0x1004 + +#define DST_OFFSET 0x1404 +#define DST_PITCH 0x1408 +#define DST_WIDTH 0x140c +#define DST_HEIGHT 0x1410 +#define SRC_X 0x1414 +#define SRC_Y 0x1418 +#define DST_X 0x141c +#define DST_Y 0x1420 +#define SRC_PITCH_OFFSET 0x1428 +#define DST_PITCH_OFFSET 0x142c +#define SRC_Y_X 0x1434 +#define DST_Y_X 0x1438 +#define DST_HEIGHT_WIDTH 0x143c +#define DP_GUI_MASTER_CNTL 0x146c +#define BRUSH_SCALE 0x1470 +#define BRUSH_Y_X 0x1474 +#define DP_BRUSH_BKGD_CLR 0x1478 +#define DP_BRUSH_FRGD_CLR 0x147c +#define BRUSH_DATA0 0x1480 +#define BRUSH_DATA1 0x1484 +#define BRUSH_DATA2 0x1488 +#define BRUSH_DATA3 0x148c +#define BRUSH_DATA4 0x1490 +#define BRUSH_DATA5 0x1494 +#define BRUSH_DATA6 0x1498 +#define BRUSH_DATA7 0x149c +#define BRUSH_DATA8 0x14a0 +#define BRUSH_DATA9 0x14a4 +#define BRUSH_DATA10 0x14a8 +#define BRUSH_DATA11 0x14ac +#define BRUSH_DATA12 0x14b0 +#define BRUSH_DATA13 0x14b4 +#define BRUSH_DATA14 0x14b8 +#define BRUSH_DATA15 0x14bc +#define BRUSH_DATA16 0x14c0 +#define BRUSH_DATA17 0x14c4 +#define BRUSH_DATA18 0x14c8 +#define BRUSH_DATA19 0x14cc +#define BRUSH_DATA20 0x14d0 +#define BRUSH_DATA21 0x14d4 +#define BRUSH_DATA22 0x14d8 +#define BRUSH_DATA23 0x14dc +#define BRUSH_DATA24 0x14e0 +#define BRUSH_DATA25 0x14e4 +#define BRUSH_DATA26 0x14e8 +#define BRUSH_DATA27 0x14ec +#define BRUSH_DATA28 0x14f0 +#define BRUSH_DATA29 0x14f4 +#define BRUSH_DATA30 0x14f8 +#define BRUSH_DATA31 0x14fc +#define BRUSH_DATA32 0x1500 +#define BRUSH_DATA33 0x1504 +#define BRUSH_DATA34 0x1508 +#define BRUSH_DATA35 0x150c +#define BRUSH_DATA36 0x1510 +#define BRUSH_DATA37 0x1514 +#define BRUSH_DATA38 0x1518 +#define BRUSH_DATA39 0x151c +#define BRUSH_DATA40 0x1520 +#define BRUSH_DATA41 0x1524 +#define BRUSH_DATA42 0x1528 +#define BRUSH_DATA43 0x152c +#define BRUSH_DATA44 0x1530 +#define BRUSH_DATA45 0x1534 +#define BRUSH_DATA46 0x1538 +#define BRUSH_DATA47 0x153c +#define BRUSH_DATA48 0x1540 +#define BRUSH_DATA49 0x1544 +#define BRUSH_DATA50 0x1548 +#define BRUSH_DATA51 0x154c +#define BRUSH_DATA52 0x1550 +#define BRUSH_DATA53 0x1554 +#define BRUSH_DATA54 0x1558 +#define BRUSH_DATA55 0x155c +#define BRUSH_DATA56 0x1560 +#define BRUSH_DATA57 0x1564 +#define BRUSH_DATA58 0x1568 +#define BRUSH_DATA59 0x156c +#define BRUSH_DATA60 0x1570 +#define BRUSH_DATA61 0x1574 +#define BRUSH_DATA62 0x1578 +#define BRUSH_DATA63 0x157c +#define DST_WIDTH_X 0x1588 +#define DST_HEIGHT_WIDTH_8 0x158c +#define SRC_X_Y 0x1590 +#define DST_X_Y 0x1594 +#define DST_WIDTH_HEIGHT 0x1598 +#define DST_WIDTH_X_INCY 0x159c +#define DST_HEIGHT_Y 0x15a0 +#define DST_X_SUB 0x15a4 +#define DST_Y_SUB 0x15a8 +#define SRC_OFFSET 0x15ac +#define SRC_PITCH 0x15b0 +#define DST_HEIGHT_WIDTH_BW 0x15b4 +#define CLR_CMP_CNTL 0x15c0 +#define CLR_CMP_CLR_SRC 0x15c4 +#define CLR_CMP_CLR_DST 0x15c8 +#define CLR_CMP_MASK 0x15cc +#define DP_SRC_FRGD_CLR 0x15d8 +#define DP_SRC_BKGD_CLR 0x15dc +#define GUI_SCRATCH_REG0 0x15e0 +#define GUI_SCRATCH_REG1 0x15e4 +#define GUI_SCRATCH_REG2 0x15e8 +#define GUI_SCRATCH_REG3 0x15ec +#define GUI_SCRATCH_REG4 0x15f0 +#define GUI_SCRATCH_REG5 0x15f4 +#define LEAD_BRES_ERR 0x1600 +#define LEAD_BRES_INC 0x1604 +#define LEAD_BRES_DEC 0x1608 +#define TRAIL_BRES_ERR 0x160c +#define TRAIL_BRES_INC 0x1610 +#define TRAIL_BRES_DEC 0x1614 +#define TRAIL_X 0x1618 +#define LEAD_BRES_LNTH 0x161c +#define TRAIL_X_SUB 0x1620 +#define LEAD_BRES_LNTH_SUB 0x1624 +#define DST_BRES_ERR 0x1628 +#define DST_BRES_INC 0x162c +#define DST_BRES_DEC 0x1630 +#define DST_BRES_LNTH 0x1634 +#define DST_BRES_LNTH_SUB 0x1638 +#define SC_LEFT 0x1640 +#define SC_RIGHT 0x1644 +#define SC_TOP 0x1648 +#define SC_BOTTOM 0x164c +#define SRC_SC_RIGHT 0x1654 +#define SRC_SC_BOTTOM 0x165c +#define AUX_SC_CNTL 0x1660 +#define AUX1_SC_LEFT 0x1664 +#define AUX1_SC_RIGHT 0x1668 +#define AUX1_SC_TOP 0x166c +#define AUX1_SC_BOTTOM 0x1670 +#define AUX2_SC_LEFT 0x1674 +#define AUX2_SC_RIGHT 0x1678 +#define AUX2_SC_TOP 0x167c +#define AUX2_SC_BOTTOM 0x1680 +#define AUX3_SC_LEFT 0x1684 +#define AUX3_SC_RIGHT 0x1688 +#define AUX3_SC_TOP 0x168c +#define AUX3_SC_BOTTOM 0x1690 +#define GUI_DEBUG0 0x16a0 +#define GUI_DEBUG1 0x16a4 +#define GUI_TIMEOUT 0x16b0 +#define GUI_TIMEOUT0 0x16b4 +#define GUI_TIMEOUT1 0x16b8 +#define GUI_PROBE 0x16bc +#define DP_CNTL 0x16c0 +#define DP_DATATYPE 0x16c4 +#define DP_MIX 0x16c8 +#define DP_WRITE_MASK 0x16cc +#define DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0 +#define DEFAULT_OFFSET 0x16e0 +#define DEFAULT_PITCH 0x16e4 +#define DEFAULT_SC_BOTTOM_RIGHT 0x16e8 +#define SC_TOP_LEFT 0x16ec +#define SC_BOTTOM_RIGHT 0x16f0 +#define SRC_SC_BOTTOM_RIGHT 0x16f4 +#define WAIT_UNTIL 0x1720 +#define CACHE_CNTL 0x1724 +#define GUI_STAT 0x1740 +#define PC_GUI_MODE 0x1744 +#define PC_GUI_CTLSTAT 0x1748 +#define PC_DEBUG_MODE 0x1760 +#define BRES_DST_ERR_DEC 0x1780 +#define TRAIL_BRES_T12_ERR_DEC 0x1784 +#define TRAIL_BRES_T12_INC 0x1788 +#define DP_T12_CNTL 0x178c +#define DST_BRES_T1_LNTH 0x1790 +#define DST_BRES_T2_LNTH 0x1794 +#define HOST_DATA0 0x17c0 +#define HOST_DATA1 0x17c4 +#define HOST_DATA2 0x17c8 +#define HOST_DATA3 0x17cc +#define HOST_DATA4 0x17d0 +#define HOST_DATA5 0x17d4 +#define HOST_DATA6 0x17d8 +#define HOST_DATA7 0x17dc +#define HOST_DATA_LAST 0x17e0 +#define SECONDARY_SCALE_PITCH 0x1980 +#define SECONDARY_SCALE_X_INC 0x1984 +#define SECONDARY_SCALE_Y_INC 0x1988 +#define SECONDARY_SCALE_HACC 0x198c +#define SECONDARY_SCALE_VACC 0x1990 +#define SCALE_SRC_HEIGHT_WIDTH 0x1994 +#define SCALE_OFFSET_0 0x1998 +#define SCALE_PITCH 0x199c +#define SCALE_X_INC 0x19a0 +#define SCALE_Y_INC 0x19a4 +#define SCALE_HACC 0x19a8 +#define SCALE_VACC 0x19ac +#define SCALE_DST_X_Y 0x19b0 +#define SCALE_DST_HEIGHT_WIDTH 0x19b4 +#define SCALE_3D_CNTL 0x1a00 +#define SCALE_3D_DATATYPE 0x1a20 +#define SETUP_CNTL 0x1bc4 +#define SOLID_COLOR 0x1bc8 +#define WINDOW_XY_OFFSET 0x1bcc +#define DRAW_LINE_POINT 0x1bd0 +#define SETUP_CNTL_PM4 0x1bd4 +#define DST_PITCH_OFFSET_C 0x1c80 +#define DP_GUI_MASTER_CNTL_C 0x1c84 +#define SC_TOP_LEFT_C 0x1c88 +#define SC_BOTTOM_RIGHT_C 0x1c8c + +#define CLR_CMP_MASK_3D 0x1A28 +#define MISC_3D_STATE_CNTL_REG 0x1CA0 +#define MC_SRC1_CNTL 0x19D8 +#define TEX_CNTL 0x1800 + +/* CONSTANTS */ +#define GUI_ACTIVE 0x80000000 +#define ENGINE_IDLE 0x0 + +#define PLL_WR_EN 0x00000080 + +#define CLK_PIN_CNTL 0x0001 +#define PPLL_CNTL 0x0002 +#define PPLL_REF_DIV 0x0003 +#define PPLL_DIV_0 0x0004 +#define PPLL_DIV_1 0x0005 +#define PPLL_DIV_2 0x0006 +#define PPLL_DIV_3 0x0007 +#define VCLK_ECP_CNTL 0x0008 +#define HTOTAL_CNTL 0x0009 +#define X_MPLL_REF_FB_DIV 0x000a +#define XPLL_CNTL 0x000b +#define XDLL_CNTL 0x000c +#define XCLK_CNTL 0x000d +#define MPLL_CNTL 0x000e +#define MCLK_CNTL 0x000f +#define AGP_PLL_CNTL 0x0010 +#define FCP_CNTL 0x0012 +#define PLL_TEST_CNTL 0x0013 + +#define PPLL_RESET 0x01 +#define PPLL_ATOMIC_UPDATE_EN 0x10000 +#define PPLL_VGA_ATOMIC_UPDATE_EN 0x20000 +#define PPLL_REF_DIV_MASK 0x3FF +#define PPLL_FB3_DIV_MASK 0x7FF +#define PPLL_POST3_DIV_MASK 0x70000 +#define PPLL_ATOMIC_UPDATE_R 0x8000 +#define PPLL_ATOMIC_UPDATE_W 0x8000 +#define MEM_CFG_TYPE_MASK 0x3 +#define XCLK_SRC_SEL_MASK 0x7 +#define XPLL_FB_DIV_MASK 0xFF00 +#define X_MPLL_REF_DIV_MASK 0xFF + +/* CRTC control values (CRTC_GEN_CNTL) */ +#define CRTC_CSYNC_EN 0x00000010 + +#define CRTC_PIX_WIDTH_MASK 0x00000700 +#define CRTC_PIX_WIDTH_4BPP 0x00000100 +#define CRTC_PIX_WIDTH_8BPP 0x00000200 +#define CRTC_PIX_WIDTH_15BPP 0x00000300 +#define CRTC_PIX_WIDTH_16BPP 0x00000400 +#define CRTC_PIX_WIDTH_24BPP 0x00000500 +#define CRTC_PIX_WIDTH_32BPP 0x00000600 + +/* DAC_CNTL bit constants */ +#define DAC_8BIT_EN 0x00000100 + +/* GEN_RESET_CNTL bit constants */ +#define SOFT_RESET_GUI 0x00000001 +#define SOFT_RESET_VCLK 0x00000100 +#define SOFT_RESET_PCLK 0x00000200 +#define SOFT_RESET_ECP 0x00000400 +#define SOFT_RESET_DISPENG_XCLK 0x00000800 + +/* PC_GUI_CTLSTAT bit constants */ +#define PC_BUSY_INIT 0x10000000 +#define PC_BUSY_GUI 0x20000000 +#define PC_BUSY_NGUI 0x40000000 +#define PC_BUSY 0x80000000 + +#define BUS_MASTER_DIS 0x00000040 +#define PM4_BUFFER_CNTL_NONPM4 0x00000000 + +/* DP_GUI_MASTER_CNTL bit constants */ +#define GMC_SRC_PITCH_OFFSET_DEFAULT 0x00000000 +#define GMC_DST_PITCH_OFFSET_DEFAULT 0x00000000 +#define GMC_SRC_CLIP_DEFAULT 0x00000000 +#define GMC_DST_CLIP_DEFAULT 0x00000000 +#define GMC_BRUSH_SOLIDCOLOR 0x000000d0 +#define GMC_SRC_DSTCOLOR 0x00003000 +#define GMC_BYTE_ORDER_MSB_TO_LSB 0x00000000 +#define GMC_DP_SRC_RECT 0x02000000 +#define GMC_3D_FCN_EN_CLR 0x00000000 +#define GMC_AUX_CLIP_CLEAR 0x20000000 +#define GMC_DST_CLR_CMP_FCN_CLEAR 0x10000000 +#define GMC_WRITE_MASK_SET 0x40000000 +#define GMC_DP_CONVERSION_TEMP_6500 0x00000000 + +/* DP_GUI_MASTER_CNTL ROP3 named constants */ +#define ROP3_PATCOPY 0x00f00000 +#define ROP3_SRCCOPY 0x00cc0000 // S + +#define SRC_DSTCOLOR 0x00030000 + +/* DP_CNTL bit constants */ +#define DST_X_RIGHT_TO_LEFT 0x00000000 +#define DST_X_LEFT_TO_RIGHT 0x00000001 +#define DST_Y_BOTTOM_TO_TOP 0x00000000 +#define DST_Y_TOP_TO_BOTTOM 0x00000002 +#define DST_X_MAJOR 0x00000000 +#define DST_Y_MAJOR 0x00000004 +#define DST_X_TILE 0x00000008 +#define DST_Y_TILE 0x00000010 +#define DST_LAST_PEL 0x00000020 +#define DST_TRAIL_X_RIGHT_TO_LEFT 0x00000000 +#define DST_TRAIL_X_LEFT_TO_RIGHT 0x00000040 +#define DST_TRAP_FILL_RIGHT_TO_LEFT 0x00000000 +#define DST_TRAP_FILL_LEFT_TO_RIGHT 0x00000080 +#define DST_BRES_SIGN 0x00000100 +#define DST_HOST_BIG_ENDIAN_EN 0x00000200 +#define DST_POLYLINE_NONLAST 0x00008000 +#define DST_RASTER_STALL 0x00010000 +#define DST_POLY_EDGE 0x00040000 + +/* DP_MIX bit constants */ +#define DP_SRC_RECT 0x00000200 +#define DP_SRC_HOST 0x00000300 +#define DP_SRC_HOST_BYTEALIGN 0x00000400 + +#endif /* REG_RAGE128_H */ diff -u --recursive --new-file v2.3.22/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.3.22/linux/drivers/video/aty128fb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/aty128fb.c Mon Oct 18 11:37:43 1999 @@ -0,0 +1,2151 @@ +/* $Id: aty128fb.c,v 1.1 1999/10/12 11:00:43 geert Exp $ + * linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128 + * + * Copyright (C) Summer 1999, Anthony Tong + * + * Brad Douglas + * - x86 support + * - MTRR + * - Probe ROM for PLL + * + * Based off of Geert's atyfb.c and vfb.c. + * + * TODO: + * - panning + * - fix 15/16 bpp on big endian arch's + * - monitor sensing (DDC) + * - other platform support (only ppc/x86 supported) + * - PPLL_REF_DIV & XTALIN calculation + * - determine MCLK from previous hardware setting + */ + +/* + * A special note of gratitude to ATI's devrel for providing documentation, + * example code and hardware. Thanks Nitya. -atong + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_PPC) +#include +#include +#include +#include