diff -u --recursive --new-file v2.4.4/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.4/linux/Documentation/Configure.help Fri Apr 20 16:23:12 2001 +++ linux/Documentation/Configure.help Fri May 4 15:16:28 2001 @@ -5635,7 +5635,7 @@ Default: 253 Initial Bus Reset Settle Delay -CONFIG_AIC7XXX_RESET_DELAY +CONFIG_AIC7XXX_RESET_DELAY_MS The number of milliseconds to delay after an initial bus reset. The bus settle delay following all error recovery actions is dictated by the SCSI layer and is not affected by this value. diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.4/linux/Documentation/DocBook/Makefile Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/Makefile Mon May 7 12:14:56 2001 @@ -95,6 +95,7 @@ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ $(TOPDIR)/kernel/kmod.c \ + $(TOPDIR)/kernel/module.c \ $(TOPDIR)/kernel/printk.c \ $(TOPDIR)/kernel/sched.c \ $(TOPDIR)/kernel/sysctl.c \ diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/deviceiobook.tmpl linux/Documentation/DocBook/deviceiobook.tmpl --- v2.4.4/linux/Documentation/DocBook/deviceiobook.tmpl Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/deviceiobook.tmpl Tue May 1 14:20:25 2001 @@ -171,7 +171,7 @@ with 'isa_' and are isa_readb, isa_writeb, isa_readw, isa_writew, isa_readl, - isa_writelisa_memcpy_fromio + isa_writel, isa_memcpy_fromio and isa_memcpy_toio diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.4.4/linux/Documentation/DocBook/kernel-api.tmpl Fri Apr 6 10:42:55 2001 +++ linux/Documentation/DocBook/kernel-api.tmpl Mon May 7 12:14:56 2001 @@ -140,8 +140,13 @@ - Module Loading + Module Support + Module Loading !Ekernel/kmod.c + + Inter Module support +!Ekernel/module.c + diff -u --recursive --new-file v2.4.4/linux/Documentation/cris/README linux/Documentation/cris/README --- v2.4.4/linux/Documentation/cris/README Fri Apr 6 10:42:55 2001 +++ linux/Documentation/cris/README Tue May 1 16:04:56 2001 @@ -1,13 +1,19 @@ Linux 2.4 on the CRIS architecture ================================== -$Id: README,v 1.6 2001/02/21 15:27:25 bjornw Exp $ +$Id: README,v 1.7 2001/04/19 12:38:32 bjornw Exp $ This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded network CPU. For more information about CRIS and ETRAX please see further below. - +In order to compile this you need a version of gcc with support for the +ETRAX chip family. Please see this link for more information on how to +download the compiler and other tools useful when building and booting +software for the ETRAX platform: +http://developer.axis.com/doc/software/devboard_lx/install-howto.html + + What is CRIS ? -------------- @@ -97,7 +103,7 @@ ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB eth0 initialized eth0: changed MAC to 00:40:8C:CD:00:00 -ETRAX 100LX serial-driver $Revision: 1.6 $, (c) 2000 Axis Communications AB +ETRAX 100LX serial-driver $Revision: 1.7 $, (c) 2000 Axis Communications AB ttyS0 at 0xb0000060 is a builtin UART with DMA ttyS1 at 0xb0000068 is a builtin UART with DMA ttyS2 at 0xb0000070 is a builtin UART with DMA @@ -127,7 +133,7 @@ Hostname is bbox1 Telnetd starting, using port 23. using /bin/sash as shell. -sftpd[15]: sftpd $Revision: 1.6 $ starting up +sftpd[15]: sftpd $Revision: 1.7 $ starting up diff -u --recursive --new-file v2.4.4/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.4.4/linux/Documentation/devices.txt Sat Dec 30 11:26:10 2000 +++ linux/Documentation/devices.txt Tue May 1 16:04:56 2001 @@ -765,7 +765,7 @@ 36 char Netlink support 0 = /dev/route Routing, device updates, kernel to user 1 = /dev/skip enSKIP security cache control - 3 = /dec/fwmonitor Firewall packet copies + 3 = /dev/fwmonitor Firewall packet copies 16 = /dev/tap0 First Ethertap device ... 31 = /dev/tap15 16th Ethertap device @@ -2436,7 +2436,7 @@ 224 char A2232 serial card 0 = /dev/ttyY0 First A2232 port - 1 = /dev/cuy0 Second A2232 port + 1 = /dev/ttyY1 Second A2232 port ... 225 char A2232 serial card (alternate devices) diff -u --recursive --new-file v2.4.4/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.4/linux/Documentation/networking/8139too.txt Thu Apr 19 09:32:48 2001 +++ linux/Documentation/networking/8139too.txt Mon May 7 14:13:19 2001 @@ -185,6 +185,13 @@ Change History -------------- +Version 0.9.17 - May 7, 2001 + +* Fix chipset wakeup bug which prevent media connection for 8139B +* Print out "media is unconnected..." instead of + "partner ability 0000" + + Version 0.9.16 - April 14, 2001 * Complete MMIO audit, disable read-after-every-write diff -u --recursive --new-file v2.4.4/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt --- v2.4.4/linux/Documentation/scsi-generic.txt Thu Apr 12 12:03:50 2001 +++ linux/Documentation/scsi-generic.txt Tue May 1 16:04:56 2001 @@ -238,8 +238,8 @@ open(const char * filename, int flags) -------------------------------------- The filename should be an 'sg' device such as -/dev/sg[a-z] /dev/sg[0,1,2,...] +/dev/sg[a-z] <<< now deprecated >>> or a symbolic link to one of these. [Devfs has its own sub-directory for sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .] It seems as though SCSI devices are allocated to sg minor numbers in the diff -u --recursive --new-file v2.4.4/linux/Documentation/sound/MAD16 linux/Documentation/sound/MAD16 --- v2.4.4/linux/Documentation/sound/MAD16 Mon Aug 23 10:23:23 1999 +++ linux/Documentation/sound/MAD16 Tue May 1 16:05:00 2001 @@ -1,3 +1,5 @@ +(This recipe has been edited to update the configuration symbols.) + From: Shaw Carruthers I have been using mad16 sound for some time now with no problems, current @@ -14,9 +16,9 @@ .config has: CONFIG_SOUND=m -CONFIG_ADLIB=m -CONFIG_MAD16=m -CONFIG_YM3812=m +CONFIG_SOUND_ADLIB=m +CONFIG_SOUND_MAD16=m +CONFIG_SOUND_YM3812=m modules.conf has: diff -u --recursive --new-file v2.4.4/linux/Documentation/sound/Opti linux/Documentation/sound/Opti --- v2.4.4/linux/Documentation/sound/Opti Wed Mar 8 11:37:03 2000 +++ linux/Documentation/sound/Opti Tue May 1 16:05:00 2001 @@ -29,21 +29,21 @@ Sound card support should be enabled as a module (chose m). Answer 'm' for these items: - Generic OPL2/OPL3 FM synthesizer support (CONFIG_ADLIB) - Microsoft Sound System support (CONFIG_MSS) - Support for OPTi MAD16 and/or Mozart based cards (CONFIG_MAD16) - FM synthesizer (YM3812/OPL-3) support (CONFIG_YM3812) + Generic OPL2/OPL3 FM synthesizer support (CONFIG_SOUND_ADLIB) + Microsoft Sound System support (CONFIG_SOUND_MSS) + Support for OPTi MAD16 and/or Mozart based cards (CONFIG_SOUND_MAD16) + FM synthesizer (YM3812/OPL-3) support (CONFIG_SOUND_YM3812) The configuration menu may ask for addresses, IRQ lines or DMA channels. If the card is used as a module the module loading options will override these values. For the OPTi 931 you can answer 'n' to: - Support MIDI in older MAD16 based cards (requires SB) (CONFIG_MAD16_OLDCARD) + Support MIDI in older MAD16 based cards (requires SB) (CONFIG_SOUND_MAD16_OLDCARD) If you do need MIDI support in a Mozart or C928 based card you need to answer 'm' to the above question. In that case you will also need to answer 'm' to: - '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SB) + '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SOUND_SB) Go on and compile your kernel and modules. Install the modules. Run depmod -a. diff -u --recursive --new-file v2.4.4/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.4/linux/MAINTAINERS Wed Apr 25 14:35:25 2001 +++ linux/MAINTAINERS Tue May 1 16:05:00 2001 @@ -161,7 +161,7 @@ APPLETALK NETWORK LAYER P: Jay Schulist M: jschlst@turbolinux.com -L: linux-atalk@netspace.org +L: linux-atalk@lists.netspace.org S: Maintained ARM MFM AND FLOPPY DRIVERS @@ -280,13 +280,17 @@ CONFIGURE, MENUCONFIG, XCONFIG P: Michael Elizabeth Chastain M: mec@shout.net -L: linux-kbuild@torque.net -W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ +L: kbuild-devel@lists.sourceforge.net +W: http://kbuild.sourceforge.net S: Maintained CONFIGURE.HELP -P: Axel Boldt -M: axel@uni-paderborn.de +P: Steven P. Cole +M: Steven P. Cole +P: Eric S. Raymond +M: Eric S. Raymond +L: kbuild-devel@lists.sourceforge.net +W: http://kbuild.sourceforge.net S: Maintained COSA/SRP SYNC SERIAL DRIVER @@ -393,7 +397,7 @@ DISK GEOMETRY AND PARTITION HANDLING P: Andries Brouwer -M: aeb@veritas.com +M: aeb@cwi.nl W: http://www.win.tue.nl/~aeb/linux/Large-Disk.html W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html @@ -548,22 +552,6 @@ W: http://www.nt.tuwien.ac.at/~kkudielk/Linux/ S: Maintained -KERNEL BUILD (Makefile, Rules.make, scripts/*) -P: Keith Owens -M: kaos@ocs.com.au -P: Michael Elizabeth Chastain -M: mec@shout.net -L: linux-kbuild@torque.net -W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ -S: Maintained - -LOGICAL VOLUME MANAGER -P: Heinz Mauelshagen -M: linux-LVM@EZ-Darmstadt.Telekom.de -L: linux-LVM@msede.com -W: http://linux.msede.com/lvm -S: Maintained - HIPPI P: Jes Sorensen M: jes@linuxcare.com @@ -759,6 +747,15 @@ L: autofs@linux.kernel.org S: Maintained +KERNEL BUILD (Makefile, Rules.make, scripts/*) +P: Keith Owens +M: kaos@ocs.com.au +P: Michael Elizabeth Chastain +M: mec@shout.net +L: linux-kbuild@torque.net +W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ +S: Maintained + KERNEL NFSD P: Neil Brown M: neilb@cse.unsw.edu.au @@ -792,6 +789,13 @@ W: http://www.linuxppc.org/ L: linuxppc-dev@lists.linuxppc.org S: Maintained + +LOGICAL VOLUME MANAGER +P: Heinz Mauelshagen +M: linux-LVM@EZ-Darmstadt.Telekom.de +L: linux-LVM@msede.com +W: http://linux.msede.com/lvm +S: Maintained M68K P: Jes Sorensen diff -u --recursive --new-file v2.4.4/linux/Makefile linux/Makefile --- v2.4.4/linux/Makefile Fri Apr 27 18:17:19 2001 +++ linux/Makefile Mon May 7 14:13:28 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 4 -EXTRAVERSION = +SUBLEVEL = 5 +EXTRAVERSION =-pre2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -144,7 +144,6 @@ DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o -DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) diff -u --recursive --new-file v2.4.4/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.4.4/linux/arch/alpha/defconfig Sun Mar 4 14:30:18 2001 +++ linux/arch/alpha/defconfig Fri May 4 15:16:28 2001 @@ -286,7 +286,7 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --recursive --new-file v2.4.4/linux/arch/cris/Makefile linux/arch/cris/Makefile --- v2.4.4/linux/arch/cris/Makefile Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/Makefile Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.15 2001/02/16 17:50:04 larsv Exp $ +# $Id: Makefile,v 1.18 2001/04/17 13:58:38 orjanf Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -25,8 +25,8 @@ # regenerating stuff (even for incremental linking of subsystems!) is # even more nauseating. LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \ - sed -e s/@ETRAX_DRAM_VIRTUAL_BASE@/0x$(ETRAX_DRAM_VIRTUAL_BASE)/ \ - -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \ + sed -e s/@CONFIG_ETRAX_DRAM_VIRTUAL_BASE@/0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE)/ \ + -e s/@CONFIG_ETRAX_DRAM_SIZE_M@/$(CONFIG_ETRAX_DRAM_SIZE)/ \ < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \ else true; \ fi && $(CROSS_COMPILE)ld -mcriself @@ -42,7 +42,7 @@ CFLAGS := $(CFLAGS) -march=v10 -fno-strict-aliasing -pipe -D__linux__ -ifdef CONFIG_KGDB +ifdef CONFIG_ETRAX_KGDB CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g CFLAGS += -fno-omit-frame-pointer endif @@ -76,7 +76,7 @@ cramfs: ## cramfs - Creates a cramfs image - mkcramfs -b 8192 root cramfs.img + mkcramfs -b 8192 -m romfs_meta.txt root cramfs.img cat vmlinux.bin cramfs.img >timage clinux: vmlinux.bin decompress.bin rescue.bin diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/Makefile linux/arch/cris/boot/compressed/Makefile --- v2.4.4/linux/arch/cris/boot/compressed/Makefile Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/compressed/Makefile Tue May 1 16:04:56 2001 @@ -24,7 +24,7 @@ vmlinuz: piggy.img decompress.bin - cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz + cat decompress.bin piggy.img > vmlinuz rm -f piggy.img head.o: head.S diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/head.S linux/arch/cris/boot/compressed/head.S --- v2.4.4/linux/arch/cris/boot/compressed/head.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/compressed/head.S Tue May 1 16:04:56 2001 @@ -1,16 +1,19 @@ /* - * arch/etrax100/boot/compressed/head.S + * arch/cris/boot/compressed/head.S * - * Copyright (C) 1999 Axis Communications AB + * Copyright (C) 1999, 2001 Axis Communications AB * * Code that sets up the DRAM registers, calls the * decompressor to unpack the piggybacked kernel, and jumps. * */ +#include #define ASSEMBLER_MACROS_ONLY #include +#define RAM_INIT_MAGIC 0x56902387 + ;; Exported symbols .globl _input_data @@ -21,23 +24,28 @@ nop di - ;; We need to initialze DRAM registers before we start using the DRAM -#include "../../lib/dram_init.S" +;; We need to initialze DRAM registers before we start using the DRAM -dram_init_finished: + cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? + beq dram_init_finished + nop + +#include "../../lib/dram_init.S" +dram_init_finished: + ;; Initiate the PA and PB ports - move.b DEF_R_PORT_PA_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 move.b r0, [R_PORT_PA_DATA] - move.b DEF_R_PORT_PA_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 move.b r0, [R_PORT_PA_DIR] - move.b DEF_R_PORT_PB_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 move.b r0, [R_PORT_PB_DATA] - move.b DEF_R_PORT_PB_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 move.b r0, [R_PORT_PB_DIR] ;; Setup the stack to a suitably high address. @@ -70,6 +78,7 @@ move.d r5, [_input_data] ; for the decompressor + ;; Clear the decompressors BSS (between _edata and _end) moveq 0, r0 @@ -81,19 +90,22 @@ nop ;; Do the decompression and save compressed size in _inptr - + jsr _decompress_kernel - ;; Put start address of cramfs in r9 so the kernel can use it + ;; Put start address of root partition in r9 so the kernel can use it ;; when mounting from flash move.d [_input_data], r9 ; flash address of compressed kernel add.d [_inptr], r9 ; size of compressed kernel - + ;; Enter the decompressed kernel + move.d RAM_INIT_MAGIC, r8 ; Tell kernel that DRAM is initialized jump 0x40004000 ; kernel is linked to this address .data _input_data: .dword 0 ; used by the decompressor + +#include "../../lib/hw_settings.S" diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/misc.c linux/arch/cris/boot/compressed/misc.c --- v2.4.4/linux/arch/cris/boot/compressed/misc.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/compressed/misc.c Tue May 1 16:04:56 2001 @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.3 2001/01/17 15:54:18 jonashg Exp $ + * $Id: misc.c,v 1.6 2001/04/09 10:00:21 starvik Exp $ * * This is a collection of several routines from gzip-1.0.3 * adapted for Linux. @@ -21,6 +21,7 @@ #define KERNEL_LOAD_ADR 0x40004000 #include + #include #include @@ -143,21 +144,21 @@ static void puts(const char *s) { -#ifndef CONFIG_DEBUG_PORT_NULL +#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL while(*s) { -#ifdef CONFIG_DEBUG_PORT0 +#ifdef CONFIG_ETRAX_DEBUG_PORT0 while(!(*R_SERIAL0_STATUS & (1 << 5))) ; *R_SERIAL0_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 while(!(*R_SERIAL1_STATUS & (1 << 5))) ; *R_SERIAL1_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 while(!(*R_SERIAL2_STATUS & (1 << 5))) ; *R_SERIAL2_TR_DATA = *s++; #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 while(!(*R_SERIAL3_STATUS & (1 << 5))) ; *R_SERIAL3_TR_DATA = *s++; #endif @@ -227,33 +228,45 @@ void decompress_kernel() { + char revision; + /* input_data is set in head.S */ inbuf = input_data; -#ifdef CONFIG_DEBUG_PORT0 +#ifdef CONFIG_ETRAX_DEBUG_PORT0 *R_SERIAL0_XOFF = 0; *R_SERIAL0_BAUD = 0x99; *R_SERIAL0_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 *R_SERIAL1_XOFF = 0; *R_SERIAL1_BAUD = 0x99; *R_SERIAL1_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 + *R_GEN_CONFIG = 0x08; *R_SERIAL2_XOFF = 0; *R_SERIAL2_BAUD = 0x99; *R_SERIAL2_TR_CTRL = 0x40; #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 + *R_GEN_CONFIG = 0x100; *R_SERIAL3_XOFF = 0; *R_SERIAL3_BAUD = 0x99; *R_SERIAL3_TR_CTRL = 0x40; #endif - + setup_normal_output_buffer(); makecrc(); + + __asm__ volatile ("move vr,%0" : "=rm" (revision)); + if (revision < 10) + { + puts("You need an ETRAX 100LX to run linux 2.4\n"); + while(1); + } + puts("Uncompressing Linux...\n"); gunzip(); puts("Done. Now booting the kernel.\n"); diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/head.S linux/arch/cris/boot/rescue/head.S --- v2.4.4/linux/arch/cris/boot/rescue/head.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/rescue/head.S Tue May 1 16:04:56 2001 @@ -1,66 +1,67 @@ - ;; $Id: head.S,v 1.3 2001/02/14 16:57:25 larsv Exp $ - ;; - ;; Rescue code, made to reside at the beginning of the - ;; flash-memory. when it starts, it checks a partition - ;; table at the first sector after the rescue sector. - ;; the partition table was generated by the product builder - ;; script and contains offsets, lengths, types and checksums - ;; for each partition that this code should check. - ;; - ;; If any of the checksums fail, we assume the flash is so - ;; corrupt that we cant use it to boot into the ftp flash - ;; loader, and instead we initialize the serial port to - ;; receive a flash-loader and new flash image. we dont include - ;; any flash code here, but just accept a certain amount of - ;; bytes from the serial port and jump into it. the downloaded - ;; code is put in the cache. - ;; - ;; The partitiontable is designed so that it is transparent to - ;; code execution - it has a relative branch opcode in the - ;; beginning that jumps over it. each entry contains extra - ;; data so we can add stuff later. - ;; - ;; Partition table format: - ;; - ;; Code transparency: - ;; - ;; 2 bytes [opcode 'nop'] - ;; 2 bytes [opcode 'di'] - ;; 4 bytes [opcode 'ba ', 8-bit or 16-bit version] - ;; 2 bytes [opcode 'nop', delay slot] - ;; - ;; Table validation (at +10): - ;; - ;; 2 bytes [magic/version word for partitiontable - 0xef, 0xbe] - ;; 2 bytes [length of all entries plus the end marker] - ;; 4 bytes [checksum for the partitiontable itself] - ;; - ;; Entries, each with the following format, last has offset -1: - ;; - ;; 4 bytes [offset in bytes, from start of flash] - ;; 4 bytes [length in bytes of partition] - ;; 4 bytes [checksum, simple longword sum] - ;; 2 bytes [partition type] - ;; 2 bytes [flags, only bit 0 used, ro/rw = 1/0] - ;; 16 bytes [reserved for future use] - ;; - ;; End marker - ;; - ;; 4 bytes [-1] - ;; - ;; 10 bytes [0, padding] - ;; - ;; Bit 0 in flags signifies RW or RO. The rescue code only bothers - ;; to check the checksum for RO partitions, since the others will - ;; change its data without updating the checksums. A 1 in bit 0 - ;; means RO, 0 means RW. That way, it is possible to set a partition - ;; in RO mode initially, and later mark it as RW, since you can always - ;; write 0's to the flash. - ;; - ;; During the wait for serial input, the status LED will flash so the - ;; user knows something went wrong. - ;; - ;; Copyright (C) 1999 Axis Communications AB +/* $Id: head.S,v 1.7 2001/04/18 12:05:07 bjornw Exp $ + * + * Rescue code, made to reside at the beginning of the + * flash-memory. when it starts, it checks a partition + * table at the first sector after the rescue sector. + * the partition table was generated by the product builder + * script and contains offsets, lengths, types and checksums + * for each partition that this code should check. + * + * If any of the checksums fail, we assume the flash is so + * corrupt that we cant use it to boot into the ftp flash + * loader, and instead we initialize the serial port to + * receive a flash-loader and new flash image. we dont include + * any flash code here, but just accept a certain amount of + * bytes from the serial port and jump into it. the downloaded + * code is put in the cache. + * + * The partitiontable is designed so that it is transparent to + * code execution - it has a relative branch opcode in the + * beginning that jumps over it. each entry contains extra + * data so we can add stuff later. + * + * Partition table format: + * + * Code transparency: + * + * 2 bytes [opcode 'nop'] + * 2 bytes [opcode 'di'] + * 4 bytes [opcode 'ba ', 8-bit or 16-bit version] + * 2 bytes [opcode 'nop', delay slot] + * + * Table validation (at +10): + * + * 2 bytes [magic/version word for partitiontable - 0xef, 0xbe] + * 2 bytes [length of all entries plus the end marker] + * 4 bytes [checksum for the partitiontable itself] + * + * Entries, each with the following format, last has offset -1: + * + * 4 bytes [offset in bytes, from start of flash] + * 4 bytes [length in bytes of partition] + * 4 bytes [checksum, simple longword sum] + * 2 bytes [partition type] + * 2 bytes [flags, only bit 0 used, ro/rw = 1/0] + * 16 bytes [reserved for future use] + * + * End marker + * + * 4 bytes [-1] + * + * 10 bytes [0, padding] + * + * Bit 0 in flags signifies RW or RO. The rescue code only bothers + * to check the checksum for RO partitions, since the others will + * change its data without updating the checksums. A 1 in bit 0 + * means RO, 0 means RW. That way, it is possible to set a partition + * in RO mode initially, and later mark it as RW, since you can always + * write 0's to the flash. + * + * During the wait for serial input, the status LED will flash so the + * user knows something went wrong. + * + * Copyright (C) 1999,2001 Axis Communications AB + */ #include #define ASSEMBLER_MACROS_ONLY @@ -69,7 +70,7 @@ ;; The partitiontable is looked for at the first sector after the boot ;; sector. Sector size is 65536 bytes in all flashes we use. -#define PTABLE_START 0x10000 +#define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR #define PTABLE_MAGIC 0xbeef ;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0. @@ -82,28 +83,28 @@ #define CODE_START 0x40000000 #define CODE_LENGTH 784 -#ifdef CONFIG_RESCUE_SER0 +#ifdef CONFIG_ETRAX_RESCUE_SER0 #define SERXOFF R_SERIAL0_XOFF #define SERBAUD R_SERIAL0_BAUD #define SERRECC R_SERIAL0_REC_CTRL #define SERRDAT R_SERIAL0_REC_DATA #define SERSTAT R_SERIAL0_STATUS #endif -#ifdef CONFIG_RESCUE_SER1 +#ifdef CONFIG_ETRAX_RESCUE_SER1 #define SERXOFF R_SERIAL1_XOFF #define SERBAUD R_SERIAL1_BAUD #define SERRECC R_SERIAL1_REC_CTRL #define SERRDAT R_SERIAL1_REC_DATA #define SERSTAT R_SERIAL1_STATUS #endif -#ifdef CONFIG_RESCUE_SER2 +#ifdef CONFIG_ETRAX_RESCUE_SER2 #define SERXOFF R_SERIAL2_XOFF #define SERBAUD R_SERIAL2_BAUD #define SERRECC R_SERIAL2_REC_CTRL #define SERRDAT R_SERIAL2_REC_DATA #define SERSTAT R_SERIAL2_STATUS #endif -#ifdef CONFIG_RESCUE_SER3 +#ifdef CONFIG_ETRAX_RESCUE_SER3 #define SERXOFF R_SERIAL3_XOFF #define SERBAUD R_SERIAL3_BAUD #define SERRECC R_SERIAL3_REC_CTRL @@ -112,7 +113,8 @@ #endif #define NOP_DI 0xf025050f - +#define RAM_INIT_MAGIC 0x56902387 + .text ;; This is the entry point of the rescue code @@ -221,14 +223,14 @@ ;; setup port PA and PB default initial directions and data ;; (so we can flash LEDs, and so that DTR and others are set) - move.b DEF_R_PORT_PA_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 move.b r0, [R_PORT_PA_DIR] - move.b DEF_R_PORT_PA_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 move.b r0, [R_PORT_PA_DATA] - move.b DEF_R_PORT_PB_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 move.b r0, [R_PORT_PB_DIR] - move.b DEF_R_PORT_PB_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 move.b r0, [R_PORT_PB_DATA] ;; setup the serial port at 115200 baud @@ -250,10 +252,10 @@ addq 1, r1 #ifndef CONFIG_ETRAX_NO_LEDS #ifdef CONFIG_ETRAX_PA_LEDS - move.b DEF_R_PORT_PA_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2 #endif #ifdef CONFIG_ETRAX_PB_LEDS - move.b DEF_R_PORT_PB_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2 #endif move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 btstq 16, r1 @@ -293,7 +295,8 @@ nop ;; jump into downloaded code - + + move.d RAM_INIT_MAGIC, r8 ; Tell next product that DRAM is initialized jump CODE_START flash_ok: @@ -303,7 +306,8 @@ bne 1f nop move.d PTABLE_START, r7; otherwise use the ptable start -1: +1: + move.d RAM_INIT_MAGIC, r8 ; Tell next product that DRAM is initialized jump r7 ; boot! diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/kimagerescue.S linux/arch/cris/boot/rescue/kimagerescue.S --- v2.4.4/linux/arch/cris/boot/rescue/kimagerescue.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/rescue/kimagerescue.S Tue May 1 16:04:56 2001 @@ -1,41 +1,42 @@ - ;; $Id: kimagerescue.S,v 1.2 2001/02/14 16:57:25 larsv Exp $ - ;; - ;; Rescue code to be prepended on a kimage and copied to the - ;; rescue serial port. - ;; This is called from the rescue code, it will copy received data to - ;; 4000500 and after a timeout jump to it. - +/* $Id: kimagerescue.S,v 1.4 2001/04/18 12:04:46 bjornw Exp $ + * + * Rescue code to be prepended on a kimage and copied to the + * rescue serial port. + * This is called from the rescue code, it will copy received data to + * 4004000 and after a timeout jump to it. + */ + #include #define ASSEMBLER_MACROS_ONLY #include -#define CODE_START 0x40000500 +#define CODE_START 0x40004000 #define CODE_LENGTH 784 #define TIMEOUT_VALUE 1000 -#ifdef CONFIG_RESCUE_SER0 +#ifdef CONFIG_ETRAX_RESCUE_SER0 #define SERXOFF R_SERIAL0_XOFF #define SERBAUD R_SERIAL0_BAUD #define SERRECC R_SERIAL0_REC_CTRL #define SERRDAT R_SERIAL0_REC_DATA #define SERSTAT R_SERIAL0_STATUS #endif -#ifdef CONFIG_RESCUE_SER1 +#ifdef CONFIG_ETRAX_RESCUE_SER1 #define SERXOFF R_SERIAL1_XOFF #define SERBAUD R_SERIAL1_BAUD #define SERRECC R_SERIAL1_REC_CTRL #define SERRDAT R_SERIAL1_REC_DATA #define SERSTAT R_SERIAL1_STATUS #endif -#ifdef CONFIG_RESCUE_SER2 +#ifdef CONFIG_ETRAX_RESCUE_SER2 #define SERXOFF R_SERIAL2_XOFF #define SERBAUD R_SERIAL2_BAUD #define SERRECC R_SERIAL2_REC_CTRL #define SERRDAT R_SERIAL2_REC_DATA #define SERSTAT R_SERIAL2_STATUS #endif -#ifdef CONFIG_RESCUE_SER3 +#ifdef CONFIG_ETRAX_RESCUE_SER3 #define SERXOFF R_SERIAL3_XOFF #define SERBAUD R_SERIAL3_BAUD #define SERRECC R_SERIAL3_REC_CTRL @@ -55,14 +56,14 @@ ;; setup port PA and PB default initial directions and data ;; (so we can flash LEDs, and so that DTR and others are set) - move.b DEF_R_PORT_PA_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 move.b r0, [R_PORT_PA_DIR] - move.b DEF_R_PORT_PA_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 move.b r0, [R_PORT_PA_DATA] - move.b DEF_R_PORT_PB_DIR, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 move.b r0, [R_PORT_PB_DIR] - move.b DEF_R_PORT_PB_DATA, r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 move.b r0, [R_PORT_PB_DATA] ;; We need to setup the bus registers before we start using the DRAM @@ -99,10 +100,10 @@ nop #ifndef CONFIG_ETRAX_NO_LEDS #ifdef CONFIG_ETRAX_PA_LEDS - move.b DEF_R_PORT_PA_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2 #endif #ifdef CONFIG_ETRAX_PB_LEDS - move.b DEF_R_PORT_PB_DATA, r2 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2 #endif move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0 btstq 16, r1 diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/testrescue.S linux/arch/cris/boot/rescue/testrescue.S --- v2.4.4/linux/arch/cris/boot/rescue/testrescue.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/rescue/testrescue.S Tue May 1 16:04:56 2001 @@ -1,9 +1,10 @@ - ;; $Id: testrescue.S,v 1.1 2001/01/31 15:32:09 johana Exp $ - ;; - ;; Simple testcode to download by the rescue block. - ;; Just lits some LEDs to show it was downloaded correctly. - ;; - ;; Copyright (C) 1999 Axis Communications AB +/* $Id: testrescue.S,v 1.2 2001/04/18 12:05:07 bjornw Exp $ + * + * Simple testcode to download by the rescue block. + * Just lits some LEDs to show it was downloaded correctly. + * + * Copyright (C) 1999 Axis Communications AB + */ #define ASSEMBLER_MACROS_ONLY #include diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/tools/build.c linux/arch/cris/boot/tools/build.c --- v2.4.4/linux/arch/cris/boot/tools/build.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/boot/tools/build.c Tue May 1 16:04:56 2001 @@ -31,6 +31,7 @@ #include /* contains read/write */ #include #include +#include #include #define MINIX_HEADER 32 diff -u --recursive --new-file v2.4.4/linux/arch/cris/config.in linux/arch/cris/config.in --- v2.4.4/linux/arch/cris/config.in Tue Apr 17 17:19:24 2001 +++ linux/arch/cris/config.in Tue May 1 16:04:56 2001 @@ -24,14 +24,10 @@ tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi -bool 'Use kernel gdb debugger' CONFIG_KGDB +bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG -bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE - -bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG - endmenu mainmenu_option next_comment @@ -46,20 +42,19 @@ if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then define_bool CONFIG_CRIS_LOW_MAP y - define_hex ETRAX_DRAM_VIRTUAL_BASE 60000000 + define_hex CONFIG_ETRAX_DRAM_VIRTUAL_BASE 60000000 else - define_hex ETRAX_DRAM_VIRTUAL_BASE c0000000 + define_hex CONFIG_ETRAX_DRAM_VIRTUAL_BASE c0000000 fi -int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8 +int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8 -int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2 int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2 choice 'Product LED port' \ "Port-PA-LEDs CONFIG_ETRAX_PA_LEDS \ Port-PB-LEDs CONFIG_ETRAX_PB_LEDS \ - Mem-0x90000000-LEDs CONFIG_ETRAX_90000000_LEDS \ + Port-CSP0-LEDs CONFIG_ETRAX_CSP0_LEDS \ None CONFIG_ETRAX_NO_LEDS" Port-PA-LEDs if [ "$CONFIG_ETRAX_NO_LEDS" != "y" ]; then @@ -71,38 +66,54 @@ int ' Third red LED bit' CONFIG_ETRAX_LED3G 2 fi +if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then + int ' Fourth red LED bit' CONFIG_ETRAX_LED4R 2 + int ' Fourth green LED bit' CONFIG_ETRAX_LED4G 2 + int ' Fifth red LED bit' CONFIG_ETRAX_LED5R 2 + int ' Fifth green LED bit' CONFIG_ETRAX_LED5G 2 + int ' Sixth red LED bit' CONFIG_ETRAX_LED6R 2 + int ' Sixth green LED bit' CONFIG_ETRAX_LED6G 2 + int ' Seventh red LED bit' CONFIG_ETRAX_LED7R 2 + int ' Seventh green LED bit' CONFIG_ETRAX_LED7G 2 + int ' Eigth yellow LED bit' CONFIG_ETRAX_LED8Y 2 + int ' Ninth yellow LED bit' CONFIG_ETRAX_LED9Y 2 + int ' Tenth yellow LED bit' CONFIG_ETRAX_LED10Y 2 + int ' Eleventh yellow LED bit' CONFIG_ETRAX_LED11Y 2 + int ' Twelfth red LED bit' CONFIG_ETRAX_LED12R 2 +fi + choice 'Product debug-port' \ - "Serial-0 CONFIG_DEBUG_PORT0 \ - Serial-1 CONFIG_DEBUG_PORT1 \ - Serial-2 CONFIG_DEBUG_PORT2 \ - Serial-3 CONFIG_DEBUG_PORT3 \ - disabled CONFIG_DEBUG_PORT_NULL" Serial-0 + "Serial-0 CONFIG_ETRAX_DEBUG_PORT0 \ + Serial-1 CONFIG_ETRAX_DEBUG_PORT1 \ + Serial-2 CONFIG_ETRAX_DEBUG_PORT2 \ + Serial-3 CONFIG_ETRAX_DEBUG_PORT3 \ + disabled CONFIG_ETRAX_DEBUG_PORT_NULL" Serial-0 choice 'Product rescue-port' \ - "Serial-0 CONFIG_RESCUE_SER0 \ - Serial-1 CONFIG_RESCUE_SER1 \ - Serial-2 CONFIG_RESCUE_SER2 \ - Serial-3 CONFIG_RESCUE_SER3" Serial-0 - -hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6 -hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104 - -bool 'SDRAM support' CONFIG_SDRAM n -if [ "$CONFIG_SDRAM" = "n" ]; then - hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040 - hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611 + "Serial-0 CONFIG_ETRAX_RESCUE_SER0 \ + Serial-1 CONFIG_ETRAX_RESCUE_SER1 \ + Serial-2 CONFIG_ETRAX_RESCUE_SER2 \ + Serial-3 CONFIG_ETRAX_RESCUE_SER3" Serial-0 + +hex 'R_WAITSTATES' CONFIG_ETRAX_DEF_R_WAITSTATES 95a6 +hex 'R_BUS_CONFIG' CONFIG_ETRAX_DEF_R_BUS_CONFIG 104 + +bool 'SDRAM support' CONFIG_ETRAX_SDRAM n +if [ "$CONFIG_ETRAX_SDRAM" = "n" ]; then + hex 'R_DRAM_CONFIG' CONFIG_ETRAX_DEF_R_DRAM_CONFIG 1a200040 + hex 'R_DRAM_TIMING' CONFIG_ETRAX_DEF_R_DRAM_TIMING 5611 fi -if [ "$CONFIG_SDRAM" = "y" ]; then - hex 'R_SDRAM_CONFIG' DEF_R_SDRAM_CONFIG d2fa7878 - hex 'R_SDRAM_TIMING' DEF_R_SDRAM_TIMING 80004801 +if [ "$CONFIG_ETRAX_SDRAM" = "y" ]; then + hex 'R_SDRAM_CONFIG' CONFIG_ETRAX_DEF_R_SDRAM_CONFIG d2fa7878 + hex 'R_SDRAM_TIMING' CONFIG_ETRAX_DEF_R_SDRAM_TIMING 80004801 fi -hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c -hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00 -hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00 -hex 'R_PORT_PB_DIR' DEF_R_PORT_PB_DIR 00 -hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff +hex 'R_PORT_PA_DIR' CONFIG_ETRAX_DEF_R_PORT_PA_DIR 1c +hex 'R_PORT_PA_DATA' CONFIG_ETRAX_DEF_R_PORT_PA_DATA 00 +hex 'R_PORT_PB_CONFIG' CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG 00 +hex 'R_PORT_PB_DIR' CONFIG_ETRAX_DEF_R_PORT_PB_DIR 00 +hex 'R_PORT_PB_DATA' CONFIG_ETRAX_DEF_R_PORT_PB_DATA ff endmenu diff -u --recursive --new-file v2.4.4/linux/arch/cris/cris.ld linux/arch/cris/cris.ld --- v2.4.4/linux/arch/cris/cris.ld Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/cris.ld Tue May 1 16:04:56 2001 @@ -1,10 +1,16 @@ /* ld script to make the Linux/CRIS kernel * Authors: Bjorn Wesen (bjornw@axis.com) + * + * It is VERY DANGEROUS to fiddle around with the symbols in this + * script. It is for example quite vital that all generated sections + * that are used are actually named here, otherwise the linker will + * put them at the end, where the init stuff is which is FREED after + * the kernel has booted. */ SECTIONS { - . = @ETRAX_DRAM_VIRTUAL_BASE@; + . = @CONFIG_ETRAX_DRAM_VIRTUAL_BASE@; _dram_start = .; _ibr_start = .; . = . + 0x4000; /* see head.S and pages reserved at the start */ @@ -75,5 +81,5 @@ *(.exitcall.exit) } - _dram_end = _dram_start + @ETRAX_DRAM_SIZE_M@*1024*1024; + _dram_end = _dram_start + @CONFIG_ETRAX_DRAM_SIZE_M@*1024*1024; } diff -u --recursive --new-file v2.4.4/linux/arch/cris/defconfig linux/arch/cris/defconfig --- v2.4.4/linux/arch/cris/defconfig Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/defconfig Tue May 1 16:04:56 2001 @@ -15,10 +15,8 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_JAVA is not set -# CONFIG_KGDB is not set +# CONFIG_ETRAX_KGDB is not set # CONFIG_ETRAX_WATCHDOG is not set -CONFIG_USE_SERIAL_CONSOLE=y -# CONFIG_KERNEL_IFCONFIG is not set # # Hardware setup @@ -27,8 +25,8 @@ # CONFIG_ETRAX100LX_V2 is not set # CONFIG_SVINTO_SIM is not set CONFIG_CRIS_LOW_MAP=y -ETRAX_DRAM_VIRTUAL_BASE=60000000 -ETRAX_DRAM_SIZE=8 +CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 +CONFIG_ETRAX_DRAM_SIZE=8 CONFIG_ETRAX_FLASH_LENGTH=2 CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_PA_LEDS=y @@ -39,24 +37,24 @@ CONFIG_ETRAX_LED1R=2 CONFIG_ETRAX_LED2G=2 CONFIG_ETRAX_LED2R=2 -CONFIG_DEBUG_PORT0=y -# CONFIG_DEBUG_PORT1 is not set -# CONFIG_DEBUG_PORT2 is not set -# CONFIG_DEBUG_PORT3 is not set -CONFIG_RESCUE_SER0=y -# CONFIG_RESCUE_SER1 is not set -# CONFIG_RESCUE_SER2 is not set -# CONFIG_RESCUE_SER3 is not set -DEF_R_WAITSTATES=95a6 -DEF_R_BUS_CONFIG=104 -# CONFIG_SDRAM is not set -DEF_R_DRAM_CONFIG=1a200040 -DEF_R_DRAM_TIMING=5611 -DEF_R_PORT_PA_DIR=1d -DEF_R_PORT_PA_DATA=f0 -DEF_R_PORT_PB_CONFIG=00 -DEF_R_PORT_PB_DIR=1e -DEF_R_PORT_PB_DATA=f3 +CONFIG_ETRAX_DEBUG_PORT0=y +# CONFIG_ETRAX_DEBUG_PORT1 is not set +# CONFIG_ETRAX_DEBUG_PORT2 is not set +# CONFIG_ETRAX_DEBUG_PORT3 is not set +CONFIG_ETRAX_RESCUE_SER0=y +# CONFIG_ETRAX_RESCUE_SER1 is not set +# CONFIG_ETRAX_RESCUE_SER2 is not set +# CONFIG_ETRAX_RESCUE_SER3 is not set +CONFIG_ETRAX_DEF_R_WAITSTATES=95a6 +CONFIG_ETRAX_DEF_R_BUS_CONFIG=104 +# CONFIG_ETRAX_SDRAM is not set +CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040 +CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611 +CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d +CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0 +CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 +CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e +CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 # # Drivers for Etrax built-in interfaces @@ -69,7 +67,7 @@ # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set # CONFIG_ETRAX_SERIAL_PORT2 is not set # CONFIG_ETRAX_SERIAL_PORT3 is not set -# CONFIG_RS485 is not set +# CONFIG_ETRAX_RS485 is not set # CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set # CONFIG_ETRAX_IDE is not set CONFIG_ETRAX_AXISFLASHMAP=y @@ -84,15 +82,10 @@ CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y CONFIG_ETRAX_GPIO=y CONFIG_ETRAX_PA_BUTTON_BITMASK=02 -CONFIG_PA_CHANGEABLE_DIR=00 -CONFIG_PA_CHANGEABLE_BITS=FF -CONFIG_PB_CHANGEABLE_DIR=00 -CONFIG_PB_CHANGEABLE_BITS=FF -# CONFIG_JULIETTE is not set -# CONFIG_JULIETTE_VIDEO is not set -# CONFIG_JULIETTE_CCD is not set -# CONFIG_JULIETTE_SS1M is not set -# CONFIG_JULIETTE_MEGCCD is not set +CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF +CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF # CONFIG_ETRAX_USB_HOST is not set # diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in --- v2.4.4/linux/arch/cris/drivers/Config.in Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/Config.in Tue May 1 16:04:56 2001 @@ -1,5 +1,5 @@ mainmenu_option next_comment -comment 'Drivers for Etrax built-in interfaces' +comment 'Drivers for ETRAX 100LX built-in interfaces' bool 'Ethernet support' CONFIG_ETRAX_ETHERNET if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then @@ -46,13 +46,13 @@ fi fi bool ' Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3 - bool ' RS-485 support' CONFIG_RS485 - if [ "$CONFIG_RS485" = "y" ]; then - bool ' RS-485 mode on PA' CONFIG_RS485_ON_PA - if [ "$CONFIG_RS485_ON_PA" = "y" ]; then - int ' RS-485 mode on PA bit' CONFIG_RS485_ON_PA_BIT 3 + bool ' RS-485 support' CONFIG_ETRAX_RS485 + if [ "$CONFIG_ETRAX_RS485" = "y" ]; then + bool ' RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA + if [ "$CONFIG_ETRAX_RS485_ON_PA" = "y" ]; then + int ' RS-485 mode on PA bit' CONFIG_ETRAX_RS485_ON_PA_BIT 3 fi - bool ' Disable serial receiver' CONFIG_RS485_DISABLE_RECEIVER + bool ' Disable serial receiver' CONFIG_ETRAX_RS485_DISABLE_RECEIVER fi fi @@ -60,14 +60,29 @@ if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL" = "y" ]; then bool ' Synchronous serial port 0 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0 if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0" = "y" ]; then - bool ' Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA y + bool ' Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA fi bool ' Synchronous serial port 1 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1 if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1" = "y" ]; then - bool ' Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA y + bool ' Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA fi fi +bool 'Parallel port support' CONFIG_ETRAX_PARPORT +if [ "$CONFIG_ETRAX_PARPORT" = "y" ]; then + bool ' Parallel port 0 enabled' CONFIG_ETRAX_PARALLEL_PORT0 + bool ' Parallel port 1 enabled' CONFIG_ETRAX_PARALLEL_PORT1 +# here we define the CONFIG_'s necessary to enable parallel port support + define_tristate CONFIG_PARPORT y + define_bool CONFIG_PARPORT_1284 y + define_tristate CONFIG_PRINTER y +else + define_tristate CONFIG_PARPORT n + define_bool CONFIG_PARPORT_1284 n + define_tristate CONFIG_PRINTER n +fi + + bool 'ATA/IDE support' CONFIG_ETRAX_IDE if [ "$CONFIG_ETRAX_IDE" = "y" ]; then @@ -89,7 +104,8 @@ choice 'IDE reset pin' \ "Port_PB_Bit_7 CONFIG_ETRAX_IDE_PB7_RESET\ Port_G_Bit_27 CONFIG_ETRAX_IDE_G27_RESET\ - Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7 + Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET\ + Port_CSP0_Bit_08 CONFIG_ETRAX_IDE_CSP0_8_RESET" Port_PB_Bit_7 else define_bool CONFIG_IDE n fi @@ -97,6 +113,7 @@ bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then + int ' Byte-offset of partition table sector' CONFIG_ETRAX_PTABLE_SECTOR 65536 # here we define the CONFIG_'s necessary to enable MTD support # for the flash define_bool CONFIG_MTD y @@ -118,16 +135,25 @@ bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C fi +bool 'I2C EEPROM (non-volatile RAM) support' CONFIG_ETRAX_I2C_EEPROM +if [ "$CONFIG_ETRAX_I2C_EEPROM" = "y" ]; then + choice ' EEPROM size' \ + "Probed CONFIG_ETRAX_I2C_EEPROM_PROBE \ + 2kB CONFIG_ETRAX_I2C_EEPROM_2KB \ + 8kB CONFIG_ETRAX_I2C_EEPROM_8KB \ + 16kB CONFIG_ETRAX_I2C_EEPROM_16KB" Probed +fi + bool 'GPIO support' CONFIG_ETRAX_GPIO if [ "$CONFIG_ETRAX_GPIO" = "y" ]; then hex ' PA-buttons bitmask' CONFIG_ETRAX_PA_BUTTON_BITMASK 02 - hex ' PA user changeable dir mask' CONFIG_PA_CHANGEABLE_DIR 00 - hex ' PA user changeable bits mask' CONFIG_PA_CHANGEABLE_BITS FF - hex ' PB user changeable dir mask' CONFIG_PB_CHANGEABLE_DIR 00 - hex ' PB user changeable bits mask' CONFIG_PB_CHANGEABLE_BITS FF + hex ' PA user changeable dir mask' CONFIG_ETRAX_PA_CHANGEABLE_DIR 00 + hex ' PA user changeable bits mask' CONFIG_ETRAX_PA_CHANGEABLE_BITS FF + hex ' PB user changeable dir mask' CONFIG_ETRAX_PB_CHANGEABLE_DIR 00 + hex ' PB user changeable bits mask' CONFIG_ETRAX_PB_CHANGEABLE_BITS FF fi -bool 'Juliette support' CONFIG_JULIETTE n +bool 'ARTPEC-1 support' CONFIG_JULIETTE if [ "$CONFIG_JULIETTE" = "y" ]; then source arch/cris/drivers/juliette/Config.in @@ -136,8 +162,18 @@ bool 'USB host' CONFIG_ETRAX_USB_HOST if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then define_bool CONFIG_USB y - bool ' USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 n - bool ' USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 n + bool ' USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 + bool ' USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 +else + define_bool CONFIG_USB n +fi + +bool 'DS1302 Real Time Clock support' CONFIG_ETRAX_DS1302 +if [ "$CONFIG_ETRAX_DS1302" = "y" ]; then + bool ' DS1302 RST on Generic Port' CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + int ' DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2 + int ' DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1 + int ' DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0 fi endmenu diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile --- v2.4.4/linux/arch/cris/drivers/Makefile Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/Makefile Tue May 1 16:04:56 2001 @@ -12,10 +12,13 @@ obj-$(CONFIG_ETRAX_IDE) += ide.o obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o obj-$(CONFIG_ETRAX_I2C) += i2c.o +obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o obj-$(CONFIG_ETRAX_GPIO) += gpio.o obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o -obj-$(CONFIG_JULIETTE) += juliette/juliette.o -subdir-$(CONFIG_JULIETTE) += juliette +obj-$(CONFIG_ETRAX_PARPORT) += parport.o +obj-$(CONFIG_ETRAX_DS1302) += ds1302.o + + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c --- v2.4.4/linux/arch/cris/drivers/axisflashmap.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/axisflashmap.c Tue May 1 16:04:56 2001 @@ -11,6 +11,15 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.7 2001/04/05 13:41:46 markusl + * Updated according to review remarks + * + * Revision 1.6 2001/03/07 09:21:21 bjornw + * No need to waste .data + * + * Revision 1.5 2001/03/06 16:27:01 jonashg + * Probe the entire flash area for flash devices. + * * Revision 1.4 2001/02/23 12:47:15 bjornw * Uncached flash in LOW_MAP moved from 0xe to 0x8 * @@ -50,19 +59,13 @@ #endif /* - * WINDOW_SIZE is the total size where the flash chips are mapped, - * my guess is that this can be the total memory area even if there - * are many flash chips inside the area or if they are not all mounted. - * So possibly we can get rid of the CONFIG_ here and just write something - * like 32 MB always. - */ - -#define WINDOW_SIZE (CONFIG_ETRAX_FLASH_LENGTH * 1024 * 1024) - -/* Byte-offset where the partition-table is placed in the first chip + * WINDOW_SIZE is the total size where the flash chips may be mapped. + * MTD probes should find all devices there and it does not matter + * if there are unmapped gaps or aliases (mirrors of flash devices). + * The MTD probes will ignore them. */ -#define PTABLE_SECTOR 65536 +#define WINDOW_SIZE (128 * 1024 * 1024) /* * Map driver @@ -70,8 +73,6 @@ * Ok this is the scoop - we need to access the flash both with and without * the cache - without when doing all the fancy flash interfacing, and with * when we do actual copying because otherwise it will be slow like molasses. - * I hope this works the way it's intended, so that there won't be any cases - * of non-synchronicity because of the different access modes below... */ static __u8 flash_read8(struct map_info *map, unsigned long ofs) @@ -110,12 +111,6 @@ *(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d; } -static void flash_copy_to(struct map_info *map, unsigned long to, - const void *from, ssize_t len) -{ - memcpy((void *)(FLASH_CACHED_ADDR + to), from, len); -} - static struct map_info axis_map = { name: "Axis flash", size: WINDOW_SIZE, @@ -127,7 +122,6 @@ write8: flash_write8, write16: flash_write16, write32: flash_write32, - copy_to: flash_copy_to }; /* If no partition-table was found, we use this default-set. @@ -139,18 +133,18 @@ static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { { name: "boot firmware", - size: PTABLE_SECTOR, + size: CONFIG_ETRAX_PTABLE_SECTOR, offset: 0 }, { name: "kernel", size: 0x1a0000, - offset: PTABLE_SECTOR + offset: CONFIG_ETRAX_PTABLE_SECTOR }, { name: "filesystem", size: 0x50000, - offset: (0x1a0000 + PTABLE_SECTOR) + offset: (0x1a0000 + CONFIG_ETRAX_PTABLE_SECTOR) } }; @@ -214,11 +208,11 @@ printk(KERN_NOTICE "Axis flash mapping: %x at %x\n", WINDOW_SIZE, FLASH_CACHED_ADDR); - mymtd = do_cfi_probe(&axis_map); + mymtd = (struct mtd_info *)do_cfi_probe(&axis_map); #ifdef CONFIG_MTD_AMDSTD if (!mymtd) { - mymtd = do_amd_flash_probe(&axis_map); + mymtd = (struct mtd_info *)do_amd_flash_probe(&axis_map); } #endif @@ -236,18 +230,15 @@ */ ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + - PTABLE_SECTOR + PARTITION_TABLE_OFFSET); + CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); pidx++; /* first partition is always set to the default */ if ((ptable_head->magic == PARTITION_TABLE_MAGIC) - && (ptable_head->size - < (MAX_PARTITIONS - * sizeof(struct partitiontable_entry) + 4)) - && (*(unsigned long*) - ((void*)ptable_head - + sizeof(*ptable_head) - + ptable_head->size - 4) - == PARTITIONTABLE_END_MARKER)) { + && (ptable_head->size < + (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + 4)) + && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + + ptable_head->size - 4) + == PARTITIONTABLE_END_MARKER)) { /* Looks like a start, sane length and end of a * partition table, lets check csum etc. */ @@ -256,7 +247,7 @@ (struct partitiontable_entry *) ((unsigned long)ptable_head + sizeof(*ptable_head) + ptable_head->size); - unsigned long offset = PTABLE_SECTOR; + unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; unsigned char *p; unsigned long csum = 0; @@ -293,16 +284,7 @@ && ptable->offset != 0xffffffff && ptable < max_addr && pidx < MAX_PARTITIONS) { -#if 0 - /* wait with multi-chip support until we know - * how mtd detects multiple chips - */ - if ((offset + ptable->offset) >= chips[0].size) { - partitions[pidx].start - = offset + chips[1].start - + ptable->offset - chips[0].size; - } -#endif + axis_partitions[pidx].offset = offset + ptable->offset; axis_partitions[pidx].size = ptable->size; diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/ds1302.c linux/arch/cris/drivers/ds1302.c --- v2.4.4/linux/arch/cris/drivers/ds1302.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/ds1302.c Tue May 1 16:04:56 2001 @@ -0,0 +1,488 @@ +/*!*************************************************************************** +*! +*! FILE NAME : ds1302.c +*! +*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O +*! +*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status +*! +*! $Log: ds1302.c,v $ +*! Revision 1.3 2001/03/26 16:03:06 bjornw +*! Needs linux/config.h +*! +*! Revision 1.2 2001/03/20 19:42:00 bjornw +*! Use the ETRAX prefix on the DS1302 options +*! +*! Revision 1.1 2001/03/20 09:13:50 magnusmn +*! Linux 2.4 port +*! +*! Revision 1.10 2000/07/05 15:38:23 bjornw +*! Dont update kernel time when a RTC_SET_TIME is done +*! +*! Revision 1.9 2000/03/02 15:42:59 macce +*! * Hack to make RTC work on all 2100/2400 +*! +*! Revision 1.8 2000/02/23 16:59:18 torbjore +*! added setup of R_GEN_CONFIG when RTC is connected to the generic port. +*! +*! Revision 1.7 2000/01/17 15:51:43 johana +*! Added RTC_SET_CHARGE ioctl to enable trickle charger. +*! +*! Revision 1.6 1999/10/27 13:19:47 bjornw +*! Added update_xtime_from_cmos which reads back the updated RTC into the kernel. +*! /dev/rtc calls it now. +*! +*! Revision 1.5 1999/10/27 12:39:37 bjornw +*! Disabled superuser check. Anyone can now set the time. +*! +*! Revision 1.4 1999/09/02 13:27:46 pkj +*! Added shadow for R_PORT_PB_CONFIG. +*! Renamed port_g_shadow to port_g_data_shadow. +*! +*! Revision 1.3 1999/09/02 08:28:06 pkj +*! Made it possible to select either port PB or the generic port for the RST +*! signal line to the DS1302 RTC. +*! Also make sure the RST bit is configured as output on Port PB (if used). +*! +*! Revision 1.2 1999/09/01 14:47:20 bjornw +*! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read +*! and set the date. Register as major 121. +*! +*! Revision 1.1 1999/09/01 09:45:29 bjornw +*! Implemented a DS1302 RTC driver. +*! +*! +*! --------------------------------------------------------------------------- +*! +*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! +*! $Id: ds1302.c,v 1.3 2001/03/26 16:03:06 bjornw Exp $ +*! +*!***************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define RTC_MAJOR_NR 121 /* local major, change later */ + +/* The DS1302 might be connected to different bits on different products. + * It has three signals - SDA, SCL and RST. RST and SCL are always outputs, + * but SDA can have a selected direction. + * For now, only PORT_PB is hardcoded. + */ + +/* The RST bit may be on either the Generic Port or Port PB */ +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT +#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#define TK_RST_DIR(x) +#else +#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) +#endif + + +#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) +#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) + +#define TK_SDA_IN() ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1) +/* 1 is out, 0 is in */ +#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) +#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) + + +/* + * The reason for tempudelay and not udelay is that loops_per_usec + * (used in udelay) is not set when functions here are called from time.c + */ + +static void tempudelay(int time) +{ + int i; + for(i = 0; i < time * 10000; i++); +} + + +/* send 8 bits */ +static void +out_byte(int x) +{ + int i; + TK_SDA_DIR(1); + for (i = 8; i--;) { + /* the chip latches incoming bits on the rising edge of SCL */ + TK_SCL_OUT(0); + TK_SDA_OUT(x & 1); + tempudelay(1); + TK_SCL_OUT(1); + tempudelay(1); + x >>= 1; + } + TK_SDA_DIR(0); +} + +static unsigned char +in_byte(void) +{ + unsigned char x = 0; + int i; + + /* Read byte. Bits come LSB first, on the falling edge of SCL. + * Assume SDA is in input direction already + */ + TK_SDA_DIR(0); + + for (i = 8; i--;) { + TK_SCL_OUT(0); + tempudelay(1); + x >>= 1; + x |= (TK_SDA_IN() << 7); + TK_SCL_OUT(1); + tempudelay(1); + } + + return x; +} + +/* prepares for a transaction by de-activating RST (active-low) */ + +static void +start(void) +{ + TK_SCL_OUT(0); + tempudelay(1); + TK_RST_OUT(0); + tempudelay(5); + TK_RST_OUT(1); +} + +/* ends a transaction by taking RST active again */ + +static void +stop(void) +{ + tempudelay(2); + TK_RST_OUT(0); +} + +/* enable writing */ + +static void +ds1302_wenable(void) +{ + start(); + out_byte(0x8e); /* Write control register */ + out_byte(0x00); /* Disable write protect bit 7 = 0 */ + stop(); +} + +/* disable writing */ + +static void +ds1302_wdisable(void) +{ + start(); + out_byte(0x8e); /* Write control register */ + out_byte(0x80); /* Disable write protect bit 7 = 0 */ + stop(); +} + +/* probe for the chip by writing something to its RAM and try reading it back */ + +static int +ds1302_probe(void) +{ + int retval, res; + + TK_RST_DIR(1); + TK_SCL_DIR(1); + TK_SDA_DIR(0); + + /* try to talk to timekeeper */ + + ds1302_wenable(); + start(); + out_byte(0xc0); /* write RAM byte 0 */ + out_byte(0x42); /* write something magic */ + start(); + out_byte(0xc1); /* read RAM byte 0 */ + + if((res = in_byte()) == 0x42) { + char buf[100]; + stop(); + ds1302_wdisable(); + printk("DS1302 RTC found.\n"); + printk("SDA, SCL, RST on PB%i, PB%i, %s%i\n", + CONFIG_ETRAX_DS1302_SDABIT, + CONFIG_ETRAX_DS1302_SCLBIT, +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + "GENIO", +#else + "PB", +#endif + CONFIG_ETRAX_DS1302_RSTBIT + ); + get_rtc_status(buf); + printk(buf); + retval = 1; + } else { + stop(); + printk("DS1302 RTC not found.\n"); + retval = 0; + } + + return retval; +} + + +/* read a byte from the selected register in the DS1302 */ + +unsigned char +ds1302_readreg(int reg) +{ + unsigned char x; + + start(); + out_byte(0x81 | (reg << 1)); /* Read register */ + x = in_byte(); + stop(); + + return x; +} + +/* write a byte to the selected register */ + +void +ds1302_writereg(int reg, unsigned char val) +{ + ds1302_wenable(); + start(); + out_byte(0x80 | (reg << 1)); /* Write register */ + out_byte(val); + stop(); + ds1302_wdisable(); +} + +void +get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); + rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); + rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); + rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); + rtc_tm->tm_year = CMOS_READ(RTC_YEAR); + + restore_flags(flags); + + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + + if (rtc_tm->tm_year <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +static unsigned char days_in_mo[] = + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date) */ + +static int +rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned long flags; + + switch(cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + struct rtc_time rtc_tm; + + get_rtc_time(&rtc_tm); + if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) + return -EFAULT; + return 0; + } + + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control, save_freq_select; + unsigned int yrs; +#if 0 + if (!suser()) + return -EACCES; +#endif + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + + if ((yrs < 1970) || (yrs > 2069)) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if (yrs >= 2000) + yrs -= 2000; /* RTC (0, 1, ... 69) */ + else + yrs -= 1900; /* RTC (70, 71, ... 99) */ + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + save_flags(flags); + cli(); + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + restore_flags(flags); + + /* notice that at this point, the RTC is updated but the kernel + * is still running with the old time. you need to set that + * separately with settimeofday or adjtimex. + */ + return 0; + } + + case RTC_SET_CHARGE: /* Set the RTC TRICKLE CHARGE register */ + { + int tcs_val; + unsigned char save_control, save_freq_select; +#if 0 + if (!suser()) + return -EACCES; +#endif + + if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) + return -EFAULT; + + tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); + ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +/* + * Info exported via "/proc/rtc". + */ + +int +get_rtc_status(char *buf) +{ + char *p; + struct rtc_time tm; + + p = buf; + + get_rtc_time(&tm); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + + return p - buf; +} + + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + ioctl: rtc_ioctl, +}; + +/* just probe for the RTC and register the device to handle the ioctl needed */ + +int +ds1302_init(void) +{ + + /* Ugly hack to handle both 2100 and 2400 hardware. + Remove... + */ + if(!ds1302_probe()) { +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + /* + * Make sure that R_GEN_CONFIG is + * setup correct. + */ + genconfig_shadow = ( (genconfig_shadow & ~IO_MASK(R_GEN_CONFIG, ata) ) | + ( IO_STATE( R_GEN_CONFIG, ata, select ) ) ); + *R_GEN_CONFIG = genconfig_shadow; + if(!ds1302_probe()) + return -1; +#else + return -1; +#endif + } + + if (register_chrdev(RTC_MAJOR_NR, "rtc", &rtc_fops)) { + printk("unable to get major %d for rtc\n", RTC_MAJOR_NR); + return -1; + } + return 0; +} + + diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c --- v2.4.4/linux/arch/cris/drivers/eeprom.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/eeprom.c Tue May 1 16:04:56 2001 @@ -0,0 +1,1161 @@ +/*!************************************************************************** +*! +*! FILE NAME: e100eeprom.c +*! +*! DESCRIPTION: Implements an interface for i2c compatible eeproms to run +*! under linux. +*! Supports 2k, 8k(?) and 16k +*! Uses adaptive timing adjustents by Johan.Adolfsson@axis.com +*! Probing results: +*! 8k or not is detected (the assumes 2k or 16k) +*! 2k or 16k detected using test reads and writes. +*! +*! FUNCTIONS: +*! +*! (Exported) +*! eeprom_init() +*! +*! (Local) +*! +*! eeprom_open() +*! eeprom_lseek() +*! eeprom_read() +*! eeprom_write() +*! eeprom_close() +*! eeprom_address() +*! eeprom_disable_write_protect() +*! +*! +*! $Id: eeprom.c,v 1.3 2001/03/19 16:04:46 markusl Exp $ +*! +*!------------------------------------------------------------------------ +*! HISTORY +*! +*! DATE NAME CHANGES +*! ---- ---- ------- +*! Aug 28 1999 Edgar Iglesias Initial Version +*! Aug 31 1999 Edgar Iglesias Allow simultaneous users. +*! Sep 03 1999 Edgar Iglesias Updated probe. +*! Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*! in the spin-lock. +*! +*! $Log: eeprom.c,v $ +*! Revision 1.3 2001/03/19 16:04:46 markusl +*! Fixed init of fops struct +*! +*! Revision 1.2 2001/03/19 10:35:07 markusl +*! 2.4 port of eeprom driver +*! +*! Revision 1.8 2000/05/18 10:42:25 edgar +*! Make sure to end write cycle on _every_ write +*! +*! Revision 1.7 2000/01/17 17:41:01 johana +*! Adjusted probing and return -ENOSPC when writing outside EEPROM +*! +*! Revision 1.6 2000/01/17 15:50:36 johana +*! Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?) +*! EEPROMs +*! +*! Revision 1.5 1999/09/03 15:07:37 edgar +*! Added bail-out check to the spinlock +*! +*! Revision 1.4 1999/09/03 12:11:17 bjornw +*! Proper atomicity (need to use spinlocks, not if's). users -> busy. +*! +*! +*! (c) 1999 Axis Communications AB, Lund, Sweden +*!**************************************************************************/ + +/********************** INCLUDE FILES SECTION ******************************/ + +#include +#include +#include +#include +#include +#include +#include "i2c.h" + +/********************** CONSTANT AND MACRO SECTION *************************/ +#define D(x) + +/* If we should use adaptive timing or not: */ +//#define EEPROM_ADAPTIVE_TIMING + +#define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */ +#define EEPROM_MINOR_NR 0 + +#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */ +/* + * this one defines how many times to try when eeprom fails. + */ +#define EEPROM_RETRIES 10 + +#define EEPROM_2KB (2 * 1024) +/*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */ +#define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */ +#define EEPROM_16KB (16 * 1024) + +#define i2c_delay(x) udelay(x) + +/********************** TYPE DEFINITION SECTION ****************************/ + +/* + * This structure describes the attached eeprom chip. + * The values are probed for. + */ + +struct eeprom_type +{ + unsigned long size; + unsigned long sequential_write_pagesize; + unsigned char select_cmd; + unsigned long usec_delay_writecycles; /* Min time between write cycles (up to 10ms for some models) */ + unsigned long int usec_delay_step; /* For adaptive algorithm */ + int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */ + + /* this one is to keep the read/write operations atomic */ + wait_queue_head_t wait_q; + int busy; + int retry_cnt_addr; /* Used to keep track of number of retries for + adaptive timing adjustments */ + int retry_cnt_read; + + + +}; + +/********************** LOCAL FUNCTION DECLARATION SECTION *****************/ + +static int eeprom_open (struct inode * inode, struct file * file); +static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig); +static ssize_t eeprom_read (struct file * file, char * buf, size_t count, loff_t *off); +static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off); +static int eeprom_close(struct inode * inode, struct file * file); + +static int eeprom_address(unsigned long addr); +static int read_from_eeprom(char * buf, int count); +static int eeprom_write_buf(unsigned long int addr, + const char * buf, int count); +static int eeprom_read_buf(unsigned long addr, + char * buf, int count); + +static void eeprom_disable_write_protect(void); + + +/********************** GLOBAL VARIABLE DECLARATION SECTION ****************/ + +/********************** LOCAL VARIABLE DECLARATION SECTION *****************/ + +/* chip description */ +static struct eeprom_type eeprom; + +/* + * This is the exported file-operations structure + * for this device. + */ + +struct file_operations eeprom_fops = +{ + llseek: eeprom_lseek, + read: eeprom_read, + write: eeprom_write, + open: eeprom_open, + release: eeprom_close +}; + +/********************** FUNCTION DEFINITION SECTION ************************/ + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_init +*# +*# PARAMETERS : none +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : eeprom init call. Probes for different eeprom models. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Updated probing. Added forced values. +*# +*#**************************************************************************/ + +int __init eeprom_init(void) +{ + init_waitqueue_head(&eeprom.wait_q); + eeprom.busy = 0; + +#if CONFIG_ETRAX_I2C_EEPROM_PROBE +#define EETEXT "Found" +#else +#define EETEXT "Assuming" +#endif + if (register_chrdev(EEPROM_MAJOR_NR, "mem", &eeprom_fops)) + { + printk("unable to get major %d for eeprom device\n", EEPROM_MAJOR_NR); + return -1; + } + + printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n"); + + /* + * Note: Most of this probing method was taken from the printserver (5470e) + * codebase. It did not contain a way of finding the 16Kb chips + * (M24128 or variants). The method used here might not work + * for all models. If you encounter problems the easiest way + * is probably to define your model within #ifdef's, and hard- + * code it. + * + */ + + eeprom.size = 0; + eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/ + eeprom.usec_delay_step = 128; + eeprom.adapt_state = 0; + +#if CONFIG_ETRAX_I2C_EEPROM_PROBE + i2c_start(); + i2c_outbyte(0x80); + if(!i2c_getack()) + { + /* It's not 8k.. */ + int success = 0; + unsigned char buf_2k_start[16]; + + /* Im not sure this will work... :) */ + /* assume 2Kb, if failure go for 16Kb */ + /* Test with 16kB settings.. */ + /* If it's a 2kB EEPROM and we address it outside it's range + * it will mirror the address space: + * 1. We read two locations (that are mirrored), + * if the content differs * it's a 16kB EEPROM. + * 2. if it doesn't differ - write diferent value to one of the locations, + * check the other - if content still is the same it's a 2k EEPROM, + * restore original data. + * + */ +#define LOC1 8 +#define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */ + + /* 2k settings */ + i2c_stop(); + eeprom.size = EEPROM_2KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 16; + if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 ) + { + D(printk("2k start: '%16.16s'\n", buf_2k_start)); + } + else + { + printk("Failed to read in 2k mode!\n"); + } + + /* 16k settings */ + eeprom.size = EEPROM_16KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 64; + + { + unsigned char loc1[4], loc2[4], tmp[4]; + if( eeprom_read_buf(LOC2, loc2, 4) == 4) + { + if( eeprom_read_buf(LOC1, loc1, 4) == 4) + { + D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); +#if 0 + if (memcmp(loc1, loc2, 4) != 0 ) + { + /* It's 16k */ + printk("16k detected in step 1\n"); + eeprom.size = EEPROM_16KB; + success = 1; + } + else +#endif + { + /* Do step 2 check */ + /* Invert value */ + loc1[0] = ~loc1[0]; + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + /* If 2k EEPROM this write will actually write 10 bytes + * from pos 0 + */ + D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); + if( eeprom_read_buf(LOC1, tmp, 4) == 4) + { + D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n", + LOC1, loc1, tmp)); + if (memcmp(loc1, tmp, 4) != 0 ) + { + printk("read and write differs! Not 16kB\n"); + loc1[0] = ~loc1[0]; + + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + + } + i2c_stop(); + /* Go to 2k mode and write original data */ + eeprom.size = EEPROM_2KB; + eeprom.select_cmd = 0xA0; + eeprom.sequential_write_pagesize = 16; + if( eeprom_write_buf(0, buf_2k_start, 16) == 16) + { + } + else + { + printk("Failed to write back 2k start!\n"); + } + + eeprom.size = EEPROM_2KB; + } + } + + if(!success) + { + if( eeprom_read_buf(LOC2, loc2, 1) == 1) + { + D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", + LOC1, loc1, LOC2, loc2)); + if (memcmp(loc1, loc2, 4) == 0 ) + { + /* Data the same, must be mirrored -> 2k */ + /* Restore data */ + printk("2k detected in step 2\n"); + loc1[0] = ~loc1[0]; + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + + } + + eeprom.size = EEPROM_2KB; + } + else + { + printk("16k detected in step 2\n"); + loc1[0] = ~loc1[0]; + /* Data differs, assume 16k */ + /* Restore data */ + if (eeprom_write_buf(LOC1, loc1, 1) == 1) + { + success = 1; + } + else + { + printk("eeprom: Restore 16k failed during probe EEPROM might be corrupt!\n"); + } + + eeprom.size = EEPROM_16KB; + } + } + } + } + } /* read LOC1 */ + } /* address LOC1 */ + if (!success) + { + printk("eeprom: Probing failed!, using 2KB!\n"); + eeprom.size = EEPROM_2KB; + } + } /* read */ + } + } + else + { + i2c_outbyte(0x00); + if(!i2c_getack()) + { + /* No 8k */ + eeprom.size = EEPROM_2KB; + } + else + { + i2c_start(); + i2c_outbyte(0x81); + if (!i2c_getack()) + { + eeprom.size = EEPROM_2KB; + } + else + { + /* It's a 8kB */ + i2c_inbyte(); + eeprom.size = EEPROM_8KB; + } + } + } + i2c_stop(); +#elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB) + eeprom.size = EEPROM_16KB; +#elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB) + eeprom.size = EEPROM_8KB; +#elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB) + eeprom.size = EEPROM_2KB; +#endif + + switch(eeprom.size) + { + case (EEPROM_2KB): + printk("e100eeprom: " EETEXT " i2c compatible 2Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 16; + eeprom.select_cmd = 0xA0; + break; + case (EEPROM_8KB): + printk("e100eeprom: " EETEXT " i2c compatible 8Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 16; + eeprom.select_cmd = 0x80; + break; + case (EEPROM_16KB): + printk("e100eeprom: " EETEXT " i2c compatible 16Kb eeprom.\n"); + eeprom.sequential_write_pagesize = 64; + eeprom.select_cmd = 0xA0; + break; + default: + eeprom.size = 0; + printk("e100eeprom: Did not find a supported eeprom\n"); + break; + } + + + + eeprom_disable_write_protect(); + + return 0; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_open +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Opens the device. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Removed users check. +*# +*#**************************************************************************/ + +static int eeprom_open(struct inode * inode, struct file * file) +{ + + if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR) + return -ENXIO; + if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR) + return -ENXIO; + + if( eeprom.size > 0 ) + { + /* OK */ + return 0; + } + + /* No EEprom found */ + return -EFAULT; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_lseek +*# +*# PARAMETERS : file : Pointer to the file +*# offset : The offset (in bytes) +*# orig : look at the note +*# +*# RETURNS : 0 if OK +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Changes the current file position. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Return -EOVERFLOW when beyond eeprom size. +*# +*#**************************************************************************/ + +static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig) +{ +/* + * orig 0: position from begning of eeprom + * orig 1: relative from current position + * orig 2: position from last eeprom address + */ + + switch (orig) + { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + break; + case 2: + file->f_pos = eeprom.size - offset; + break; + default: + return -EINVAL; + } + + /* truncate position */ + if (file->f_pos < 0) + { + file->f_pos = 0; + return(-EOVERFLOW); + } + + if (file->f_pos >= eeprom.size) + { + file->f_pos = eeprom.size - 1; + return(-EOVERFLOW); + } + + return ( file->f_pos ); +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_read +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# buf : Destination buffer +*# count : max nr bytes to read +*# +*# RETURNS : number of read bytes. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Reads data from eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 17 2000 Johan Adolfsson Initial version +*# +*#**************************************************************************/ +static int eeprom_read_buf(unsigned long addr, + char * buf, int count) +{ + struct file f; + + f.f_pos = addr; + return eeprom_read(&f, buf, count, &addr); +} + + + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_read +*# +*# PARAMETERS : file : Pointer to the file +*# buf : Destination buffer +*# count : max nr bytes to read +*# +*# RETURNS : number of read bytes. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Reads data from eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues +*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*# in the spin-lock. +*# +*#**************************************************************************/ + +static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) +{ + int i, read=0; + unsigned long p = file->f_pos; + + unsigned char page; + + if(p >= eeprom.size) /* Address i 0 - (size-1) */ + { + return -EFAULT; + } + + while(eeprom.busy) + { + interruptible_sleep_on(&eeprom.wait_q); + + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; + + } + eeprom.busy++; + + page = (unsigned char) (p >> 8); + + if(!eeprom_address(p)) + { + printk("eeprom: Read failed to address the eeprom: " + "0x%08X (%i) page: %i\n", p, p, page); + i2c_stop(); + + /* don't forget to wake them up */ + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return -EFAULT; + } + + if( (p + count) > eeprom.size) + { + /* truncate count */ + count = eeprom.size - p; + } + + /* stop dummy write op and initiate the read op */ + i2c_start(); + + /* special case for small eeproms */ + if(eeprom.size < EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) ); + } + + /* go on with the actual read */ + read = read_from_eeprom( buf, count); + + if(read > 0) + { + file->f_pos += read; + } + + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return read; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_write_buf +*# +*# PARAMETERS : addr : Address to write to +*# buf : Data buffer to write from +*# count : number bytes to write +*# +*# RETURNS : number of bytes actualy written. +*# +*# SIDE EFFECTS : None +*# +*# DESCRIPTION : Writes data to eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 17 2000 Johan Adolfsson Initial vesion +*# +*#**************************************************************************/ +static int eeprom_write_buf(unsigned long int addr, + const char * buf, int count) +{ + struct file f; + + f.f_pos = addr; + + return eeprom_write(&f, buf, count, &addr); +} + + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_write +*# +*# PARAMETERS : file : Pointer to the file +*# buf : Data buffer to write from +*# count : number bytes to write +*# +*# RETURNS : number of bytes actualy written. +*# +*# SIDE EFFECTS : updates file->f_pos +*# +*# DESCRIPTION : Writes data to eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues +*# Sep 03 1999 Edgar Iglesias Moved the actual reading to read_from_eeprom +*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted +*# in the spin-lock. +*# May 18 2000 Edgar Iglesias Make sure to end write cycle after every write. +*# +*#**************************************************************************/ + +static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, + loff_t *off) +{ + int i, written, restart=1; + unsigned long p; + + while(eeprom.busy) + { + interruptible_sleep_on(&eeprom.wait_q); + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; + } + eeprom.busy++; + for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) + { + restart = 0; + written = 0; + p = file->f_pos; + + + while( (written < count) && (p < eeprom.size)) + { + /* address the eeprom */ + if(!eeprom_address(p)) + { + printk("eeprom: Write failed to address the eeprom: 0x%08X (%i) \n", + p, p); + i2c_stop(); + + /* don't forget to wake them up */ + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + return -EFAULT; + } +#ifdef EEPROM_ADAPTIVE_TIMING + /* Adaptive algorithm to adjust timing */ + if (eeprom.retry_cnt_addr > 0) + { + /* To Low now */ + D(printk(">D=%i d=%i\n", + eeprom.usec_delay_writecycles, eeprom.usec_delay_step)); + + if (eeprom.usec_delay_step < 4) + { + eeprom.usec_delay_step++; + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + } + else + { + + if (eeprom.adapt_state > 0) + { + /* To Low before */ + eeprom.usec_delay_step *= 2; + if (eeprom.usec_delay_step > 2) + { + eeprom.usec_delay_step--; + } + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + } + else if (eeprom.adapt_state < 0) + { + /* To High before (toggle dir) */ + eeprom.usec_delay_writecycles += eeprom.usec_delay_step; + if (eeprom.usec_delay_step > 1) + { + eeprom.usec_delay_step /= 2; + eeprom.usec_delay_step--; + } + } + } + + eeprom.adapt_state = 1; + } + else + { + /* To High (or good) now */ + D(printk(" 1) + { + if (eeprom.usec_delay_step > 0) + { + eeprom.usec_delay_step *= 2; + eeprom.usec_delay_step--; + } + + if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) + { + eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; + } + } + } + else if (eeprom.adapt_state > 0) + { + /* To Low before (toggle dir) */ + if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) + { + eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; + } + if (eeprom.usec_delay_step > 1) + { + eeprom.usec_delay_step /= 2; + eeprom.usec_delay_step--; + } + + eeprom.adapt_state = -1; + } + + if (eeprom.adapt_state > -100) + { + eeprom.adapt_state--; + } + else + { + /* Restart adaption */ + D(printk("#Restart\n")); + eeprom.usec_delay_step++; + } + } +#endif /* EEPROM_ADAPTIVE_TIMING */ + /* write until we hit a page boundary or count */ + do + { + i2c_outbyte(buf[written]); + if(!i2c_getack()) + { + restart=1; + printk("eeprom: write error, retrying. %d\n", i); + i2c_stop(); + break; + } + written++; + p++; + } while( written < count && ( p % eeprom.sequential_write_pagesize )); + + /* end write cycle */ + i2c_stop(); + i2c_delay(eeprom.usec_delay_writecycles); + } /* while */ + } /* for */ + + eeprom.busy--; + wake_up_interruptible(&eeprom.wait_q); + if (written == 0 && file->f_pos >= eeprom.size){ + return -ENOSPC; + } + file->f_pos += written; + return written; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_close +*# +*# PARAMETERS : inode : Pointer to the inode +*# file : Pointer to the file +*# +*# RETURNS : nothing +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Closes the device. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Removed eeprom.users stuff. +*# +*#**************************************************************************/ + +static int eeprom_close(struct inode * inode, struct file * file) +{ + /* do nothing for now */ + return 0; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_address +*# +*# PARAMETERS : addr : Address to be given to eeprom +*# +*# RETURNS : 1 if OK, 0 if failure. +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Sets the current address of the eeprom. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Aug 28 1999 Edgar Iglesias Initial version +*# Sep 03 1999 Edgar Iglesias Corrected typo. +*# +*#**************************************************************************/ + +static int eeprom_address(unsigned long addr) +{ + int i, j; + unsigned char page, offset; + + page = (unsigned char) (addr >> 8); + offset = (unsigned char) addr; + + for(i = 0; i < EEPROM_RETRIES; i++) + { + /* start a dummy write for addressing */ + i2c_start(); + + if(eeprom.size == EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd ); + i2c_getack(); + i2c_outbyte(page); + } + else + { + i2c_outbyte( eeprom.select_cmd | (page << 1) ); + } + if(!i2c_getack()) + { + /* retry */ + i2c_stop(); + /* Must have a delay here.. 500 works, >50, 100->works 5th time*/ + i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i); + /* The chip needs up to 10 ms from write stop to next start */ + + } + else + { + i2c_outbyte(offset); + + if(!i2c_getack()) + { + /* retry */ + i2c_stop(); + } + else + break; + } + } + + + eeprom.retry_cnt_addr = i; + D(printk("%i\n", eeprom.retry_cnt_addr)); + if(eeprom.retry_cnt_addr == EEPROM_RETRIES) + { + /* failed */ + return 0; + } + return 1; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: read_from_eeprom +*# +*# PARAMETERS : buf : Destination buffer. +*# count : Number of bytes to read. +*# +*# RETURNS : number of read bytes or -EFAULT. +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Reads from current adress. +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Sep 03 1999 Edgar Iglesias Initial version +*# +*#**************************************************************************/ + +static int read_from_eeprom(char * buf, int count) +{ + int i, read=0; + + for(i = 0; i < EEPROM_RETRIES; i++) + { + if(eeprom.size == EEPROM_16KB) + { + i2c_outbyte( eeprom.select_cmd | 1 ); + } + + if(i2c_getack()); + { + break; + } + } + + if(i == EEPROM_RETRIES) + { + printk("eeprom: failed to read from eeprom\n"); + i2c_stop(); + + return -EFAULT; + } + + while( (read < count)) + { + buf[read++] = i2c_inbyte(); + + /* + * make sure we don't ack last byte or you will get very strange + * results! + */ + if(read < count) + { + i2c_sendack(); + } + } + + /* stop the operation */ + i2c_stop(); + + return read; +} + +/*#************************************************************************** +*# +*# FUNCTION NAME: eeprom_disable_write_protect +*# +*# PARAMETERS : None +*# +*# RETURNS : Nothing +*# +*# SIDE EFFECTS : +*# +*# DESCRIPTION : Disables write protection if applicable +*# +*#--------------------------------------------------------------------------- +*# HISTORY +*# +*# DATE NAME CHANGES +*# ---- ---- ------- +*# Jan 14 2000 Johan Adolfsson Initial version (from PS pareerom.c) +*# +*#**************************************************************************/ +#define DBP_SAVE(x) +#define ax_printf printk +static void eeprom_disable_write_protect(void) +{ + /* Disable write protect */ + if (eeprom.size == EEPROM_8KB) + { + /* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 2\n")); + } + i2c_outbyte(0x02); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 3\n")); + } + i2c_stop(); + + i2c_delay(1000); + + /* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 55\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 52\n")); + } + i2c_outbyte(0x06); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 53\n")); + } + i2c_stop(); + + /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh*/ + i2c_start(); + i2c_outbyte(0xbe); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 56\n")); + } + i2c_outbyte(0xFF); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 57\n")); + } + i2c_outbyte(0x06); + if(!i2c_getack()) + { + DBP_SAVE(ax_printf("Get ack returns false 58\n")); + } + i2c_stop(); + + /* Write protect disabled */ + } +} + +module_init(eeprom_init); + +/********************** END OF FILE e100eeprom.c *****************************/ diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c --- v2.4.4/linux/arch/cris/drivers/ethernet.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/ethernet.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: ethernet.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $ +/* $Id: ethernet.c,v 1.12 2001/04/05 11:43:11 tobiasa Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * @@ -7,6 +7,21 @@ * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.12 2001/04/05 11:43:11 tobiasa + * Check dev before panic. + * + * Revision 1.11 2001/04/04 11:21:05 markusl + * Updated according to review remarks + * + * Revision 1.10 2001/03/26 16:03:06 bjornw + * Needs linux/config.h + * + * Revision 1.9 2001/03/19 14:47:48 pkj + * * Make sure there is always a pause after the network LEDs are + * changed so they will not look constantly lit during heavy traffic. + * * Always use HZ when setting times relative to jiffies. + * * Use LED_NETWORK_SET() when setting the network LEDs. + * * Revision 1.8 2001/02/27 13:52:48 bjornw * malloc.h -> slab.h * @@ -40,10 +55,13 @@ * */ +#include + #include #include #include +#include #include #include #include @@ -52,11 +70,7 @@ #include #include #include -#include -#include #include -#include -#include #include #include @@ -65,11 +79,17 @@ #include #include /* DMA and register descriptions */ +#include /* LED_* I/O functions */ +#include +#include +#include //#define ETHDEBUG - #define D(x) +#define ETH_TX_DMA 0 +#define ETH_RX_DMA 1 + /* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels @@ -126,12 +146,12 @@ #define MDIO_PHYS_ADDR 0x0 /* Network flash constants */ -#define NET_FLASH_TIME 2 /* 20 ms */ -#define NET_LINK_UP_CHECK_INTERVAL 200 /* 2 s */ +#define NET_FLASH_TIME (HZ/50) /* 20 ms */ +#define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ +#define NET_LINK_UP_CHECK_INTERVAL (2*HZ) /* 2 s */ -/* RX_DESC_BUF_SIZE should be a multiple of four to avoid the buffer - * alignment bug in Etrax 100 release 1 - */ +#define NO_NETWORK_ACTIVITY 0 +#define NETWORK_ACTIVITY 1 #define RX_DESC_BUF_SIZE 256 #define NBR_OF_RX_DESC (RX_BUF_SIZE / \ @@ -146,8 +166,8 @@ static unsigned char RxBuf[RX_BUF_SIZE]; -static etrax_dma_descr RxDescList[NBR_OF_RX_DESC]; -static etrax_dma_descr TxDesc; +static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); +static etrax_dma_descr TxDesc __attribute__ ((aligned(4))); static struct sk_buff *tx_skb; @@ -155,8 +175,8 @@ static struct timer_list speed_timer; static struct timer_list clear_led_timer; static int current_speed; -static int led_clear_time; -static int nolink; +static int led_next_time; +static int led_active; /* Index to functions, as function prototypes. */ @@ -184,6 +204,7 @@ static void e100_reset_tranceiver(void); static void e100_clear_network_leds(unsigned long dummy); +static void e100_set_network_leds(int active); #define tx_done(dev) (*R_DMA_CH0_CMD == 0) @@ -201,7 +222,7 @@ int i; int anOffset = 0; - printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB\n"); + printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n"); dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ @@ -212,6 +233,8 @@ if (!dev) { printk("dev == NULL. Should this happen?\n"); dev = init_etherdev(dev, sizeof(struct net_local)); + if (!dev) + panic("init_etherdev failed\n"); } /* setup generic handlers and stuff in the dev struct */ @@ -272,13 +295,12 @@ /* Initialize speed indicator stuff. */ - nolink = 0; current_speed = 10; speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.function = e100_check_speed; add_timer(&speed_timer); clear_led_timer.function = e100_clear_network_leds; - clear_led_timer.expires = jiffies + 10; + clear_led_timer.expires = jiffies + HZ/10; add_timer(&clear_led_timer); return 0; @@ -345,8 +367,17 @@ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); - *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ - *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + *R_IRQ_MASK0_CLR = + IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); + + /* clear dma0 and 1 eop and descr irq masks */ + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Reset and wait for the DMA channels */ @@ -383,17 +414,17 @@ * and clean up on failure. */ - if(request_dma(0, cardname)) { + if(request_dma(ETH_TX_DMA, cardname)) { goto grace_exit; } - if(request_dma(1, cardname)) { + if(request_dma(ETH_RX_DMA, cardname)) { grace_exit: /* this will cause some 'trying to free free irq' but what the heck... */ - free_dma(0); - free_irq(NETWORK_DMARX_IRQ, NULL); - free_irq(NETWORK_DMATX_IRQ, NULL); - free_irq(NETWORK_STATUS_IRQ, NULL); + free_dma(ETH_TX_DMA); + free_irq(NETWORK_DMARX_IRQ, (void *)dev); + free_irq(NETWORK_DMATX_IRQ, (void *)dev); + free_irq(NETWORK_STATUS_IRQ, (void *)dev); return -EAGAIN; } @@ -466,21 +497,19 @@ e100_check_speed(unsigned long dummy) { unsigned long data; + int old_speed = current_speed; + data = e100_get_mdio_reg(MDIO_BASE_STATUS_REG); if (!(data & MDIO_LINK_UP_MASK)) { - nolink = 1; - LED_NETWORK_TX_SET(1); /* Make it red, link is down. */ + current_speed = 0; } else { - nolink = 0; - LED_NETWORK_TX_SET(0); /* Link is up again, clear red LED. */ data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); - if (data & MDIO_SPEED) { - current_speed = 100; - } else { - current_speed = 10; - } + current_speed = (data & MDIO_SPEED ? 100 : 10); } + if (old_speed != current_speed) + e100_set_network_leds(NO_NETWORK_ACTIVITY); + /* Reinitialize the timer. */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; add_timer(&speed_timer); @@ -534,23 +563,26 @@ static void e100_send_mdio_bit(unsigned char bit) { - volatile int i; - *R_NETWORK_MGM_CTRL = 2 | bit&1; - for (i=40; i; i--); - *R_NETWORK_MGM_CTRL = 6 | bit&1; - for (i=40; i; i--); + *R_NETWORK_MGM_CTRL = + IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | + IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); + udelay(1); + *R_NETWORK_MGM_CTRL = + IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | + IO_MASK(R_NETWORK_MGM_CTRL, mdck) | + IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); + udelay(1); } static unsigned char e100_receive_mdio_bit() { unsigned char bit; - volatile int i; *R_NETWORK_MGM_CTRL = 0; - bit = *R_NETWORK_STAT & 1; - for (i=40; i; i--); - *R_NETWORK_MGM_CTRL = 4; - for (i=40; i; i--); + bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT); + udelay(1); + *R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck); + udelay(1); return bit; } @@ -566,7 +598,7 @@ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2); - e100_send_mdio_cmd(cmd, 0); + e100_send_mdio_cmd(cmd, 1); data |= 0x8000; @@ -656,8 +688,8 @@ { struct net_device *dev = (struct net_device *)dev_id; unsigned long irqbits = *R_IRQ_MASK2_RD; - - if(irqbits & (1U << 3)) { + + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ @@ -671,10 +703,15 @@ */ e100_rx(dev); ((struct net_local *)dev->priv)->stats.rx_packets++; - *R_DMA_CH1_CMD = 3; /* restart/continue on the channel, for safety */ - *R_DMA_CH1_CLR_INTR = 3; /* clear dma channel 1 eop/descr irq bits */ - /* now, we might have gotten another packet so we have to loop back - and check if so */ + /* restart/continue on the channel, for safety */ + *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart); + /* clear dma channel 1 eop/descr irq bits */ + *R_DMA_CH1_CLR_INTR = + IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do); + + /* now, we might have gotten another packet + so we have to loop back and check if so */ } } } @@ -692,8 +729,9 @@ unsigned long irqbits = *R_IRQ_MASK2_RD; struct net_local *np = (struct net_local *)dev->priv; - if(irqbits & 2) { /* check for a dma0_eop interrupt */ - + /* check for a dma0_eop interrupt */ + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { + /* This protects us from concurrent execution of * our dev->hard_start_xmit function above. */ @@ -727,12 +765,14 @@ struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK0_RD; - if(irqbits & (1 << 19)) { /* check for overrun irq */ + /* check for overrun irq */ + if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { update_rx_stats(&np->stats); /* this will ack the irq */ D(printk("ethernet receiver overrun!\n")); } - if(irqbits & (1 << 17)) { /* check for excessive collision irq */ - *R_NETWORK_TR_CTRL = 1 << 8; /* clear the interrupt */ + /* check for excessive collision irq */ + if(irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { + *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); } @@ -746,23 +786,19 @@ struct sk_buff *skb; int length=0; int i; + struct net_local *np = (struct net_local *)dev->priv; struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; unsigned char *skb_data_ptr; - /* light the network rx packet depending on the current speed. - ** But only if link has been detected. - */ - if (!nolink) - if (current_speed == 10) { - LED_NETWORK_TX_SET(1); - LED_NETWORK_RX_SET(1); - } else - LED_NETWORK_RX_SET(1); - - /* Set the earliest time we may clear the LED */ + if (!led_active && jiffies > led_next_time) { + /* light the network leds depending on the current speed. */ + e100_set_network_leds(NETWORK_ACTIVITY); + + /* Set the earliest time we may clear the LED */ + led_next_time = jiffies + NET_FLASH_TIME; + led_active = 1; + } - led_clear_time = jiffies + NET_FLASH_TIME; - /* If the packet is broken down in many small packages then merge * count how much space we will need to alloc with skb_alloc() for * it to fit. @@ -790,6 +826,7 @@ skb = dev_alloc_skb(length - ETHER_HEAD_LEN); if (!skb) { + np->stats.rx_errors++; printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); return; @@ -798,7 +835,7 @@ skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ -#if 0 +#ifdef ETHDEBUG printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", skb->head, skb->data, skb->tail, skb->end); printk("copying packet to 0x%x.\n", skb_data_ptr); @@ -849,9 +886,17 @@ *R_NETWORK_GEN_CONFIG = IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); - - *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ - *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + + *R_IRQ_MASK0_CLR = + IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | + IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); + + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Stop the receiver and the transmitter */ @@ -864,8 +909,8 @@ free_irq(NETWORK_DMATX_IRQ, (void *)dev); free_irq(NETWORK_STATUS_IRQ, (void *)dev); - free_dma(0); - free_dma(1); + free_dma(ETH_TX_DMA); + free_dma(ETH_RX_DMA); /* Update the statistics here. */ @@ -997,22 +1042,16 @@ e100_hardware_send_packet(char *buf, int length) { D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); - /* light the network leds depending on the current speed. - ** But only if link has been detected. - */ - if (!nolink) { - if (current_speed == 10) { - LED_NETWORK_TX_SET(1); - LED_NETWORK_RX_SET(1); - } else { - LED_NETWORK_RX_SET(1); - } - } - /* Set the earliest time we may clear the LED */ + if (!led_active && jiffies > led_next_time) { + /* light the network leds depending on the current speed. */ + e100_set_network_leds(NETWORK_ACTIVITY); + + /* Set the earliest time we may clear the LED */ + led_next_time = jiffies + NET_FLASH_TIME; + led_active = 1; + } - led_clear_time = jiffies + NET_FLASH_TIME; - /* configure the tx dma descriptor */ TxDesc.sw_len = length; @@ -1028,16 +1067,41 @@ static void e100_clear_network_leds(unsigned long dummy) { - if (jiffies > led_clear_time) { - if (nolink) - LED_NETWORK_TX_SET(1); - else - LED_NETWORK_TX_SET(0); - LED_NETWORK_RX_SET(0); + if (led_active && jiffies > led_next_time) { + e100_set_network_leds(NO_NETWORK_ACTIVITY); + + /* Set the earliest time we may set the LED */ + led_next_time = jiffies + NET_FLASH_PAUSE; + led_active = 0; } - - clear_led_timer.expires = jiffies + 10; + + clear_led_timer.expires = jiffies + HZ/10; add_timer(&clear_led_timer); +} + +static void +e100_set_network_leds(int active) +{ +#ifdef CONFIG_LED_OFF_DURING_ACTIVITY + int light_leds = (active == NO_NETWORK_ACTIVITY); +#else + int light_leds = (active == NETWORK_ACTIVITY); +#endif + + if (!current_speed) { + /* Make LED red, link is down */ + LED_NETWORK_SET(LED_RED); + } + else if (light_leds) { + if (current_speed == 10) { + LED_NETWORK_SET(LED_ORANGE); + } else { + LED_NETWORK_SET(LED_GREEN); + } + } + else { + LED_NETWORK_SET(LED_OFF); + } } static struct net_device dev_etrax_ethernet; /* only got one */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c --- v2.4.4/linux/arch/cris/drivers/parport.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/parport.c Tue May 1 16:04:56 2001 @@ -0,0 +1,591 @@ +/* $Id: parport.c,v 1.4 2001/04/06 13:04:02 hugo Exp $ + * + * Elinux parallel port driver + * NOTE! + * Since par0 shares DMA with ser2 and par 1 shares DMA with ser3 + * this should be handled if both are enabled at the same time. + * THIS IS NOT HANDLED YET! + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Fredrik Hugosson + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK printk +#else +static inline int DPRINTK(void *nothing, ...) {return 0;} +#endif + +/* + * Etrax100 DMAchannels: + * Par0 out : DMA2 + * Par0 in : DMA3 + * Par1 out : DMA4 + * Par1 in : DMA5 + * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding + * DMA and DMA irq + */ + +//#define CONFIG_PAR0_INT 1 +//#define CONFIG_PAR1_INT 1 + +#define SETF(var, reg, field, val) \ + var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val) + +#define SETS(var, reg, field, val) \ + var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val) + +struct etrax100par_struct { + /* parallell port control */ + volatile u32 *reg_ctrl_data; /* R_PARx_CTRL_DATA */ + const volatile u32 *reg_status_data; /* R_PARx_STATUS_DATA */ + volatile u32 *reg_config; /* R_PARx_CONFIG */ + volatile u32 *reg_delay; /* R_PARx_DELAY */ + + /* DMA control */ + int odma; + unsigned long dma_irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + + volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ + volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ + + volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ + volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ + const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ + volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ + + /* Non DMA interrupt stuff */ + unsigned long int_irq; /* R_VECT_MASK_RD */ + const volatile u32 *irq_mask_rd; /* R_IRQ_MASKX_RD */ + volatile u32 *irq_mask_clr; /* R_IRQ_MASKX_RD */ + const volatile u32 *irq_read; /* R_IRQ_READX */ + volatile u32 *irq_mask_set; /* R_IRQ_MASKX_SET */ + unsigned long irq_mask_tx; /* bitmask in R_IRQ_ for tx (ready) int */ + unsigned long irq_mask_rx; /* bitmask in R_IRQ_ for rx (data) int */ + unsigned long irq_mask_ecp_cmd; /* mask in R_IRQ_ for ecp_cmd int */ + unsigned long irq_mask_peri; /* bitmask in R_IRQ_ for peri int */ + int portnr; + + /* ----- end of fields initialised in port_table[] below ----- */ + + // struct etrax_dma_descr tr_descr; + // unsigned char tr_buf[LP_BUFFER_SIZE]; + // const unsigned char *tr_buf_curr; /* current char sent */ + // const unsigned char *tr_buf_last; /* last char in buf */ + + // int fifo_magic; /* fifo amount - bytes left in dma buffer */ + // unsigned char fifo_didmagic; /* a fifo eop has been forced */ + // volatile int tr_running; /* 1 if output is running */ + + struct parport *port; + + /* Shadow registers */ + volatile unsigned long reg_ctrl_data_shadow; /* for R_PARx_CTRL_DATA */ + volatile unsigned long reg_config_shadow; /* for R_PARx_CONFIG */ + volatile unsigned long reg_delay_shadow; /* for R_PARx_DELAY */ +}; + +/* Always have the complete structs here, even if the port is not used! + * (that way we can index this by the port number) + */ +static struct etrax100par_struct port_table[] = { + { + R_PAR0_CTRL_DATA, + R_PAR0_STATUS_DATA, + R_PAR0_CONFIG, + R_PAR0_DELAY, + /* DMA interrupt stuff */ + 2, + 1U << 4, /* uses DMA 2 and 3 */ + R_DMA_CH2_CLR_INTR, + R_DMA_CH2_FIRST, + R_DMA_CH2_CMD, + R_DMA_CH3_CLR_INTR, + R_DMA_CH3_FIRST, + R_DMA_CH3_CMD, + R_DMA_CH3_STATUS, + R_DMA_CH3_HWSW, + /* Non DMA interrupt stuff */ + IO_BITNR(R_VECT_MASK_RD, par0), + R_IRQ_MASK0_RD, + R_IRQ_MASK0_CLR, + R_IRQ_READ0, + R_IRQ_MASK0_SET, + IO_FIELD(R_IRQ_MASK0_RD, par0_ready, 1U), /* tx (ready)*/ + IO_FIELD(R_IRQ_MASK0_RD, par0_data, 1U), /* rx (data)*/ + IO_FIELD(R_IRQ_MASK0_RD, par0_ecp_cmd, 1U), /* ecp_cmd */ + IO_FIELD(R_IRQ_MASK0_RD, par0_peri, 1U), /* peri */ + 0 + }, + { + R_PAR1_CTRL_DATA, + R_PAR1_STATUS_DATA, + R_PAR1_CONFIG, + R_PAR1_DELAY, + /* DMA interrupt stuff */ + 4, + 1U << 8, /* uses DMA 4 and 5 */ + + R_DMA_CH4_CLR_INTR, + R_DMA_CH4_FIRST, + R_DMA_CH4_CMD, + R_DMA_CH5_CLR_INTR, + R_DMA_CH5_FIRST, + R_DMA_CH5_CMD, + R_DMA_CH5_STATUS, + R_DMA_CH5_HWSW, + /* Non DMA interrupt stuff */ + IO_BITNR(R_VECT_MASK_RD, par1), + R_IRQ_MASK1_RD, + R_IRQ_MASK1_CLR, + R_IRQ_READ1, + R_IRQ_MASK1_SET, + IO_FIELD(R_IRQ_MASK1_RD, par1_ready, 1U), /* tx (ready)*/ + IO_FIELD(R_IRQ_MASK1_RD, par1_data, 1U), /* rx (data)*/ + IO_FIELD(R_IRQ_MASK1_RD, par1_ecp_cmd, 1U), /* ecp_cmd */ + IO_FIELD(R_IRQ_MASK1_RD, par1_peri, 1U), /* peri */ + 1 + } +}; + + +#define NR_PORTS (sizeof(port_table)/sizeof(struct etrax100par_struct)) + +static void +parport_etrax_write_data(struct parport *p, unsigned char value) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: etrax_write_data %02X\n", p->portnum, value); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, data, value); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static unsigned char +parport_etrax_read_data(struct parport *p) +{ + unsigned char ret; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + ret = IO_EXTRACT(R_PAR0_STATUS_DATA, data, *info->reg_status_data); + + DPRINTK("* E100 PP %d: etrax_read_data %02X\n", p->portnum, ret); + return ret; +} + + +static void +parport_etrax_write_control(struct parport *p, unsigned char control) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: etrax_write_control %02x\n", p->portnum, control); + + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, strb, + (control & PARPORT_CONTROL_STROBE) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd, + (control & PARPORT_CONTROL_AUTOFD) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init, + (control & PARPORT_CONTROL_INIT) > 0); + SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli, + (control & PARPORT_CONTROL_SELECT) > 0); + + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static unsigned char +parport_etrax_read_control( struct parport *p) +{ + unsigned char ret = 0; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + if (IO_EXTRACT(R_PAR0_CTRL_DATA, strb, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_STROBE; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_AUTOFD; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_INIT; + if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow)) + ret |= PARPORT_CONTROL_SELECT; + + DPRINTK("* E100 PP %d: etrax_read_control %02x\n", p->portnum, ret); + return ret; +} + + +static unsigned char +parport_etrax_frob_control(struct parport *p, unsigned char mask, + unsigned char val) +{ + unsigned char old; + + DPRINTK("* E100 PP %d: frob_control mask %02x, value %02x\n", + p->portnum, mask, val); + old = parport_etrax_read_control(p); + parport_etrax_write_control(p, (old & ~mask) ^ val); + return old; +} + + +static unsigned char +parport_etrax_read_status(struct parport *p) +{ + unsigned char ret = 0; + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + if (IO_EXTRACT(R_PAR0_STATUS_DATA, fault, *info->reg_status_data)) + ret |= PARPORT_STATUS_ERROR; + if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data)) + ret |= PARPORT_STATUS_SELECT; + if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data)) + ret |= PARPORT_STATUS_PAPEROUT; + if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data)) + ret |= PARPORT_STATUS_ACK; + if (!IO_EXTRACT(R_PAR0_STATUS_DATA, busy, *info->reg_status_data)) + ret |= PARPORT_STATUS_BUSY; + + DPRINTK("* E100 PP %d: status register %04x\n", + p->portnum, *info->reg_status_data); + DPRINTK("* E100 PP %d: read_status %02x\n", p->portnum, ret); + return ret; +} + + +static void +parport_etrax_enable_irq(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + *info->irq_mask_set = info->irq_mask_tx; + DPRINTK("* E100 PP %d: enable irq\n", p->portnum); +} + + +static void +parport_etrax_disable_irq(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + *info->irq_mask_clr = info->irq_mask_tx; + DPRINTK("* E100 PP %d: disable irq\n", p->portnum); +} + + +static void +parport_etrax_data_forward(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: forward mode\n", p->portnum); + SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, enable); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static void +parport_etrax_data_reverse(struct parport *p) +{ + struct etrax100par_struct *info = + (struct etrax100par_struct *)p->private_data; + + DPRINTK("* E100 PP %d: reverse mode\n", p->portnum); + SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, disable); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; +} + + +static void +parport_etrax_init_state(struct pardevice *dev, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_init_state\n"); +} + + +static void +parport_etrax_save_state(struct parport *p, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_save_state\n"); +} + + +static void +parport_etrax_restore_state(struct parport *p, struct parport_state *s) +{ + DPRINTK("* E100 PP: parport_etrax_restore_state\n"); +} + + +static void +parport_etrax_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + + +static void +parport_etrax_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + + +static struct +parport_operations pp_etrax_ops = { + parport_etrax_write_data, + parport_etrax_read_data, + + parport_etrax_write_control, + parport_etrax_read_control, + parport_etrax_frob_control, + + parport_etrax_read_status, + + parport_etrax_enable_irq, + parport_etrax_disable_irq, + + parport_etrax_data_forward, + parport_etrax_data_reverse, + + parport_etrax_init_state, + parport_etrax_save_state, + parport_etrax_restore_state, + + parport_etrax_inc_use_count, + parport_etrax_dec_use_count, + + parport_ieee1284_epp_write_data, + parport_ieee1284_epp_read_data, + parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr, + + parport_ieee1284_ecp_write_data, + parport_ieee1284_ecp_read_data, + parport_ieee1284_ecp_write_addr, + + parport_ieee1284_write_compat, + parport_ieee1284_read_nibble, + parport_ieee1284_read_byte, +}; + + +static void +parport_etrax_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct etrax100par_struct *info = (struct etrax100par_struct *) + ((struct parport *)dev_id)->private_data; + DPRINTK("* E100 PP %d: Interrupt received\n", + ((struct parport *)dev_id)->portnum); + *info->irq_mask_clr = info->irq_mask_tx; + parport_generic_irq(irq, (struct parport *)dev_id, regs); +} + +/* ----------- Initialisation code --------------------------------- */ + +static void +parport_etrax_show_parallel_version(void) +{ + printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n"); +} + +#ifdef CONFIG_ETRAX_PAR0_DMA +#define PAR0_USE_DMA 1 +#else +#define PAR0_USE_DMA 0 +#endif + +#ifdef CONFIG_ETRAX_PAR1_DMA +#define PAR1_USE_DMA 1 +#else +#define PAR1_USE_DMA 0 +#endif + +static void +parport_etrax_init_registers(void) +{ + struct etrax100par_struct *info; + int i; + + /* The different times below will be (value*160 + 20) ns, */ + /* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6), */ + /* the setup time will be (6*160+20) = 980ns. */ + + for (i = 0, info = port_table; i < 2; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + info->reg_config_shadow = + IO_STATE(R_PAR0_CONFIG, iseli, inv) | + IO_STATE(R_PAR0_CONFIG, iautofd, inv) | + IO_STATE(R_PAR0_CONFIG, istrb, inv) | + IO_STATE(R_PAR0_CONFIG, iinit, inv) | + IO_STATE(R_PAR0_CONFIG, rle_in, disable) | + IO_STATE(R_PAR0_CONFIG, rle_out, disable) | + IO_STATE(R_PAR0_CONFIG, enable, on) | + IO_STATE(R_PAR0_CONFIG, force, off) | + IO_STATE(R_PAR0_CONFIG, ign_ack, wait) | + IO_STATE(R_PAR0_CONFIG, oe_ack, wait_oe) | + IO_STATE(R_PAR0_CONFIG, mode, manual); + + if ((i == 0 && PAR0_USE_DMA) || (i == 1 && PAR1_USE_DMA)) + info->reg_config_shadow |= + IO_STATE(R_PAR0_CONFIG, dma, enable); + else + info->reg_config_shadow |= + IO_STATE(R_PAR0_CONFIG, dma, disable); + + *info->reg_config = info->reg_config_shadow; + + info->reg_ctrl_data_shadow = + IO_STATE(R_PAR0_CTRL_DATA, peri_int, nop) | + IO_STATE(R_PAR0_CTRL_DATA, oe, enable) | + IO_STATE(R_PAR0_CTRL_DATA, seli, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, autofd, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, strb, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, init, inactive) | + IO_STATE(R_PAR0_CTRL_DATA, ecp_cmd, data) | + IO_FIELD(R_PAR0_CTRL_DATA, data, 0); + *info->reg_ctrl_data = info->reg_ctrl_data_shadow; + + /* Clear peri int without setting shadow */ + *info->reg_ctrl_data = info->reg_ctrl_data_shadow | + IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack); + + info->reg_delay_shadow = + IO_FIELD(R_PAR0_DELAY, setup, 5) | + IO_FIELD(R_PAR0_DELAY, strobe, 5) | + IO_FIELD(R_PAR0_DELAY, hold, 5); + *info->reg_delay = info->reg_delay_shadow; + } + +#ifdef CONFIG_ETRAX_PARALLEL_PORT0 +#ifdef CONFIG_ETRAX_PAR0_DMA + RESET_DMA(2); + WAIT_DMA(2); +#ifdef CONFIG_ETRAX_SERIAL_PORT2 + printk(" Warning - DMA clash with ser2!\n"); +#endif /* SERIAL_PORT2 */ +#endif /* DMA */ +#endif /* PORT0 */ + +#ifdef CONFIG_ETRAX_PARALLEL_PORT1 +#ifdef CONFIG_ETRAX_PAR1_DMA + RESET_DMA(4); + WAIT_DMA(4); +#ifdef CONFIG_ETRAX_SERIAL_PORT3 + printk(" Warning - DMA clash with ser3!\n"); +#endif /* SERIAL_PORT3 */ +#endif /* DMA */ +#endif /* PORT1 */ +} + + +int __init +parport_etrax_init(void) +{ + struct parport *p; + int port_exists = 0; + int i; + struct etrax100par_struct *info; + const char *names[] = { "parallel 0 tx+rx", "parallel 1 tx+rx" }; + + parport_etrax_show_parallel_version(); + parport_etrax_init_registers(); + + for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + p = parport_register_port((unsigned long)0, info->int_irq, + PARPORT_DMA_NONE, &pp_etrax_ops); + if (!p) + continue; + + info->port = p; + p->private_data = info; + /* Axis FIXME: Set mode flags. */ + /* p->modes = PARPORT_MODE_TRISTATE | PARPORT_MODE_SAFEININT; */ + + if(request_irq(info->int_irq, parport_etrax_interrupt, + SA_SHIRQ, names[i], p)) { + parport_unregister_port (p); + continue; + } + + printk(KERN_INFO "%s: ETRAX 100LX port %d using irq\n", + p->name, i); + parport_proc_register(p); + parport_announce_port(p); + port_exists = 1; + } + + return port_exists; +} + +void __exit +parport_etrax_exit(void) +{ + int i; + struct etrax100par_struct *info; + + for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { +#ifndef CONFIG_ETRAX_PARALLEL_PORT0 + if (i == 0) + continue; +#endif +#ifndef CONFIG_ETRAX_PARALLEL_PORT1 + if (i == 1) + continue; +#endif + if (info->int_irq != PARPORT_IRQ_NONE) + free_irq(info->int_irq, info->port); + parport_proc_unregister(info->port); + parport_unregister_port(info->port); + } +} diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c --- v2.4.4/linux/arch/cris/drivers/serial.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/serial.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: serial.c,v 1.10 2001/03/05 13:14:07 bjornw Exp $ +/* $Id: serial.c,v 1.12 2001/04/19 12:23:07 bjornw Exp $ * * Serial port driver for the ETRAX 100LX chip * @@ -7,6 +7,15 @@ * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.12 2001/04/19 12:23:07 bjornw + * CONFIG_RS485 -> CONFIG_ETRAX_RS485 + * + * Revision 1.11 2001/04/05 14:29:48 markusl + * Updated according to review remarks i.e. + * -Use correct types in port structure to avoid compiler warnings + * -Try to use IO_* macros whenever possible + * -Open should never return -EBUSY + * * Revision 1.10 2001/03/05 13:14:07 bjornw * Another spelling fix * @@ -190,7 +199,7 @@ * */ -static char *serial_version = "$Revision: 1.10 $"; +static char *serial_version = "$Revision: 1.12 $"; #include #include @@ -299,6 +308,18 @@ #define REG_BAUD 3 #define REG_XOFF 4 /* this is a 32 bit register */ +/* + * General note regarding the use of IO_* macros in this file: + * + * We will use the bits defined for DMA channel 6 when using various + * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are + * the same for all channels (which of course they are). + * + * We will also use the bits defined for serial port 0 when writing commands + * to the different ports, as these bits too are the same for all ports. + */ + + /* this is the data for the four serial ports in the etrax100 */ /* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ /* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ @@ -343,9 +364,9 @@ /* RS-485 */ -#if defined(CONFIG_RS485) -#if defined(CONFIG_RS485_ON_PA) -static int rs485_pa_bit = CONFIG_RS485_ON_PA_BIT; +#if defined(CONFIG_ETRAX_RS485) +#if defined(CONFIG_ETRAX_RS485_ON_PA) +static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #endif @@ -421,8 +442,8 @@ } }; -#if defined(CONFIG_RS485) && defined(CONFIG_RS485_ON_PA) -unsigned char rs485_pa_port = CONFIG_RS485_ON_PA_BIT; +#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA) +unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #define E100_RTS_MASK 0x20 @@ -668,7 +689,8 @@ { #ifndef CONFIG_SVINTO_SIM /* disable the receiver */ - info->port[REG_REC_CTRL] = (info->rx_ctrl &= ~0x40); + info->port[REG_REC_CTRL] = info->rx_ctrl &= + ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); #endif } @@ -677,7 +699,8 @@ { #ifndef CONFIG_SVINTO_SIM /* enable the receiver */ - info->port[REG_REC_CTRL] = (info->rx_ctrl |= 0x40); + info->port[REG_REC_CTRL] = info->rx_ctrl |= + IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); #endif } @@ -747,14 +770,14 @@ } #endif -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) /* Enable RS-485 mode on selected port. This is UGLY. */ static int e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) { struct e100_serial * info = (struct e100_serial *)tty->driver_data; -#if defined(CONFIG_RS485_ON_PA) +#if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); #endif @@ -766,7 +789,6 @@ return 0; } -/* Enable RS-485 mode on selected port. This is UGLY. */ static int e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) { @@ -782,7 +804,7 @@ * the receiver before initiating a DMA transfer */ e100_rts(info, info->rs485.rts_on_send); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_disable_rx(info); e100_disable_rxdma_irq(info); #endif @@ -824,14 +846,16 @@ max_j = jiffies + (delay_ms * HZ)/1000 + 10; while (jiffies < max_j ) { - if (info->port[REG_STATUS] & 0x20) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { for( i=0 ; i<100; i++ ) {}; - if (info->port[REG_STATUS] & 0x20) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { /* ~25 for loops per usec */ - stop_delay = 25 * (1000000 / info->baud); + stop_delay = 1000000 / info->baud; if(cflags & CSTOPB) stop_delay *= 2; - for( i=0 ; irs485.rts_after_sent); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif @@ -942,7 +966,9 @@ return; #endif /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ - *info->oclrintradr = 3; + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); #ifdef SERIAL_DEBUG_INTR if(info->line == SERIAL_DEBUG_LINE) @@ -987,19 +1013,20 @@ /* our job here is done, don't schedule any new DMA transfer */ info->tr_running = 0; -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) /* Check if we should toggle RTS now */ if (info->rs485.enabled) { /* Make sure fifo is empty */ int in_fifo = 0 ; do{ - in_fifo = (*info->ostatusadr) & 0x007F ; + in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail, + *info->ostatusadr); } while (in_fifo > 0) ; /* Any way to really check transmitter empty? (TEMT) */ /* Control RTS to set to RX mode */ e100_rts(info, info->rs485.rts_after_sent); -#if defined(CONFIG_RS485_DISABLE_RECEIVER) +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif @@ -1060,7 +1087,9 @@ /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ - *info->iclrintradr = 3; + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); if(!tty) /* something wrong... */ return; @@ -1088,7 +1117,9 @@ /* read the status register so we can detect errors */ rstat = info->port[REG_STATUS]; - if(rstat & 0xe) { + if(rstat & (IO_MASK(R_SERIAL0_STATUS, overrun) | + IO_MASK(R_SERIAL0_STATUS, par_err) | + IO_MASK(R_SERIAL0_STATUS, framing_err))) { /* if we got an error, we must reset it by reading the * data_in field */ @@ -1148,7 +1179,7 @@ descr->status = 0; *info->ifirstadr = virt_to_phys(descr); - *info->icmdadr = 1; /* start */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); #ifdef SERIAL_HANDLE_EARLY_ERRORS e100_enable_serial_data_irq(info); @@ -1170,8 +1201,9 @@ /* reset the input dma channel to be sure it works */ - *info->icmdadr = 4; - while((*info->icmdadr & 7) == 4); + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); descr = &info->rec_descr; @@ -1186,7 +1218,8 @@ info->tty->flip.count = 0; *info->ifirstadr = virt_to_phys(descr); - *info->icmdadr = 1; /* start */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); + } @@ -1293,7 +1326,7 @@ static struct timer_list flush_timer; static void -timed_flush_handler(void) +timed_flush_handler(unsigned long ptr) { struct e100_serial *info; int i; @@ -1381,7 +1414,7 @@ PROCSTAT(early_errors_cnt[info->line]++); /* restart the DMA */ - *info->icmdadr = 3; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); } else { /* it was a valid byte, now let the dma do the rest */ #ifdef SERIAL_DEBUG_INTR @@ -1472,7 +1505,7 @@ if (info->flags & ASYNC_INITIALIZED) { free_page(page); restore_flags(flags); - return -EBUSY; + return 0; } if (info->xmit.buf) @@ -1518,14 +1551,22 @@ * Reset the DMA channels and make sure their interrupts are cleared */ - *info->icmdadr = 4; /* reset command */ - *info->ocmdadr = 4; /* reset command */ - - while((*info->icmdadr & 7) == 4); /* wait until reset cycle is complete */ - while((*info->ocmdadr & 7) == 4); - - *info->iclrintradr = 3; /* make sure the irqs are cleared */ - *info->oclrintradr = 3; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + + /* wait until reset cycle is complete */ + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1597,8 +1638,8 @@ /* reset both dma channels */ - *info->icmdadr = 4; - *info->ocmdadr = 4; + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); #endif /* CONFIG_SVINTO_SIM */ @@ -1658,42 +1699,51 @@ #ifndef CONFIG_SVINTO_SIM info->port[REG_BAUD] = cflag_to_etrax_baud(cflag); /* start with default settings and then fill in changes */ - - info->rx_ctrl &= ~(0x07); /* 8 bit, no/even parity */ - info->tx_ctrl &= ~(0x37); /* 8 bit, no/even parity, 1 stop bit, no cts */ + + /* 8 bit, no/even parity */ + info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par)); + + /* 8 bit, no/even parity, 1 stop bit, no cts */ + info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par) | + IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) | + IO_MASK(R_SERIAL0_TR_CTRL, auto_cts)); if ((cflag & CSIZE) == CS7) { /* set 7 bit mode */ - info->tx_ctrl |= 0x01; - info->rx_ctrl |= 0x01; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); } if (cflag & CSTOPB) { /* set 2 stop bit mode */ - info->tx_ctrl |= 0x10; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits); } if (cflag & PARENB) { /* enable parity */ - info->tx_ctrl |= 0x02; - info->rx_ctrl |= 0x02; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); } if (cflag & PARODD) { /* set odd parity */ - info->tx_ctrl |= 0x04; - info->rx_ctrl |= 0x04; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); } if (cflag & CRTSCTS) { /* enable automatic CTS handling */ - info->tx_ctrl |= 0x20; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); } /* make sure the tx and rx are enabled */ - info->tx_ctrl |= 0x40; - info->rx_ctrl |= 0x40; + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); /* actually write the control regs to the hardware */ @@ -2330,7 +2380,7 @@ return -EFAULT; return 0; -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) case TIOCSERSETRS485: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct rs485_control)); @@ -2488,10 +2538,10 @@ /* port closed */ -#if defined(CONFIG_RS485) +#if defined(CONFIG_ETRAX_RS485) if (info->rs485.enabled) { info->rs485.enabled = 0; -#if defined(CONFIG_RS485_ON_PA) +#if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); #endif } diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h --- v2.4.4/linux/arch/cris/drivers/serial.h Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/serial.h Tue May 1 16:04:56 2001 @@ -25,26 +25,26 @@ struct e100_serial { int baud; - volatile unsigned char * port; /* R_SERIALx_CTRL */ - unsigned long irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + volatile u8 *port; /* R_SERIALx_CTRL */ + u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ - volatile unsigned long *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ - volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ - const volatile unsigned short *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ - volatile unsigned long *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ + volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ + volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ + const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ + volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ - volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ - volatile unsigned long *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ - volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ - const volatile unsigned short *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ - volatile unsigned long *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ + volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ + volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD, input */ + const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ + volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ int flags; /* defined in tty.h */ - unsigned char rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ - unsigned char tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ - unsigned char iseteop; /* bit number for R_SET_EOP for the input dma */ + u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ + u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ + u8 iseteop; /* bit number for R_SET_EOP for the input dma */ /* end of fields defined in rs_table[] in .c-file */ unsigned char fifo_didmagic; /* a fifo eop has been forced */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/sync_serial.c linux/arch/cris/drivers/sync_serial.c --- v2.4.4/linux/arch/cris/drivers/sync_serial.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/sync_serial.c Tue May 1 16:04:56 2001 @@ -2,8 +2,9 @@ * Simple synchronous serial port driver for ETRAX 100LX. * * Synchronous serial ports are used for continous streamed data like audio. - * The deault setting for this driver is compatible with the STA 013 MP3 decoder - * The driver can easily be tuned to fit other audio encoder/decoders and SPI + * The default setting for this driver is compatible with the STA 013 MP3 + * decoder. The driver can easily be tuned to fit other audio encoder/decoders + * and SPI * * Copyright (c) 2001 Axis Communications AB * @@ -29,37 +30,43 @@ #include /* The receiver is a bit tricky beacuse of the continous stream of data. */ -/* */ -/* Two DMA descriptors are linked together. Each DMA descriptor is */ -/* responsible for one half of a common buffer. */ -/* */ -/* ------------------------------ */ -/* | ---------- ---------- | */ -/* --> | Descr1 |-->| Descr2 |--- */ -/* ---------- ---------- */ -/* | | */ -/* v v */ -/* ----------------------------- */ -/*  | BUFFER | */ -/* ----------------------------- */ -/* | | */ -/* readp writep */ -/* */ +/* */ +/* Two DMA descriptors are linked together. Each DMA descriptor is */ +/* responsible for one half of a common buffer. */ +/* */ +/* ------------------------------ */ +/* | ---------- ---------- | */ +/* --> | Descr1 |-->| Descr2 |--- */ +/* ---------- ---------- */ +/* | | */ +/* v v */ +/* ----------------------------- */ +/* | BUFFER | */ +/* ----------------------------- */ +/* | | */ +/* readp writep */ +/* */ /* If the application keeps up the pace readp will be right after writep.*/ -/* If the application can't keep the pace we have to throw away data. */ +/* If the application can't keep the pace we have to throw away data. */ /* The idea is that readp should be ready with the data pointed out by */ /* Descr1 when the DMA has filled in Descr2. Otherwise we will discard */ /* the rest of the data pointed out by Descr1 and set readp to the start */ -/* of Descr2 */ +/* of Descr2 */ #define SYNC_SERIAL_MAJOR 125 -#define IN_BUFFER_SIZE 8192 +/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ +/* words can be handled */ + +#define IN_BUFFER_SIZE 12288 #define OUT_BUFFER_SIZE 4096 +#define DEFAULT_FRAME_RATE 0 +#define DEFAULT_WORD_RATE 7 + #define DEBUG(x) -/* Define some macros to access Etrax 100 registers */ +/* Define some macros to access ETRAX 100 registers */ #define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ IO_FIELD(##reg##, field, val) #define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ @@ -81,10 +88,8 @@ char data_avail_bit; /* In R_IRQ_MASK1_RD */ char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */ char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */ - char input_dma_eop_bit; /* In R_IRQ_MASK2_RD */ char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */ char output_dma_bit; /* In R_IRQ_MASK2_RD */ - char eop_bit; /* In R_SET_EOP */ int enabled; /* 1 if port is enabled */ int use_dma; /* 1 if port uses dma */ @@ -125,7 +130,6 @@ static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static void flush_handler(void); /* The ports */ static struct sync_port ports[]= @@ -133,40 +137,36 @@ { R_SYNC_SERIAL1_STATUS, /* status */ R_SYNC_SERIAL1_CTRL, /* ctrl_data */ - R_DMA_CH8_FIRST, /* output_dma_first */ - R_DMA_CH8_CMD, /* output_dma_cmd */ - R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH9_FIRST, /* input_dma_first */ - R_DMA_CH9_CMD, /* input_dma_cmd */ - R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ + R_DMA_CH8_FIRST, /* output_dma_first */ + R_DMA_CH8_CMD, /* output_dma_cmd */ + R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH9_FIRST, /* input_dma_first */ + R_DMA_CH9_CMD, /* input_dma_cmd */ + R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ R_SYNC_SERIAL1_TR_DATA, /* data_out */ R_SYNC_SERIAL1_REC_DATA,/* data in */ IO_BITNR(R_IRQ_MASK1_RD, ser1_data), /* data_avail_bit */ IO_BITNR(R_IRQ_MASK1_RD, ser1_ready), /* transmitter_ready_bit */ IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma9_eop), /* input_dma_eop_bit */ IO_BITNR(R_IRQ_MASK2_RD, dma9_descr), /* input_dma_descr_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ - IO_BITNR(R_SET_EOP, ch9_eop) /* eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ }, { R_SYNC_SERIAL3_STATUS, /* status */ R_SYNC_SERIAL3_CTRL, /* ctrl_data */ - R_DMA_CH4_FIRST, /* output_dma_first */ - R_DMA_CH4_CMD, /* output_dma_cmd */ - R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH5_FIRST, /* input_dma_first */ - R_DMA_CH5_CMD, /* input_dma_cmd */ - R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ + R_DMA_CH4_FIRST, /* output_dma_first */ + R_DMA_CH4_CMD, /* output_dma_cmd */ + R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ + R_DMA_CH5_FIRST, /* input_dma_first */ + R_DMA_CH5_CMD, /* input_dma_cmd */ + R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ R_SYNC_SERIAL3_TR_DATA, /* data_out */ R_SYNC_SERIAL3_REC_DATA,/* data in */ IO_BITNR(R_IRQ_MASK1_RD, ser3_data), /* data_avail_bit */ IO_BITNR(R_IRQ_MASK1_RD, ser3_ready), /* transmitter_ready_bit */ IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma5_eop), /* input_dma_eop_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_eop_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ - IO_BITNR(R_SET_EOP, ch5_eop) /* eop_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_descr_bit */ + IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ } }; @@ -174,9 +174,6 @@ static unsigned sync_serial_prescale_shadow = 0; static unsigned gen_config_ii_shadow = 0; -/* Timer used to flush data from the DMA */ -static struct timer_list flush_timer; - #define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) static struct file_operations sync_serial_fops = { @@ -213,24 +210,25 @@ #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) ports[0].use_dma = 1; initialize_port(0); - if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", NULL)) + if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", &ports[0])) panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", NULL)) + if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[0])) panic("Can't allocate sync serial port 1 IRQ"); RESET_DMA(8); WAIT_DMA(8); RESET_DMA(9); WAIT_DMA(9); - *R_DMA_CH8_CLR_INTR = 3; /* Clear IRQ */ - *R_DMA_CH9_CLR_INTR = 3; /* Clear IRQ */ + *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); + *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); start_dma_in(&ports[0]); #else ports[0].use_dma = 0; initialize_port(0); - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL)) + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0])) panic("Can't allocate sync serial manual irq"); *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set); #endif @@ -243,18 +241,19 @@ #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) ports[1].use_dma = 1; initialize_port(1); - if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", NULL)) + if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", &ports[1])) panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", NULL)) + if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", &ports[1])) panic("Can't allocate sync serial port 1 IRQ"); RESET_DMA(4); WAIT_DMA(4); RESET_DMA(5); WAIT_DMA(5); - *R_DMA_CH4_CLR_INTR = 3; /* Clear IRQ */ - *R_DMA_CH5_CLR_INTR = 3; /* Clear IRQ */ + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); + *R_DMA_CH5_CLR_INTR = IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma5_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set); start_dma_in(&ports[1]); #else @@ -262,7 +261,7 @@ initialize_port(1); if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */ { - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL)) + if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1])) panic("Can't allocate sync serial manual irq"); } *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set); @@ -278,22 +277,14 @@ IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, 0) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, 7) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, DEFAULT_FRAME_RATE) | + IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, DEFAULT_WORD_RATE) | IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal)); /* Select synchronous ports */ *R_GEN_CONFIG_II = gen_config_ii_shadow; - /*Initialize DMA flush timer if dma is used */ - if (ports[0].use_dma || ports[1].use_dma) - { - init_timer(&flush_timer); - flush_timer.function = flush_handler; - mod_timer(&flush_timer, jiffies + 10); - } - - printk("Etrax100LX synchronous serial port driver\n"); + printk("ETRAX 100LX synchronous serial port driver\n"); return 0; } @@ -321,9 +312,9 @@ IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word) | IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on) | IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, running) | + IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, stopped) | IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb) | - IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, enable) | + IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, disable) | IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit) | IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8) | IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8) | @@ -365,27 +356,43 @@ static int sync_serial_release(struct inode *inode, struct file *file) { - ports[MINOR(inode->i_rdev)].busy = 0; + int dev = MINOR(inode->i_rdev); + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + ports[dev].busy = 0; return 0; } static int sync_serial_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + int return_val = 0; int dev = MINOR(file->f_dentry->d_inode->i_rdev); - sync_port* port = &ports[dev]; + sync_port* port; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -1; + } + port = &ports[dev]; /* Disable port while changing config */ if (dev) { RESET_DMA(4); WAIT_DMA(4); - *R_DMA_CH4_CLR_INTR = 3; + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); } else { RESET_DMA(8); WAIT_DMA(8); - *R_DMA_CH8_CLR_INTR = 3; + *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); } *R_GEN_CONFIG_II = gen_config_ii_shadow; @@ -516,7 +523,7 @@ } break; default: - return -EINVAL; + return_val = -1; } /* Set config and enable port */ *port->ctrl_data = port->ctrl_data_shadow; @@ -527,15 +534,23 @@ SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); *R_GEN_CONFIG_II = gen_config_ii_shadow; - return 0; + return return_val; } static ssize_t sync_serial_manual_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { + int dev = MINOR(file->f_dentry->d_inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - sync_port* port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + sync_port* port; + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + + port = &ports[dev]; copy_from_user(port->out_buffer, buf, count); port->outp = port->out_buffer; port->out_count = count; @@ -547,17 +562,36 @@ schedule(); set_current_state(TASK_RUNNING); remove_wait_queue(&port->out_wait_q, &wait); + if (signal_pending(current)) + { + return -EINTR; + } return count; } static ssize_t sync_serial_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { - DECLARE_WAITQUEUE(wait, current); - sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); + sync_port *port; + + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + port = &ports[dev]; DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count)); + count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count; + + /* Make sure transmitter is running */ + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable); + *port->ctrl_data = port->ctrl_data_shadow; + if (!port->use_dma) { return sync_serial_manual_write(file, buf, count, ppos); @@ -570,26 +604,47 @@ schedule(); set_current_state(TASK_RUNNING); remove_wait_queue(&port->out_wait_q, &wait); + if (signal_pending(current)) + { + return -EINTR; + } return count; } static ssize_t sync_serial_read(struct file * file, char * buf, size_t count, loff_t *ppos) { + int dev = MINOR(file->f_dentry->d_inode->i_rdev); int avail; - sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)]; + sync_port *port; char* start; char* end; unsigned long flags; - DEBUG(printk("Read dev %d count\n")); + if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) + { + DEBUG(printk("Invalid minor %d\n", dev)); + return -ENODEV; + } + port = &ports[dev]; + + DEBUG(printk("Read dev %d count %d\n", dev, count)); + + /* Make sure receiver is running */ + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); + SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable); + *port->ctrl_data = port->ctrl_data_shadow; /* Calculate number of available bytes */ while (port->readp == port->writep) /* No data */ { if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); + interruptible_sleep_on(&port->in_wait_q); + if (signal_pending(current)) + { + return -EINTR; + } } /* Save pointers to avoid that they are modified by interrupt */ @@ -673,12 +728,12 @@ return; } port->in_descr1.hw_len = 0; - port->in_descr1.ctrl = d_eop | d_int; + port->in_descr1.ctrl = d_int; port->in_descr1.status = 0; port->in_descr1.next = virt_to_phys(&port->in_descr2); port->in_descr2.hw_len = 0; port->in_descr2.next = virt_to_phys(&port->in_descr1); - port->in_descr2.ctrl = d_eop | d_int; + port->in_descr2.ctrl = d_int; port->in_descr2.status = 0; /* Find out which descriptor to start */ @@ -766,22 +821,6 @@ start_dma_in(port); wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ } - else if (ireg & (1 << port->input_dma_eop_bit)) /* EOP interrupt */ - { - /* EOP interrupt means that DMA has not reached end of descriptor */ - *port->input_dma_clr_irq = - IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); - - /* Find out the current descriptor */ - if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) - port->writep += port->in_descr2.hw_len; - else - port->writep += port->in_descr1.hw_len; - - start_dma_in(port); - wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ - } } } @@ -853,21 +892,6 @@ } } } -} - -static void flush_handler(void) -{ - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - if (ports[i].enabled) - { - *R_SET_EOP = 1 << ports[i].eop_bit; - } - } - /* restart flush timer */ - mod_timer(&flush_timer, jiffies + 10); } module_init(etrax_sync_serial_init); diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c --- v2.4.4/linux/arch/cris/drivers/usb-host.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/drivers/usb-host.c Tue May 1 16:04:56 2001 @@ -623,7 +623,7 @@ traffic_ep->nep = tmp_ep->nep; tmp_ep->nep = virt_to_phys(traffic_ep); - dbg_intr("One ep successfully inserted"); + dbg_intr("One ep sucessfully inserted"); } i++; } @@ -1804,7 +1804,7 @@ r_usb_ept_data); if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* no_error means that this urb was successfully sent or that we have + /* no_error means that this urb was sucessfully sent or that we have some undefinde error*/ if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 || @@ -1888,9 +1888,9 @@ /* This means that the endpoint has no error, is disabled and had inserted traffic, - i.e. transfer successfully completed + i.e. transfer sucessfully completed */ - dbg_ctrl("Last SB for CTRL %d sent successfully", epid); + dbg_ctrl("Last SB for CTRL %d sent sucessfully", epid); handle_control_transfer_attn(epid, 0); } } @@ -1905,9 +1905,9 @@ /* This means that the endpoint has no error, is disabled and had inserted traffic, - i.e. transfer successfully completed + i.e. transfer sucessfully completed */ - dbg_bulk("Last SB for BULK %d sent successfully", epid); + dbg_bulk("Last SB for BULK %d sent sucessfully", epid); handle_bulk_transfer_attn(epid, 0); } } diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile --- v2.4.4/linux/arch/cris/kernel/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/Makefile Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 2001/01/10 21:11:07 bjornw Exp $ +# $Id: Makefile,v 1.4 2001/04/17 13:58:39 orjanf Exp $ # # Makefile for the linux kernel. # @@ -18,7 +18,7 @@ ptrace.o setup.o time.o sys_cris.o shadows.o \ debugport.o semaphore.o -obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_ETRAX_KGDB) += kgdb.o clean: diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/debugport.c linux/arch/cris/kernel/debugport.c --- v2.4.4/linux/arch/cris/kernel/debugport.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/debugport.c Tue May 1 16:04:56 2001 @@ -12,6 +12,12 @@ * init_etrax_debug() * * $Log: debugport.c,v $ + * Revision 1.6 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.5 2001/03/26 14:22:05 bjornw + * Namechange of some config options + * * Revision 1.4 2000/10/06 12:37:26 bjornw * Use physical addresses when talking to DMA * @@ -29,7 +35,7 @@ /* Which serial-port is our debug port ? */ -#if defined(CONFIG_DEBUG_PORT0) || defined(CONFIG_DEBUG_PORT_NULL) +#if defined(CONFIG_ETRAX_DEBUG_PORT0) || defined(CONFIG_ETRAX_DEBUG_PORT_NULL) #define DEBUG_PORT_IDX 0 #define DEBUG_OCMD R_DMA_CH6_CMD #define DEBUG_FIRST R_DMA_CH6_FIRST @@ -43,7 +49,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma6_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT1 +#ifdef CONFIG_ETRAX_DEBUG_PORT1 #define DEBUG_PORT_IDX 1 #define DEBUG_OCMD R_DMA_CH8_CMD #define DEBUG_FIRST R_DMA_CH8_FIRST @@ -57,7 +63,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma8_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT2 +#ifdef CONFIG_ETRAX_DEBUG_PORT2 #define DEBUG_PORT_IDX 2 #define DEBUG_OCMD R_DMA_CH2_CMD #define DEBUG_FIRST R_DMA_CH2_FIRST @@ -71,7 +77,7 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma2_descr, clr) #endif -#ifdef CONFIG_DEBUG_PORT3 +#ifdef CONFIG_ETRAX_DEBUG_PORT3 #define DEBUG_PORT_IDX 3 #define DEBUG_OCMD R_DMA_CH4_CMD #define DEBUG_FIRST R_DMA_CH4_FIRST @@ -97,7 +103,7 @@ unsigned long flags; int in_progress; -#ifdef CONFIG_DEBUG_PORT_NULL +#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL /* no debug printout at all */ return; #endif @@ -111,7 +117,7 @@ save_flags(flags); cli(); -#ifdef CONFIG_KGDB +#ifdef CONFIG_ETRAX_KGDB /* kgdb needs to output debug info using the gdb protocol */ putDebugString(buf, len); restore_flags(flags); diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.4/linux/arch/cris/kernel/entry.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/entry.S Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.15 2001/03/05 13:14:30 bjornw Exp $ +/* $Id: entry.S,v 1.22 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,40 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.22 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.21 2001/04/17 11:33:29 orjanf + * Updated according to review: + * * Included asm/sv_addr_ag.h to get macro for internal register. + * * Corrected comment regarding system call argument passing. + * * Removed comment about instruction being in a delay slot. + * * Added comment about SYMBOL_NAME macro. + * + * Revision 1.20 2001/04/12 08:51:07 hp + * - Add entry for sys_fcntl64. In fact copy last piece from i386 including ... + * - .rept to fill table to safe state with sys_ni_syscall. + * + * Revision 1.19 2001/04/04 09:43:32 orjanf + * * Moved do_sigtrap from traps.c to entry.S. + * * LTASK_PID need not be global anymore. + * + * Revision 1.18 2001/03/26 09:25:02 markusl + * Updated after review, should now handle USB interrupts correctly. + * + * Revision 1.17 2001/03/21 16:12:55 bjornw + * * Always make room for the cpu status record in the frame, in order to + * use the same framelength and layout for both mmu busfaults and normal + * irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore. + * * Fixed bug with using addq for popping the stack in the epilogue - it + * destroyed the flag register. Use instructions that don't affect the + * flag register instead. + * * Removed write to R_PORT_PA_DATA during spurious_interrupt + * + * Revision 1.16 2001/03/20 19:43:02 bjornw + * * Get rid of esp0 setting + * * Give a 7th argument to a systemcall - the stackframe + * * Revision 1.15 2001/03/05 13:14:30 bjornw * Spelling fix * @@ -80,7 +114,8 @@ #include #include - +#include + ;; functions exported from this file .globl _system_call @@ -95,10 +130,11 @@ .globl _spurious_interrupt .globl _hw_bp_trigs .globl _mmu_bus_fault - + .globl _do_sigtrap + .globl _gdb_handle_breakpoint + .globl _sys_call_table - .globl LTASK_PID ;; syscall error codes LENOSYS = 38 @@ -115,11 +151,6 @@ PT_TRACESYS_BIT = 1 - ;; Offset for esp0 into task_struct: current->thread.esp0. - ;; FIXME: In need of padding somewhere, to get dword-alignment. - -THREAD_ESP0 = 597 - ;; some pt_regs offsets (from ptrace.h) LORIG_R10 = 4 @@ -182,7 +213,7 @@ ;; Since we can't have system calls inside interrupts, it should not matter ;; that we don't stack IRP. ;; - ;; In r1 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,r0 + ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp ;; ;; This function looks on the _surface_ like spaghetti programming, but it's ;; really designed so that the fast-path does not force cache-loading of non-used @@ -190,7 +221,7 @@ _system_call: ;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call - push brp ; this is normally push irp + move brp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame push srp push dccr push mof @@ -202,15 +233,11 @@ movs.w -LENOSYS,r0 move.d r0,[sp+LR10] ; put the default return value in r10 in the frame - ;; Perform "current->thread.esp0 = sp". - ;; This used to be a separate function; set_esp0(ssp). - movs.w -8192,r0 ; THREAD_SIZE == 8192 - and.d sp,r0 - - move.d sp,[r0+THREAD_ESP0] - ;; check if this process is syscall-traced + movs.w -8192,r0 ; THREAD_SIZE == 8192 + and.d sp,r0 + move.d [r0+LTASK_PTRACE],r0 btstq PT_TRACESYS_BIT, r0 bmi tracesys @@ -222,6 +249,11 @@ bcc _ret_from_sys_call lslq 2,r9 ; multiply by 4, in the delay slot + ;; as a bonus 7th parameter, we give the location on the stack + ;; of the register structure itself. some syscalls need this. + + push sp + ;; the parameter carrying registers r10, r11, r12 and 13 are intact. ;; the fifth and sixth parameters (if any) was in mof and srp ;; respectively, and we need to put them on the stack. @@ -230,8 +262,8 @@ push mof jsr [r9+_sys_call_table] ; actually do the system call - addq 2*4,sp ; pop the mof and srp parameters - move.d r10,[sp+LR10] ; save the return value + addq 3*4,sp ; pop the mof, srp and regs parameters + move.d r10,[sp+LR10] ; save the return value moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call @@ -274,31 +306,20 @@ pop mof ; multiply overflow register pop dccr ; condition codes pop srp ; subroutine return pointer - jmpu [sp+] ; return by popping irp and jumping there - ;; jmpu takes the U-flag into account to see if we return to - ;; user-mode or kernel mode. + ;; now we have a 4-word SBFS frame which we do not want to restore + ;; using RBF since it was not stacked with SBFS. instead we would like to + ;; just get the PC value to restart it with, and skip the rest of + ;; the frame. + move [sp=sp+16], p8 ; pop the SBFS frame from the sp + jmpu [sp-16] ; return through the irp field in the sbfs frame RBFexit: - cmpq 2, r10 ; was it CRIS_FRAME_FIXUP ? - beq 2f movem [sp+],r13 ; registers r0-r13, in delay slot pop mof ; multiply overflow register pop dccr ; condition codes pop srp ; subroutine return pointer rbf [sp+] ; return by popping the CPU status -2: pop mof ; multiply overflow register - pop dccr ; condition codes - pop srp ; subroutine return pointer - ;; now we have a 4-word SBFS frame which we do not want to restore - ;; using RBF since we have made a fixup. instead we would like to - ;; just get the PC value to restart it with, and skip the rest of - ;; the frame. - pop irp ; fixup location will be here - reti ; return to IRP, taking U-flag into account - addq 12,sp ; Skip rest of SBFS frame. - - tracesys: ;; this first invocation of syscall_trace _requires_ that ;; LR10 in the frame contains -LENOSYS (as is set in the beginning @@ -332,13 +353,19 @@ move [sp+LMOF], mof move [sp+LSRP], srp + ;; as a bonus 7th parameter, we give the location on the stack + ;; of the register structure itself. some syscalls need this. + + push sp + ;; the fifth and sixth parameters needs to be put on the stack for ;; the system call to find them push srp push mof + jsr r9 ; actually call the system-call - addq 2*4,sp ; pop the r0 parameter + addq 3*4,sp ; pop the srp, mof and regs parameters 1: move.d r10,[sp+LR10] ; save the return value @@ -354,8 +381,7 @@ LTHREAD_KSP = 0 LTHREAD_USP = 4 -LTHREAD_ESP0 = 8 -LTHREAD_DCCR = 12 +LTHREAD_DCCR = 8 ;; _resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct @@ -468,8 +494,6 @@ _IRQ1_interrupt: _spurious_interrupt: di - move.b 4,r0 - move.b r0,[0xb0000030] basse2: ba basse2 nop @@ -479,7 +503,7 @@ _multiple_interrupt: ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! - push irp + move irp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame push srp push dccr push mof @@ -491,15 +515,15 @@ move.d _irq_shortcuts + 8,r1 moveq 2,r2 ; first bit we care about is the timer0 irq - move.d [0xb00000d8],r0 ; read the irq bits that triggered the multiple irq + move.d [R_VECT_MASK_RD],r0 ; read the irq bits that triggered the multiple irq multloop: btst r2,r0 ; check for the irq given by bit r2 bmi do_shortcut ; actually do the shortcut nop - addq 1,r2 ; next vector bit - remember this is in the delay slot! + addq 1,r2 ; next vector bit addq 4,r1 ; next vector - cmpq 26,r2 - bne multloop ; process all irq's up to and including number 25 + cmp.b 32,r2 + bne multloop ; process all irq's up to and including number 31 nop ;; strange, we didn't get any set vector bits.. oh well, just return @@ -513,6 +537,48 @@ nop jump [r1] ; jump to the irq handlers shortcut +_do_sigtrap: + ;; + ;; SIGTRAP the process that executed the break instruction. + ;; Make a frame that Rexit in entry.S expects. + ;; + move brp,[sp=sp-16] ; Push BRP while faking a cpu status record. + push srp ; Push subroutine return pointer. + push dccr ; Push condition codes. + push mof ; Push multiply overflow reg. + di ; Need to disable irq's at this point. + subq 14*4,sp ; Make room for r0-r13. + movem r13,[sp] ; Push the r0-r13 registers. + push r10 ; Push orig_r10. + clear.d [sp=sp-4] ; Frametype - this is a normal stackframe. + + movs.w -8192,r9 ; THREAD_SIZE == 8192 + and.d sp,r9 + move.d [r9+LTASK_PID],r10 ; current->pid as arg1. + moveq 5,r11 ; SIGTRAP as arg2. + jsr _sys_kill + jump _ret_from_intr ; Use the return routine for interrupts. + +_gdb_handle_breakpoint: + push dccr + push r0 +#ifdef CONFIG_ETRAX_KGDB + move dccr,r0 ; U-flag not affected by previous insns. + btstq 8,r0 ; Test the U-flag. + bmi _ugdb_handle_breakpoint ; Go to user mode debugging. + nop ; Empty delay slot (cannot pop r0 here). + pop r0 ; Restore r0. + ba _kgdb_handle_breakpoint ; Go to kernel debugging. + pop dccr ; Restore dccr in delay slot. +#endif + +_ugdb_handle_breakpoint: + move brp,r0 ; Use r0 temporarily for calculation. + subq 2,r0 ; Set to address of previous instruction. + move r0,brp + pop r0 ; Restore r0. + ba _do_sigtrap ; SIGTRAP the offending process. + pop dccr ; Restore dccr in delay slot. .data @@ -521,8 +587,11 @@ _hw_bp_trig_ptr: .dword _hw_bp_trigs -/* linux/linkage.h got it wrong for this compiler currently */ - +/* Because we compile this file with -traditional, we need to redefine + token-concatenation to the traditional trick, using an empty comment. + Normally (in other files, with ISO C as in gcc default) this is done + with the ## preprocessor operator. */ + #undef SYMBOL_NAME #define SYMBOL_NAME(X) _/**/X @@ -748,6 +817,8 @@ .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ /* * NOTE!! This doesn't have to be exact - we just have @@ -756,9 +827,7 @@ * been shrunk every time we add a new system call. */ - ;; TODO: this needs to actually generate sys_ni_syscall entires - ;; since we now have removed the check for NULL entries in this - ;; table in system_call! - - .space (NR_syscalls-220)*4 + .rept NR_syscalls-221 + .long SYMBOL_NAME(sys_ni_syscall) + .endr diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S --- v2.4.4/linux/arch/cris/kernel/head.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/head.S Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.20 2001/02/23 12:47:56 bjornw Exp $ +/* $Id: head.S,v 1.29 2001/04/18 12:51:59 orjanf Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,40 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.29 2001/04/18 12:51:59 orjanf + * * Reverted review change regarding the use of bcs/bcc. + * * Removed non-working LED-clearing code. + * + * Revision 1.28 2001/04/17 13:58:39 orjanf + * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. + * + * Revision 1.27 2001/04/17 11:42:35 orjanf + * Changed according to review: + * * Added comment explaining memory map bug. + * * Changed bcs and bcc to blo and bhs, respectively. + * * Removed mentioning of Stallone and Olga boards. + * + * Revision 1.26 2001/04/06 12:31:07 jonashg + * Check for cramfs in flash before RAM instead of RAM before flash. + * + * Revision 1.25 2001/04/04 06:23:53 starvik + * Initialize DRAM if not already initialized + * + * Revision 1.24 2001/04/03 11:12:00 starvik + * Removed dram init (done by rescue or etrax100boot + * Corrected include + * + * Revision 1.23 2001/04/03 09:53:03 starvik + * Include hw_settings.S + * + * Revision 1.22 2001/03/26 14:23:26 bjornw + * Namechange of some config options + * + * Revision 1.21 2001/03/08 12:14:41 bjornw + * * Config name for ETRAX IDE was renamed + * * Removed G27 auto-setting when JULIETTE is chosen (need to make this + * a new config option later) + * * Revision 1.20 2001/02/23 12:47:56 bjornw * MMU regs during LOW_MAP updated to reflect a newer reality * @@ -76,7 +110,8 @@ #include #define CRAMFS_MAGIC 0x28cd3d45 - +#define RAM_INIT_MAGIC 0x56902387 + ;; exported symbols .globl _etrax_irv @@ -92,9 +127,9 @@ ;; since etrax actually starts at address 2 when booting from flash, we ;; put a nop (2 bytes) here first so we dont accidentally skip the di ;; - ;; NOTICE! The register r9 is used as a parameter carrying register from - ;; the decompressor (if the kernel was compressed). It should not be - ;; used in the code below until it is read. + ;; NOTICE! The registers r8 and r9 are used as a parameter carrying + ;; information from the decompressor (if the kernel was compressed). + ;; They should not be used in the code below until it is read. nop di @@ -109,6 +144,7 @@ ;; ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory ;; slightly different. We also let the simulator get this mapping for now. + ;; (The bug is that you can't remap bit 31.) #ifdef CONFIG_CRIS_LOW_MAP move.d 0x0004b098, r0 ; kseg mappings, temporary map of 0xc0->0x40 @@ -161,8 +197,14 @@ inflash: ;; We need to initialze DRAM registers before we start using the DRAM -#include "../lib/dram_init.S" + cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? + beq dram_init_finished + nop + +#include "../lib/dram_init.S" + +dram_init_finished: ;; Copy text+data to DRAM ;; This is fragile - the calculation of r4 as the image size depends ;; on that the labels below actually are the first and last positions @@ -218,7 +260,39 @@ moveq 0, r0 move.d r0, [_romfs_length] ; default if there is no cramfs - ;; First check if there is a cramfs (magic value) + ;; The kernel could have been unpacked to DRAM by the loader, but + ;; the cramfs image could still be in the Flash directly after the + ;; compressed kernel image. The loader passes the address of the + ;; byte succeeding the last compressed byte in the flash in the + ;; register r9 when starting the kernel. Check if r9 points to a + ;; decent cramfs image! + ;; (Notice that if this is not booted from the loader, r9 will be + ;; garbage but we do sanity checks on it, the chance that it points + ;; to a cramfs magic is small.. ) + + cmp.d 0x0ffffff8, r9 + bcc no_romfs_in_flash ; r9 points outside the flash area + nop + move.d [r9], r0 ; cramfs_super.magic + cmp.d CRAMFS_MAGIC, r0 + bne no_romfs_in_flash + nop + move.d [r9+4], r0 ; cramfs_super.length + move.d r0, [_romfs_length] +#ifdef CONFIG_CRIS_LOW_MAP + add.d 0x50000000, r9 ; add flash start in virtual memory (cached) +#else + add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) +#endif + move.d r9, [_romfs_start] + + moveq 1, r0 + move.d r0, [_romfs_in_flash] + + jump start_it ; enter code, cached this time + +no_romfs_in_flash: + ;; Check if there is a cramfs (magic value). ;; Notice that we check for cramfs magic value - which is ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does ;; not need this mechanism anyway) @@ -226,7 +300,7 @@ move.d __vmlinux_end, r0 ; the image will be after the vmlinux end address move.d [r0], r1 ; cramfs assumes same endian on host/target cmp.d CRAMFS_MAGIC, r1; magic value in cramfs superblock - bne no_romfs_in_ram + bne 1f nop ;; Ok. What is its size ? @@ -263,40 +337,6 @@ move.d r0, [_romfs_in_flash] jump start_it ; better skip the additional cramfs check below - -no_romfs_in_ram: - - ;; We have still one other possibility at this point - the kernel - ;; could have been unpacked to DRAM by the loader, but the cramfs - ;; image was still in the Flash directly after the compressed kernel - ;; image. The loader passes the address of the byte succeeding the - ;; last compressed byte in the flash in the register r9 when starting - ;; the kernel. Check if r9 points to a decent cramfs image! - ;; (Notice that if this is not booted from the loader, r9 will be - ;; garbage but we do sanity checks on it, the chance that it points - ;; to a cramfs magic is small.. ) - - cmp.d 0x0ffffff8, r9 - bcc 1f ; r9 points outside the flash area - nop - move.d [r9], r0 ; cramfs_super.magic - cmp.d CRAMFS_MAGIC, r0 - bne 1f - nop - move.d [r9+4], r0 ; cramfs_super.length - move.d r0, [_romfs_length] -#ifdef CONFIG_CRIS_LOW_MAP - add.d 0x50000000, r9 ; add flash start in virtual memory (cached) -#else - add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) -#endif - move.d r9, [_romfs_start] - - moveq 1, r0 - move.d r0, [_romfs_in_flash] -1: - - jump start_it ; enter code, cached this time start_it: ;; the kernel stack is overlayed with the task structure for each @@ -368,10 +408,10 @@ ;; Etrax product HW genconfig setup moveq 0,r0 -#if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY) +#if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY) or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA #endif -#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1) +#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA #endif #ifdef CONFIG_DMA_MEMCPY @@ -389,7 +429,7 @@ #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) or.w 0x80,r0 ; parport 1 enabled using DMA 4/5 #endif -#ifdef CONFIG_BLK_DEV_ETRAXIDE +#ifdef CONFIG_ETRAX_IDE or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled #endif @@ -405,9 +445,6 @@ #ifdef CONFIG_JULIETTE or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette -#ifndef CONFIG_BLK_DEV_ETRAXIDE - or.d 0x41,r0 ; HACK for now! To make G27 connected for the RTC -#endif #endif move.d r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG @@ -447,20 +484,20 @@ ;; setup port PA and PB default initial directions and data ;; including their shadow registers - move.b DEF_R_PORT_PA_DIR,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,r0 move.b r0,[_port_pa_dir_shadow] move.b r0,[R_PORT_PA_DIR] - move.b DEF_R_PORT_PA_DATA,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA,r0 move.b r0,[_port_pa_data_shadow] move.b r0,[R_PORT_PA_DATA] - move.b DEF_R_PORT_PB_CONFIG,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,r0 move.b r0,[_port_pb_config_shadow] move.b r0,[R_PORT_PB_CONFIG] - move.b DEF_R_PORT_PB_DIR,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR,r0 move.b r0,[_port_pb_dir_shadow] move.b r0,[R_PORT_PB_DIR] - move.b DEF_R_PORT_PB_DATA,r0 + move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA,r0 move.b r0,[_port_pb_data_shadow] move.b r0,[R_PORT_PB_DATA] move.d 0, r0 @@ -499,12 +536,6 @@ move.b 0x40,r0 ; tr enable move.b r0,[R_SERIAL1_TR_CTRL] -#ifdef CONFIG_ETRAX_90000000_LEDS - ;; clear LED's on Stallone and Olga boards - moveq -1,r0 - move.d r0,[_port_90000000_shadow] - move.d r0,[0x90000000] -#endif #ifdef CONFIG_ETRAX_SERIAL_PORT3 ;; setup the serial port 3 at 115200 baud for debug purposes @@ -544,3 +575,5 @@ #else _swapper_pg_dir = 0xc0002000 #endif + +#include "../lib/hw_settings.S" diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c --- v2.4.4/linux/arch/cris/kernel/irq.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/irq.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.11 2001/02/27 13:52:52 bjornw Exp $ +/* $Id: irq.c,v 1.14 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/kernel/irq.c * @@ -160,7 +160,7 @@ BUILD_IRQ(23, 0x800000) BUILD_IRQ(24, 0x1000000) BUILD_IRQ(25, 0x2000000) -/* IRQ 26-30 are resereved */ +/* IRQ 26-30 are reserved */ BUILD_IRQ(31, 0x80000000) /* @@ -261,11 +261,11 @@ irq_enter(cpu); kstat.irqs[cpu][irq]++; - action = *(irq + irq_action); + action = irq_action[irq]; if (action) { if (!(action->flags & SA_INTERRUPT)) __sti(); - action = *(irq + irq_action); + action = irq_action[irq]; do_random = 0; do { do_random |= action->flags; @@ -396,7 +396,7 @@ save_flags(flags); cli(); *p = action->next; - if (!irq[irq_action]) { + if (!irq_action[irq]) { mask_irq(irq); set_int_vector(irq, bad_interrupt[irq], 0); } @@ -419,8 +419,8 @@ */ void system_call(void); /* from entry.S */ -void gdb_handle_breakpoint(void); /* from traps.c */ -void do_sigtrap(void); /* also from traps.c */ +void do_sigtrap(void); /* from entry.S */ +void gdb_handle_breakpoint(void); /* from entry.S */ void init_IRQ(void) { @@ -475,10 +475,10 @@ /* setup a breakpoint handler for debugging used for both user and kernel mode debugging (which is why it is not inside an ifdef - CONFIG_KGDB) */ + CONFIG_ETRAX_KGDB) */ set_break_vector(8, gdb_handle_breakpoint); -#ifdef CONFIG_KGDB +#ifdef CONFIG_ETRAX_KGDB /* setup kgdb if its enabled, and break into the debugger */ kgdb_init(); breakpoint(); diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c --- v2.4.4/linux/arch/cris/kernel/kgdb.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/kgdb.c Tue May 1 16:04:56 2001 @@ -18,6 +18,9 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.5 2001/04/17 13:58:39 orjanf +*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. +*! *! Revision 1.4 2001/02/23 13:45:19 bjornw *! config.h check *! @@ -49,7 +52,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.4 2001/02/23 13:45:19 bjornw Exp $ +*! $Id: kgdb.c,v 1.5 2001/04/17 13:58:39 orjanf Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -60,8 +63,8 @@ * kgdb usage notes: * ----------------- * - * If you select CONFIG_KGDB in the configuration, the kernel will be built - * with different gcc flags: "-g" is added to get debug infos, and + * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be + * built with different gcc flags: "-g" is added to get debug infos, and * "-fomit-frame-pointer" is omitted to make debugging easier. Since the * resulting kernel will be quite big (approx. > 7 MB), it will be stripped * before compresion. Such a kernel will behave just as usually, except if diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c --- v2.4.4/linux/arch/cris/kernel/process.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/process.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.12 2001/02/27 13:52:52 bjornw Exp $ +/* $Id: process.c,v 1.13 2001/03/20 19:44:06 bjornw Exp $ * * linux/arch/cris/kernel/process.c * @@ -7,6 +7,10 @@ * * Authors: Bjorn Wesen (bjornw@axis.com) * + * $Log: process.c,v $ + * Revision 1.13 2001/03/20 19:44:06 bjornw + * Use the 7th syscall argument for regs instead of current_regs + * */ /* @@ -33,6 +37,8 @@ #include #include #include +#include + #include //#define DEBUG @@ -64,13 +70,6 @@ static int hlt_counter=0; -/* in a system call, set_esp0 is called to remember the stack frame, therefore - in the implementation of syscalls we can use that value to access the stack - frame and saved registers. -*/ - -#define currentregs ((struct pt_regs *)current->thread.esp0) - void disable_hlt(void) { hlt_counter++; @@ -178,7 +177,7 @@ * remember that the task_struct doubles as the kernel stack for the task */ - childregs = ((struct pt_regs *) ((unsigned long)p + THREAD_SIZE)) - 1; + childregs = user_regs(p); *childregs = *regs; /* struct copy of pt_regs */ @@ -202,14 +201,11 @@ p->thread.ksp = (unsigned long) swstack; - /* esp0 keeps the pt_regs stacked structure pointer */ - - p->thread.esp0 = (unsigned long) childregs; - #ifdef DEBUG - printk("kern_stack_page 0x%x, used stack %d, thread.usp 0x%x, usp 0x%x\n", - current->kernel_stack_page, usedstack, p->thread.usp, usp); + printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); + show_registers(childregs); #endif + return 0; } @@ -240,33 +236,53 @@ #endif } -asmlinkage int sys_fork(void) +/* + * Be aware of the "magic" 7th argument in the four system-calls below. + * They need the latest stackframe, which is put as the 7th argument by + * entry.S. The previous arguments are dummies or actually used, but need + * to be defined to reach the 7th argument. + * + * N.B.: Another method to get the stackframe is to use current_regs(). But + * it returns the latest stack-frame stacked when going from _user mode_ and + * some of these (at least sys_clone) are called from kernel-mode sometimes + * (for example during kernel_thread, above) and thus cannot use it. Thus, + * to be sure not to get any surprises, we use the method for the other calls + * as well. + */ + +asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), currentregs, 0); + return do_fork(SIGCHLD, rdusp(), regs, 0); } /* if newusp is 0, we just grab the old usp */ -asmlinkage int sys_clone(unsigned long newusp, unsigned long flags) +asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, + long r12, long r13, long mof, long srp, + struct pt_regs *regs) { if (!newusp) newusp = rdusp(); - return do_fork(flags, newusp, currentregs, 0); + return do_fork(flags, newusp, regs, 0); } /* vfork is a system call in i386 because of register-pressure - maybe * we can remove it and handle it in libc but we put it here until then. */ -asmlinkage int sys_vfork(void) +asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), currentregs, 0); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); } /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *fname, char **argv, char **envp) +asmlinkage int sys_execve(const char *fname, char **argv, char **envp, + long r13, long mof, long srp, + struct pt_regs *regs) { int error; char *filename; @@ -276,7 +292,7 @@ if (IS_ERR(filename)) goto out; - error = do_execve(filename, argv, envp, currentregs); + error = do_execve(filename, argv, envp, regs); putname(filename); out: return error; diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c --- v2.4.4/linux/arch/cris/kernel/ptrace.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/ptrace.c Tue May 1 16:04:56 2001 @@ -3,11 +3,18 @@ * * Parts taken from the m68k port. * - * Copyright (c) 2000 Axis Communications AB + * Copyright (c) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen * * $Log: ptrace.c,v $ + * Revision 1.5 2001/03/26 14:24:28 orjanf + * * Changed loop condition. + * * Added comment documenting non-standard ptrace behaviour. + * + * Revision 1.4 2001/03/20 19:44:41 bjornw + * Use the user_regs macro instead of thread.esp0 + * * Revision 1.3 2000/12/18 23:45:25 bjornw * Linux/CRIS first version * @@ -49,8 +56,8 @@ if (regno == PT_USP) return task->thread.usp; - else if (regno <= PT_MAX) - return ((unsigned long *)(task->thread.esp0))[regno]; + else if (regno < PT_MAX) + return ((unsigned long *)user_regs(task))[regno]; else return 0; } @@ -65,12 +72,20 @@ if (regno == PT_USP) task->thread.usp = data; - else if (regno <= PT_MAX) - ((unsigned long *)(task->thread.esp0))[regno] = data; + else if (regno < PT_MAX) + ((unsigned long *)user_regs(task))[regno] = data; else return -1; return 0; } + +/* Note that this implementation of ptrace behaves differently from vanilla + * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, + * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not + * ignored. Instead, the data variable is expected to point at a location + * (in user space) where the result of the ptrace call is written (instead of + * being returned). + */ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c --- v2.4.4/linux/arch/cris/kernel/setup.c Fri Apr 27 14:10:31 2001 +++ linux/arch/cris/kernel/setup.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.11 2001/03/02 15:52:03 bjornw Exp $ +/* $Id: setup.c,v 1.14 2001/04/03 12:54:12 starvik Exp $ * * linux/arch/cris/kernel/setup.c * @@ -60,7 +60,7 @@ * given by the macro __pa(). * * In this DRAM, the kernel code and data is loaded, in the beginning. - * It really starts at c00a0000 to make room for some special pages - + * It really starts at c0004000 to make room for some special pages - * the start address is text_start. The kernel data ends at _end. After * this the ROM filesystem is appended (if there is any). * @@ -77,11 +77,6 @@ unsigned long memory_start; extern void console_print_etrax(const char *b); -#if (defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)) - /* TODO: move this into flash_init I think */ - flash_probe(); -#endif - /* register an initial console printing routine for printk's */ init_etrax_debug(); @@ -167,8 +162,9 @@ paging_init(); - /* we dont use a command line yet, so just let it be an empty string */ - + /* we dont use a command line yet, so just let it be an empty string + to start with */ + *cmdline_p = command_line; strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */ diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/shadows.c linux/arch/cris/kernel/shadows.c --- v2.4.4/linux/arch/cris/kernel/shadows.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/shadows.c Tue May 1 16:04:56 2001 @@ -1,20 +1,36 @@ -/* $Id: shadows.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $ +/* $Id: shadows.c,v 1.2 2001/03/15 14:25:16 bjornw Exp $ * - * Various Etrax shadow registers. Defines for these are in include/asm-etrax100/io.h + * Various shadow registers. Defines for these are in include/asm-etrax100/io.h */ -#include +/* Shadows for internal Etrax-registers */ + +unsigned long genconfig_shadow; +unsigned long port_g_data_shadow; +unsigned char port_pa_dir_shadow; +unsigned char port_pa_data_shadow; +unsigned char port_pb_i2c_shadow; +unsigned char port_pb_config_shadow; +unsigned char port_pb_dir_shadow; +unsigned char port_pb_data_shadow; +unsigned long r_timer_ctrl_shadow; + +/* Shadows for external I/O port registers. + * These are only usable if there actually IS a latch connected + * to the corresponding external chip-select pin. + * + * A common usage is that CSP0 controls LED's and CSP4 video chips. + */ + +unsigned long port_cse1_shadow; +unsigned long port_csp0_shadow; +unsigned long port_csp4_shadow; + +/* Corresponding addresses for the ports. + * These are initialized in arch/cris/mm/init.c using ioremap. + */ + +volatile unsigned long *port_cse1_addr; +volatile unsigned long *port_csp0_addr; +volatile unsigned long *port_csp4_addr; -unsigned long genconfig_shadow = 42; -unsigned long port_g_data_shadow = 42; -unsigned char port_pa_dir_shadow = 42; -unsigned char port_pa_data_shadow = 42; -unsigned char port_pb_i2c_shadow = 42; -unsigned char port_pb_config_shadow = 42; -unsigned char port_pb_dir_shadow = 42; -unsigned char port_pb_data_shadow = 42; -unsigned long r_timer_ctrl_shadow = 42; - -#ifdef CONFIG_ETRAX_90000000_LEDS -unsigned long port_90000000_shadow = 42; -#endif diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c --- v2.4.4/linux/arch/cris/kernel/signal.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/signal.c Tue May 1 16:04:56 2001 @@ -36,6 +36,9 @@ /* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */ /* manipulate regs so that upon return, it will be re-executed */ +/* We rely on that pc points to the instruction after "break 13", so the + * library must never do strange things like putting it in a delay slot. + */ #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); @@ -76,12 +79,14 @@ } /* - * Atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. Define + * dummy arguments to be able to reach the regs argument. (Note that this + * arrangement relies on old_sigset_t occupying one register.) */ int -sys_sigsuspend(old_sigset_t mask) +sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, + long srp, struct pt_regs *regs) { - struct pt_regs * regs = (struct pt_regs *)current_regs(); sigset_t saveset; mask &= _BLOCKABLE; @@ -100,10 +105,13 @@ } } +/* Define dummy arguments to be able to reach the regs argument. (Note that + * this arrangement relies on size_t occupying one register.) + */ int -sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, + long mof, long srp, struct pt_regs *regs) { - struct pt_regs * regs = (struct pt_regs *)current_regs(); sigset_t saveset, newset; /* XXX: Don't preclude handling different sized sigset_t's. */ @@ -225,9 +233,11 @@ return 1; } -asmlinkage int sys_sigreturn(void) +/* Define dummy arguments to be able to reach the regs argument. */ + +asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, + long srp, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *)current_regs(); struct sigframe *frame = (struct sigframe *)rdusp(); sigset_t set; @@ -265,9 +275,11 @@ return 0; } -asmlinkage int sys_rt_sigreturn(void) +/* Define dummy arguments to be able to reach the regs argument. */ + +asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, + long mof, long srp, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *)current_regs(); struct rt_sigframe *frame = (struct rt_sigframe *)rdusp(); sigset_t set; stack_t st; @@ -389,7 +401,6 @@ /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; /* This is movu.w __NR_sigreturn, r9; break 13; */ - /* TODO: check byteorder */ err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(0xe93d, (short *)(frame->retcode+4)); @@ -535,7 +546,14 @@ * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. + * + * Also note that the regs structure given here as an argument, is the latest + * pushed pt_regs. It may or may not be the same as the first pushed registers + * when the initial usermode->kernelmode transition took place. Therefore + * we can use user_mode(regs) to see if we came directly from kernel or user + * mode below. */ + int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c --- v2.4.4/linux/arch/cris/kernel/sys_cris.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/sys_cris.c Tue May 1 16:04:56 2001 @@ -1,6 +1,6 @@ -/* $Id: sys_cris.c,v 1.4 2001/01/31 14:55:58 perf Exp $ +/* $Id: sys_cris.c,v 1.7 2001/04/17 11:52:15 orjanf Exp $ * - * linux/arch/cris/kernel/sys_etrax.c + * linux/arch/cris/kernel/sys_cris.c * * This file contains various random system calls that * have a non-standard calling sequence on some platforms. @@ -177,20 +177,13 @@ case MSGCTL: return sys_msgctl (first, second, (struct msqid_ds *) ptr); - case SHMAT: - switch (version) { - default: { - ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); - if (ret) - return ret; - return put_user (raddr, (ulong *) third); - } - case 1: /* iBCS2 emulator entry point */ - if (!segment_eq(get_fs(), get_ds())) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); - } + case SHMAT: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } case SHMDT: return sys_shmdt ((char *)ptr); case SHMGET: diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c --- v2.4.4/linux/arch/cris/kernel/traps.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/kernel/traps.c Tue May 1 16:04:56 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.8 2001/02/23 13:45:20 bjornw Exp $ +/* $Id: traps.c,v 1.11 2001/04/04 09:43:31 orjanf Exp $ * * linux/arch/cris/traps.c * @@ -9,7 +9,6 @@ * Copyright (C) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen - * Orjan Friberg * */ @@ -45,8 +44,10 @@ int i; extern char _stext, _etext; - // debugging aid: "show_stack(NULL);" prints the - // back trace for this cpu. + /* + * debugging aid: "show_stack(NULL);" prints the + * back trace for this cpu. + */ if(sp == NULL) sp = (unsigned long*)rdsp(); @@ -107,8 +108,8 @@ { unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx\n", - regs->irp, regs->srp, regs->dccr, usp ); + printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n", + regs->irp, regs->srp, regs->dccr, usp, regs->mof ); printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", @@ -120,7 +121,7 @@ printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); - // TODO, fix in_kernel detection + /* TODO, fix in_kernel detection */ #if 0 /* @@ -168,65 +169,5 @@ void __init trap_init(void) { - + /* Nothing needs to be done */ } - -/* Use static variables instead of the stack for temporary storage. */ -static int saved_r0 = 0; -static int saved_dccr = 0; - -asm (" - .global _gdb_handle_breakpoint - .global _do_sigtrap -_gdb_handle_breakpoint: -;; -;; This handles a break instruction for entering a debug session. -;; - move dccr,[_saved_dccr] ; Save dccr. - move.d r0,[_saved_r0] ; Save r0. " -#ifdef CONFIG_KGDB -" - move ccr,r0 - btstq 8,r0 ; Test the U-flag. - bmi _ugdb_handle_breakpoint ; Go to user mode debugging. - nop ; Delay slot. - move.d [_saved_r0],r0 ; Restore r0. - move [_saved_dccr],dccr ; Restore dccr. - ba _kgdb_handle_breakpoint ; Go to kernel debugging. - nop ; Delay slot. " -#endif -" -_ugdb_handle_breakpoint: -;; -;; Yes, we could do a 'push brp' here and let gdb adjust the pc once it -;; starts talking to the target again, but this way we avoid a 'P' packet. -;; - move brp,r0 ; Use r0 temporarily for calculation. - subq 2,r0 ; Set to address of previous instruction. - move r0,brp ; Restore new brp. - move.d [_saved_r0],r0 ; Restore r0. - move [_saved_dccr],dccr ; Restore dccr. - -_do_sigtrap: -;; -;; SIGTRAP the process that executed the break instruction. -;; Make a frame that Rexit in entry.S expects. -;; - push brp ; Push breakpoint return pointer. - push srp ; Push subroutine return pointer. - push dccr ; Push condition codes. - push mof ; Push multiply overflow reg. - di ; Need to disable irq's at this point. - subq 14*4,sp ; Make room for r0-r13. - movem r13,[sp] ; Push the r0-r13 registers. - push r10 ; Push orig_r10. - clear.d [sp=sp-4] ; Frametype - this is a normal stackframe. - - movs.w -8192,r9 ; THREAD_SIZE == 8192 - and.d sp,r9 - move.d [r9+LTASK_PID],r10 ; current->pid as arg1. - moveq 5,r11 ; SIGTRAP as arg2. - jsr _sys_kill - - jump _ret_from_intr ; Use the return routine for interrupts. -"); diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S --- v2.4.4/linux/arch/cris/lib/dram_init.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/lib/dram_init.S Tue May 1 16:04:56 2001 @@ -1,63 +1,97 @@ - ;; $Id: dram_init.S,v 1.2 2001/02/08 15:20:00 starvik Exp $ - ;; - ;; DRAM/SDRAM initialization - alter with care - ;; This file is intended to be included from other assembler files - ;; - ;; Copyright (C) 2000 Axis Communications AB - ;; - ;; Authors: Mikael Starvik (starvik@axis.com) - ;; Bjorn Wesen (bjornw@axis.com) - ;; - ;; $Log: dram_init.S,v $ - ;; Revision 1.2 2001/02/08 15:20:00 starvik - ;; Corrected SDRAM initialization - ;; Should now be included as inline - ;; - ;; Revision 1.1 2001/01/29 13:08:02 starvik - ;; Initial version - ;; This file should be included from all assembler files that needs to - ;; initialize DRAM/SDRAM. - ;; - ;; - ;; +/* $Id: dram_init.S,v 1.7 2001/04/18 12:05:39 bjornw Exp $ + * + * DRAM/SDRAM initialization - alter with care + * This file is intended to be included from other assembler files + * + * Note: This file may not modify r9 because r9 is used to carry + * information from the decompresser to the kernel + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Mikael Starvik (starvik@axis.com) + * + * $Log: dram_init.S,v $ + * Revision 1.7 2001/04/18 12:05:39 bjornw + * Fixed comments, and explicitely include config.h to be sure its there + * + * Revision 1.6 2001/04/10 06:20:16 starvik + * Delay should be 200us, not 200ns + * + * Revision 1.5 2001/04/09 06:01:13 starvik + * Added support for 100 MHz SDRAMs + * + * Revision 1.4 2001/03/26 14:24:01 bjornw + * Namechange of some config options + * + * Revision 1.3 2001/03/23 08:29:41 starvik + * Corrected calculation of mrs_data + * + * Revision 1.2 2001/02/08 15:20:00 starvik + * Corrected SDRAM initialization + * Should now be included as inline + * + * Revision 1.1 2001/01/29 13:08:02 starvik + * Initial version + * This file should be included from all assembler files that needs to + * initialize DRAM/SDRAM. + * + */ + +/* Just to be certain the config file is included, we include it here + * explicitely instead of depending on it being included in the file that + * uses this code. + */ #include + #ifndef CONFIG_SVINTO_SIM - move.d DEF_R_WAITSTATES, r0 + move.d CONFIG_ETRAX_DEF_R_WAITSTATES, r0 move.d r0, [R_WAITSTATES] - move.d DEF_R_BUS_CONFIG, r0 + move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, r0 move.d r0, [R_BUS_CONFIG] -#ifndef CONFIG_SDRAM - move.d DEF_R_DRAM_CONFIG, r0 +#ifndef CONFIG_ETRAX_SDRAM + move.d CONFIG_ETRAX_DEF_R_DRAM_CONFIG, r0 move.d r0, [R_DRAM_CONFIG] - move.d DEF_R_DRAM_TIMING, r0 + move.d CONFIG_ETRAX_DEF_R_DRAM_TIMING, r0 move.d r0, [R_DRAM_TIMING] #else ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization ; Bank configuration - move.d DEF_R_SDRAM_CONFIG, r0 + move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r0 move.d r0, [R_SDRAM_CONFIG] ; Calculate value of mrs_data - ; cas_delay = 2 && bus_width = 32 => 0x40 - ; cas_delay = 3 && bus_width = 32 => 0x60 - ; cas_delay = 2 && bus_width = 16 => 0x20 - ; cas_delay = 3 && bus_width = 16 => 0x30 + ; CAS latency = 2 && bus_width = 32 => 0x40 + ; CAS latency = 3 && bus_width = 32 => 0x60 + ; CAS latency = 2 && bus_width = 16 => 0x20 + ; CAS latency = 3 && bus_width = 16 => 0x30 - move.d 0x40, r2 ; Assume 32 bits and cas_delay = 2 - move.d DEF_R_SDRAM_TIMING, r1 - and.d 0x0c, r1 ; Get cas delay - cmp.d 0x08, r1 ; cas_delay = 2? - beq bw_check + move.d 0x40, r2 ; Assume 32 bits and CAS latency = 2 + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1 + move.d r1, r3 + and.d 0x03, r1 ; Get CAS latency + and.d 0x1000, r3 ; 50 or 100 MHz? + beq speed_50 + nop +speed_100: + cmp.d 0x00, r1 ; CAS latency = 2? + beq bw_check + nop + or.d 0x20, r2 ; CAS latency = 3 + ba bw_check + nop +speed_50: + cmp.d 0x01, r1 ; CAS latency = 2? + beq bw_check nop - or.d 0x20, r2 ; cas_delay = 3 + or.d 0x20, r2 ; CAS latency = 3 bw_check: - move.d DEF_R_SDRAM_CONFIG, r1 + move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r1 and.d 0x800000, r1 ; DRAM width is bit 23 bne set_timing nop @@ -65,14 +99,17 @@ ; Set timing parameters. Starts master clock set_timing: - move.d DEF_R_SDRAM_TIMING, r1 + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1 + and.d 0x8000f9ff, r1 ; Make sure mrs data and command is 0 or.d 0x80000000, r1 ; Make sure sdram enable bit is set + move.d r1, r5 + or.d 0x0000c000, r1 ; ref = disable lslq 16, r2 ; mrs data starts at bit 16 or.d r2, r1 move.d r1, [R_SDRAM_TIMING] - ; Wait 200ns - move.d 10, r2 + ; Wait 200us + move.d 10000, r2 sdram_loop: bne sdram_loop subq 1, r2 @@ -83,10 +120,10 @@ command_loop: clear.d r4 move.b [r2+], r4 - lslq 9, r4 ; Command starts at bit 9 + lslq 9, r4 ; Command starts at bit 9 or.d r1, r4 move.d r4, [R_SDRAM_TIMING] - nop ; Wait five nop cycles between each command + nop ; Wait five nop cycles between each command nop nop nop @@ -94,6 +131,7 @@ cmp.d r2, r3 bne command_loop nop + move.d r5, [R_SDRAM_TIMING] ba sdram_commands_end nop diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/hw_settings.S linux/arch/cris/lib/hw_settings.S --- v2.4.4/linux/arch/cris/lib/hw_settings.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/hw_settings.S Tue May 1 16:04:56 2001 @@ -0,0 +1,61 @@ + ;; $Id: hw_settings.S,v 1.2 2001/04/03 11:11:09 starvik Exp $ + ;; + ;; This table is used by some tools to extract hardware parameters. + ;; The table should be included in the kernel and the decompressor. + ;; Don't forget to update the tools if you change this table. + ;; + ;; Copyright (C) 2001 Axis Communications AB + ;; + ;; Authors: Mikael Starvik (starvik@axis.com) + + +#define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \ + (CONFIG_ETRAX_DEF_R_PORT_PA_DATA)) +#define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \ + (CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \ + (CONFIG_ETRAX_DEF_R_PORT_PB_DATA)) + + .ascii "HW_PARAM_MAGIC" ; Magic number + .dword 0xc0004000 ; Kernel start address + + ; Debug port +#ifdef CONFIG_ETRAX_DEBUG_PORT0 + .dword 0 +#elif defined(CONFIG_ETRAX_DEBUG_PORT1) + .dword 1 +#elif defined(CONFIG_ETRAX_DEBUG_PORT2) + .dword 2 +#elif defined(CONFIG_ETRAX_DEBUG_PORT3) + .dword 3 +#else + .dword 4 ; No debug +#endif + + ; SDRAM or EDO DRAM? +#ifdef CONFIG_ETRAX_SDRAM + .dword 1 +#else + .dword 0 +#endif + + ; Register values + .dword R_WAITSTATES + .dword CONFIG_ETRAX_DEF_R_WAITSTATES + .dword R_BUS_CONFIG + .dword CONFIG_ETRAX_DEF_R_BUS_CONFIG +#ifdef CONFIG_ETRAX_SDRAM + .dword R_SDRAM_CONFIG + .dword CONFIG_ETRAX_DEF_R_SDRAM_CONFIG + .dword R_SDRAM_TIMING + .dword CONFIG_ETRAX_DEF_R_SDRAM_TIMING +#else + .dword R_DRAM_CONFIG + .dword CONFIG_ETRAX_DEF_R_DRAM_CONFIG + .dword R_DRAM_TIMING + .dword CONFIG_ETRAX_DEF_R_DRAM_TIMING +#endif + .dword R_PORT_PA_SET + .dword PA_SET_VALUE + .dword R_PORT_PB_SET + .dword PB_SET_VALUE + .dword 0 ; No more register values diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/memset.c linux/arch/cris/lib/memset.c --- v2.4.4/linux/arch/cris/lib/memset.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/memset.c Tue May 1 16:04:56 2001 @@ -27,6 +27,8 @@ /*# */ /*#-------------------------------------------------------------------------*/ +#include + /* No, there's no macro saying 12*4, since it is "hard" to get it into the asm in a good way. Thus better to expose the problem everywhere. */ @@ -39,7 +41,7 @@ void *memset(void *pdst, int c, - unsigned int plen) + size_t plen) { /* Ok. Now we want the parameters put in special registers. Make sure the compiler is able to make something useful of this. */ @@ -54,7 +56,12 @@ /* Ugh. This is fragile at best. Check with newer GCC releases, if they compile cascaded "x |= x << 8" sanely! */ - __asm__("movu.b %0,r13\n\tlslq 8,r13\n\tmove.b %0,r13\n\tmove.d r13,%0\n\tlslq 16,r13\n\tor.d r13,%0" + __asm__("movu.b %0,r13\n\t" + "lslq 8,r13\n\t" + "move.b %0,r13\n\t" + "move.d r13,%0\n\t" + "lslq 16,r13\n\t" + "or.d r13,%0" : "=r" (lc) : "0" (lc) : "r13"); { diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/string.c linux/arch/cris/lib/string.c --- v2.4.4/linux/arch/cris/lib/string.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/string.c Tue May 1 16:04:56 2001 @@ -31,9 +31,11 @@ /*# */ /*#-------------------------------------------------------------------------*/ +#include + void *memcpy(void *pdst, const void *psrc, - unsigned int pn) + size_t pn) { /* Ok. Now we want the parameters put in special registers. Make sure the compiler is able to make something useful of this. diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/extable.c linux/arch/cris/mm/extable.c --- v2.4.4/linux/arch/cris/mm/extable.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/mm/extable.c Tue May 1 16:04:56 2001 @@ -37,8 +37,7 @@ #ifndef CONFIG_MODULES /* There is only the kernel to search. */ - ret = search_one_table(_start___ex_table, _stop___ex_table-1, addr); - if (ret) return ret; + return search_one_table(_start___ex_table, _stop___ex_table-1, addr); #else /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c --- v2.4.4/linux/arch/cris/mm/fault.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/mm/fault.c Tue May 1 16:04:56 2001 @@ -1,11 +1,20 @@ /* * linux/arch/cris/mm/fault.c * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.12 2001/04/04 10:51:14 bjornw + * mmap_sem is grabbed for reading + * + * Revision 1.11 2001/03/23 07:36:07 starvik + * Corrected according to review remarks + * + * Revision 1.10 2001/03/21 16:10:11 bjornw + * CRIS_FRAME_FIXUP not needed anymore, use FRAME_NORMAL + * * Revision 1.9 2001/03/05 13:22:20 bjornw * Spell-fix and fix in vmalloc_fault handling * @@ -70,12 +79,12 @@ address = cause & PAGE_MASK; /* get faulting address */ - page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); + D(page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause)); + D(acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause)); + D(inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause)); + D(index = IO_EXTRACT(R_TLB_SELECT, index, select)); miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); - acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); - inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); - index = IO_EXTRACT(R_TLB_SELECT, index, select); D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, " "idx %d pid %d\n", @@ -304,23 +313,32 @@ /* Are we prepared to handle this kernel fault? * * (The kernel has valid exception-points in the source - * when it accesses user-memory. When it fails in one + * when it acesses user-memory. When it fails in one * of those points, we find it in a table and do a jump * to some fixup code that loads an appropriate error * code) */ if ((fixup = search_exception_table(regs->irp)) != 0) { + /* Adjust the instruction pointer in the stackframe */ + regs->irp = fixup; - regs->frametype = CRIS_FRAME_FIXUP; + + /* We do not want to return by restoring the CPU-state + * anymore, so switch frame-types (see ptrace.h) + */ + + regs->frametype = CRIS_FRAME_NORMAL; + D(printk("doing fixup to 0x%x\n", fixup)); return; } -/* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) (address) < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c --- v2.4.4/linux/arch/cris/mm/init.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/mm/init.c Tue May 1 16:04:56 2001 @@ -7,6 +7,22 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.23 2001/04/04 14:35:40 bjornw + * * Removed get_pte_slow and friends (2.4.3 change) + * * Removed bad_pmd handling (2.4.3 change) + * + * Revision 1.22 2001/04/04 13:38:04 matsfg + * Moved ioremap to a separate function instead + * + * Revision 1.21 2001/03/27 09:28:33 bjornw + * ioremap used too early - lets try it in mem_init instead + * + * Revision 1.20 2001/03/23 07:39:21 starvik + * Corrected according to review remarks + * + * Revision 1.19 2001/03/15 14:25:17 bjornw + * More general shadow registers and ioremaped addresses for external I/O + * * Revision 1.18 2001/02/23 12:46:44 bjornw * * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached * flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O @@ -68,6 +84,7 @@ #include #include #include +#include static unsigned long totalram_pages; @@ -79,128 +96,13 @@ extern void show_net_buffers(void); extern void tlb_init(void); -/* - * empty_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 a inode - * unused etc.. - * - * the main point is that when a page table error occurs, we want to get - * out of the kernel safely before killing the process, so we need something - * to feed the MMU with when the fault occurs even if we don't have any - * real PTE's or page tables. - * - * empty_bad_page_table is the accompanying page-table: it is initialized - * to point to empty_bad_page writable-shared entries. - * - * empty_zero_page is a special page that is used for zero-initialized - * data and COW. - */ -unsigned long empty_bad_page_table; -unsigned long empty_bad_page; unsigned long empty_zero_page; -pte_t * __bad_pagetable(void) -{ - /* somehow it is enough to just clear it and not fill it with - * bad page PTE's... - */ - memset((void *)empty_bad_page_table, 0, PAGE_SIZE); - - return (pte_t *) empty_bad_page_table; -} - -pte_t __bad_page(void) -{ - - /* clear the empty_bad_page page. this should perhaps be - * a more simple inlined loop like it is on the other - * architectures. - */ - - memset((void *)empty_bad_page, 0, PAGE_SIZE); - - return pte_mkdirty(__mk_pte((void *)empty_bad_page, PAGE_SHARED)); -} - -static pte_t * get_bad_pte_table(void) -{ - pte_t *empty_bad_pte_table = (pte_t *)empty_bad_page_table; - pte_t v; - int i; - - v = __bad_page(); - - 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_set(pmd, get_bad_pte_table()); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_set_kernel(pmd, get_bad_pte_table()); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page(pte); - pmd_set_kernel(pmd, pte); - return pte + offset; - } - pmd_set_kernel(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page(pte); - pmd_set(pmd, pte); - return pte + offset; - } - pmd_set(pmd, get_bad_pte_table()); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -#ifndef CONFIG_NO_PGT_CACHE -struct pgtable_cache_struct quicklists; - /* trim the page-table cache if necessary */ -int do_check_pgt_cache(int low, int high) +int +do_check_pgt_cache(int low, int high) { int freed = 0; @@ -211,25 +113,20 @@ freed++; } if(pmd_quicklist) { - free_pmd_slow(get_pmd_fast()); + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); freed++; } if(pte_quicklist) { - free_pte_slow(get_pte_fast()); - freed++; + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; } } while(pgtable_cache_size > low); } return freed; } -#else -int do_check_pgt_cache(int low, int high) -{ - return 0; -} -#endif -void show_mem(void) +void +show_mem(void) { int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0; int shared = 0; @@ -287,15 +184,51 @@ /* see README.mm for details on the KSEG setup */ -#ifdef CONFIG_CRIS_LOW_MAP +#ifndef CONFIG_CRIS_LOW_MAP + /* This code is for the corrected Etrax-100 LX version 2... */ + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ + IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_9, page ) | + IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_7, page ) | + IO_STATE(R_MMU_KSEG, seg_6, page ) | + IO_STATE(R_MMU_KSEG, seg_5, page ) | + IO_STATE(R_MMU_KSEG, seg_4, page ) | + IO_STATE(R_MMU_KSEG, seg_3, page ) | + IO_STATE(R_MMU_KSEG, seg_2, page ) | + IO_STATE(R_MMU_KSEG, seg_1, page ) | + IO_STATE(R_MMU_KSEG, seg_0, page ) ); + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#else /* Etrax-100 LX version 1 has a bug so that we cannot map anything * across the 0x80000000 boundary, so we need to shrink the user-virtual * area to 0x50000000 instead of 0xb0000000 and map things slightly * different. The unused areas are marked as paged so that we can catch * freak kernel accesses there. * - * The Juliette chip is mapped at 0xa so we pass that segment straight + * The ARTPEC chip is mapped at 0xa so we pass that segment straight * through. We cannot vremap it because the vmalloc area is below 0x8 * and Juliette needs an uncached area above 0x8. * @@ -308,7 +241,7 @@ IO_STATE(R_MMU_KSEG, seg_d, page ) | IO_STATE(R_MMU_KSEG, seg_c, page ) | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* Juliette etc. */ + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ @@ -337,44 +270,7 @@ IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#else - /* This code is for the hopefully corrected Etrax-100 LX version 2... */ - - *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ - IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ - IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ - IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ - IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_9, page ) | - IO_STATE(R_MMU_KSEG, seg_8, page ) | - IO_STATE(R_MMU_KSEG, seg_7, page ) | - IO_STATE(R_MMU_KSEG, seg_6, page ) | - IO_STATE(R_MMU_KSEG, seg_5, page ) | - IO_STATE(R_MMU_KSEG, seg_4, page ) | - IO_STATE(R_MMU_KSEG, seg_3, page ) | - IO_STATE(R_MMU_KSEG, seg_2, page ) | - IO_STATE(R_MMU_KSEG, seg_1, page ) | - IO_STATE(R_MMU_KSEG, seg_0, page ) ); - - *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | - IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | - IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | - IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); - - *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#endif +#endif *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); @@ -393,8 +289,6 @@ * to a couple of allocated pages */ - empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); memset((void *)empty_zero_page, 0, PAGE_SIZE); @@ -412,6 +306,7 @@ */ free_area_init_node(0, 0, 0, zones_size, PAGE_OFFSET, 0); + } extern unsigned long loops_per_jiffy; /* init/main.c */ @@ -462,7 +357,7 @@ datasize >> 10, initsize >> 10 ); - + /* HACK alert - calculate a loops_per_usec for asm/delay.h here * since this is called just after calibrate_delay in init/main.c * but before places which use udelay. cannot be in time.c since @@ -474,9 +369,52 @@ return; } +/* Initialize remaps of some I/O-ports. This is designed to be callable + * multiple times from the drivers init-sections, because we don't know + * beforehand which driver will get initialized first. + */ + +void +init_ioremap(void) +{ + + /* Give the external I/O-port addresses their values */ + + static int initialized = 0; + + if( !initialized ) { + initialized++; + +#ifdef CONFIG_CRIS_LOW_MAP + /* Simply a linear map (see the KSEG map above in paging_init) */ + port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | + MEM_NON_CACHEABLE); + port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | + MEM_NON_CACHEABLE); + port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | + MEM_NON_CACHEABLE); +#else + /* Note that nothing blows up just because we do this remapping + * it's ok even if the ports are not used or connected + * to anything (or connected to a non-I/O thing) */ + port_cse1_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSE1_START | + MEM_NON_CACHEABLE), 16); + port_csp0_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP0_START | + MEM_NON_CACHEABLE), 16); + port_csp4_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP4_START | + MEM_NON_CACHEABLE), 16); +#endif + } +} + + /* free the pages occupied by initialization code */ -void free_initmem(void) +void +free_initmem(void) { #if 0 /* currently this is a bad idea since the cramfs image is catted onto @@ -497,7 +435,8 @@ #endif } -void si_meminfo(struct sysinfo *val) +void +si_meminfo(struct sysinfo *val) { int i; diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/ioremap.c linux/arch/cris/mm/ioremap.c --- v2.4.4/linux/arch/cris/mm/ioremap.c Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/mm/ioremap.c Tue May 1 16:04:56 2001 @@ -51,7 +51,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -64,6 +64,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; @@ -72,19 +73,23 @@ flush_cache_all(); if (address >= end) BUG(); + spin_lock(&init_mm.page_table_lock); do { pmd_t *pmd; - pmd = pmd_alloc_kernel(dir, address); + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, - phys_addr + address, flags)) - return -ENOMEM; + phys_addr + address, flags)) + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); - return 0; + return error; } /* diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c --- v2.4.4/linux/arch/cris/mm/tlb.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/mm/tlb.c Tue May 1 16:04:56 2001 @@ -288,7 +288,7 @@ /* clear the page_id map */ - for(i = 0; i < 64; i++) + for(i = 0; i < NUM_PAGEID; i++) page_id_map[i] = NULL; /* invalidate the entire TLB */ diff -u --recursive --new-file v2.4.4/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.4.4/linux/arch/i386/boot/setup.S Wed Apr 11 18:50:25 2001 +++ linux/arch/i386/boot/setup.S Tue May 1 16:04:56 2001 @@ -32,6 +32,16 @@ * * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. * + * + * Fix to work around buggy BIOSes which dont use carry bit correctly + * and/or report extended memory in CX/DX for e801h memory size detection + * call. As a result the kernel got wrong figures. The int15/e801h docs + * from Ralf Brown interrupt list seem to indicate AX/BX should be used + * anyway. So to avoid breaking many machines (presumably there was a reason + * to orginally use CX/DX instead of AX/BX), we do a kludge to see + * if CX/DX have been changed in the e801 call and if so use AX/BX . + * Michael Miller, April 2001 + * */ #define __ASSEMBLY__ @@ -336,10 +346,24 @@ # to write everything into the same place.) meme801: + stc # fix to work around buggy + xorw %cx,%cx # BIOSes which dont clear/set + xorw %dx,%dx # carry on pass/error of + # e801h memory size call + # or merely pass cx,dx though + # without changing them. movw $0xe801, %ax int $0x15 jc mem88 + cmpw $0x0, %cx # Kludge to handle BIOSes + jne e801usecxdx # which report their extended + cmpw $0x0, %dx # memory in AX/BX rather than + jne e801usecxdx # CX/DX. The spec I have read + movw %ax, %cx # seems to indicate AX/BX + movw %bx, %dx # are more reasonable anyway... + +e801usecxdx: andl $0xffff, %edx # clear sign extend shll $6, %edx # and go from 64k to 1k chunks movl %edx, (0x1e0) # store extended memory size diff -u --recursive --new-file v2.4.4/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.4/linux/arch/i386/config.in Fri Apr 20 18:26:15 2001 +++ linux/arch/i386/config.in Mon Apr 30 16:59:06 2001 @@ -27,21 +27,21 @@ mainmenu_option next_comment comment 'Processor type and features' choice 'Processor family' \ - "386 CONFIG_M386 \ - 486 CONFIG_M486 \ - 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ - Pentium-Classic CONFIG_M586TSC \ - Pentium-MMX CONFIG_M586MMX \ - Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \ - Pentium-III CONFIG_MPENTIUMIII \ - Pentium-4 CONFIG_MPENTIUM4 \ - K6/K6-II/K6-III CONFIG_MK6 \ - Athlon/Duron/K7 CONFIG_MK7 \ - Crusoe CONFIG_MCRUSOE \ - Winchip-C6 CONFIG_MWINCHIPC6 \ - Winchip-2 CONFIG_MWINCHIP2 \ - Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ - CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro + "386 CONFIG_M386 \ + 486 CONFIG_M486 \ + 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ + Pentium-Classic CONFIG_M586TSC \ + Pentium-MMX CONFIG_M586MMX \ + Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \ + Pentium-III/Celeron(Coppermine) CONFIG_MPENTIUMIII \ + Pentium-4 CONFIG_MPENTIUM4 \ + K6/K6-II/K6-III CONFIG_MK6 \ + Athlon/Duron/K7 CONFIG_MK7 \ + Crusoe CONFIG_MCRUSOE \ + Winchip-C6 CONFIG_MWINCHIPC6 \ + Winchip-2 CONFIG_MWINCHIP2 \ + Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \ + CyrixIII/C3 CONFIG_MCYRIXIII" Pentium-Pro # # Define implied options from the CPU selection here # diff -u --recursive --new-file v2.4.4/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.4/linux/arch/i386/defconfig Fri Apr 27 14:41:16 2001 +++ linux/arch/i386/defconfig Mon May 7 23:51:25 2001 @@ -441,7 +441,6 @@ # CONFIG_PCMCIA_XIRTULIP is not set CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y -# CONFIG_PCMCIA_HERMES is not set # CONFIG_PCMCIA_NETWAVE is not set # CONFIG_PCMCIA_WAVELAN is not set # CONFIG_AIRONET4500_CS is not set @@ -676,6 +675,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.4.4/linux/arch/i386/kernel/mtrr.c Wed Apr 11 19:02:27 2001 +++ linux/arch/i386/kernel/mtrr.c Tue May 1 16:04:56 2001 @@ -646,12 +646,32 @@ unsigned long low; } centaur_mcr[8]; +static u8 centaur_mcr_reserved; +static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ + +/* + * Report boot time MCR setups + */ + +void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) +{ + centaur_mcr[mcr].low = lo; + centaur_mcr[mcr].high = hi; +} + static void centaur_get_mcr (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) { *base = centaur_mcr[reg].high >> PAGE_SHIFT; *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ + if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2)) + *type = MTRR_TYPE_UNCACHABLE; + if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25) + *type = MTRR_TYPE_WRBACK; + if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31) + *type = MTRR_TYPE_WRBACK; + } /* End Function centaur_get_mcr */ static void (*get_mtrr) (unsigned int reg, unsigned long *base, @@ -794,7 +814,15 @@ else { high = base << PAGE_SHIFT; - low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + if(centaur_mcr_type == 0) + low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ + else + { + if(type == MTRR_TYPE_UNCACHABLE) + low = -size << PAGE_SHIFT | 0x02; /* NC */ + else + low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */ + } } centaur_mcr[reg].high = high; centaur_mcr[reg].low = low; @@ -1104,6 +1132,28 @@ return -ENOSPC; } /* End Function generic_get_free_region */ +static int centaur_get_free_region (unsigned long base, unsigned long size) +/* [SUMMARY] Get a free MTRR. + The starting (base) address of the region. + The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + max = get_num_var_ranges (); + for (i = 0; i < max; ++i) + { + if(centaur_mcr_reserved & (1< The starting (base) address of the region. @@ -1164,9 +1214,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1229,9 +1279,13 @@ case MTRR_IF_CENTAUR_MCR: if ( mtrr_if == MTRR_IF_CENTAUR_MCR ) { - if (type != MTRR_TYPE_WRCOMB) + /* + * FIXME: Winchip2 supports uncached + */ + if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) { - printk (KERN_WARNING "mtrr: only write-combining is supported\n"); + printk (KERN_WARNING "mtrr: only write-combining%s supported\n", + centaur_mcr_type?" and uncacheable are":" is"); return -EINVAL; } } @@ -1348,9 +1402,9 @@ * * The available types are * - * %MTRR_TYPE_UNCACHEABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * @@ -1947,23 +2001,64 @@ { unsigned i; struct set_mtrr_context ctxt; + u32 lo, hi; + int wc2 = -1; set_mtrr_prepare (&ctxt); /* Unfortunately, MCR's are read-only, so there is no way to * find out what the bios might have done. */ - /* Clear all MCR's. + + /* + * Enable MCR key if we are using a winchip2 + */ + + if(boot_cpu_data.x86_model==4) + wc2 = 0; + + if(boot_cpu_data.x86_model==8 || boot_cpu_data.x86_model == 9) + { + rdmsr(0x120, lo, hi); + if(((lo>>17)&7)==1) /* Type 1 Winchip2 MCR */ + { + lo&= ~0x1C0; /* clear key */ + lo|= 0x040; /* set key to 1 */ + wrmsr(0x120, lo, hi); /* unlock MCR */ + wc2 = 1; + centaur_mcr_type = 1; + } + } + /* Clear any unconfigured MCR's. * This way we are sure that the centaur_mcr array contains the actual * values. The disadvantage is that any BIOS tweaks are thus undone. + * */ for (i = 0; i < 8; ++i) { - centaur_mcr[i].high = 0; - centaur_mcr[i].low = 0; - wrmsr (0x110 + i , 0, 0); + if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) + { + if(wc2 == 0 || ( wc2 == 1 && !(lo & (1<<(9+i))))) + wrmsr (0x110 + i , 0, 0); + else + /* + * If the BIOS set up an MCR we cannot see it + * but we don't wish to obliterate it + */ + centaur_mcr_reserved |= (1<ops, NULL)) - printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); + printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); pcibios_last_bus = -1; } @@ -295,10 +295,10 @@ case 0x61: case 0x6a: case 0x7e: - printk("SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n"); + printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n"); return 0; default: - printk("SiS router pirq escape (%d)\n", pirq); + printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); return 0; } return (x & 0x80) ? 0 : (x & 0x0f); @@ -329,10 +329,10 @@ case 0x61: case 0x6a: case 0x7e: - printk("advanced SiS pirq mapping not yet implemented\n"); + printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n"); return 0; default: - printk("SiS router pirq escape (%d)\n", pirq); + printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq); return 0; } pci_write_config_byte(router, reg, x); @@ -351,7 +351,7 @@ static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { if (pirq > 8) { - printk("VLSI router pirq escape (%d)\n", pirq); + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); return 0; } return read_config_nybble(router, 0x74, pirq-1); @@ -360,7 +360,7 @@ static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { if (pirq > 8) { - printk("VLSI router pirq escape (%d)\n", pirq); + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); return 0; } write_config_nybble(router, 0x74, pirq-1, irq); @@ -411,6 +411,7 @@ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_0, pirq_piix_get, pirq_piix_set }, { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, @@ -439,7 +440,7 @@ #ifdef CONFIG_PCI_BIOS if (!rt->signature) { - printk("PCI: Using BIOS for IRQ routing\n"); + printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); pirq_router = &pirq_bios_router; return; } @@ -464,7 +465,7 @@ pirq_router = r; } } - printk("PCI: Using IRQ router %s [%04x/%04x] at %s\n", + printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", pirq_router->name, pirq_router_dev->vendor, pirq_router_dev->device, @@ -568,7 +569,7 @@ } else return 0; } - printk("PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); + printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); /* Update IRQ for all devices with the same pirq value */ pci_for_each_dev(dev2) { @@ -582,13 +583,13 @@ if (info->irq[pin].link == pirq) { /* We refuse to override the dev->irq information. Give a warning! */ if (dev2->irq && dev2->irq != irq) { - printk("IRQ routing conflict in pirq table for device %s\n", dev2->slot_name); + printk(KERN_INFO "IRQ routing conflict in pirq table for device %s\n", dev2->slot_name); continue; } dev2->irq = irq; pirq_penalty[irq]++; if (dev != dev2) - printk("PCI: The same IRQ used for device %s\n", dev2->slot_name); + printk(KERN_INFO "PCI: The same IRQ used for device %s\n", dev2->slot_name); } } return 1; @@ -667,7 +668,7 @@ } #endif if (irq >= 0) { - printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", + printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); dev->irq = irq; } diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.4/linux/arch/i386/kernel/setup.c Fri Apr 27 14:10:32 2001 +++ linux/arch/i386/kernel/setup.c Mon May 7 12:12:31 2001 @@ -127,6 +127,9 @@ unsigned int BIOS_revision; unsigned int mca_pentium_flag; +/* For PCI or other memory-mapped resources */ +unsigned long pci_mem_start = 0x10000000; + /* * Setup options */ @@ -1008,6 +1011,9 @@ /* 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); + + /* Tell the PCI layer not to allocate too close to the RAM area.. */ + pci_mem_start = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff; #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.4.4/linux/arch/i386/kernel/traps.c Mon Mar 19 18:23:40 2001 +++ linux/arch/i386/kernel/traps.c Mon May 7 14:15:21 2001 @@ -973,7 +973,7 @@ set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); - set_trap_gate(14,&page_fault); + set_intr_gate(14,&page_fault); set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); diff -u --recursive --new-file v2.4.4/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.4.4/linux/arch/i386/mm/fault.c Mon Mar 19 12:35:09 2001 +++ linux/arch/i386/mm/fault.c Tue May 15 00:16:51 2001 @@ -117,6 +117,10 @@ /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + /* It's safe to allow irq's after cr2 has been saved */ + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + tsk = current; /* @@ -127,8 +131,12 @@ * be in an interrupt or a critical region, and should * only copy the information from the master page table, * nothing more. + * + * This verifies that the fault happens in kernel space + * (error_code & 4) == 0, and that the fault was not a + * protection error (error_code & 1) == 0. */ - if (address >= TASK_SIZE) + if (address >= TASK_SIZE && !(error_code & 5)) goto vmalloc_fault; mm = tsk->mm; @@ -224,7 +232,6 @@ bad_area: up_read(&mm->mmap_sem); -bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { tsk->thread.cr2 = address; @@ -322,27 +329,32 @@ /* * Synchronize this task's top level page-table * with the 'reference' page table. + * + * Do _not_ use "tsk" here. We might be inside + * an interrupt in the middle of a task switch.. */ int offset = __pgd_offset(address); pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; + pte_t *pte_k; - pgd = tsk->active_mm->pgd + offset; + asm("movl %%cr3,%0":"=r" (pgd)); + pgd = offset + (pgd_t *)__va(pgd); pgd_k = init_mm.pgd + offset; - if (!pgd_present(*pgd)) { - if (!pgd_present(*pgd_k)) - goto bad_area_nosemaphore; - set_pgd(pgd, *pgd_k); - return; - } - + if (!pgd_present(*pgd_k)) + goto no_context; + set_pgd(pgd, *pgd_k); + pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); - - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) - goto bad_area_nosemaphore; + if (!pmd_present(*pmd_k)) + goto no_context; set_pmd(pmd, *pmd_k); + + pte_k = pte_offset(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; return; } } diff -u --recursive --new-file v2.4.4/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.4.4/linux/arch/ppc/defconfig Sun Mar 4 14:30:18 2001 +++ linux/arch/ppc/defconfig Fri May 4 15:16:28 2001 @@ -297,7 +297,7 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=15000 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set diff -u --recursive --new-file v2.4.4/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v2.4.4/linux/arch/sparc/kernel/head.S Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/kernel/head.S Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.103 2000/05/09 17:40:13 davem Exp $ +/* $Id: head.S,v 1.104 2001/04/27 07:02:41 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.4/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.4.4/linux/arch/sparc/kernel/irq.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/kernel/irq.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.111 2001/04/14 21:13:46 davem Exp $ +/* $Id: irq.c,v 1.112 2001/04/27 07:02:42 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device diff -u --recursive --new-file v2.4.4/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.4.4/linux/arch/sparc/kernel/sys_sunos.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/kernel/sys_sunos.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.133 2001/03/24 09:36:10 davem Exp $ +/* $Id: sys_sunos.c,v 1.134 2001/04/27 07:02:42 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.4/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c --- v2.4.4/linux/arch/sparc/prom/console.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc/prom/console.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.23 2000/08/26 02:38:03 anton Exp $ +/* $Id: console.c,v 1.24 2001/04/27 07:02:42 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.4/linux/arch/sparc64/defconfig Thu Apr 26 22:17:25 2001 +++ linux/arch/sparc64/defconfig Fri May 4 15:16:28 2001 @@ -311,7 +311,7 @@ CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 @@ -573,6 +573,7 @@ CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_DPCM=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.4.4/linux/arch/sparc64/kernel/pci.c Thu Apr 12 12:10:25 2001 +++ linux/arch/sparc64/kernel/pci.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.24 2001/03/28 10:56:34 davem Exp $ +/* $Id: pci.c,v 1.25 2001/05/02 00:27:27 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -77,13 +77,13 @@ volatile int pci_poke_faulted; /* Probe for all PCI controllers in the system. */ -extern void sabre_init(int); -extern void psycho_init(int); -extern void schizo_init(int); +extern void sabre_init(int, char *); +extern void psycho_init(int, char *); +extern void schizo_init(int, char *); static struct { char *model_name; - void (*init)(int); + void (*init)(int, char *); } pci_controller_table[] = { { "SUNW,sabre", sabre_init }, { "pci108e,a000", sabre_init }, @@ -104,7 +104,7 @@ if (!strncmp(model_name, pci_controller_table[i].model_name, namelen)) { - pci_controller_table[i].init(node); + pci_controller_table[i].init(node, model_name); return; } } diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.4.4/linux/arch/sparc64/kernel/pci_psycho.c Thu Apr 19 08:38:49 2001 +++ linux/arch/sparc64/kernel/pci_psycho.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.22 2001/04/17 01:19:23 davem Exp $ +/* $Id: pci_psycho.c,v 1.23 2001/05/02 00:27:27 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1521,7 +1521,7 @@ #define PSYCHO_CONFIGSPACE 0x001000000UL -void __init psycho_init(int node) +void __init psycho_init(int node, char *model_name) { struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c --- v2.4.4/linux/arch/sparc64/kernel/pci_sabre.c Thu Apr 26 22:17:25 2001 +++ linux/arch/sparc64/kernel/pci_sabre.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.27 2001/04/24 05:14:12 davem Exp $ +/* $Id: pci_sabre.c,v 1.29 2001/05/02 00:32:56 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -215,7 +215,7 @@ ((unsigned long)(DEVFN) << 8) | \ ((unsigned long)(REG))) -static int apb_present; +static int hummingbird_p; static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm, unsigned char bus, @@ -231,7 +231,7 @@ static int sabre_out_of_range(unsigned char devfn) { - if (!apb_present) + if (hummingbird_p) return 0; return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || @@ -243,7 +243,7 @@ unsigned char bus, unsigned char devfn) { - if (!apb_present) + if (hummingbird_p) return 0; return ((pbm->parent == 0) || @@ -1461,12 +1461,10 @@ prom_printf("Cannot register Hummingbird's MEM space.\n"); prom_halt(); } - } else { - apb_present = 1; } } -void __init sabre_init(int pnode) +void __init sabre_init(int pnode, char *model_name) { struct linux_prom64_registers pr_regs[2]; struct pci_controller_info *p; @@ -1477,6 +1475,18 @@ u32 vdma[2]; u32 upa_portid, dma_mask; int bus; + + hummingbird_p = 0; + if (!strcmp(model_name, "pci108e,a001")) + hummingbird_p = 1; + else if (!strcmp(model_name, "SUNW,sabre")) { + char compat[64]; + + if (prom_getproperty(pnode, "compatible", + compat, sizeof(compat)) > 0 && + !strcmp(compat, "pci108e,a001")) + hummingbird_p = 1; + } p = kmalloc(sizeof(*p), GFP_ATOMIC); if (!p) { diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c --- v2.4.4/linux/arch/sparc64/kernel/pci_schizo.c Thu Apr 19 08:38:49 2001 +++ linux/arch/sparc64/kernel/pci_schizo.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_schizo.c,v 1.14 2001/04/17 01:19:23 davem Exp $ +/* $Id: pci_schizo.c,v 1.15 2001/05/02 00:27:27 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -1709,7 +1709,7 @@ schizo_write(pbm_b_base + 0x2000UL, tmp); } -void __init schizo_init(int node) +void __init schizo_init(int node, char *model_name) { struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; diff -u --recursive --new-file v2.4.4/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.4.4/linux/arch/sparc64/kernel/sys_sunos32.c Thu Apr 26 22:17:26 2001 +++ linux/arch/sparc64/kernel/sys_sunos32.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.59 2001/03/24 09:36:11 davem Exp $ +/* $Id: sys_sunos32.c,v 1.60 2001/04/27 07:02:42 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.4.4/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c --- v2.4.4/linux/drivers/acorn/block/mfmhd.c Thu Oct 26 23:35:47 2000 +++ linux/drivers/acorn/block/mfmhd.c Sat Apr 28 11:27:53 2001 @@ -1485,14 +1485,7 @@ for (i = maxp - 1; i >= 0; i--) { int minor = start + i; - kdev_t devi = MKDEV(MAJOR_NR, minor); - struct super_block *sb = get_super(devi); - - sync_dev (devi); - if (sb) - invalidate_inodes (sb); - invalidate_buffers (devi); - + invalidate_device (MKDEV(MAJOR_NR, minor), 1); mfm_gendisk.part[minor].start_sect = 0; mfm_gendisk.part[minor].nr_sects = 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.4.4/linux/drivers/block/DAC960.c Tue Feb 20 21:26:22 2001 +++ linux/drivers/block/DAC960.c Sat Apr 28 11:27:53 2001 @@ -5134,16 +5134,12 @@ PartitionNumber); int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber); - SuperBlock_T *SuperBlock = get_super(Device); if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0) continue; /* Flush all changes and invalidate buffered state. */ - sync_dev(Device); - if (SuperBlock != NULL) - invalidate_inodes(SuperBlock); - invalidate_buffers(Device); + invalidate_device(Device, 1); /* Clear existing partition sizes. */ diff -u --recursive --new-file v2.4.4/linux/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.4.4/linux/drivers/block/acsi.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/block/acsi.c Sat Apr 28 11:27:53 2001 @@ -1886,13 +1886,7 @@ for( i = max_p - 1; i >= 0 ; i-- ) { if (gdev->part[start + i].nr_sects != 0) { - kdev_t devp = MKDEV(MAJOR_NR, start + i); - struct super_block *sb = get_super(devp); - - fsync_dev(devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devp); + invalidate_device(MKDEV(MAJOR_NR, start + i), 1); gdev->part[start + i].nr_sects = 0; } gdev->part[start+i].start_sect = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.4.4/linux/drivers/block/amiflop.c Sun Oct 1 20:35:15 2000 +++ linux/drivers/block/amiflop.c Sat Apr 28 11:27:53 2001 @@ -1540,10 +1540,7 @@ break; case FDFMTEND: floppy_off(drive); - sb = get_super(inode->i_rdev); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 0); break; case FDGETPRM: memset((void *)&getprm, 0, sizeof (getprm)); diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss.c linux/drivers/block/cciss.c --- v2.4.4/linux/drivers/block/cciss.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/block/cciss.c Tue May 1 16:05:00 2001 @@ -44,8 +44,8 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq CISS Driver (v 2.4.2)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,2) +#define DRIVER_NAME "Compaq CISS Driver (v 2.4.3)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,3) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation"); @@ -125,10 +125,10 @@ ctlr = h->ctlr; size = sprintf(buffer, "%s: Compaq %s Controller\n" - " Board ID: %08lx\n" + " Board ID: 0x%08lx\n" " Firmware Version: %c%c%c%c\n" - " Memory Address: %08lx\n" - " IRQ: 0x%x\n" + " Memory Address: 0x%08lx\n" + " IRQ: %d\n" " Logical drives: %d\n" " Current Q depth: %d\n" " Current # commands on controller %d\n" @@ -172,7 +172,7 @@ static void __init cciss_procinit(int i) { if (proc_cciss == NULL) { - proc_cciss = proc_mkdir("driver/cciss", NULL); + proc_cciss = proc_mkdir("cciss", proc_root_driver); if (!proc_cciss) return; } @@ -691,13 +691,9 @@ max_p = gdev->max_p; start = target << gdev->minor_shift; - for(i=max_p; i>=0; i--) { + for(i=max_p-1; i>=0; i--) { int minor = start+i; - kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; @@ -1222,6 +1218,9 @@ struct request *creq; u64bit temp64; + // Loop till the queue is empty if or it is plugged + while (1) + { if (q->plugged || list_empty(queue_head)) { start_io(h); return; @@ -1329,7 +1328,7 @@ h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; - start_io(h); + } // while loop } static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) @@ -1951,7 +1950,7 @@ } } } - remove_proc_entry("driver/cciss", &proc_root); + remove_proc_entry("cciss", proc_root_driver); kfree(hba[i]->cmd_pool); kfree(hba[i]->errinfo_pool); kfree(hba[i]->cmd_pool_bits); diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h --- v2.4.4/linux/drivers/block/cciss_cmd.h Fri Apr 13 20:26:07 2001 +++ linux/drivers/block/cciss_cmd.h Tue May 1 16:05:00 2001 @@ -125,20 +125,20 @@ //Command List Structure typedef union _SCSI3Addr_struct { struct { + BYTE Dev; BYTE Bus:6; BYTE Mode:2; // b00 - BYTE Dev; } PeripDev; struct { + BYTE DevLSB; BYTE DevMSB:6; BYTE Mode:2; // b01 - BYTE DevLSB; } LogDev; struct { - BYTE Targ:6; - BYTE Mode:2; // b10 BYTE Dev:5; BYTE Bus:3; + BYTE Targ:6; + BYTE Mode:2; // b10 } LogUnit; } SCSI3Addr_struct; diff -u --recursive --new-file v2.4.4/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.4.4/linux/drivers/block/cpqarray.c Tue Feb 13 14:13:43 2001 +++ linux/drivers/block/cpqarray.c Tue May 1 16:05:00 2001 @@ -44,8 +44,8 @@ #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.2)" -#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,2) +#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.3)" +#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,3) /* Embedded module documentation macros - see modules.h */ /* Original author Chris Frantz - Compaq Computer Corporation */ @@ -204,7 +204,7 @@ static void __init ida_procinit(int i) { if (proc_array == NULL) { - proc_array = proc_mkdir("driver/array", NULL); + proc_array = proc_mkdir("array", proc_root_driver); if (!proc_array) return; } @@ -228,12 +228,12 @@ ctlr = h->ctlr; size = sprintf(buffer, "%s: Compaq %s Controller\n" - " Board ID: %08lx\n" + " Board ID: 0x%08lx\n" " Firmware Revision: %c%c%c%c\n" - " Controller Sig: %08lx\n" - " Memory Address: %08lx\n" - " I/O Port: %04x\n" - " IRQ: %x\n" + " Controller Sig: 0x%08lx\n" + " Memory Address: 0x%08lx\n" + " I/O Port: 0x%04x\n" + " IRQ: %d\n" " Logical drives: %d\n" " Physical drives: %d\n\n" " Current Q depth: %d\n" @@ -314,7 +314,7 @@ int i; struct gendisk *g; - remove_proc_entry("driver/array", NULL); + remove_proc_entry("array", proc_root_driver); for(i=0; iaccess.set_intr_mask(hba[i], 0); @@ -580,9 +580,11 @@ pdev = pci_find_device(ida_vendor_id[brdtype], ida_device_id[brdtype], NULL); while (pdev) { - printk(KERN_DEBUG "cpqarray: Device %x has been found at %x %x\n", + printk(KERN_DEBUG "cpqarray: Device 0x%x has" + " been found at bus %d dev %d func %d\n", ida_vendor_id[brdtype], - pdev->bus->number, pdev->devfn); + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); if (nr_ctlr == 8) { printk(KERN_WARNING "cpqarray: This driver" " supports a maximum of 8 controllers.\n"); @@ -906,6 +908,9 @@ struct buffer_head *bh; struct request *creq; +// Loop till the queue is empty if or it is plugged + while (1) +{ if (q->plugged || list_empty(queue_head)) { start_io(h); return; @@ -993,8 +998,7 @@ h->Qdepth++; if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth; - - start_io(h); + } // while loop } /* @@ -1574,13 +1578,9 @@ max_p = gdev->max_p; start = target << gdev->minor_shift; - for(i=max_p; i>=0; i--) { + for(i=max_p-1; i>=0; i--) { int minor = start+i; - kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.4.4/linux/drivers/block/nbd.c Wed Apr 11 19:02:30 2001 +++ linux/drivers/block/nbd.c Tue May 1 14:20:25 2001 @@ -5,7 +5,8 @@ * deadlocks sometimes - you can not swap over TCP in general. * * Copyright 1997-2000 Pavel Machek - * + * Parts copyright 2001 Steven Whitehouse + * * (part of code stolen from loop.c) * * 97-3-25 compiled 0-th version, not yet tested it @@ -20,6 +21,9 @@ * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines * 01-2-27 Fix to store proper blockcount for kernel (calculated using * BLOCK_SIZE_BITS, not device blocksize) + * 01-3-11 Make nbd work with new Linux block layer code. It now supports + * plugging like all the other block devices. Also added in MSG_MORE to + * reduce number of partial TCP segments sent. * * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * why not: would need verify_area and friends, would share yet another diff -u --recursive --new-file v2.4.4/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c --- v2.4.4/linux/drivers/block/paride/pd.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/block/paride/pd.c Sat Apr 28 11:27:53 2001 @@ -589,9 +589,6 @@ { int p, unit, minor; long flags; - kdev_t devp; - - struct super_block *sb; unit = DEVICE_NR(dev); if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV; @@ -607,13 +604,7 @@ for (p=(PD_PARTNS-1);p>=0;p--) { minor = p + unit*PD_PARTNS; - devp = MKDEV(MAJOR_NR, minor); - fsync_dev(devp); - - sb = get_super(devp); - if (sb) invalidate_inodes(sb); - - invalidate_buffers(devp); + invalidate_device(MKDEV(MAJOR_NR, minor), 1); pd_hd[minor].start_sect = 0; pd_hd[minor].nr_sects = 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- v2.4.4/linux/drivers/block/ps2esdi.c Wed Apr 18 11:49:13 2001 +++ linux/drivers/block/ps2esdi.c Tue May 1 16:05:00 2001 @@ -56,7 +56,7 @@ #include #define PS2ESDI_IRQ 14 -#define MAX_HD 1 +#define MAX_HD 2 #define MAX_RETRIES 5 #define MAX_16BIT 65536 #define ESDI_TIMEOUT 0xf000 @@ -105,14 +105,14 @@ static void ps2esdi_get_device_cfg(void); -void ps2esdi_reset_timer(unsigned long unused); +static void ps2esdi_reset_timer(unsigned long unused); -u_int dma_arb_level; /* DMA arbitration level */ +static u_int dma_arb_level; /* DMA arbitration level */ static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int); static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open); -int no_int_yet; +static int no_int_yet; static int access_count[MAX_HD]; static char ps2esdi_valid[MAX_HD]; static int ps2esdi_sizes[MAX_HD << 6]; @@ -123,26 +123,26 @@ static struct timer_list esdi_timer = { function: ps2esdi_reset_timer }; static int reset_status; static int ps2esdi_slot = -1; -int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ -int intg_esdi = 0; /* If integrated adapter */ +static int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ +static int intg_esdi = 0; /* If integrated adapter */ struct ps2esdi_i_struct { unsigned int head, sect, cyl, wpcom, lzone, ctl; }; #if 0 #if 0 /* try both - I don't know which one is better... UB */ -struct ps2esdi_i_struct ps2esdi_info[] = +static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = { {4, 48, 1553, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; #else -struct ps2esdi_i_struct ps2esdi_info[] = +static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = { {64, 32, 161, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; #endif #endif -struct ps2esdi_i_struct ps2esdi_info[] = +static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; @@ -191,9 +191,9 @@ #ifdef MODULE -int cyl[2] = {-1,-1}; -int head[2] = {-1, -1}; -int sect[2] = {-1, -1}; +static int cyl[MAX_HD] = {-1,-1}; +static int head[MAX_HD] = {-1, -1}; +static int sect[MAX_HD] = {-1, -1}; MODULE_PARM(tp720esdi, "i"); MODULE_PARM(cyl, "i"); @@ -203,7 +203,7 @@ int init_module(void) { int drive; - for(drive = 0; drive <= 1; drive++) { + for(drive = 0; drive < MAX_HD; drive++) { struct ps2_esdi_i_struct *info = &ps2esdi_info[drive]; if (cyl[drive] != -1) { @@ -1145,15 +1145,9 @@ for (partition = ps2esdi_gendisk.max_p - 1; partition >= 0; partition--) { int minor = (start | partition); - kdev_t devp = MKDEV(MAJOR_NR, minor); - struct super_block * sb = get_super(devp); - - sync_dev(devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devp); - ps2esdi_gendisk.part[start + partition].start_sect = 0; - ps2esdi_gendisk.part[start + partition].nr_sects = 0; + invalidate_device(MKDEV(MAJOR_NR, minor), 1); + ps2esdi_gendisk.part[minor].start_sect = 0; + ps2esdi_gendisk.part[minor].nr_sects = 0; } grok_partitions(&ps2esdi_gendisk, target, 1<<6, @@ -1165,7 +1159,7 @@ return (0); } -void ps2esdi_reset_timer(unsigned long unused) +static void ps2esdi_reset_timer(unsigned long unused) { int status; diff -u --recursive --new-file v2.4.4/linux/drivers/block/smart1,2.h linux/drivers/block/smart1,2.h --- v2.4.4/linux/drivers/block/smart1,2.h Fri Jun 23 21:04:36 2000 +++ linux/drivers/block/smart1,2.h Tue May 1 16:05:00 2001 @@ -45,7 +45,7 @@ } /* - * This card is the oposite of the other cards. + * This card is the opposite of the other cards. * 0 turns interrupts on... * 0x08 turns them off... */ diff -u --recursive --new-file v2.4.4/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.4.4/linux/drivers/block/xd.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/block/xd.c Sat Apr 28 11:27:53 2001 @@ -401,13 +401,7 @@ for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) { int minor = (start | partition); - kdev_t devp = MKDEV(MAJOR_NR, minor); - struct super_block * sb = get_super(devp); - - sync_dev(devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devp); + invalidate_device(MKDEV(MAJOR_NR, minor), 1); xd_gendisk.part[minor].start_sect = 0; xd_gendisk.part[minor].nr_sects = 0; }; @@ -1163,16 +1157,6 @@ int partition,dev,start; devfs_unregister_blkdev(MAJOR_NR, "xd"); - for (dev = 0; dev < xd_drives; dev++) { - start = dev << xd_gendisk.minor_shift; - for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) { - int minor = (start | partition); - kdev_t devp = MKDEV(MAJOR_NR, minor); - start = dev << xd_gendisk.minor_shift; - sync_dev(devp); - invalidate_buffers(devp); - } - } xd_done(); devfs_unregister (devfs_handle); if (xd_drives) { diff -u --recursive --new-file v2.4.4/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.4.4/linux/drivers/cdrom/cdrom.c Thu Mar 29 11:56:07 2001 +++ linux/drivers/cdrom/cdrom.c Fri May 4 15:09:23 2001 @@ -2626,7 +2626,8 @@ static void cdrom_sysctl_unregister(void) { - unregister_sysctl_table(cdrom_sysctl_header); + if (cdrom_sysctl_header) + unregister_sysctl_table(cdrom_sysctl_header); } #endif /* CONFIG_SYSCTL */ diff -u --recursive --new-file v2.4.4/linux/drivers/char/mxser.c linux/drivers/char/mxser.c --- v2.4.4/linux/drivers/char/mxser.c Fri Mar 2 11:12:07 2001 +++ linux/drivers/char/mxser.c Tue May 1 21:57:44 2001 @@ -27,10 +27,11 @@ * * Copyright (C) 1999,2000 Moxa Technologies Co., LTD. * - * for : LINUX 2.0.X, 2.2.X - * date : 1999/07/22 - * version : 1.1 + * for : LINUX 2.0.X, 2.2.X, 2.4.X + * date : 2001/05/01 + * version : 1.2 * + * Fixes for C104H/PCI by Tim Hockin */ #include @@ -61,7 +62,7 @@ #include #include -#define MXSER_VERSION "1.1kern" +#define MXSER_VERSION "1.2" #define MXSERMAJOR 174 #define MXSERCUMAJOR 175 @@ -120,7 +121,7 @@ #define CI104J_ASIC_ID 5 enum { - MXSER_BOARD_C168_ISA = 1, + MXSER_BOARD_C168_ISA = 0, MXSER_BOARD_C104_ISA, MXSER_BOARD_CI104J, MXSER_BOARD_C168_PCI, @@ -434,7 +435,7 @@ "mxser", info); if (retval) { restore_flags(flags); - printk("Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]); + printk("Board %d: %s", board, mxser_brdname[hwconf->board_type]); printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq); return (retval); } @@ -455,7 +456,7 @@ unsigned int ioaddress; hwconf->board_type = board_type; - hwconf->ports = mxser_numports[board_type - 1]; + hwconf->ports = mxser_numports[board_type]; ioaddress = pci_resource_start (pdev, 2); for (i = 0; i < hwconf->ports; i++) hwconf->ioaddr[i] = ioaddress + 8 * i; @@ -544,7 +545,7 @@ if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], + mxser_brdname[hwconf.board_type], ioaddr[b]); if (retval <= 0) { @@ -579,7 +580,7 @@ if (retval != 0) printk("Found MOXA %s board (CAP=0x%x)\n", - mxser_brdname[hwconf.board_type - 1], + mxser_brdname[hwconf.board_type], ioaddr[b]); if (retval <= 0) { @@ -612,21 +613,15 @@ n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo); index = 0; - b = 0; - while (b < n) { + for (b = 0; b < n; b++) { pdev = pci_find_device(mxser_pcibrds[b].vendor_id, mxser_pcibrds[b].device_id, pdev); - if (!pdev) - { - b++; - continue; - } - if (pci_enable_device(pdev)) + if (!pdev || pci_enable_device(pdev)) continue; hwconf.pdev = pdev; printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", - mxser_brdname[mxser_pcibrds[b].board_type - 1], - pdev->bus->number, PCI_SLOT(pdev->devfn >> 3)); + mxser_brdname[mxser_pcibrds[b].board_type], + pdev->bus->number, PCI_SLOT(pdev->devfn)); if (m >= MXSER_BOARDS) { printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS); } else { @@ -1352,7 +1347,7 @@ return; if (port == 0) return; - max = mxser_numports[mxsercfg[i].board_type - 1]; + max = mxser_numports[mxsercfg[i].board_type]; while (1) { irqbits = inb(port->vector) & port->vectormask; diff -u --recursive --new-file v2.4.4/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.4.4/linux/drivers/char/random.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/char/random.c Tue May 1 16:05:00 2001 @@ -610,7 +610,7 @@ static void batch_entropy_process(void *private_); /* note: the size must be a power of 2 */ -static int batch_entropy_init(int size, struct entropy_store *r) +static int __init batch_entropy_init(int size, struct entropy_store *r) { batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL); if (!batch_entropy_pool) diff -u --recursive --new-file v2.4.4/linux/drivers/char/synclink.c linux/drivers/char/synclink.c --- v2.4.4/linux/drivers/char/synclink.c Wed Apr 18 14:40:06 2001 +++ linux/drivers/char/synclink.c Tue May 1 16:05:00 2001 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 3.2 2000/11/06 22:34:38 paul Exp $ + * $Id: synclink.c,v 3.8 2001/03/30 17:30:38 ez Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -107,8 +107,12 @@ #endif #ifdef CONFIG_SYNCLINK_SYNCPPP +#if LINUX_VERSION_CODE < VERSION(2,4,3) +#include "../net/wan/syncppp.h" +#else #include #endif +#endif #include #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -176,6 +180,14 @@ int cts_down; }; +/* transmit holding buffer definitions*/ +#define MAX_TX_HOLDING_BUFFERS 5 +struct tx_holding_buffer { + int buffer_size; + unsigned char * buffer; +}; + + /* * Device instance data structure */ @@ -241,11 +253,21 @@ DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */ unsigned int current_rx_buffer; + int num_tx_dma_buffers; /* number of tx dma frames required */ + int tx_dma_buffers_used; unsigned int tx_buffer_count; /* count of total allocated Tx buffers */ DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */ + int start_tx_dma_buffer; /* tx dma buffer to start tx dma operation */ + int current_tx_buffer; /* next tx dma buffer to be loaded */ unsigned char *intermediate_rxbuffer; + int num_tx_holding_buffers; /* number of tx holding buffer allocated */ + int get_tx_holding_index; /* next tx holding buffer for adapter to load */ + int put_tx_holding_index; /* next tx holding buffer to store user request */ + int tx_holding_count; /* number of tx holding buffers waiting */ + struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS]; + int rx_enabled; int rx_overflow; @@ -685,6 +707,8 @@ #define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->tcsr_value + (b))) #define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b)) +#define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1)) + void usc_process_rxoverrun_sync( struct mgsl_struct *info ); void usc_start_receiver( struct mgsl_struct *info ); void usc_stop_receiver( struct mgsl_struct *info ); @@ -775,7 +799,10 @@ */ void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); int mgsl_get_rx_frame( struct mgsl_struct *info ); +int mgsl_get_raw_rx_frame( struct mgsl_struct *info ); void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); +void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); +int num_free_tx_dma_buffers(struct mgsl_struct *info); void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); @@ -790,6 +817,10 @@ void mgsl_free_buffer_list_memory(struct mgsl_struct *info); int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); +int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); +void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); +int load_next_tx_holding_buffer(struct mgsl_struct *info); +int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); /* * Bottom half interrupt handlers @@ -810,6 +841,7 @@ void mgsl_isr_io_pin( struct mgsl_struct *info ); void mgsl_isr_misc( struct mgsl_struct *info ); void mgsl_isr_receive_dma( struct mgsl_struct *info ); +void mgsl_isr_transmit_dma( struct mgsl_struct *info ); typedef void (*isr_dispatch_func)(struct mgsl_struct *); @@ -874,6 +906,8 @@ static int debug_level = 0; static int maxframe[MAX_TOTAL_DEVICES] = {0,}; static int dosyncppp[MAX_TOTAL_DEVICES] = {0,}; +static int txdmabufs[MAX_TOTAL_DEVICES] = {0,}; +static int txholdbufs[MAX_TOTAL_DEVICES] = {0,}; MODULE_PARM(break_on_load,"i"); MODULE_PARM(ttymajor,"i"); @@ -884,9 +918,11 @@ MODULE_PARM(debug_level,"i"); MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); +MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); +MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "3.2"; +static char *driver_version = "3.8"; static int __init synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -1096,11 +1132,14 @@ void mgsl_bh_receive(struct mgsl_struct *info) { + int (*get_rx_frame)(struct mgsl_struct *info) = + (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); + if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_receive(%s)\n", __FILE__,__LINE__,info->device_name); - while( mgsl_get_rx_frame(info) ); + while( (get_rx_frame)(info) ); } void mgsl_bh_transmit(struct mgsl_struct *info) @@ -1318,11 +1357,6 @@ #endif } else info->input_signal_events.dcd_down++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & MISCSTATUS_DCD_LATCHED)) - hardpps(); -#endif } if (status & MISCSTATUS_CTS_LATCHED) { @@ -1609,6 +1643,58 @@ } /* end of mgsl_isr_receive_dma() */ +/* mgsl_isr_transmit_dma() + * + * This function services a transmit DMA channel interrupt. + * + * For this driver there is one source of transmit DMA interrupts + * as identified in the Transmit DMA Mode Register (TDMR): + * + * BIT2 EOB End of Buffer. This interrupt occurs when a + * transmit DMA buffer has been emptied. + * + * The driver maintains enough transmit DMA buffers to hold at least + * one max frame size transmit frame. When operating in a buffered + * transmit mode, there may be enough transmit DMA buffers to hold at + * least two or more max frame size frames. On an EOB condition, + * determine if there are any queued transmit buffers and copy into + * transmit DMA buffers if we have room. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_transmit_dma( struct mgsl_struct *info ) +{ + u16 status; + + /* clear interrupt pending and IUS bit for Tx DMA IRQ */ + usc_OutDmaReg(info, CDIR, BIT8+BIT0 ); + + /* Read the transmit DMA status to identify interrupt type. */ + /* This also clears the status bits. */ + + status = usc_InDmaReg( info, TDMR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_transmit_dma(%s) status=%04X\n", + __FILE__,__LINE__,info->device_name,status); + + if ( status & BIT2 ) { + --info->tx_dma_buffers_used; + + /* if there are transmit frames queued, + * try to load the next one + */ + if ( load_next_tx_holding_buffer(info) ) { + /* if call returns non-zero value, we have + * at least one free tx holding buffer + */ + info->pending_bh |= BH_TRANSMIT; + } + } + +} /* end of mgsl_isr_transmit_dma() */ + /* mgsl_interrupt() * * Interrupt service routine entry point. @@ -1652,6 +1738,8 @@ /* Dispatch interrupt vector */ if ( UscVector ) (*UscIsrTable[UscVector])(info); + else if ( (DmaVector&(BIT10|BIT9)) == BIT10) + mgsl_isr_transmit_dma(info); else mgsl_isr_receive_dma(info); @@ -1818,7 +1906,9 @@ usc_stop_transmitter(info); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - if (info->params.mode == MGSL_MODE_HDLC || info->netcount) + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW || + info->netcount) usc_set_sync_mode(info); else usc_set_async_mode(info); @@ -1970,8 +2060,7 @@ spin_lock_irqsave(&info->irq_spinlock,flags); - if ( (info->params.mode != MGSL_MODE_HDLC) || - !info->tx_active ) { + if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) { if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { info->xmit_buf[info->xmit_head++] = ch; @@ -2015,8 +2104,8 @@ spin_lock_irqsave(&info->irq_spinlock,flags); if (!info->tx_active) { - if ( (info->params.mode == MGSL_MODE_HDLC) && - info->xmit_cnt ) { + if ( (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW) && info->xmit_cnt ) { /* operating in synchronous (frame oriented) mode */ /* copy data from circular xmit_buf to */ /* transmit DMA buffer. */ @@ -2060,11 +2149,51 @@ if (!tty || !info->xmit_buf || !tmp_buf) goto cleanup; - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { + /* operating in synchronous (frame oriented) mode */ /* operating in synchronous (frame oriented) mode */ - if (info->tx_active) { - ret = 0; goto cleanup; + + if ( info->params.mode == MGSL_MODE_HDLC ) { + ret = 0; + goto cleanup; + } + /* transmitter is actively sending data - + * if we have multiple transmit dma and + * holding buffers, attempt to queue this + * frame for transmission at a later time. + */ + if (info->tx_holding_count >= info->num_tx_holding_buffers ) { + /* no tx holding buffers available */ + ret = 0; + goto cleanup; + } + + /* queue transmit frame request */ + ret = count; + if (from_user) { + down(&tmp_buf_sem); + COPY_FROM_USER(err,tmp_buf, buf, count); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n", + __FILE__,__LINE__,info->device_name); + ret = -EFAULT; + } else + save_tx_buffer_request(info,tmp_buf,count); + up(&tmp_buf_sem); + } + else + save_tx_buffer_request(info,buf,count); + + /* if we have sufficient tx dma buffers, + * load the next buffered tx request + */ + spin_lock_irqsave(&info->irq_spinlock,flags); + load_next_tx_holding_buffer(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + goto cleanup; } /* if operating in HDLC LoopMode and the adapter */ @@ -2200,7 +2329,8 @@ printk("%s(%d):mgsl_write_room(%s)=%d\n", __FILE__,__LINE__, info->device_name,ret ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* operating in synchronous (frame oriented) mode */ if ( info->tx_active ) return 0; @@ -2234,10 +2364,11 @@ printk("%s(%d):mgsl_chars_in_buffer(%s)=%d\n", __FILE__,__LINE__, info->device_name,info->xmit_cnt ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* operating in synchronous (frame oriented) mode */ if ( info->tx_active ) - return info->tx_buffer_list[0].rcc; + return info->max_frame_size; else return 0; } @@ -2627,11 +2758,11 @@ unsigned long flags; int s; int rc=0; - u16 regval; struct mgsl_icount cprev, cnow; - int events = 0; + int events; int mask; - struct _input_signal_events signal_events_prev, signal_events_now; + struct _input_signal_events oldsigs, newsigs; + DECLARE_WAITQUEUE(wait, current); COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); if (rc) { @@ -2644,114 +2775,99 @@ spin_lock_irqsave(&info->irq_spinlock,flags); + /* return immediately if state matches requested events */ usc_get_serial_signals(info); s = info->serial_signals; + events = mask & + ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + + ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + + ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + + ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); + if (events) { + spin_unlock_irqrestore(&info->irq_spinlock,flags); + goto exit; + } - /* note the counters on entry */ + /* save current irq counts */ cprev = info->icount; - signal_events_prev = info->input_signal_events; + oldsigs = info->input_signal_events; - if (mask & MgslEvent_ExitHuntMode) { - /* enable exit hunt mode IRQ */ - regval = usc_InReg(info,RICR); - if (!(regval & RXSTATUS_EXITED_HUNT)) - usc_OutReg(info, RICR, regval | RXSTATUS_EXITED_HUNT); + /* enable hunt and idle irqs if needed */ + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { + u16 oldreg = usc_InReg(info,RICR); + u16 newreg = oldreg + + (mask & MgslEvent_ExitHuntMode ? RXSTATUS_EXITED_HUNT:0) + + (mask & MgslEvent_IdleReceived ? RXSTATUS_IDLE_RECEIVED:0); + if (oldreg != newreg) + usc_OutReg(info, RICR, newreg); } - if (mask & MgslEvent_IdleReceived) { - /* enable idle mode received IRQ */ - regval = usc_InReg(info,RICR); - if (!(regval & RXSTATUS_IDLE_RECEIVED)) - usc_OutReg(info, RICR, regval | RXSTATUS_IDLE_RECEIVED); - } + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&info->event_wait_q, &wait); spin_unlock_irqrestore(&info->irq_spinlock,flags); - /* Determine if any user requested events for input signals is currently TRUE */ - - events |= (mask & ((s & SerialSignal_DSR) ? - MgslEvent_DsrActive:MgslEvent_DsrInactive)); - - events |= (mask & ((s & SerialSignal_DCD) ? - MgslEvent_DcdActive:MgslEvent_DcdInactive)); - - events |= (mask & ((s & SerialSignal_CTS) ? - MgslEvent_CtsActive:MgslEvent_CtsInactive)); - - events |= (mask & ((s & SerialSignal_RI) ? - MgslEvent_RiActive:MgslEvent_RiInactive)); - - while(!events) { - /* sleep until event occurs */ - interruptible_sleep_on(&info->event_wait_q); - - /* see if a signal woke us */ + for(;;) { + schedule(); if (signal_pending(current)) { rc = -ERESTARTSYS; break; } + /* get current irq counts */ spin_lock_irqsave(&info->irq_spinlock,flags); - - /* get icount and serial signal states */ cnow = info->icount; - signal_events_now = info->input_signal_events; + newsigs = info->input_signal_events; + set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&info->irq_spinlock,flags); - if (signal_events_now.dsr_up != signal_events_prev.dsr_up && - mask & MgslEvent_DsrActive ) - events |= MgslEvent_DsrActive; - - if (signal_events_now.dsr_down != signal_events_prev.dsr_down && - mask & MgslEvent_DsrInactive ) - events |= MgslEvent_DsrInactive; - - if (signal_events_now.dcd_up != signal_events_prev.dcd_up && - mask & MgslEvent_DcdActive ) - events |= MgslEvent_DcdActive; - - if (signal_events_now.dcd_down != signal_events_prev.dcd_down && - mask & MgslEvent_DcdInactive ) - events |= MgslEvent_DcdInactive; - - if (signal_events_now.cts_up != signal_events_prev.cts_up && - mask & MgslEvent_CtsActive ) - events |= MgslEvent_CtsActive; - - if (signal_events_now.cts_down != signal_events_prev.cts_down && - mask & MgslEvent_CtsInactive ) - events |= MgslEvent_CtsInactive; - - if (signal_events_now.ri_up != signal_events_prev.ri_up && - mask & MgslEvent_RiActive ) - events |= MgslEvent_RiActive; - - if (signal_events_now.ri_down != signal_events_prev.ri_down && - mask & MgslEvent_RiInactive ) - events |= MgslEvent_RiInactive; - - if (cnow.exithunt != cprev.exithunt) - events |= (mask & MgslEvent_ExitHuntMode); + /* if no change, wait aborted for some reason */ + if (newsigs.dsr_up == oldsigs.dsr_up && + newsigs.dsr_down == oldsigs.dsr_down && + newsigs.dcd_up == oldsigs.dcd_up && + newsigs.dcd_down == oldsigs.dcd_down && + newsigs.cts_up == oldsigs.cts_up && + newsigs.cts_down == oldsigs.cts_down && + newsigs.ri_up == oldsigs.ri_up && + newsigs.ri_down == oldsigs.ri_down && + cnow.exithunt == cprev.exithunt && + cnow.rxidle == cprev.rxidle) { + rc = -EIO; + break; + } - if (cnow.rxidle != cprev.rxidle) - events |= (mask & MgslEvent_IdleReceived); + events = mask & + ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + + (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + + (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + + (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + + (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + + (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + + (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + + (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + + (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + + (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); + if (events) + break; cprev = cnow; - signal_events_prev = signal_events_now; + oldsigs = newsigs; } + remove_wait_queue(&info->event_wait_q, &wait); + set_current_state(TASK_RUNNING); + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { spin_lock_irqsave(&info->irq_spinlock,flags); if (!waitqueue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ - regval = usc_InReg(info,RICR); - usc_OutReg(info, RICR, regval & + usc_OutReg(info, RICR, usc_InReg(info,RICR) & ~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)); } spin_unlock_irqrestore(&info->irq_spinlock,flags); } - +exit: if ( rc == 0 ) PUT_USER(rc, events, mask_ptr); @@ -2759,6 +2875,56 @@ } /* end of mgsl_wait_event() */ +static int modem_input_wait(struct mgsl_struct *info,int arg) +{ + unsigned long flags; + int rc; + struct mgsl_icount cprev, cnow; + DECLARE_WAITQUEUE(wait, current); + + /* save current irq counts */ + spin_lock_irqsave(&info->irq_spinlock,flags); + cprev = info->icount; + add_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get new irq counts */ + spin_lock_irqsave(&info->irq_spinlock,flags); + cnow = info->icount; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + /* if no change, wait aborted for some reason */ + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + rc = -EIO; + break; + } + + /* check for change in caller specified modem input */ + if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || + (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || + (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || + (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { + rc = 0; + break; + } + + cprev = cnow; + } + remove_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_RUNNING); + return rc; +} + /* get_modem_info() * * Read the state of the serial control and @@ -2926,7 +3092,7 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) { int error; - struct mgsl_icount cprev, cnow; /* kernel counter temps */ + struct mgsl_icount cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ unsigned long flags; @@ -2961,37 +3127,12 @@ while(MOD_IN_USE) MOD_DEC_USE_COUNT; return 0; - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was + + /* Wait for modem input (DCD,RI,DSR,CTS) change + * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) */ case TIOCMIWAIT: - spin_lock_irqsave(&info->irq_spinlock,flags); - /* note the counters on entry */ - cprev = info->icount; - spin_unlock_irqrestore(&info->irq_spinlock,flags); - while (1) { - interruptible_sleep_on(&info->status_event_wait_q); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - save_flags(flags); cli(); - cnow = info->icount; /* atomic copy */ - restore_flags(flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ + return modem_input_wait(info,(int)arg); /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) @@ -3243,7 +3384,8 @@ if (timeout) char_time = MIN(char_time, timeout); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { while (info->tx_active) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); @@ -3601,7 +3743,8 @@ if (info->serial_signals & SerialSignal_RI) strcat(stat_buf, "|RI"); - if (info->params.mode == MGSL_MODE_HDLC) { + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) @@ -3742,15 +3885,15 @@ * * This leaves 62 4K pages. * - * The next N pages are used for a transmit frame. We - * reserve enough 4K page blocks to hold the configured - * MaxFrameSize + * The next N pages are used for transmit frame(s). We + * reserve enough 4K page blocks to hold the required + * number of transmit dma buffers (num_tx_dma_buffers), + * each of MaxFrameSize size. * * Of the remaining pages (62-N), determine how many can * be used to receive full MaxFrameSize inbound frames */ - - info->tx_buffer_count = BuffersPerFrame; + info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; info->rx_buffer_count = 62 - info->tx_buffer_count; } else { /* Calculate the number of PAGE_SIZE buffers needed for */ @@ -3763,7 +3906,7 @@ /* End of List condition if all receive buffers are used when */ /* using linked list DMA buffers. */ - info->tx_buffer_count = BuffersPerFrame; + info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6; /* @@ -3783,12 +3926,14 @@ if ( mgsl_alloc_buffer_list_memory( info ) < 0 || mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 || mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0 || - mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 ) { + mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 || + mgsl_alloc_intermediate_txbuffer_memory(info) < 0 ) { printk("%s(%d):Can't allocate DMA buffer memory\n",__FILE__,__LINE__); return -ENOMEM; } mgsl_reset_rx_dma_buffers( info ); + mgsl_reset_tx_dma_buffers( info ); return 0; @@ -4044,6 +4189,149 @@ } /* end of mgsl_free_intermediate_rxbuffer_memory() */ +/* + * mgsl_alloc_intermediate_txbuffer_memory() + * + * Allocate intermdiate transmit buffer(s) large enough to hold max_frame_size. + * This buffer is used to load transmit frames into the adapter's dma transfer + * buffers when there is sufficient space. + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: 0 if success, otherwise -ENOMEM + */ +int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) +{ + int i; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s %s(%d) allocating %d tx holding buffers\n", + info->device_name, __FILE__,__LINE__,info->num_tx_holding_buffers); + + memset(info->tx_holding_buffers,0,sizeof(info->tx_holding_buffers)); + + for ( i=0; inum_tx_holding_buffers; ++i) { + info->tx_holding_buffers[i].buffer = + kmalloc(info->max_frame_size, GFP_KERNEL); + if ( info->tx_holding_buffers[i].buffer == NULL ) + return -ENOMEM; + } + + return 0; + +} /* end of mgsl_alloc_intermediate_txbuffer_memory() */ + +/* + * mgsl_free_intermediate_txbuffer_memory() + * + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: None + */ +void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) +{ + int i; + + for ( i=0; inum_tx_holding_buffers; ++i ) { + if ( info->tx_holding_buffers[i].buffer ) { + kfree(info->tx_holding_buffers[i].buffer); + info->tx_holding_buffers[i].buffer=NULL; + } + } + + info->get_tx_holding_index = 0; + info->put_tx_holding_index = 0; + info->tx_holding_count = 0; + +} /* end of mgsl_free_intermediate_txbuffer_memory() */ + + +/* + * load_next_tx_holding_buffer() + * + * attempts to load the next buffered tx request into the + * tx dma buffers + * + * Arguments: + * + * info pointer to device instance data + * + * Return Value: 1 if next buffered tx request loaded + * into adapter's tx dma buffer, + * 0 otherwise + */ +int load_next_tx_holding_buffer(struct mgsl_struct *info) +{ + int ret = 0; + + if ( info->tx_holding_count ) { + /* determine if we have enough tx dma buffers + * to accomodate the next tx frame + */ + struct tx_holding_buffer *ptx = + &info->tx_holding_buffers[info->get_tx_holding_index]; + int num_free = num_free_tx_dma_buffers(info); + int num_needed = ptx->buffer_size / DMABUFFERSIZE; + if ( ptx->buffer_size % DMABUFFERSIZE ) + ++num_needed; + + if (num_needed <= num_free) { + info->xmit_cnt = ptx->buffer_size; + mgsl_load_tx_dma_buffer(info,ptx->buffer,ptx->buffer_size); + + --info->tx_holding_count; + if ( ++info->get_tx_holding_index >= info->num_tx_holding_buffers) + info->get_tx_holding_index=0; + + /* restart transmit timer */ + del_timer(&info->tx_timer); + info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + add_timer(&info->tx_timer); + + ret = 1; + } + } + + return ret; +} + +/* + * save_tx_buffer_request() + * + * attempt to store transmit frame request for later transmission + * + * Arguments: + * + * info pointer to device instance data + * Buffer pointer to buffer containing frame to load + * BufferSize size in bytes of frame in Buffer + * + * Return Value: 1 if able to store, 0 otherwise + */ +int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize) +{ + struct tx_holding_buffer *ptx; + + if ( info->tx_holding_count >= info->num_tx_holding_buffers ) { + return 0; /* all buffers in use */ + } + + ptx = &info->tx_holding_buffers[info->put_tx_holding_index]; + ptx->buffer_size = BufferSize; + memcpy( ptx->buffer, Buffer, BufferSize); + + ++info->tx_holding_count; + if ( ++info->put_tx_holding_index >= info->num_tx_holding_buffers) + info->put_tx_holding_index=0; + + return 1; +} + int mgsl_claim_resources(struct mgsl_struct *info) { if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) { @@ -4120,7 +4408,7 @@ return 0; errout: mgsl_release_resources(info); - return ENODEV; + return -ENODEV; } /* end of mgsl_claim_resources() */ @@ -4141,6 +4429,7 @@ } mgsl_free_dma_buffers(info); mgsl_free_intermediate_rxbuffer_memory(info); + mgsl_free_intermediate_txbuffer_memory(info); if ( info->io_addr_requested ) { release_region(info->io_base,info->io_addr_size); @@ -4187,6 +4476,20 @@ if (maxframe[info->line]) info->max_frame_size = maxframe[info->line]; info->dosyncppp = dosyncppp[info->line]; + + if (txdmabufs[info->line]) { + info->num_tx_dma_buffers = txdmabufs[info->line]; + if (info->num_tx_dma_buffers < 1) + info->num_tx_dma_buffers = 1; + } + + if (txholdbufs[info->line]) { + info->num_tx_holding_buffers = txholdbufs[info->line]; + if (info->num_tx_holding_buffers < 1) + info->num_tx_holding_buffers = 1; + else if (info->num_tx_holding_buffers > MAX_TX_HOLDING_BUFFERS) + info->num_tx_holding_buffers = MAX_TX_HOLDING_BUFFERS; + } } mgsl_device_count++; @@ -4255,6 +4558,8 @@ spin_lock_init(&info->netlock); memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); info->idle_mode = HDLC_TXIDLE_FLAGS; + info->num_tx_dma_buffers = 1; + info->num_tx_holding_buffers = 0; } return info; @@ -4432,6 +4737,7 @@ unsigned long flags; int rc; struct mgsl_struct *info; + struct mgsl_struct *tmp; printk("Unloading %s: version %s\n", driver_name, driver_version); save_flags(flags); @@ -4451,7 +4757,9 @@ mgsl_sppp_delete(info); #endif mgsl_release_resources(info); + tmp = info; info = info->next_device; + kfree(tmp); } if (tmp_buf) { @@ -4691,6 +4999,27 @@ * * 0000 0110 0000 0110 = 0x0606 */ + if (info->params.mode == MGSL_MODE_RAW) { + RegValue = 0x0001; /* Set Receive mode = external sync */ + + usc_OutReg( info, IOCR, /* Set IOCR DCD is RxSync Detect Input */ + (unsigned short)((usc_InReg(info, IOCR) & ~(BIT13|BIT12)) | BIT12)); + + /* + * TxSubMode: + * CMR <15> 0 Don't send CRC on Tx Underrun + * CMR <14> x undefined + * CMR <13> 0 Send preamble before openning sync + * CMR <12> 0 Send 8-bit syncs, 1=send Syncs per TxLength + * + * TxMode: + * CMR <11-8) 0100 MonoSync + * + * 0x00 0100 xxxx xxxx 04xx + */ + RegValue |= 0x0400; + } + else { RegValue = 0x0606; @@ -4700,12 +5029,14 @@ RegValue |= BIT15; else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC ) RegValue |= BIT15 + BIT14; + } if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE ) RegValue |= BIT13; } - if ( info->params.flags & HDLC_FLAG_SHARE_ZERO ) + if ( info->params.mode == MGSL_MODE_HDLC && + (info->params.flags & HDLC_FLAG_SHARE_ZERO) ) RegValue |= BIT12; if ( info->params.addr_filter != 0xff ) @@ -4745,15 +5076,13 @@ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; } - if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) RegValue |= BIT9; - else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) + else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) RegValue |= ( BIT12 | BIT10 | BIT9 ); usc_OutReg( info, RMR, RegValue ); - - /* Set the Receive count Limit Register (RCLR) to 0xffff. */ /* When an opening flag of an SDLC frame is recognized the */ /* Receive Character count (RCC) is loaded with the value in */ @@ -4822,9 +5151,9 @@ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; } - if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) RegValue |= BIT9 + BIT8; - else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) + else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8); usc_OutReg( info, TMR, RegValue ); @@ -5495,7 +5824,8 @@ usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); usc_RTCmd( info, RTCmd_PurgeRxFifo ); - if ( info->params.mode == MGSL_MODE_HDLC ) { + if ( info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW ) { /* DMA mode Transfers */ /* Program the DMA controller. */ /* Enable the DMA controller end of buffer interrupt. */ @@ -5585,8 +5915,14 @@ /* Transmit DMA buffer is loaded, so program USC */ /* to send the frame contained in the buffers. */ + FrameSize = info->tx_buffer_list[info->start_tx_dma_buffer].rcc; - FrameSize = info->tx_buffer_list[0].rcc; + /* if operating in Raw sync mode, reset the rcc component + * of the tx dma buffer entry, otherwise, the serial controller + * will send a closing sync char after this count. + */ + if ( info->params.mode == MGSL_MODE_RAW ) + info->tx_buffer_list[info->start_tx_dma_buffer].rcc = 0; /* Program the Transmit Character Length Register (TCLR) */ /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ @@ -5595,7 +5931,7 @@ usc_RTCmd( info, RTCmd_PurgeTxFifo ); /* Program the address of the 1st DMA Buffer Entry in linked list */ - phys_addr = info->tx_buffer_list[0].phys_entry; + phys_addr = info->tx_buffer_list[info->start_tx_dma_buffer].phys_entry; usc_OutDmaReg( info, NTARL, (u16)phys_addr ); usc_OutDmaReg( info, NTARU, (u16)(phys_addr >> 16) ); @@ -5603,6 +5939,19 @@ usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); usc_EnableInterrupts( info, TRANSMIT_STATUS ); + if ( info->params.mode == MGSL_MODE_RAW && + info->num_tx_dma_buffers > 1 ) { + /* When running external sync mode, attempt to 'stream' transmit */ + /* by filling tx dma buffers as they become available. To do this */ + /* we need to enable Tx DMA EOB Status interrupts : */ + /* */ + /* 1. Arm End of Buffer (EOB) Transmit DMA Interrupt (BIT2 of TDIAR) */ + /* 2. Enable Transmit DMA Interrupts (BIT0 of DICR) */ + + usc_OutDmaReg( info, TDIAR, BIT2|BIT3 ); + usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT0) ); + } + /* Initialize Transmit DMA Channel */ usc_DmaCmd( info, DmaCmd_InitTxChannel ); @@ -6026,6 +6375,9 @@ void usc_loopback_frame( struct mgsl_struct *info ) { int i; + unsigned long oldmode = info->params.mode; + + info->params.mode = MGSL_MODE_HDLC; usc_DisableMasterIrqBit( info ); @@ -6079,6 +6431,8 @@ usc_EnableMasterIrqBit(info); + info->params.mode = oldmode; + } /* end of usc_loopback_frame() */ /* usc_set_sync_mode() Programs the USC for SDLC communications. @@ -6130,6 +6484,38 @@ info->tcsr_value += usc_idle_mode; usc_OutReg(info, TCSR, info->tcsr_value); + /* + * if SyncLink WAN adapter is running in external sync mode, the + * transmitter has been set to Monosync in order to try to mimic + * a true raw outbound bit stream. Monosync still sends an open/close + * sync char at the start/end of a frame. Try to match those sync + * patterns to the idle mode set here + */ + if ( info->params.mode == MGSL_MODE_RAW ) { + unsigned char syncpat = 0; + switch( info->idle_mode ) { + case HDLC_TXIDLE_FLAGS: + syncpat = 0x7e; + break; + case HDLC_TXIDLE_ALT_ZEROS_ONES: + syncpat = 0x55; + break; + case HDLC_TXIDLE_ZEROS: + case HDLC_TXIDLE_SPACE: + syncpat = 0x00; + break; + case HDLC_TXIDLE_ONES: + case HDLC_TXIDLE_MARK: + syncpat = 0xff; + break; + case HDLC_TXIDLE_ALT_MARK_SPACE: + syncpat = 0xaa; + break; + } + + usc_SetTransmitSyncChars(info,syncpat,syncpat); + } + } /* end of usc_set_txidle() */ /* usc_get_serial_signals() @@ -6307,6 +6693,48 @@ */ /* + * mgsl_reset_tx_dma_buffers() + * + * Set the count for all transmit buffers to 0 to indicate the + * buffer is available for use and set the current buffer to the + * first buffer. This effectively makes all buffers free and + * discards any data in buffers. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) +{ + unsigned int i; + + for ( i = 0; i < info->tx_buffer_count; i++ ) { + *((unsigned long *)&(info->tx_buffer_list[i].count)) = 0; + } + + info->current_tx_buffer = 0; + info->start_tx_dma_buffer = 0; + info->tx_dma_buffers_used = 0; + + info->get_tx_holding_index = 0; + info->put_tx_holding_index = 0; + info->tx_holding_count = 0; + +} /* end of mgsl_reset_tx_dma_buffers() */ + +/* + * num_free_tx_dma_buffers() + * + * returns the number of free tx dma buffers available + * + * Arguments: info pointer to device instance data + * Return Value: number of free tx dma buffers + */ +int num_free_tx_dma_buffers(struct mgsl_struct *info) +{ + return info->tx_buffer_count - info->tx_dma_buffers_used; +} + +/* * mgsl_reset_rx_dma_buffers() * * Set the count for all receive buffers to DMABUFFERSIZE @@ -6392,10 +6820,11 @@ unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; DMABUFFERENTRY *pBufEntry; - unsigned int framesize; + unsigned int framesize = 0; int ReturnCode = 0; unsigned long flags; struct tty_struct *tty = info->tty; + int return_frame = 0; /* * current_rx_buffer points to the 1st buffer of the next available @@ -6451,14 +6880,20 @@ info->icount.rxabort++; else if ( status & RXSTATUS_OVERRUN ) info->icount.rxover++; - else + else { info->icount.rxcrc++; + if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) + return_frame = 1; + } framesize = 0; #ifdef CONFIG_SYNCLINK_SYNCPPP info->netstats.rx_errors++; info->netstats.rx_frame_errors++; #endif - } else { + } else + return_frame = 1; + + if ( return_frame ) { /* receive frame has no errors, get frame size. * The frame size is the starting value of the RCC (which was * set to 0xffff) minus the ending value of the RCC (decremented @@ -6483,7 +6918,9 @@ MIN(framesize,DMABUFFERSIZE),0); if (framesize) { - if (framesize > info->max_frame_size) + if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) && + ((framesize+1) > info->max_frame_size) ) || + (framesize > info->max_frame_size) ) info->icount.rxlong++; else { /* copy dma buffer(s) to contiguous intermediate buffer */ @@ -6491,6 +6928,7 @@ int index = StartIndex; unsigned char *ptmp = info->intermediate_rxbuffer; + if ( !(status & RXSTATUS_CRC_ERROR)) info->icount.rxok++; while(copy_count) { @@ -6509,6 +6947,18 @@ index = 0; } + if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) { + ++framesize; + *ptmp = (status & RXSTATUS_CRC_ERROR ? + RX_CRC_ERROR : + RX_OK); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + printk("%s(%d):mgsl_get_rx_frame(%s) rx frame status=%d\n", + __FILE__,__LINE__,info->device_name, + *ptmp); + } + #ifdef CONFIG_SYNCLINK_SYNCPPP if (info->netcount) { /* pass frame to syncppp device */ @@ -6518,6 +6968,7 @@ #endif { /* Call the line discipline receive callback directly. */ + if ( tty && tty->ldisc.receive_buf ) tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); } } @@ -6547,6 +6998,180 @@ } /* end of mgsl_get_rx_frame() */ +/* mgsl_get_raw_rx_frame() + * + * This function attempts to return a received frame from the + * receive DMA buffers when running in external loop mode. In this mode, + * we will return at most one DMABUFFERSIZE frame to the application. + * The USC receiver is triggering off of DCD going active to start a new + * frame, and DCD going inactive to terminate the frame (similar to + * processing a closing flag character). + * + * In this routine, we will return DMABUFFERSIZE "chunks" at a time. + * If DCD goes inactive, the last Rx DMA Buffer will have a non-zero + * status field and the RCC field will indicate the length of the + * entire received frame. We take this RCC field and get the modulus + * of RCC and DMABUFFERSIZE to determine if number of bytes in the + * last Rx DMA buffer and return that last portion of the frame. + * + * Arguments: info pointer to device extension + * Return Value: 1 if frame returned, otherwise 0 + */ +int mgsl_get_raw_rx_frame(struct mgsl_struct *info) +{ + unsigned int CurrentIndex, NextIndex; + unsigned short status; + DMABUFFERENTRY *pBufEntry; + unsigned int framesize = 0; + int ReturnCode = 0; + unsigned long flags; + struct tty_struct *tty = info->tty; + + /* + * current_rx_buffer points to the 1st buffer of the next available + * receive frame. The status field is set by the 16C32 after + * completing a receive frame. If the status field of this buffer + * is zero, either the USC is still filling this buffer or this + * is one of a series of buffers making up a received frame. + * + * If the count field of this buffer is zero, the USC is either + * using this buffer or has used this buffer. Look at the count + * field of the next buffer. If that next buffer's count is + * non-zero, the USC is still actively using the current buffer. + * Otherwise, if the next buffer's count field is zero, the + * current buffer is complete and the USC is using the next + * buffer. + */ + CurrentIndex = NextIndex = info->current_rx_buffer; + ++NextIndex; + if ( NextIndex == info->rx_buffer_count ) + NextIndex = 0; + + if ( info->rx_buffer_list[CurrentIndex].status != 0 || + (info->rx_buffer_list[CurrentIndex].count == 0 && + info->rx_buffer_list[NextIndex].count == 0)) { + /* + * Either the status field of this dma buffer is non-zero + * (indicating the last buffer of a receive frame) or the next + * buffer is marked as in use -- implying this buffer is complete + * and an intermediate buffer for this received frame. + */ + + status = info->rx_buffer_list[CurrentIndex].status; + + if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN + + RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) { + if ( status & RXSTATUS_SHORT_FRAME ) + info->icount.rxshort++; + else if ( status & RXSTATUS_ABORT ) + info->icount.rxabort++; + else if ( status & RXSTATUS_OVERRUN ) + info->icount.rxover++; + else + info->icount.rxcrc++; + framesize = 0; + } else { + /* + * A receive frame is available, get frame size and status. + * + * The frame size is the starting value of the RCC (which was + * set to 0xffff) minus the ending value of the RCC (decremented + * once for each receive character) minus 2 or 4 for the 16-bit + * or 32-bit CRC. + * + * If the status field is zero, this is an intermediate buffer. + * It's size is 4K. + * + * If the DMA Buffer Entry's Status field is non-zero, the + * receive operation completed normally (ie: DCD dropped). The + * RCC field is valid and holds the received frame size. + * It is possible that the RCC field will be zero on a DMA buffer + * entry with a non-zero status. This can occur if the total + * frame size (number of bytes between the time DCD goes active + * to the time DCD goes inactive) exceeds 65535 bytes. In this + * case the 16C32 has underrun on the RCC count and appears to + * stop updating this counter to let us know the actual received + * frame size. If this happens (non-zero status and zero RCC), + * simply return the entire RxDMA Buffer + */ + if ( status ) { + /* + * In the event that the final RxDMA Buffer is + * terminated with a non-zero status and the RCC + * field is zero, we interpret this as the RCC + * having underflowed (received frame > 65535 bytes). + * + * Signal the event to the user by passing back + * a status of RxStatus_CrcError returning the full + * buffer and let the app figure out what data is + * actually valid + */ + if ( info->rx_buffer_list[CurrentIndex].rcc ) + framesize = RCLRVALUE - info->rx_buffer_list[CurrentIndex].rcc; + else + framesize = DMABUFFERSIZE; + } + else + framesize = DMABUFFERSIZE; + } + + if ( framesize > DMABUFFERSIZE ) { + /* + * if running in raw sync mode, ISR handler for + * End Of Buffer events terminates all buffers at 4K. + * If this frame size is said to be >4K, get the + * actual number of bytes of the frame in this buffer. + */ + framesize = framesize % DMABUFFERSIZE; + } + + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk("%s(%d):mgsl_get_raw_rx_frame(%s) status=%04X size=%d\n", + __FILE__,__LINE__,info->device_name,status,framesize); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr, + MIN(framesize,DMABUFFERSIZE),0); + + if (framesize) { + /* copy dma buffer(s) to contiguous intermediate buffer */ + /* NOTE: we never copy more than DMABUFFERSIZE bytes */ + + pBufEntry = &(info->rx_buffer_list[CurrentIndex]); + memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); + info->icount.rxok++; + + /* Call the line discipline receive callback directly. */ + if ( tty && tty->ldisc.receive_buf ) + tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); + } + + /* Free the buffers used by this frame. */ + mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex ); + + ReturnCode = 1; + } + + + if ( info->rx_enabled && info->rx_overflow ) { + /* The receiver needs to restarted because of + * a receive overflow (buffer or FIFO). If the + * receive buffers are now empty, then restart receiver. + */ + + if ( !info->rx_buffer_list[CurrentIndex].status && + info->rx_buffer_list[CurrentIndex].count ) { + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_start_receiver(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + } + + return ReturnCode; + +} /* end of mgsl_get_raw_rx_frame() */ + /* mgsl_load_tx_dma_buffer() * * Load the transmit DMA buffer with the specified data. @@ -6576,12 +7201,19 @@ info->cmr_value |= BIT13; } + /* begin loading the frame in the next available tx dma + * buffer, remember it's starting location for setting + * up tx dma operation + */ + i = info->current_tx_buffer; + info->start_tx_dma_buffer = i; + /* Setup the status and RCC (Frame Size) fields of the 1st */ /* buffer entry in the transmit DMA buffer list. */ - info->tx_buffer_list[0].status = info->cmr_value & 0xf000; - info->tx_buffer_list[0].rcc = BufferSize; - info->tx_buffer_list[0].count = BufferSize; + info->tx_buffer_list[i].status = info->cmr_value & 0xf000; + info->tx_buffer_list[i].rcc = BufferSize; + info->tx_buffer_list[i].count = BufferSize; /* Copy frame data from 1st source buffer to the DMA buffers. */ /* The frame data may span multiple DMA buffers. */ @@ -6590,6 +7222,9 @@ /* Get a pointer to next DMA buffer entry. */ pBufEntry = &info->tx_buffer_list[i++]; + if ( i == info->tx_buffer_count ) + i=0; + /* Calculate the number of bytes that can be copied from */ /* the source buffer to this DMA buffer. */ if ( BufferSize > DMABUFFERSIZE ) @@ -6609,8 +7244,13 @@ /* Advance source pointer and reduce remaining data count. */ Buffer += Copycount; BufferSize -= Copycount; + + ++info->tx_dma_buffers_used; } + /* remember next available tx dma buffer */ + info->current_tx_buffer = i; + } /* end of mgsl_load_tx_dma_buffer() */ /* @@ -6741,7 +7381,7 @@ unsigned int i; char *TmpPtr; BOOLEAN rc = TRUE; - unsigned short status; + unsigned short status=0; unsigned long EndTime; unsigned long flags; MGSL_PARAMS tmp_params; @@ -6998,7 +7638,7 @@ status = info->rx_buffer_list[0].status; if ( status & (BIT8 + BIT3 + BIT1) ) { - /* receive error has occurred */ + /* receive error has occured */ rc = FALSE; } else { if ( memcmp( info->tx_buffer_list[0].virt_addr , @@ -7219,7 +7859,9 @@ if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_tx_timeout(%s)\n", __FILE__,__LINE__,info->device_name); - if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { + if(info->tx_active && + (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW) ) { info->icount.txtimeout++; } spin_lock_irqsave(&info->irq_spinlock,flags); diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.4.4/linux/drivers/i2o/i2o_block.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_block.c Tue May 1 16:12:51 2001 @@ -28,14 +28,16 @@ * Support for larger I/Os through merge* functions * (taken from DAC960 driver) * Boji T Kannanthanam: - * Reduced the timeout during RAID 5 creation. - * This is to prevent race condition when a RAID volume - * is created and immediately deleted. + * Set the I2O Block devices to be detected in increasing + * order of TIDs during boot. + * Search and set the I2O block device that we boot off from as + * the first device to be claimed (as /dev/i2o/hda) + * Properly attach/detach I2O gendisk structure from the system + * gendisk list. The I2O block devices now appear in + * /proc/partitions. * * To do: * Serial number scanning to find duplicates for FC multipathing - * Remove the random timeout in the code needed for RAID 5 - * volume creation. */ #include @@ -86,7 +88,8 @@ #define I2OB_EVENT_MASK (I2O_EVT_IND_BSA_VOLUME_LOAD | \ I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ - I2O_EVT_IND_BSA_CAPACITY_CHANGE) + I2O_EVT_IND_BSA_CAPACITY_CHANGE | \ + I2O_EVT_IND_BSA_SCSI_SMART ) /* @@ -135,6 +138,8 @@ request_queue_t *req_queue; int max_segments; int done_flag; + int constipated; + int depth; }; /* @@ -164,7 +169,9 @@ struct i2ob_request *i2ob_qhead; request_queue_t req_queue; }; -static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS] = {NULL}; +static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS]; +static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS]; +static struct i2ob_request *i2ob_backlog_tail[MAX_I2O_CONTROLLERS]; /* * Each I2O disk is one of these. @@ -179,10 +186,10 @@ * Mutex and spin lock for event handling synchronization * evt_msg contains the last event. */ -DECLARE_MUTEX(i2ob_evt_sem); +static DECLARE_MUTEX_LOCKED(i2ob_evt_sem); +static DECLARE_MUTEX_LOCKED(i2ob_thread_dead); static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED; -static unsigned int evt_msg[MSG_FRAME_SIZE>>2]; -DECLARE_WAIT_QUEUE_HEAD(i2ob_evt_wait); +static u32 evt_msg[MSG_FRAME_SIZE>>2]; static struct timer_list i2ob_timer; static int i2ob_timer_started = 0; @@ -195,6 +202,7 @@ static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); static void i2ob_end_request(struct request *); static void i2ob_request(request_queue_t *); +static int i2ob_backlog_request(struct i2o_controller *, struct i2ob_device *); static int i2ob_init_iop(unsigned int); static request_queue_t* i2ob_get_queue(kdev_t); static int i2ob_query_device(struct i2ob_device *, int, int, void*, int); @@ -203,6 +211,7 @@ static int evt_pid = 0; static int evt_running = 0; +static int scan_unit = 0; /* * I2O OSM registration structure...keeps getting bigger and bigger :) @@ -255,7 +264,12 @@ __raw_writel(i2ob_context|(unit<<8), msg+8); __raw_writel(ireq->num, msg+12); __raw_writel(req->nr_sectors << 9, msg+20); - + + /* + * Mask out partitions from now on + */ + unit &= 0xF0; + /* This can be optimised later - just want to be sure its right for starters */ offset = ((u64)(req->sector+base)) << 9; @@ -266,8 +280,6 @@ if(req->cmd == READ) { __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); - /* We don't yet do cache/readahead and other magic */ - __raw_writel(1<<16, msg+16); while(bh!=NULL) { if(bh->b_data == last) { @@ -293,16 +305,20 @@ count -= bh->b_size; bh = bh->b_reqnext; } + /* + * Heuristic for now since the block layer doesnt give + * us enough info. If its a big write assume sequential + * readahead on controller. If its small then don't read + * ahead but do use the controller cache. + */ + if(size >= 8192) + __raw_writel((8<<24)|(1<<16)|8, msg+16); + else + __raw_writel((8<<24)|(1<<16)|4, msg+16); } else if(req->cmd == WRITE) { __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); - /* - * Allow replies to come back once data is cached in the controller - * This allows us to handle writes quickly thus giving more of the - * queue to reads. - */ - __raw_writel(0x00000010, msg+16); while(bh!=NULL) { if(bh->b_data == last) { @@ -328,13 +344,32 @@ count -= bh->b_size; bh = bh->b_reqnext; } + + if(c->battery) + { + + if(size>16384) + __raw_writel(4, msg+16); + else + /* + * Allow replies to come back once data is cached in the controller + * This allows us to handle writes quickly thus giving more of the + * queue to reads. + */ + __raw_writel(16, msg+16); + } + else + { + /* Large write, don't cache */ + if(size>8192) + __raw_writel(4, msg+16); + else + /* write through */ + __raw_writel(8, msg+16); + } } __raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); - if(req->current_nr_sectors > i2ob_max_sectors[unit]) - printk("Gathered sectors %ld.\n", - req->current_nr_sectors); - if(count != 0) { printk(KERN_ERR "Request count botched by %d.\n", count); @@ -434,7 +469,32 @@ return 1; } +static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit) +{ + unsigned long msg; + u32 m = i2ob_get(d); + + if(m == 0xFFFFFFFF) + return -1; + + msg = c->mem_offset + m; + /* + * Ask the controller to write the cache back. This sorts out + * the supertrak firmware flaw and also does roughly the right + * thing for other cases too. + */ + + __raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg); + __raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4); + __raw_writel(i2ob_context|(unit<<8), msg+8); + __raw_writel(0, msg+12); + __raw_writel(60<<16, msg+16); + + i2o_post_message(c,m); + return 0; +} + /* * OSM reply handler. This gets all the message replies */ @@ -447,7 +507,7 @@ u32 *m = (u32 *)msg; u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)]; - + /* * FAILed message */ @@ -482,9 +542,20 @@ if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) { spin_lock(&i2ob_evt_lock); - memcpy(&evt_msg, m, msg->size); + memcpy(evt_msg, msg, (m[0]>>16)<<2); spin_unlock(&i2ob_evt_lock); - wake_up_interruptible(&i2ob_evt_wait); + up(&i2ob_evt_sem); + return; + } + + if(msg->function == I2O_CMD_BLOCK_CFLUSH) + { + spin_lock_irqsave(&io_request_lock, flags); + dev->constipated=0; + DEBUG(("unconstipated\n")); + if(i2ob_backlog_request(c, dev)==0) + i2ob_request(dev->req_queue); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -517,6 +588,7 @@ if(st!=0) { + int err; char *bsa_errors[] = { "Success", @@ -535,12 +607,78 @@ "Volume has changed, waiting for acknowledgement" }; + err = m[4]&0xFFFF; + + /* + * Device not ready means two things. One is that the + * the thing went offline (but not a removal media) + * + * The second is that you have a SuperTrak 100 and the + * firmware got constipated. Unlike standard i2o card + * setups the supertrak returns an error rather than + * blocking for the timeout in these cases. + */ + + + spin_lock_irqsave(&io_request_lock, flags); + if(err==4) + { + /* + * Time to uncork stuff + */ + + if(!dev->constipated) + { + dev->constipated = 1; + DEBUG(("constipated\n")); + /* Now pull the chain */ + if(i2ob_flush(c, dev, unit)<0) + { + DEBUG(("i2ob: Unable to queue flush. Retrying I/O immediately.\n")); + dev->constipated=0; + } + DEBUG(("flushing\n")); + } + + /* + * Recycle the request + */ + +// i2ob_unhook_request(ireq, c->unit); + + /* + * Place it on the recycle queue + */ + + ireq->next = NULL; + if(i2ob_backlog_tail[c->unit]!=NULL) + i2ob_backlog_tail[c->unit]->next = ireq; + else + i2ob_backlog[c->unit] = ireq; + i2ob_backlog_tail[c->unit] = ireq; + + atomic_dec(&i2ob_queues[c->unit]->queue_depth); + + /* + * If the constipator flush failed we want to + * poke the queue again. + */ + + i2ob_request(dev->req_queue); + spin_unlock_irqrestore(&io_request_lock, flags); + + /* + * and out + */ + + return; + } + spin_unlock_irqrestore(&io_request_lock, flags); printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, bsa_errors[m[4]&0XFFFF]); if(m[4]&0x00FF0000) printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); - printk("\n"); - + printk(".\n"); ireq->req->errors++; } else @@ -559,7 +697,9 @@ /* * We may be able to do more I/O */ - i2ob_request(dev->req_queue); + + if(i2ob_backlog_request(c, dev)==0) + i2ob_request(dev->req_queue); spin_unlock_irqrestore(&io_request_lock, flags); } @@ -575,6 +715,14 @@ unsigned int flags; int unit; int i; + //The only event that has data is the SCSI_SMART event. + struct i2o_reply { + u32 header[4]; + u32 evt_indicator; + u8 ASC; + u8 ASCQ; + u8 data[16]; + } *evt_local; lock_kernel(); daemonize(); @@ -585,15 +733,13 @@ while(1) { -#warning "RACE" - interruptible_sleep_on(&i2ob_evt_wait); - if(signal_pending(current)) { + if(down_interruptible(&i2ob_evt_sem)) + { evt_running = 0; - return 0; + printk("exiting..."); + break; } - printk(KERN_INFO "Doing something in i2o_block event thread\n"); - /* * Keep another CPU/interrupt from overwriting the * message while we're reading it @@ -602,10 +748,12 @@ * None of the BSA we care about events have EventData */ spin_lock_irqsave(&i2ob_evt_lock, flags); - unit = evt_msg[3]; - evt = evt_msg[4]; + evt_local = (struct i2o_reply *)evt_msg; spin_unlock_irqrestore(&i2ob_evt_lock, flags); + unit = evt_local->header[3]; + evt = evt_local->evt_indicator; + switch(evt) { /* @@ -675,18 +823,43 @@ break; } + /* + * We got a SCSI SMART event, we just log the relevant + * information and let the user decide what they want + * to do with the information. + */ + case I2O_EVT_IND_BSA_SCSI_SMART: + { + char buf[16]; + printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",i2ob_dev[unit].i2odev->dev_name); + evt_local->data[16]='\0'; + sprintf(buf,"%s",&evt_local->data[0]); + printk(KERN_INFO " Disk Serial#:%s\n",buf); + printk(KERN_INFO " ASC 0x%02x \n",evt_local->ASC); + printk(KERN_INFO " ASCQ 0x%02x \n",evt_local->ASCQ); + break; + } + + /* + * Non event + */ + + case 0: + break; + /* * An event we didn't ask for. Call the card manufacturer * and tell them to fix their firmware :) */ default: - printk(KERN_INFO "%s: Received event we didn't register for\n" - KERN_INFO " Call I2O card manufacturer\n", - i2ob_dev[unit].i2odev->dev_name); + printk(KERN_INFO "%s: Received event %d we didn't register for\n" + KERN_INFO " Blame the I2O card manufacturer 8)\n", + i2ob_dev[unit].i2odev->dev_name, evt); break; } }; + up_and_exit(&i2ob_thread_dead,0); return 0; } @@ -724,6 +897,34 @@ spin_unlock_irqrestore(&io_request_lock,flags); } +static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev) +{ + u32 m; + struct i2ob_request *ireq; + + while((ireq=i2ob_backlog[c->unit])!=NULL) + { + int unit; + + if(atomic_read(&i2ob_queues[c->unit]->queue_depth) > dev->depth/4) + break; + + m = i2ob_get(dev); + if(m == 0xFFFFFFFF) + break; + + i2ob_backlog[c->unit] = ireq->next; + if(i2ob_backlog[c->unit] == NULL) + i2ob_backlog_tail[c->unit] = NULL; + + unit = MINOR(ireq->req->rq_dev); + i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit); + } + if(i2ob_backlog[c->unit]) + return 1; + return 0; +} + /* * The I2O block driver is listed as one of those that pulls the * front entry off the queue before processing it. This is important @@ -731,6 +932,7 @@ * on us. We must unlink CURRENT in this routine before we return, if * we use it. */ + static void i2ob_request(request_queue_t *q) { struct request *req; @@ -738,9 +940,8 @@ int unit; struct i2ob_device *dev; u32 m; - - // printk(KERN_INFO "i2ob_request() called with queue %p\n", q); - + + while (!list_empty(&q->queue_head)) { /* * On an IRQ completion if there is an inactive @@ -760,9 +961,16 @@ * generic IOP commit control. Certainly its not right * its global! */ - if(atomic_read(&i2ob_queues[dev->unit]->queue_depth)>=MAX_I2OB_DEPTH) + if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth) break; + + /* + * Is the channel constipated ? + */ + if(i2ob_backlog[dev->unit]!=NULL) + break; + /* Get a message */ m = i2ob_get(dev); @@ -773,7 +981,7 @@ */ if (!i2ob_timer_started) { - printk(KERN_ERR "i2ob: starting timer\n"); + DEBUG((KERN_ERR "i2ob: starting timer\n")); /* * Set the timer_started flag to insure @@ -795,6 +1003,7 @@ */ add_timer(&i2ob_timer); + return; } } @@ -804,7 +1013,7 @@ req->errors = 0; blkdev_dequeue_request(req); req->sem = NULL; - + ireq = i2ob_queues[dev->unit]->i2ob_qhead; i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; ireq->req = req; @@ -892,13 +1101,7 @@ for( i = 15; i>=0 ; i--) { int m = minor+i; - kdev_t d = MKDEV(MAJOR_NR, m); - struct super_block *sb = get_super(d); - - sync_dev(d); - if(sb) - invalidate_inodes(sb); - invalidate_buffers(d); + invalidate_device(MKDEV(MAJOR_NR, m), 1); i2ob_gendisk.part[m].start_sect = 0; i2ob_gendisk.part[m].nr_sects = 0; } @@ -1009,7 +1212,8 @@ msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = 60<<16; - i2o_post_wait(dev->controller, msg, 20, 2); + DEBUG("Flushing..."); + i2o_post_wait(dev->controller, msg, 20, 60); /* * Unlock the media @@ -1019,14 +1223,18 @@ msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = -1; + DEBUG("Unlocking..."); i2o_post_wait(dev->controller, msg, 20, 2); + DEBUG("Unlocked.\n"); /* * Now unclaim the device. */ + if (i2o_release_device(dev->i2odev, &i2o_block_handler)) printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); - + + DEBUG("Unclaim\n"); } MOD_DEC_USE_COUNT; return 0; @@ -1055,12 +1263,14 @@ { u32 msg[6]; + DEBUG("Claim "); if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) { dev->refcnt--; printk(KERN_INFO "I2O Block: Could not open device\n"); return -EBUSY; } + DEBUG("Claimed "); /* * Mount the media if needed. Note that we don't use @@ -1072,6 +1282,7 @@ msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; msg[4] = -1; msg[5] = 0; + DEBUG("Mount "); i2o_post_wait(dev->controller, msg, 24, 2); /* @@ -1080,7 +1291,9 @@ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; msg[4] = -1; + DEBUG("Lock "); i2o_post_wait(dev->controller, msg, 20, 2); + DEBUG("Ready.\n"); } MOD_INC_USE_COUNT; return 0; @@ -1132,7 +1345,8 @@ i2ob_query_device(dev, 0x0000, 5, &flags, 4); i2ob_query_device(dev, 0x0000, 6, &status, 4); i2ob_sizes[unit] = (int)(size>>10); - i2ob_hardsizes[unit] = blocksize; + for(i=unit; i <= unit+15 ; i++) + i2ob_hardsizes[i] = blocksize; i2ob_gendisk.part[unit].nr_sects = size>>9; i2ob[unit].nr_sects = (int)(size>>9); @@ -1143,20 +1357,33 @@ /* * Max number of Scatter-Gather Elements */ - i2ob_dev[unit].max_segments = - (d->controller->status_block->inbound_frame_size - 8)/2; - printk(KERN_INFO "Max Segments set to %d\n", - i2ob_dev[unit].max_segments); - printk(KERN_INFO "Byte limit is %d.\n", limit); - for(i=unit;i<=unit+15;i++) { - i2ob_max_sectors[i]=MAX_SECTORS; - i2ob_dev[i].max_segments = - (d->controller->status_block->inbound_frame_size - 8)/2; + if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy) + { + i2ob_max_sectors[i] = 32; + i2ob_dev[i].max_segments = 8; + i2ob_dev[i].depth = 4; + } + else if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.short_req) + { + i2ob_max_sectors[i] = 8; + i2ob_dev[i].max_segments = 8; + } + else + { + /* MAX_SECTORS was used but 255 is a dumb number for + striped RAID */ + i2ob_max_sectors[i]=256; + i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 8)/2; + } } + printk(KERN_INFO "Max segments set to %d\n", + i2ob_dev[unit].max_segments); + printk(KERN_INFO "Byte limit is %d.\n", limit); + i2ob_query_device(dev, 0x0000, 0, &type, 1); sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4)); @@ -1190,6 +1417,7 @@ printk(", %dMb cache", cachesize>>10); else printk(", %dKb cache", cachesize); + } printk(".\n"); printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", @@ -1277,53 +1505,94 @@ /* * Probe the I2O subsytem for block class devices */ -static void i2ob_probe(void) +static void i2ob_scan(int bios) { int i; - int unit = 0; int warned = 0; + + struct i2o_device *d, *b=NULL; + struct i2o_controller *c; + struct i2ob_device *dev; for(i=0; i< MAX_I2O_CONTROLLERS; i++) { - struct i2o_controller *c=i2o_find_controller(i); - struct i2o_device *d; + c=i2o_find_controller(i); if(c==NULL) continue; - for(d=c->devices;d!=NULL;d=d->next) - { + /* + * The device list connected to the I2O Controller is doubly linked + * Here we traverse the end of the list , and start claiming devices + * from that end. This assures that within an I2O controller atleast + * the newly created volumes get claimed after the older ones, thus + * mapping to same major/minor (and hence device file name) after + * every reboot. + * The exception being: + * 1. If there was a TID reuse. + * 2. There was more than one I2O controller. + */ + + if(!bios) + { + for (d=c->devices;d!=NULL;d=d->next) + if(d->next == NULL) + b = d; + } + else + b = c->devices; + + while(b != NULL) + { + d=b; + if(bios) + b = b->next; + else + b = b->prev; + if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) continue; if(d->lct_data.user_tid != 0xFFF) continue; + if(bios) + { + if(d->lct_data.bios_info != 0x80) + continue; + printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid); + } + else + { + if(d->lct_data.bios_info == 0x80) + continue; /*Already claimed on pass 1 */ + } + if(i2o_claim_device(d, &i2o_block_handler)) { printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit, d->lct_data.tid); - printk(KERN_WARNING "\tDevice refused claim! Skipping installation\n"); + printk(KERN_WARNING "\t%sevice refused claim! Skipping installation\n", bios?"Boot d":"D"); continue; } - if(uniti2odev = d; dev->controller = c; dev->unit = c->unit; dev->tid = d->lct_data.tid; - if(i2ob_install_device(c,d,unit)) + if(i2ob_install_device(c,d,scan_unit)) printk(KERN_WARNING "Could not install I2O block device\n"); else { - unit+=16; + scan_unit+=16; i2ob_dev_count++; /* We want to know when device goes away */ @@ -1333,7 +1602,7 @@ else { if(!warned++) - printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", unit>>4); + printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4); } i2o_release_device(d, &i2o_block_handler); } @@ -1341,6 +1610,31 @@ } } +static void i2ob_probe(void) +{ + /* + * Some overhead/redundancy involved here, while trying to + * claim the first boot volume encountered as /dev/i2o/hda + * everytime. All the i2o_controllers are searched and the + * first i2o block device marked as bootable is claimed + * If an I2O block device was booted off , the bios sets + * its bios_info field to 0x80, this what we search for. + * Assuming that the bootable volume is /dev/i2o/hda + * everytime will prevent any kernel panic while mounting + * root partition + */ + + printk(KERN_INFO "i2o_block: Checking for Boot device...\n"); + i2ob_scan(1); + + /* + * Now the remainder. + */ + printk(KERN_INFO "i2o_block: Checking for I2O Block devices...\n"); + i2ob_scan(0); +} + + /* * New device notification handler. Called whenever a new * I2O block storage device is added to the system. @@ -1369,14 +1663,6 @@ break; } - /* - * Creating a RAID 5 volume takes a little while and the UTIL_CLAIM - * will fail if we don't give the card enough time to do it's magic, - * so we just sleep for a little while and let it do it's thing - */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(3*HZ); - if(i2o_claim_device(d, &i2o_block_handler)) { printk(KERN_INFO @@ -1435,6 +1721,7 @@ if(unit >= MAX_I2OB<<4) { printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n"); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -1492,8 +1779,6 @@ i2ob_media_change_flag[unit] = 1; i2ob_dev_count--; - - return; } /* @@ -1540,8 +1825,11 @@ msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = 60<<16; - i2o_post_wait(dev->controller, msg, 20, 2); + + DEBUG("Flushing..."); + i2o_post_wait(dev->controller, msg, 20, 60); + DEBUG("Unlocking..."); /* * Unlock the media */ @@ -1551,20 +1839,21 @@ msg[3] = (u32)query_done; msg[4] = -1; i2o_post_wait(dev->controller, msg, 20, 2); + + DEBUG("Unlocked.\n"); } } } static struct block_device_operations i2ob_fops = { - open: i2ob_open, - release: i2ob_release, - ioctl: i2ob_ioctl, - check_media_change: i2ob_media_change, - revalidate: i2ob_revalidate, + open: i2ob_open, + release: i2ob_release, + ioctl: i2ob_ioctl, + check_media_change: i2ob_media_change, + revalidate: i2ob_revalidate, }; - static struct gendisk i2ob_gendisk = { MAJOR_NR, @@ -1573,9 +1862,10 @@ 1<<4, i2ob, i2ob_sizes, - 0, + MAX_I2OB, + NULL, NULL, - NULL + &i2ob_fops, }; @@ -1593,7 +1883,7 @@ int i; printk(KERN_INFO "I2O Block Storage OSM v0.9\n"); - printk(KERN_INFO " (c) Copyright 1999, 2000 Red Hat Software.\n"); + printk(KERN_INFO " (c) Copyright 1999-2001 Red Hat Software.\n"); /* * Register the block device interfaces @@ -1629,6 +1919,7 @@ i2ob_dev[i].tid = 0; i2ob_dev[i].head = NULL; i2ob_dev[i].tail = NULL; + i2ob_dev[i].depth = MAX_I2OB_DEPTH; i2ob_blksizes[i] = 1024; i2ob_max_sectors[i] = 2; } @@ -1683,7 +1974,13 @@ register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, &i2ob_fops, 0); i2ob_probe(); - + + /* + * Adding i2ob_gendisk into the gendisk list. + */ + i2ob_gendisk.next = gendisk_head; + gendisk_head = &i2ob_gendisk; + return 0; } @@ -1695,9 +1992,20 @@ void cleanup_module(void) { - struct gendisk **gdp; + struct gendisk *gdp; int i; + if(evt_running) { + printk(KERN_INFO "Killing I2O block threads..."); + i = kill_proc(evt_pid, SIGTERM, 1); + if(!i) { + printk("waiting..."); + } + /* Be sure it died */ + down(&i2ob_thread_dead); + printk("done.\n"); + } + /* * Unregister for updates from any devices..otherwise we still * get them and the core jumps to random memory :O @@ -1713,6 +2021,18 @@ } /* + * We may get further callbacks for ourself. The i2o_core + * code handles this case reasonably sanely. The problem here + * is we shouldn't get them .. but a couple of cards feel + * obliged to tell us stuff we dont care about. + * + * This isnt ideal at all but will do for now. + */ + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + + /* * Flush the OSM */ @@ -1729,28 +2049,20 @@ */ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - if(evt_running) { - i = kill_proc(evt_pid, SIGTERM, 1); - if(!i) { - int count = 5 * 100; - while(evt_running && --count) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR "Giving up on i2oblock thread...\n"); - } - } - - /* * Why isnt register/unregister gendisk in the kernel ??? */ - for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) - if (*gdp == &i2ob_gendisk) - break; - + if (gendisk_head == &i2ob_gendisk) { + gendisk_head = i2ob_gendisk.next; + } + else { + for (gdp = gendisk_head; gdp; gdp = gdp->next) + if (gdp->next == &i2ob_gendisk) + { + gdp->next = i2ob_gendisk.next; + break; + } + } } #endif diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c --- v2.4.4/linux/drivers/i2o/i2o_config.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_config.c Tue May 1 16:10:37 2001 @@ -42,7 +42,6 @@ static int i2o_cfg_context = -1; static void *page_buf; -static void *i2o_buffer; static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; @@ -499,6 +498,7 @@ if(!res) { i2o_unlock_controller(c); + kfree(query); return -ENOMEM; } @@ -517,16 +517,25 @@ msg[7] = 0xD4000000|(kcmd.qlen); msg[8] = virt_to_bus(query); } - - token = i2o_post_wait(c, msg, 9*4, 10); - if(token) + /* + Wait for a considerable time till the Controller + does its job before timing out. The controller might + take more time to process this request if there are + many devices connected to it. + */ + token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res); + if(token < 0) { printk(KERN_DEBUG "token = %#10x\n", token); i2o_unlock_controller(c); - kfree(res); - if(kcmd.qlen) kfree(query); + + if(token != -ETIMEDOUT) + { + kfree(res); + if(kcmd.qlen) kfree(query); + } - return -ETIMEDOUT; + return token; } i2o_unlock_controller(c); @@ -595,17 +604,18 @@ msg[8]= virt_to_bus(buffer); // printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait(c, msg, sizeof(msg), 60); + status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL); i2o_unlock_controller(c); - kfree(buffer); + if(status != -ETIMEDOUT) + kfree(buffer); if (status != I2O_POST_WAIT_OK) { // it fails if you try and send frags out of order // and for some yet unknown reasons too printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); - return -ETIMEDOUT; + return status; } return 0; @@ -660,14 +670,15 @@ msg[8]= virt_to_bus(buffer); // printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); - status = i2o_post_wait(c, msg, sizeof(msg), 60); + status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL); i2o_unlock_controller(c); if (status != I2O_POST_WAIT_OK) { - kfree(buffer); + if(status != -ETIMEDOUT) + kfree(buffer); printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); - return -ETIMEDOUT; + return status; } __copy_to_user(kxfer.buf, buffer, fragsize); @@ -787,13 +798,6 @@ struct i2o_evt_get kget; unsigned int flags; - // access_ok doesn't check for NULL?!?! - if(!arg) - return -EFAULT; - - if(!access_ok(VERIFY_WRITE, uget, sizeof(struct i2o_evt_get))) - return -EFAULT; - for(p = open_files; p; p = p->next) if(p->q_id == id) break; @@ -812,8 +816,8 @@ kget.lost = p->q_lost; spin_unlock_irqrestore(&i2o_config_lock, flags); - __copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)); - + if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) + return -EFAULT; return 0; } @@ -958,8 +962,6 @@ kfree(page_buf); if(i2o_cfg_context != -1) i2o_remove_handler(&cfg_handler); - if(i2o_buffer) - kfree(i2o_buffer); } EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.4.4/linux/drivers/i2o/i2o_core.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_core.c Tue May 1 16:10:37 2001 @@ -1,5 +1,5 @@ -/* - * Core I2O structure managment +/* + * Core I2O structure management * * (C) Copyright 1999 Red Hat Software * @@ -49,7 +49,7 @@ #include "i2o_lan.h" -// #define DRIVERDEBUG +//#define DRIVERDEBUG #ifdef DRIVERDEBUG #define dprintk(s, args...) printk(s, ## args) @@ -147,10 +147,12 @@ */ struct i2o_post_wait_data { - int status; - u32 id; - wait_queue_head_t *wq; - struct i2o_post_wait_data *next; + int *status; /* Pointer to status block on caller stack */ + int *complete; /* Pointer to completion flag on caller stack */ + u32 id; /* Unique identifier */ + wait_queue_head_t *wq; /* Wake up for caller (NULL for dead) */ + struct i2o_post_wait_data *next; /* Chain */ + void *mem[2]; /* Memory blocks to recover on failure path */ }; static struct i2o_post_wait_data *post_wait_queue = NULL; static u32 post_wait_id = 0; // Unique ID for each post_wait @@ -169,10 +171,10 @@ I2O_CLASS_EXECUTIVE }; - /* - * Used when queing a reply to be handled later + * Used when queueing a reply to be handled later */ + struct reply_info { struct i2o_controller *iop; @@ -199,10 +201,12 @@ static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED; /* - * Semaphore used to syncrhonize event handling thread with + * Semaphore used to synchronize event handling thread with * interrupt handler. */ -DECLARE_MUTEX(evt_sem); + +static DECLARE_MUTEX(evt_sem); +static DECLARE_MUTEX_LOCKED(evt_dead); DECLARE_WAIT_QUEUE_HEAD(evt_wait); static struct notifier_block i2o_reboot_notifier = @@ -212,6 +216,12 @@ 0 }; +/* + * Config options + */ + +static int verbose = 0; +MODULE_PARM(verbose, "i"); /* * I2O Core reply handler @@ -252,7 +262,7 @@ if(msg[2]&0x80000000) // Post wait message { if (msg[4] >> 24) - status = -(msg[4] & 0xFFFF); + status = (msg[4] & 0xFFFF); else status = I2O_POST_WAIT_OK; @@ -369,6 +379,9 @@ d->controller=c; d->owner=NULL; d->next=c->devices; + d->prev=NULL; + if (c->devices != NULL) + c->devices->prev=d; c->devices=d; *d->dev_name = 0; @@ -696,7 +709,7 @@ { down(&i2o_configuration_lock); if (d->owner) { - printk(KERN_INFO "Device claim called, but dev allready owned by %s!", + printk(KERN_INFO "Device claim called, but dev already owned by %s!", h->name); up(&i2o_configuration_lock); return -EBUSY; @@ -721,37 +734,59 @@ * Drop a claim by an OSM on a given I2O device. The handler is cleared * and 0 is returned on success. * + * AC - some devices seem to want to refuse an unclaim until they have + * finished internal processing. It makes sense since you don't want a + * new device to go reconfiguring the entire system until you are done. + * Thus we are prepared to wait briefly. */ int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) { int err = 0; + int tries; down(&i2o_configuration_lock); if (d->owner != h) { - printk(KERN_INFO "Claim release called, but not owned by %s!", + printk(KERN_INFO "Claim release called, but not owned by %s!\n", h->name); up(&i2o_configuration_lock); return -ENOENT; } - d->owner = NULL; - - if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, - I2O_CLAIM_PRIMARY)) + for(tries=0;tries<10;tries++) { - err = -ENXIO; - d->owner = h; - } + d->owner = NULL; + /* + * If the controller takes a nonblocking approach to + * releases we have to sleep/poll for a few times. + */ + + if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) ) + { + err = -ENXIO; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + else + { + err=0; + break; + } + } up(&i2o_configuration_lock); return err; } -/* - * Called by OSMs to let the core know that they want to be - * notified if the given device is deleted from the system. +/** + * i2o_device_notify_on - Enable deletion notifiers + * @d: device for notification + * @h: handler to install + * + * Called by OSMs to let the core know that they want to be + * notified if the given device is deleted from the system. */ + int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h) { int i; @@ -773,7 +808,11 @@ return 0; } -/* +/** + * i2o_device_notify_off - Remove deletion notifiers + * @d: device for notification + * @h: handler to remove + * * Called by OSMs to let the core know that they no longer * are interested in the fate of the given device. */ @@ -794,9 +833,18 @@ return -ENOENT; } -/* - * Event registration API +/** + * i2o_event_register - register interest in an event + * @c: Controller to register interest with + * @tid: I2O task id + * @init_context: initiator context to use with this notifier + * @tr_context: transaction context to use with this notifier + * @evt_mask: mask of events + * + * Create and posts an event registration message to the task. No reply + * is waited for, or expected. Errors in posting will be reported. */ + int i2o_event_register(struct i2o_controller *c, u32 tid, u32 init_context, u32 tr_context, u32 evt_mask) { @@ -814,11 +862,13 @@ } /* - * Event ack API + * i2o_event_ack - acknowledge an event + * @c: controller + * @msg: pointer to the UTIL_EVENT_REGISTER reply we received * - * We just take a pointer to the original UTIL_EVENT_REGISTER reply - * message and change the function code since that's what spec - * describes an EventAck message looking like. + * We just take a pointer to the original UTIL_EVENT_REGISTER reply + * message and change the function code since that's what spec + * describes an EventAck message looking like. */ int i2o_event_ack(struct i2o_controller *c, u32 *msg) @@ -850,12 +900,12 @@ while(1) { - down_interruptible(&evt_sem); - if(signal_pending(current)) + if(down_interruptible(&evt_sem)) { dprintk(KERN_INFO "I2O event thread dead\n"); + printk("exiting..."); evt_running = 0; - return 0; + up_and_exit(&evt_dead, 0); } /* @@ -922,6 +972,10 @@ kmalloc(sizeof(struct i2o_device), GFP_KERNEL); int i; + if (d == NULL) { + printk(KERN_EMERG "i2oevtd: out of memory\n"); + break; + } memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry)); d->next = NULL; @@ -974,7 +1028,11 @@ printk(KERN_WARNING "%s: Warning notification received!" "Check configuration for errors!\n", c->name); break; - + + case I2O_EVT_IND_EVT_MASK_MODIFIED: + /* Well I guess that was us hey .. */ + break; + default: printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]); break; @@ -1124,12 +1182,6 @@ m=(struct i2o_message *)bus_to_virt(mv); msg=(u32*)m; - /* - * Temporary Debugging - */ - if(m->function==0x15) - printk(KERN_ERR "%s: UTFR!\n", c->name); - i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; if(i && i->reply) i->reply(i,c,m); @@ -1219,9 +1271,9 @@ /** - * i2o_wait_message + * i2o_wait_message - obtain an i2o message from the IOP * @c: controller - * @why: explanation + * @why: explanation * * This function waits up to 5 seconds for a message slot to be * available. If no message is available it prints an error message @@ -1266,9 +1318,11 @@ char str[22]; int ret; int unit = d->lct_data.tid; - - printk(KERN_INFO "Target ID %d.\n", unit); + if(verbose==0) + return; + + printk(KERN_INFO "Target ID %d.\n", unit); if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0) { buf[16]=0; @@ -1279,13 +1333,11 @@ buf[16]=0; printk(KERN_INFO " Device: %s\n", buf); } -#if 0 if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0) { buf[16]=0; printk(KERN_INFO " Description: %s\n", buf); } -#endif if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0) { buf[8]=0; @@ -1581,7 +1633,7 @@ /** - * i2o_reset_controller + * i2o_reset_controller - reset an IOP * @c: controller to reset * * Reset the IOP into INIT state and wait until IOP gets into RESET state. @@ -1601,7 +1653,10 @@ /* Quiesce all IOPs first */ for (iop = i2o_controller_chain; iop; iop = iop->next) - i2o_quiesce_controller(iop); + { + if(iop->type != I2O_TYPE_PCI || !iop->bus.pci.dpt) + i2o_quiesce_controller(iop); + } m=i2o_wait_message(c, "AdapterReset"); if(m==0xFFFFFFFF) @@ -1628,19 +1683,19 @@ /* Wait for a reply */ time=jiffies; - while(status[0]==0) + while(*status==0) { if((jiffies-time)>=20*HZ) { printk(KERN_ERR "IOP reset timeout.\n"); - kfree(status); + // Better to leak this for safety: kfree(status); return -ETIMEDOUT; } schedule(); barrier(); } - if (status[0]==I2O_CMD_IN_PROGRESS) + if (*status==I2O_CMD_IN_PROGRESS) { /* * Once the reset is sent, the IOP goes into the INIT state @@ -1799,7 +1854,7 @@ u32 msg[6]; int ret, size = sizeof(i2o_hrt); - /* Read first just the header to figure out the real size */ + /* First read just the header to figure out the real size */ do { if (c->hrt == NULL) { @@ -1816,7 +1871,18 @@ msg[4]= (0xD0000000 | size); /* Simple transaction */ msg[5]= virt_to_bus(c->hrt); /* Dump it here */ - if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) { + ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL); + + if(ret == -ETIMEDOUT) + { + /* The HRT block we used is in limbo somewhere. When the iop wakes up + we will recover it */ + c->hrt = NULL; + return ret; + } + + if(ret<0) + { printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", c->name, -ret); return ret; @@ -1845,14 +1911,15 @@ static int i2o_systab_send(struct i2o_controller *iop) { u32 msg[12]; - u32 privmem[2]; - u32 privio[2]; int ret; + u32 *privbuf = kmalloc(16, GFP_KERNEL); + if(privbuf == NULL) + return -ENOMEM; - privmem[0] = iop->status_block->current_mem_base; - privmem[1] = iop->status_block->current_mem_size; - privio[0] = iop->status_block->current_io_base; - privio[1] = iop->status_block->current_io_size; + privbuf[0] = iop->status_block->current_mem_base; + privbuf[1] = iop->status_block->current_mem_size; + privbuf[2] = iop->status_block->current_io_base; + privbuf[3] = iop->status_block->current_io_size; msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; @@ -1864,20 +1931,33 @@ * Provide three SGL-elements: * System table (SysTab), Private memory space declaration and * Private i/o space declaration + * + * FIXME: provide these for controllers needing them */ msg[6] = 0x54000000 | sys_tbl_len; msg[7] = virt_to_bus(sys_tbl); msg[8] = 0x54000000 | 0; - msg[9] = virt_to_bus(privmem); + msg[9] = virt_to_bus(privbuf); msg[10] = 0xD4000000 | 0; - msg[11] = virt_to_bus(privio); + msg[11] = virt_to_bus(privbuf+8); - if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120))) - printk(KERN_INFO "%s: Unable to set SysTab (status=%#x).\n", + ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL); + + if(ret==-ETIMEDOUT) + { + printk(KERN_ERR "%s: SysTab setup timed out.\n", iop->name); + } + else if(ret<0) + { + printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", iop->name, -ret); + kfree(privbuf); + } else + { dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); - + kfree(privbuf); + } i2o_status_get(iop); // Entered READY state return ret; @@ -2162,7 +2242,16 @@ msg[6] = 0xD0000000|size; msg[7] = virt_to_bus(c->lct); - if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) { + ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL); + + if(ret == -ETIMEDOUT) + { + c->lct = NULL; + return ret; + } + + if(ret<0) + { printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", c->name, -ret); return ret; @@ -2206,8 +2295,11 @@ /* * Bring a controller online into OPERATIONAL state. */ + int i2o_online_controller(struct i2o_controller *iop) { + u32 v; + if (i2o_systab_send(iop) < 0) return -1; @@ -2223,6 +2315,15 @@ if (i2o_lct_get(iop) < 0) return -1; + /* Check battery status */ + + iop->battery = 0; + if(i2o_query_scalar(iop, ADAPTER_TID, 0x0000, 4, &v, 4)>=0) + { + if(v&16) + iop->battery = 1; + } + return 0; } @@ -2346,83 +2447,134 @@ return 0; } -/* - * This core API allows an OSM to post a message and then be told whether - * or not the system received a successful reply. It is useful when - * the OSM does not want to know the exact 3 +/** + * i2o_post_wait_mem - I2O query/reply with DMA buffers + * @c: controller + * @msg: message to send + * @len: length of message + * @timeout: time in seconds to wait + * @mem1: attached memory buffer 1 + * @mem2: attached memory buffer 2 + * + * This core API allows an OSM to post a message and then be told whether + * or not the system received a successful reply. + * + * If the message times out then the value '-ETIMEDOUT' is returned. This + * is a special case. In this situation the message may (should) complete + * at an indefinite time in the future. When it completes it will use the + * memory buffers attached to the request. If -ETIMEDOUT is returned then + * the memory buffers must not be freed. Instead the event completion will + * free them for you. In all other cases the buffers are your problem. + * + * Pass NULL for unneeded buffers. */ -int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) + +int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2) { DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); - int status = 0; + int complete = 0; + int status; int flags = 0; - struct i2o_post_wait_data *p1, *p2; struct i2o_post_wait_data *wait_data = kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL); if(!wait_data) return -ENOMEM; + /* + * Create a new notification object + */ + wait_data->status = &status; + wait_data->complete = &complete; + wait_data->mem[0] = mem1; + wait_data->mem[1] = mem2; /* - * The spin locking is needed to keep anyone from playing - * with the queue pointers and id while we do the same + * Queue the event with its unique id */ spin_lock_irqsave(&post_wait_lock, flags); + wait_data->next = post_wait_queue; post_wait_queue = wait_data; wait_data->id = (++post_wait_id) & 0x7fff; - spin_unlock_irqrestore(&post_wait_lock, flags); - wait_data->wq = &wq_i2o_post; - wait_data->status = -ETIMEDOUT; + spin_unlock_irqrestore(&post_wait_lock, flags); + + /* + * Fill in the message id + */ + msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); + /* + * Post the message to the controller. At some point later it + * will return. If we time out before it returns then + * complete will be zero. From the point post_this returns + * the wait_data may have been deleted. + */ if ((status = i2o_post_this(c, msg, len))==0) { - interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); - status = wait_data->status; + sleep_on_timeout(&wq_i2o_post, HZ * timeout); } - -#ifdef DRIVERDEBUG - if(status == -ETIMEDOUT) - printk(KERN_INFO "%s: POST WAIT TIMEOUT\n",c->name); -#endif - - /* - * Remove the entry from the queue. - * Since i2o_post_wait() may have been called again by - * a different thread while we were waiting for this - * instance to complete, we're not guaranteed that - * this entry is at the head of the queue anymore, so - * we need to search for it, find it, and delete it. - */ - p2 = NULL; + else + return -EIO; + + if(signal_pending(current)) + status = -EINTR; + spin_lock_irqsave(&post_wait_lock, flags); - for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) { - if(p1 == wait_data) { - if(p2) - p2->next = p1->next; - else - post_wait_queue = p1->next; - - break; + barrier(); /* Be sure we see complete as it is locked */ + if(!complete) + { + /* + * Mark the entry dead. We cannot remove it. This is important. + * When it does terminate (which it must do if the controller hasnt + * died..) then it will otherwise scribble on stuff. + * !complete lets us safely check if the entry is still + * allocated and thus we can write into it + */ + wait_data->wq = NULL; + status = -ETIMEDOUT; + } + else + { + /* Debugging check - remove me soon */ + if(status == -ETIMEDOUT) + { + printk("TIMEDOUT BUG!\n"); + status = -EIO; } } + /* And the wait_data is not leaked either! */ spin_unlock_irqrestore(&post_wait_lock, flags); - - kfree(wait_data); - return status; } +/** + * i2o_post_wait - I2O query/reply + * @c: controller + * @msg: message to send + * @len: length of message + * @timeout: time in seconds to wait + * + * This core API allows an OSM to post a message and then be told whether + * or not the system received a successful reply. + */ + +int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout) +{ + return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL); +} + /* * i2o_post_wait is completed and we want to wake up the * sleeping proccess. Called by core's reply handler. */ + static void i2o_post_wait_complete(u32 context, int status) { - struct i2o_post_wait_data *p1 = NULL; - + struct i2o_post_wait_data **p1, *q; + unsigned long flags; + /* * We need to search through the post_wait * queue to see if the given message is still @@ -2435,18 +2587,49 @@ * Lock needed to keep anyone from moving queue pointers * around while we're looking through them. */ - spin_lock(&post_wait_lock); - for(p1 = post_wait_queue; p1; p1 = p1->next) { - if(p1->id == ((context >> 16) & 0x7fff)) { - p1->status = status; - wake_up_interruptible(p1->wq); + + spin_lock_irqsave(&post_wait_lock, flags); + + for(p1 = &post_wait_queue; *p1!=NULL; p1 = &((*p1)->next)) + { + q = (*p1); + if(q->id == ((context >> 16) & 0x7fff)) { + /* + * Delete it + */ + + *p1 = q->next; + + /* + * Live or dead ? + */ + + if(q->wq) + { + /* Live entry - wakeup and set status */ + *q->status = status; + *q->complete = 1; + wake_up(q->wq); + } + else + { + /* + * Free resources. Caller is dead + */ + if(q->mem[0]) + kfree(q->mem[0]); + if(q->mem[1]) + kfree(q->mem[1]); + printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n"); + } + kfree(q); spin_unlock(&post_wait_lock); return; } } spin_unlock(&post_wait_lock); - printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n"); + printk(KERN_DEBUG "i2o_post_wait: Bogus reply!\n"); } /* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET @@ -2461,25 +2644,52 @@ void *oplist, int oplen, void *reslist, int reslen) { u32 msg[9]; - u8 *res = (u8 *)reslist; u32 *res32 = (u32*)reslist; u32 *restmp = (u32*)reslist; int len = 0; int i = 0; int wait_status; - + u32 *opmem, *resmem; + + /* Get DMAable memory */ + opmem = kmalloc(oplen, GFP_KERNEL); + if(opmem == NULL) + return -ENOMEM; + memcpy(opmem, oplist, oplen); + + resmem = kmalloc(reslen, GFP_KERNEL); + if(resmem == NULL) + { + kfree(opmem); + return -ENOMEM; + } + msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; msg[1] = cmd << 24 | HOST_TID << 12 | tid; msg[3] = 0; msg[4] = 0; msg[5] = 0x54000000 | oplen; /* OperationList */ - msg[6] = virt_to_bus(oplist); + msg[6] = virt_to_bus(opmem); msg[7] = 0xD0000000 | reslen; /* ResultList */ - msg[8] = virt_to_bus(reslist); + msg[8] = virt_to_bus(resmem); - if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10))) - return wait_status; /* -DetailedStatus */ + wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem); + + /* + * This only looks like a memory leak - don't "fix" it. + */ + if(wait_status == -ETIMEDOUT) + return wait_status; + /* Query failed */ + if(wait_status != 0) + { + kfree(resmem); + kfree(opmem); + return wait_status; + } + + memcpy(reslist, resmem, reslen); /* * Calculate number of bytes of Result LIST * We need to loop through each Result BLOCK and grab the length @@ -2500,13 +2710,13 @@ * If this is the only request,than we return an error */ if((res32[0]&0x0000FFFF) == 1) - return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ + { + return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */ + } } - len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ } - return (len << 2); /* bytes used by result list */ } @@ -2526,10 +2736,10 @@ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, opblk, sizeof(opblk), resblk, sizeof(resblk)); - if (size < 0) - return size; - memcpy(buf, resblk+8, buflen); /* cut off header */ + + if(size>buflen) + return buflen; return size; } @@ -2570,6 +2780,8 @@ opblk, 12+buflen, resblk, sizeof(resblk)); kfree(opblk); + if(size>buflen) + return buflen; return size; } @@ -2614,6 +2826,8 @@ opblk, 10+ibuflen, resblk, reslen); kfree(opblk); + if(size>reslen) + return reslen; return size; } @@ -2662,6 +2876,8 @@ opblk, 10+buflen, resblk, sizeof(resblk)); kfree(opblk); + if(size>buflen) + return buflen; return size; } @@ -3113,8 +3329,6 @@ } -#ifdef MODULE - EXPORT_SYMBOL(i2o_controller_chain); EXPORT_SYMBOL(i2o_num_controllers); EXPORT_SYMBOL(i2o_find_controller); @@ -3131,6 +3345,7 @@ EXPORT_SYMBOL(i2o_post_this); EXPORT_SYMBOL(i2o_post_wait); +EXPORT_SYMBOL(i2o_post_wait_mem); EXPORT_SYMBOL(i2o_query_scalar); EXPORT_SYMBOL(i2o_set_scalar); @@ -3147,6 +3362,8 @@ EXPORT_SYMBOL(i2o_get_class_name); +#ifdef MODULE + MODULE_AUTHOR("Red Hat Software"); MODULE_DESCRIPTION("I2O Core"); @@ -3206,17 +3423,13 @@ * If this is shutdown time, the thread has already been killed */ if(evt_running) { + printk("Terminating i2o threads..."); stat = kill_proc(evt_pid, SIGTERM, 1); if(!stat) { - int count = 10 * 100; - while(evt_running && count--) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - - if(!count) - printk(KERN_ERR "i2o: Event thread still running!\n"); + printk("waiting..."); + down(&evt_dead); } + printk("done.\n"); } #ifdef CONFIG_I2O_PCI_MODULE diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c --- v2.4.4/linux/drivers/i2o/i2o_pci.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2o/i2o_pci.c Tue May 1 16:11:29 2001 @@ -160,6 +160,10 @@ c->bus.pci.irq = -1; + c->bus.pci.queue_buggy = 0; + c->bus.pci.dpt = 0; + c->bus.pci.short_req = 0; + c->irq_mask = (volatile u32 *)(mem+0x34); c->post_port = (volatile u32 *)(mem+0x40); c->reply_port = (volatile u32 *)(mem+0x44); @@ -175,6 +179,30 @@ c->type = I2O_TYPE_PCI; + /* + * Cards that fall apart if you hit them with large I/O + * loads... + */ + + if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630) + { + c->bus.pci.short_req=1; + printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n"); + } + if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) + { + c->bus.pci.queue_buggy=1; + printk(KERN_INFO "I2O: Promise workarounds activated.\n"); + } + + /* + * Cards that go bananas if you quiesce them before you reset + * them + */ + + if(dev->vendor == PCI_VENDOR_ID_DPT) + c->bus.pci.dpt=1; + /* * Enable Write Combining MTRR for IOP's memory region */ @@ -186,13 +214,12 @@ * since the region contains the Messaging unit which shouldn't be cached. */ c->bus.pci.mtrr_reg1 = -1; - if(dev->vendor == PCI_VENDOR_ID_INTEL) + if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT) { - printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); - c->bus.pci.mtrr_reg1 = - mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); - if(c->bus.pci.mtrr_reg1< 0) - printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); + printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); + c->bus.pci.mtrr_reg1 = mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1); + if(c->bus.pci.mtrr_reg1< 0) + printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n"); } #endif diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c --- v2.4.4/linux/drivers/i2o/i2o_proc.c Fri Nov 17 16:51:47 2000 +++ linux/drivers/i2o/i2o_proc.c Tue May 1 16:09:53 2001 @@ -2356,7 +2356,7 @@ len += sprintf(buf+len, "Packet orphan limit : %d\n", work32[2]); len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]); - len += sprintf(buf+len, " [%s] HW CRC supression\n", + len += sprintf(buf+len, " [%s] HW CRC suppression\n", (work32[3]&0x00000004) ? "+" : "-"); len += sprintf(buf+len, " [%s] HW IPv4 checksum\n", (work32[3]&0x00000100) ? "+" : "-"); @@ -2368,7 +2368,7 @@ (work32[3]&0x00000800) ? "+" : "-"); len += sprintf(buf+len, " [%s] HW ICMP checksum\n", (work32[3]&0x00001000) ? "+" : "-"); - len += sprintf(buf+len, " [%s] Loopback supression enable\n", + len += sprintf(buf+len, " [%s] Loopback suppression enable\n", (work32[3]&0x00002000) ? "+" : "-"); len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]); diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c --- v2.4.4/linux/drivers/i2o/i2o_scsi.c Mon Oct 30 14:44:29 2000 +++ linux/drivers/i2o/i2o_scsi.c Tue May 1 16:09:53 2001 @@ -262,7 +262,7 @@ if(st) { - /* An error has occured */ + /* An error has occurred */ dprintk((KERN_DEBUG "SCSI error %08X", m[4])); diff -u --recursive --new-file v2.4.4/linux/drivers/ide/hd.c linux/drivers/ide/hd.c --- v2.4.4/linux/drivers/ide/hd.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/ide/hd.c Sat Apr 28 11:27:53 2001 @@ -892,13 +892,7 @@ for (i=max_p - 1; i >=0 ; i--) { int minor = start + i; - kdev_t devi = MKDEV(MAJOR_NR, minor); - struct super_block *sb = get_super(devi); - - sync_dev(devi); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR, minor), 1); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; } diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c --- v2.4.4/linux/drivers/ide/ide-pci.c Thu Apr 19 22:57:06 2001 +++ linux/drivers/ide/ide-pci.c Tue May 1 16:05:00 2001 @@ -581,7 +581,7 @@ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) { printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n"); - if(dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && + if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) { printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n"); diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c --- v2.4.4/linux/drivers/ide/ide-pnp.c Wed May 24 18:38:26 2000 +++ linux/drivers/ide/ide-pnp.c Tue May 1 16:06:23 2001 @@ -49,7 +49,7 @@ /* ISA PnP device table entry */ struct pnp_dev_t { - unsigned int vendor, device; + unsigned short card_vendor, card_device, vendor, device; int (*init_fn)(struct pci_dev *dev, int enable); }; @@ -81,8 +81,9 @@ /* Add your devices here :)) */ struct pnp_dev_t idepnp_devices[] __initdata = { - /* Generic ESDI/IDE/ATA compatible hard disk controller */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600), + /* Generic ESDI/IDE/ATA compatible hard disk controller */ + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600), pnpide_generic_init }, { 0 } }; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.4/linux/drivers/ide/ide.c Wed Apr 11 19:06:12 2001 +++ linux/drivers/ide/ide.c Tue May 1 16:05:00 2001 @@ -179,6 +179,8 @@ static int ide_lock; #endif /* __mc68000__ || CONFIG_APUS */ +int noautodma = 0; + /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ @@ -1762,11 +1764,7 @@ for (p = 0; p < (1<part[p].nr_sects > 0) { kdev_t devp = MKDEV(major, minor+p); - struct super_block * sb = get_super(devp); - fsync_dev (devp); - if (sb) - invalidate_inodes(sb); - invalidate_buffers (devp); + invalidate_device(devp, 1); set_blocksize(devp, 1024); } drive->part[p].start_sect = 0; @@ -1983,9 +1981,7 @@ for (p = 0; p < (1<part[p].nr_sects > 0) { kdev_t devp = MKDEV(hwif->major, minor+p); - struct super_block * sb = get_super(devp); - if (sb) invalidate_inodes(sb); - invalidate_buffers (devp); + invalidate_device(devp, 0); } } #ifdef CONFIG_PROC_FS @@ -2893,6 +2889,12 @@ return 1; } #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + + if (!strcmp(s, "ide=nodma")) { + printk("IDE: Prevented DMA\n"); + noautodma = 1; + return 1; + } #ifdef CONFIG_BLK_DEV_IDEPCI if (!strcmp(s, "ide=reverse")) { diff -u --recursive --new-file v2.4.4/linux/drivers/ide/opti621.c linux/drivers/ide/opti621.c --- v2.4.4/linux/drivers/ide/opti621.c Tue Nov 7 11:02:24 2000 +++ linux/drivers/ide/opti621.c Tue May 1 16:05:00 2001 @@ -118,7 +118,7 @@ /* Uncommnent for disable read prefetch. * There is some readprefetch capatibility in hdparm, * but when I type hdparm -P 1 /dev/hda, I got errors - * and till reset drive is inacessible. + * and till reset drive is inaccessible. * This (hw) read prefetch is safe on my drive. */ diff -u --recursive --new-file v2.4.4/linux/drivers/ide/osb4.c linux/drivers/ide/osb4.c --- v2.4.4/linux/drivers/ide/osb4.c Sun Feb 4 10:05:30 2001 +++ linux/drivers/ide/osb4.c Tue May 1 16:05:00 2001 @@ -402,10 +402,16 @@ #ifdef DEBUG printk("%s: reg64 == 0x%08x\n", name, reg64); #endif - reg64 &= ~0x0000A000; -#ifdef CONFIG_SMP - reg64 |= 0x00008000; -#endif + +// reg64 &= ~0x0000A000; +//#ifdef CONFIG_SMP +// reg64 |= 0x00008000; +//#endif + /* Assume the APIC was set up properly by the BIOS for now . If it + wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control + APIC enable, routing and decode */ + + reg64 &= ~0x00002000; pci_write_config_dword(isa_dev, 0x64, reg64); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); @@ -441,7 +447,8 @@ #else /* CONFIG_BLK_DEV_IDEDMA */ if (hwif->dma_base) { - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &osb4_dmaproc; } else { hwif->autodma = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c --- v2.4.4/linux/drivers/ide/pdc202xx.c Thu Apr 19 22:57:06 2001 +++ linux/drivers/ide/pdc202xx.c Tue May 1 16:05:00 2001 @@ -101,13 +101,6 @@ return(pdc202xx_dma_verbose(drive_pci)); } -char *pdc202xx_interrupt_verbose (u8 sc1d) -{ - char *p = NULL; - p += sprintf(p,"0x%02x ", sc1d); - return (char *)p; -} - static char * pdc202xx_info (char *buf, struct pci_dev *dev) { char *p = buf; @@ -862,7 +855,8 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &pdc202xx_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } else { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff -u --recursive --new-file v2.4.4/linux/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c --- v2.4.4/linux/drivers/ide/rz1000.c Thu Apr 13 22:54:26 2000 +++ linux/drivers/ide/rz1000.c Tue May 1 16:05:00 2001 @@ -94,4 +94,4 @@ init_rz1000 (dev, "RZ1001"); } -#endif CONFIG_BLK_DEV_IDEPCI +#endif /* CONFIG_BLK_DEV_IDEPCI */ diff -u --recursive --new-file v2.4.4/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c --- v2.4.4/linux/drivers/macintosh/via-cuda.c Sun Sep 17 09:48:05 2000 +++ linux/drivers/macintosh/via-cuda.c Tue May 1 16:05:00 2001 @@ -170,7 +170,7 @@ } /* Clear and enable interrupts, but only on PPC. On 68K it's done */ - /* for us by the the main VIA driver in arch/m68k/mac/via.c */ + /* for us by the main VIA driver in arch/m68k/mac/via.c */ #ifndef CONFIG_MAC via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/tvaudio.c linux/drivers/media/video/tvaudio.c --- v2.4.4/linux/drivers/media/video/tvaudio.c Mon Feb 19 14:43:36 2001 +++ linux/drivers/media/video/tvaudio.c Tue May 1 16:05:00 2001 @@ -124,7 +124,7 @@ /* ---------------------------------------------------------------------- */ -/* i2c adresses */ +/* i2c addresses */ static unsigned short normal_i2c[] = { I2C_TDA8425 >> 1, diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c --- v2.4.4/linux/drivers/mtd/ftl.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/mtd/ftl.c Sat Apr 28 11:27:54 2001 @@ -915,9 +915,6 @@ static release_t ftl_close(struct inode *inode, struct file *file) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - struct super_block *sb = get_super(inode->i_rdev); -#endif int minor = MINOR(inode->i_rdev); partition_t *part = myparts[minor >> 4]; int i; @@ -925,11 +922,7 @@ DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); /* Flush all writes */ - fsync_dev(inode->i_rdev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (sb) invalidate_inodes(sb); -#endif - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 1); /* Wait for any pending erase operations to complete */ if (part->mtd->sync) diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c --- v2.4.4/linux/drivers/mtd/mtdblock.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/mtd/mtdblock.c Sat Apr 28 11:27:54 2001 @@ -355,19 +355,12 @@ { int dev; struct mtdblk_dev *mtdblk; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - struct super_block * sb = get_super(inode->i_rdev); -#endif DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); if (inode == NULL) release_return(-ENODEV); - fsync_dev(inode->i_rdev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (sb) invalidate_inodes(sb); -#endif - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 1); dev = MINOR(inode->i_rdev); mtdblk = mtdblks[dev]; diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/nftl.c linux/drivers/mtd/nftl.c --- v2.4.4/linux/drivers/mtd/nftl.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/mtd/nftl.c Sat Apr 28 11:27:54 2001 @@ -997,17 +997,13 @@ static int nftl_release(struct inode *inode, struct file *fp) { - struct super_block *sb = get_super(inode->i_rdev); struct NFTLrecord *thisNFTL; thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16]; DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); - fsync_dev(inode->i_rdev); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(inode->i_rdev); + invalidate_device(inode->i_rdev, 1); if (thisNFTL->mtd->sync) thisNFTL->mtd->sync(thisNFTL->mtd); diff -u --recursive --new-file v2.4.4/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.4/linux/drivers/net/8139too.c Thu Apr 19 09:32:48 2001 +++ linux/drivers/net/8139too.c Mon May 7 14:13:19 2001 @@ -149,7 +149,7 @@ #include -#define RTL8139_VERSION "0.9.16" +#define RTL8139_VERSION "0.9.17" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -728,7 +728,7 @@ struct rtl8139_private *tp; u8 tmp8; int rc; - unsigned int i, have_pci_pm = 1; + unsigned int i; u32 pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 tmp; @@ -770,10 +770,6 @@ DPRINTK("PIO region size == 0x%02X\n", pio_len); DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); - /* ugly hueristic, but it's a chicken-and-egg problem */ - if (pio_len < RTL8139B_IO_SIZE) - have_pci_pm = 0; - #ifdef USE_IO_OPS /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { @@ -824,30 +820,7 @@ #endif /* USE_IO_OPS */ /* Bring old chips out of low-power mode. */ - if (have_pci_pm) { - u8 new_tmp8 = tmp8 = RTL_R8 (Config1); - if ((rtl_chip_info[tp->chipset].flags & HasLWake) && - (tmp8 & LWAKE)) - new_tmp8 &= ~LWAKE; - new_tmp8 |= Cfg1_PM_Enable; - if (new_tmp8 != tmp8) { - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, tmp8); - RTL_W8 (Cfg9346, Cfg9346_Lock); - } - if (rtl_chip_info[tp->chipset].flags & HasLWake) { - tmp8 = RTL_R8 (Config4); - if (tmp8 & LWPTN) - RTL_W8 (Config4, tmp8 & ~LWPTN); - } - } else { - RTL_W8 (HltClk, 'R'); - tmp8 = RTL_R8 (Config1); - tmp8 &= ~(SLEEP | PWRDN); - RTL_W8 (Config1, tmp8); - } - - rtl8139_chip_reset (ioaddr); + RTL_W8 (HltClk, 'R'); /* check for missing/broken hardware */ if (RTL_R32 (TxConfig) == 0xFFFFFFFF) { @@ -877,6 +850,32 @@ tp->chipset, rtl_chip_info[tp->chipset].name); + if (tp->chipset >= CH_8139B) { + u8 new_tmp8 = tmp8 = RTL_R8 (Config1); + DPRINTK("PCI PM wakeup\n"); + if ((rtl_chip_info[tp->chipset].flags & HasLWake) && + (tmp8 & LWAKE)) + new_tmp8 &= ~LWAKE; + new_tmp8 |= Cfg1_PM_Enable; + if (new_tmp8 != tmp8) { + RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tmp8); + RTL_W8 (Cfg9346, Cfg9346_Lock); + } + if (rtl_chip_info[tp->chipset].flags & HasLWake) { + tmp8 = RTL_R8 (Config4); + if (tmp8 & LWPTN) + RTL_W8 (Config4, tmp8 & ~LWPTN); + } + } else { + DPRINTK("Old chip wakeup\n"); + tmp8 = RTL_R8 (Config1); + tmp8 &= ~(SLEEP | PWRDN); + RTL_W8 (Config1, tmp8); + } + + rtl8139_chip_reset (ioaddr); + DPRINTK ("EXIT, returning 0\n"); *dev_out = dev; return 0; @@ -1358,11 +1357,16 @@ else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040) tp->full_duplex = 1; - printk(KERN_INFO"%s: Setting %s%s-duplex based on" + if (mii_reg5) { + printk(KERN_INFO"%s: Setting %s%s-duplex based on" " auto-negotiated partner ability %4.4x.\n", dev->name, mii_reg5 == 0 ? "" : (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", tp->full_duplex ? "full" : "half", mii_reg5); + } else { + printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + dev->name); + } } if (tp->chipset >= CH_8139B) { @@ -1542,11 +1546,18 @@ || (mii_reg5 & 0x01C0) == 0x0040; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; - printk (KERN_INFO - "%s: Setting %s-duplex based on MII #%d link" - " partner ability of %4.4x.\n", dev->name, - tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); + + if (mii_reg5) { + printk (KERN_INFO + "%s: Setting %s-duplex based on MII #%d link" + " partner ability of %4.4x.\n", + dev->name, + tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + } else { + printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + dev->name); + } #if 0 RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); diff -u --recursive --new-file v2.4.4/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.4/linux/drivers/net/Config.in Sun Apr 22 15:43:21 2001 +++ linux/drivers/net/Config.in Mon May 7 19:42:14 2001 @@ -261,6 +261,9 @@ dep_bool ' Aironet 4500/4800 I365 broken support (EXPERIMENTAL)' CONFIG_AIRONET4500_I365 $CONFIG_EXPERIMENTAL fi dep_tristate ' Aironet 4500/4800 PROC interface ' CONFIG_AIRONET4500_PROC $CONFIG_AIRONET4500 m + +# New directory for Wireless LAN devices - cards above will move there + source drivers/net/wireless/Config.in fi endmenu diff -u --recursive --new-file v2.4.4/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.4.4/linux/drivers/net/Makefile Thu Apr 19 22:46:05 2001 +++ linux/drivers/net/Makefile Mon May 7 19:42:14 2001 @@ -8,7 +8,7 @@ obj-n := obj- := -mod-subdirs := appletalk arcnet fc irda tokenring pcmcia wan +mod-subdirs := appletalk arcnet fc irda tokenring pcmcia wireless wan O_TARGET := net.o @@ -30,6 +30,7 @@ endif subdir-$(CONFIG_NET_PCMCIA) += pcmcia +subdir-$(CONFIG_NET_RADIO) += wireless subdir-$(CONFIG_TULIP) += tulip subdir-$(CONFIG_IRDA) += irda subdir-$(CONFIG_TR) += tokenring diff -u --recursive --new-file v2.4.4/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.4.4/linux/drivers/net/acenic_firmware.h Tue Mar 6 19:28:33 2001 +++ linux/drivers/net/acenic_firmware.h Tue May 1 22:03:44 2001 @@ -17,7 +17,7 @@ #define tigonFwSbssLen 0x38 #define tigonFwBssAddr 0x00015dd0 #define tigonFwBssLen 0x2080 -#ifndef CONFIG_ACENIC_OMIT_TIGON_I +#ifdef CONFIG_ACENIC_OMIT_TIGON_I #define tigonFwText 0 #define tigonFwData 0 #define tigonFwRodata 0 diff -u --recursive --new-file v2.4.4/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.4.4/linux/drivers/net/dmfe.c Wed Apr 25 16:14:08 2001 +++ linux/drivers/net/dmfe.c Tue May 1 20:59:24 2001 @@ -1306,7 +1306,7 @@ rxptr = db->rx_insert_ptr; while (db->rx_avail_cnt < RX_DESC_CNT) { - if ((skb = alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC)) == NULL) + if ((skb = dev_alloc_skb(RX_ALLOC_SIZE)) == NULL) break; rxptr->rx_skb_ptr = (u32) skb; rxptr->rdes2 = virt_to_bus(skb->tail); diff -u --recursive --new-file v2.4.4/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.4.4/linux/drivers/net/eql.c Wed Apr 18 14:40:06 2001 +++ linux/drivers/net/eql.c Mon May 14 23:55:12 2001 @@ -422,6 +422,8 @@ slave_t *s = eql_new_slave (); equalizer_t *eql = (equalizer_t *) master_dev->priv; + if (!s) + return -ENOMEM; s->dev = slave_dev; s->priority = srq.priority; s->priority_bps = srq.priority; diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in --- v2.4.4/linux/drivers/net/irda/Config.in Fri Jan 28 19:36:22 2000 +++ linux/drivers/net/irda/Config.in Tue May 1 16:05:00 2001 @@ -5,14 +5,6 @@ dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA -comment 'FIR device drivers' -dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA -dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA -dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA -if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then -dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA -fi - comment 'Dongle support' bool 'Serial dongle support' CONFIG_DONGLE if [ "$CONFIG_DONGLE" != "n" ]; then @@ -22,6 +14,15 @@ dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA +fi + +comment 'FIR device drivers' +dep_tristate 'IrDA USB dongles (Experimental)' CONFIG_USB_IRDA $CONFIG_IRDA $CONFIG_USB $CONFIG_EXPERIMENTAL +dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA +dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA +dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then +dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA fi endmenu diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile --- v2.4.4/linux/drivers/net/irda/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/net/irda/Makefile Tue May 1 16:05:00 2001 @@ -12,6 +12,7 @@ obj-$(CONFIG_IRTTY_SIR) += irtty.o obj-$(CONFIG_IRPORT_SIR) += irport.o +obj-$(CONFIG_USB_IRDA) += irda-usb.o obj-$(CONFIG_NSC_FIR) += nsc-ircc.o obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c --- v2.4.4/linux/drivers/net/irda/irda-usb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/irda/irda-usb.c Tue May 1 16:05:00 2001 @@ -0,0 +1,1176 @@ +/***************************************************************************** + * + * Filename: irda-usb.c + * Version: 0.9 + * Description: IrDA-USB Driver + * Status: Experimental + * Author: Dag Brattli + * + * Copyright (C) 2001, Dag Brattli + * Copyright (C) 2001, Jean Tourrilhes + * Copyright (C) 2000, Roman Weissgaerber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +static u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */ +static int qos_mtt_bits = 0; + +static void irda_usb_dump_class_desc(struct irda_class_desc *desc); +static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum); +static void irda_usb_disconnect(struct usb_device *dev, void *ptr); +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); +static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static int irda_usb_open(struct irda_usb_cb *self); +static int irda_usb_close(struct irda_usb_cb *self); +static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb); +static void write_bulk_callback(purb_t purb); +static void irda_usb_receive(purb_t purb); +static int irda_usb_net_init(struct net_device *dev); +static int irda_usb_net_open(struct net_device *dev); +static int irda_usb_net_close(struct net_device *dev); +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void irda_usb_net_timeout(struct net_device *dev); +static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev); + +/* Master instance for each hardware found */ +#define NIRUSB 4 /* Max number of USB-IrDA dongles */ +static struct irda_usb_cb irda_instance[NIRUSB]; + +/* These are the currently known IrDA USB dongles. Add new dongles here */ +static struct usb_device_id dongles[] = { + /* ACTiSYS Corp, ACT-IR2000U FIR-USB Adapter */ + { USB_DEVICE(0x9c4, 0x011), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* KC Technology Inc., KC-180 USB IrDA Device */ + { USB_DEVICE(0x50f, 0x180), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ + { USB_DEVICE(0x8e9, 0x100), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW }, + { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, + bInterfaceClass: USB_CLASS_APP_SPEC, + bInterfaceSubClass: USB_CLASS_IRDA, + driver_info: IUC_DEFAULT, }, + { }, /* The end */ +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + * Note : it might be worth protecting this function by a global + * spinlock... + */ +static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct irda_usb_cb *self = NULL; + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct irda_class_desc *irda_desc; + int capability = id->driver_info; + int ret; + int ep; + int i; + + IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); + + MESSAGE("IRDA-USB found at address %d\n", dev->devnum); + + /* Try to cleanup all instance that have a pending disconnect + * Instance will be in this state is the disconnect() occurs + * before the net_close(). + * Jean II */ + for (i = 0; i < NIRUSB; i++) { + struct irda_usb_cb *irda = &irda_instance[i]; + if ((irda->usbdev != NULL) && + (irda->present == 0) && + (irda->netopen == 0)) { + IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n"); + irda_usb_disconnect(irda->usbdev, (void *) irda); + } + } + + /* Find an free instance to handle this new device... */ + self = NULL; + for (i = 0; i < NIRUSB; i++) { + if(irda_instance[i].usbdev == NULL) { + self = &irda_instance[i]; + break; + } + } + if (self == NULL) { + IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n", + NIRUSB); + return NULL; + } + + /* Reset the instance */ + self->present = 0; + self->netopen = 0; + + /* Is this really necessary? */ + if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) { + err("set_configuration failed"); + return NULL; + } + + /* Is this really necessary? */ + ret = usb_set_interface(dev, ifnum, 0); + IRDA_DEBUG(0, "usb-irda: set interface result %d\n", ret); + switch (ret) { + case USB_ST_NOERROR: /* 0 */ + break; + case USB_ST_STALL: /* -EPIPE = -32 */ + usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); + IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" ); + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret); + return NULL; + break; + } + + /* Find our endpoints */ + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + endpoint = interface->endpoint; + ep = endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if ((endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + self->bulk_in_ep = ep; + else { + self->bulk_out_ep = ep; + self->bulk_out_mtu = endpoint[0].wMaxPacketSize; + } + + ep = endpoint[1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if ((endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + self->bulk_in_ep = ep; + else { + self->bulk_out_ep = ep; + self->bulk_out_mtu = endpoint[1].wMaxPacketSize; + } + + if (self->bulk_out_ep == 0 || self->bulk_in_ep == 0 || + endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK || + endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK) + { + ERROR(__FUNCTION__ "(), Bogus endpoints"); + return NULL; + } + + /* Find IrDA class descriptor */ + irda_desc = irda_usb_find_class_desc(dev, ifnum); + if (irda_desc == NULL) + return NULL; + + self->irda_desc = irda_desc; + self->present = 1; + self->netopen = 0; + self->capability = capability; + self->usbdev = dev; + ret = irda_usb_open(self); + if (ret) + return NULL; + + return self; +} + +/* + * Function irda_usb_find_class_desc(dev, ifnum) + * + * Returns instance of IrDA class descriptor, or NULL if not found + * + */ +static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct irda_class_desc *desc, *ptr; + int ret; + + desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); + if (desc == NULL) + return NULL; + memset(desc, 0, sizeof(struct irda_class_desc)); + + ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc)); + IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret); + if (ret) { + WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret); + } + + /* Check if we found it? */ + if (desc->bDescriptorType == USB_DT_IRDA) + return desc; + + IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n"); + + /* Check if the class descriptor is interleaved with standard descriptors */ + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr); + if (ret) { + kfree(desc); + return NULL; + } + *desc = *ptr; +#if 0 + irda_usb_dump_class_desc(desc); +#endif + return desc; +} + +/* + * Function usb_irda_dump_class_desc(desc) + * + * Prints out the contents of the IrDA class descriptor + * + */ +static void irda_usb_dump_class_desc(struct irda_class_desc *desc) +{ + printk("bLength=%x\n", desc->bLength); + printk("bDescriptorType=%x\n", desc->bDescriptorType); + printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision); + printk("bmDataSize=%x\n", desc->bmDataSize); + printk("bmWindowSize=%x\n", desc->bmWindowSize); + printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); + printk("wBaudRate=%x\n", desc->wBaudRate); + printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); + printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); + printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList); +} + +static void irda_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Oups ! We are not there any more */ + self->present = 0; + + /* Hum... Check if networking is still active */ + if (self->netopen) { + /* Accept no more transmissions */ + /*netif_device_detach(self->netdev);*/ + netif_stop_queue(self->netdev); + /* Stop all the receive URBs */ + for (i = 0; i < IU_MAX_RX_URBS; i++) + usb_unlink_urb(&(self->rx_urb[i])); + /* Cancel Tx and speed URB */ + usb_unlink_urb(&(self->tx_urb)); + usb_unlink_urb(&(self->speed_urb)); + + IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n"); + /* better not do anything just yet, usb_irda_cleanup() + * will do whats needed */ + return; + } + + /* Cleanup the device stuff */ + irda_usb_close(self); + /* No longer attached to USB bus */ + self->usbdev = NULL; + IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n"); +} + +static struct usb_driver irda_driver = { + name: "irda-usb", + probe: irda_usb_probe, + disconnect: irda_usb_disconnect, + id_table: dongles, +}; + +static void irda_usb_init_qos(struct irda_usb_cb *self) +{ + struct irda_class_desc *desc; + + desc = self->irda_desc; + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + self->qos.baud_rate.bits = desc->wBaudRate; + self->qos.min_turn_time.bits = desc->bmMinTurnaroundTime; + self->qos.additional_bofs.bits = desc->bmAdditionalBOFs; + self->qos.window_size.bits = desc->bmWindowSize; + self->qos.data_size.bits = desc->bmDataSize; + + IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits); + + /* Don't always trust what the dongle tell us */ + if (self->capability & IUC_SIR_ONLY) + self->qos.baud_rate.bits &= 0xff; + if (self->capability & IUC_SMALL_PKT) + self->qos.data_size.bits = 0x07; + if (self->capability & IUC_NO_WINDOW) + self->qos.window_size.bits = 0x01; + if (self->capability & IUC_MAX_WINDOW) + self->qos.window_size.bits = 0x7f; + if (self->capability & IUC_MAX_XBOFS) + self->qos.additional_bofs.bits = 0x01; + +#if 1 + /* Module parameter can override the rx window size */ + if (qos_mtt_bits) + self->qos.min_turn_time.bits = qos_mtt_bits; +#endif + /* + * Note : most of those values apply only for the receive path, + * the transmit path will be set differently - Jean II + */ + irda_qos_bits_to_value(&self->qos); + + self->flags |= IFF_SIR; + if (self->qos.baud_rate.value > 115200) + self->flags |= IFF_MIR; + if (self->qos.baud_rate.value > 1152000) + self->flags |= IFF_FIR; + if (self->qos.baud_rate.value > 4000000) + self->flags |= IFF_VFIR; +} + +static int irda_usb_open(struct irda_usb_cb *self) +{ + struct net_device *netdev; + int err; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + spin_lock_init(&self->lock); + + irda_usb_init_qos(self); + + self->tx_list = hashbin_new(HB_GLOBAL); + + /* Create a network device for us */ + if (!(netdev = dev_alloc("irda%d", &err))) { + ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + return -1; + } + self->netdev = netdev; + netdev->priv = (void *) self; + + /* Override the network functions we need to use */ + netdev->init = irda_usb_net_init; + netdev->hard_start_xmit = irda_usb_hard_xmit; + netdev->tx_timeout = irda_usb_net_timeout; + netdev->watchdog_timeo = 110*HZ/1000; /* 110 ms > USB timeout */ + netdev->open = irda_usb_net_open; + netdev->stop = irda_usb_net_close; + netdev->get_stats = irda_usb_net_get_stats; + netdev->do_ioctl = irda_usb_net_ioctl; + + rtnl_lock(); + err = register_netdevice(netdev); + rtnl_unlock(); + if (err) { + ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + return -1; + } + MESSAGE("IrDA: Registered device %s\n", netdev->name); + + return 0; +} + +static int irda_usb_close(struct irda_usb_cb *self) +{ + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(self != NULL, return -1;); + + /* Remove netdevice */ + if (self->netdev) { + rtnl_lock(); + unregister_netdevice(self->netdev); + self->netdev = NULL; + rtnl_unlock(); + } + hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any); + + return 0; +} + +/* + * Function irda_usb_build_header(self, skb, header) + * + * Builds USB-IrDA outbound header + * + * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2 + * that the setting of the link speed and xbof number in this outbound header + * should be applied *AFTER* the frame has been sent. + * Unfortunately, some devices are not compliant with that... It seems that + * reading the spec is far too difficult... + * Jean II + */ +static void irda_usb_build_header(struct irda_usb_cb *self, u8 *header, + int force) +{ + /* Set the negotiated link speed */ + if (self->new_speed != -1) { + /* Hum... Ugly hack :-( + * Some device are not compliant with the spec and change + * parameters *before* sending the frame. - Jean II + */ + if ((self->capability & IUC_SPEED_BUG) && + (!force) && (self->speed != -1)) + { + /* No speed and xbofs change here + * (we'll do it later in the write callback) */ + IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n"); + *header = 0; + return; + } + + IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed); + self->speed = self->new_speed; + self->new_speed = -1; + + switch (self->speed) { + case 2400: + *header = SPEED_2400; + break; + default: + case 9600: + *header = SPEED_9600; + break; + case 19200: + *header = SPEED_19200; + break; + case 38400: + *header = SPEED_38400; + break; + case 57600: + *header = SPEED_57600; + break; + case 115200: + *header = SPEED_115200; + break; + case 576000: + *header = SPEED_576000; + break; + case 1152000: + *header = SPEED_1152000; + break; + case 4000000: + *header = SPEED_4000000; + self->new_xbofs = 0; + break; + } + } else + /* No change */ + *header = 0; + + /* Set the negotiated additional XBOFS */ + if (self->new_xbofs != -1) { + IRDA_DEBUG(0, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs); + self->xbofs = self->new_xbofs; + self->new_xbofs = -1; + + switch (self->xbofs) { + case 48: + *header |= 0x10; + break; + case 28: + case 24: /* USB spec 1.0 says 24 */ + *header |= 0x20; + break; + default: + case 12: + *header |= 0x30; + break; + case 5: /* Bug in IrLAP spec? (should be 6) */ + case 6: + *header |= 0x40; + break; + case 3: + *header |= 0x50; + break; + case 2: + *header |= 0x60; + break; + case 1: + *header |= 0x70; + break; + case 0: + *header |= 0x80; + break; + } + } +} + +static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) +{ + struct sk_buff *skb; + unsigned long flags; + purb_t purb; + int ret; + + IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n", + self->new_speed, self->new_xbofs); + + purb = &self->speed_urb; + if (purb->status != USB_ST_NOERROR) { + WARNING(__FUNCTION__ "(), URB still in use!\n"); + return; + } + spin_lock_irqsave(&self->lock, flags); + + /* Allocate the fake frame */ + skb = dev_alloc_skb(IRDA_USB_SPEED_MTU); + if (!skb) + return; + ((struct irda_skb_cb *)skb->cb)->context = self; + + /* Set the new speed and xbofs in this fake frame */ + irda_usb_build_header(self, skb_put(skb, USB_IRDA_HEADER), 1); + + /* Submit the 0 length IrDA frame to trigger new speed settings */ + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + skb->data, IRDA_USB_MAX_MTU, + write_bulk_callback, skb); + purb->transfer_buffer_length = skb->len; + purb->transfer_flags |= USB_QUEUE_BULK; + purb->timeout = MSECS_TO_JIFFIES(100); + + if ((ret = usb_submit_urb(purb))) { + IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n"); + } + spin_unlock_irqrestore(&self->lock, flags); +} + +static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct irda_usb_cb *self = netdev->priv; + purb_t purb = &self->tx_urb; + unsigned long flags; + s32 speed; + s16 xbofs; + int mtt; + + /* Check if the device is still there */ + if ((!self) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n"); + return 1; /* Failed */ + } + + netif_stop_queue(netdev); + + /* Check if we need to change the number of xbofs */ + xbofs = irda_get_next_xbofs(skb); + if ((xbofs != self->xbofs) && (xbofs != -1)) { + self->new_xbofs = xbofs; + } + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->speed) && (speed != -1)) { + /* Set the desired speed */ + self->new_speed = speed; + + /* Check for empty frame */ + if (!skb->len) { + /* IrLAP send us an empty frame to make us change the + * speed. Changing speed with the USB adapter is in + * fact sending an empty frame to the adapter, so we + * could just let the present function do its job. + * However, we would wait for min turn time, + * do an extra memcpy and increment packet counters... + * Jean II */ + irda_usb_change_speed_xbofs(self); + netdev->trans_start = jiffies; + dev_kfree_skb(skb); + /* Will netif_wake_queue() in callback */ + return 0; + } + } + + if (purb->status != USB_ST_NOERROR) { + WARNING(__FUNCTION__ "(), URB still in use!\n"); + dev_kfree_skb(skb); + return 0; + } + + /* Make room for IrDA-USB header */ + if (skb_cow(skb, USB_IRDA_HEADER)) { + dev_kfree_skb(skb); + return 0; + } + + spin_lock_irqsave(&self->lock, flags); + + /* Change setting for next frame */ + irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0); + + /* FIXME: Make macro out of this one */ + ((struct irda_skb_cb *)skb->cb)->context = self; + + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + skb->data, IRDA_USB_MAX_MTU, + write_bulk_callback, skb); + purb->transfer_buffer_length = skb->len; + purb->transfer_flags |= USB_QUEUE_BULK; + purb->timeout = MSECS_TO_JIFFIES(100); + + /* Generate min turn time */ + mtt = irda_get_mtt(skb); + if (mtt) { + int diff; + get_fast_time(&self->now); + diff = self->now.tv_usec - self->stamp.tv_usec; + if (diff < 0) + diff += 1000000; + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) { + mtt -= diff; + if (mtt > 1000) { + /* + * FIXME: can we do better than this? Maybe call + * a function which sends a frame to a non + * existing device, or change the speed to the + * current one a number of times just to burn + * time a better way. + */ + mdelay(mtt/1000); + irda_usb_write_bulk(self, purb); + goto out; + } else + udelay(mtt); + } + } + irda_usb_write_bulk(self, purb); +out: + spin_unlock_irqrestore(&self->lock, flags); + + return 0; +} + +static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb) +{ + int len = purb->transfer_buffer_length; + int res; + + if ((res = usb_submit_urb(purb))) { + IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n"); + self->stats.tx_errors++; + netif_start_queue(self->netdev); + + return; + } + self->stats.tx_packets++; + self->stats.tx_bytes += len; + self->netdev->trans_start = jiffies; + + /* Send empty frame if size if a multiple of the USB max packet size */ + ASSERT(self->bulk_out_mtu == 64, return;); + if ((len % self->bulk_out_mtu) == 0) { + /* Borrow speed urb */ + purb = &self->speed_urb; + FILL_BULK_URB(purb, self->usbdev, + usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), + self, /* Anything not on the stack will do */ + IRDA_USB_MAX_MTU, NULL, NULL); + purb->transfer_buffer_length = 0; + purb->transfer_flags |= USB_QUEUE_BULK; + res = usb_submit_urb(purb); + } +} + +/* + * Note : this function will be called with both tx_urb and speed_urb... + */ +static void write_bulk_callback(purb_t purb) +{ + struct sk_buff *skb = purb->context; + struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; + + /* We should always have a context */ + if (self == NULL) { + IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n"); + return; + } + + /* urb is now available */ + purb->status = USB_ST_NOERROR; + + dev_kfree_skb_any(skb); + purb->context = NULL; + + /* Check for timeout and other USB nasties */ + if (purb->status != USB_ST_NOERROR) { + /* I get a lot of -ECONNABORTED = -103 here - Jean II */ + WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", + purb->status, purb->transfer_flags); + /* Don't do anything here, that might confuse the USB layer, + * and we could go in recursion and blow the kernel stack... + * Instead, we will wait for irda_usb_net_timeout(), the + * network layer watchdog, to fix the situation. + * Jean II */ + /* A reset of the dongle might be welcomed here - Jean II */ + return; + } + + + /* URB is now available */ + purb->status = USB_ST_NOERROR; + + /* If the network is closed, stop everything */ + if ((!self->netopen) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n"); + return; + } + + /* If we need to change the speed or xbofs, do it now */ + if ((self->new_speed != -1) || (self->new_xbofs != -1)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n"); + irda_usb_change_speed_xbofs(self); + } else { + /* Otherwise, allow the stack to send more packets */ + netif_wake_queue(self->netdev); + } +} + +static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb) +{ + struct irda_skb_cb *cb; + int ret; + + IRDA_DEBUG(2, __FUNCTION__ "()\n"); + + /* Check that we have an urb */ + if (!purb) { + IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n"); + return; + } + + /* Allocate new skb if it has not been recycled */ + if (!skb) { + skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1); + if (!skb) { + /* If this ever happen, we are in deep s***. + * Basically, the Rx path will stop... */ + IRDA_DEBUG(0, __FUNCTION__ "(), Failed to allocate Rx skb\n"); + return; + } + } else { + /* Reset recycled skb */ + skb->data = skb->tail = skb->head; + skb->len = 0; + } + /* Make sure IP header get aligned (IrDA header is 5 bytes ) */ + skb_reserve(skb, 1); + + /* Save ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + cb->context = self; + + /* Reinitialize URB */ + FILL_BULK_URB(purb, self->usbdev, + usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), + skb->data, skb->truesize, + irda_usb_receive, skb); + purb->transfer_flags |= USB_QUEUE_BULK; + purb->status = USB_ST_NOERROR; + purb->next = NULL; /* Make sure we don't auto resubmit */ + + ret = usb_submit_urb(purb); + if (ret) { + /* If this ever happen, we are in deep s***. + * Basically, the Rx path will stop... */ + IRDA_DEBUG(0, __FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); + } +} + +/* + * Function irda_usb_receive(purb) + * + * Called by the USB subsystem when a frame has been received + * + */ +static void irda_usb_receive(purb_t purb) +{ + struct sk_buff *skb = (struct sk_buff *) purb->context; + struct irda_usb_cb *self; + struct irda_skb_cb *cb; + struct sk_buff *new; + + /* Find ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + ASSERT(cb != NULL, return;); + self = (struct irda_usb_cb *) cb->context; + ASSERT(self != NULL, return;); + + /* If the network is closed or the device gone, stop everything */ + if ((!self->netopen) || (!self->present)) { + IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n"); + /* Don't re-submit the URB : will stall the Rx path */ + return; + } + + /* Check the status */ + if (purb->status != USB_ST_NOERROR) { + switch (purb->status) { + case USB_ST_CRC: /* -EILSEQ */ + self->stats.rx_errors++; + self->stats.rx_crc_errors++; + break; + case -ECONNRESET: + WARNING(__FUNCTION__ "(), Connection Reset !!!\n"); + /* uhci_cleanup_unlink() is going to kill the Rx + * URB just after we return. No problem, at this + * point the URB will be idle ;-) - Jean II */ + break; + default: + WARNING(__FUNCTION__ "(), RX status %d\n", purb->status); + break; + } + goto done; + } + + /* Check for empty frames */ + if (purb->actual_length <= USB_IRDA_HEADER) { + WARNING(__FUNCTION__ "(), empty frame!\n"); + goto done; + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + get_fast_time(&self->stamp); + + /* Fix skb, and remove USB-IrDA header */ + skb_put(skb, purb->actual_length); + skb_pull(skb, USB_IRDA_HEADER); + + /* Don't waste a lot of memory on small IrDA frames */ + if (skb->len < RX_COPY_THRESHOLD) { + new = dev_alloc_skb(skb->len+1); + if (!new) { + self->stats.rx_dropped++; + goto done; + } + + /* Make sure IP header get aligned (IrDA header is 5 bytes) */ + skb_reserve(new, 1); + + /* Copy packet, so we can recycle the original */ + memcpy(skb_put(new, skb->len), skb->data, skb->len); + /* We will cleanup the skb in irda_usb_submit */ + } else { + /* Deliver the original skb */ + new = skb; + skb = NULL; + } + + self->stats.rx_bytes += new->len; + self->stats.rx_packets++; + + /* Ask the networking layer to queue the packet for the IrDA stack */ + new->dev = self->netdev; + new->mac.raw = new->data; + new->protocol = htons(ETH_P_IRDA); + netif_rx(new); +done: + /* Recycle Rx URB (and possible the skb as well) */ + irda_usb_submit(self, skb, self->rx_idle_urb); + + /* Recycle Rx URB : Now, the idle URB is the present one */ + self->rx_idle_urb = purb; + purb->context = NULL; + /* Prevent the USB layer playing games with our URBs */ + purb->status = -ENOENT; +} + +static int irda_usb_net_init(struct net_device *dev) +{ + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Set up to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + return 0; +} + +/* + * Function irda_usb_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + * + * Note : don't mess with self->netopen - Jean II + */ +static int irda_usb_net_open(struct net_device *netdev) +{ + struct irda_usb_cb *self; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(netdev != NULL, return -1;); + self = (struct irda_usb_cb *) netdev->priv; + ASSERT(self != NULL, return -1;); + + /* Can only open the device if it's there */ + if(!self->present) { + WARNING(__FUNCTION__ "(), device not present!\n"); + return -1; + } + + /* Initialise default speed and xbofs value + * (IrLAP will change that soon) */ + self->speed = -1; + self->xbofs = -1; + self->new_speed = -1; + self->new_xbofs = -1; + + /* To do *before* submitting Rx urbs and starting net Tx queue + * Jean II */ + self->netopen = 1; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + * Note : will send immediately a speed change... + */ + self->irlap = irlap_open(netdev, &self->qos); + ASSERT(self->irlap != NULL, return -1;); + + /* Allow IrLAP to send data to us */ + netif_start_queue(netdev); + + /* Now that we can pass data to IrLAP, allow the USB layer + * to send us some data... */ + for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) + irda_usb_submit(self, NULL, &(self->rx_urb[i])); + /* Note : we submit all the Rx URB except for one - Jean II */ + self->rx_idle_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]); + self->rx_idle_urb->context = NULL; + + /* Ready to play !!! */ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Function irda_usb_net_close (self) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int irda_usb_net_close(struct net_device *netdev) +{ + struct irda_usb_cb *self; + int i; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(netdev != NULL, return -1;); + self = (struct irda_usb_cb *) netdev->priv; + ASSERT(self != NULL, return -1;); + + /* Clear this flag *before* unlinking the urbs and *before* + * stopping the network Tx queue - Jean II */ + self->netopen = 0; + + /* Stop network Tx queue */ + netif_stop_queue(netdev); + + /* Deallocate all the Rx path buffers (URBs and skb) */ + for (i = 0; i < IU_MAX_RX_URBS; i++) { + purb_t purb = &(self->rx_urb[i]); + struct sk_buff *skb = (struct sk_buff *) purb->context; + /* Cancel the receive command */ + usb_unlink_urb(purb); + /* The skb is ours, free it */ + if (skb) { + dev_kfree_skb(skb); + purb->context = NULL; + } + } + /* Cancel Tx and speed URB */ + usb_unlink_urb(&self->tx_urb); + usb_unlink_urb(&self->speed_urb); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + MOD_DEC_USE_COUNT; + + return 0; +} + +static void irda_usb_net_timeout(struct net_device *netdev) +{ + struct irda_usb_cb *self = netdev->priv; + int done = 0; /* If we have made any progress */ + purb_t purb; + + IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n"); + + if (!self || !self->present) { + WARNING(__FUNCTION__ "(), device not present!\n"); + netif_stop_queue(netdev); + return; + } + WARNING("%s: Tx timed out\n", netdev->name); + + /* Check Tx URB */ + purb = &self->tx_urb; + switch (purb->status) { + case -ECONNABORTED: /* Can't find proper USB_ST_* code */ + purb->status = USB_ST_NOERROR; + netif_wake_queue(self->netdev); + done = 1; + break; + case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */ + usb_unlink_urb(purb); + done = 1; + break; + default: + break; + } + /* Check speed URB */ + purb = &self->speed_urb; + switch (purb->status) { + case -ECONNABORTED: /* Can't find proper USB_ST_* code */ + purb->status = USB_ST_NOERROR; + netif_wake_queue(self->netdev); + done = 1; + break; + case USB_ST_URB_PENDING: /* -EINPROGRESS */ + usb_unlink_urb(purb); + done = 1; + break; + default: + break; + } + /* Maybe we need a reset */ + /* if(done == 0) */ +} + +static int irda_usb_is_receiving(struct irda_usb_cb *self) +{ + return 0; /* For now */ +} + +static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct irda_usb_cb *self; + int ret = 0; + + ASSERT(dev != NULL, return -1;); + self = dev->priv; + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Check if the device is still there */ + if (!self->present) + return -EFAULT; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + /* Set the desired speed */ + self->new_speed = irq->ifr_baudrate; + irda_usb_change_speed_xbofs(self); + /* Note : will spinlock in above function */ + break; + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + irq->ifr_receiving = irda_usb_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev) +{ + struct irda_usb_cb *self = dev->priv; + return &self->stats; +} + +int __init usb_irda_init(void) +{ + if (usb_register(&irda_driver) < 0) + return -1; + + MESSAGE("USB IrDA support registered\n"); + return 0; +} +module_init(usb_irda_init); + +void __exit usb_irda_cleanup(void) +{ + struct irda_usb_cb *irda = NULL; + int i; + + /* Find zombie instances and kill them... */ + for (i = 0; i < NIRUSB; i++) { + irda = &irda_instance[i]; + /* If the Device is zombie */ + if((irda->usbdev != NULL) && (irda->present == 0)) { + IRDA_DEBUG(0, __FUNCTION__ "(), disconnect zombie now !\n"); + irda_usb_disconnect(irda->usbdev, (void *) irda); + } + } + /* Deregister the driver and remove all pending instances */ + usb_deregister(&irda_driver); +} +module_exit(usb_irda_cleanup); + +MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); +MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli and Jean Tourrilhes "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); + + + diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c --- v2.4.4/linux/drivers/net/irda/nsc-ircc.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/irda/nsc-ircc.c Tue May 1 16:05:00 2001 @@ -251,9 +251,14 @@ IRDA_DEBUG(2, __FUNCTION__ "()\n"); + MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, + info->cfg_base); + if ((nsc_ircc_setup(info)) == -1) return -1; + MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); + /* Allocate new instance of the driver */ self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL); if (self == NULL) { @@ -315,8 +320,8 @@ self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, GFP_KERNEL|GFP_DMA); if (self->tx_buff.head == NULL) { - kfree(self); kfree(self->rx_buff.head); + kfree(self); return -ENOMEM; } memset(self->tx_buff.head, 0, self->tx_buff.truesize); @@ -699,8 +704,6 @@ ERROR("%s, Wrong chip version %02x\n", driver_name, version); return -1; } - MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, - info->cfg_base); /* Switch to advanced mode */ switch_bank(iobase, BANK2); @@ -729,8 +732,6 @@ outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */ outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ - MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name); - /* Enable receive interrupts */ switch_bank(iobase, BANK0); outb(IER_RXHDL_IE, iobase+IER); @@ -1858,7 +1859,7 @@ if (request_dma(self->io.dma, dev->name)) { WARNING("%s, unable to allocate dma=%d\n", driver_name, self->io.dma); - free_irq(self->io.irq, self); + free_irq(self->io.irq, dev); return -EAGAIN; } @@ -2008,18 +2009,10 @@ static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) { - int iobase; - if (!self->io.suspended) return; - iobase = self->io.fir_base; - - /* Switch to advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_EXT_SL, iobase+ECR1); - switch_bank(iobase, BANK0); - + nsc_ircc_setup(&self->io); nsc_ircc_net_open(self->netdev); MESSAGE("%s, Waking up\n", driver_name); diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.4.4/linux/drivers/net/irda/toshoboe.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/irda/toshoboe.c Tue May 1 16:05:00 2001 @@ -81,10 +81,18 @@ #include -static char *driver_name = "toshoboe"; +#define PCI_DEVICE_ID_FIR701b 0x0d01 -static struct toshoboe_cb *dev_self[NSELFS + 1] = -{NULL, NULL, NULL, NULL, NULL}; +static struct pci_device_id toshoboe_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701b, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl); + +static const char *driver_name = "toshoboe"; + +static struct toshoboe_cb *dev_self[NSELFS + 1]; static int max_baud = 4000000; @@ -191,8 +199,8 @@ outb_p (OBOE_NTR_VAL, OBOE_NTR); outb_p (0xf0, OBOE_REG_D); outb_p (0xff, OBOE_ISR); - outb_p (0x0f, OBOE_REG_1A); - outb_p (0xff, OBOE_REG_1B); + outb_p (0x0f, OBOE_REG_1B); + outb_p (0xff, OBOE_REG_1A); physaddr = virt_to_bus (self->taskfile); @@ -608,18 +616,21 @@ /* Disable interrupts & save flags */ save_flags(flags); cli(); - switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } /* toshoboe_setbaud(self, irq->ifr_baudrate); */ /* Just change speed once - inserted by Paul Bristow */ self->new_speed = irq->ifr_baudrate; break; case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ @@ -628,9 +639,8 @@ default: ret = -EOPNOTSUPP; } - +out: restore_flags(flags); - return ret; } @@ -712,6 +722,9 @@ return -ENOMEM; } + if ((err=pci_enable_device(pci_dev))) + return err; + self = kmalloc (sizeof (struct toshoboe_cb), GFP_KERNEL); if (self == NULL) @@ -898,7 +911,7 @@ /*FIXME: can't sleep here wait one second */ while ((i--) && (self->txpending)) - mdelay (100); + udelay (100); toshoboe_stopchip (self); toshoboe_disablebm (self); @@ -978,6 +991,24 @@ } while (pci_dev); + + if (!found) do + { + pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA, + PCI_DEVICE_ID_FIR701b, pci_dev); + if (pci_dev) + { + printk (KERN_WARNING "ToshOboe: Found 701b chip at 0x%0lx irq %d\n", + pci_dev->resource[0].start, + pci_dev->irq); + + if (!toshoboe_open (pci_dev)) + found++; + } + + } + while (pci_dev); + if (found) diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.4.4/linux/drivers/net/pcmcia/Config.in Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/pcmcia/Config.in Mon May 7 19:42:14 2001 @@ -26,7 +26,6 @@ bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA - dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $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 dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile --- v2.4.4/linux/drivers/net/pcmcia/Makefile Sun Mar 25 18:24:31 2001 +++ linux/drivers/net/pcmcia/Makefile Mon May 7 19:42:14 2001 @@ -12,7 +12,7 @@ obj- := # Things that need to export symbols -export-objs := ray_cs.o hermes.o +export-objs := ray_cs.o # 16-bit client drivers obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o @@ -25,7 +25,6 @@ obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o # 16-bit wireless client drivers -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o hermes.o obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/hermes.c linux/drivers/net/pcmcia/hermes.c --- v2.4.4/linux/drivers/net/pcmcia/hermes.c Wed Apr 25 14:45:48 2001 +++ linux/drivers/net/pcmcia/hermes.c Wed Dec 31 16:00:00 1969 @@ -1,502 +0,0 @@ -/* hermes.c - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * - * This file distributed under the GPL, version 2. - */ - -static const char *version = "hermes.c: 12 Dec 2000 David Gibson "; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hermes.h" - -#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ -#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ -#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ -#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ -#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ -#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ - -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - -/* - * Debugging helpers - */ - -#undef HERMES_DEBUG -#ifdef HERMES_DEBUG - -#include - -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ - printk(#stuff);} while (0) - -#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) - -#else /* ! HERMES_DEBUG */ - -#define DEBUG(lvl, stuff...) do { } while (0) - -#endif /* ! HERMES_DEBUG */ - -/* - * Prototypes - */ - -static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); - -/* - * Internal inline functions - */ - -/* - * Internal functions - */ - -/* Issue a command to the chip. Waiting for it to complete is the caller's - problem. - - Returns -EBUSY if the command register is busy, 0 on success. - - Callable from any context. -*/ -static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) -{ - uint16_t reg; -/* unsigned long k = CMD_BUSY_TIMEOUT; */ - - /* First check that the command register is not busy */ - reg = hermes_read_regn(hw, CMD); - if (reg & HERMES_CMD_BUSY) { - return -EBUSY; - } - - hermes_write_regn(hw, PARAM2, 0); - hermes_write_regn(hw, PARAM1, 0); - hermes_write_regn(hw, PARAM0, param0); - hermes_write_regn(hw, CMD, cmd); - - return 0; -} - -/* - * Function definitions - */ - -void hermes_struct_init(hermes_t *hw, ushort io) -{ - hw->iobase = io; - hw->inten = 0x0; -} - -int hermes_reset(hermes_t *hw) -{ - uint16_t status, reg; - int err = 0; - int k; - - /* We don't want to be interrupted while resetting the chipset */ - hw->inten = 0x0; - hermes_write_regn(hw, INTEN, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - /* Because we hope we can reset the card even if it gets into - a stupid state, we actually wait to see if the command - register will unbusy itself */ - k = CMD_BUSY_TIMEOUT; - reg = hermes_read_regn(hw, CMD); - while (k && (reg & HERMES_CMD_BUSY)) { - if (reg == 0xffff) /* Special case - the card has probably been removed, - so don't wait for the timeout */ - return -ENODEV; - - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* No need to explicitly handle the timeout - hermes_issue_cmd() will - probably return -EBUSY */ - - /* We don't use hermes_docmd_wait here, because the reset wipes - the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (! hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - err = status & HERMES_STATUS_RESULT; - - out: - return err; -} - -/* Issue a command to the chip, and (busy!) wait for it to - * complete. - * - * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware - * - * Callable from any context, but locking is your problem. */ -int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) -{ - int err; - int k; - uint16_t reg; - - err = hermes_issue_cmd(hw, cmd, parm0); - if (err) { - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", - hw->iobase); - err = -ENODEV; - } else - printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", - hw->iobase); - goto out; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", - hw->iobase); - err = -ETIMEDOUT; - goto out; - } - - resp->status = hermes_read_regn(hw, STATUS); - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - err = resp->status & HERMES_STATUS_RESULT; - - out: - return err; -} - -int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) -{ - int err = 0; - hermes_response_t resp; - int k; - uint16_t reg; - - if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); - if (err) { - printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", - hw->iobase, err); - return err; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = ALLOC_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_ALLOC)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", - hw->iobase); - return -ENODEV; - } - - if (! (reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", - hw->iobase); - return -ETIMEDOUT; - } - - *fid = hermes_read_regn(hw, ALLOCFID); - hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); - - return 0; -} - -/* Set up a BAP to read a particular chunk of data from card's internal buffer. - * - * Returns: < 0 on internal failure (errno), 0 on success, >0 on error - * from firmware - * - * Callable from any context */ -static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) -{ - int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; - int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; - int k; - int l = BAP_ERROR_RETRY; - uint16_t reg; - - /* Paranoia.. */ - if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) - return -EINVAL; - - k = BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - - if (reg & HERMES_OFFSET_BUSY) - return -EBUSY; - - /* Now we actually set up the transfer */ - retry: - hermes_write_reg(hw, sreg, id); - hermes_write_reg(hw, oreg, offset); - - /* Wait for the BAP to be ready */ - k = BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - /* For some reason, seeking the BAP seems to randomly fail somewhere - (firmware bug?). We retry a few times before giving up. */ - if (reg & HERMES_OFFSET_ERR) { - if (l--) { - udelay(1); - goto retry; - } else - return -EIO; - } - - return 0; -} - -/* Read a block of data from the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, - uint16_t id, uint16_t offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len % 2) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_read_data(hw, dreg, buf, len/2); - - out: - return err; -} - -/* Write a block of data to the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, - uint16_t id, uint16_t offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len % 2) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_write_data(hw, dreg, buf, len/2); - - out: - return err; -} - -/* Read a Length-Type-Value record from the card. - * - * If length is NULL, we ignore the length read from the card, and - * read the entire buffer regardless. This is useful because some of - * the configuration records appear to have incorrect lengths in - * practice. - * - * Callable from user or bh context. */ -int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, - uint16_t *length, void *buf) -{ - int err = 0; - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - uint16_t rlength, rtype; - hermes_response_t resp; - int count; - - if (buflen % 2) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); - if (err) - goto out; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - goto out; - - rlength = hermes_read_reg(hw, dreg); - rtype = hermes_read_reg(hw, dreg); - - if (length) - *length = rlength; - - if (rtype != rid) - printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " - "not match type (0x%04x)\n", rid, rtype); - if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) - printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", hw->iobase, - HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); - - /* For now we always read the whole buffer, the - lengths in the records seem to be wrong, frequently */ - count = buflen / 2; - -#if 0 - if (length) - count = (MIN(buflen, rlength) + 1) / 2; - else { - count = buflen / 2; - if (rlength != buflen) - printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ -record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); - } -#endif - hermes_read_data(hw, dreg, buf, count); - - out: - return err; -} - -int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, - uint16_t length, const void *value) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - hermes_response_t resp; - int count; - - DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", - bap, rid, length, * ((uint16_t *)value)); - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - goto out; - - hermes_write_reg(hw, dreg, length); - hermes_write_reg(hw, dreg, rid); - - count = length - 1; - - hermes_write_data(hw, dreg, value, count); - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, - rid, &resp); - - out: - return err; -} - -EXPORT_SYMBOL(hermes_struct_init); -EXPORT_SYMBOL(hermes_reset); -EXPORT_SYMBOL(hermes_docmd_wait); -EXPORT_SYMBOL(hermes_allocate); - -EXPORT_SYMBOL(hermes_bap_pread); -EXPORT_SYMBOL(hermes_bap_pwrite); -EXPORT_SYMBOL(hermes_read_ltv); -EXPORT_SYMBOL(hermes_write_ltv); - -static int __init init_hermes(void) -{ - printk(KERN_INFO "%s\n", version); - - return 0; -} - -module_init(init_hermes); diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/hermes.h linux/drivers/net/pcmcia/hermes.h --- v2.4.4/linux/drivers/net/pcmcia/hermes.h Wed Apr 25 14:45:48 2001 +++ linux/drivers/net/pcmcia/hermes.h Wed Dec 31 16:00:00 1969 @@ -1,402 +0,0 @@ -/* hermes.h - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia - * - * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * This file distributed under the GPL, version 2. - */ - -#ifndef _HERMES_H -#define _HERMES_H - -/* Notes on locking: - * - * As a module of low level hardware access routines, there is no - * locking. Users of this module should ensure that they serialize - * access to the hermes_t structure, and to the hardware -*/ - -#include -#include - -/* - * Limits and constants - */ -#define HERMES_ALLOC_LEN_MIN (4) -#define HERMES_ALLOC_LEN_MAX (2400) -#define HERMES_LTV_LEN_MAX (34) -#define HERMES_BAP_DATALEN_MAX (4096) -#define HERMES_BAP_OFFSET_MAX (4096) -#define HERMES_PORTID_MAX (7) -#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) -#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ -#define HERMES_PDA_RECS_MAX (200) /* a guess */ -#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ -#define HERMES_SCANRESULT_MAX (35) -#define HERMES_CHINFORESULT_MAX (8) -#define HERMES_FRAME_LEN_MAX (2304) -#define HERMES_MAX_MULTICAST (16) -#define HERMES_MAGIC (0x7d1f) - -/* - * Hermes register offsets - */ -#define HERMES_CMD (0x00) -#define HERMES_PARAM0 (0x02) -#define HERMES_PARAM1 (0x04) -#define HERMES_PARAM2 (0x06) -#define HERMES_STATUS (0x08) -#define HERMES_RESP0 (0x0A) -#define HERMES_RESP1 (0x0C) -#define HERMES_RESP2 (0x0E) -#define HERMES_INFOFID (0x10) -#define HERMES_RXFID (0x20) -#define HERMES_ALLOCFID (0x22) -#define HERMES_TXCOMPLFID (0x24) -#define HERMES_SELECT0 (0x18) -#define HERMES_OFFSET0 (0x1C) -#define HERMES_DATA0 (0x36) -#define HERMES_SELECT1 (0x1A) -#define HERMES_OFFSET1 (0x1E) -#define HERMES_DATA1 (0x38) -#define HERMES_EVSTAT (0x30) -#define HERMES_INTEN (0x32) -#define HERMES_EVACK (0x34) -#define HERMES_CONTROL (0x14) -#define HERMES_SWSUPPORT0 (0x28) -#define HERMES_SWSUPPORT1 (0x2A) -#define HERMES_SWSUPPORT2 (0x2C) -#define HERMES_AUXPAGE (0x3A) -#define HERMES_AUXOFFSET (0x3C) -#define HERMES_AUXDATA (0x3E) - -/* - * CMD register bitmasks - */ -#define HERMES_CMD_BUSY (0x8000) -#define HERMES_CMD_AINFO (0x7f00) -#define HERMES_CMD_MACPORT (0x0700) -#define HERMES_CMD_RECL (0x0100) -#define HERMES_CMD_WRITE (0x0100) -#define HERMES_CMD_PROGMODE (0x0300) -#define HERMES_CMD_CMDCODE (0x003f) - -/* - * STATUS register bitmasks - */ -#define HERMES_STATUS_RESULT (0x7f00) -#define HERMES_STATUS_CMDCODE (0x003f) - -/* - * OFFSET refister bitmasks - */ -#define HERMES_OFFSET_BUSY (0x8000) -#define HERMES_OFFSET_ERR (0x4000) -#define HERMES_OFFSET_DATAOFF (0x0ffe) - -/* - * Event register bitmasks (INTEN, EVSTAT, EVACK) - */ -#define HERMES_EV_TICK (0x8000) -#define HERMES_EV_WTERR (0x4000) -#define HERMES_EV_INFDROP (0x2000) -#define HERMES_EV_INFO (0x0080) -#define HERMES_EV_DTIM (0x0020) -#define HERMES_EV_CMD (0x0010) -#define HERMES_EV_ALLOC (0x0008) -#define HERMES_EV_TXEXC (0x0004) -#define HERMES_EV_TX (0x0002) -#define HERMES_EV_RX (0x0001) - -/* - * Command codes - */ -/*--- Controller Commands --------------------------*/ -#define HERMES_CMD_INIT (0x0000) -#define HERMES_CMD_ENABLE (0x0001) -#define HERMES_CMD_DISABLE (0x0002) -#define HERMES_CMD_DIAG (0x0003) - -/*--- Buffer Mgmt Commands --------------------------*/ -#define HERMES_CMD_ALLOC (0x000A) -#define HERMES_CMD_TX (0x000B) -#define HERMES_CMD_CLRPRST (0x0012) - -/*--- Regulate Commands --------------------------*/ -#define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQ (0x0011) - -/*--- Configure Commands --------------------------*/ -#define HERMES_CMD_ACCESS (0x0021) -#define HERMES_CMD_DOWNLD (0x0022) - -/*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_MONITOR (0x0038) -#define HERMES_MONITOR_ENABLE (0x000b) -#define HERMES_MONITOR_DISABLE (0x000f) - -/* - * Configuration RIDs - */ - -#define HERMES_RID_CNF_PORTTYPE (0xfc00) -#define HERMES_RID_CNF_MACADDR (0xfc01) -#define HERMES_RID_CNF_DESIRED_SSID (0xfc02) -#define HERMES_RID_CNF_CHANNEL (0xfc03) -#define HERMES_RID_CNF_OWN_SSID (0xfc04) -#define HERMES_RID_CNF_SYSTEM_SCALE (0xfc06) -#define HERMES_RID_CNF_MAX_DATA_LEN (0xfc07) -#define HERMES_RID_CNF_PM_ENABLE (0xfc09) -#define HERMES_RID_CNF_PM_MCAST_RX (0xfc0b) -#define HERMES_RID_CNF_PM_PERIOD (0xfc0c) -#define HERMES_RID_CNF_PM_HOLDOVER (0xfc0d) -#define HERMES_RID_CNF_NICKNAME (0xfc0e) -#define HERMES_RID_CNF_WEP_ON (0xfc20) -#define HERMES_RID_CNF_MWO_ROBUST (0xfc25) -#define HERMES_RID_CNF_PRISM2_WEP_ON (0xfc28) -#define HERMES_RID_CNF_MULTICAST_LIST (0xfc80) -#define HERMES_RID_CNF_CREATEIBSS (0xfc81) -#define HERMES_RID_CNF_FRAG_THRESH (0xfc82) -#define HERMES_RID_CNF_RTS_THRESH (0xfc83) -#define HERMES_RID_CNF_TX_RATE_CTRL (0xfc84) -#define HERMES_RID_CNF_PROMISCUOUS (0xfc85) -#define HERMES_RID_CNF_KEYS (0xfcb0) -#define HERMES_RID_CNF_TX_KEY (0xfcb1) -#define HERMES_RID_CNF_TICKTIME (0xfce0) - -#define HERMES_RID_CNF_PRISM2_TX_KEY (0xfc23) -#define HERMES_RID_CNF_PRISM2_KEY0 (0xfc24) -#define HERMES_RID_CNF_PRISM2_KEY1 (0xfc25) -#define HERMES_RID_CNF_PRISM2_KEY2 (0xfc26) -#define HERMES_RID_CNF_PRISM2_KEY3 (0xfc27) -#define HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID (0xfc21) -#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE (0xfc2A) -#define HERMES_RID_CNF_SYMBOL_BASIC_RATES (0xfc8A) -#define HERMES_RID_CNF_SYMBOL_PREAMBLE (0xfc8C) - -/* - * Information RIDs - */ -#define HERMES_RID_CHANNEL_LIST (0xfd10) -#define HERMES_RID_STAIDENTITY (0xfd20) -#define HERMES_RID_CURRENT_SSID (0xfd41) -#define HERMES_RID_CURRENT_BSSID (0xfd42) -#define HERMES_RID_COMMSQUALITY (0xfd43) -#define HERMES_RID_CURRENT_TX_RATE (0xfd44) -#define HERMES_RID_SHORT_RETRY_LIMIT (0xfd48) -#define HERMES_RID_LONG_RETRY_LIMIT (0xfd49) -#define HERMES_RID_MAX_TX_LIFETIME (0xfd4A) -#define HERMES_RID_WEP_AVAIL (0xfd4f) -#define HERMES_RID_CURRENT_CHANNEL (0xfdc1) -#define HERMES_RID_DATARATES (0xfdc6) -#define HERMES_RID_SYMBOL_PRIMARY_VER (0xfd03) -#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd21) -#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) - -/* - * Frame structures and constants - */ - -typedef struct hermes_frame_desc { - /* Hermes - i.e. little-endian byte-order */ - uint16_t status; /* 0x0 */ - uint16_t res1, res2; /* 0x2, 0x4 */ - uint16_t q_info; /* 0x6 */ - uint16_t res3, res4; /* 0x8, 0xA */ - uint16_t tx_ctl; /* 0xC */ -} __attribute__ ((packed)) hermes_frame_desc_t; - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_MSGTYPE (0xE000) - -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) - -/* RFC-1042 encoded frame */ -#define HERMES_RXSTAT_1042 (0x2000) -/* Bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) -/* Wavelan-II Management Protocol frame */ -#define HERMES_RXSTAT_WMP (0x6000) - -#ifdef __KERNEL__ - -/* Basic control structure */ -typedef struct hermes { - uint iobase; - - uint16_t inten; /* Which interrupts should be enabled? */ -} hermes_t; - -typedef struct hermes_response { - uint16_t status, resp0, resp1, resp2; -} hermes_response_t; - -/* Firmware information structure */ -typedef struct hermes_identity { - uint16_t id, vendor, major, minor; -} __attribute__ ((packed)) hermes_identity_t; - -/* "ID" structure - used for ESSID and station nickname */ -typedef struct hermes_id { - uint16_t len; - uint16_t val[16]; -} __attribute__ ((packed)) hermes_id_t; - -typedef struct hermes_commsqual { - uint16_t qual, signal, noise; -} __attribute__ ((packed)) hermes_commsqual_t; - -typedef struct hermes_multicast { - uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __attribute__ ((packed)) hermes_multicast_t; - -/* Register access convenience macros */ -#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) -#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) - -#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) -#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) -#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) - -/* Function prototypes */ -void hermes_struct_init(hermes_t *hw, ushort io); -int hermes_reset(hermes_t *hw); -int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); -int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); - - -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, - uint16_t id, uint16_t offset); -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, - uint16_t id, uint16_t offset); -int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, - uint16_t *length, void *buf); -int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, - uint16_t length, const void *value); - -/* Inline functions */ - -static inline int hermes_present(hermes_t *hw) -{ - return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; -} - -static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) -{ - hw->inten |= events; - hermes_write_regn(hw, INTEN, hw->inten); -} - -static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) -{ - hw->inten = events; - hermes_write_regn(hw, INTEN, events); -} - -static inline int hermes_enable_port(hermes_t *hw, int port) -{ - hermes_response_t resp; - - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, &resp); -} - -static inline int hermes_disable_port(hermes_t *hw, int port) -{ - hermes_response_t resp; - - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, &resp); -} - -#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) -#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) - -#define HERMES_READ_RECORD(hw, bap, rid, buf) \ - (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) -#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ - (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) - -static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) -{ - uint16_t rec; - int err; - - err = HERMES_READ_RECORD(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) -{ - uint16_t rec = cpu_to_le16(word); - return HERMES_WRITE_RECORD(hw, bap, rid, &rec); -} - -static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) -{ - int err; - - err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); - if (err) - return err; - - le16_to_cpus(&buf->id); - le16_to_cpus(&buf->vendor); - le16_to_cpus(&buf->major); - le16_to_cpus(&buf->minor); - - return 0; -} - -static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) -{ - int err; - - err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); - if (err) - return err; - - le16_to_cpus(&buf->qual); - le16_to_cpus(&buf->signal); - le16_to_cpus(&buf->noise); - - return 0; -} - -#else /* ! __KERNEL__ */ - -/* These are provided for the benefit of userspace drivers and testing programs - which use ioperm() or iopl() */ - -#define hermes_read_reg(base, off) (inw((base) + (off))) -#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) - -#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) -#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) -#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) - -#endif /* ! __KERNEL__ */ - -#endif /* _HERMES_H */ diff -u --recursive --new-file v2.4.4/linux/drivers/net/pcmcia/orinoco_cs.c linux/drivers/net/pcmcia/orinoco_cs.c --- v2.4.4/linux/drivers/net/pcmcia/orinoco_cs.c Wed Apr 25 14:45:48 2001 +++ linux/drivers/net/pcmcia/orinoco_cs.c Wed Dec 31 16:00:00 1969 @@ -1,4327 +0,0 @@ -/* orinoco_cs.c 0.04 - (formerly known as dldwd_cs.c) - * - * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - * It should also be usable on various Prism II based cards such as the - * Linksys, D-Link and Farallon Skyline. It should also work on Symbol - * cards such as the 3Com AirConnect and Ericsson WLAN. - * - * Copyright (C) 2000 David Gibson, Linuxcare Australia - * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * - * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 - * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David - * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights - * Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License version 2 (the "GPL"), in which - * case the provisions of the GPL are applicable instead of the above. - * If you wish to allow the use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -/* Notes on locking: - * - * The basic principle of operation is that everything except the - * interrupt handler is serialized through a single spinlock in the - * dldwd_priv_t structure, using dldwd_lock() and - * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). - * - * The kernel's IRQ handling stuff ensures that the interrupt handler - * does not re-enter itself. The interrupt handler is written such - * that everything it does is safe without a lock: chiefly this means - * that the Rx path uses one of the Hermes chipset's BAPs while - * everything else uses the other. - * - * For the moment access to the device statistics from the interrupt - * handler is unsafe - we just put up with any resulting errors in the - * statisics. FIXME: This should probably be changed to store the - * stats in atomic types. - * - * EXCEPT that we don't want the irq handler running when we actually - * reset or shut down the card, because strange things might happen - * (probably the worst would be one packet of garbage, but you can't - * be too careful). For this we use __dldwd_stop_irqs() which will set - * a flag to disable the interrupt handler, and wait for any - * outstanding instances of the handler to complete. THIS WILL LOSE - * INTERRUPTS! so it shouldn't be used except for resets, when we - * don't care about that.*/ - -/* - * Tentative changelog... - * - * v0.01 -> v0.02 - 21/3/2001 - Jean II - * o Allow to use regular ethX device name instead of dldwdX - * o Warning on IBSS with ESSID=any for firmware 6.06 - * o Put proper range.throughput values (optimistic) - * o IWSPY support (IOCTL and stat gather in Rx path) - * o Allow setting frequency in Ad-Hoc mode - * o Disable WEP setting if !has_wep to work on old firmware - * o Fix txpower range - * o Start adding support for Samsung/Compaq firmware - * - * v0.02 -> v0.03 - 23/3/2001 - Jean II - * o Start adding Symbol support - need to check all that - * o Fix Prism2/Symbol WEP to accept 128 bits keys - * o Add Symbol WEP (add authentication type) - * o Add Prism2/Symbol rate - * o Add PM timeout (holdover duration) - * o Enable "iwconfig eth0 key off" and friends (toggle flags) - * o Enable "iwconfig eth0 power unicast/all" (toggle flags) - * o Try with an intel card. It report firmware 1.01, behave like - * an antiquated firmware, however on windows it says 2.00. Yuck ! - * o Workaround firmware bug in allocate buffer (Intel 1.01) - * o Finish external renaming to orinoco... - * o Testing with various Wavelan firmwares - * - * v0.03 -> v0.04 - 30/3/2001 - Jean II - * o Update to Wireless 11 -> add retry limit/lifetime support - * o Tested with a D-Link DWL 650 card, fill in firmware support - * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) - * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( - * It work on D-Link *only* after a tcpdump. Weird... - * And still doesn't work on Intel card. Grrrr... - * o Update the mode after a setport3 - * o Add preamble setting for Symbol cards (not yet enabled) - * o Don't complain as much about Symbol cards... - * - * v0.04 -> v0.04b - 22/4/2001 - David Gibson - * o Removed the 'eth' parameter - always use ethXX as the - * interface name instead of dldwdXX. The other was racy - * anyway. - * o Clean up RID definitions in hermes.h, other cleanups - * - * v0.04b -> v0.04c - 24/4/2001 - Jean II - * o Tim Hurley reported a D-Link card - * with vendor 02 and firmware 0.08. Added in the capabilities... - * o Tested Lucent firmware 7.28, everything works... - * - * TODO - Jean II - * o inline functions (lot's of candidate, need to reorder code) - * o Separate Pcmcia specific code to help Airport/Mini PCI driver - * o Test PrismII/Symbol cards & firmware versions - */ - -#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 "hermes.h" - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -static char *version = "orinoco_cs.c 0.04 (David Gibson )"; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0) -#else -#define DEBUG(n, args...) do { } while (0) -#define DEBUGMORE(n, args...) do { } while (0) -#endif - -#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); -#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); - -#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) - -#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) - - -#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) -#error "orinoco_cs requires Wireless extensions v10 or later." -#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ -#define WIRELESS_SPY // enable iwspy support - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* The old way: bit map of interrupts to choose from */ -/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ -static uint irq_mask = 0xdeb8; -/* Newer, simpler way of listing specific interrupts */ -static int irq_list[4] = { -1 }; -/* Do a Pcmcia soft reset (may help some cards) */ -static int reset_cor = 0; - -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(reset_cor, "i"); - -/*====================================================================*/ - -#define DLDWD_MIN_MTU 256 -#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) - -#define LTV_BUF_SIZE 128 -#define USER_BAP 0 -#define IRQ_BAP 1 -#define DLDWD_MACPORT 0 -#define IRQ_LOOP_MAX 10 -#define TX_NICBUF_SIZE 2048 -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Intel firmware */ -#define MAX_KEYS 4 -#define MAX_KEY_SIZE 14 -#define LARGE_KEY_SIZE 13 -#define SMALL_KEY_SIZE 5 -#define MAX_FRAME_SIZE 2304 - -const long channel_frequency[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; - -#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) - -/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. - It gives the rate in halfMb/s, negative indicates auto mode */ -const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; - -#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) -typedef struct dldwd_key { - uint16_t len; - char data[MAX_KEY_SIZE]; -} __attribute__ ((packed)) dldwd_key_t; - -typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; - -typedef struct dldwd_priv { - dev_link_t link; - dev_node_t node; - int instance; - - spinlock_t lock; - long state; -#define DLDWD_STATE_INIRQ 0 -#define DLDWD_STATE_DOIRQ 1 - - /* Net device stuff */ - struct net_device ndev; - struct net_device_stats stats; - struct iw_statistics wstats; - - - /* Hardware control variables */ - hermes_t hw; - uint16_t txfid; - - /* Capabilities of the hardware/firmware */ - hermes_identity_t firmware_info; - int firmware_type; -#define FIRMWARE_TYPE_LUCENT 1 -#define FIRMWARE_TYPE_PRISM2 2 -#define FIRMWARE_TYPE_SYMBOL 3 - int has_ibss, has_port3, prefer_port3, has_ibss_any; - int has_wep, has_big_wep; - int has_mwo; - int has_pm; - int has_retry; - int has_preamble; - int broken_reset, broken_allocate; - uint16_t channel_mask; - - /* Current configuration */ - uint32_t iw_mode; - int port_type, allow_ibss; - uint16_t wep_on, wep_restrict, tx_key; - dldwd_keys_t keys; - char nick[IW_ESSID_MAX_SIZE+1]; - char desired_essid[IW_ESSID_MAX_SIZE+1]; - uint16_t frag_thresh, mwo_robust; - uint16_t channel; - uint16_t ap_density, rts_thresh; - uint16_t tx_rate_ctrl; - uint16_t pm_on, pm_mcast, pm_period, pm_timeout; - uint16_t retry_short, retry_long, retry_time; - uint16_t preamble; - - int promiscuous, allmulti, mc_count; - -#ifdef WIRELESS_SPY - int spy_number; - u_char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; -#endif - - /* /proc based debugging stuff */ - struct proc_dir_entry *dir_dev; - struct proc_dir_entry *dir_regs; - struct proc_dir_entry *dir_recs; -} dldwd_priv_t; - -struct p80211_hdr { - uint16_t frame_ctl; - uint16_t duration_id; - uint8_t addr1[ETH_ALEN]; - uint8_t addr2[ETH_ALEN]; - uint8_t addr3[ETH_ALEN]; - uint16_t seq_ctl; - uint8_t addr4[ETH_ALEN]; - uint16_t data_len; -} __attribute__ ((packed)); - -/* Frame control field constants */ -#define DLDWD_FCTL_VERS 0x0002 -#define DLDWD_FCTL_FTYPE 0x000c -#define DLDWD_FCTL_STYPE 0x00f0 -#define DLDWD_FCTL_TODS 0x0100 -#define DLDWD_FCTL_FROMDS 0x0200 -#define DLDWD_FCTL_MOREFRAGS 0x0400 -#define DLDWD_FCTL_RETRY 0x0800 -#define DLDWD_FCTL_PM 0x1000 -#define DLDWD_FCTL_MOREDATA 0x2000 -#define DLDWD_FCTL_WEP 0x4000 -#define DLDWD_FCTL_ORDER 0x8000 - -#define DLDWD_FTYPE_MGMT 0x0000 -#define DLDWD_FTYPE_CTL 0x0004 -#define DLDWD_FTYPE_DATA 0x0008 - -struct p8022_hdr { - uint8_t dsap; - uint8_t ssap; - uint8_t ctrl; - uint8_t oui[3]; -} __attribute__ ((packed)); - -struct dldwd_frame_hdr { - hermes_frame_desc_t desc; - struct p80211_hdr p80211; - struct ethhdr p8023; - struct p8022_hdr p8022; - uint16_t ethertype; -} __attribute__ ((packed)); - -#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ - sizeof(struct p80211_hdr)) -#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) - -/* - * Function prototypes - */ - -/* PCMCIA gumpf */ - -static void dldwd_config(dev_link_t * link); -static void dldwd_release(u_long arg); -static int dldwd_event(event_t event, int priority, - event_callback_args_t * args); - -static dev_link_t *dldwd_attach(void); -static void dldwd_detach(dev_link_t *); - -/* Hardware control routines */ - -static int __dldwd_hw_reset(dldwd_priv_t *priv); -static void dldwd_shutdown(dldwd_priv_t *dev); -static int dldwd_reset(dldwd_priv_t *dev); -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); -static long dldwd_hw_get_freq(dldwd_priv_t *priv); -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - int32_t *rates, int max); - -/* Interrupt handling routines */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); - -/* struct net_device methods */ -static int dldwd_init(struct net_device *dev); -static int dldwd_open(struct net_device *dev); -static int dldwd_stop(struct net_device *dev); - -static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); -static void dldwd_tx_timeout(struct net_device *dev); - -static struct net_device_stats *dldwd_get_stats(struct net_device *dev); -static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); -static void dldwd_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct dldwd_frame_hdr *hdr); - -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); -static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - -static int dldwd_change_mtu(struct net_device *dev, int new_mtu); -static void __dldwd_set_multicast_list(struct net_device *dev); - -/* /proc debugging stuff */ -static int dldwd_proc_init(void); -static void dldwd_proc_cleanup(void); -static int dldwd_proc_dev_init(dldwd_priv_t *dev); -static void dldwd_proc_dev_cleanup(dldwd_priv_t *dev); - -/* - * Inline functions - */ -static inline void -dldwd_lock(dldwd_priv_t *priv) -{ - spin_lock_bh(&priv->lock); -} - -static inline void -dldwd_unlock(dldwd_priv_t *priv) -{ - spin_unlock_bh(&priv->lock); -} - -static inline int -dldwd_irqs_allowed(dldwd_priv_t *priv) -{ - return test_bit(DLDWD_STATE_DOIRQ, &priv->state); -} - -static inline void -__dldwd_stop_irqs(dldwd_priv_t *priv) -{ - hermes_t *hw = &priv->hw; - - hermes_set_irqmask(hw, 0); - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); - while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) - ; -} - -static inline void -__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) -{ - hermes_t *hw = &priv->hw; - - TRACE_ENTER(priv->ndev.name); - - __cli(); - set_bit(DLDWD_STATE_DOIRQ, &priv->state); - hermes_set_irqmask(hw, irqmask); - __sti(); - - TRACE_EXIT(priv->ndev.name); -} - -static inline void -set_port_type(dldwd_priv_t *priv) -{ - switch (priv->iw_mode) { - case IW_MODE_INFRA: - priv->port_type = 1; - priv->allow_ibss = 0; - break; - case IW_MODE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->allow_ibss = 0; - } else { - priv->port_type = 1; - priv->allow_ibss = 1; - } - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev.name); - } -} - -static inline void -dldwd_set_multicast_list(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - - dldwd_lock(priv); - __dldwd_set_multicast_list(dev); - dldwd_unlock(priv); -} - -/* - * Hardware control routines - */ - -static int -__dldwd_hw_reset(dldwd_priv_t *priv) -{ - hermes_t *hw = &priv->hw; - int err; - - if (! priv->broken_reset) - return hermes_reset(hw); - else { - hw->inten = 0; - hermes_write_regn(hw, INTEN, 0); - err = hermes_disable_port(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - return err; - } -} - -static void -dldwd_shutdown(dldwd_priv_t *priv) -{ -/* hermes_t *hw = &priv->hw; */ - int err = 0; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - __dldwd_stop_irqs(priv); - - err = __dldwd_hw_reset(priv); - if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ - printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); - - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); -} - -static int -dldwd_reset(dldwd_priv_t *priv) -{ - struct net_device *dev = &priv->ndev; - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t idbuf; - int frame_size; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - - __dldwd_stop_irqs(priv); - - err = __dldwd_hw_reset(priv); - if (err) - goto out; - - frame_size = TX_NICBUF_SIZE; - /* This stupid bug is present in Intel firmware 1.10, and - * may be fixed in later firmwares - Jean II */ - if(priv->broken_allocate) - frame_size = TX_NICBUF_SIZE_BUG; - err = hermes_allocate(hw, frame_size, &priv->txfid); - if (err) - goto out; - - /* Now set up all the parameters on the card */ - - /* Set up the link mode */ - - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); - if (err) - goto out; - if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, - priv->allow_ibss); - if (err) - goto out; - if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) - && (!priv->has_ibss_any)) { - printk(KERN_WARNING "%s: This firmware requires an \ -ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - } - } - - /* Set up encryption */ - if (priv->has_wep) { - err = __dldwd_hw_setup_wep(priv); - if (err) - goto out; - } - - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? - HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) - goto out; - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), - &idbuf); - if (err) - goto out; - - /* Set the channel/frequency */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); - if (err) - goto out; - - /* Set AP density */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); - if (err) - goto out; - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); - if (err) - goto out; - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); - if (err) - goto out; - - /* Set bitrate */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, - priv->tx_rate_ctrl); - if (err) - goto out; - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, - priv->pm_on); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, - priv->pm_mcast); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, - priv->pm_period); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, - priv->pm_timeout); - if (err) - goto out; - } - - /* Set retry settings - will fail on lot's of firmwares */ - if (priv->has_retry) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, - priv->retry_short); - if (err) { - printk(KERN_WARNING "%s: Can't set retry limit!\n", dev->name); - goto out; - } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, - priv->retry_long); - if (err) - goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, - priv->retry_time); - if (err) - goto out; - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, - priv->preamble); - if (err) { - printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); - goto out; - } - } - - /* Set promiscuity / multicast*/ - priv->promiscuous = 0; - priv->allmulti = 0; - priv->mc_count = 0; - __dldwd_set_multicast_list(dev); - - err = hermes_enable_port(hw, DLDWD_MACPORT); - if (err) - goto out; - - __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | - HERMES_EV_TX | HERMES_EV_TXEXC | - HERMES_EV_WTERR | HERMES_EV_INFO | - HERMES_EV_INFDROP); - - out: - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); - - return err; -} - -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - int extra_wep_flag = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ - if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); - if (err) - return err; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); - if (err) - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); - if (err) - return err; - break; - - case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->wep_on) { - char keybuf[LARGE_KEY_SIZE+1]; - int keylen; - int i; - - /* Write all 4 keys */ - for(i = 0; i < MAX_KEYS; i++) { - keylen = priv->keys[i].len; - keybuf[keylen] = '\0'; - memcpy(keybuf, priv->keys[i].data, keylen); - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNF_PRISM2_KEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen + 1), - &keybuf); - if (err) - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, - priv->tx_key); - if (err) - return err; - - /* Authentication is where Prism2 and Symbol - * firmware differ... */ - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { - /* Symbol cards : set the authentication : - * 0 -> no encryption, 1 -> open, - * 2 -> shared key, 3 -> shared key 128bit */ - if(priv->wep_restrict) { - if(priv->keys[priv->tx_key].len > - SMALL_KEY_SIZE) - extra_wep_flag = 3; - else - extra_wep_flag = 2; - } else - extra_wep_flag = 1; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict); - if (err) - return err; - } else { - /* Prism2 card : we need to modify master - * WEP setting */ - if(priv->wep_restrict) - extra_wep_flag = 2; - else - extra_wep_flag = 0; - } - } - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag)); - if (err) - return err; - break; - - default: - if (priv->wep_on) { - printk(KERN_ERR "%s: WEP enabled, although not supported!\n", - priv->ndev.name); - return -EINVAL; - } - } - - return 0; -} - -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - - dldwd_lock(priv); - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, - ETH_ALEN, NULL, buf); - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - - TRACE_ENTER(priv->ndev.name); - - dldwd_lock(priv); - - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWN_SSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - uint16_t rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : - HERMES_RID_CNF_DESIRED_SSID; - - err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - - memset(buf, 0, sizeof(buf)); - memcpy(buf, p, len); - buf[len] = '\0'; - - fail_unlock: - dldwd_unlock(priv); - - TRACE_EXIT(priv->ndev.name); - - return err; -} - -static long dldwd_hw_get_freq(dldwd_priv_t *priv) -{ - - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t channel; - long freq = 0; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); - if (err) - goto out; - - if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - struct net_device *dev = &priv->ndev; - - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); - err = -EBUSY; - goto out; - - } - freq = channel_frequency[channel-1] * 100000; - - out: - dldwd_unlock(priv); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - int32_t *rates, int max) -{ - hermes_t *hw = &priv->hw; - hermes_id_t list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - - dldwd_lock(priv); - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), - NULL, &list); - dldwd_unlock(priv); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = MIN(num, max); - - for (i = 0; i < num; i++) { - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - } - - return 0; -} - -#ifndef PCMCIA_DEBUG -static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} -#else -static void show_rx_frame(struct dldwd_frame_hdr *frame) -{ - printk(KERN_DEBUG "RX descriptor:\n"); - printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); - printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); - printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); - printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); - printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); - printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); - printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); - - printk(KERN_DEBUG "IEEE 802.11 header:\n"); - printk(KERN_DEBUG " frame_ctl = 0x%04x\n", - frame->p80211.frame_ctl); - printk(KERN_DEBUG " duration_id = 0x%04x\n", - frame->p80211.duration_id); - printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr1[0], frame->p80211.addr1[1], - frame->p80211.addr1[2], frame->p80211.addr1[3], - frame->p80211.addr1[4], frame->p80211.addr1[5]); - printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr2[0], frame->p80211.addr2[1], - frame->p80211.addr2[2], frame->p80211.addr2[3], - frame->p80211.addr2[4], frame->p80211.addr2[5]); - printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr3[0], frame->p80211.addr3[1], - frame->p80211.addr3[2], frame->p80211.addr3[3], - frame->p80211.addr3[4], frame->p80211.addr3[5]); - printk(KERN_DEBUG " seq_ctl = 0x%04x\n", - frame->p80211.seq_ctl); - printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p80211.addr4[0], frame->p80211.addr4[1], - frame->p80211.addr4[2], frame->p80211.addr4[3], - frame->p80211.addr4[4], frame->p80211.addr4[5]); - printk(KERN_DEBUG " data_len = 0x%04x\n", - frame->p80211.data_len); - - printk(KERN_DEBUG "IEEE 802.3 header:\n"); - printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_dest[0], frame->p8023.h_dest[1], - frame->p8023.h_dest[2], frame->p8023.h_dest[3], - frame->p8023.h_dest[4], frame->p8023.h_dest[5]); - printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", - frame->p8023.h_source[0], frame->p8023.h_source[1], - frame->p8023.h_source[2], frame->p8023.h_source[3], - frame->p8023.h_source[4], frame->p8023.h_source[5]); - printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); - - printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); - printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); - printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); - printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); - printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", - frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); - printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); -} -#endif - -/* - * Interrupt handler - */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) -{ - dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; - hermes_t *hw = &priv->hw; - struct net_device *dev = &priv->ndev; - int count = IRQ_LOOP_MAX; - uint16_t evstat, events; - static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ - - if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) - BUG(); - - if (! dldwd_irqs_allowed(priv)) { - clear_bit(DLDWD_STATE_INIRQ, &priv->state); - return; - } - - DEBUG(3, "%s: dldwd_interrupt() irq %d\n", priv->ndev.name, irq); - - while (1) { - if (jiffies != old_time) - timecount = 0; - if ( (++timecount > 50) || (! count--) ) { - printk(KERN_CRIT "%s: IRQ handler is looping too \ -much! Shutting down.\n", - dev->name); - /* Perform an emergency shutdown */ - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); - hermes_set_irqmask(hw, 0); - break; - } - - evstat = hermes_read_regn(hw, EVSTAT); - DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", - count, evstat, hw->inten); - - events = evstat & hw->inten; - - if (! events) { - if (netif_queue_stopped(dev)) { - /* There seems to be a firmware bug which - sometimes causes the card to give an - interrupt with no event set, when there - sould be a Tx completed event. */ - DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", - dev->name, (int)hermes_read_regn(hw, ALLOCFID)); - events = HERMES_EV_TX | HERMES_EV_ALLOC; - } else /* Nothing's happening, we're done */ - break; - } - - /* Check the card hasn't been removed */ - if (! hermes_present(hw)) { - DEBUG(0, "dldwd_interrupt(): card removed\n"); - break; - } - - if (events & HERMES_EV_TICK) - __dldwd_ev_tick(priv, hw); - if (events & HERMES_EV_WTERR) - __dldwd_ev_wterr(priv, hw); - if (events & HERMES_EV_INFDROP) - __dldwd_ev_infdrop(priv, hw); - if (events & HERMES_EV_INFO) - __dldwd_ev_info(priv, hw); - if (events & HERMES_EV_RX) - __dldwd_ev_rx(priv, hw); - if (events & HERMES_EV_TXEXC) - __dldwd_ev_txexc(priv, hw); - if (events & HERMES_EV_TX) - __dldwd_ev_tx(priv, hw); - if (events & HERMES_EV_ALLOC) - __dldwd_ev_alloc(priv, hw); - - hermes_write_regn(hw, EVACK, events); - } - - clear_bit(DLDWD_STATE_INIRQ, &priv->state); -} - -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); -} - -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", - priv->ndev.name); -} - -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) -{ - printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); -} - -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) -{ - DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); - /* We don't actually do anything about it - we assume the MAC - controller can deal with it */ -} - -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - uint16_t rxfid, status; - int length, data_len, data_off; - char *p; - struct dldwd_frame_hdr hdr; - struct ethhdr *eh; - int err; - - rxfid = hermes_read_regn(hw, RXFID); - DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); - - /* We read in the entire frame header here. This isn't really - necessary, since we ignore most of it, but it's - conceptually simpler. We can tune this later if - necessary. */ - err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading frame header. " - "Frame dropped.\n", dev->name, err); - stats->rx_errors++; - goto drop; - } - - status = le16_to_cpu(hdr.desc.status); - - if (status & HERMES_RXSTAT_ERR) { - if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { - stats->rx_crc_errors++; - printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n", - dev->name); - show_rx_frame(&hdr); - } else if ((status & HERMES_RXSTAT_ERR) - == HERMES_RXSTAT_UNDECRYPTABLE) { - wstats->discard.code++; - printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - } else { - wstats->discard.misc++; - printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", - dev->name, status & HERMES_RXSTAT_ERR); - } - stats->rx_errors++; - goto drop; - } - - length = le16_to_cpu(hdr.p80211.data_len); - /* Yes, you heard right, that's le16. 802.2 and 802.3 are - big-endian, but 802.11 is little-endian believe it or - not. */ - /* Correct. 802.3 is big-endian byte order and little endian bit - * order, whereas 802.11 is little endian for both byte and bit - * order. That's specified in the 802.11 spec. - Jean II */ - - /* Sanity check */ - if (length > MAX_FRAME_SIZE) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - stats->rx_errors++; - goto drop; - } - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length+ETH_HLEN+2+1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - stats->rx_dropped++; - goto drop; - } - - skb_reserve(skb, 2); /* This way the IP header is aligned */ - - /* Handle decapsulation */ - switch (status & HERMES_RXSTAT_MSGTYPE) { - /* These both indicate a SNAP within 802.2 LLC within - 802.3 within 802.11 frame which we'll need to - de-encapsulate. IEEE and ISO OSI have a lot to - answer for. */ - case HERMES_RXSTAT_1042: - case HERMES_RXSTAT_TUNNEL: - data_len = length - ENCAPS_OVERHEAD; - data_off = sizeof(hdr); - - eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); - - memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); - eh->h_proto = hdr.ethertype; - - break; - - /* Otherwise, we just throw the whole thing in, and hope - the protocol layer can deal with it as 802.3 */ - default: - data_len = length; - data_off = P8023_OFFSET; - break; - } - - p = skb_put(skb, data_len); - if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), - rxfid, data_off) != 0) { - printk(KERN_WARNING "%s: Error reading packet data\n", - dev->name); - stats->rx_errors++; - goto drop; - } - - dev->last_rx = jiffies; - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - - /* Process the wireless stats if needed */ - dldwd_stat_gather(dev, skb, &hdr); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - if (skb) - dev_kfree_skb_irq(skb); - return; -} - -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - - printk(KERN_WARNING "%s: Tx error!\n", dev->name); - - netif_wake_queue(dev); - stats->tx_errors++; -} - -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) -{ - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; - - DEBUG(3, "%s: Transmit completed\n", dev->name); - - stats->tx_packets++; - netif_wake_queue(dev); -} - -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) -{ - uint16_t allocfid; - - allocfid = hermes_read_regn(hw, ALLOCFID); - DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); - - /* For some reason we don't seem to get transmit completed events properly */ - if (allocfid == priv->txfid) - __dldwd_ev_tx(priv, hw); - -/* hermes_write_regn(hw, ALLOCFID, 0); */ -} - -/* - * struct net_device methods - */ - -static int dldwd_init(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - hermes_id_t nickbuf; - uint16_t reclen; - int len; - char *vendor_str; - uint32_t firmver; - - TRACE_ENTER("dldwd"); - - dldwd_lock(priv); - - err = hermes_reset(hw); - if (err != 0) { - printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); - goto out; - } - - /* Get the firmware version */ - err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); - if (err) { - printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", - dev->name, err); - memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); - } - - firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; - DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver); - - /* Determine capabilities from the firmware version */ - - switch (priv->firmware_info.vendor) { - case 0x1: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - * ELSA, Melco, HP, IBM, Dell 1150 cards */ - vendor_str = "Lucent"; - /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ - - priv->firmware_type = FIRMWARE_TYPE_LUCENT; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; /* Still works in 7.28 */ - priv->has_ibss = (firmver >= 0x60006); - priv->has_ibss_any = (firmver >= 0x60010); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); - priv->has_retry = 0; - priv->has_preamble = 0; - /* Tested with Lucent firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case 0x2: - vendor_str = "Generic Prism II"; - /* Some D-Link cards report vendor 0x02... */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = (firmver >= 0x00007); /* FIXME */ - priv->has_wep = (firmver >= 0x00007); /* FIXME */ - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x00007); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - - /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */ - - /* Special case for Symbol cards */ - if(firmver == 0x10001) { - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - vendor_str = "Symbol"; - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - - /* FIXME : probably need to use SYMBOL_***ARY_VER - * to get proper firmware version */ - priv->firmware_type = FIRMWARE_TYPE_SYMBOL; - priv->broken_reset = 0; - priv->broken_allocate = 1; - priv->has_port3 = 1; - priv->has_ibss = 1; /* FIXME */ - priv->has_wep = 1; /* FIXME */ - priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ - priv->has_mwo = 0; - priv->has_pm = 1; /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; /* FIXME */ - /* Tested with Intel firmware : v15 => Jean II */ - } - break; - case 0x3: - vendor_str = "Samsung"; - /* To check - Should cover Samsung & Compaq */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = 0; /* FIXME: available in later firmwares */ - priv->has_wep = (firmver >= 0x20000); /* FIXME */ - priv->has_big_wep = 0; /* FIXME */ - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x20000); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - break; - case 0x6: - /* D-Link DWL 650, ... */ - vendor_str = "LinkSys/D-Link"; - /* D-Link MAC : 00:40:05:* */ - - priv->firmware_type = FIRMWARE_TYPE_PRISM2; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 1; - priv->has_ibss = (firmver >= 0x00007); /* FIXME */ - priv->has_wep = (firmver >= 0x00007); /* FIXME */ - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = (firmver >= 0x00007); /* FIXME */ - priv->has_retry = 0; - priv->has_preamble = 0; - /* Tested with D-Link firmware 0.07 => Jean II */ - /* Note : with 0.07, IBSS to a Lucent card seem flaky */ - break; - default: - vendor_str = "UNKNOWN"; - - priv->firmware_type = 0; - priv->broken_reset = 0; - priv->broken_allocate = 0; - priv->has_port3 = 0; - priv->has_ibss = 0; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_mwo = 0; - priv->has_pm = 0; - priv->has_retry = 0; - priv->has_preamble = 0; - } - - printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", - dev->name, priv->firmware_info.id, priv->firmware_info.vendor, - vendor_str, priv->firmware_info.major, priv->firmware_info.minor); - - if (priv->has_port3) - printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); - if (priv->has_ibss) - printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", - dev->name); - if (priv->has_wep) { - printk(KERN_INFO "%s: WEP supported, ", dev->name); - if (priv->has_big_wep) - printk("\"128\"-bit key.\n"); - else - printk("40-bit key.\n"); - } - - /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, - ETH_ALEN, NULL, dev->dev_addr); - if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); - goto out; - } - - printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name, dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); - - /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - printk(KERN_ERR "%s: failed to read station name!n", - dev->name); - goto out; - } - if ( nickbuf.len ) - len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); - else - len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick); - - /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); - if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); - if (err) { - printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); - goto out; - } - - /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, - &priv->mwo_robust); - else - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, - &priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); - goto out; - } - - /* Set initial bitrate control*/ - priv->tx_rate_ctrl = 3; - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, - &priv->pm_period); - if (err) { - printk(KERN_ERR "%s: failed to read power management period!\n", - dev->name); - goto out; - } - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, - &priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: failed to read power management timeout!\n", - dev->name); - goto out; - } - } - - /* Retry setup */ - if (priv->has_retry) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &priv->retry_short); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &priv->retry_long); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &priv->retry_time); - if (err) - goto out; - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); - if (err) - goto out; - } - - /* Set up the default configuration */ - priv->iw_mode = IW_MODE_INFRA; - /* By default use IEEE/IBSS ad-hoc mode if we have it */ - priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); - set_port_type(priv); - - priv->promiscuous = 0; - priv->allmulti = 0; - priv->wep_on = 0; - priv->tx_key = 0; - - printk(KERN_INFO "%s: ready\n", dev->name); - - out: - dldwd_unlock(priv); - - TRACE_EXIT("dldwd"); - - return err; -} - -static int dldwd_open(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dev_link_t *link = &priv->link; - int err = 0; - - TRACE_ENTER(dev->name); - - link->open++; - MOD_INC_USE_COUNT; - netif_device_attach(dev); - - err = dldwd_reset(priv); - if (err) - dldwd_stop(dev); - else - netif_start_queue(dev); - - TRACE_EXIT(dev->name); - - return err; -} - -static int dldwd_stop(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dev_link_t *link = &priv->link; - - TRACE_ENTER(dev->name); - - netif_stop_queue(dev); - - dldwd_shutdown(priv); - - link->open--; - - if (link->state & DEV_STALE_CONFIG) - mod_timer(&link->release, jiffies + HZ/20); - - MOD_DEC_USE_COUNT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static struct net_device_stats *dldwd_get_stats(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - - return &priv->stats; -} - -static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - hermes_t *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err = 0; - hermes_commsqual_t cq; - - dldwd_lock(priv); - - if (priv->port_type == 3) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); -#ifdef WIRELESS_SPY - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (priv->spy_number > 0) { - wstats->qual.qual = priv->spy_stat[0].qual; - wstats->qual.level = priv->spy_stat[0].level; - wstats->qual.noise = priv->spy_stat[0].noise; - wstats->qual.updated = priv->spy_stat[0].updated; - } -#endif /* WIRELESS_SPY */ - } else { - err = hermes_read_commsqual(hw, USER_BAP, &cq); - - DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, - cq.qual, cq.signal, cq.noise); - - /* Why are we using MIN/MAX ? We don't really care - * if the value goes above max, because we export the - * raw dBm values anyway. The normalisation should be done - * in user space - Jean II */ - wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); - wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; - wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; - wstats->qual.updated = 7; - } - - dldwd_unlock(priv); - - if (err) - return NULL; - - return wstats; -} - -#ifdef WIRELESS_SPY -static inline void dldwd_spy_gather(struct net_device *dev, - u_char *mac, - hermes_commsqual_t *cq) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... */ - for (i = 0; i < priv->spy_number; i++) - if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { - priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); - priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; - priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; - priv->spy_stat[i].updated = 7; - } -} -#endif /* WIRELESS_SPY */ - -static void dldwd_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct dldwd_frame_hdr *hdr) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - hermes_commsqual_t cq; - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ -#ifdef WIRELESS_EXT - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if ( -#ifdef WIRELESS_SPY - (priv->spy_number > 0) || -#endif - 0 ) - { - u_char *stats = (u_char *) &(hdr->desc.q_info); - /* This code may look strange. Everywhere we are using 16 bit - * ints except here. I've verified that these are are the - * correct values. Please check on PPC - Jean II */ - cq.signal = stats[1]; /* High order byte */ - cq.noise = stats[0]; /* Low order byte */ - cq.qual = stats[0] - stats[1]; /* Better than nothing */ - - DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, - cq.qual, cq.signal, cq.noise); - -#ifdef WIRELESS_SPY - dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); -#endif - } -#endif /* WIRELESS_EXT */ -} - -struct p8022_hdr encaps_hdr = { - 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} -}; - -static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - struct net_device_stats *stats = &priv->stats; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t txfid = priv->txfid; - char *p; - struct ethhdr *eh; - int len, data_len, data_off; - struct dldwd_frame_hdr hdr; - hermes_response_t resp; - - if (! netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return 1; - - } - - if (netif_queue_stopped(dev)) { - printk(KERN_ERR "%s: Tx while transmitter busy!\n", - dev->name); - return 1; - } - - dldwd_lock(priv); - - /* Length of the packet body */ - len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); - - eh = (struct ethhdr *)skb->data; - - /* Build the IEEE 802.11 header */ - memset(&hdr, 0, sizeof(hdr)); - memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); - memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); - hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; - - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ - data_len = len; - data_off = sizeof(hdr); - p = skb->data + ETH_HLEN; - - /* 802.11 header */ - hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); - - /* 802.3 header */ - memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); - memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); - hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); - - /* 802.2 header */ - memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); - - hdr.ethertype = eh->h_proto; - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), - txfid, 0); - if (err) { - printk(KERN_ERR - "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } else { /* IEEE 802.3 frame */ - data_len = len + ETH_HLEN; - data_off = P8023_OFFSET; - p = skb->data; - - /* 802.11 header */ - hdr.p80211.data_len = cpu_to_le16(len); - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, - txfid, 0); - if (err) { - printk(KERN_ERR - "%s: Error %d writing packet header to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - } - - /* Round up for odd length packets */ - err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", - dev->name, err); - stats->tx_errors++; - goto fail; - } - - - /* Finally, we actually initiate the send */ - err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); - if (err) { - printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); - stats->tx_errors++; - goto fail; - } - - dev->trans_start = jiffies; - stats->tx_bytes += data_off + data_len; - - netif_stop_queue(dev); - - dldwd_unlock(priv); - - dev_kfree_skb(skb); - - return 0; - fail: - - dldwd_unlock(priv); - return err; -} - -static void dldwd_tx_timeout(struct net_device *dev) -{ - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - struct net_device_stats *stats = &priv->stats; - int err = 0; - - printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); - - stats->tx_errors++; - - err = dldwd_reset(priv); - if (err) - printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", - dev->name, err); - else { - dev->trans_start = jiffies; - netif_wake_queue(dev); - } -} - -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - int ptype; - struct iw_range range; - int numrates; - int i, k; - - TRACE_ENTER(dev->name); - - err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); - if (err) - return err; - - rrq->length = sizeof(range); - - dldwd_lock(priv); - ptype = priv->port_type; - dldwd_unlock(priv); - - memset(&range, 0, sizeof(range)); - - /* Much of this shamelessly taken from wvlan_cs.c. No idea - * what it all means -dgibson */ -#if WIRELESS_EXT > 10 - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 11; -#endif /* WIRELESS_EXT > 10 */ - - range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ - - /* Set available channels/frequencies */ - range.num_channels = NUM_CHANNELS; - k = 0; - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - range.freq[k].i = i + 1; - range.freq[k].m = channel_frequency[i] * 100000; - range.freq[k].e = 1; - k++; - } - - if (k >= IW_MAX_FREQUENCIES) - break; - } - range.num_frequency = k; - - range.sensitivity = 3; - - if ((ptype == 3) && (priv->spy_number == 0)){ - /* Quality stats meaningless in ad-hoc mode */ - range.max_qual.qual = 0; - range.max_qual.level = 0; - range.max_qual.noise = 0; - } else { - range.max_qual.qual = 0x8b - 0x2f; - range.max_qual.level = 0x2f - 0x95 - 1; - range.max_qual.noise = 0x2f - 0x95 - 1; - } - - err = dldwd_hw_get_bitratelist(priv, &numrates, - range.bitrate, IW_MAX_BITRATES); - if (err) - return err; - range.num_bitrates = numrates; - - /* Set an indication of the max TCP throughput in bit/s that we can - * expect using this interface. May be use for QoS stuff... - * Jean II */ - if(numrates > 2) - range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ - else - range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ - - range.min_rts = 0; - range.max_rts = 2347; - range.min_frag = 256; - range.max_frag = 2346; - - dldwd_lock(priv); - if (priv->has_wep) { - range.max_encoding_tokens = MAX_KEYS; - - range.encoding_size[0] = SMALL_KEY_SIZE; - range.num_encoding_sizes = 1; - - if (priv->has_big_wep) { - range.encoding_size[1] = LARGE_KEY_SIZE; - range.num_encoding_sizes = 2; - } - } else { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } - dldwd_unlock(priv); - - range.min_pmp = 0; - range.max_pmp = 65535000; - range.min_pmt = 0; - range.max_pmt = 65535 * 1000; /* ??? */ - range.pmp_flags = IW_POWER_PERIOD; - range.pmt_flags = IW_POWER_TIMEOUT; - range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; - - range.num_txpower = 1; - range.txpower[0] = 15; /* 15dBm */ - range.txpower_capa = IW_TXPOW_DBM; - -#if WIRELESS_EXT > 10 - range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range.retry_flags = IW_RETRY_LIMIT; - range.r_time_flags = IW_RETRY_LIFETIME; - range.min_retry = 0; - range.max_retry = 65535; /* ??? */ - range.min_r_time = 0; - range.max_r_time = 65535 * 1000; /* ??? */ -#endif /* WIRELESS_EXT > 10 */ - - if (copy_to_user(rrq->pointer, &range, sizeof(range))) - return -EFAULT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - int setindex = priv->tx_key; - int enable = priv->wep_on; - int restricted = priv->wep_restrict; - uint16_t xlen = 0; - int err = 0; - char keybuf[MAX_KEY_SIZE]; - - if (erq->pointer) { - /* We actually have a key to set */ - - if (copy_from_user(keybuf, erq->pointer, erq->length)) - return -EFAULT; - } - - dldwd_lock(priv); - - if (erq->pointer) { - if (erq->length > MAX_KEY_SIZE) { - err = -E2BIG; - goto out; - } - - if ( (erq->length > LARGE_KEY_SIZE) - || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { - err = -EINVAL; - goto out; - } - - if ((index < 0) || (index >= MAX_KEYS)) - index = priv->tx_key; - - if (erq->length > SMALL_KEY_SIZE) { - xlen = LARGE_KEY_SIZE; - } else if (erq->length > 0) { - xlen = SMALL_KEY_SIZE; - } else - xlen = 0; - - /* Switch on WEP if off */ - if ((!enable) && (xlen > 0)) { - setindex = index; - enable = 1; - } - } else { - /* Important note : if the user do "iwconfig eth0 enc off", - * we will arrive there with an index of -1. This is valid - * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= MAX_KEYS)) { - if((index != -1) || (erq->flags == 0)) { - err = -EINVAL; - goto out; - } - } else { - /* Set the index : Check that the key is valid */ - if(priv->keys[index].len == 0) { - err = -EINVAL; - goto out; - } - setindex = index; - } - } - - if (erq->flags & IW_ENCODE_DISABLED) - enable = 0; - /* Only for Prism2 & Symbol cards (so far) - Jean II */ - if (erq->flags & IW_ENCODE_OPEN) - restricted = 0; - if (erq->flags & IW_ENCODE_RESTRICTED) - restricted = 1; - - if (erq->pointer) { - priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); - memcpy(priv->keys[index].data, keybuf, erq->length); - } - priv->tx_key = setindex; - priv->wep_on = enable; - priv->wep_restrict = restricted; - - out: - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - uint16_t xlen = 0; - char keybuf[MAX_KEY_SIZE]; - - - dldwd_lock(priv); - - if ((index < 0) || (index >= MAX_KEYS)) - index = priv->tx_key; - - erq->flags = 0; - if (! priv->wep_on) - erq->flags |= IW_ENCODE_DISABLED; - erq->flags |= index + 1; - - /* Only for symbol cards - Jean II */ - if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { - if(priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - } - - xlen = le16_to_cpu(priv->keys[index].len); - - erq->length = xlen; - - if (erq->pointer) { - memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); - } - - dldwd_unlock(priv); - - if (erq->pointer) { - if (copy_to_user(erq->pointer, keybuf, xlen)) - return -EFAULT; - } - - return 0; -} - -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - char essidbuf[IW_ESSID_MAX_SIZE+1]; - - /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it - * anyway... - Jean II */ - - memset(&essidbuf, 0, sizeof(essidbuf)); - - if (erq->flags) { - if (erq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (copy_from_user(&essidbuf, erq->pointer, erq->length)) - return -EFAULT; - - essidbuf[erq->length] = '\0'; - } - - dldwd_lock(priv); - - memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); - - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) -{ - dldwd_priv_t *priv = dev->priv; - char essidbuf[IW_ESSID_MAX_SIZE+1]; - int active; - int err = 0; - - TRACE_ENTER(dev->name); - - err = dldwd_hw_get_essid(priv, &active, essidbuf); - if (err) - return err; - - erq->flags = 1; - erq->length = strlen(essidbuf) + 1; - if (erq->pointer) - if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) - return -EFAULT; - - TRACE_EXIT(dev->name); - - return 0; -} - -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) -{ - dldwd_priv_t *priv = dev->priv; - char nickbuf[IW_ESSID_MAX_SIZE+1]; - - if (nrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - memset(nickbuf, 0, sizeof(nickbuf)); - - if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) - return -EFAULT; - - nickbuf[nrq->length] = '\0'; - - dldwd_lock(priv); - - memcpy(priv->nick, nickbuf, sizeof(priv->nick)); - - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) -{ - dldwd_priv_t *priv = dev->priv; - char nickbuf[IW_ESSID_MAX_SIZE+1]; - - dldwd_lock(priv); - memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); - dldwd_unlock(priv); - - nrq->length = strlen(nickbuf)+1; - - if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) - return -EFAULT; - - return 0; -} - -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) -{ - dldwd_priv_t *priv = dev->priv; - int chan = -1; - - /* We can only use this in Ad-Hoc demo mode to set the operating - * frequency, or in IBSS mode to set the frequency where the IBSS - * will be created - Jean II */ - if (priv->iw_mode != IW_MODE_ADHOC) - return -EOPNOTSUPP; - - if ( (frq->e == 0) && (frq->m <= 1000) ) { - /* Setting by channel number */ - chan = frq->m; - } else { - /* Setting by frequency - search the table */ - int mult = 1; - int i; - - for (i = 0; i < (6 - frq->e); i++) - mult *= 10; - - for (i = 0; i < NUM_CHANNELS; i++) - if (frq->m == (channel_frequency[i] * mult)) - chan = i+1; - } - - if ( (chan < 1) || (chan > NUM_CHANNELS) || - ! (priv->channel_mask & (1 << (chan-1)) ) ) - return -EINVAL; - - dldwd_lock(priv); - priv->channel = chan; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - uint16_t val; - int err; - - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); - dldwd_unlock(priv); - - if (err) - return err; - - srq->value = val; - srq->fixed = 0; /* auto */ - - return 0; -} - -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) -{ - dldwd_priv_t *priv = dev->priv; - int val = srq->value; - - if ((val < 1) || (val > 3)) - return -EINVAL; - - dldwd_lock(priv); - priv->ap_density = val; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int val = rrq->value; - - if (rrq->disabled) - val = 2347; - - if ( (val < 0) || (val > 2347) ) - return -EINVAL; - - dldwd_lock(priv); - priv->rts_thresh = val; - dldwd_unlock(priv); - - return 0; -} - -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - dldwd_lock(priv); - - if (priv->has_mwo) { - if (frq->disabled) - priv->mwo_robust = 0; - else { - if (frq->fixed) - printk(KERN_WARNING "%s: Fixed fragmentation not \ -supported on this firmware. Using MWO robust instead.\n", dev->name); - priv->mwo_robust = 1; - } - } else { - if (frq->disabled) - priv->frag_thresh = 2346; - else { - if ( (frq->value < 256) || (frq->value > 2346) ) - err = -EINVAL; - else - priv->frag_thresh = frq->value & ~0x1; /* must be even */ - } - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t val; - - dldwd_lock(priv); - - if (priv->has_mwo) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); - if (err) - val = 0; - - frq->value = val ? 2347 : 0; - frq->disabled = ! val; - frq->fixed = 0; - } else { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); - if (err) - val = 0; - - frq->value = val; - frq->disabled = (val >= 2346); - frq->fixed = 1; - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - int rate_ctrl = -1; - int fixed, upto; - int brate; - int i; - - dldwd_lock(priv); - - /* Normalise value */ - brate = rrq->value / 500000; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - if (! rrq->fixed) { - if (brate > 0) - brate = -brate; - else - brate = -22; - } - - for (i = 0; i < NUM_RATES; i++) - if (rate_list[i] == brate) { - rate_ctrl = i; - break; - } - - if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - switch(brate) { - case 0: - fixed = 0x0; - upto = 0x15; - break; - case 2: - fixed = 0x1; - upto = 0x1; - break; - case 4: - fixed = 0x2; - upto = 0x3; - break; - case 11: - fixed = 0x4; - upto = 0x7; - break; - case 22: - fixed = 0x8; - upto = 0x15; - break; - default: - fixed = 0x0; - upto = 0x0; - } - if (rrq->fixed) - rate_ctrl = fixed; - else - rate_ctrl = upto; - if (rate_ctrl == 0) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - } - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t val; - int brate = 0; - - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); - if (err) - goto out; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - brate = rate_list[val]; - - if (brate < 0) { - rrq->fixed = 0; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; - - if (val == 6) - brate = 11; - else - brate = 2*val; - } else - rrq->fixed = 1; - break; - case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - /* Check if auto or fixed (crude approximation) */ - if((val & 0x1) && (val > 1)) { - rrq->fixed = 0; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; - } else - rrq->fixed = 1; - - if(val >= 8) - brate = 22; - else if(val >= 4) - brate = 11; - else if(val >= 2) - brate = 4; - else - brate = 2; - break; - } - - rrq->value = brate * 500000; - rrq->disabled = 0; - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - - dldwd_lock(priv); - - if (prq->disabled) { - priv->pm_on = 0; - } else { - switch (prq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - priv->pm_mcast = 0; - priv->pm_on = 1; - break; - case IW_POWER_ALL_R: - priv->pm_mcast = 1; - priv->pm_on = 1; - break; - case IW_POWER_ON: - /* No flags : but we may have a value - Jean II */ - break; - default: - err = -EINVAL; - } - if (err) - goto out; - - if (prq->flags & IW_POWER_TIMEOUT) { - priv->pm_on = 1; - priv->pm_timeout = prq->value / 1000; - } - if (prq->flags & IW_POWER_PERIOD) { - priv->pm_on = 1; - priv->pm_period = prq->value / 1000; - } - /* It's valid to not have a value if we are just toggling - * the flags... Jean II */ - if(!priv->pm_on) { - err = -EINVAL; - goto out; - } - } - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t enable, period, timeout, mcast; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); - if (err) - goto out; - - prq->disabled = !enable; - /* Note : by default, display the period */ - if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - prq->flags = IW_POWER_TIMEOUT; - prq->value = timeout * 1000; - } else { - prq->flags = IW_POWER_PERIOD; - prq->value = period * 1000; - } - if (mcast) - prq->flags |= IW_POWER_ALL_R; - else - prq->flags |= IW_POWER_UNICAST_R; - - out: - dldwd_unlock(priv); - - return err; -} - -#if WIRELESS_EXT > 10 -static int dldwd_ioctl_setretry(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - int err = 0; - - - dldwd_lock(priv); - - if ((rrq->disabled) || (!priv->has_retry)){ - err = -EOPNOTSUPP; - goto out; - } else { - if (rrq->flags & IW_RETRY_LIMIT) { - if (rrq->flags & IW_RETRY_MAX) - priv->retry_long = rrq->value; - else if (rrq->flags & IW_RETRY_MIN) - priv->retry_short = rrq->value; - else { - /* No modifier : set both */ - priv->retry_long = rrq->value; - priv->retry_short = rrq->value; - } - } - if (rrq->flags & IW_RETRY_LIFETIME) { - priv->retry_time = rrq->value / 1000; - } - if ((rrq->flags & IW_RETRY_TYPE) == 0) { - err = -EINVAL; - goto out; - } - } - - out: - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - uint16_t short_limit, long_limit, lifetime; - - dldwd_lock(priv); - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); - if (err) - goto out; - - rrq->disabled = 0; /* Can't be disabled */ - - /* Note : by default, display the retry number */ - if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - rrq->flags = IW_RETRY_LIFETIME; - rrq->value = lifetime * 1000; /* ??? */ - } else { - /* By default, display the min number */ - if ((rrq->flags & IW_RETRY_MAX)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - rrq->value = long_limit; - } else { - rrq->flags = IW_RETRY_LIMIT; - rrq->value = short_limit; - if(short_limit != long_limit) - rrq->flags |= IW_RETRY_MIN; - } - } - - out: - dldwd_unlock(priv); - - return err; -} -#endif /* WIRELESS_EXT > 10 */ - -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) -{ - dldwd_priv_t *priv = dev->priv; - int val = *( (int *) wrq->u.name ); - int err = 0; - - dldwd_lock(priv); - switch (val) { - case 0: /* Try to do IEEE ad-hoc mode */ - if (! priv->has_ibss) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 0; - - break; - - case 1: /* Try to do Lucent proprietary ad-hoc mode */ - if (! priv->has_port3) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 1; - break; - - default: - err = -EINVAL; - } - - if (! err) - /* Actually update the mode we are using */ - set_port_type(priv); - - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) -{ - dldwd_priv_t *priv = dev->priv; - int *val = (int *)wrq->u.name; - - dldwd_lock(priv); - *val = priv->prefer_port3; - dldwd_unlock(priv); - - return 0; -} - -/* Spy is used for link quality/strength measurements in Ad-Hoc mode - * Jean II */ -static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) -{ - dldwd_priv_t *priv = dev->priv; - struct sockaddr address[IW_MAX_SPY]; - int number = srq->length; - int i; - int err = 0; - - /* Check the number of addresses */ - if (number > IW_MAX_SPY) - return -E2BIG; - - /* Get the data in the driver */ - if (srq->pointer) { - if (copy_from_user(address, srq->pointer, - sizeof(struct sockaddr) * number)) - return -EFAULT; - } - - /* Make sure nobody mess with the structure while we do */ - dldwd_lock(priv); - - /* dldwd_lock() doesn't disable interrupts, so make sure the - * interrupt rx path don't get confused while we copy */ - priv->spy_number = 0; - - if (number > 0) { - /* Extract the addresses */ - for (i = 0; i < number; i++) - memcpy(priv->spy_address[i], address[i].sa_data, - ETH_ALEN); - /* Reset stats */ - memset(priv->spy_stat, 0, - sizeof(struct iw_quality) * IW_MAX_SPY); - /* Set number of addresses */ - priv->spy_number = number; - } - - /* Time to show what we have done... */ - DEBUG(0, "%s: New spy list:\n", dev->name); - for (i = 0; i < number; i++) { - DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, i+1, - priv->spy_address[i][0], priv->spy_address[i][1], - priv->spy_address[i][2], priv->spy_address[i][3], - priv->spy_address[i][4], priv->spy_address[i][5]); - } - - /* Now, let the others play */ - dldwd_unlock(priv); - - return err; -} - -static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) -{ - dldwd_priv_t *priv = dev->priv; - struct sockaddr address[IW_MAX_SPY]; - struct iw_quality spy_stat[IW_MAX_SPY]; - int number; - int i; - - dldwd_lock(priv); - - number = priv->spy_number; - if ((number > 0) && (srq->pointer)) { - /* Create address struct */ - for (i = 0; i < number; i++) { - memcpy(address[i].sa_data, priv->spy_address[i], - ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - /* Copy stats */ - /* In theory, we should disable irqs while copying the stats - * because the rx path migh update it in the middle... - * Bah, who care ? - Jean II */ - memcpy(&spy_stat, priv->spy_stat, - sizeof(struct iw_quality) * IW_MAX_SPY); - for (i=0; i < number; i++) - priv->spy_stat[i].updated = 0; - } - - dldwd_unlock(priv); - - /* Push stuff to user space */ - srq->length = number; - if(copy_to_user(srq->pointer, address, - sizeof(struct sockaddr) * number)) - return -EFAULT; - if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), - &spy_stat, sizeof(struct iw_quality) * number)) - return -EFAULT; - - return 0; -} - -static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - dldwd_priv_t *priv = dev->priv; - struct iwreq *wrq = (struct iwreq *)rq; - int err = 0; - int changed = 0; - - TRACE_ENTER(dev->name); - - switch (cmd) { - case SIOCGIWNAME: - DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); - strcpy(wrq->u.name, "IEEE 802.11-DS"); - break; - - case SIOCGIWAP: - DEBUG(1, "%s: SIOCGIWAP\n", dev->name); - wrq->u.ap_addr.sa_family = ARPHRD_ETHER; - err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); - break; - - case SIOCGIWRANGE: - DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); - err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); - break; - - case SIOCSIWMODE: - DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); - dldwd_lock(priv); - switch (wrq->u.mode) { - case IW_MODE_ADHOC: - if (! (priv->has_ibss || priv->has_port3) ) - err = -EINVAL; - else { - priv->iw_mode = IW_MODE_ADHOC; - changed = 1; - } - break; - - case IW_MODE_INFRA: - priv->iw_mode = IW_MODE_INFRA; - changed = 1; - break; - - default: - err = -EINVAL; - break; - } - set_port_type(priv); - dldwd_unlock(priv); - break; - - case SIOCGIWMODE: - DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); - dldwd_lock(priv); - wrq->u.mode = priv->iw_mode; - dldwd_unlock(priv); - break; - - case SIOCSIWENCODE: - DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - - err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); - if (! err) - changed = 1; - break; - - case SIOCGIWENCODE: - DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); - if (! priv->has_wep) { - err = -EOPNOTSUPP; - break; - } - - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); - break; - - case SIOCSIWESSID: - DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); - err = dldwd_ioctl_setessid(dev, &wrq->u.essid); - if (! err) - changed = 1; - break; - - case SIOCGIWESSID: - DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); - err = dldwd_ioctl_getessid(dev, &wrq->u.essid); - break; - - case SIOCSIWNICKN: - DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); - err = dldwd_ioctl_setnick(dev, &wrq->u.data); - if (! err) - changed = 1; - break; - - case SIOCGIWNICKN: - DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); - err = dldwd_ioctl_getnick(dev, &wrq->u.data); - break; - - case SIOCGIWFREQ: - DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); - wrq->u.freq.m = dldwd_hw_get_freq(priv); - wrq->u.freq.e = 1; - break; - - case SIOCSIWFREQ: - DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); - err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); - if (! err) - changed = 1; - break; - - case SIOCGIWSENS: - DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); - err = dldwd_ioctl_getsens(dev, &wrq->u.sens); - break; - - case SIOCSIWSENS: - DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); - err = dldwd_ioctl_setsens(dev, &wrq->u.sens); - if (! err) - changed = 1; - break; - - case SIOCGIWRTS: - DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); - wrq->u.rts.value = priv->rts_thresh; - wrq->u.rts.disabled = (wrq->u.rts.value == 2347); - wrq->u.rts.fixed = 1; - break; - - case SIOCSIWRTS: - DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); - err = dldwd_ioctl_setrts(dev, &wrq->u.rts); - if (! err) - changed = 1; - break; - - case SIOCSIWFRAG: - DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); - err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); - if (! err) - changed = 1; - break; - - case SIOCGIWFRAG: - DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); - err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); - break; - - case SIOCSIWRATE: - DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); - err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); - if (! err) - changed = 1; - break; - - case SIOCGIWRATE: - DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); - err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); - break; - - case SIOCSIWPOWER: - DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); - err = dldwd_ioctl_setpower(dev, &wrq->u.power); - if (! err) - changed = 1; - break; - - case SIOCGIWPOWER: - DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); - err = dldwd_ioctl_getpower(dev, &wrq->u.power); - break; - - case SIOCGIWTXPOW: - DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); - /* The card only supports one tx power, so this is easy */ - wrq->u.txpower.value = 15; /* dBm */ - wrq->u.txpower.fixed = 1; - wrq->u.txpower.disabled = 0; - wrq->u.txpower.flags = IW_TXPOW_DBM; - break; - -#if WIRELESS_EXT > 10 - case SIOCSIWRETRY: - DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name); - err = dldwd_ioctl_setretry(dev, &wrq->u.retry); - if (! err) - changed = 1; - break; - - case SIOCGIWRETRY: - DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); - err = dldwd_ioctl_getretry(dev, &wrq->u.retry); - break; -#endif /* WIRELESS_EXT > 10 */ - - case SIOCSIWSPY: - DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); - - err = dldwd_ioctl_setspy(dev, &wrq->u.data); - break; - - case SIOCGIWSPY: - DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); - - err = dldwd_ioctl_getspy(dev, &wrq->u.data); - break; - - case SIOCGIWPRIV: - DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); - if (wrq->u.data.pointer) { - struct iw_priv_args privtab[] = { - { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, - { SIOCDEVPRIVATE + 0x2, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_port3" }, - { SIOCDEVPRIVATE + 0x3, 0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_port3" }, - { SIOCDEVPRIVATE + 0x4, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_preamble" }, - { SIOCDEVPRIVATE + 0x5, 0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_preamble" } - }; - - err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); - if (err) - break; - - wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); - if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) - err = -EFAULT; - } - break; - - case SIOCDEVPRIVATE + 0x0: /* force_reset */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - dldwd_reset(priv); - break; - - case SIOCDEVPRIVATE + 0x2: /* set_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - err = dldwd_ioctl_setport3(dev, wrq); - if (! err) - changed = 1; - break; - - case SIOCDEVPRIVATE + 0x3: /* get_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", - dev->name); - err = dldwd_ioctl_getport3(dev, wrq); - break; - - case SIOCDEVPRIVATE + 0x4: /* set_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", - dev->name); - if (! capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - - /* 802.11b has recently defined some short preamble. - * Basically, the Phy header has been reduced in size. - * This increase performance, especially at high rates - * (the preamble is transmitted at 1Mb/s), unfortunately - * this give compatibility troubles... - Jean II */ - if(priv->has_preamble) { - int val = *( (int *) wrq->u.name ); - - dldwd_lock(priv); - if(val) - priv->preamble = 1; - else - priv->preamble = 0; - dldwd_unlock(priv); - changed = 1; - } else - err = -EOPNOTSUPP; - break; - - case SIOCDEVPRIVATE + 0x5: /* get_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", - dev->name); - if(priv->has_preamble) { - int *val = (int *)wrq->u.name; - - dldwd_lock(priv); - *val = priv->preamble; - dldwd_unlock(priv); - } else - err = -EOPNOTSUPP; - break; - - default: - err = -EOPNOTSUPP; - } - - if (! err && changed && netif_running(dev)) { - err = dldwd_reset(priv); - if (err) - dldwd_stop(dev); - } - - TRACE_EXIT(dev->name); - - return err; -} - -static int dldwd_change_mtu(struct net_device *dev, int new_mtu) -{ - TRACE_ENTER(dev->name); - - if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) - return -EINVAL; - - dev->mtu = new_mtu; - - TRACE_EXIT(dev->name); - - return 0; -} - -static void __dldwd_set_multicast_list(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - hermes_t *hw = &priv->hw; - int err = 0; - int promisc, allmulti, mc_count; - - TRACE_ENTER(dev->name); - - DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", - dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count); - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ( (dev->flags & IFF_PROMISC) ) { - promisc = 1; - allmulti = 0; - mc_count = 0; - } else if ( (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > HERMES_MAX_MULTICAST) ) { - promisc = 0; - allmulti = 1; - mc_count = HERMES_MAX_MULTICAST; - } else { - promisc = 0; - allmulti = 0; - mc_count = dev->mc_count; - } - - DEBUG(3, "promisc=%d mc_count=%d\n", - promisc, mc_count); - - if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", - dev->name, err, promisc); - } else - priv->promiscuous = promisc; - } - - if (allmulti) { - /* FIXME: This method of doing allmulticast reception - comes from the NetBSD driver. Haven't actually - tested whether it works or not. */ - hermes_multicast_t mclist; - - memset(&mclist, 0, sizeof(mclist)); - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->allmulti = 1; - - } else if (mc_count || (! mc_count && priv->mc_count) ) { - struct dev_mc_list *p = dev->mc_list; - hermes_multicast_t mclist; - int i; - - for (i = 0; i < mc_count; i++) { - /* First some paranoid checks */ - if (! p) { - printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", - dev->name); - break; - } - if (p->dmi_addrlen != ETH_ALEN) { - - printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", - dev->name, p->dmi_addrlen); - break; - } - - memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); - p = p->next; - } - - /* More paranoia */ - if (p) - printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", - dev->name); - - priv->mc_count = i; - - DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); - - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, - HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->allmulti = 0; - } - - /* Since we can set the promiscuous flag when it wasn't asked - for, make sure the net_device knows about it. */ - if (priv->promiscuous) - dev->flags |= IFF_PROMISC; - else - dev->flags &= ~IFF_PROMISC; - - if (priv->allmulti) - dev->flags |= IFF_ALLMULTI; - else - dev->flags &= ~IFF_ALLMULTI; - - TRACE_EXIT(dev->name); -} - -/* - * procfs stuff - */ - -static struct proc_dir_entry *dir_base = NULL; - -/* - * This function updates the total amount of data printed so far. It then - * determines if the amount of data printed into a buffer has reached the - * offset requested. If it hasn't, then the buffer is shifted over so that - * the next bit of data can be printed over the old bit. If the total - * amount printed so far exceeds the total amount requested, then this - * function returns 1, otherwise 0. - */ -static int - -shift_buffer(char *buffer, int requested_offset, int requested_len, - int *total, int *slop, char **buf) -{ - int printed; - - printed = *buf - buffer; - if (*total + printed <= requested_offset) { - *total += printed; - *buf = buffer; - } - else { - if (*total < requested_offset) { - *slop = requested_offset - *total; - } - *total = requested_offset + printed - *slop; - } - if (*total > requested_offset + requested_len) { - return 1; - } - else { - return 0; - } -} - -/* - * This function calculates the actual start of the requested data - * in the buffer. It also calculates actual length of data returned, - * which could be less that the amount of data requested. - */ -#define PROC_BUFFER_SIZE 4096 -#define PROC_SAFE_SIZE 3072 - -static int -calc_start_len(char *buffer, char **start, int requested_offset, - int requested_len, int total, char *buf) -{ - int return_len, buffer_len; - - buffer_len = buf - buffer; - if (buffer_len >= PROC_BUFFER_SIZE - 1) { - printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); - } - - /* - * There may be bytes before and after the - * chunk that was actually requested. - */ - return_len = total - requested_offset; - if (return_len < 0) { - return_len = 0; - } - *start = buf - return_len; - if (return_len > requested_len) { - return_len = requested_len; - } - return return_len; -} - -static int -dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, - int requested_len, int *eof, void *data) -{ - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; - char *buf; - int total = 0, slop = 0; - - buf = page; - -#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) - - DHERMESREG(CMD); - DHERMESREG(PARAM0); - DHERMESREG(PARAM1); - DHERMESREG(PARAM2); - DHERMESREG(STATUS); - DHERMESREG(RESP0); - DHERMESREG(RESP1); - DHERMESREG(RESP2); - DHERMESREG(INFOFID); - DHERMESREG(RXFID); - DHERMESREG(ALLOCFID); - DHERMESREG(TXCOMPLFID); - DHERMESREG(SELECT0); - DHERMESREG(OFFSET0); - DHERMESREG(SELECT1); - DHERMESREG(OFFSET1); - DHERMESREG(EVSTAT); - DHERMESREG(INTEN); - DHERMESREG(EVACK); - DHERMESREG(CONTROL); - DHERMESREG(SWSUPPORT0); - DHERMESREG(SWSUPPORT1); - DHERMESREG(SWSUPPORT2); - DHERMESREG(AUXPAGE); - DHERMESREG(AUXOFFSET); - DHERMESREG(AUXDATA); -#undef DHERMESREG - - shift_buffer(page, requested_offset, requested_len, &total, - &slop, &buf); - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -struct { - uint16_t rid; - char *name; - int minlen, maxlen; - int displaytype; -#define DISPLAY_WORDS 0 -#define DISPLAY_BYTES 1 -#define DISPLAY_STRING 2 -} record_table[] = { -#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } - RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), - RTCNFENTRY(MACADDR, DISPLAY_BYTES), - RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), - RTCNFENTRY(CHANNEL, DISPLAY_WORDS), - RTCNFENTRY(OWN_SSID, DISPLAY_STRING), - RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), - RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), - RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), - RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), - RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), - RTCNFENTRY(NICKNAME, DISPLAY_STRING), - RTCNFENTRY(WEP_ON, DISPLAY_WORDS), - RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), - RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), - RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), - RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), - RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), - RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), - RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), - RTCNFENTRY(KEYS, DISPLAY_BYTES), - RTCNFENTRY(TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(TICKTIME, DISPLAY_WORDS), - RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), - RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS), -#undef RTCNFENTRY -#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } - RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), - RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), - RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), - RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), - RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), - RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), - RTINFENTRY(DATARATES, DISPLAY_BYTES), -#undef RTINFENTRY -}; -#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) - -static int -dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, - int requested_len, int *eof, void *data) -{ - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; - char *buf; - int total = 0, slop = 0; - int i; - uint16_t length; - int err; - - buf = page; - - /* print out all the config RIDs */ - for (i = 0; i < NUM_RIDS; i++) { - uint16_t rid = record_table[i].rid; - int minlen = record_table[i].minlen; - int maxlen = record_table[i].maxlen; - int len; - uint8_t *val8; - uint16_t *val16; - int j; - - val8 = kmalloc(maxlen + 2, GFP_KERNEL); - if (! val8) - return -ENOMEM; - - err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, - &length, val8); - if (err) { - DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); - continue; - } - val16 = (uint16_t *)val8; - - buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, - rid, length, (length-1)*2); - len = MIN( MAX(minlen, (length-1)*2), maxlen); - - switch (record_table[i].displaytype) { - case DISPLAY_WORDS: - for (j = 0; j < len / 2; j++) { - buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); - } - buf--; - break; - - case DISPLAY_BYTES: - default: - for (j = 0; j < len; j++) { - buf += sprintf(buf, "%02X:", val8[j]); - } - buf--; - break; - - case DISPLAY_STRING: - len = MIN(len, le16_to_cpu(val16[0])+2); - val8[len] = '\0'; - buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); - break; - } - - buf += sprintf(buf, "\n"); - - kfree(val8); - - if (shift_buffer(page, requested_offset, requested_len, - &total, &slop, &buf)) - break; - - if ( (buf - page) > PROC_SAFE_SIZE ) - break; - } - - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -/* initialise the /proc subsystem for the hermes driver, creating the - * separate entries */ -static int -dldwd_proc_init(void) -{ - int err = 0; - - TRACE_ENTER("dldwd"); - - /* create the directory for it to sit in */ - dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); - if (dir_base == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); - dldwd_proc_cleanup(); - err = -ENOMEM; - } - - TRACE_EXIT("dldwd"); - - return err; -} - -static int -dldwd_proc_dev_init(dldwd_priv_t *dev) -{ - dev->dir_dev = NULL; - /* create the directory for it to sit in */ - dev->dir_dev = create_proc_entry(dev->node.dev_name, S_IFDIR | S_IRUGO | S_IXUGO, - dir_base); - if (dev->dir_dev == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", dev->node.dev_name); - goto fail; - } - - dev->dir_regs = NULL; - dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_regs, dev); - if (dev->dir_regs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", dev->node.dev_name); - goto fail; - } - - dev->dir_recs = NULL; - dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_recs, dev); - if (dev->dir_recs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", dev->node.dev_name); - goto fail; - } - - return 0; - fail: - dldwd_proc_dev_cleanup(dev); - return -ENOMEM; -} - -static void -dldwd_proc_dev_cleanup(dldwd_priv_t *priv) -{ - if (priv->dir_regs) { - remove_proc_entry("regs", priv->dir_dev); - priv->dir_regs = NULL; - } - if (priv->dir_recs) { - remove_proc_entry("recs", priv->dir_dev); - priv->dir_recs = NULL; - } - if (priv->dir_dev) { - remove_proc_entry(priv->node.dev_name, dir_base); - priv->dir_dev = NULL; - } -} - -static void -dldwd_proc_cleanup(void) -{ - TRACE_ENTER("dldwd"); - - if (dir_base) { - remove_proc_entry("hermes", &proc_root); - dir_base = NULL; - } - - TRACE_EXIT("dldwd"); -} - -/*====================================================================*/ - -/* - * From here on in, it's all PCMCIA junk, taken almost directly from - * dummy_cs.c - */ - -/* - 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 = "orinoco_cs"; - -/* - A linked list of "instances" of the dummy 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; -static int num_instances = 0; - -/*====================================================================*/ - -static void cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); -} - -/*====================================================================== - dldwd_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 *dldwd_attach(void) -{ - dldwd_priv_t *priv; - dev_link_t *link; - struct net_device *ndev; - client_reg_t client_reg; - int ret, i; - - TRACE_ENTER("dldwd"); - - /* Allocate space for private device-specific data */ - priv = kmalloc(sizeof(*priv), GFP_KERNEL); - if (! priv) { - link = NULL; - goto out; - } - - memset(priv, 0, sizeof(*priv)); - priv->instance = num_instances++; /* FIXME: Racy? */ - spin_lock_init(&priv->lock); - - link = &priv->link; - ndev = &priv->ndev; - link->priv = ndev->priv = priv; - - /* Initialize the dev_link_t structure */ - link->release.function = &dldwd_release; - link->release.data = (u_long) link; - - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - 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 = NULL; - - /* - General socket configuration defaults can go here. In this - client, we assume very little, and rely on the CIS for almost - everything. In most clients, many details (i.e., number, sizes, - and attributes of IO windows) are fixed by the nature of the - device, and can be hard-wired here. - */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - - /* Set up the net_device */ - ether_setup(ndev); - ndev->init = dldwd_init; - ndev->open = dldwd_open; - ndev->stop = dldwd_stop; - ndev->hard_start_xmit = dldwd_xmit; - ndev->tx_timeout = dldwd_tx_timeout; - ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ - - ndev->get_stats = dldwd_get_stats; - ndev->get_wireless_stats = dldwd_get_wireless_stats; - - ndev->do_ioctl = dldwd_ioctl; - - ndev->change_mtu = dldwd_change_mtu; - ndev->set_multicast_list = dldwd_set_multicast_list; - - netif_stop_queue(ndev); - - /* 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 = &dldwd_event; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); - if (ret != CS_SUCCESS) { - cs_error(link->handle, RegisterClient, ret); - dldwd_detach(link); - link = NULL; - goto out; - } - - out: - TRACE_EXIT("dldwd"); - return link; -} /* dldwd_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 dldwd_detach(dev_link_t * link) -{ - dev_link_t **linkp; - dldwd_priv_t *priv = link->priv; - - TRACE_ENTER("dldwd"); - - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) - break; - if (*linkp == NULL) - goto out; - - /* - 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(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " - "still locked\n", link->dev->dev_name); -#endif - link->state |= DEV_STALE_LINK; - goto out; - } - - /* Break the link with Card Services */ - if (link->handle) - CardServices(DeregisterClient, link->handle); - - /* Unlink device structure, and free it */ - *linkp = link->next; - DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); - if (link->dev) { - DEBUG(0, "orinoco_cs: About to unregister net device %p\n", - &priv->ndev); - unregister_netdev(&priv->ndev); - } - kfree(priv); - - num_instances--; /* FIXME: Racy? */ - - out: - TRACE_EXIT("dldwd"); -} /* dldwd_detach */ - -/* - * Do a soft reset of the Pcmcia card using the Configuration Option Register - * Can't do any harm, and actually may do some good on some cards... - */ -static int dldwd_cor_reset(dev_link_t *link) -{ - conf_reg_t reg; - u_long default_cor; - - /* Save original COR value */ - reg.Function = 0; - reg.Action = CS_READ; - reg.Offset = CISREG_COR; - reg.Value = 0; - CardServices(AccessConfigurationRegister, link->handle, ®); - default_cor = reg.Value; - - DEBUG(2, "dldwd : dldwd_cor_reset() : cor=0x%lX\n", default_cor); - - /* Soft-Reset card */ - reg.Action = CS_WRITE; - reg.Offset = CISREG_COR; - reg.Value = (default_cor | COR_SOFT_RESET); - CardServices(AccessConfigurationRegister, link->handle, ®); - - /* Wait until the card has acknowledged our reset */ - mdelay(1); - - /* Restore original COR configuration index */ - reg.Value = (default_cor & COR_CONFIG_MASK); - CardServices(AccessConfigurationRegister, link->handle, ®); - - /* Wait until the card has finished restarting */ - mdelay(1); - - return(0); -} - -/*====================================================================== - dldwd_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 - -#define CFG_CHECK(fn, args...) \ -if (CardServices(fn, args) != 0) goto next_entry - -static void dldwd_config(dev_link_t * link) -{ - client_handle_t handle = link->handle; - dldwd_priv_t *priv = link->priv; - hermes_t *hw = &priv->hw; - struct net_device *ndev = &priv->ndev; - tuple_t tuple; - cisparse_t parse; - int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - cistpl_cftable_entry_t dflt = { 0 }; - cisinfo_t info; - - TRACE_ENTER("dldwd"); - - CS_CHECK(ValidateCIS, handle, &info); - - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - 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; - - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, handle, &conf); - link->conf.Vcc = conf.Vcc; - - DEBUG(0, "dldwd_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", - link->conf.ConfigBase, link->conf.Vcc); - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); - - DEBUG(0, "dldwd_config: index = 0x%x, flags = 0x%x\n", - cfg->index, cfg->flags); - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != - cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - goto next_entry; - } - } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != - dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - DEBUG(0, "dldwd_config: We seem to have configured Vcc and Vpp\n"); - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = - (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = - io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = - link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK(RequestIO, link->handle, &link->io); - } - - - /* If we got this far, we're cool! */ - - break; - - next_entry: - if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); - CS_CHECK(GetNextTuple, handle, &tuple); - } - - /* - Allocate an interrupt line. Note that this does not assign a - handler to the interrupt, unless the 'Handler' member of the - irq structure is initialized. - */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) { - int i; - - 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 = dldwd_interrupt; - link->irq.Instance = priv; - - CS_CHECK(RequestIRQ, link->handle, &link->irq); - } - - /* We initialize the hermes structure before completing PCMCIA - configuration just in case the interrupt handler gets - called. */ - hermes_struct_init(hw, link->io.BasePort1); - - /* - This actually configures the PCMCIA socket -- setting up - the I/O windows and the interrupt mapping, and putting the - card and host interface into "Memory and IO" mode. - */ - CS_CHECK(RequestConfiguration, link->handle, &link->conf); - - ndev->base_addr = link->io.BasePort1; - ndev->irq = link->irq.AssignedIRQ; - - /* Do a Pcmcia soft reset of the card (optional) */ - if(reset_cor) - dldwd_cor_reset(link); - - /* register_netdev will give us an ethX name */ - ndev->name[0] = '\0'; - /* Tell the stack we exist */ - if (register_netdev(ndev) != 0) { - printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); - goto failed; - } - strcpy(priv->node.dev_name, ndev->name); - - /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - priv->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc / 10, link->conf.Vcc % 10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1 / 10, - link->conf.Vpp1 % 10); - if (link->conf.Attributes & CONF_ENABLE_IRQ) - printk(", irq %d", link->irq.AssignedIRQ); - if (link->io.NumPorts1) - printk(", io 0x%04x-0x%04x", link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); - if (link->io.NumPorts2) - printk(" & 0x%04x-0x%04x", link->io.BasePort2, - link->io.BasePort2 + link->io.NumPorts2 - 1); - printk("\n"); - - /* And give us the proc nodes for debugging */ - if (dldwd_proc_dev_init(priv) != 0) { - printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", - priv->node.dev_name); - goto failed; - } - - /* - At this point, the dev_node_t structure(s) need to be - initialized and arranged in a linked list at link->dev. - */ - priv->node.major = priv->node.minor = 0; - link->dev = &priv->node; - link->state &= ~DEV_CONFIG_PENDING; - - TRACE_EXIT("dldwd"); - - return; - - cs_failed: - cs_error(link->handle, last_fn, last_ret); - failed: - dldwd_release((u_long) link); - - TRACE_EXIT("dldwd"); -} /* dldwd_config */ - -/*====================================================================== - After a card is removed, dldwd_release() will unregister the - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - ======================================================================*/ - -static void dldwd_release(u_long arg) -{ - dev_link_t *link = (dev_link_t *) arg; - dldwd_priv_t *priv = link->priv; - - TRACE_ENTER(link->dev->dev_name); - - /* - If the device is currently in use, we won't release until it - is actually closed, because until then, we can't be sure that - no one will try to access the device or its data structures. - */ - if (link->open) { - DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - /* - In a normal driver, additional code may be needed to release - other kernel data structures associated with this device. - */ - - dldwd_proc_dev_cleanup(priv); - - /* Don't bother checking to see if these succeed or not */ - CardServices(ReleaseConfiguration, link->handle); - if (link->io.NumPorts1) - CardServices(ReleaseIO, link->handle, &link->io); - if (link->irq.AssignedIRQ) - CardServices(ReleaseIRQ, link->handle, &link->irq); - link->state &= ~DEV_CONFIG; - - TRACE_EXIT(link->dev->dev_name); -} /* dldwd_release */ - -/*====================================================================== - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. - - When a CARD_REMOVAL event is received, we immediately set a - private 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 dldwd_event(event_t event, int priority, - event_callback_args_t * args) -{ - dev_link_t *link = args->client_data; - dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; - struct net_device *dev = &priv->ndev; - - TRACE_ENTER("dldwd"); - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - dldwd_shutdown(priv); - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) { - netif_stop_queue(dev); - netif_device_detach(dev); - mod_timer(&link->release, jiffies + HZ / 20); - } - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dldwd_config(link); - break; - case CS_EVENT_PM_SUSPEND: - - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - dldwd_shutdown(priv); - /* Mark the device as stopped, to block IO until later */ - - if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue(dev); - netif_device_detach(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) { - if (dldwd_reset(priv) == 0) { - netif_device_attach(dev); - netif_start_queue(dev); - } else { - printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", - dev->name); - dldwd_stop(dev); - } - } - } - /* - In a normal driver, additional code may go here to restore - the device state and restart IO. - */ - break; - } - - TRACE_EXIT("dldwd"); - - return 0; -} /* dldwd_event */ - -static int __init init_dldwd_cs(void) -{ - servinfo_t serv; - int err; - - TRACE_ENTER("dldwd"); - - printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); - - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "orinoco_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &dldwd_attach, &dldwd_detach); - - - err = dldwd_proc_init(); - - TRACE_EXIT("dldwd"); - return err; -} - -static void __exit exit_dldwd_cs(void) -{ - TRACE_ENTER("dldwd"); - - dldwd_proc_cleanup(); - - unregister_pccard_driver(&dev_info); - - if (dev_list) - DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); - while (dev_list != NULL) { - del_timer(&dev_list->release); - if (dev_list->state & DEV_CONFIG) - dldwd_release((u_long) dev_list); - dldwd_detach(dev_list); - } - - TRACE_EXIT("dldwd"); -} - -module_init(init_dldwd_cs); -module_exit(exit_dldwd_cs); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/Config.in linux/drivers/net/wireless/Config.in --- v2.4.4/linux/drivers/net/wireless/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/Config.in Mon May 7 19:42:14 2001 @@ -0,0 +1,22 @@ +# +# Wireless LAN device configuration +# + +###tristate ' Hermes chipset support' CONFIG_NET_ORINOCO +###dep_tristate ' PCMCIA Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_NET_ORINOCO $CONFIG_PCMCIA + +if [ "$CONFIG_ALL_PPC" = "y" ]; then + tristate ' Apple Airport support (built-in)' CONFIG_APPLE_AIRPORT +fi + +# If Pcmcia is compiled in, offer Pcmcia cards... +if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then + comment 'Wireless Pcmcia cards support' + + dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA + +# If one of the Pcmcia cards above is enabled, activate Pcmcia network support + if [ "$CONFIG_PCMCIA_HERMES" = "y" ]; then + define_bool CONFIG_PCMCIA_NETCARD y + fi +fi diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/Makefile linux/drivers/net/wireless/Makefile --- v2.4.4/linux/drivers/net/wireless/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/Makefile Mon May 7 19:42:14 2001 @@ -0,0 +1,27 @@ +# +# drivers/net/wireless/Makefile +# +# Makefile for the Linux Wireless network device drivers. +# + +O_TARGET := orinoco_drvs.o + +obj-y := +obj-m := +obj-n := +obj- := + +# Things that need to export symbols +export-objs := orinoco.o hermes.o + +# ISA Bus cards + +# PCI bus cards + +# Other cards +obj-$(CONFIG_APPLE_AIRPORT) += airport.o orinoco.o hermes.o + +# 16-bit Pcmcia wireless client drivers +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o orinoco.o hermes.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/README linux/drivers/net/wireless/README --- v2.4.4/linux/drivers/net/wireless/README Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/README Mon May 7 19:42:14 2001 @@ -0,0 +1,25 @@ + README + ------ + + This directory is mostly for Wireless LAN drivers, in their +various incarnations (ISA, PCI, Pcmcia...). + This separate directory is needed because a lot of driver work +on different bus (typically PCI + Pcmcia) and share 95% of the +code. This allow the code and the config options to be in one single +place instead of scattered all over the driver tree, which is never +100% satisfactory. + + Note : if you want more info on the topic of Wireless LANs, +you are kindly invited to have a look at the Wireless Howto : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ + Some Wireless LAN drivers, like orinoco_cs, require the use of +Wireless Tools to be configured : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + + Special notes for distribution maintainers : + 1) wvlan_cs will be discontinued soon in favor of orinoco_cs + 2) Please add Wireless Tools support in your scripts + + Have fun... + + Jean diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/airport.c linux/drivers/net/wireless/airport.c --- v2.4.4/linux/drivers/net/wireless/airport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/airport.c Mon May 7 19:42:14 2001 @@ -0,0 +1,270 @@ +/* airport.c 0.05 + * + * A driver for "Hermes" chipset based Apple Airport wireless + * card. + * + * Copyright notice & release notes in file orinoco.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hermes.h" +#include "orinoco.h" + +typedef struct dldwd_card { + struct device_node* node; + int irq_requested; + int ndev_registered; + /* Common structure (fully included), see orinoco.h */ + struct dldwd_priv priv; +} dldwd_card_t; + +static char *version = "airport.c 0.05 (Benjamin Herrenschmidt )"; + +/* + * Function prototypes + */ + +static dldwd_priv_t* airport_attach(struct device_node *of_node); +static void airport_detach(dldwd_priv_t* priv); +static int airport_init(struct net_device *dev); +static int airport_open(struct net_device *dev); +static int airport_stop(struct net_device *dev); + +/* + A linked list of "instances" of the dummy 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 dldwd_priv_t *airport_dev; + +static int airport_init(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + int rc; + + TRACE_ENTER(priv->ndev.name); + + MOD_INC_USE_COUNT; + + feature_set_airport_power(card->node, 1); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + rc = dldwd_init(dev); + if (rc) { + feature_set_airport_power(card->node, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + } + priv->hw_ready = 1; + + MOD_DEC_USE_COUNT; + + return rc; +} + +static int +airport_open(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + int rc; + + TRACE_ENTER(priv->ndev.name); + + netif_device_attach(dev); + rc = dldwd_reset(priv); + if (rc) + airport_stop(dev); + else + netif_start_queue(dev); + + TRACE_EXIT(priv->ndev.name); + + return rc; +} + +static int +airport_stop(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + + TRACE_ENTER(priv->ndev.name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + TRACE_EXIT(priv->ndev.name); + + return 0; +} + +static dldwd_priv_t* +airport_attach(struct device_node* of_node) +{ + dldwd_priv_t *priv; + struct net_device *ndev; + dldwd_card_t* card; + hermes_t *hw; + + TRACE_ENTER("dldwd"); + + if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { + printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); + return NULL; + } + + /* Allocate space for private device-specific data */ + card = kmalloc(sizeof(*card), GFP_KERNEL); + if (!card) { + printk(KERN_ERR "airport: can't allocate device datas\n"); + return NULL; + } + memset(card, 0, sizeof(*card)); + + priv = &(card->priv); + priv->card = card; + ndev = &priv->ndev; + hw = &priv->hw; + card->node = of_node; + + /* Setup the common part */ + if (dldwd_setup(priv) < 0) { + kfree(card); + return NULL; + } + + /* Overrides */ + ndev->init = airport_init; + ndev->open = airport_open; + ndev->stop = airport_stop; + + /* Setup interrupts & base address */ + ndev->irq = of_node->intrs[0].line; + ndev->base_addr = (unsigned long)ioremap(of_node->addrs[0].address, 0x1000) - _IO_BASE; + + hermes_struct_init(hw, ndev->base_addr); + + if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) { + printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq); + goto failed; + } + card->irq_requested = 1; + + /* register_netdev will give us an ethX name */ + ndev->name[0] = '\0'; + /* Tell the stack we exist */ + if (register_netdev(ndev) != 0) { + printk(KERN_ERR "airport: register_netdev() failed\n"); + goto failed; + } + printk(KERN_INFO "airport: card registered for interface %s\n", ndev->name); + card->ndev_registered = 1; + + SET_MODULE_OWNER(ndev); + + /* And give us the proc nodes for debugging */ + if (dldwd_proc_dev_init(priv) != 0) + printk(KERN_ERR "airport: Failed to create /proc node for %s\n", + ndev->name); + + return priv; + +failed: + airport_detach(priv); + return NULL; +} /* airport_attach */ + +/*====================================================================== + This deletes a driver "instance". + ======================================================================*/ + +static void +airport_detach(dldwd_priv_t *priv) +{ + dldwd_card_t* card = (dldwd_card_t *)priv->card; + + priv->hw_ready = 0; + + /* Unregister proc entry */ + dldwd_proc_dev_cleanup(priv); + + if (card->ndev_registered) + unregister_netdev(&priv->ndev); + card->ndev_registered = 0; + + if (card->irq_requested) + free_irq(priv->ndev.irq, priv); + card->irq_requested = 0; + +// FIXME +// if (ndev->base_addr) +// iounmap(ndev->base_addr + _IO_BASE); +// ndev->base_addr = 0; + + feature_set_airport_power(card->node, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + kfree(card); +} /* airport_detach */ + +static int __init +init_airport(void) +{ + struct device_node* airport_node; + + printk(KERN_INFO "%s\n", version); + + MOD_INC_USE_COUNT; + + /* Lookup card in device tree */ + airport_node = find_devices("radio"); + if (airport_node && !strcmp(airport_node->parent->name, "mac-io")) + airport_dev = airport_attach(airport_node); + + MOD_DEC_USE_COUNT; + + return airport_dev ? 0 : -ENODEV; +} + +static void __exit +exit_airport(void) +{ + if (airport_dev) + airport_detach(airport_dev); + airport_dev = NULL; +} + +MODULE_DESCRIPTION("Apple Airport driver"); + +module_init(init_airport); +module_exit(exit_airport); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/hermes.c linux/drivers/net/wireless/hermes.c --- v2.4.4/linux/drivers/net/wireless/hermes.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/hermes.c Mon May 7 19:42:14 2001 @@ -0,0 +1,502 @@ +/* hermes.c + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * This file distributed under the GPL, version 2. + */ + +static const char *version = "hermes.c: 12 Dec 2000 David Gibson "; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hermes.h" + +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ +#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ +#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ +#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +/* + * Debugging helpers + */ + +#undef HERMES_DEBUG +#ifdef HERMES_DEBUG + +#include + +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ + printk(#stuff);} while (0) + +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) + +#else /* ! HERMES_DEBUG */ + +#define DEBUG(lvl, stuff...) do { } while (0) + +#endif /* ! HERMES_DEBUG */ + +/* + * Prototypes + */ + +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); + +/* + * Internal inline functions + */ + +/* + * Internal functions + */ + +/* Issue a command to the chip. Waiting for it to complete is the caller's + problem. + + Returns -EBUSY if the command register is busy, 0 on success. + + Callable from any context. +*/ +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) +{ + uint16_t reg; +/* unsigned long k = CMD_BUSY_TIMEOUT; */ + + /* First check that the command register is not busy */ + reg = hermes_read_regn(hw, CMD); + if (reg & HERMES_CMD_BUSY) { + return -EBUSY; + } + + hermes_write_regn(hw, PARAM2, 0); + hermes_write_regn(hw, PARAM1, 0); + hermes_write_regn(hw, PARAM0, param0); + hermes_write_regn(hw, CMD, cmd); + + return 0; +} + +/* + * Function definitions + */ + +void hermes_struct_init(hermes_t *hw, uint io) +{ + hw->iobase = io; + hw->inten = 0x0; +} + +int hermes_reset(hermes_t *hw) +{ + uint16_t status, reg; + int err = 0; + int k; + + /* We don't want to be interrupted while resetting the chipset */ + hw->inten = 0x0; + hermes_write_regn(hw, INTEN, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + /* Because we hope we can reset the card even if it gets into + a stupid state, we actually wait to see if the command + register will unbusy itself */ + k = CMD_BUSY_TIMEOUT; + reg = hermes_read_regn(hw, CMD); + while (k && (reg & HERMES_CMD_BUSY)) { + if (reg == 0xffff) /* Special case - the card has probably been removed, + so don't wait for the timeout */ + return -ENODEV; + + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* No need to explicitly handle the timeout - hermes_issue_cmd() will + probably return -EBUSY */ + + /* We don't use hermes_docmd_wait here, because the reset wipes + the magic constant in SWSUPPORT0 away, and it gets confused */ + err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (! hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = status & HERMES_STATUS_RESULT; + + out: + return err; +} + +/* Issue a command to the chip, and (busy!) wait for it to + * complete. + * + * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware + * + * Callable from any context, but locking is your problem. */ +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) +{ + int err; + int k; + uint16_t reg; + + err = hermes_issue_cmd(hw, cmd, parm0); + if (err) { + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", + hw->iobase); + err = -ENODEV; + } else + printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", + hw->iobase); + goto out; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", + hw->iobase); + err = -ETIMEDOUT; + goto out; + } + + resp->status = hermes_read_regn(hw, STATUS); + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = resp->status & HERMES_STATUS_RESULT; + + out: + return err; +} + +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) +{ + int err = 0; + hermes_response_t resp; + int k; + uint16_t reg; + + if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); + if (err) { + printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", + hw->iobase, err); + return err; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = ALLOC_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_ALLOC)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", + hw->iobase); + return -ENODEV; + } + + if (! (reg & HERMES_EV_ALLOC)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", + hw->iobase); + return -ETIMEDOUT; + } + + *fid = hermes_read_regn(hw, ALLOCFID); + hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); + + return 0; +} + +/* Set up a BAP to read a particular chunk of data from card's internal buffer. + * + * Returns: < 0 on internal failure (errno), 0 on success, >0 on error + * from firmware + * + * Callable from any context */ +static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) +{ + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; + int k; + int l = BAP_ERROR_RETRY; + uint16_t reg; + + /* Paranoia.. */ + if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) + return -EINVAL; + + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + + if (reg & HERMES_OFFSET_BUSY) + return -EBUSY; + + /* Now we actually set up the transfer */ + retry: + hermes_write_reg(hw, sreg, id); + hermes_write_reg(hw, oreg, offset); + + /* Wait for the BAP to be ready */ + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } + + if (reg & HERMES_OFFSET_BUSY) + return -ETIMEDOUT; + + /* For some reason, seeking the BAP seems to randomly fail somewhere + (firmware bug?). We retry a few times before giving up. */ + if (reg & HERMES_OFFSET_ERR) { + if (l--) { + udelay(1); + goto retry; + } else + return -EIO; + } + + return 0; +} + +/* Read a block of data from the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_read_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Write a block of data to the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_write_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Read a Length-Type-Value record from the card. + * + * If length is NULL, we ignore the length read from the card, and + * read the entire buffer regardless. This is useful because some of + * the configuration records appear to have incorrect lengths in + * practice. + * + * Callable from user or bh context. */ +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf) +{ + int err = 0; + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + uint16_t rlength, rtype; + hermes_response_t resp; + int count; + + if (buflen % 2) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); + if (err) + goto out; + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + rlength = hermes_read_reg(hw, dreg); + rtype = hermes_read_reg(hw, dreg); + + if (length) + *length = rlength; + + if (rtype != rid) + printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " + "not match type (0x%04x)\n", rid, rtype); + if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) + printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " + "(rid=0x%04x, len=0x%04x)\n", hw->iobase, + HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); + + /* For now we always read the whole buffer, the + lengths in the records seem to be wrong, frequently */ + count = buflen / 2; + +#if 0 + if (length) + count = (MIN(buflen, rlength) + 1) / 2; + else { + count = buflen / 2; + if (rlength != buflen) + printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ +record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); + } +#endif + hermes_read_data(hw, dreg, buf, count); + + out: + return err; +} + +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + hermes_response_t resp; + int count; + + DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", + bap, rid, length, * ((uint16_t *)value)); + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + hermes_write_reg(hw, dreg, length); + hermes_write_reg(hw, dreg, rid); + + count = length - 1; + + hermes_write_data(hw, dreg, value, count); + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + rid, &resp); + + out: + return err; +} + +EXPORT_SYMBOL(hermes_struct_init); +EXPORT_SYMBOL(hermes_reset); +EXPORT_SYMBOL(hermes_docmd_wait); +EXPORT_SYMBOL(hermes_allocate); + +EXPORT_SYMBOL(hermes_bap_pread); +EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_read_ltv); +EXPORT_SYMBOL(hermes_write_ltv); + +static int __init init_hermes(void) +{ + printk(KERN_INFO "%s\n", version); + + return 0; +} + +module_init(init_hermes); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/hermes.h linux/drivers/net/wireless/hermes.h --- v2.4.4/linux/drivers/net/wireless/hermes.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/hermes.h Mon May 7 19:42:14 2001 @@ -0,0 +1,402 @@ +/* hermes.h + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * This file distributed under the GPL, version 2. + */ + +#ifndef _HERMES_H +#define _HERMES_H + +/* Notes on locking: + * + * As a module of low level hardware access routines, there is no + * locking. Users of this module should ensure that they serialize + * access to the hermes_t structure, and to the hardware +*/ + +#include +#include + +/* + * Limits and constants + */ +#define HERMES_ALLOC_LEN_MIN (4) +#define HERMES_ALLOC_LEN_MAX (2400) +#define HERMES_LTV_LEN_MAX (34) +#define HERMES_BAP_DATALEN_MAX (4096) +#define HERMES_BAP_OFFSET_MAX (4096) +#define HERMES_PORTID_MAX (7) +#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) +#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ +#define HERMES_PDA_RECS_MAX (200) /* a guess */ +#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ +#define HERMES_SCANRESULT_MAX (35) +#define HERMES_CHINFORESULT_MAX (8) +#define HERMES_FRAME_LEN_MAX (2304) +#define HERMES_MAX_MULTICAST (16) +#define HERMES_MAGIC (0x7d1f) + +/* + * Hermes register offsets + */ +#define HERMES_CMD (0x00) +#define HERMES_PARAM0 (0x02) +#define HERMES_PARAM1 (0x04) +#define HERMES_PARAM2 (0x06) +#define HERMES_STATUS (0x08) +#define HERMES_RESP0 (0x0A) +#define HERMES_RESP1 (0x0C) +#define HERMES_RESP2 (0x0E) +#define HERMES_INFOFID (0x10) +#define HERMES_RXFID (0x20) +#define HERMES_ALLOCFID (0x22) +#define HERMES_TXCOMPLFID (0x24) +#define HERMES_SELECT0 (0x18) +#define HERMES_OFFSET0 (0x1C) +#define HERMES_DATA0 (0x36) +#define HERMES_SELECT1 (0x1A) +#define HERMES_OFFSET1 (0x1E) +#define HERMES_DATA1 (0x38) +#define HERMES_EVSTAT (0x30) +#define HERMES_INTEN (0x32) +#define HERMES_EVACK (0x34) +#define HERMES_CONTROL (0x14) +#define HERMES_SWSUPPORT0 (0x28) +#define HERMES_SWSUPPORT1 (0x2A) +#define HERMES_SWSUPPORT2 (0x2C) +#define HERMES_AUXPAGE (0x3A) +#define HERMES_AUXOFFSET (0x3C) +#define HERMES_AUXDATA (0x3E) + +/* + * CMD register bitmasks + */ +#define HERMES_CMD_BUSY (0x8000) +#define HERMES_CMD_AINFO (0x7f00) +#define HERMES_CMD_MACPORT (0x0700) +#define HERMES_CMD_RECL (0x0100) +#define HERMES_CMD_WRITE (0x0100) +#define HERMES_CMD_PROGMODE (0x0300) +#define HERMES_CMD_CMDCODE (0x003f) + +/* + * STATUS register bitmasks + */ +#define HERMES_STATUS_RESULT (0x7f00) +#define HERMES_STATUS_CMDCODE (0x003f) + +/* + * OFFSET refister bitmasks + */ +#define HERMES_OFFSET_BUSY (0x8000) +#define HERMES_OFFSET_ERR (0x4000) +#define HERMES_OFFSET_DATAOFF (0x0ffe) + +/* + * Event register bitmasks (INTEN, EVSTAT, EVACK) + */ +#define HERMES_EV_TICK (0x8000) +#define HERMES_EV_WTERR (0x4000) +#define HERMES_EV_INFDROP (0x2000) +#define HERMES_EV_INFO (0x0080) +#define HERMES_EV_DTIM (0x0020) +#define HERMES_EV_CMD (0x0010) +#define HERMES_EV_ALLOC (0x0008) +#define HERMES_EV_TXEXC (0x0004) +#define HERMES_EV_TX (0x0002) +#define HERMES_EV_RX (0x0001) + +/* + * Command codes + */ +/*--- Controller Commands --------------------------*/ +#define HERMES_CMD_INIT (0x0000) +#define HERMES_CMD_ENABLE (0x0001) +#define HERMES_CMD_DISABLE (0x0002) +#define HERMES_CMD_DIAG (0x0003) + +/*--- Buffer Mgmt Commands --------------------------*/ +#define HERMES_CMD_ALLOC (0x000A) +#define HERMES_CMD_TX (0x000B) +#define HERMES_CMD_CLRPRST (0x0012) + +/*--- Regulate Commands --------------------------*/ +#define HERMES_CMD_NOTIFY (0x0010) +#define HERMES_CMD_INQ (0x0011) + +/*--- Configure Commands --------------------------*/ +#define HERMES_CMD_ACCESS (0x0021) +#define HERMES_CMD_DOWNLD (0x0022) + +/*--- Debugging Commands -----------------------------*/ +#define HERMES_CMD_MONITOR (0x0038) +#define HERMES_MONITOR_ENABLE (0x000b) +#define HERMES_MONITOR_DISABLE (0x000f) + +/* + * Configuration RIDs + */ + +#define HERMES_RID_CNF_PORTTYPE (0xfc00) +#define HERMES_RID_CNF_MACADDR (0xfc01) +#define HERMES_RID_CNF_DESIRED_SSID (0xfc02) +#define HERMES_RID_CNF_CHANNEL (0xfc03) +#define HERMES_RID_CNF_OWN_SSID (0xfc04) +#define HERMES_RID_CNF_SYSTEM_SCALE (0xfc06) +#define HERMES_RID_CNF_MAX_DATA_LEN (0xfc07) +#define HERMES_RID_CNF_PM_ENABLE (0xfc09) +#define HERMES_RID_CNF_PM_MCAST_RX (0xfc0b) +#define HERMES_RID_CNF_PM_PERIOD (0xfc0c) +#define HERMES_RID_CNF_PM_HOLDOVER (0xfc0d) +#define HERMES_RID_CNF_NICKNAME (0xfc0e) +#define HERMES_RID_CNF_WEP_ON (0xfc20) +#define HERMES_RID_CNF_MWO_ROBUST (0xfc25) +#define HERMES_RID_CNF_PRISM2_WEP_ON (0xfc28) +#define HERMES_RID_CNF_MULTICAST_LIST (0xfc80) +#define HERMES_RID_CNF_CREATEIBSS (0xfc81) +#define HERMES_RID_CNF_FRAG_THRESH (0xfc82) +#define HERMES_RID_CNF_RTS_THRESH (0xfc83) +#define HERMES_RID_CNF_TX_RATE_CTRL (0xfc84) +#define HERMES_RID_CNF_PROMISCUOUS (0xfc85) +#define HERMES_RID_CNF_KEYS (0xfcb0) +#define HERMES_RID_CNF_TX_KEY (0xfcb1) +#define HERMES_RID_CNF_TICKTIME (0xfce0) + +#define HERMES_RID_CNF_PRISM2_TX_KEY (0xfc23) +#define HERMES_RID_CNF_PRISM2_KEY0 (0xfc24) +#define HERMES_RID_CNF_PRISM2_KEY1 (0xfc25) +#define HERMES_RID_CNF_PRISM2_KEY2 (0xfc26) +#define HERMES_RID_CNF_PRISM2_KEY3 (0xfc27) +#define HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID (0xfc21) +#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE (0xfc2A) +#define HERMES_RID_CNF_SYMBOL_BASIC_RATES (0xfc8A) +#define HERMES_RID_CNF_SYMBOL_PREAMBLE (0xfc8C) + +/* + * Information RIDs + */ +#define HERMES_RID_CHANNEL_LIST (0xfd10) +#define HERMES_RID_STAIDENTITY (0xfd20) +#define HERMES_RID_CURRENT_SSID (0xfd41) +#define HERMES_RID_CURRENT_BSSID (0xfd42) +#define HERMES_RID_COMMSQUALITY (0xfd43) +#define HERMES_RID_CURRENT_TX_RATE (0xfd44) +#define HERMES_RID_SHORT_RETRY_LIMIT (0xfd48) +#define HERMES_RID_LONG_RETRY_LIMIT (0xfd49) +#define HERMES_RID_MAX_TX_LIFETIME (0xfd4A) +#define HERMES_RID_WEP_AVAIL (0xfd4f) +#define HERMES_RID_CURRENT_CHANNEL (0xfdc1) +#define HERMES_RID_DATARATES (0xfdc6) +#define HERMES_RID_SYMBOL_PRIMARY_VER (0xfd03) +#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd21) +#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) + +/* + * Frame structures and constants + */ + +typedef struct hermes_frame_desc { + /* Hermes - i.e. little-endian byte-order */ + uint16_t status; /* 0x0 */ + uint16_t res1, res2; /* 0x2, 0x4 */ + uint16_t q_info; /* 0x6 */ + uint16_t res3, res4; /* 0x8, 0xA */ + uint16_t tx_ctl; /* 0xC */ +} __attribute__ ((packed)) hermes_frame_desc_t; + +#define HERMES_RXSTAT_ERR (0x0003) +#define HERMES_RXSTAT_MACPORT (0x0700) +#define HERMES_RXSTAT_MSGTYPE (0xE000) + +#define HERMES_RXSTAT_BADCRC (0x0001) +#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) + +/* RFC-1042 encoded frame */ +#define HERMES_RXSTAT_1042 (0x2000) +/* Bridge-tunnel encoded frame */ +#define HERMES_RXSTAT_TUNNEL (0x4000) +/* Wavelan-II Management Protocol frame */ +#define HERMES_RXSTAT_WMP (0x6000) + +#ifdef __KERNEL__ + +/* Basic control structure */ +typedef struct hermes { + uint iobase; + + uint16_t inten; /* Which interrupts should be enabled? */ +} hermes_t; + +typedef struct hermes_response { + uint16_t status, resp0, resp1, resp2; +} hermes_response_t; + +/* Firmware information structure */ +typedef struct hermes_identity { + uint16_t id, vendor, major, minor; +} __attribute__ ((packed)) hermes_identity_t; + +/* "ID" structure - used for ESSID and station nickname */ +typedef struct hermes_id { + uint16_t len; + uint16_t val[16]; +} __attribute__ ((packed)) hermes_id_t; + +typedef struct hermes_commsqual { + uint16_t qual, signal, noise; +} __attribute__ ((packed)) hermes_commsqual_t; + +typedef struct hermes_multicast { + uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)) hermes_multicast_t; + +/* Register access convenience macros */ +#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) +#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) + +#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) +#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) +#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) + +/* Function prototypes */ +void hermes_struct_init(hermes_t *hw, uint io); +int hermes_reset(hermes_t *hw); +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); + + +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf); +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value); + +/* Inline functions */ + +static inline int hermes_present(hermes_t *hw) +{ + return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; +} + +static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) +{ + hw->inten |= events; + hermes_write_regn(hw, INTEN, hw->inten); +} + +static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) +{ + hw->inten = events; + hermes_write_regn(hw, INTEN, events); +} + +static inline int hermes_enable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +static inline int hermes_disable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) +#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) + +#define HERMES_READ_RECORD(hw, bap, rid, buf) \ + (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) +#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) + +static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) +{ + uint16_t rec; + int err; + + err = HERMES_READ_RECORD(hw, bap, rid, &rec); + *word = le16_to_cpu(rec); + return err; +} + +static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) +{ + uint16_t rec = cpu_to_le16(word); + return HERMES_WRITE_RECORD(hw, bap, rid, &rec); +} + +static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->id); + le16_to_cpus(&buf->vendor); + le16_to_cpus(&buf->major); + le16_to_cpus(&buf->minor); + + return 0; +} + +static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->qual); + le16_to_cpus(&buf->signal); + le16_to_cpus(&buf->noise); + + return 0; +} + +#else /* ! __KERNEL__ */ + +/* These are provided for the benefit of userspace drivers and testing programs + which use ioperm() or iopl() */ + +#define hermes_read_reg(base, off) (inw((base) + (off))) +#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) + +#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) +#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) +#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) + +#endif /* ! __KERNEL__ */ + +#endif /* _HERMES_H */ diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/orinoco.c linux/drivers/net/wireless/orinoco.c --- v2.4.4/linux/drivers/net/wireless/orinoco.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/orinoco.c Mon May 7 19:42:14 2001 @@ -0,0 +1,3551 @@ +/* orinoco.c 0.05 - (formerly known as dldwd_cs.c and orinoco_cs.c) + * + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright (C) 2000 David Gibson, Linuxcare Australia + * With some help from : + * Copyright (C) 2001 Jean Tourrilhes, HP Labs + * Copyright (C) 2001 Benjamin Herrenschmidt + * + * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 + * + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus + * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David + * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights + * Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the above. + * If you wish to allow the use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +/* Notes on locking: + * + * The basic principle of operation is that everything except the + * interrupt handler is serialized through a single spinlock in the + * dldwd_priv_t structure, using dldwd_lock() and + * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). + * + * The kernel's IRQ handling stuff ensures that the interrupt handler + * does not re-enter itself. The interrupt handler is written such + * that everything it does is safe without a lock: chiefly this means + * that the Rx path uses one of the Hermes chipset's BAPs while + * everything else uses the other. + * + * For the moment access to the device statistics from the interrupt + * handler is unsafe - we just put up with any resulting errors in the + * statisics. FIXME: This should probably be changed to store the + * stats in atomic types. + * + * EXCEPT that we don't want the irq handler running when we actually + * reset or shut down the card, because strange things might happen + * (probably the worst would be one packet of garbage, but you can't + * be too careful). For this we use __dldwd_stop_irqs() which will set + * a flag to disable the interrupt handler, and wait for any + * outstanding instances of the handler to complete. THIS WILL LOSE + * INTERRUPTS! so it shouldn't be used except for resets, when we + * don't care about that.*/ + +/* + * Tentative changelog... + * + * v0.01 -> v0.02 - 21/3/2001 - Jean II + * o Allow to use regular ethX device name instead of dldwdX + * o Warning on IBSS with ESSID=any for firmware 6.06 + * o Put proper range.throughput values (optimistic) + * o IWSPY support (IOCTL and stat gather in Rx path) + * o Allow setting frequency in Ad-Hoc mode + * o Disable WEP setting if !has_wep to work on old firmware + * o Fix txpower range + * o Start adding support for Samsung/Compaq firmware + * + * v0.02 -> v0.03 - 23/3/2001 - Jean II + * o Start adding Symbol support - need to check all that + * o Fix Prism2/Symbol WEP to accept 128 bits keys + * o Add Symbol WEP (add authentication type) + * o Add Prism2/Symbol rate + * o Add PM timeout (holdover duration) + * o Enable "iwconfig eth0 key off" and friends (toggle flags) + * o Enable "iwconfig eth0 power unicast/all" (toggle flags) + * o Try with an intel card. It report firmware 1.01, behave like + * an antiquated firmware, however on windows it says 2.00. Yuck ! + * o Workaround firmware bug in allocate buffer (Intel 1.01) + * o Finish external renaming to orinoco... + * o Testing with various Wavelan firmwares + * + * v0.03 -> v0.04 - 30/3/2001 - Jean II + * o Update to Wireless 11 -> add retry limit/lifetime support + * o Tested with a D-Link DWL 650 card, fill in firmware support + * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) + * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( + * It work on D-Link *only* after a tcpdump. Weird... + * And still doesn't work on Intel card. Grrrr... + * o Update the mode after a setport3 + * o Add preamble setting for Symbol cards (not yet enabled) + * o Don't complain as much about Symbol cards... + * + * v0.04 -> v0.04b - 22/4/2001 - David Gibson + * o Removed the 'eth' parameter - always use ethXX as the + * interface name instead of dldwdXX. The other was racy + * anyway. + * o Clean up RID definitions in hermes.h, other cleanups + * + * v0.04b -> v0.04c - 24/4/2001 - Jean II + * o Tim Hurley reported a D-Link card + * with vendor 02 and firmware 0.08. Added in the capabilities... + * o Tested Lucent firmware 7.28, everything works... + * + * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt + * o Spin-off Pcmcia code. This file is renamed orinoco.c, + * and orinoco_cs.c now contains only the Pcmcia specific stuff + * o Add Airport driver support on top of orinoco.c (see airport.c) + * + * v0.05 -> v0.05a - 4/5/2001 - Jean II + * o Revert to old Pcmcia code to fix breakage of Ben's changes... + * + * v0.05a -> v0.05b - 4/5/2001 - Jean II + * o add module parameter 'ignore_cis_vcc' for D-Link @ 5V + * o D-Link firmware doesn't support multicast. We just print a few + * error messages, but otherwise everything works... + * o For David : set/getport3 works fine, just upgrade iwpriv... + * + * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt + * o Adapt airport.c to latest changes in orinoco.c + * o Remove deferred power enabling code + * + * v0.05c -> v0.05d - 5/5/2001 - Jean II + * o Workaround to SNAP decapsulate frame from LinkSys AP + * original patch from : Dong Liu + * (note : the memcmp bug was mine - fixed) + * o Remove set_retry stuff, no firmware support it (bloat--). + * + * TODO - Jean II + * o inline functions (lot's of candidate, need to reorder code) + * o Test PrismII/Symbol cards & firmware versions + * o Mini-PCI support + */ + +#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 "hermes.h" +#include "orinoco.h" + +static char *version = "orinoco.c 0.05d (David Gibson and others)"; + +/* Level of debugging. Used in the macros in orinoco.h */ +#ifdef ORINOCO_DEBUG +int dldwd_debug = ORINOCO_DEBUG; +MODULE_PARM(dldwd_debug, "i"); +#endif + +const long channel_frequency[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) + +/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. + It gives the rate in halfMb/s, negative indicates auto mode */ +const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; + +#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) + +struct p80211_hdr { + uint16_t frame_ctl; + uint16_t duration_id; + uint8_t addr1[ETH_ALEN]; + uint8_t addr2[ETH_ALEN]; + uint8_t addr3[ETH_ALEN]; + uint16_t seq_ctl; + uint8_t addr4[ETH_ALEN]; + uint16_t data_len; +} __attribute__ ((packed)); + +/* Frame control field constants */ +#define DLDWD_FCTL_VERS 0x0002 +#define DLDWD_FCTL_FTYPE 0x000c +#define DLDWD_FCTL_STYPE 0x00f0 +#define DLDWD_FCTL_TODS 0x0100 +#define DLDWD_FCTL_FROMDS 0x0200 +#define DLDWD_FCTL_MOREFRAGS 0x0400 +#define DLDWD_FCTL_RETRY 0x0800 +#define DLDWD_FCTL_PM 0x1000 +#define DLDWD_FCTL_MOREDATA 0x2000 +#define DLDWD_FCTL_WEP 0x4000 +#define DLDWD_FCTL_ORDER 0x8000 + +#define DLDWD_FTYPE_MGMT 0x0000 +#define DLDWD_FTYPE_CTL 0x0004 +#define DLDWD_FTYPE_DATA 0x0008 + +struct p8022_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t ctrl; + uint8_t oui[3]; +} __attribute__ ((packed)); + +struct dldwd_frame_hdr { + hermes_frame_desc_t desc; + struct p80211_hdr p80211; + struct ethhdr p8023; + struct p8022_hdr p8022; + uint16_t ethertype; +} __attribute__ ((packed)); + +#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ + sizeof(struct p80211_hdr)) +#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) + +/* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */ +struct p8022_hdr encaps_hdr = { + 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} +}; + +/* + * Function prototypes + */ + +static void dldwd_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr); + +static struct net_device_stats *dldwd_get_stats(struct net_device *dev); +static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); + +/* Hardware control routines */ + +static int __dldwd_hw_reset(dldwd_priv_t *priv); +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); +static long dldwd_hw_get_freq(dldwd_priv_t *priv); +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max); + +/* Interrupt handling routines */ +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); +static void __dldwd_set_multicast_list(struct net_device *dev); + +/* /proc debugging stuff */ +static int dldwd_proc_init(void); +static void dldwd_proc_cleanup(void); + +/* + * Inline functions + */ +static inline void +dldwd_lock(dldwd_priv_t *priv) +{ + spin_lock_bh(&priv->lock); +} + +static inline void +dldwd_unlock(dldwd_priv_t *priv) +{ + spin_unlock_bh(&priv->lock); +} + +static inline int +dldwd_irqs_allowed(dldwd_priv_t *priv) +{ + return test_bit(DLDWD_STATE_DOIRQ, &priv->state); +} + +static inline void +__dldwd_stop_irqs(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + + hermes_set_irqmask(hw, 0); + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) + ; +} + +static inline void +__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) +{ + hermes_t *hw = &priv->hw; + + TRACE_ENTER(priv->ndev.name); + + __cli(); + set_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, irqmask); + __sti(); + + TRACE_EXIT(priv->ndev.name); +} + +static inline void +set_port_type(dldwd_priv_t *priv) +{ + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->allow_ibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->allow_ibss = 0; + } else { + priv->port_type = 1; + priv->allow_ibss = 1; + } + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev.name); + } +} + +extern void +dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + + dldwd_lock(priv); + __dldwd_set_multicast_list(dev); + dldwd_unlock(priv); +} + +/* + * Hardware control routines + */ + +static int +__dldwd_hw_reset(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err; + + if (! priv->broken_reset) + return hermes_reset(hw); + else { + hw->inten = 0; + hermes_write_regn(hw, INTEN, 0); + err = hermes_disable_port(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + return err; + } +} + +void +dldwd_shutdown(dldwd_priv_t *priv) +{ +/* hermes_t *hw = &priv->hw; */ + int err = 0; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ + printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); + + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); +} + +int +dldwd_reset(dldwd_priv_t *priv) +{ + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t idbuf; + int frame_size; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err) + goto out; + + frame_size = TX_NICBUF_SIZE; + /* This stupid bug is present in Intel firmware 1.10, and + * may be fixed in later firmwares - Jean II */ + if(priv->broken_allocate) + frame_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, frame_size, &priv->txfid); + if (err) + goto out; + + /* Now set up all the parameters on the card */ + + /* Set up the link mode */ + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); + if (err) + goto out; + if (priv->has_ibss) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, + priv->allow_ibss); + if (err) + goto out; + if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) + && (!priv->has_ibss_any)) { + printk(KERN_WARNING "%s: This firmware requires an \ +ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + } + } + + /* Set up encryption */ + if (priv->has_wep) { + err = __dldwd_hw_setup_wep(priv); + if (err) + goto out; + } + + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? + HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) + goto out; + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) + goto out; + + /* Set the channel/frequency */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); + if (err) + goto out; + + /* Set AP density */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); + if (err) + goto out; + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); + if (err) + goto out; + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); + if (err) + goto out; + + /* Set bitrate */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, + priv->tx_rate_ctrl); + if (err) + goto out; + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, + priv->pm_on); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, + priv->pm_mcast); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + priv->pm_period); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + priv->pm_timeout); + if (err) + goto out; + } + + /* Set preamble - only for Symbol so far... */ + if (priv->has_preamble) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, + priv->preamble); + if (err) { + printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); + goto out; + } + } + + /* Set promiscuity / multicast*/ + priv->promiscuous = 0; + priv->allmulti = 0; + priv->mc_count = 0; + __dldwd_set_multicast_list(dev); + + err = hermes_enable_port(hw, DLDWD_MACPORT); + if (err) + goto out; + + __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + HERMES_EV_TX | HERMES_EV_TXEXC | + HERMES_EV_WTERR | HERMES_EV_INFO | + HERMES_EV_INFDROP); + + out: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + int extra_wep_flag = 0; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ + if (priv->wep_on) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); + if (err) + return err; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); + if (err) + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); + if (err) + return err; + break; + + case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + if (priv->wep_on) { + char keybuf[LARGE_KEY_SIZE+1]; + int keylen; + int i; + + /* Write all 4 keys */ + for(i = 0; i < MAX_KEYS; i++) { + keylen = priv->keys[i].len; + keybuf[keylen] = '\0'; + memcpy(keybuf, priv->keys[i].data, keylen); + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_KEY0 + i, + HERMES_BYTES_TO_RECLEN(keylen + 1), + &keybuf); + if (err) + return err; + } + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, + priv->tx_key); + if (err) + return err; + + /* Authentication is where Prism2 and Symbol + * firmware differ... */ + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { + /* Symbol cards : set the authentication : + * 0 -> no encryption, 1 -> open, + * 2 -> shared key, 3 -> shared key 128bit */ + if(priv->wep_restrict) { + if(priv->keys[priv->tx_key].len > + SMALL_KEY_SIZE) + extra_wep_flag = 3; + else + extra_wep_flag = 2; + } else + extra_wep_flag = 1; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict); + if (err) + return err; + } else { + /* Prism2 card : we need to modify master + * WEP setting */ + if(priv->wep_restrict) + extra_wep_flag = 2; + else + extra_wep_flag = 0; + } + } + + /* Master WEP setting : on/off */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag)); + if (err) + return err; + break; + + default: + if (priv->wep_on) { + printk(KERN_ERR "%s: WEP enabled, although not supported!\n", + priv->ndev.name); + return -EINVAL; + } + } + + return 0; +} + +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + dldwd_lock(priv); + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, + ETH_ALEN, NULL, buf); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + if (strlen(priv->desired_essid) > 0) { + /* We read the desired SSID from the hardware rather + than from priv->desired_essid, just in case the + firmware is allowed to change it on us. I'm not + sure about this */ + /* My guess is that the OWN_SSID should always be whatever + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + uint16_t rid; + + *active = 1; + + rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : + HERMES_RID_CNF_DESIRED_SSID; + + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; + } + + len = le16_to_cpu(essidbuf.len); + + memset(buf, 0, sizeof(buf)); + memcpy(buf, p, len); + buf[len] = '\0'; + + fail_unlock: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static long dldwd_hw_get_freq(dldwd_priv_t *priv) +{ + + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t channel; + long freq = 0; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); + if (err) + goto out; + + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + struct net_device *dev = &priv->ndev; + + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); + err = -EBUSY; + goto out; + + } + freq = channel_frequency[channel-1] * 100000; + + out: + dldwd_unlock(priv); + + if (err > 0) + err = -EBUSY; + return err ? err : freq; +} + +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max) +{ + hermes_t *hw = &priv->hw; + hermes_id_t list; + unsigned char *p = (unsigned char *)&list.val; + int err = 0; + int num; + int i; + + dldwd_lock(priv); + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), + NULL, &list); + dldwd_unlock(priv); + + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = MIN(num, max); + + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ + } + + return 0; +} + +#ifndef PCMCIA_DEBUG +static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} +#else +static void show_rx_frame(struct dldwd_frame_hdr *frame) +{ + printk(KERN_DEBUG "RX descriptor:\n"); + printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); + printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); + printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); + printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); + printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); + printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); + printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); + + printk(KERN_DEBUG "IEEE 802.11 header:\n"); + printk(KERN_DEBUG " frame_ctl = 0x%04x\n", + frame->p80211.frame_ctl); + printk(KERN_DEBUG " duration_id = 0x%04x\n", + frame->p80211.duration_id); + printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr1[0], frame->p80211.addr1[1], + frame->p80211.addr1[2], frame->p80211.addr1[3], + frame->p80211.addr1[4], frame->p80211.addr1[5]); + printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr2[0], frame->p80211.addr2[1], + frame->p80211.addr2[2], frame->p80211.addr2[3], + frame->p80211.addr2[4], frame->p80211.addr2[5]); + printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr3[0], frame->p80211.addr3[1], + frame->p80211.addr3[2], frame->p80211.addr3[3], + frame->p80211.addr3[4], frame->p80211.addr3[5]); + printk(KERN_DEBUG " seq_ctl = 0x%04x\n", + frame->p80211.seq_ctl); + printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr4[0], frame->p80211.addr4[1], + frame->p80211.addr4[2], frame->p80211.addr4[3], + frame->p80211.addr4[4], frame->p80211.addr4[5]); + printk(KERN_DEBUG " data_len = 0x%04x\n", + frame->p80211.data_len); + + printk(KERN_DEBUG "IEEE 802.3 header:\n"); + printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_dest[0], frame->p8023.h_dest[1], + frame->p8023.h_dest[2], frame->p8023.h_dest[3], + frame->p8023.h_dest[4], frame->p8023.h_dest[5]); + printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_source[0], frame->p8023.h_source[1], + frame->p8023.h_source[2], frame->p8023.h_source[3], + frame->p8023.h_source[4], frame->p8023.h_source[5]); + printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); + + printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); + printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); + printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); + printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); + printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", + frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); + printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); +} +#endif + +/* + * Interrupt handler + */ +void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) +{ + dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; + hermes_t *hw = &priv->hw; + struct net_device *dev = &priv->ndev; + int count = IRQ_LOOP_MAX; + uint16_t evstat, events; + static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ + + if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) + BUG(); + + if (! dldwd_irqs_allowed(priv)) { + clear_bit(DLDWD_STATE_INIRQ, &priv->state); + return; + } + + DEBUG(3, "%s: dldwd_interrupt()\n", priv->ndev.name); + + while (1) { + if (jiffies != old_time) + timecount = 0; + if ( (++timecount > 50) || (! count--) ) { + printk(KERN_CRIT "%s: IRQ handler is looping too \ +much! Shutting down.\n", + dev->name); + /* Perform an emergency shutdown */ + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, 0); + break; + } + + evstat = hermes_read_regn(hw, EVSTAT); + DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", + count, evstat, hw->inten); + + events = evstat & hw->inten; + + if (! events) { + if (netif_queue_stopped(dev)) { + /* There seems to be a firmware bug which + sometimes causes the card to give an + interrupt with no event set, when there + sould be a Tx completed event. */ + DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", + dev->name, (int)hermes_read_regn(hw, ALLOCFID)); + events = HERMES_EV_TX | HERMES_EV_ALLOC; + } else /* Nothing's happening, we're done */ + break; + } + + /* Check the card hasn't been removed */ + if (! hermes_present(hw)) { + DEBUG(0, "dldwd_interrupt(): card removed\n"); + break; + } + + if (events & HERMES_EV_TICK) + __dldwd_ev_tick(priv, hw); + if (events & HERMES_EV_WTERR) + __dldwd_ev_wterr(priv, hw); + if (events & HERMES_EV_INFDROP) + __dldwd_ev_infdrop(priv, hw); + if (events & HERMES_EV_INFO) + __dldwd_ev_info(priv, hw); + if (events & HERMES_EV_RX) + __dldwd_ev_rx(priv, hw); + if (events & HERMES_EV_TXEXC) + __dldwd_ev_txexc(priv, hw); + if (events & HERMES_EV_TX) + __dldwd_ev_tx(priv, hw); + if (events & HERMES_EV_ALLOC) + __dldwd_ev_alloc(priv, hw); + + hermes_write_regn(hw, EVACK, events); + } + + clear_bit(DLDWD_STATE_INIRQ, &priv->state); +} + +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); +} + +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) +{ + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", + priv->ndev.name); +} + +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); +} + +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) +{ + DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); + /* We don't actually do anything about it - we assume the MAC + controller can deal with it */ +} + +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + struct iw_statistics *wstats = &priv->wstats; + struct sk_buff *skb = NULL; + uint16_t rxfid, status; + int length, data_len, data_off; + char *p; + struct dldwd_frame_hdr hdr; + struct ethhdr *eh; + int err; + + rxfid = hermes_read_regn(hw, RXFID); + DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); + + /* We read in the entire frame header here. This isn't really + necessary, since we ignore most of it, but it's + conceptually simpler. We can tune this later if + necessary. */ + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } + + status = le16_to_cpu(hdr.desc.status); + + if (status & HERMES_RXSTAT_ERR) { + if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { + stats->rx_crc_errors++; + printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n", + dev->name); + show_rx_frame(&hdr); + } else if ((status & HERMES_RXSTAT_ERR) + == HERMES_RXSTAT_UNDECRYPTABLE) { + wstats->discard.code++; + printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + } else { + wstats->discard.misc++; + printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", + dev->name, status & HERMES_RXSTAT_ERR); + } + stats->rx_errors++; + goto drop; + } + + length = le16_to_cpu(hdr.p80211.data_len); + /* Yes, you heard right, that's le16. 802.2 and 802.3 are + big-endian, but 802.11 is little-endian believe it or + not. */ + /* Correct. 802.3 is big-endian byte order and little endian bit + * order, whereas 802.11 is little endian for both byte and bit + * order. That's specified in the 802.11 spec. - Jean II */ + + /* Sanity check */ + if (length > MAX_FRAME_SIZE) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + stats->rx_errors++; + goto drop; + } + + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + stats->rx_dropped++; + goto drop; + } + + skb_reserve(skb, 2); /* This way the IP header is aligned */ + + /* Handle decapsulation + * In most cases, the firmware tell us about SNAP frames. + * For some reason, the SNAP frames sent by LinkSys APs + * are not properly recognised by most firmwares. + * So, check ourselves (note : only 3 bytes out of 6). + */ + if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || + ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || + (!memcmp(&hdr.p8022, &encaps_hdr, 3))) { + /* These indicate a SNAP within 802.2 LLC within + 802.11 frame which we'll need to de-encapsulate to + the original EthernetII frame. + IEEE and ISO OSI have a lot to answer for. */ + + /* Remove SNAP header, reconstruct EthernetII frame */ + data_len = length - ENCAPS_OVERHEAD; + data_off = sizeof(hdr); + + eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); + + memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); + eh->h_proto = hdr.ethertype; + } else { + /* All other cases indicate a genuine 802.3 frame. + * No decapsulation needed */ + + /* Otherwise, we just throw the whole thing in, + * and hope the protocol layer can deal with it + * as 802.3 */ + data_len = length; + data_off = P8023_OFFSET; + } + + p = skb_put(skb, data_len); + if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), + rxfid, data_off) != 0) { + printk(KERN_WARNING "%s: Error reading packet data\n", + dev->name); + stats->rx_errors++; + goto drop; + } + + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* Process the wireless stats if needed */ + dldwd_stat_gather(dev, skb, &hdr); + + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; + + drop: + if (skb) + dev_kfree_skb_irq(skb); + return; +} + +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + printk(KERN_WARNING "%s: Tx error!\n", dev->name); + + netif_wake_queue(dev); + stats->tx_errors++; +} + +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + DEBUG(3, "%s: Transmit completed\n", dev->name); + + stats->tx_packets++; + netif_wake_queue(dev); +} + +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) +{ + uint16_t allocfid; + + allocfid = hermes_read_regn(hw, ALLOCFID); + DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); + + /* For some reason we don't seem to get transmit completed events properly */ + if (allocfid == priv->txfid) + __dldwd_ev_tx(priv, hw); + +/* hermes_write_regn(hw, ALLOCFID, 0); */ +} + +/* + * struct net_device methods + */ + +int +dldwd_init(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t nickbuf; + uint16_t reclen; + int len; + char *vendor_str; + uint32_t firmver; + + TRACE_ENTER("dldwd"); + + dldwd_lock(priv); + + err = hermes_reset(hw); + if (err != 0) { + printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); + goto out; + } + + /* Get the firmware version */ + err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); + if (err) { + printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", + dev->name, err); + memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); + } + + firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; + DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver); + + /* Determine capabilities from the firmware version */ + + switch (priv->firmware_info.vendor) { + case 0x1: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + * ELSA, Melco, HP, IBM, Dell 1150 cards */ + vendor_str = "Lucent"; + /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ + + priv->firmware_type = FIRMWARE_TYPE_LUCENT; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; /* Still works in 7.28 */ + priv->has_ibss = (firmver >= 0x60006); + priv->has_ibss_any = (firmver >= 0x60010); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); + priv->has_preamble = 0; + /* Tested with Lucent firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case 0x2: + vendor_str = "Generic Prism II"; + /* Some D-Link cards report vendor 0x02... */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x00007); /* FIXME */ + priv->has_wep = (firmver >= 0x00007); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x00007); /* FIXME */ + priv->has_preamble = 0; + + /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */ + + /* Special case for Symbol cards */ + if(firmver == 0x10001) { + /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ + vendor_str = "Symbol"; + /* Intel MAC : 00:02:B3:* */ + /* 3Com MAC : 00:50:DA:* */ + + /* FIXME : probably need to use SYMBOL_***ARY_VER + * to get proper firmware version */ + priv->firmware_type = FIRMWARE_TYPE_SYMBOL; + priv->broken_reset = 0; + priv->broken_allocate = 1; + priv->has_port3 = 1; + priv->has_ibss = 1; /* FIXME */ + priv->has_wep = 1; /* FIXME */ + priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ + priv->has_mwo = 0; + priv->has_pm = 1; /* FIXME */ + priv->has_preamble = 0; /* FIXME */ + /* Tested with Intel firmware : v15 => Jean II */ + } + break; + case 0x3: + vendor_str = "Samsung"; + /* To check - Should cover Samsung & Compaq */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 0; /* FIXME */ + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); /* FIXME */ + priv->has_preamble = 0; + break; + case 0x6: + /* D-Link DWL 650, ... */ + vendor_str = "LinkSys/D-Link"; + /* D-Link MAC : 00:40:05:* */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x00007); /* FIXME */ + priv->has_wep = (firmver >= 0x00007); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x00007); /* FIXME */ + priv->has_preamble = 0; + /* Tested with D-Link firmware 0.07 => Jean II */ + /* Note : with 0.07, IBSS to a Lucent card seem flaky */ + break; + default: + vendor_str = "UNKNOWN"; + + priv->firmware_type = 0; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 0; + priv->has_ibss = 0; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = 0; + priv->has_preamble = 0; + } + + printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", + dev->name, priv->firmware_info.id, priv->firmware_info.vendor, + vendor_str, priv->firmware_info.major, priv->firmware_info.minor); + + if (priv->has_port3) + printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); + if (priv->has_ibss) + printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", + dev->name); + if (priv->has_wep) { + printk(KERN_INFO "%s: WEP supported, ", dev->name); + if (priv->has_big_wep) + printk("\"128\"-bit key.\n"); + else + printk("40-bit key.\n"); + } + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, + ETH_ALEN, NULL, dev->dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], + dev->dev_addr[5]); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name!n", + dev->name); + goto out; + } + if ( nickbuf.len ) + len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + else + len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick); + + /* Get allowed channels */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); + if (err) { + printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); + goto out; + } + + /* Get initial RTS threshold */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); + goto out; + } + + /* Set initial bitrate control*/ + priv->tx_rate_ctrl = 3; + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + &priv->pm_period); + if (err) { + printk(KERN_ERR "%s: failed to read power management period!\n", + dev->name); + goto out; + } + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management timeout!\n", + dev->name); + goto out; + } + } + + /* Preamble setup */ + if (priv->has_preamble) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); + if (err) + goto out; + } + + /* Set up the default configuration */ + priv->iw_mode = IW_MODE_INFRA; + /* By default use IEEE/IBSS ad-hoc mode if we have it */ + priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); + set_port_type(priv); + + priv->promiscuous = 0; + priv->allmulti = 0; + priv->wep_on = 0; + priv->tx_key = 0; + + printk(KERN_INFO "%s: ready\n", dev->name); + + out: + dldwd_unlock(priv); + + TRACE_EXIT("dldwd"); + + return err; +} + +struct net_device_stats * +dldwd_get_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + + return &priv->stats; +} + +struct iw_statistics * +dldwd_get_wireless_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_t *hw = &priv->hw; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + hermes_commsqual_t cq; + + if (!priv->hw_ready) + return NULL; + + dldwd_lock(priv); + + if (priv->port_type == 3) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); +#ifdef WIRELESS_SPY + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (priv->spy_number > 0) { + wstats->qual.qual = priv->spy_stat[0].qual; + wstats->qual.level = priv->spy_stat[0].level; + wstats->qual.noise = priv->spy_stat[0].noise; + wstats->qual.updated = priv->spy_stat[0].updated; + } +#endif /* WIRELESS_SPY */ + } else { + err = hermes_read_commsqual(hw, USER_BAP, &cq); + + DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + + /* Why are we using MIN/MAX ? We don't really care + * if the value goes above max, because we export the + * raw dBm values anyway. The normalisation should be done + * in user space - Jean II */ + wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); + wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; + wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; + wstats->qual.updated = 7; + } + + dldwd_unlock(priv); + + if (err) + return NULL; + + return wstats; +} + +#ifdef WIRELESS_SPY +static inline void dldwd_spy_gather(struct net_device *dev, + u_char *mac, + hermes_commsqual_t *cq) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + int i; + + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + for (i = 0; i < priv->spy_number; i++) + if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { + priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); + priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].updated = 7; + } +} +#endif /* WIRELESS_SPY */ + +void +dldwd_stat_gather( struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_commsqual_t cq; + + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ +#ifdef WIRELESS_EXT + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if ( +#ifdef WIRELESS_SPY + (priv->spy_number > 0) || +#endif + 0 ) + { + u_char *stats = (u_char *) &(hdr->desc.q_info); + /* This code may look strange. Everywhere we are using 16 bit + * ints except here. I've verified that these are are the + * correct values. Please check on PPC - Jean II */ + cq.signal = stats[1]; /* High order byte */ + cq.noise = stats[0]; /* Low order byte */ + cq.qual = stats[0] - stats[1]; /* Better than nothing */ + + DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + +#ifdef WIRELESS_SPY + dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); +#endif + } +#endif /* WIRELESS_EXT */ +} + +int +dldwd_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t txfid = priv->txfid; + char *p; + struct ethhdr *eh; + int len, data_len, data_off; + struct dldwd_frame_hdr hdr; + hermes_response_t resp; + + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", + dev->name); + return 1; + + } + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR "%s: Tx while transmitter busy!\n", + dev->name); + return 1; + } + + dldwd_lock(priv); + + /* Length of the packet body */ + len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); + + eh = (struct ethhdr *)skb->data; + + /* Build the IEEE 802.11 header */ + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); + memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); + hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ + data_len = len; + data_off = sizeof(hdr); + p = skb->data + ETH_HLEN; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); + + /* 802.3 header */ + memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); + hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); + + /* 802.2 header */ + memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); + + hdr.ethertype = eh->h_proto; + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } else { /* IEEE 802.3 frame */ + data_len = len + ETH_HLEN; + data_off = P8023_OFFSET; + p = skb->data; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(len); + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } + + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + + /* Finally, we actually initiate the send */ + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); + if (err) { + printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); + stats->tx_errors++; + goto fail; + } + + dev->trans_start = jiffies; + stats->tx_bytes += data_off + data_len; + + netif_stop_queue(dev); + + dldwd_unlock(priv); + + dev_kfree_skb(skb); + + return 0; + fail: + + dldwd_unlock(priv); + return err; +} + +void +dldwd_tx_timeout(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + int err = 0; + + printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); + + stats->tx_errors++; + + err = dldwd_reset(priv); + if (err) + printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", + dev->name, err); + else { + dev->trans_start = jiffies; + netif_wake_queue(dev); + } +} + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int ptype; + struct iw_range range; + int numrates; + int i, k; + + TRACE_ENTER(dev->name); + + err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); + if (err) + return err; + + rrq->length = sizeof(range); + + dldwd_lock(priv); + ptype = priv->port_type; + dldwd_unlock(priv); + + memset(&range, 0, sizeof(range)); + + /* Much of this shamelessly taken from wvlan_cs.c. No idea + * what it all means -dgibson */ +#if WIRELESS_EXT > 10 + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 11; +#endif /* WIRELESS_EXT > 10 */ + + range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ + + /* Set available channels/frequencies */ + range.num_channels = NUM_CHANNELS; + k = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + range.freq[k].i = i + 1; + range.freq[k].m = channel_frequency[i] * 100000; + range.freq[k].e = 1; + k++; + } + + if (k >= IW_MAX_FREQUENCIES) + break; + } + range.num_frequency = k; + + range.sensitivity = 3; + + if ((ptype == 3) && (priv->spy_number == 0)){ + /* Quality stats meaningless in ad-hoc mode */ + range.max_qual.qual = 0; + range.max_qual.level = 0; + range.max_qual.noise = 0; + } else { + range.max_qual.qual = 0x8b - 0x2f; + range.max_qual.level = 0x2f - 0x95 - 1; + range.max_qual.noise = 0x2f - 0x95 - 1; + } + + err = dldwd_hw_get_bitratelist(priv, &numrates, + range.bitrate, IW_MAX_BITRATES); + if (err) + return err; + range.num_bitrates = numrates; + + /* Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface. May be use for QoS stuff... + * Jean II */ + if(numrates > 2) + range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ + else + range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ + + range.min_rts = 0; + range.max_rts = 2347; + range.min_frag = 256; + range.max_frag = 2346; + + dldwd_lock(priv); + if (priv->has_wep) { + range.max_encoding_tokens = MAX_KEYS; + + range.encoding_size[0] = SMALL_KEY_SIZE; + range.num_encoding_sizes = 1; + + if (priv->has_big_wep) { + range.encoding_size[1] = LARGE_KEY_SIZE; + range.num_encoding_sizes = 2; + } + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + dldwd_unlock(priv); + + range.min_pmp = 0; + range.max_pmp = 65535000; + range.min_pmt = 0; + range.max_pmt = 65535 * 1000; /* ??? */ + range.pmp_flags = IW_POWER_PERIOD; + range.pmt_flags = IW_POWER_TIMEOUT; + range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; + + range.num_txpower = 1; + range.txpower[0] = 15; /* 15dBm */ + range.txpower_capa = IW_TXPOW_DBM; + +#if WIRELESS_EXT > 10 + range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range.retry_flags = IW_RETRY_LIMIT; + range.r_time_flags = IW_RETRY_LIFETIME; + range.min_retry = 0; + range.max_retry = 65535; /* ??? */ + range.min_r_time = 0; + range.max_r_time = 65535 * 1000; /* ??? */ +#endif /* WIRELESS_EXT > 10 */ + + if (copy_to_user(rrq->pointer, &range, sizeof(range))) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + int setindex = priv->tx_key; + int enable = priv->wep_on; + int restricted = priv->wep_restrict; + uint16_t xlen = 0; + int err = 0; + char keybuf[MAX_KEY_SIZE]; + + if (erq->pointer) { + /* We actually have a key to set */ + + if (copy_from_user(keybuf, erq->pointer, erq->length)) + return -EFAULT; + } + + dldwd_lock(priv); + + if (erq->pointer) { + if (erq->length > MAX_KEY_SIZE) { + err = -E2BIG; + goto out; + } + + if ( (erq->length > LARGE_KEY_SIZE) + || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { + err = -EINVAL; + goto out; + } + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + if (erq->length > SMALL_KEY_SIZE) { + xlen = LARGE_KEY_SIZE; + } else if (erq->length > 0) { + xlen = SMALL_KEY_SIZE; + } else + xlen = 0; + + /* Switch on WEP if off */ + if ((!enable) && (xlen > 0)) { + setindex = index; + enable = 1; + } + } else { + /* Important note : if the user do "iwconfig eth0 enc off", + * we will arrive there with an index of -1. This is valid + * but need to be taken care off... Jean II */ + if ((index < 0) || (index >= MAX_KEYS)) { + if((index != -1) || (erq->flags == 0)) { + err = -EINVAL; + goto out; + } + } else { + /* Set the index : Check that the key is valid */ + if(priv->keys[index].len == 0) { + err = -EINVAL; + goto out; + } + setindex = index; + } + } + + if (erq->flags & IW_ENCODE_DISABLED) + enable = 0; + /* Only for Prism2 & Symbol cards (so far) - Jean II */ + if (erq->flags & IW_ENCODE_OPEN) + restricted = 0; + if (erq->flags & IW_ENCODE_RESTRICTED) + restricted = 1; + + if (erq->pointer) { + priv->keys[index].len = cpu_to_le16(xlen); + memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); + memcpy(priv->keys[index].data, keybuf, erq->length); + } + priv->tx_key = setindex; + priv->wep_on = enable; + priv->wep_restrict = restricted; + + out: + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + uint16_t xlen = 0; + char keybuf[MAX_KEY_SIZE]; + + + dldwd_lock(priv); + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + erq->flags = 0; + if (! priv->wep_on) + erq->flags |= IW_ENCODE_DISABLED; + erq->flags |= index + 1; + + /* Only for symbol cards - Jean II */ + if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { + if(priv->wep_restrict) + erq->flags |= IW_ENCODE_RESTRICTED; + else + erq->flags |= IW_ENCODE_OPEN; + } + + xlen = le16_to_cpu(priv->keys[index].len); + + erq->length = xlen; + + if (erq->pointer) { + memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); + } + + dldwd_unlock(priv); + + if (erq->pointer) { + if (copy_to_user(erq->pointer, keybuf, xlen)) + return -EFAULT; + } + + return 0; +} + +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + + /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it + * anyway... - Jean II */ + + memset(&essidbuf, 0, sizeof(essidbuf)); + + if (erq->flags) { + if (erq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + if (copy_from_user(&essidbuf, erq->pointer, erq->length)) + return -EFAULT; + + essidbuf[erq->length] = '\0'; + } + + dldwd_lock(priv); + + memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + int active; + int err = 0; + + TRACE_ENTER(dev->name); + + err = dldwd_hw_get_essid(priv, &active, essidbuf); + if (err) + return err; + + erq->flags = 1; + erq->length = strlen(essidbuf) + 1; + if (erq->pointer) + if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + if (nrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + memset(nickbuf, 0, sizeof(nickbuf)); + + if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) + return -EFAULT; + + nickbuf[nrq->length] = '\0'; + + dldwd_lock(priv); + + memcpy(priv->nick, nickbuf, sizeof(priv->nick)); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + dldwd_lock(priv); + memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); + dldwd_unlock(priv); + + nrq->length = strlen(nickbuf)+1; + + if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) + return -EFAULT; + + return 0; +} + +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) +{ + dldwd_priv_t *priv = dev->priv; + int chan = -1; + + /* We can only use this in Ad-Hoc demo mode to set the operating + * frequency, or in IBSS mode to set the frequency where the IBSS + * will be created - Jean II */ + if (priv->iw_mode != IW_MODE_ADHOC) + return -EOPNOTSUPP; + + if ( (frq->e == 0) && (frq->m <= 1000) ) { + /* Setting by channel number */ + chan = frq->m; + } else { + /* Setting by frequency - search the table */ + int mult = 1; + int i; + + for (i = 0; i < (6 - frq->e); i++) + mult *= 10; + + for (i = 0; i < NUM_CHANNELS; i++) + if (frq->m == (channel_frequency[i] * mult)) + chan = i+1; + } + + if ( (chan < 1) || (chan > NUM_CHANNELS) || + ! (priv->channel_mask & (1 << (chan-1)) ) ) + return -EINVAL; + + dldwd_lock(priv); + priv->channel = chan; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + uint16_t val; + int err; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); + dldwd_unlock(priv); + + if (err) + return err; + + srq->value = val; + srq->fixed = 0; /* auto */ + + return 0; +} + +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + int val = srq->value; + + if ((val < 1) || (val > 3)) + return -EINVAL; + + dldwd_lock(priv); + priv->ap_density = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = rrq->value; + + if (rrq->disabled) + val = 2347; + + if ( (val < 0) || (val > 2347) ) + return -EINVAL; + + dldwd_lock(priv); + priv->rts_thresh = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + dldwd_lock(priv); + + if (priv->has_mwo) { + if (frq->disabled) + priv->mwo_robust = 0; + else { + if (frq->fixed) + printk(KERN_WARNING "%s: Fixed fragmentation not \ +supported on this firmware. Using MWO robust instead.\n", dev->name); + priv->mwo_robust = 1; + } + } else { + if (frq->disabled) + priv->frag_thresh = 2346; + else { + if ( (frq->value < 256) || (frq->value > 2346) ) + err = -EINVAL; + else + priv->frag_thresh = frq->value & ~0x1; /* must be even */ + } + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + + dldwd_lock(priv); + + if (priv->has_mwo) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); + if (err) + val = 0; + + frq->value = val ? 2347 : 0; + frq->disabled = ! val; + frq->fixed = 0; + } else { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); + if (err) + val = 0; + + frq->value = val; + frq->disabled = (val >= 2346); + frq->fixed = 1; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int rate_ctrl = -1; + int fixed, upto; + int brate; + int i; + + dldwd_lock(priv); + + /* Normalise value */ + brate = rrq->value / 500000; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + if (! rrq->fixed) { + if (brate > 0) + brate = -brate; + else + brate = -22; + } + + for (i = 0; i < NUM_RATES; i++) + if (rate_list[i] == brate) { + rate_ctrl = i; + break; + } + + if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + switch(brate) { + case 0: + fixed = 0x0; + upto = 0x15; + break; + case 2: + fixed = 0x1; + upto = 0x1; + break; + case 4: + fixed = 0x2; + upto = 0x3; + break; + case 11: + fixed = 0x4; + upto = 0x7; + break; + case 22: + fixed = 0x8; + upto = 0x15; + break; + default: + fixed = 0x0; + upto = 0x0; + } + if (rrq->fixed) + rate_ctrl = fixed; + else + rate_ctrl = upto; + if (rate_ctrl == 0) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + int brate = 0; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); + if (err) + goto out; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + brate = rate_list[val]; + + if (brate < 0) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + + if (val == 6) + brate = 11; + else + brate = 2*val; + } else + rrq->fixed = 1; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + /* Check if auto or fixed (crude approximation) */ + if((val & 0x1) && (val > 1)) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + } else + rrq->fixed = 1; + + if(val >= 8) + brate = 22; + else if(val >= 4) + brate = 11; + else if(val >= 2) + brate = 4; + else + brate = 2; + break; + } + + rrq->value = brate * 500000; + rrq->disabled = 0; + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + + dldwd_lock(priv); + + if (prq->disabled) { + priv->pm_on = 0; + } else { + switch (prq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + priv->pm_mcast = 0; + priv->pm_on = 1; + break; + case IW_POWER_ALL_R: + priv->pm_mcast = 1; + priv->pm_on = 1; + break; + case IW_POWER_ON: + /* No flags : but we may have a value - Jean II */ + break; + default: + err = -EINVAL; + } + if (err) + goto out; + + if (prq->flags & IW_POWER_TIMEOUT) { + priv->pm_on = 1; + priv->pm_timeout = prq->value / 1000; + } + if (prq->flags & IW_POWER_PERIOD) { + priv->pm_on = 1; + priv->pm_period = prq->value / 1000; + } + /* It's valid to not have a value if we are just toggling + * the flags... Jean II */ + if(!priv->pm_on) { + err = -EINVAL; + goto out; + } + } + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t enable, period, timeout, mcast; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); + if (err) + goto out; + + prq->disabled = !enable; + /* Note : by default, display the period */ + if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + prq->flags = IW_POWER_TIMEOUT; + prq->value = timeout * 1000; + } else { + prq->flags = IW_POWER_PERIOD; + prq->value = period * 1000; + } + if (mcast) + prq->flags |= IW_POWER_ALL_R; + else + prq->flags |= IW_POWER_UNICAST_R; + + out: + dldwd_unlock(priv); + + return err; +} + +#if WIRELESS_EXT > 10 +static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t short_limit, long_limit, lifetime; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); + if (err) + goto out; + + rrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the retry number */ + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = lifetime * 1000; /* ??? */ + } else { + /* By default, display the min number */ + if ((rrq->flags & IW_RETRY_MAX)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + rrq->value = long_limit; + } else { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = short_limit; + if(short_limit != long_limit) + rrq->flags |= IW_RETRY_MIN; + } + } + + out: + dldwd_unlock(priv); + + return err; +} +#endif /* WIRELESS_EXT > 10 */ + +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = *( (int *) wrq->u.name ); + int err = 0; + + dldwd_lock(priv); + switch (val) { + case 0: /* Try to do IEEE ad-hoc mode */ + if (! priv->has_ibss) { + err = -EINVAL; + break; + } + DEBUG(2, "%s: Prefer IBSS Ad-Hoc mode\n", dev->name); + priv->prefer_port3 = 0; + + break; + + case 1: /* Try to do Lucent proprietary ad-hoc mode */ + if (! priv->has_port3) { + err = -EINVAL; + break; + } + DEBUG(2, "%s: Prefer Ad-Hoc demo mode\n", dev->name); + priv->prefer_port3 = 1; + break; + + default: + err = -EINVAL; + } + + if (! err) + /* Actually update the mode we are using */ + set_port_type(priv); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->prefer_port3; + dldwd_unlock(priv); + + return 0; +} + +/* Spy is used for link quality/strength measurements in Ad-Hoc mode + * Jean II */ +static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + int number = srq->length; + int i; + int err = 0; + + /* Check the number of addresses */ + if (number > IW_MAX_SPY) + return -E2BIG; + + /* Get the data in the driver */ + if (srq->pointer) { + if (copy_from_user(address, srq->pointer, + sizeof(struct sockaddr) * number)) + return -EFAULT; + } + + /* Make sure nobody mess with the structure while we do */ + dldwd_lock(priv); + + /* dldwd_lock() doesn't disable interrupts, so make sure the + * interrupt rx path don't get confused while we copy */ + priv->spy_number = 0; + + if (number > 0) { + /* Extract the addresses */ + for (i = 0; i < number; i++) + memcpy(priv->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(priv->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + /* Set number of addresses */ + priv->spy_number = number; + } + + /* Time to show what we have done... */ + DEBUG(0, "%s: New spy list:\n", dev->name); + for (i = 0; i < number; i++) { + DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, i+1, + priv->spy_address[i][0], priv->spy_address[i][1], + priv->spy_address[i][2], priv->spy_address[i][3], + priv->spy_address[i][4], priv->spy_address[i][5]); + } + + /* Now, let the others play */ + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + struct iw_quality spy_stat[IW_MAX_SPY]; + int number; + int i; + + dldwd_lock(priv); + + number = priv->spy_number; + if ((number > 0) && (srq->pointer)) { + /* Create address struct */ + for (i = 0; i < number; i++) { + memcpy(address[i].sa_data, priv->spy_address[i], + ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats */ + /* In theory, we should disable irqs while copying the stats + * because the rx path migh update it in the middle... + * Bah, who care ? - Jean II */ + memcpy(&spy_stat, priv->spy_stat, + sizeof(struct iw_quality) * IW_MAX_SPY); + for (i=0; i < number; i++) + priv->spy_stat[i].updated = 0; + } + + dldwd_unlock(priv); + + /* Push stuff to user space */ + srq->length = number; + if(copy_to_user(srq->pointer, address, + sizeof(struct sockaddr) * number)) + return -EFAULT; + if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), + &spy_stat, sizeof(struct iw_quality) * number)) + return -EFAULT; + + return 0; +} + +int +dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + dldwd_priv_t *priv = dev->priv; + struct iwreq *wrq = (struct iwreq *)rq; + int err = 0; + int changed = 0; + + TRACE_ENTER(dev->name); + + /* In theory, we could allow most of the the SET stuff to be done + * In practice, the laps of time at startup when the card is not + * ready is very short, so why bother... + * Note that hw_ready is different from up/down (ifconfig), when + * the device is not yet up, it is usually already ready... + * Jean II */ + if (!priv->hw_ready) + return -ENODEV; + + switch (cmd) { + case SIOCGIWNAME: + DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); + strcpy(wrq->u.name, "IEEE 802.11-DS"); + break; + + case SIOCGIWAP: + DEBUG(1, "%s: SIOCGIWAP\n", dev->name); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); + break; + + case SIOCGIWRANGE: + DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); + err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); + break; + + case SIOCSIWMODE: + DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); + dldwd_lock(priv); + switch (wrq->u.mode) { + case IW_MODE_ADHOC: + if (! (priv->has_ibss || priv->has_port3) ) + err = -EINVAL; + else { + priv->iw_mode = IW_MODE_ADHOC; + changed = 1; + } + break; + + case IW_MODE_INFRA: + priv->iw_mode = IW_MODE_INFRA; + changed = 1; + break; + + default: + err = -EINVAL; + break; + } + set_port_type(priv); + dldwd_unlock(priv); + break; + + case SIOCGIWMODE: + DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); + dldwd_lock(priv); + wrq->u.mode = priv->iw_mode; + dldwd_unlock(priv); + break; + + case SIOCSIWENCODE: + DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); + if (! err) + changed = 1; + break; + + case SIOCGIWENCODE: + DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); + break; + + case SIOCSIWESSID: + DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); + err = dldwd_ioctl_setessid(dev, &wrq->u.essid); + if (! err) + changed = 1; + break; + + case SIOCGIWESSID: + DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); + err = dldwd_ioctl_getessid(dev, &wrq->u.essid); + break; + + case SIOCSIWNICKN: + DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); + err = dldwd_ioctl_setnick(dev, &wrq->u.data); + if (! err) + changed = 1; + break; + + case SIOCGIWNICKN: + DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); + err = dldwd_ioctl_getnick(dev, &wrq->u.data); + break; + + case SIOCGIWFREQ: + DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); + wrq->u.freq.m = dldwd_hw_get_freq(priv); + wrq->u.freq.e = 1; + break; + + case SIOCSIWFREQ: + DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); + err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); + if (! err) + changed = 1; + break; + + case SIOCGIWSENS: + DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); + err = dldwd_ioctl_getsens(dev, &wrq->u.sens); + break; + + case SIOCSIWSENS: + DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); + err = dldwd_ioctl_setsens(dev, &wrq->u.sens); + if (! err) + changed = 1; + break; + + case SIOCGIWRTS: + DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); + wrq->u.rts.value = priv->rts_thresh; + wrq->u.rts.disabled = (wrq->u.rts.value == 2347); + wrq->u.rts.fixed = 1; + break; + + case SIOCSIWRTS: + DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); + err = dldwd_ioctl_setrts(dev, &wrq->u.rts); + if (! err) + changed = 1; + break; + + case SIOCSIWFRAG: + DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); + err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); + if (! err) + changed = 1; + break; + + case SIOCGIWFRAG: + DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); + err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); + break; + + case SIOCSIWRATE: + DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); + err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); + if (! err) + changed = 1; + break; + + case SIOCGIWRATE: + DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); + err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); + break; + + case SIOCSIWPOWER: + DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); + err = dldwd_ioctl_setpower(dev, &wrq->u.power); + if (! err) + changed = 1; + break; + + case SIOCGIWPOWER: + DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); + err = dldwd_ioctl_getpower(dev, &wrq->u.power); + break; + + case SIOCGIWTXPOW: + DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); + /* The card only supports one tx power, so this is easy */ + wrq->u.txpower.value = 15; /* dBm */ + wrq->u.txpower.fixed = 1; + wrq->u.txpower.disabled = 0; + wrq->u.txpower.flags = IW_TXPOW_DBM; + break; + +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name); + err = -EOPNOTSUPP; + break; + + case SIOCGIWRETRY: + DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); + err = dldwd_ioctl_getretry(dev, &wrq->u.retry); + break; +#endif /* WIRELESS_EXT > 10 */ + + case SIOCSIWSPY: + DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); + + err = dldwd_ioctl_setspy(dev, &wrq->u.data); + break; + + case SIOCGIWSPY: + DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); + + err = dldwd_ioctl_getspy(dev, &wrq->u.data); + break; + + case SIOCGIWPRIV: + DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); + if (wrq->u.data.pointer) { + struct iw_priv_args privtab[] = { + { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, + { SIOCDEVPRIVATE + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_port3" }, + { SIOCDEVPRIVATE + 0x3, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_port3" }, + { SIOCDEVPRIVATE + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_preamble" }, + { SIOCDEVPRIVATE + 0x5, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_preamble" } + }; + + err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); + if (err) + break; + + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); + if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) + err = -EFAULT; + } + break; + + case SIOCDEVPRIVATE + 0x0: /* force_reset */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); + dldwd_reset(priv); + break; + + case SIOCDEVPRIVATE + 0x2: /* set_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_setport3(dev, wrq); + if (! err) + changed = 1; + break; + + case SIOCDEVPRIVATE + 0x3: /* get_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", + dev->name); + err = dldwd_ioctl_getport3(dev, wrq); + break; + + case SIOCDEVPRIVATE + 0x4: /* set_preamble */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + /* 802.11b has recently defined some short preamble. + * Basically, the Phy header has been reduced in size. + * This increase performance, especially at high rates + * (the preamble is transmitted at 1Mb/s), unfortunately + * this give compatibility troubles... - Jean II */ + if(priv->has_preamble) { + int val = *( (int *) wrq->u.name ); + + dldwd_lock(priv); + if(val) + priv->preamble = 1; + else + priv->preamble = 0; + dldwd_unlock(priv); + changed = 1; + } else + err = -EOPNOTSUPP; + break; + + case SIOCDEVPRIVATE + 0x5: /* get_preamble */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", + dev->name); + if(priv->has_preamble) { + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->preamble; + dldwd_unlock(priv); + } else + err = -EOPNOTSUPP; + break; + + default: + err = -EOPNOTSUPP; + } + + if (! err && changed && netif_running(dev)) { + err = dldwd_reset(priv); + if (err) { + /* Ouch ! What are we supposed to do ? */ + printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n", + dev->name); + netif_stop_queue(dev); + dldwd_shutdown(priv); + priv->hw_ready = 0; + } + } + + TRACE_EXIT(dev->name); + + return err; +} + +int +dldwd_change_mtu(struct net_device *dev, int new_mtu) +{ + TRACE_ENTER(dev->name); + + if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) + return -EINVAL; + + dev->mtu = new_mtu; + + TRACE_EXIT(dev->name); + + return 0; +} + +static void +__dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, allmulti, mc_count; + + /* We'll wait until it's ready. Anyway, the network doesn't call us + * here until we are open - Jean II */ + if (!priv->hw_ready) + return; + + + TRACE_ENTER(dev->name); + + DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", + dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count); + + /* The Hermes doesn't seem to have an allmulti mode, so we go + * into promiscuous mode and let the upper levels deal. */ + if ( (dev->flags & IFF_PROMISC) ) { + promisc = 1; + allmulti = 0; + mc_count = 0; + } else if ( (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > HERMES_MAX_MULTICAST) ) { + promisc = 0; + allmulti = 1; + mc_count = HERMES_MAX_MULTICAST; + } else { + promisc = 0; + allmulti = 0; + mc_count = dev->mc_count; + } + + DEBUG(3, "promisc=%d mc_count=%d\n", + promisc, mc_count); + + if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", + dev->name, err, promisc); + } else + priv->promiscuous = promisc; + } + + if (allmulti) { + /* FIXME: This method of doing allmulticast reception + comes from the NetBSD driver. Haven't actually + tested whether it works or not. */ + hermes_multicast_t mclist; + + memset(&mclist, 0, sizeof(mclist)); + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 1; + + } else if (mc_count || (! mc_count && priv->mc_count) ) { + struct dev_mc_list *p = dev->mc_list; + hermes_multicast_t mclist; + int i; + + for (i = 0; i < mc_count; i++) { + /* First some paranoid checks */ + if (! p) { + printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", + dev->name); + break; + } + if (p->dmi_addrlen != ETH_ALEN) { + + printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", + dev->name, p->dmi_addrlen); + break; + } + + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); + p = p->next; + } + + /* More paranoia */ + if (p) + printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", + dev->name); + + priv->mc_count = i; + + DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); + + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, + HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), + &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 0; + } + + /* Since we can set the promiscuous flag when it wasn't asked + for, make sure the net_device knows about it. */ + if (priv->promiscuous) + dev->flags |= IFF_PROMISC; + else + dev->flags &= ~IFF_PROMISC; + + if (priv->allmulti) + dev->flags |= IFF_ALLMULTI; + else + dev->flags &= ~IFF_ALLMULTI; + + TRACE_EXIT(dev->name); +} + +/* + * procfs stuff + */ + +static struct proc_dir_entry *dir_base = NULL; + +/* + * This function updates the total amount of data printed so far. It then + * determines if the amount of data printed into a buffer has reached the + * offset requested. If it hasn't, then the buffer is shifted over so that + * the next bit of data can be printed over the old bit. If the total + * amount printed so far exceeds the total amount requested, then this + * function returns 1, otherwise 0. + */ +static int + +shift_buffer(char *buffer, int requested_offset, int requested_len, + int *total, int *slop, char **buf) +{ + int printed; + + printed = *buf - buffer; + if (*total + printed <= requested_offset) { + *total += printed; + *buf = buffer; + } + else { + if (*total < requested_offset) { + *slop = requested_offset - *total; + } + *total = requested_offset + printed - *slop; + } + if (*total > requested_offset + requested_len) { + return 1; + } + else { + return 0; + } +} + +/* + * This function calculates the actual start of the requested data + * in the buffer. It also calculates actual length of data returned, + * which could be less that the amount of data requested. + */ +#define PROC_BUFFER_SIZE 4096 +#define PROC_SAFE_SIZE 3072 + +static int +calc_start_len(char *buffer, char **start, int requested_offset, + int requested_len, int total, char *buf) +{ + int return_len, buffer_len; + + buffer_len = buf - buffer; + if (buffer_len >= PROC_BUFFER_SIZE - 1) { + printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); + } + + /* + * There may be bytes before and after the + * chunk that was actually requested. + */ + return_len = total - requested_offset; + if (return_len < 0) { + return_len = 0; + } + *start = buf - return_len; + if (return_len > requested_len) { + return_len = requested_len; + } + return return_len; +} + +static int +dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + + /* Hum, in this case hardware register are probably not readable... */ + if (!dev->hw_ready) + return -ENODEV; + + buf = page; + +#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) + + DHERMESREG(CMD); + DHERMESREG(PARAM0); + DHERMESREG(PARAM1); + DHERMESREG(PARAM2); + DHERMESREG(STATUS); + DHERMESREG(RESP0); + DHERMESREG(RESP1); + DHERMESREG(RESP2); + DHERMESREG(INFOFID); + DHERMESREG(RXFID); + DHERMESREG(ALLOCFID); + DHERMESREG(TXCOMPLFID); + DHERMESREG(SELECT0); + DHERMESREG(OFFSET0); + DHERMESREG(SELECT1); + DHERMESREG(OFFSET1); + DHERMESREG(EVSTAT); + DHERMESREG(INTEN); + DHERMESREG(EVACK); + DHERMESREG(CONTROL); + DHERMESREG(SWSUPPORT0); + DHERMESREG(SWSUPPORT1); + DHERMESREG(SWSUPPORT2); + DHERMESREG(AUXPAGE); + DHERMESREG(AUXOFFSET); + DHERMESREG(AUXDATA); +#undef DHERMESREG + + shift_buffer(page, requested_offset, requested_len, &total, + &slop, &buf); + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +struct { + uint16_t rid; + char *name; + int minlen, maxlen; + int displaytype; +#define DISPLAY_WORDS 0 +#define DISPLAY_BYTES 1 +#define DISPLAY_STRING 2 +} record_table[] = { +#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } + RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), + RTCNFENTRY(MACADDR, DISPLAY_BYTES), + RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), + RTCNFENTRY(CHANNEL, DISPLAY_WORDS), + RTCNFENTRY(OWN_SSID, DISPLAY_STRING), + RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), + RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), + RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), + RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), + RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), + RTCNFENTRY(NICKNAME, DISPLAY_STRING), + RTCNFENTRY(WEP_ON, DISPLAY_WORDS), + RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), + RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), + RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), + RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), + RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), + RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), + RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), + RTCNFENTRY(KEYS, DISPLAY_BYTES), + RTCNFENTRY(TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(TICKTIME, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS), +#undef RTCNFENTRY +#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } + RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), + RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), + RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), + RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), + RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), + RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), + RTINFENTRY(DATARATES, DISPLAY_BYTES), +#undef RTINFENTRY +}; +#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) + +static int +dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + int i; + uint16_t length; + int err; + + /* Hum, in this case hardware register are probably not readable... */ + if (!dev->hw_ready) + return -ENODEV; + + buf = page; + + /* print out all the config RIDs */ + for (i = 0; i < NUM_RIDS; i++) { + uint16_t rid = record_table[i].rid; + int minlen = record_table[i].minlen; + int maxlen = record_table[i].maxlen; + int len; + uint8_t *val8; + uint16_t *val16; + int j; + + val8 = kmalloc(maxlen + 2, GFP_KERNEL); + if (! val8) + return -ENOMEM; + + err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, + &length, val8); + if (err) { + DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); + continue; + } + val16 = (uint16_t *)val8; + + buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, + rid, length, (length-1)*2); + len = MIN( MAX(minlen, (length-1)*2), maxlen); + + switch (record_table[i].displaytype) { + case DISPLAY_WORDS: + for (j = 0; j < len / 2; j++) { + buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); + } + buf--; + break; + + case DISPLAY_BYTES: + default: + for (j = 0; j < len; j++) { + buf += sprintf(buf, "%02X:", val8[j]); + } + buf--; + break; + + case DISPLAY_STRING: + len = MIN(len, le16_to_cpu(val16[0])+2); + val8[len] = '\0'; + buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); + break; + } + + buf += sprintf(buf, "\n"); + + kfree(val8); + + if (shift_buffer(page, requested_offset, requested_len, + &total, &slop, &buf)) + break; + + if ( (buf - page) > PROC_SAFE_SIZE ) + break; + } + + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +/* initialise the /proc subsystem for the hermes driver, creating the + * separate entries */ +static int +dldwd_proc_init(void) +{ + int err = 0; + + TRACE_ENTER("dldwd"); + + /* create the directory for it to sit in */ + dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); + if (dir_base == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); + dldwd_proc_cleanup(); + err = -ENOMEM; + } + + TRACE_EXIT("dldwd"); + + return err; +} + +int +dldwd_proc_dev_init(dldwd_priv_t *dev) +{ + struct net_device *ndev = &dev->ndev; + + dev->dir_dev = NULL; + /* create the directory for it to sit in */ + dev->dir_dev = create_proc_entry(ndev->name, S_IFDIR | S_IRUGO | S_IXUGO, + dir_base); + if (dev->dir_dev == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", ndev->name); + goto fail; + } + + dev->dir_regs = NULL; + dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_regs, dev); + if (dev->dir_regs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", ndev->name); + goto fail; + } + + dev->dir_recs = NULL; + dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_recs, dev); + if (dev->dir_recs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", ndev->name); + goto fail; + } + + return 0; + fail: + dldwd_proc_dev_cleanup(dev); + return -ENOMEM; +} + +void +dldwd_proc_dev_cleanup(dldwd_priv_t *priv) +{ + struct net_device *ndev = &priv->ndev; + + if (priv->dir_regs) { + remove_proc_entry("regs", priv->dir_dev); + priv->dir_regs = NULL; + } + if (priv->dir_recs) { + remove_proc_entry("recs", priv->dir_dev); + priv->dir_recs = NULL; + } + if (priv->dir_dev) { + remove_proc_entry(ndev->name, dir_base); + priv->dir_dev = NULL; + } +} + +static void +dldwd_proc_cleanup(void) +{ + TRACE_ENTER("dldwd"); + + if (dir_base) { + remove_proc_entry("hermes", &proc_root); + dir_base = NULL; + } + + TRACE_EXIT("dldwd"); +} + +int +dldwd_setup(dldwd_priv_t* priv) +{ + struct net_device *ndev = &priv->ndev;; + + spin_lock_init(&priv->lock); + + /* Set up the net_device */ + ether_setup(ndev); + ndev->priv = priv; + + /* Setup up default routines */ + ndev->init = dldwd_init; + ndev->open = NULL; /* Caller *must* override */ + ndev->stop = NULL; + ndev->hard_start_xmit = dldwd_xmit; + ndev->tx_timeout = dldwd_tx_timeout; + ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ + + ndev->get_stats = dldwd_get_stats; + ndev->get_wireless_stats = dldwd_get_wireless_stats; + + ndev->do_ioctl = dldwd_ioctl; + + ndev->change_mtu = dldwd_change_mtu; + ndev->set_multicast_list = dldwd_set_multicast_list; + + netif_stop_queue(ndev); + + return 0; +} + +#ifdef ORINOCO_DEBUG +EXPORT_SYMBOL(dldwd_debug); +#endif +EXPORT_SYMBOL(dldwd_init); +EXPORT_SYMBOL(dldwd_xmit); +EXPORT_SYMBOL(dldwd_tx_timeout); +EXPORT_SYMBOL(dldwd_ioctl); +EXPORT_SYMBOL(dldwd_change_mtu); +EXPORT_SYMBOL(dldwd_set_multicast_list); +EXPORT_SYMBOL(dldwd_shutdown); +EXPORT_SYMBOL(dldwd_reset); +EXPORT_SYMBOL(dldwd_setup); +EXPORT_SYMBOL(dldwd_proc_dev_init); +EXPORT_SYMBOL(dldwd_proc_dev_cleanup); +EXPORT_SYMBOL(dldwd_interrupt); + +static int __init init_dldwd(void) +{ + int err; + + err = dldwd_proc_init(); + + printk(KERN_INFO "%s\n", version); + + return 0; +} + +static void __exit exit_dldwd(void) +{ + dldwd_proc_cleanup(); +} + +module_init(init_dldwd); +module_exit(exit_dldwd); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/orinoco.h linux/drivers/net/wireless/orinoco.h --- v2.4.4/linux/drivers/net/wireless/orinoco.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/orinoco.h Mon May 7 19:42:14 2001 @@ -0,0 +1,145 @@ +/* orinoco.h + * + * Common definitions to all pieces of the various orinoco + * drivers + */ + +#ifndef _ORINOCO_H +#define _ORINOCO_H + +/* To enable debug messages */ +//#define ORINOCO_DEBUG 3 + +#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) +#error "orinoco_cs requires Wireless extensions v10 or later." +#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ +#define WIRELESS_SPY // enable iwspy support + + +#define DLDWD_MIN_MTU 256 +#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) + +#define LTV_BUF_SIZE 128 +#define USER_BAP 0 +#define IRQ_BAP 1 +#define DLDWD_MACPORT 0 +#define IRQ_LOOP_MAX 10 +#define TX_NICBUF_SIZE 2048 +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Intel firmware */ +#define MAX_KEYS 4 +#define MAX_KEY_SIZE 14 +#define LARGE_KEY_SIZE 13 +#define SMALL_KEY_SIZE 5 +#define MAX_FRAME_SIZE 2304 + +typedef struct dldwd_key { + uint16_t len; + char data[MAX_KEY_SIZE]; +} __attribute__ ((packed)) dldwd_key_t; + +typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; + +/*====================================================================*/ + + +typedef struct dldwd_priv { + void* card; /* Pointer to card dependant structure */ + + spinlock_t lock; + long state; +#define DLDWD_STATE_INIRQ 0 +#define DLDWD_STATE_DOIRQ 1 + int hw_ready; /* HW may be suspended by platform */ + + /* Net device stuff */ + struct net_device ndev; + struct net_device_stats stats; + struct iw_statistics wstats; + + + /* Hardware control variables */ + hermes_t hw; + uint16_t txfid; + + /* Capabilities of the hardware/firmware */ + hermes_identity_t firmware_info; + int firmware_type; +#define FIRMWARE_TYPE_LUCENT 1 +#define FIRMWARE_TYPE_PRISM2 2 +#define FIRMWARE_TYPE_SYMBOL 3 + int has_ibss, has_port3, prefer_port3, has_ibss_any; + int has_wep, has_big_wep; + int has_mwo; + int has_pm; + int has_preamble; + int broken_reset, broken_allocate; + uint16_t channel_mask; + + /* Current configuration */ + uint32_t iw_mode; + int port_type, allow_ibss; + uint16_t wep_on, wep_restrict, tx_key; + dldwd_keys_t keys; + char nick[IW_ESSID_MAX_SIZE+1]; + char desired_essid[IW_ESSID_MAX_SIZE+1]; + uint16_t frag_thresh, mwo_robust; + uint16_t channel; + uint16_t ap_density, rts_thresh; + uint16_t tx_rate_ctrl; + uint16_t pm_on, pm_mcast, pm_period, pm_timeout; + uint16_t preamble; + + int promiscuous, allmulti, mc_count; + +#ifdef WIRELESS_SPY + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#endif + + /* /proc based debugging stuff */ + struct proc_dir_entry *dir_dev; + struct proc_dir_entry *dir_regs; + struct proc_dir_entry *dir_recs; +} dldwd_priv_t; + +/*====================================================================*/ + +extern int dldwd_debug; +extern struct list_head dldwd_instances; + +#ifdef ORINOCO_DEBUG +#define DEBUG(n, args...) if (dldwd_debug>(n)) printk(KERN_DEBUG args) +#define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0) +#else +#define DEBUG(n, args...) do { } while (0) +#define DEBUGMORE(n, args...) do { } while (0) +#endif /* ORINOCO_DEBUG */ + +#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); +#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) + +/* struct net_device methods */ +extern int dldwd_init(struct net_device *dev); +extern int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); +extern void dldwd_tx_timeout(struct net_device *dev); + +extern int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +extern int dldwd_change_mtu(struct net_device *dev, int new_mtu); +extern void dldwd_set_multicast_list(struct net_device *dev); + +/* utility routines */ +extern void dldwd_shutdown(dldwd_priv_t *dev); +extern int dldwd_reset(dldwd_priv_t *dev); +extern int dldwd_setup(dldwd_priv_t* priv); +extern int dldwd_proc_dev_init(dldwd_priv_t *dev); +extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv); +extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); + + +#endif diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/orinoco_cs.c linux/drivers/net/wireless/orinoco_cs.c --- v2.4.4/linux/drivers/net/wireless/orinoco_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/orinoco_cs.c Mon May 7 19:42:14 2001 @@ -0,0 +1,789 @@ +/* orinoco_cs.c 0.05 - (formerly known as dldwd_cs.c) + * + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright notice & release notes in file orinoco.c + */ + +#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 "hermes.h" +#include "orinoco.h" + +/* Pcmcia specific structure */ +typedef struct dldwd_card { + dev_link_t link; + dev_node_t node; + int instance; + + /* Common structure (fully included), see orinoco.h */ + struct dldwd_priv priv; +} dldwd_card_t; + +static char *version = "orinoco_cs.c 0.05 (David Gibson and others)"; + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static uint irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; +/* Do a Pcmcia soft reset (may help some cards) */ +static int reset_cor = 0; +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but + * don't have any CIS entry for it. This workaround it... */ +static int ignore_cis_vcc = 0; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(reset_cor, "i"); +MODULE_PARM(ignore_cis_vcc, "i"); + +/* + * Function prototypes + */ + +/* struct net_device methods */ +static int dldwd_cs_open(struct net_device *dev); +static int dldwd_cs_stop(struct net_device *dev); + +/* PCMCIA gumpf */ +static void dldwd_cs_config(dev_link_t * link); +static void dldwd_cs_release(u_long arg); +static int dldwd_cs_event(event_t event, int priority, + event_callback_args_t * args); + +static dev_link_t *dldwd_cs_attach(void); +static void dldwd_cs_detach(dev_link_t *); + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "orinoco_cs"; + +/* + A linked list of "instances" of the dummy 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; +static int num_instances = 0; + +/*====================================================================*/ + +static void +cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +static int +dldwd_cs_open(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + dev_link_t *link = &card->link; + int err; + + TRACE_ENTER(priv->ndev.name); + + link->open++; + netif_device_attach(dev); + + err = dldwd_reset(priv); + if (err) + dldwd_cs_stop(dev); + else + netif_start_queue(dev); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int +dldwd_cs_stop(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dldwd_card_t* card = (dldwd_card_t *)priv->card; + dev_link_t *link = &card->link; + + TRACE_ENTER(priv->ndev.name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + link->open--; + + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + + TRACE_EXIT(priv->ndev.name); + + return 0; +} + +/*====================================================================== + dldwd_cs_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 * +dldwd_cs_attach(void) +{ + dldwd_card_t *card; + dldwd_priv_t *priv; + dev_link_t *link; + struct net_device *ndev; + client_reg_t client_reg; + int ret, i; + + TRACE_ENTER("dldwd"); + + /* Allocate space for private device-specific data */ + card = kmalloc(sizeof(*card), GFP_KERNEL); + if (! card) { + link = NULL; + goto out; + } + memset(card, 0, sizeof(*card)); + + /* Link both structure together */ + priv = &(card->priv); + priv->card = card; + card->instance = num_instances++; /* FIXME: Racy? */ + link = &card->link; + ndev = &priv->ndev; + link->priv = priv; + + /* Initialize the dev_link_t structure */ + link->release.function = &dldwd_cs_release; + link->release.data = (u_long) link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + 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 = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Setup the common part */ + if(dldwd_setup(priv) < 0) { + kfree(card); + return NULL; + } + + /* Overrides */ + ndev->open = dldwd_cs_open; + ndev->stop = dldwd_cs_stop; + + /* 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 = &dldwd_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + dldwd_cs_detach(link); + link = NULL; + goto out; + } + + out: + TRACE_EXIT("dldwd"); + return link; +} /* dldwd_cs_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 +dldwd_cs_detach(dev_link_t * link) +{ + dev_link_t **linkp; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER("dldwd"); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + goto out; + + /* + 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(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + goto out; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); + if (link->dev) { + DEBUG(0, "orinoco_cs: About to unregister net device %p\n", + &priv->ndev); + unregister_netdev(&priv->ndev); + } + kfree(priv->card); + + num_instances--; /* FIXME: Racy? */ + + out: + TRACE_EXIT("dldwd"); +} /* dldwd_cs_detach */ + +/* + * Do a soft reset of the Pcmcia card using the Configuration Option Register + * Can't do any harm, and actually may do some good on some cards... + */ +static int +dldwd_cs_cor_reset(dev_link_t *link) +{ + conf_reg_t reg; + u_long default_cor; + + /* Save original COR value */ + reg.Function = 0; + reg.Action = CS_READ; + reg.Offset = CISREG_COR; + reg.Value = 0; + CardServices(AccessConfigurationRegister, link->handle, ®); + default_cor = reg.Value; + + DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%lX\n", default_cor); + + /* Soft-Reset card */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_COR; + reg.Value = (default_cor | COR_SOFT_RESET); + CardServices(AccessConfigurationRegister, link->handle, ®); + + /* Wait until the card has acknowledged our reset */ + mdelay(1); + + /* Restore original COR configuration index */ + reg.Value = (default_cor & COR_CONFIG_MASK); + CardServices(AccessConfigurationRegister, link->handle, ®); + + /* Wait until the card has finished restarting */ + mdelay(1); + + return(0); +} + +/*====================================================================== + dldwd_cs_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 + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void +dldwd_cs_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + dldwd_priv_t *priv = link->priv; + dldwd_card_t *card = (dldwd_card_t *)priv->card; + hermes_t *hw = &priv->hw; + struct net_device *ndev = &priv->ndev; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + cistpl_cftable_entry_t dflt = { 0 }; + cisinfo_t info; + + TRACE_ENTER("dldwd"); + + CS_CHECK(ValidateCIS, handle, &info); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + 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; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", + link->conf.ConfigBase, link->conf.Vcc); + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n", + cfg->index, cfg->flags); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if(!ignore_cis_vcc) + goto next_entry; + } + } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + if(!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + DEBUG(0, "dldwd_cs_config: We seem to have configured Vcc and Vpp\n"); + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = + (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = + io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = + link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + + /* If we got this far, we're cool! */ + + break; + + next_entry: + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + int i; + + 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 = dldwd_interrupt; + link->irq.Instance = priv; + + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } + + /* We initialize the hermes structure before completing PCMCIA + configuration just in case the interrupt handler gets + called. */ + hermes_struct_init(hw, link->io.BasePort1); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + ndev->base_addr = link->io.BasePort1; + ndev->irq = link->irq.AssignedIRQ; + + /* Do a Pcmcia soft reset of the card (optional) */ + if(reset_cor) + dldwd_cs_cor_reset(link); + + /* register_netdev will give us an ethX name */ + ndev->name[0] = '\0'; + /* Tell the stack we exist */ + if (register_netdev(ndev) != 0) { + printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); + goto failed; + } + strcpy(card->node.dev_name, ndev->name); + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + ndev->name, link->conf.ConfigIndex, + link->conf.Vcc / 10, link->conf.Vcc % 10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1 / 10, + link->conf.Vpp1 % 10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2 + link->io.NumPorts2 - 1); + printk("\n"); + + /* Allow /proc & ioctls to act */ + priv->hw_ready = 1; + + /* And give us the proc nodes for debugging */ + if (dldwd_proc_dev_init(priv) != 0) { + printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", + ndev->name); + goto failed; + } + + /* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */ + SET_MODULE_OWNER(ndev); + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + card->node.major = card->node.minor = 0; + link->dev = &card->node; + link->state &= ~DEV_CONFIG_PENDING; + + TRACE_EXIT("dldwd"); + + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + failed: + dldwd_cs_release((u_long) link); + + TRACE_EXIT("dldwd"); +} /* dldwd_cs_config */ + +/*====================================================================== + After a card is removed, dldwd_cs_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + ======================================================================*/ + +static void +dldwd_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER(link->dev->dev_name); + + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unregister proc entry */ + dldwd_proc_dev_cleanup(priv); + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + TRACE_EXIT(link->dev->dev_name); +} /* dldwd_cs_release */ + +/*====================================================================== + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private 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 +dldwd_cs_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; + struct net_device *dev = &priv->ndev; + + TRACE_ENTER("dldwd"); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + priv->hw_ready = 0; + dldwd_shutdown(priv); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_stop_queue(dev); + netif_device_detach(dev); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dldwd_cs_config(link); + break; + case CS_EVENT_PM_SUSPEND: + + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + dldwd_shutdown(priv); + /* Mark the device as stopped, to block IO until later */ + + if (link->state & DEV_CONFIG) { + if (link->open) { + netif_stop_queue(dev); + netif_device_detach(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) { + if (dldwd_reset(priv) == 0) { + netif_device_attach(dev); + netif_start_queue(dev); + } else { + printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", + dev->name); + dldwd_cs_stop(dev); + } + } + } + /* + In a normal driver, additional code may go here to restore + the device state and restart IO. + */ + break; + } + + TRACE_EXIT("dldwd"); + + return 0; +} /* dldwd_cs_event */ + +static int __init +init_dldwd_cs(void) +{ + servinfo_t serv; + + TRACE_ENTER("dldwd"); + + printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); + + DEBUG(0, "%s\n", version); + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "orinoco_cs: Card Services release " + "does not match!\n"); + return -1; + } + + register_pccard_driver(&dev_info, &dldwd_cs_attach, &dldwd_cs_detach); + + + TRACE_EXIT("dldwd"); + return 0; +} + +static void __exit +exit_dldwd_cs(void) +{ + TRACE_ENTER("dldwd"); + + unregister_pccard_driver(&dev_info); + + if (dev_list) + DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); + while (dev_list != NULL) { + del_timer(&dev_list->release); + if (dev_list->state & DEV_CONFIG) + dldwd_cs_release((u_long) dev_list); + dldwd_cs_detach(dev_list); + } + + TRACE_EXIT("dldwd"); +} + +module_init(init_dldwd_cs); +module_exit(exit_dldwd_cs); diff -u --recursive --new-file v2.4.4/linux/drivers/net/wireless/todo.txt linux/drivers/net/wireless/todo.txt --- v2.4.4/linux/drivers/net/wireless/todo.txt Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wireless/todo.txt Mon May 7 19:42:14 2001 @@ -0,0 +1,24 @@ + Wireless Todo + ------------- + +1) Bring other kernel Wireless LAN drivers here + Already done : + o hermes.c/orinoco.c -> Wavelan IEEE driver + Airport driver + Drivers I have control over : + o wavelan.c -> old Wavelan ISA driver + o wavelan_cs.c -> old Wavelan Pcmcia driver (warning : header) + o netwave_cs.c -> Netwave Pcmcia driver + Drivers likely to go : + o ray_cs.c -> Raytheon/Aviator driver (maintainer MIA) + Drivers I have absolutely no control over : + o arlan.c -> old Aironet Arlan 655 (need to ask Elmer) + o aironet4500_xxx.c -> Elmer's Aironet driver (need to ask Elmer) + o airo.c/airo_cs.c -> Ben's Aironet driver (not yet in kernel) + o strip.c -> Metricom's stuff. Not a wlan. Hum... + + ETA : Kernel 2.5.X + +2) Bring new Wireless LAN driver not yet in the kernel there + See my web page for details + + Jean II diff -u --recursive --new-file v2.4.4/linux/drivers/parport/parport_mfc3.c linux/drivers/parport/parport_mfc3.c --- v2.4.4/linux/drivers/parport/parport_mfc3.c Mon Nov 27 17:11:26 2000 +++ linux/drivers/parport/parport_mfc3.c Tue May 1 16:05:00 2001 @@ -91,7 +91,7 @@ static unsigned char mfc3_read_data(struct parport *p) { - /* clears interupt bit. Triggers also /STROBE. */ + /* clears interrupt bit. Triggers also /STROBE. */ return pia(p)->pprb; } diff -u --recursive --new-file v2.4.4/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.4.4/linux/drivers/pci/pci.c Thu Apr 19 08:38:48 2001 +++ linux/drivers/pci/pci.c Tue May 1 16:05:00 2001 @@ -843,7 +843,7 @@ * Ugh. We don't know enough about this bridge. Just assume * that it's entirely transparent. */ - printk("Unknown bridge resource %d: assuming transparent\n", 0); + printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0); child->resource[0] = child->parent->resource[0]; } @@ -859,7 +859,7 @@ res->name = child->name; } else { /* See comment above. Same thing */ - printk("Unknown bridge resource %d: assuming transparent\n", 1); + printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1); child->resource[1] = child->parent->resource[1]; } @@ -886,7 +886,7 @@ res->name = child->name; } else { /* See comments above */ - printk("Unknown bridge resource %d: assuming transparent\n", 2); + printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2); child->resource[2] = child->parent->resource[2]; } } diff -u --recursive --new-file v2.4.4/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c --- v2.4.4/linux/drivers/pcmcia/i82365.c Sat Mar 3 10:50:29 2001 +++ linux/drivers/pcmcia/i82365.c Tue May 1 16:05:00 2001 @@ -257,23 +257,31 @@ /*====================================================================*/ +static spinlock_t bus_lock = SPIN_LOCK_UNLOCKED; + static u_char i365_get(u_short sock, u_short reg) { + unsigned long flags; + spin_lock_irqsave(&bus_lock,flags); { ioaddr_t port = socket[sock].ioaddr; u_char val; reg = I365_REG(socket[sock].psock, reg); outb(reg, port); val = inb(port+1); + spin_unlock_irqrestore(&bus_lock,flags); return val; } } static void i365_set(u_short sock, u_short reg, u_char data) { + unsigned long flags; + spin_lock_irqsave(&bus_lock,flags); { ioaddr_t port = socket[sock].ioaddr; u_char val = I365_REG(socket[sock].psock, reg); outb(val, port); outb(data, port+1); + spin_unlock_irqrestore(&bus_lock,flags); } } @@ -872,6 +880,13 @@ events = pending_events[i]; pending_events[i] = 0; spin_unlock_irq(&pending_event_lock); + /* + SS_DETECT events need a small delay here. The reason for this is that + the "is there a card" electronics need time to see the card after the + "we have a card coming in" electronics have seen it. + */ + if (events & SS_DETECT) + mdelay(2); if (socket[i].handler) socket[i].handler(socket[i].info, events); } @@ -881,6 +896,8 @@ routine: pcic_bh }; +static unsigned long last_detect_jiffies; + static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs) { @@ -906,6 +923,20 @@ continue; } events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; + + + /* Several sockets will send multiple "new card detected" + events in rapid succession. However, the rest of the pcmcia expects + only one such event. We just ignore these events by having a + timeout */ + + if (events) { + if ((jiffies - last_detect_jiffies)<(HZ/20)) + events = 0; + last_detect_jiffies = jiffies; + + } + if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD) events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; else { @@ -970,6 +1001,7 @@ status = i365_get(sock, I365_STATUS); *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; + if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; else { @@ -1247,7 +1279,7 @@ i = i365_get_pair(sock, base+I365_W_START); mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0; mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0; - mem->sys_start += ((u_long)(i & 0x0fff) << 12); + mem->sys_start = ((u_long)(i & 0x0fff) << 12); i = i365_get_pair(sock, base+I365_W_STOP); mem->speed = (i & I365_MEM_WS0) ? 1 : 0; diff -u --recursive --new-file v2.4.4/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.4.4/linux/drivers/sbus/char/su.c Thu Apr 26 22:17:26 2001 +++ linux/drivers/sbus/char/su.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.47 2001/04/18 21:06:15 davem Exp $ +/* $Id: su.c,v 1.48 2001/04/27 07:02:42 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2220,7 +2220,7 @@ */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.47 $"; + char *revision = "$Revision: 1.48 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.4.4/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.4.4/linux/drivers/sbus/char/zs.c Thu Apr 26 22:17:26 2001 +++ linux/drivers/sbus/char/zs.c Tue May 1 20:59:24 2001 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.63 2001/04/17 06:30:36 davem Exp $ +/* $Id: zs.c,v 1.64 2001/04/27 07:02:42 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1922,7 +1922,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.63 $"; + char *revision = "$Revision: 1.64 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.4.4/linux/drivers/scsi/Makefile Mon Mar 26 15:36:30 2001 +++ linux/drivers/scsi/Makefile Fri May 4 15:16:28 2001 @@ -6,6 +6,12 @@ # # 20 Sep 2000, Torben Mathiasen # Changed link order to reflect new scsi initialization. +# +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! +# The link order must be, SCSI Core, SCSI HBA drivers, and +# lastly SCSI peripheral drivers (disk/tape/cdrom/etc.) to +# satisfy certain initialization assumptions in the SCSI layer. +# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! O_TARGET := scsidrv.o @@ -64,6 +70,9 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +ifeq ($(CONFIG_SCSI_AIC7XXX),y) +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o +endif obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_IPS) += ips.o obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.4.4/linux/drivers/scsi/aha1542.c Tue Mar 6 19:44:37 2001 +++ linux/drivers/scsi/aha1542.c Tue May 1 16:05:00 2001 @@ -254,7 +254,7 @@ /* Only used at boot time, so we do not need to worry about latency as much here */ -static int aha1542_in(unsigned int base, unchar * cmdp, int len) +static int __init aha1542_in(unsigned int base, unchar * cmdp, int len) { unsigned long flags; @@ -276,7 +276,7 @@ /* Similar to aha1542_in, except that we wait a very short period of time. We use this if we know the board is alive and awake, but we are not sure if the board will respond to the command we are about to send or not */ -static int aha1542_in1(unsigned int base, unchar * cmdp, int len) +static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len) { unsigned long flags; @@ -886,7 +886,7 @@ /* This function should only be called for 1542C boards - we can detect the special firmware settings and unlock the board */ -static int aha1542_mbenable(int base) +static int __init aha1542_mbenable(int base) { static unchar mbenable_cmd[3]; static unchar mbenable_result[2]; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/Config.in linux/drivers/scsi/aic7xxx/Config.in --- v2.4.4/linux/drivers/scsi/aic7xxx/Config.in Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/Config.in Fri May 4 15:16:28 2001 @@ -2,6 +2,7 @@ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253 - int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY 5000 + int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY_MS 15000 + bool ' Build Adapter Firmware with Kernel Build' CONFIG_AIC7XXX_BUILD_FIRMWARE fi fi diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/Makefile linux/drivers/scsi/aic7xxx/Makefile --- v2.4.4/linux/drivers/scsi/aic7xxx/Makefile Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/Makefile Fri May 4 15:16:28 2001 @@ -4,7 +4,7 @@ # Makefile for the Linux aic7xxx SCSI driver. # -O_TARGET = aic7xxx_drv.o +O_TARGET := aic7xxx_drv.o list-multi := aic7xxx_mod.o @@ -25,8 +25,13 @@ aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) $(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS) +ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq +else +aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg + echo "Warning, generated aic7xxx firmware files may be out of date!\n" +endif aicasm/aicasm: aicasm/*.[chyl] $(MAKE) -C aicasm diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7770.c linux/drivers/scsi/aic7xxx/aic7770.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7770.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7770.c Fri May 4 15:16:28 2001 @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7770.c#6 $ + * $Id: //depot/src/aic7xxx/aic7770.c#11 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $ */ @@ -95,8 +95,6 @@ u_int hostconf; u_int irq; u_int intdef; - u_int hcntrl; - int shared; ahc_init_probe_config(&probe_config); error = entry->setup(ahc->dev_softc, &probe_config); @@ -107,15 +105,15 @@ if (error != 0) return (error); - /* Pause the card preseving the IRQ type */ - hcntrl = ahc_inb(ahc, HCNTRL) & IRQMS; - ahc_outb(ahc, HCNTRL, hcntrl | PAUSE); - while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) - ; + probe_config.description = entry->name; + error = ahc_softc_init(ahc, &probe_config); + + error = ahc_reset(ahc); + if (error != 0) + return (error); /* Make sure we have a valid interrupt vector */ intdef = ahc_inb(ahc, INTDEF); - shared = (intdef & EDGE_TRIG) ? 0 : 1; irq = intdef & VECTOR; switch (irq) { case 9: @@ -130,16 +128,8 @@ return (ENXIO); } - probe_config.description = entry->name; - error = ahc_softc_init(ahc, &probe_config); - - error = aic7770_map_int(ahc, irq, shared); - if (error != 0) - return (error); - - error = ahc_reset(ahc); - if (error != 0) - return (error); + if ((intdef & EDGE_TRIG) != 0) + ahc->flags |= AHC_EDGE_INTERRUPT; switch (probe_config.chip & (AHC_EISA|AHC_VL)) { case AHC_EISA: @@ -154,7 +144,7 @@ /* Get the primary channel information */ if ((biosctrl & CHANNEL_B_PRIMARY) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= 1; if ((biosctrl & BIOSMODE) == BIOSDISABLED) { ahc->flags |= AHC_USEDEFAULTS; @@ -210,10 +200,19 @@ */ ahc_softc_insert(ahc); + error = aic7770_map_int(ahc, irq); + if (error != 0) + return (error); + /* * Enable the board's BUS drivers */ ahc_outb(ahc, BCTL, ENABLE); + + /* + * Allow interrupts. + */ + ahc_intr_enable(ahc, TRUE); return (0); } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7770_linux.c linux/drivers/scsi/aic7xxx/aic7770_linux.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7770_linux.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7770_linux.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#5 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#7 $ */ #include "aic7xxx_osm.h" @@ -128,19 +128,18 @@ } int -aic7770_map_int(struct ahc_softc *ahc, u_int irq, int shared) +aic7770_map_int(struct ahc_softc *ahc, u_int irq) { int error; + int shared; - if (shared) + shared = 0; + if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) shared = SA_SHIRQ; ahc->platform_data->irq = irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|shared, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - shared, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + shared, "aic7xxx", ahc); return (-error); } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.c#32 $ + * $Id: //depot/src/aic7xxx/aic7xxx.c#39 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ */ @@ -58,9 +58,17 @@ "aic7892", "aic7899" }; -const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); +static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); -struct hard_error_entry hard_error[] = { +/* + * Hardware error codes. + */ +struct ahc_hard_error_entry { + uint8_t errno; + char *errmesg; +}; + +static struct ahc_hard_error_entry ahc_hard_errors[] = { { ILLHADDR, "Illegal Host Access" }, { ILLSADDR, "Illegal Sequencer Address referrenced" }, { ILLOPCODE, "Illegal Opcode in sequencer program" }, @@ -70,9 +78,9 @@ { PCIERRSTAT, "PCI Error detected" }, { CIOPARERR, "CIOBUS Parity Error" }, }; -const u_int num_errors = NUM_ELEMENTS(hard_error); +static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors); -struct phase_table_entry phase_table[] = +static struct ahc_phase_table_entry ahc_phase_table[] = { { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, @@ -90,14 +98,14 @@ * In most cases we only wish to itterate over real phases, so * exclude the last element from the count. */ -const u_int num_phases = NUM_ELEMENTS(phase_table) - 1; +static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1; /* * Valid SCSIRATE values. (p. 3-17) * Provides a mapping of tranfer periods in ns to the proper value to * stick in the scsixfer reg. */ -struct ahc_syncrate ahc_syncrates[] = +static struct ahc_syncrate ahc_syncrates[] = { /* ultra2 fast/ultra period rate */ { 0x42, 0x000, 9, "80.0" }, @@ -121,7 +129,7 @@ #include "aic7xxx_seq.h" /**************************** Function Declarations ***************************/ -static struct tmode_tstate* +static struct ahc_tmode_tstate* ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel); #ifdef AHC_TARGET_MODE @@ -134,12 +142,13 @@ u_int *period, u_int *ppr_options, role_t role); -static void ahc_update_pending_syncrates(struct ahc_softc *ahc); +static void ahc_update_pending_scbs(struct ahc_softc *ahc); static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); static void ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); +static void ahc_assert_atn(struct ahc_softc *ahc); static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); @@ -174,6 +183,11 @@ struct ahc_devinfo *devinfo, cam_status status, char *message, int verbose_level); +#if AHC_TARGET_MODE +static void ahc_setup_target_msgin(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +#endif static bus_dmamap_callback_t ahc_dmamap_cb; static void ahc_build_free_scb_list(struct ahc_softc *ahc); @@ -192,7 +206,6 @@ char channel, int lun, u_int tag, role_t role, uint32_t status); static void ahc_reset_current_bus(struct ahc_softc *ahc); -static void ahc_calc_residual(struct scb *scb); #ifdef AHC_DUMP_SEQ static void ahc_dumpseq(struct ahc_softc *ahc); #endif @@ -204,7 +217,7 @@ u_int instrptr, uint8_t *dconsts); #ifdef AHC_TARGET_MODE static void ahc_queue_lstate_event(struct ahc_softc *ahc, - struct tmode_lstate *lstate, + struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg); @@ -218,10 +231,10 @@ * Restart the sequencer program from address zero */ void -restart_sequencer(struct ahc_softc *ahc) +ahc_restart(struct ahc_softc *ahc) { - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ @@ -259,7 +272,7 @@ ahc_outb(ahc, SEQCTL, FASTMODE); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); - unpause_sequencer(ahc); + ahc_unpause(ahc); } /************************* Input/Output Queues ********************************/ @@ -300,10 +313,7 @@ * Save off the residual * if there is one. */ - if (ahc_check_residual(scb) != 0) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + ahc_update_residual(scb); ahc_done(ahc, scb); } } @@ -340,14 +350,14 @@ * We upset the sequencer :-( * Lookup the error message */ - int i, error, num_errors; + int i; + int error; error = ahc_inb(ahc, ERROR); - num_errors = sizeof(hard_error)/sizeof(hard_error[0]); for (i = 0; error != 1 && i < num_errors; i++) error >>= 1; printf("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), hard_error[i].errmesg, + ahc_name(ahc), ahc_hard_errors[i].errmesg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); @@ -436,6 +446,12 @@ break; case SCSI_STATUS_CMD_TERMINATED: case SCSI_STATUS_CHECK_COND: + { + struct ahc_dma_seg *sg; + struct scsi_sense *sc; + struct ahc_initiator_tinfo *targ_info; + struct ahc_tmode_tstate *tstate; + struct ahc_transinfo *tinfo; #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { ahc_print_path(ahc, scb); @@ -444,99 +460,94 @@ } #endif - if (ahc_perform_autosense(scb)) { - struct ahc_dma_seg *sg; - struct scsi_sense *sc; - struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; - struct ahc_transinfo *tinfo; + if (ahc_perform_autosense(scb) == 0) + break; - targ_info = - ahc_fetch_transinfo(ahc, + targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, devinfo.our_scsiid, devinfo.target, &tstate); - tinfo = &targ_info->current; - sg = scb->sg_list; - sc = (struct scsi_sense *) - (&hscb->shared_data.cdb); - /* - * Save off the residual if there is one. - */ - if (ahc_check_residual(scb)) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + tinfo = &targ_info->curr; + sg = scb->sg_list; + sc = (struct scsi_sense *)(&hscb->shared_data.cdb); + /* + * Save off the residual if there is one. + */ + ahc_update_residual(scb); #ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOWSENSE) { - ahc_print_path(ahc, scb); - printf("Sending Sense\n"); - } + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("Sending Sense\n"); + } #endif - sg->addr = ahc_get_sense_bufaddr(ahc, scb); - sg->len = ahc_get_sense_bufsize(ahc, scb); - sg->len |= AHC_DMA_LAST_SEG; - - /* Fixup byte order */ - sg->addr = ahc_htole32(sg->addr); - sg->len = ahc_htole32(sg->len); - - sc->opcode = REQUEST_SENSE; - sc->byte2 = 0; - if (tinfo->protocol_version <= SCSI_REV_2 - && SCB_GET_LUN(scb) < 8) - sc->byte2 = SCB_GET_LUN(scb) << 5; - sc->unused[0] = 0; - sc->unused[1] = 0; - sc->length = sg->len; - sc->control = 0; + sg->addr = ahc_get_sense_bufaddr(ahc, scb); + sg->len = ahc_get_sense_bufsize(ahc, scb); + sg->len |= AHC_DMA_LAST_SEG; + + /* Fixup byte order */ + sg->addr = ahc_htole32(sg->addr); + sg->len = ahc_htole32(sg->len); + + sc->opcode = REQUEST_SENSE; + sc->byte2 = 0; + if (tinfo->protocol_version <= SCSI_REV_2 + && SCB_GET_LUN(scb) < 8) + sc->byte2 = SCB_GET_LUN(scb) << 5; + sc->unused[0] = 0; + sc->unused[1] = 0; + sc->length = sg->len; + sc->control = 0; - /* - * XXX Still true??? - * Would be nice to preserve DISCENB here, - * but due to the way we manage busy targets, - * we can't. - */ - hscb->control = 0; + /* + * We can't allow the target to disconnect. + * This will be an untagged transaction and + * having the target disconnect will make this + * transaction indestinguishable from outstanding + * tagged transactions. + */ + hscb->control = 0; - /* - * This request sense could be because the - * the device lost power or in some other - * way has lost our transfer negotiations. - * Renegotiate if appropriate. Unit attention - * errors will be reported before any data - * phases occur. - */ - if (ahc_get_residual(scb) - == ahc_get_transfer_length(scb)) { - ahc_update_target_msg_request(ahc, - &devinfo, - targ_info, - /*force*/TRUE, - /*paused*/TRUE); - } - hscb->cdb_len = sizeof(*sc); - hscb->dataptr = sg->addr; - hscb->datacnt = sg->len; - hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; - hscb->sgptr = ahc_htole32(hscb->sgptr); - scb->sg_count = 1; - scb->flags |= SCB_SENSE; - ahc_qinfifo_requeue_tail(ahc, scb); - ahc_outb(ahc, RETURN_1, SEND_SENSE); + /* + * This request sense could be because the + * the device lost power or in some other + * way has lost our transfer negotiations. + * Renegotiate if appropriate. Unit attention + * errors will be reported before any data + * phases occur. + */ + if (ahc_get_residual(scb) + == ahc_get_transfer_length(scb)) { + ahc_update_neg_request(ahc, &devinfo, + tstate, targ_info, + /*force*/TRUE); + } + if (tstate->auto_negotiate & devinfo.target_mask) { + hscb->control |= MK_MESSAGE; + scb->flags &= ~SCB_NEGOTIATE; + scb->flags |= SCB_AUTO_NEGOTIATE; + } + hscb->cdb_len = sizeof(*sc); + hscb->dataptr = sg->addr; + hscb->datacnt = sg->len; + hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; + hscb->sgptr = ahc_htole32(hscb->sgptr); + scb->sg_count = 1; + scb->flags |= SCB_SENSE; + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, RETURN_1, SEND_SENSE); #ifdef __FreeBSD__ - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - untimeout(ahc_timeout, (caddr_t)scb, - scb->io_ctx->ccb_h.timeout_ch); - scb->io_ctx->ccb_h.timeout_ch = - timeout(ahc_timeout, (caddr_t)scb, 5 * hz); + /* + * Ensure we have enough time to actually + * retrieve the sense. + */ + untimeout(ahc_timeout, (caddr_t)scb, + scb->io_ctx->ccb_h.timeout_ch); + scb->io_ctx->ccb_h.timeout_ch = + timeout(ahc_timeout, (caddr_t)scb, 5 * hz); #endif - } break; + } default: break; } @@ -577,7 +588,7 @@ ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO); + ahc_assert_atn(ahc); break; } case SEND_REJECT: @@ -633,7 +644,7 @@ "Lastphase = 0x%x, Curphase = 0x%x\n", ahc_name(ahc), devinfo.channel, devinfo.target, lastphase, ahc_inb(ahc, SCSISIGI)); - restart_sequencer(ahc); + ahc_restart(ahc); return; } case HOST_MSG_LOOP: @@ -650,6 +661,8 @@ * loop. */ if (ahc->msg_type == MSG_TYPE_NONE) { + struct scb *scb; + u_int scb_index; u_int bus_phase; bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; @@ -663,17 +676,13 @@ * we got here. Just punt the message. */ ahc_clear_intstat(ahc); - restart_sequencer(ahc); + ahc_restart(ahc); return; } + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); if (devinfo.role == ROLE_INITIATOR) { - struct scb *scb; - u_int scb_index; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) panic("HOST_MSG_LOOP with " "invalid SCB %x\n", scb_index); @@ -695,7 +704,9 @@ } #if AHC_TARGET_MODE else - ahc_setup_target_msgin(ahc, &devinfo); + ahc_setup_target_msgin(ahc, + &devinfo, + scb); #endif } } @@ -718,17 +729,20 @@ */ if ((intstat & SCSIINT) == 0 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { - u_int curphase; - /* - * The hardware will only let you ack bytes - * if the expected phase in SCSISIGO matches - * the current phase. Make sure this is - * currently the case. - */ - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - ahc_outb(ahc, LASTPHASE, curphase); - ahc_outb(ahc, SCSISIGO, curphase); + if ((ahc->features & AHC_DT) == 0) { + u_int curphase; + + /* + * The hardware will only let you ack bytes + * if the expected phase in SCSISIGO matches + * the current phase. Make sure this is + * currently the case. + */ + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + ahc_outb(ahc, LASTPHASE, curphase); + ahc_outb(ahc, SCSISIGO, curphase); + } ahc_inb(ahc, SCSIDATL); } break; @@ -749,13 +763,13 @@ scb = ahc_lookup_scb(ahc, scbindex); for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } ahc_print_path(ahc, scb); printf("data overrun detected %s." " Tag == 0x%x.\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, scb->hscb->tag); ahc_print_path(ahc, scb); printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", @@ -858,7 +872,7 @@ * a SEQINT, so we should restart it when * we're done. */ - unpause_sequencer(ahc); + ahc_unpause(ahc); } void @@ -897,7 +911,7 @@ if (status == 0) { printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); return; } } @@ -975,10 +989,10 @@ errorphase = lastphase; for (i = 0; i < num_phases; i++) { - if (errorphase == phase_table[i].phase) + if (errorphase == ahc_phase_table[i].phase) break; } - mesg_out = phase_table[i].mesg_out; + mesg_out = ahc_phase_table[i].mesg_out; if (scb != NULL) ahc_print_path(ahc, scb); else @@ -987,7 +1001,7 @@ scsirate = ahc_inb(ahc, SCSIRATE); printf("parity error detected %s. " "SEQADDR(0x%x) SCSIRATE(0x%x)\n", - phase_table[i].phasemsg, + ahc_phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), scsirate); @@ -1018,7 +1032,45 @@ ahc_outb(ahc, MSG_OUT, mesg_out); } ahc_outb(ahc, CLRINT, CLRSCSIINT); - unpause_sequencer(ahc); + ahc_unpause(ahc); + } else if ((status & SELTO) != 0) { + u_int scbptr; + + /* Stop the selection */ + ahc_outb(ahc, SCSISEQ, 0); + + /* No more pending messages */ + ahc_clear_msg_state(ahc); + + /* Clear interrupt state */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); + + /* + * Although the driver does not care about the + * 'Selection in Progress' status bit, the busy + * LED does. SELINGO is only cleared by a sucessful + * selection, so we must manually clear it to insure + * the LED turns off just incase no future successful + * selections occur (e.g. no devices on the bus). + */ + ahc_outb(ahc, CLRSINT0, CLRSELINGO); + + scbptr = ahc_inb(ahc, WAITING_SCBH); + ahc_outb(ahc, SCBPTR, scbptr); + scb_index = ahc_inb(ahc, SCB_TAG); + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: ahc_intr - referenced scb not " + "valid during SELTO scb(%d, %d)\n", + ahc_name(ahc), scbptr, scb_index); + } else { + ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); + ahc_freeze_devq(ahc, scb); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_restart(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { u_int lastphase; @@ -1113,7 +1165,7 @@ } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, FALSE)) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; /* * PPR Rejected. Try non-ppr negotiation @@ -1124,7 +1176,7 @@ devinfo.our_scsiid, devinfo.target, &tstate); - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; tinfo->goal.ppr_options = 0; ahc_qinfifo_requeue_tail(ahc, scb); @@ -1174,54 +1226,18 @@ printf("%s: ", ahc_name(ahc)); } for (i = 0; i < num_phases; i++) { - if (lastphase == phase_table[i].phase) + if (lastphase == ahc_phase_table[i].phase) break; } printf("Unexpected busfree %s\n" "SEQADDR == 0x%x\n", - phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) + ahc_phase_table[i].phasemsg, + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); } ahc_clear_msg_state(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); - } else if ((status & SELTO) != 0) { - u_int scbptr; - - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - /* No more pending messages */ - ahc_clear_msg_state(ahc); - - /* Clear interrupt state */ - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); - - /* - * Although the driver does not care about the - * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a sucessful - * selection, so we must manually clear it to insure - * the LED turns off just incase no future successful - * selections occur (e.g. no devices on the bus). - */ - ahc_outb(ahc, CLRSINT0, CLRSELINGO); - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d, %d)\n", - ahc_name(ahc), scbptr, scb_index); - } else { - ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); - ahc_freeze_devq(ahc, scb); - } - ahc_outb(ahc, CLRINT, CLRSCSIINT); - restart_sequencer(ahc); + ahc_restart(ahc); } else { printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", ahc_name(ahc), status); @@ -1290,7 +1306,7 @@ ahc_outb(ahc, HCNTRL, ahc->unpause); do { ahc_delay(200); - } while (!sequencer_paused(ahc)); + } while (!ahc_is_paused(ahc)); } if (stepping) { ahc_outb(ahc, SIMODE0, simode0); @@ -1363,11 +1379,11 @@ * Allocate per target mode instance (ID we respond to as a target) * transfer negotiation data structures. */ -static struct tmode_tstate * +static struct ahc_tmode_tstate * ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) { - struct tmode_tstate *master_tstate; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *master_tstate; + struct ahc_tmode_tstate *tstate; int i; master_tstate = ahc->enabled_targets[ahc->our_id]; @@ -1394,8 +1410,8 @@ memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); tstate->ultraenb = 0; for (i = 0; i < 16; i++) { - memset(&tstate->transinfo[i].current, 0, - sizeof(tstate->transinfo[i].current)); + memset(&tstate->transinfo[i].curr, 0, + sizeof(tstate->transinfo[i].curr)); memset(&tstate->transinfo[i].goal, 0, sizeof(tstate->transinfo[i].goal)); } @@ -1413,11 +1429,13 @@ static void ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; - /* Don't clean up the entry for our initiator role */ - if ((ahc->flags & AHC_INITIATORROLE) != 0 - && ((channel == 'B' && scsi_id == ahc->our_id_b) + /* + * Don't clean up our "master" tstate. + * It has our default user settings. + */ + if (((channel == 'B' && scsi_id == ahc->our_id_b) || (channel == 'A' && scsi_id == ahc->our_id)) && force == FALSE) return; @@ -1496,6 +1514,11 @@ if ((ahc->features & AHC_DT) == 0) *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + /* Skip all DT only entries if DT is not available */ + if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && maxsync < AHC_SYNCRATE_ULTRA2) + maxsync = AHC_SYNCRATE_ULTRA2; for (syncrate = &ahc_syncrates[maxsync]; syncrate->rate != NULL; @@ -1509,11 +1532,6 @@ && (syncrate->sxfr_u2 == 0)) break; - /* Skip any DT entries if DT is not available */ - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && (syncrate->sxfr_u2 & DT_SXFR) != 0) - continue; - if (*period <= syncrate->period) { /* * When responding to a target that requests @@ -1647,44 +1665,31 @@ * means the next time we send the initial identify messages for * a new transaction. */ -void -ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused) -{ - u_int targ_msg_req_orig; - - targ_msg_req_orig = ahc->targ_msg_req; - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || tinfo->current.offset != tinfo->goal.offset - || tinfo->current.ppr_options != tinfo->goal.ppr_options +int +ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct ahc_tmode_tstate *tstate, + struct ahc_initiator_tinfo *tinfo, int force) +{ + u_int auto_negotiate_orig; + + auto_negotiate_orig = tstate->auto_negotiate; + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options || (force && (tinfo->goal.period != 0 || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT || tinfo->goal.ppr_options != 0))) - ahc->targ_msg_req |= devinfo->target_mask; + tstate->auto_negotiate |= devinfo->target_mask; else - ahc->targ_msg_req &= ~devinfo->target_mask; + tstate->auto_negotiate &= ~devinfo->target_mask; - if (ahc->targ_msg_req != targ_msg_req_orig) { - /* Update the message request bit for this target */ - if (!paused) - pause_sequencer(ahc); - - ahc_outb(ahc, TARGET_MSG_REQUEST, - ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); - - if (!paused) - unpause_sequencer(ahc); - } + return (auto_negotiate_orig != tstate->auto_negotiate); } /* - * Update the user/goal/current tables of synchronous negotiation + * Update the user/goal/curr tables of synchronous negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1697,11 +1702,15 @@ u_int offset, u_int ppr_options, u_int type, int paused) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int old_period; u_int old_offset; u_int old_ppr; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + int active; + int update_needed; + + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; if (syncrate == NULL) { period = 0; @@ -1723,9 +1732,9 @@ tinfo->goal.ppr_options = ppr_options; } - old_period = tinfo->current.period; - old_offset = tinfo->current.offset; - old_ppr = tinfo->current.ppr_options; + old_period = tinfo->curr.period; + old_offset = tinfo->curr.offset; + old_ppr = tinfo->curr.ppr_options; if ((type & AHC_TRANS_CUR) != 0 && (old_period != period @@ -1733,6 +1742,7 @@ || old_ppr != ppr_options)) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1777,15 +1787,12 @@ } tinfo->scsirate = scsirate; - tinfo->current.period = period; - tinfo->current.offset = offset; - tinfo->current.ppr_options = ppr_options; - - /* Update the syncrates in any pending scbs */ - ahc_update_pending_syncrates(ahc); + tinfo->curr.period = period; + tinfo->curr.offset = offset; + tinfo->curr.ppr_options = ppr_options; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { if (offset != 0) { printf("%s: target %d synchronous at %sMHz%s, " @@ -1801,13 +1808,15 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, - paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + + if (update_needed) + ahc_update_pending_scbs(ahc); } /* - * Update the user/goal/current tables of wide negotiation + * Update the user/goal/curr tables of wide negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1818,11 +1827,14 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - u_int oldwidth; - int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + u_int oldwidth; + int active; + int update_needed; + active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + update_needed = 0; tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); @@ -1832,10 +1844,11 @@ if ((type & AHC_TRANS_GOAL) != 0) tinfo->goal.width = width; - oldwidth = tinfo->current.width; + oldwidth = tinfo->curr.width; if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { u_int scsirate; + update_needed++; scsirate = tinfo->scsirate; scsirate &= ~WIDEXFER; if (width == MSG_EXT_WDTR_BUS_16_BIT) @@ -1846,10 +1859,10 @@ if (active) ahc_outb(ahc, SCSIRATE, scsirate); - tinfo->current.width = width; + tinfo->curr.width = width; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, @@ -1857,35 +1870,22 @@ } } - ahc_update_target_msg_request(ahc, devinfo, tinfo, - /*force*/FALSE, paused); + update_needed += ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, /*force*/FALSE); + if (update_needed) + ahc_update_pending_scbs(ahc); } /* * Update the current state of tagged queuing for a given target. */ void -ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable) +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - uint16_t orig_tagenable; - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - orig_tagenable = tstate->tagenable; - if (enable) - tstate->tagenable |= devinfo->target_mask; - else - tstate->tagenable &= ~devinfo->target_mask; - - if (orig_tagenable != tstate->tagenable) { - ahc_platform_set_tags(ahc, devinfo, enable); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG); - } - + ahc_platform_set_tags(ahc, devinfo, alg); + ahc_send_async(ahc, devinfo->channel, devinfo->target, + devinfo->lun, AC_TRANSFER_NEG, &alg); } /* @@ -1894,11 +1894,12 @@ * be set correctly during future (re)selections. */ static void -ahc_update_pending_syncrates(struct ahc_softc *ahc) +ahc_update_pending_scbs(struct ahc_softc *ahc) { struct scb *pending_scb; int pending_scb_count; int i; + int paused; u_int saved_scbptr; /* @@ -1910,7 +1911,7 @@ struct ahc_devinfo devinfo; struct hardware_scb *pending_hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; ahc_scb_devinfo(ahc, &devinfo, pending_scb); tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, @@ -1921,13 +1922,25 @@ if ((tstate->ultraenb & devinfo.target_mask) != 0) pending_hscb->control |= ULTRAENB; pending_hscb->scsirate = tinfo->scsirate; - pending_hscb->scsioffset = tinfo->current.offset; + pending_hscb->scsioffset = tinfo->curr.offset; + if ((tstate->auto_negotiate & devinfo.target_mask) == 0 + && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { + pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; + pending_hscb->control &= ~MK_MESSAGE; + } pending_scb_count++; } if (pending_scb_count == 0) return; + if (ahc_is_paused(ahc)) { + paused = 1; + } else { + paused = 0; + ahc_pause(ahc); + } + saved_scbptr = ahc_inb(ahc, SCBPTR); /* Ensure that the hscbs down on the card match the new information */ for (i = 0; i < ahc->scb_data->maxhscbs; i++) { @@ -1943,14 +1956,16 @@ pending_hscb = pending_scb->hscb; control = ahc_inb(ahc, SCB_CONTROL); - control &= ~ULTRAENB; - if ((pending_hscb->control & ULTRAENB) != 0) - control |= ULTRAENB; + control &= ~(ULTRAENB|MK_MESSAGE); + control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE); ahc_outb(ahc, SCB_CONTROL, control); ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); } ahc_outb(ahc, SCBPTR, saved_scbptr); + + if (paused == 0) + ahc_unpause(ahc); } /**************************** Pathing Information *****************************/ @@ -1985,6 +2000,24 @@ role); } +struct ahc_phase_table_entry* +ahc_lookup_phase_entry(int phase) +{ + struct ahc_phase_table_entry *entry; + struct ahc_phase_table_entry *last_entry; + + /* + * num_phases doesn't include the default entry which + * will be returned if the phase doesn't match. + */ + last_entry = &ahc_phase_table[num_phases]; + for (entry = ahc_phase_table; entry < last_entry; entry++) { + if (phase == entry->phase) + break; + } + return (entry); +} + void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, role_t role) @@ -2017,6 +2050,17 @@ /************************ Message Phase Processing ****************************/ +static void +ahc_assert_atn(struct ahc_softc *ahc) +{ + u_int scsisigo; + + scsisigo = ATNO; + if ((ahc->features & AHC_DT) == 0) + scsisigo |= ahc_inb(ahc, SCSISIGI); + ahc_outb(ahc, SCSISIGO, scsisigo); +} + /* * When an initiator transaction with the MK_MESSAGE flag either reconnects * or enters the initial message out phase, we are interrupted. Fill our @@ -2083,8 +2127,7 @@ * away. */ ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0 - || (scb->flags & SCB_NEGOTIATE) != 0) { + } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { ahc_build_transfer_msg(ahc, devinfo); } else { printf("ahc_intr: AWAITING_MSG for an SCB that " @@ -2101,6 +2144,7 @@ * asked to send this message again. */ ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); + scb->hscb->control &= ~MK_MESSAGE; ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; } @@ -2118,7 +2162,7 @@ * we want to renegotiate due to a check condition. */ struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *rate; int dowide; int dosync; @@ -2130,9 +2174,19 @@ tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); - dowide = tinfo->current.width != tinfo->goal.width; - dosync = tinfo->current.period != tinfo->goal.period; - doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options; + /* + * Filter our period based on the current connection. + * If we can't perform DT transfers on this segment (not in LVD + * mode for instance), then our decision to issue a PPR message + * may change. + */ + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); + dowide = tinfo->curr.width != tinfo->goal.width; + dosync = tinfo->curr.period != period; + doppr = tinfo->curr.ppr_options != ppr_options; if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; @@ -2145,7 +2199,7 @@ "but no negotiation needed\n"); } - use_ppr = (tinfo->current.transport_version >= 3) || doppr; + use_ppr = (tinfo->curr.transport_version >= 3) || doppr; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) use_ppr = 0; @@ -2160,16 +2214,10 @@ */ if (use_ppr || (dosync && !dowide)) { - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - if (use_ppr == 0) - ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, devinfo->role); offset = tinfo->goal.offset; ahc_validate_offset(ahc, tinfo, rate, &offset, use_ppr ? tinfo->goal.width - : tinfo->current.width, + : tinfo->curr.width, devinfo->role); if (use_ppr) { ahc_construct_ppr(ahc, devinfo, period, offset, @@ -2258,7 +2306,7 @@ ahc->msgout_len = 0; ahc->msgin_index = 0; ahc->msg_type = MSG_TYPE_NONE; - if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) { + if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) { /* * The target didn't care to respond to our * message request, so clear ATN. @@ -2327,7 +2375,7 @@ * 0, and try again. */ ahc->msgout_index = 0; - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); @@ -2382,8 +2430,7 @@ * message out phase. */ if (ahc->msgout_len != 0) - ahc_outb(ahc, SCSISIGO, - ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } else ahc->msgin_index++; @@ -2548,7 +2595,7 @@ found = TRUE; } index = end_index; - } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG + } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { /* Skip tag type and tag id or residue param*/ @@ -2575,7 +2622,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int reject; int done; int response; @@ -2674,7 +2721,8 @@ /* * Send our own SDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated SDTR\n", ahc_name(ahc), devinfo->channel, @@ -2744,7 +2792,8 @@ /* * Send our own WDTR in reply */ - if (bootverbose) { + if (bootverbose + && devinfo->role == ROLE_INITIATOR) { printf("(%s:%c:%d:%d): Target " "Initiated WDTR\n", ahc_name(ahc), devinfo->channel, @@ -2879,7 +2928,7 @@ "offset %x, options %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, - ahc->msgin_buf[3], saved_width, + saved_width, ahc->msgin_buf[3], saved_offset, saved_ppr_options, bus_width, period, offset, ppr_options); } @@ -2906,7 +2955,7 @@ CAM_BDR_SENT, "Bus Device Reset Received", /*verbose_level*/0); - restart_sequencer(ahc); + ahc_restart(ahc); done = MSGLOOP_TERMINATED; break; case MSG_ABORT_TAG: @@ -2927,7 +2976,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[devinfo->lun]; if (lstate != NULL) { @@ -2979,7 +3028,7 @@ */ struct scb *scb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int scb_index; u_int last_msg; int response = 0; @@ -3004,7 +3053,7 @@ devinfo->target, devinfo->lun); } tinfo->goal.ppr_options = 0; - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; ahc->msgout_index = 0; ahc->msgout_len = 0; @@ -3046,24 +3095,39 @@ "Using asynchronous transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { - - printf("(%s:%c:%d:%d): refuses tagged commands. Performing " - "non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, devinfo, FALSE); + } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { + int tag_type; + int mask; + + tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); + + if (tag_type == MSG_SIMPLE_TASK) { + printf("(%s:%c:%d:%d): refuses tagged commands. " + "Performing non-tagged I/O\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); + mask = ~0x23; + } else { + printf("(%s:%c:%d:%d): refuses %s tagged commands. " + "Performing simple queue tagged I/O only\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, tag_type == MSG_ORDERED_TASK + ? "ordered" : "head of queue"); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); + mask = ~0x03; + } /* * Resend the identify for this CCB as the target * may believe that the selection is invalid otherwise. */ ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG); - scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; + ahc_inb(ahc, SCB_CONTROL) & mask); + scb->hscb->control &= mask; ahc_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_Q_TAG); + /*type*/MSG_SIMPLE_TASK); ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); /* * This transaction is now at the head of @@ -3225,7 +3289,7 @@ cam_status status, char *message, int verbose_level) { #ifdef AHC_TARGET_MODE - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; #endif int found; @@ -3242,7 +3306,7 @@ tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -3265,7 +3329,7 @@ AHC_TRANS_CUR, /*paused*/TRUE); ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR); + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); if (message != NULL && (verbose_level <= bootverbose)) @@ -3274,9 +3338,11 @@ } #ifdef AHC_TARGET_MODE -void -ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +static void +ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) { + /* * To facilitate adding multiple messages together, * each routine should increment the index and len @@ -3285,7 +3351,7 @@ ahc->msgout_index = 0; ahc->msgout_len = 0; - if ((ahc->targ_msg_req & devinfo->target_mask) != 0) + if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) ahc_build_transfer_msg(ahc, devinfo); else panic("ahc_intr: AWAITING target message with no message"); @@ -3319,6 +3385,7 @@ LIST_INIT(&ahc->pending_scbs); /* We don't know our unit number until the OSM sets it */ ahc->name = name; + ahc->unit = -1; for (i = 0; i < 16; i++) TAILQ_INIT(&ahc->untagged_queues[i]); if (ahc_platform_alloc(ahc, platform_arg) != 0) { @@ -3337,7 +3404,7 @@ ahc->bugs = config->bugs; ahc->flags = config->flags; ahc->channel = config->channel; - ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; + ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS); ahc->description = config->description; /* The IRQMS bit is only valid on VL and EISA chips */ if ((ahc->chip & AHC_PCI) != 0) @@ -3360,29 +3427,37 @@ { struct ahc_softc *list_ahc; -#ifdef AHC_SUPPORT_PCI +#if AHC_PCI_CONFIG > 0 /* * Second Function PCI devices need to inherit some - * settings from function 0. We assume that function 0 - * will always be found prior to function 1. + * settings from function 0. */ if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI - && ahc_get_pci_function(ahc->dev_softc) == 1) { + && (ahc->features & AHC_MULTI_FUNC) != 0) { TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { ahc_dev_softc_t list_pci; ahc_dev_softc_t pci; list_pci = list_ahc->dev_softc; pci = ahc->dev_softc; - if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci) - && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) - && ahc_get_pci_function(list_pci) == 0) { - ahc->flags &= ~AHC_BIOS_ENABLED; - ahc->flags |= - list_ahc->flags & AHC_BIOS_ENABLED; - ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; - ahc->flags |= - list_ahc->flags & AHC_CHANNEL_B_PRIMARY; + if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) + && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) { + struct ahc_softc *master; + struct ahc_softc *slave; + + if (ahc_get_pci_function(list_pci) == 0) { + master = list_ahc; + slave = ahc; + } else { + master = ahc; + slave = list_ahc; + } + slave->flags &= ~AHC_BIOS_ENABLED; + slave->flags |= + master->flags & AHC_BIOS_ENABLED; + slave->flags &= ~AHC_PRIMARY_CHANNEL; + slave->flags |= + master->flags & AHC_PRIMARY_CHANNEL; break; } } @@ -3455,7 +3530,7 @@ #endif ahc_platform_free(ahc); for (i = 0; i < AHC_NUM_TARGETS; i++) { - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; tstate = ahc->enabled_targets[i]; if (tstate != NULL) { @@ -3463,7 +3538,7 @@ int j; for (j = 0; j < AHC_NUM_LUNS; j++) { - struct tmode_lstate *lstate; + struct ahc_tmode_lstate *lstate; lstate = tstate->enabled_luns[j]; if (lstate != NULL) { @@ -3523,7 +3598,7 @@ * It contains settings that affect termination and we don't want * to disturb the integrity of the bus. */ - pause_sequencer(ahc); + ahc_pause(ahc); sxfrctl1_b = 0; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { u_int sblkctl; @@ -3961,17 +4036,26 @@ len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " "B SCSI Id=%d, primary %c, ", ahc->our_id, ahc->our_id_b, - ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A'); + (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); else { + const char *speed; const char *type; + speed = ""; + if ((ahc->features & AHC_ULTRA) != 0) { + speed = "Ultra "; + } else if ((ahc->features & AHC_DT) != 0) { + speed = "Ultra160 "; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + speed = "Ultra2 "; + } if ((ahc->features & AHC_WIDE) != 0) { type = "Wide"; } else { type = "Single"; } - len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ", - type, ahc->channel, ahc->our_id); + len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ", + speed, type, ahc->channel, ahc->our_id); } buf += len; @@ -4124,16 +4208,16 @@ * data for any target mode initiator. */ if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } if ((ahc->features & AHC_TWIN) != 0) { if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { - printf("%s: unable to allocate tmode_tstate. " + printf("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); - return (-1); + return (ENOMEM); } } @@ -4231,7 +4315,7 @@ for (i = 0; i <= max_targ; i++) { struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -4324,12 +4408,10 @@ tinfo->user.transport_version = 2; tinfo->goal.protocol_version = 2; tinfo->goal.transport_version = 2; - tinfo->current.protocol_version = 2; - tinfo->current.transport_version = 2; + tinfo->curr.protocol_version = 2; + tinfo->curr.transport_version = 2; } tstate->ultraenb = ultraenb; - tstate->discenable = discenable; - tstate->tagenable = 0; /* Wait until the XPT says its okay */ } ahc->user_discenable = discenable; ahc->user_tagenable = tagenable; @@ -4395,10 +4477,6 @@ ahc_outb(ahc, QINPOS, 0); ahc_outb(ahc, QOUTPOS, 0); - /* Don't have any special messages to send to targets */ - ahc_outb(ahc, TARGET_MSG_REQUEST, 0); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0); - /* * Use the built in queue management registers * if they are available. @@ -4450,16 +4528,33 @@ * never settle, so don't complain if we * fail here. */ - pause_sequencer(ahc); + ahc_pause(ahc); for (wait = 5000; (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; wait--) ahc_delay(100); - unpause_sequencer(ahc); + ahc_unpause(ahc); } return (0); } +void +ahc_intr_enable(struct ahc_softc *ahc, int enable) +{ + u_int hcntrl; + + hcntrl = ahc_inb(ahc, HCNTRL); + hcntrl &= ~INTEN; + ahc->pause &= ~INTEN; + ahc->unpause &= ~INTEN; + if (enable) { + hcntrl |= INTEN; + ahc->pause |= INTEN; + ahc->unpause |= INTEN; + } + ahc_outb(ahc, HCNTRL, hcntrl); +} + /* * Ensure that the card is paused in a location * outside of all critical sections and that all @@ -4478,7 +4573,7 @@ intstat = 0; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) break; @@ -5409,7 +5504,7 @@ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD, channel, ROLE_UNKNOWN); - pause_sequencer(ahc); + ahc_pause(ahc); /* Make sure the sequencer is in a safe location. */ ahc_clear_critical_section(ahc); @@ -5478,14 +5573,14 @@ * drivers affected by this action. */ for (target = 0; target <= max_scsiid; target++) { - struct tmode_tstate* tstate; + struct ahc_tmode_tstate* tstate; u_int lun; tstate = ahc->enabled_targets[target]; if (tstate == NULL) continue; for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct tmode_lstate* lstate; + struct ahc_tmode_lstate* lstate; lstate = tstate->enabled_luns[lun]; if (lstate == NULL) @@ -5499,7 +5594,7 @@ #endif /* Notify the XPT that a bus reset occurred */ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); + CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); /* * Revert to async/narrow transfers until we renegotiate. @@ -5524,9 +5619,9 @@ } if (restart_needed) - restart_sequencer(ahc); + ahc_restart(ahc); else - unpause_sequencer(ahc); + ahc_unpause(ahc); return found; } @@ -5535,7 +5630,7 @@ /* * Calculate the residual for a just completed SCB. */ -static void +void ahc_calc_residual(struct scb *scb) { struct hardware_scb *hscb; @@ -5623,7 +5718,7 @@ * Add a target mode event to this lun's queue */ static void -ahc_queue_lstate_event(struct ahc_softc *ahc, struct tmode_lstate *lstate, +ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, u_int initiator_id, u_int event_type, u_int event_arg) { struct ahc_tmode_event *event; @@ -5674,7 +5769,7 @@ * for immediate notify resources. */ void -ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate) +ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) { struct ccb_hdr *ccbh; struct ccb_immed_notify *inot; @@ -5825,7 +5920,7 @@ memcpy(ahc->critical_sections, cs_table, cs_count); } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - restart_sequencer(ahc); + ahc_restart(ahc); if (bootverbose) printf(" %d instructions downloaded\n", downloaded); @@ -6000,6 +6095,7 @@ int target; int maxtarget; int i; + uint8_t last_phase; uint8_t qinpos; uint8_t qintail; uint8_t qoutpos; @@ -6008,13 +6104,25 @@ saved_scbptr = ahc_inb(ahc, SCBPTR); - printf("%s: Dumping Card State at SEQADDR 0x%x\n", - ahc_name(ahc), + last_phase = ahc_inb(ahc, LASTPHASE); + printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n", + ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - - printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x, SSTAT0 0x%x\n", - ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL), - ahc_inb(ahc, SSTAT0)); + printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n", + ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL)); + printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n", + ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS)); + printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n", + last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0)); + printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n", + ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1)); + if ((ahc->features & AHC_DT) != 0) + printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE)); + printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); printf("SCB count = %d\n", ahc->scb_data->numscbs); printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); @@ -6112,7 +6220,8 @@ #ifdef AHC_TARGET_MODE cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure) { @@ -6153,8 +6262,8 @@ void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_en_lun *cel; cam_status status; u_int target; @@ -6227,7 +6336,7 @@ ahc->flags |= AHC_TARGETROLE; if ((ahc->features & AHC_MULTIROLE) == 0) ahc->flags &= ~AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); ahc_unlock(ahc, &s); } @@ -6296,7 +6405,7 @@ SLIST_INIT(&lstate->accept_tios); SLIST_INIT(&lstate->immed_notifies); ahc_lock(ahc, &s); - pause_sequencer(ahc); + ahc_pause(ahc); if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = lstate; ahc->enabled_luns++; @@ -6360,7 +6469,7 @@ scsiseq |= ENSELI; ahc_outb(ahc, SCSISEQ, scsiseq); } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_print_path(ccb->ccb_h.path); @@ -6410,7 +6519,7 @@ xpt_free_path(lstate->path); free(lstate, M_DEVBUF); - pause_sequencer(ahc); + ahc_pause(ahc); /* Can we clean up the target too? */ if (target != CAM_TARGET_WILDCARD) { tstate->enabled_luns[lun] = NULL; @@ -6463,11 +6572,11 @@ printf("Configuring Initiator Mode\n"); ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; - pause_sequencer(ahc); + ahc_pause(ahc); ahc_loadseq(ahc); } } - unpause_sequencer(ahc); + ahc_unpause(ahc); ahc_unlock(ahc, &s); } } @@ -6549,11 +6658,11 @@ ahc_outb(ahc, HS_MAILBOX, hs_mailbox); } else { if (!paused) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext & HOST_TQINPOS); if (!paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } } @@ -6562,8 +6671,8 @@ static int ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; + struct ahc_tmode_tstate *tstate; + struct ahc_tmode_lstate *lstate; struct ccb_accept_tio *atio; uint8_t *byte; int initiator; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.h linux/drivers/scsi/aic7xxx/aic7xxx.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.h Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.h Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.h#19 $ + * $Id: //depot/src/aic7xxx/aic7xxx.h#27 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $ */ @@ -209,9 +209,15 @@ AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */ AHC_REMOVABLE = 0x80000, /* Hot-Swap supported */ AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE, - AHC_AIC7855_FE = AHC_AIC7850_FE, - AHC_AIC7860_FE = AHC_AIC7850_FE|AHC_ULTRA, + /* + * The real 7850 does not support Ultra modes, but there are + * several cards that use the generic 7850 PCI ID even though + * they are using an Ultra capable chip (7859/7860). We start + * out with the AHC_ULTRA feature set and then check the DEVSTATUS + * register to determine if the capability is really present. + */ + AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, + AHC_AIC7860_FE = AHC_AIC7850_FE, AHC_AIC7870_FE = AHC_TARGETMODE, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, /* @@ -286,56 +292,56 @@ * chip/controller's configuration. */ typedef enum { - AHC_FNONE = 0x000, - AHC_PAGESCBS = 0x001,/* Enable SCB paging */ - AHC_CHANNEL_B_PRIMARY = 0x002,/* - * On twin channel adapters, probe - * channel B first since it is the - * primary bus. + AHC_FNONE = 0x000, + AHC_PRIMARY_CHANNEL = 0x003,/* + * The channel that should + * be probed first. */ - AHC_USEDEFAULTS = 0x004,/* + AHC_USEDEFAULTS = 0x004,/* * For cards without an seeprom * or a BIOS to initialize the chip's * SRAM, we use the default target * settings. */ - AHC_SEQUENCER_DEBUG = 0x008, - AHC_SHARED_SRAM = 0x010, - AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ - AHC_RESET_BUS_A = 0x040, - AHC_RESET_BUS_B = 0x080, - AHC_EXTENDED_TRANS_A = 0x100, - AHC_EXTENDED_TRANS_B = 0x200, - AHC_TERM_ENB_A = 0x400, - AHC_TERM_ENB_B = 0x800, - AHC_INITIATORROLE = 0x1000,/* + AHC_SEQUENCER_DEBUG = 0x008, + AHC_SHARED_SRAM = 0x010, + AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ + AHC_RESET_BUS_A = 0x040, + AHC_RESET_BUS_B = 0x080, + AHC_EXTENDED_TRANS_A = 0x100, + AHC_EXTENDED_TRANS_B = 0x200, + AHC_TERM_ENB_A = 0x400, + AHC_TERM_ENB_B = 0x800, + AHC_INITIATORROLE = 0x1000,/* * Allow initiator operations on * this controller. */ - AHC_TARGETROLE = 0x2000,/* + AHC_TARGETROLE = 0x2000,/* * Allow target operations on this * controller. */ - AHC_NEWEEPROM_FMT = 0x4000, - AHC_RESOURCE_SHORTAGE = 0x8000, - AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ - AHC_INT50_SPEEDFLEX = 0x20000,/* + AHC_NEWEEPROM_FMT = 0x4000, + AHC_RESOURCE_SHORTAGE = 0x8000, + AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ + AHC_INT50_SPEEDFLEX = 0x20000,/* * Internal 50pin connector * sits behind an aic3860 */ - AHC_SCB_BTT = 0x40000,/* + AHC_SCB_BTT = 0x40000,/* * The busy targets table is * stored in SCB space rather * than SRAM. */ - AHC_BIOS_ENABLED = 0x80000, - AHC_ALL_INTERRUPTS = 0x100000, - AHC_ULTRA_DISABLED = 0x200000/* + AHC_BIOS_ENABLED = 0x80000, + AHC_ALL_INTERRUPTS = 0x100000, + AHC_ULTRA_DISABLED = 0x200000, /* * The precision resistor for * ultra transmission speeds is * missing, so we must limit * ourselves to fast SCSI. */ + AHC_PAGESCBS = 0x400000, /* Enable SCB paging */ + AHC_EDGE_INTERRUPT = 0x800000 /* Device uses edge triggered ints */ } ahc_flag; /* @@ -515,8 +521,9 @@ SCB_DEVICE_RESET = 0x0004, SCB_SENSE = 0x0008, SCB_CDB32_PTR = 0x0010, - SCB_RECOVERY_SCB = 0x0040, - SCB_NEGOTIATE = 0x0080, + SCB_RECOVERY_SCB = 0x0020, + SCB_AUTO_NEGOTIATE = 0x0040,/* Negotiate to achieve goal. */ + SCB_NEGOTIATE = 0x0080,/* Negotiation forced for command. */ SCB_ABORT = 0x1000, SCB_UNTAGGEDQ = 0x2000, SCB_ACTIVE = 0x4000, @@ -625,7 +632,7 @@ * data structures. */ #ifdef AHC_TARGET_MODE -struct tmode_lstate { +struct ahc_tmode_lstate { struct cam_path *path; struct ccb_hdr_slist accept_tios; struct ccb_hdr_slist immed_notifies; @@ -634,7 +641,7 @@ uint8_t event_w_idx; }; #else -struct tmode_lstate; +struct ahc_tmode_lstate; #endif /******************** Transfer Negotiation Datastructures *********************/ @@ -659,7 +666,7 @@ * Per-initiator current, goal and user transfer negotiation information. */ struct ahc_initiator_tinfo { uint8_t scsirate; /* Computed value for SCSIRATE reg */ - struct ahc_transinfo current; + struct ahc_transinfo curr; struct ahc_transinfo goal; struct ahc_transinfo user; }; @@ -671,16 +678,17 @@ * that we are the target and the targets are the initiators since the * negotiation is the same regardless of role. */ -struct tmode_tstate { - struct tmode_lstate* enabled_luns[AHC_NUM_LUNS]; +struct ahc_tmode_tstate { + struct ahc_tmode_lstate* enabled_luns[AHC_NUM_LUNS]; struct ahc_initiator_tinfo transinfo[AHC_NUM_TARGETS]; /* * Per initiator state bitmasks. */ - uint16_t ultraenb; /* Using ultra sync rate */ - uint16_t discenable; /* Disconnection allowed */ - uint16_t tagenable; /* Tagged Queuing allowed */ + uint16_t auto_negotiate;/* Auto Negotiation Required */ + uint16_t ultraenb; /* Using ultra sync rate */ + uint16_t discenable; /* Disconnection allowed */ + uint16_t tagenable; /* Tagged Queuing allowed */ }; /* @@ -711,32 +719,14 @@ /***************************** Lookup Tables **********************************/ /* - * Textual descriptions of the different chips indexed by chip type. - */ -extern char *ahc_chip_names[]; -extern const u_int num_chip_names; - -/* - * Hardware error codes. - */ -struct hard_error_entry { - uint8_t errno; - char *errmesg; -}; -extern struct hard_error_entry hard_error[]; -extern const u_int num_errors; - -/* * Phase -> name and message out response * to parity errors in each phase table. */ -struct phase_table_entry { +struct ahc_phase_table_entry { uint8_t phase; uint8_t mesg_out; /* Message response to parity errors */ char *phasemsg; }; -extern struct phase_table_entry phase_table[]; -extern const u_int num_phases; /************************** Serial EEPROM Format ******************************/ @@ -765,12 +755,19 @@ #define CFSUPREM 0x0001 /* support all removeable drives */ #define CFSUPREMB 0x0002 /* support removeable boot drives */ #define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ +#define CFBIOS_BUSSCAN 0x0008 /* Have the BIOS Scan the Bus */ #define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ #define CFSTPWLEVEL 0x0010 /* Termination level control */ +#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ +#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */ +#define CFTERM_MENU 0x0040 /* BIOS displays termination menu */ #define CFEXTEND 0x0080 /* extended translation enabled */ #define CFSCAMEN 0x0100 /* SCAM enable */ +#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */ +#define CFMSG_VERBOSE 0x0000 +#define CFMSG_SILENT 0x0200 +#define CFMSG_DIAG 0x0400 +#define CFBOOTCD 0x0800 /* Support Bootable CD-ROM */ /* UNUSED 0xff00 */ /* @@ -785,10 +782,11 @@ #define CFWSTERM 0x0008 /* SCSI high byte termination */ #define CFSPARITY 0x0010 /* SCSI parity */ #define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */ -#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */ +#define CFMULTILUN 0x0020 #define CFRESETB 0x0040 /* reset SCSI bus at boot */ #define CFCLUSTERENB 0x0080 /* Cluster Enable */ -#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */ +#define CFBOOTCHAN 0x0300 /* probe this channel first */ +#define CFBOOTCHANSHIFT 8 #define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/ #define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */ #define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */ @@ -812,6 +810,7 @@ uint16_t res_1[10]; /* words 20-29 */ uint16_t signature; /* Signature == 0x250 */ #define CFSIGNATURE 0x250 +#define CFSIGNATURE2 0x300 uint16_t checksum; /* word 31 */ }; @@ -857,6 +856,8 @@ uint8_t *btt; }; +typedef void (*ahc_bus_intr_t)(struct ahc_softc *); + struct ahc_softc { bus_space_tag_t tag; bus_space_handle_t bsh; @@ -900,24 +901,29 @@ ahc_dev_softc_t dev_softc; /* + * Bus specific device information. + */ + ahc_bus_intr_t bus_intr; + + /* * Target mode related state kept on a per enabled lun basis. * Targets that are not enabled will have null entries. * As an initiator, we keep one target entry for our initiator * ID to store our sync/wide transfer settings. */ - struct tmode_tstate* enabled_targets[AHC_NUM_TARGETS]; + struct ahc_tmode_tstate *enabled_targets[AHC_NUM_TARGETS]; /* * The black hole device responsible for handling requests for * disabled luns on enabled targets. */ - struct tmode_lstate* black_hole; + struct ahc_tmode_lstate *black_hole; /* * Device instance currently on the bus awaiting a continue TIO * for a command that was not given the disconnect priveledge. */ - struct tmode_lstate* pending_device; + struct ahc_tmode_lstate *pending_device; /* * Card characteristics @@ -952,9 +958,6 @@ uint8_t our_id; uint8_t our_id_b; - /* Targets that need negotiation messages */ - uint16_t targ_msg_req; - /* * PCI error detection. */ @@ -1102,6 +1105,7 @@ struct ahc_probe_config*); void ahc_controller_info(struct ahc_softc *ahc, char *buf); int ahc_init(struct ahc_softc *ahc); +void ahc_intr_enable(struct ahc_softc *ahc, int enable); void ahc_pause_and_flushwork(struct ahc_softc *ahc); int ahc_suspend(struct ahc_softc *ahc); int ahc_resume(struct ahc_softc *ahc); @@ -1143,8 +1147,11 @@ void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb); int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset); -void restart_sequencer(struct ahc_softc *ahc); +void ahc_restart(struct ahc_softc *ahc); +void ahc_calc_residual(struct scb *scb); /*************************** Utility Functions ********************************/ +struct ahc_phase_table_entry* + ahc_lookup_phase_entry(int phase); void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, @@ -1163,10 +1170,11 @@ struct ahc_initiator_tinfo *tinfo, u_int *bus_width, role_t role); -void ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *dinfo, - struct ahc_initiator_tinfo *tinfo, - int force, int paused); +int ahc_update_neg_request(struct ahc_softc*, + struct ahc_devinfo*, + struct ahc_tmode_tstate*, + struct ahc_initiator_tinfo*, + int /*force*/); void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused); @@ -1176,22 +1184,27 @@ u_int period, u_int offset, u_int ppr_options, u_int type, int paused); +typedef enum { + AHC_QUEUE_NONE, + AHC_QUEUE_BASIC, + AHC_QUEUE_TAGGED +} ahc_queue_alg; + void ahc_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, + ahc_queue_alg alg); /**************************** Target Mode *************************************/ #ifdef AHC_TARGET_MODE void ahc_send_lstate_events(struct ahc_softc *, - struct tmode_lstate *); + struct ahc_tmode_lstate *); void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb); cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct tmode_tstate **tstate, - struct tmode_lstate **lstate, + struct ahc_tmode_tstate **tstate, + struct ahc_tmode_lstate **lstate, int notfound_failure); -void ahc_setup_target_msgin(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); #ifndef AHC_TMODE_ENABLE #define AHC_TMODE_ENABLE 0 #endif diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.reg Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.reg#13 $ + * $Id: //depot/src/aic7xxx/aic7xxx.reg#17 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $ */ @@ -877,7 +877,8 @@ address 0x094 access_mode RO bit PRELOAD_AVAIL 0x80 - bit DWORDEMP 0x20 + bit DFCACHETH 0x40 + bit FIFOQWDEMP 0x20 bit MREQPEND 0x10 bit HDONE 0x08 bit DFTHRESH 0x04 @@ -969,6 +970,7 @@ bit MSG_OUT_PHASE 0x04 bit DATA_IN_PHASE 0x02 bit DATA_OUT_PHASE 0x01 + mask DATA_PHASE_MASK 0x03 } /* @@ -1415,15 +1417,6 @@ */ LAST_MSG { size 1 - } - - /* - * Interrupt kernel for a message to this target on - * the next transaction. This is usually used for - * negotiation requests. - */ - TARGET_MSG_REQUEST { - size 2 } /* diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx.seq Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx.seq Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.seq#22 $ + * $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $ */ @@ -153,7 +153,9 @@ * the kernel driver if it happens. */ mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; + if ((ahc->features & AHC_DT) == 0) { + or SIMODE1, ENBUSFREE; + } /* * Guard against a bus free after (re)selection @@ -479,6 +481,9 @@ */ mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; + test SCB_CONTROL, MK_MESSAGE jz target_ITloop; + mvi P_MESGIN|BSYO call change_phase; + jmp host_target_message_loop; target_ITloop: /* * Start honoring ATN signals now that @@ -494,12 +499,12 @@ * on the state of NO_DISCONNECT. */ test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } mov RETURN_1, ALLZEROS; call complete_target_cmd; cmp RETURN_1, CONT_MSG_LOOP jne .; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov SCB_TAG call dma_scb; jmp target_synccmd; @@ -703,6 +708,11 @@ test CCSGCTL, CCSGEN jnz .; ret; idle_loop: + /* + * Do we need any more segments for this transfer? + */ + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; + /* Did we just finish fetching segs? */ cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; @@ -710,11 +720,6 @@ test CCSGCTL, CCSGEN jnz return; /* - * Do we need any more segments? - */ - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; - - /* * Do we have any prefetch left??? */ cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; @@ -758,8 +763,8 @@ test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; mov SG_CACHE_PRE, SINDEX; - /* Load the segment by writing DFCNTRL again */ - mov DFCNTRL, DMAPARAMS; + /* Load the segment */ + or DFCNTRL, PRELOADEN; } ret; } @@ -882,7 +887,11 @@ and DMAPARAMS, DIRECTION; mov DFCNTRL, DMAPARAMS; or SXFRCTL1,BITBUCKET; - test SSTAT1,PHASEMIS jz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz .; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz .; + } and SXFRCTL1, ~BITBUCKET; mvi DATA_OVERRUN call set_seqint; jmp ITloop; @@ -903,54 +912,48 @@ * completes or the target changes phase. */ test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - /* - * As a target, we control the phases, - * so ignore PHASEMIS. - */ - test SSTAT0, TARGET jnz ultra2_dma_loop; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1,PHASEMIS jz ultra2_dma_loop; + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { + /* + * As a target, we control the phases, + * so ignore PHASEMIS. + */ + test SSTAT0, TARGET jnz ultra2_dma_loop; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1,PHASEMIS jz ultra2_dma_loop; + } + } else { + test DFCNTRL, SCSIEN jnz ultra2_dma_loop; } ultra2_dmafinish: - test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; - if ((ahc->features & AHC_DT) == 0) { - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; - } -ultra2_dmafifoflush: + /* + * The transfer has terminated either due to a phase + * change, and/or the completion of the last segment. + * We have two goals here. Do as much other work + * as possible while the data fifo drains on a read + * and respond as quickly as possible to the standard + * messages (save data pointers/disconnect and command + * complete) that usually follow a data phase. + */ if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { /* - * On Rev A of the aic7890, the autoflush - * features doesn't function correctly. - * Perform an explicit manual flush. During - * a manual flush, the FIFOEMP bit becomes - * true every time the PCI FIFO empties - * regardless of the state of the SCSI FIFO. - * It can take up to 4 clock cycles for the - * SCSI FIFO to get data into the PCI FIFO - * and for FIFOEMP to de-assert. Here we - * guard against this condition by making - * sure the FIFOEMP bit stays on for 5 full - * clock cycles. + * On chips with broken auto-flush, start + * the flushing process now. We'll poke + * the chip from time to time to keep the + * flush process going as we complete the + * data phase. */ or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; } - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; -ultra2_dmafifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; -ultra2_dmahalt: - and DFCNTRL, ~(SCSIEN|HDMAEN); - test DFCNTRL, HDMAEN jnz .; - /* + * We assume that, even though data may still be + * transferring to the host, that the SCSI side of + * the DMA engine is now in a static state. This + * allows us to update our notion of where we are + * in this transfer. + * * If, by chance, we stopped before being able * to fetch additional segments for this transfer, * yet the last S/G was completely exhausted, @@ -961,14 +964,14 @@ * If we happened to stop on the last segment, then * our residual information is still correct from * the idle loop and there is no need to perform - * any fixups. Just jump to data_phase_finish. + * any fixups. */ ultra2_ensure_sg: test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; /* Record if we've consumed all S/G entries */ - test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; + test SSTAT2, SHVALID jnz residuals_correct; or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp data_phase_finish; + jmp residuals_correct; ultra2_shvalid: test SSTAT2, SHVALID jnz sgptr_fixup; @@ -998,6 +1001,62 @@ test SG_CACHE_SHADOW, ODD_SEG jz . + 2; or DATA_COUNT_ODD, 0x1; clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ +residuals_correct: + /* + * Go ahead and shut down the DMA engine now. + * In the future, we'll want to handle end of + * transfer messages prior to doing this, but this + * requires similar restructuring for pre-ULTRA2 + * controllers. + */ + test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; +ultra2_fifoflush: + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { + /* + * On Rev A of the aic7890, the autoflush + * feature doesn't function correctly. + * Perform an explicit manual flush. During + * a manual flush, the FIFOEMP bit becomes + * true every time the PCI FIFO empties + * regardless of the state of the SCSI FIFO. + * It can take up to 4 clock cycles for the + * SCSI FIFO to get data into the PCI FIFO + * and for FIFOEMP to de-assert. Here we + * guard against this condition by making + * sure the FIFOEMP bit stays on for 5 full + * clock cycles. + */ + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } else { + /* + * We enable the auto-ack feature on DT capable + * controllers. This means that the controller may + * have already transferred some overrun bytes into + * the data FIFO and acked them on the bus. The only + * way to detect this situation is to wait for + * LAST_SEG_DONE to come true on a completed transfer + * and then test to see if the data FIFO is non-empty. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; + /* Overrun */ + jmp data_phase_loop; + test DFSTATUS, FIFOEMP jz .; + } +ultra2_fifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz ultra2_fifoempty; +ultra2_dmahalt: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, SCSIEN|HDMAEN jnz .; } else { /* If we are the last SG block, tell the hardware. */ if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 @@ -1156,7 +1215,11 @@ } if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz data_phase_loop; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; + } } data_phase_done: @@ -1296,13 +1359,17 @@ or DFCNTRL, FIFOFLUSH; } p_command_loop: - test SSTAT0, SDONE jnz . + 2; - test SSTAT1, PHASEMIS jz p_command_loop; - /* - * Wait for our ACK to go-away on it's own - * instead of being killed by SCSIEN getting cleared. - */ - test SCSISIGI, ACKI jnz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT0, SDONE jnz . + 2; + test SSTAT1, PHASEMIS jz p_command_loop; + /* + * Wait for our ACK to go-away on it's own + * instead of being killed by SCSIEN getting cleared. + */ + test SCSISIGI, ACKI jnz .; + } else { + test DFCNTRL, SCSIEN jnz p_command_loop; + } and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1346,23 +1413,16 @@ * reason. */ p_mesgout_retry: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ + /* Turn on ATN for the retry */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; - mov FUNCTION1, SCB_SCSIID; - mov A, FUNCTION1; - mov SINDEX, TARGET_MSG_REQUEST[0]; - if ((ahc->features & AHC_TWIN) != 0) { - /* Second Channel uses high byte bits */ - test SCB_SCSIID, TWIN_CHNLB jz . + 2; - mov SINDEX, TARGET_MSG_REQUEST[1]; - } else if ((ahc->features & AHC_WIDE) != 0) { - test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ - mov SINDEX, TARGET_MSG_REQUEST[1]; - } - test SINDEX, A jnz host_message_loop; p_mesgout_identify: or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; test SCB_CONTROL, DISCENB jnz . + 2; @@ -1555,10 +1615,17 @@ * only if we've actually been into a data phase to change them. This * protects against bogus data in scratch ram and the residual counts * since they are only initialized when we go into data_in or data_out. + * Ack the message as soon as possible. For chips without S/G pipelining, + * we can only ack the message after SHADDR has been saved. On these + * chips, SHADDR increments with every bus transaction, even PIO. */ mesgin_sdptrs: - test SEQ_FLAGS, DPHASE jz mesgin_done; - + if ((ahc->features & AHC_ULTRA2) != 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + test SEQ_FLAGS, DPHASE jz ITloop; + } else { + test SEQ_FLAGS, DPHASE jz mesgin_done; + } /* * The SCB_SGPTR becomes the next one we'll download, * and the SCB_DATAPTR becomes the current SHADDR. @@ -1567,13 +1634,17 @@ */ if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov SCB_DATAPTR, SHADDR, 4; + if ((ahc->features & AHC_ULTRA2) == 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + } bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; } else { mvi DINDEX, SCB_DATAPTR; mvi SHADDR call bcopy_4; + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ mvi SCB_RESIDUAL_DATACNT call bcopy_8; } - jmp mesgin_done; + jmp ITloop; /* * Restore pointers message? Data pointers are recopied from the @@ -1751,7 +1822,11 @@ jmp mesgin_done; mk_mesg: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } mov MSG_OUT,SINDEX ret; /* @@ -1924,7 +1999,9 @@ test SSTAT1, REQINIT jz phase_lock; test SSTAT1, SCSIPERR jnz phase_lock_perr; phase_lock_latch_phase: - and SCSISIGO, PHASE_MASK, SCSISIGI; + if ((ahc->features & AHC_DT) == 0) { + and SCSISIGO, PHASE_MASK, SCSISIGI; + } and LASTPHASE, PHASE_MASK, SCSISIGI ret; if ((ahc->features & AHC_CMD_CHAN) == 0) { @@ -2068,9 +2145,9 @@ * latch is full. */ clr A; - /* Wait for some data to arrive. */ + /* Wait for at least 8 bytes of data to arrive. */ dma_scb_hang_fifo: - test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; + test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; dma_scb_hang_wait: test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; @@ -2078,8 +2155,7 @@ test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; /* * The PCI module no longer intends to perform - * a PCI transaction and HDONE has not come true. - * We are hung. Drain the fifo. + * a PCI transaction. Drain the fifo. */ dma_scb_hang_empty_fifo: /* @@ -2101,6 +2177,7 @@ */ not SINDEX; add A, 5, SINDEX; + cmp A, 4 je dma_finish_nowait; jmp dma_scb_hang_fifo; dma_scb_hang_dma_done: and DFCNTRL, ~HDMAEN; @@ -2146,6 +2223,7 @@ */ dma_finish: test DFSTATUS,HDONE jz dma_finish; +dma_finish_nowait: /* Turn off DMA */ and DFCNTRL, ~HDMAEN; test DFCNTRL, HDMAEN jnz .; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h linux/drivers/scsi/aic7xxx/aic7xxx_inline.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_inline.h Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#15 $ + * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#21 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $ */ @@ -37,10 +37,10 @@ #define _AIC7XXX_INLINE_H_ /************************* Sequencer Execution Control ************************/ -static __inline int sequencer_paused(struct ahc_softc *ahc); +static __inline int ahc_is_paused(struct ahc_softc *ahc); static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc); -static __inline void pause_sequencer(struct ahc_softc *ahc); -static __inline void unpause_sequencer(struct ahc_softc *ahc); +static __inline void ahc_pause(struct ahc_softc *ahc); +static __inline void ahc_unpause(struct ahc_softc *ahc); /* * Work around any chip bugs related to halting sequencer execution. @@ -62,7 +62,7 @@ * Returns non-zero status if the sequencer is stopped. */ static __inline int -sequencer_paused(struct ahc_softc *ahc) +ahc_is_paused(struct ahc_softc *ahc) { return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); } @@ -75,7 +75,7 @@ * for critical sections. */ static __inline void -pause_sequencer(struct ahc_softc *ahc) +ahc_pause(struct ahc_softc *ahc) { ahc_outb(ahc, HCNTRL, ahc->pause); @@ -83,7 +83,7 @@ * Since the sequencer can disable pausing in a critical section, we * must loop until it actually stops. */ - while (sequencer_paused(ahc) == 0) + while (ahc_is_paused(ahc) == 0) ; ahc_pause_bug_fix(ahc); @@ -100,7 +100,7 @@ * condition. */ static __inline void -unpause_sequencer(struct ahc_softc *ahc) +ahc_unpause(struct ahc_softc *ahc) { if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) ahc_outb(ahc, HCNTRL, ahc->unpause); @@ -188,12 +188,12 @@ /*********************** Miscelaneous Support Functions ***********************/ -static __inline int ahc_check_residual(struct scb *scb); +static __inline void ahc_update_residual(struct scb *scb); static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, u_int remote_id, - struct tmode_tstate **tstate); + struct ahc_tmode_tstate **tstate); static __inline struct scb* ahc_get_scb(struct ahc_softc *ahc); static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); @@ -211,15 +211,16 @@ * Determine whether the sequencer reported a residual * for this SCB/transaction. */ -static __inline int -ahc_check_residual(struct scb *scb) +static __inline void +ahc_update_residual(struct scb *scb) { - struct status_pkt *sp; + uint32_t sgptr; - sp = &scb->hscb->shared_data.status; - if ((scb->hscb->sgptr & SG_RESID_VALID) != 0) - return (1); - return (0); + sgptr = ahc_le32toh(scb->hscb->sgptr); + if ((sgptr & SG_RESID_VALID) != 0) + ahc_calc_residual(scb); + else + ahc_set_residual(scb, 0); } /* @@ -228,7 +229,7 @@ */ static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, - u_int remote_id, struct tmode_tstate **tstate) + u_int remote_id, struct ahc_tmode_tstate **tstate) { /* * Transfer data structures are stored from the perspective @@ -345,10 +346,10 @@ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); } else { if ((ahc->features & AHC_AUTOPAUSE) == 0) - pause_sequencer(ahc); + ahc_pause(ahc); ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); if ((ahc->features & AHC_AUTOPAUSE) == 0) - unpause_sequencer(ahc); + ahc_unpause(ahc); } } @@ -412,19 +413,28 @@ * completion queues. This avoids a costly PCI bus read in * most cases. */ - intstat = 0; - if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) + if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0 + && (queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) intstat = CMDCMPLT; - - if ((intstat & INT_PEND) == 0 - || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) { - + else { intstat = ahc_inb(ahc, INTSTAT); + /* + * We can't generate queuestat once above + * or we are exposed to a race when our + * interrupt is shared with another device. + * if instat showed a command complete interrupt, + * but our first generation of queue stat + * "just missed" the delivery of this transaction, + * we would clear the command complete interrupt + * below without ever servicing the completed + * command. + */ + queuestat = ahc_check_cmdcmpltqueues(ahc); #if AHC_PCI_CONFIG > 0 if (ahc->unsolicited_ints > 500 && (ahc->chip & AHC_PCI) != 0 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0) - ahc_pci_intr(ahc); + ahc->bus_intr(ahc); #endif } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Fri May 4 15:16:28 2001 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#66 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -112,7 +112,6 @@ * 8: SMP friendliness has been improved * */ -#include /* * The next three defines are user configurable. These should be the only @@ -158,8 +157,8 @@ * The scsi error recovery code performs its own bus settle * delay handling for error recovery actions. */ -#ifdef CONFIG_AIC7XXX_RESET_DELAY -#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY +#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS +#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS #else #define AIC7XXX_RESET_DELAY 5000 #endif @@ -479,45 +478,48 @@ #endif -static void ahc_handle_scsi_status(struct ahc_softc *, - struct ahc_linux_device *, struct scb *); -static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static void ahc_sem_timeout(u_long arg); -static void ahc_release_sim_queue(u_long arg); -static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); -static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc); -static void aic7xxx_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -static void aic7xxx_device_queue_depth(struct ahc_softc *ahc, - Scsi_Device *device); -static struct ahc_linux_target* ahc_alloc_target(struct ahc_softc *, - u_int, u_int); -static void ahc_free_target(struct ahc_softc *ahc, - struct ahc_linux_target *targ); -static struct ahc_linux_device* ahc_alloc_device(struct ahc_softc *, - struct ahc_linux_target *, - u_int); -static void ahc_free_device(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_run_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static void ahc_setup_tag_info(char *p, char *end); -static int ahc_next_unit(void); +static void ahc_linux_handle_scsi_status(struct ahc_softc *, + struct ahc_linux_device *, + struct scb *); +static void ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); +static void ahc_linux_sem_timeout(u_long arg); +static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc); +static void ahc_linux_release_sim_queue(u_long arg); +static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); +static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); +static void ahc_linux_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs); +static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, + Scsi_Device *device); +static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, + u_int, u_int); +static void ahc_linux_free_target(struct ahc_softc*, + struct ahc_linux_target*); +static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, + struct ahc_linux_target*, + u_int); +static void ahc_linux_free_device(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_run_device_queue(struct ahc_softc*, + struct ahc_linux_device*); +static void ahc_linux_setup_tag_info(char *p, char *end); +static int ahc_linux_next_unit(void); +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); static __inline struct ahc_linux_device* - ahc_get_device(struct ahc_softc *ahc, u_int channel, - u_int target, u_int lun, int /*alloc*/); -static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc, - Scsi_Cmnd *cmd); -static __inline void ahc_run_complete_queue(struct ahc_softc *ahc, - struct ahc_cmd *acmd); -static __inline void ahc_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); -static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb); + ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, + u_int target, u_int lun, int alloc); +static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, + Scsi_Cmnd *cmd); +static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc, + struct ahc_cmd *acmd); +static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*); +static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline struct ahc_linux_device* -ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target, +ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc) { struct ahc_linux_target *targ; @@ -530,7 +532,7 @@ targ = ahc->platform_data->targets[target_offset]; if (targ == NULL) { if (alloc != 0) { - targ = ahc_alloc_target(ahc, channel, target); + targ = ahc_linux_alloc_target(ahc, channel, target); if (targ == NULL) return (NULL); } else @@ -538,17 +540,17 @@ } dev = targ->devices[lun]; if (dev == NULL && alloc != 0) - dev = ahc_alloc_device(ahc, targ, lun); + dev = ahc_linux_alloc_device(ahc, targ, lun); return (dev); } static __inline void -ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Typically, the complete queue has very few entries * queued to it before the queue is emptied by - * ahc_run_complete_queue, so sorting the entries + * ahc_linux_run_complete_queue, so sorting the entries * by generation number should be inexpensive. * We perform the sort so that commands that complete * with an error are retuned in the order origionally @@ -584,7 +586,7 @@ } static __inline void -ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) +ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) { u_long done_flags; @@ -601,7 +603,8 @@ } static __inline void -ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev) { if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 && dev->active == 0) { @@ -613,11 +616,11 @@ || dev->openings == 0 || dev->qfrozen != 0) return; - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); } static __inline void -ahc_run_device_queues(struct ahc_softc *ahc) +ahc_linux_run_device_queues(struct ahc_softc *ahc) { struct ahc_linux_device *dev; @@ -626,25 +629,25 @@ && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) { LIST_REMOVE(dev, links); dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_check_device_queue(ahc, dev); + ahc_linux_check_device_queue(ahc, dev); } } static __inline void -ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { /* * Determine whether we care to filter * information out of this command. If so, - * pass it on to ahc_filter_command() for more + * pass it on to ahc_linux_filter_command() for more * heavy weight processing. */ if (cmd->cmnd[0] == INQUIRY) - ahc_filter_command(ahc, cmd); + ahc_linux_filter_command(ahc, cmd); } static __inline void -ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb) +ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { Scsi_Cmnd *cmd; @@ -662,6 +665,24 @@ scsi_to_pci_dma_dir(cmd->sc_data_direction)); } +/************************ Shutdown/halt/reboot hook ***************************/ +#include +#include + +static struct notifier_block ahc_linux_notifier = { + ahc_linux_halt, NULL, 0 +}; + +static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf) +{ + struct ahc_softc *ahc; + + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + ahc_shutdown(ahc); + } + return (NOTIFY_OK); +} + /******************************** Macros **************************************/ #define BUILD_SCSIID(ahc, cmd) \ ((((cmd)->target << TID_SHIFT) & TID) \ @@ -820,6 +841,9 @@ /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ switch (rvalue) { case AHC_PCI: + { + char primary_channel; + value = ahc_get_pci_bus(lahc->dev_softc) - ahc_get_pci_bus(rahc->dev_softc); if (value != 0) @@ -828,19 +852,18 @@ - ahc_get_pci_slot(rahc->dev_softc); if (value != 0) break; - value = ahc_get_pci_function(lahc->dev_softc) - - ahc_get_pci_function(rahc->dev_softc); /* * On multi-function devices, the user can choose * to have function 1 probed before function 0. - * Function 0 is the only one that will have - * CHANNEL_B_PRIMARY set. + * Give whichever channel is the primary channel + * the lowest priority. */ - if (value < 0 - && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) - /* Swap the two */ - value = -value; + primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; + value = 1; + if (lahc->channel == primary_channel) + value = -1; break; + } case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { value = lahc->platform_data->bios_address @@ -857,7 +880,7 @@ } static void -ahc_setup_tag_info(char *p, char *end) +ahc_linux_setup_tag_info(char *p, char *end) { char *base; char *tok; @@ -865,7 +888,7 @@ char *tok_end2; int i; int instance; - int device; + int targ; int done; char tok_list[] = {'.', ',', '{', '}', '\0'}; @@ -873,7 +896,7 @@ return; instance = -1; - device = -1; + targ = -1; done = FALSE; base = p; /* Forward us just past the ':' */ @@ -886,13 +909,13 @@ case '{': if (instance == -1) instance = 0; - else if (device == -1) - device = 0; + else if (targ == -1) + targ = 0; tok++; break; case '}': - if (device != -1) - device = -1; + if (targ != -1) + targ = -1; else if (instance != -1) instance = -1; tok++; @@ -901,11 +924,11 @@ case '.': if (instance == -1) done = TRUE; - else if (device >= 0) - device++; + else if (targ >= 0) + targ++; else if (instance >= 0) instance++; - if ((device >= AHC_NUM_TARGETS) || + if ((targ >= AHC_NUM_TARGETS) || (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) done = TRUE; tok++; @@ -926,11 +949,12 @@ done = FALSE; } } - if ((instance >= 0) && (device >= 0) && - (instance < NUM_ELEMENTS(aic7xxx_tag_info)) && - (device < AHC_NUM_TARGETS)) - aic7xxx_tag_info[instance].tag_commands[device] = + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) + && (targ < AHC_NUM_TARGETS)) { + aic7xxx_tag_info[instance].tag_commands[targ] = simple_strtoul(tok, NULL, 0) & 0xff; + } tok = tok_end; break; } @@ -980,7 +1004,7 @@ continue; if (strncmp(p, "tag_info", n) == 0) { - ahc_setup_tag_info(p + n, end); + ahc_linux_setup_tag_info(p + n, end); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); @@ -989,8 +1013,10 @@ } else { *(options[i].flag) = ~(*(options[i].flag)); } + break; } } + register_reboot_notifier(&ahc_linux_notifier); return 1; } @@ -1004,7 +1030,7 @@ * Try to detect an Adaptec 7XXX controller. */ int -aic7xxx_detect(Scsi_Host_Template *template) +ahc_linux_detect(Scsi_Host_Template *template) { struct ahc_softc *ahc; int found; @@ -1016,8 +1042,8 @@ */ if (offsetof(struct ahc_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { - printf("aic7xxx_detect: SCSI data structures changed.\n"); - printf("aic7xxx_detect: Unable to attach\n"); + printf("ahc_linux_detect: SCSI data structures changed.\n"); + printf("ahc_linux_detect: Unable to attach\n"); return (0); } #ifdef MODULE @@ -1054,7 +1080,7 @@ found = 0; TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (aic7xxx_register_host(ahc, template) == 0) + if (ahc_linux_register_host(ahc, template) == 0) found++; } aic7xxx_detect_complete++; @@ -1062,7 +1088,7 @@ } int -aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) +ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) { char buf[80]; struct Scsi_Host *host; @@ -1081,12 +1107,13 @@ host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHC_NSEG; - host->select_queue_depths = aic7xxx_select_queue_depth; + host->select_queue_depths = ahc_linux_select_queue_depth; + /* XXX No way to communicate the ID for multiple channels */ host->this_id = ahc->our_id; host->irq = ahc->platform_data->irq; host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; - ahc_set_unit(ahc, ahc_next_unit()); + ahc_set_unit(ahc, ahc_linux_next_unit()); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { @@ -1094,8 +1121,10 @@ ahc_set_name(ahc, new_name); } host->unique_id = ahc->unit; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) scsi_set_pci_device(host, ahc->dev_softc); - aic7xxx_initialize_scsi_bus(ahc); +#endif + ahc_linux_initialize_scsi_bus(ahc); ahc_unlock(ahc, &s); return (0); } @@ -1107,7 +1136,7 @@ * scenario. */ static int -ahc_next_unit() +ahc_linux_next_unit() { struct ahc_softc *ahc; int unit; @@ -1129,7 +1158,7 @@ * target. */ void -aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc) +ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc) { int i; int numtarg; @@ -1159,7 +1188,7 @@ for (; i < numtarg; i++) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; @@ -1175,20 +1204,27 @@ tinfo = ahc_fetch_transinfo(ahc, channel, our_id, target_id, &tstate); tinfo->goal = tinfo->user; + /* + * Don't try negotiations that require PPR messages + * until we successfully retrieve Inquiry data. + */ + tinfo->goal.ppr_options = 0; + if (tinfo->goal.transport_version > SCSI_REV_2) + tinfo->goal.transport_version = SCSI_REV_2; ahc_compile_devinfo(&devinfo, our_id, target_id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); - ahc_update_target_msg_request(ahc, &devinfo, tinfo, - /*force*/FALSE, /*paused*/FALSE); + ahc_update_neg_request(ahc, &devinfo, tstate, + tinfo, /*force*/FALSE); } /* Give the bus some time to recover */ if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { - ahc->platform_data->qfrozen++; + ahc_linux_freeze_sim_queue(ahc); init_timer(&ahc->platform_data->reset_timer); ahc->platform_data->reset_timer.data = (u_long)ahc; ahc->platform_data->reset_timer.expires = jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; ahc->platform_data->reset_timer.function = - ahc_release_sim_queue; + ahc_linux_release_sim_queue; add_timer(&ahc->platform_data->reset_timer); } } @@ -1238,6 +1274,11 @@ 0x1000); #endif } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* XXX Need an instance detach in the PCI code */ + if (ahc->dev_softc != NULL) + ahc->dev_softc->driver = NULL; +#endif free(ahc->platform_data, M_DEVBUF); } } @@ -1252,28 +1293,41 @@ } void -ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable) +ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { struct ahc_linux_device *dev; + int was_queuing; + int now_queuing; - dev = ahc_get_device(ahc, devinfo->channel - 'A', - devinfo->target, - devinfo->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', + devinfo->target, + devinfo->lun, /*alloc*/FALSE); + was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + now_queuing = alg != AHC_QUEUE_NONE; if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 + && (was_queuing != now_queuing) && (dev->active != 0)) { dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } - if (enable) { - /* - * Start out agressively and allow our - * dynamic queue depth algorithm take - * care of the rest. - */ - dev->maxtags = AHC_MAX_QUEUE; - dev->openings = dev->maxtags - dev->active; + dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + if (now_queuing) { + + if (!was_queuing) { + /* + * Start out agressively and allow our + * dynamic queue depth algorithm to take + * care of the rest. + */ + dev->maxtags = AHC_MAX_QUEUE; + dev->openings = dev->maxtags - dev->active; + } + if (alg == AHC_QUEUE_TAGGED) + dev->flags |= AHC_DEV_Q_TAGGED; + else + dev->flags |= AHC_DEV_Q_BASIC; } else { /* We can only have one opening */ dev->maxtags = 0; @@ -1326,9 +1380,9 @@ struct ahc_busyq *busyq; struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, chan, targ, - clun, /*alloc*/FALSE); - + dev = ahc_linux_get_device(ahc, chan, + targ, clun, + /*alloc*/FALSE); if (dev == NULL) continue; @@ -1341,7 +1395,7 @@ acmd_links.tqe); count++; cmd->result = status << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } } } @@ -1355,8 +1409,8 @@ * off the input host adapter. */ static void -aic7xxx_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) +ahc_linux_select_queue_depth(struct Scsi_Host * host, + Scsi_Device * scsi_devs) { Scsi_Device *device; struct ahc_softc *ahc; @@ -1368,7 +1422,7 @@ scbnum = 0; for (device = scsi_devs; device != NULL; device = device->next) { if (device->host == host) { - aic7xxx_device_queue_depth(ahc, device); + ahc_linux_device_queue_depth(ahc, device); scbnum += device->queue_depth; } } @@ -1379,11 +1433,11 @@ * Determines the queue depth for a given device. */ static void -aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) +ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint8_t tags; ahc_compile_devinfo(&devinfo, @@ -1397,7 +1451,7 @@ tags = 0; if (device->tagged_supported != 0 - && (tstate->discenable & devinfo.target_mask) != 0) { + && (ahc->user_discenable & devinfo.target_mask) != 0) { if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { printf("aic7xxx: WARNING, insufficient " @@ -1418,7 +1472,7 @@ } if (tags != 0) { device->queue_depth = tags; - ahc_set_tags(ahc, &devinfo, TRUE); + ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); printf("scsi%d:%d:%d:%d: Tagged Queuing enabled. Depth %d\n", ahc->platform_data->host->host_no, device->channel, device->id, device->lun, tags); @@ -1437,7 +1491,7 @@ * Queue an SCB to the controller. */ int -aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahc_softc *ahc; struct ahc_linux_device *dev; @@ -1451,29 +1505,29 @@ cmd->scsi_done = scsi_done; ahc_lock(ahc, &flags); - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/TRUE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/TRUE); if (dev == NULL) { ahc_unlock(ahc, &flags); - printf("aic7xxx_queue: Unable to allocate device!\n"); + printf("aic7xxx_linux_queue: Unable to allocate device!\n"); return (-ENOMEM); } cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); - ahc_run_device_queue(ahc, dev); + ahc_linux_run_device_queue(ahc, dev); ahc_unlock(ahc, &flags); return (0); } static void -ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_cmd *acmd; struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; uint16_t mask; while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL @@ -1524,19 +1578,26 @@ SCB_GET_OUR_ID(scb), SCB_GET_TARGET(ahc, scb), &tstate); hscb->scsirate = tinfo->scsirate; - hscb->scsioffset = tinfo->current.offset; + hscb->scsioffset = tinfo->curr.offset; if ((tstate->ultraenb & mask) != 0) hscb->control |= ULTRAENB; - if ((tstate->discenable & mask) != 0) + if ((ahc->user_discenable & mask) != 0) hscb->control |= DISCENB; - if ((tstate->tagenable & mask) != 0) { - /* XXX What about devices that dislike ordered tags? */ - if ((dev->num_commands % 256) == 0) - hscb->control |= MSG_ORDERED_Q_TAG; - else - hscb->control |= MSG_SIMPLE_Q_TAG; + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { + if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH + && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; + } } hscb->cdb_len = cmd->cmd_len; @@ -1632,7 +1693,8 @@ LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); dev->openings--; dev->active++; - dev->num_commands++; + dev->commands_issued++; + dev->commands_since_idle_or_otag++; /* * We only allow one untagged transaction @@ -1661,7 +1723,7 @@ * SCSI controller interrupt handler. */ void -aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs) +ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -1676,12 +1738,12 @@ * dynamically register one, we'll have to postpone * that until we get integrated into the kernel. */ - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &flags); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } void @@ -1692,11 +1754,11 @@ acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); } static struct ahc_linux_target* -ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) +ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) { struct ahc_linux_target *targ; u_int target_offset; @@ -1715,7 +1777,7 @@ } static void -ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) +ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) { u_int target_offset; @@ -1727,7 +1789,7 @@ } static struct ahc_linux_device* -ahc_alloc_device(struct ahc_softc *ahc, +ahc_linux_alloc_device(struct ahc_softc *ahc, struct ahc_linux_target *targ, u_int lun) { struct ahc_linux_device *dev; @@ -1760,7 +1822,7 @@ } static void -ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_linux_target *targ; @@ -1769,14 +1831,14 @@ free(dev, M_DEVBUF); targ->refcount--; if (targ->refcount == 0) - ahc_free_target(ahc, targ); + ahc_linux_free_target(ahc, targ); } /* * Return a string describing the driver. */ const char * -aic7xxx_info(struct Scsi_Host *host) +ahc_linux_info(struct Scsi_Host *host) { static char buffer[512]; char ahc_info[256]; @@ -1802,7 +1864,7 @@ void ahc_send_async(struct ahc_softc *ahc, char channel, - u_int target, u_int lun, ac_code code) + u_int target, u_int lun, ac_code code, void *arg) { switch (code) { case AC_TRANSFER_NEG: @@ -1811,7 +1873,7 @@ struct ahc_linux_target *targ; struct info_str info; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int target_offset; info.buffer = buf; @@ -1827,10 +1889,10 @@ * Don't bother reporting results while * negotiations are still pending. */ - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || tinfo->current.offset != tinfo->goal.offset - || tinfo->current.ppr_options != tinfo->goal.ppr_options) + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options) if (bootverbose == 0) break; @@ -1843,24 +1905,24 @@ target_offset += 8; targ = ahc->platform_data->targets[target_offset]; if (targ != NULL - && tinfo->current.period == targ->last_tinfo.period - && tinfo->current.width == targ->last_tinfo.width - && tinfo->current.offset == targ->last_tinfo.offset - && tinfo->current.ppr_options == targ->last_tinfo.ppr_options) + && tinfo->curr.period == targ->last_tinfo.period + && tinfo->curr.width == targ->last_tinfo.width + && tinfo->curr.offset == targ->last_tinfo.offset + && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options) if (bootverbose == 0) break; - targ->last_tinfo.period = tinfo->current.period; - targ->last_tinfo.width = tinfo->current.width; - targ->last_tinfo.offset = tinfo->current.offset; - targ->last_tinfo.ppr_options = tinfo->current.ppr_options; + targ->last_tinfo.period = tinfo->curr.period; + targ->last_tinfo.width = tinfo->curr.width; + targ->last_tinfo.offset = tinfo->curr.offset; + targ->last_tinfo.ppr_options = tinfo->curr.ppr_options; printf("(%s:%c:", ahc_name(ahc), channel); if (target == CAM_TARGET_WILDCARD) printf("*): "); else printf("%d): ", target); - ahc_format_transinfo(&info, &tinfo->current); + ahc_format_transinfo(&info, &tinfo->curr); if (info.pos < info.length) *info.buffer = '\0'; else @@ -1909,7 +1971,7 @@ dev = scb->platform_data->dev; dev->active--; dev->openings++; - ahc_unmap_scb(ahc, scb); + ahc_linux_unmap_scb(ahc, scb); if (scb->flags & SCB_SENSE) { memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), MIN(sizeof(struct scsi_sense_data), @@ -1928,10 +1990,19 @@ ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); } else { ahc_set_transaction_status(scb, CAM_REQ_CMP); - ahc_sniff_command(ahc, cmd); + ahc_linux_sniff_command(ahc, cmd); } } else if (ahc_get_transaction_status(scb) == DID_OK) { - ahc_handle_scsi_status(ahc, dev, scb); + ahc_linux_handle_scsi_status(ahc, dev, scb); + } else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) { + /* + * Should a selection timeout kill the device? + * That depends on whether the selection timeout + * is persistent. Since we have no guarantee that + * the mid-layer will issue an inquiry for this device + * again, we can't just kill it off. + dev->flags |= AHC_DEV_UNCONFIGURED; + */ } if (dev->openings == 1 @@ -1950,10 +2021,14 @@ dev->openings++; } - if (dev->active == 0 - && (dev->flags & AHC_DEV_UNCONFIGURED) != 0) - ahc_free_device(ahc, dev); - else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + if (dev->active == 0) + dev->commands_since_idle_or_otag = 0; + + if (TAILQ_EMPTY(&dev->busyq)) { + if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 + && dev->active == 0) + ahc_linux_free_device(ahc, dev); + } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links); dev->flags |= AHC_DEV_ON_RUN_LIST; } @@ -1964,12 +2039,12 @@ } ahc_free_scb(ahc, scb); - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); } static void -ahc_handle_scsi_status(struct ahc_softc *ahc, - struct ahc_linux_device *dev, struct scb *scb) +ahc_linux_handle_scsi_status(struct ahc_softc *ahc, + struct ahc_linux_device *dev, struct scb *scb) { /* * We don't currently trust the mid-layer to @@ -2050,7 +2125,7 @@ } static void -ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) { switch (cmd->cmnd[0]) { case INQUIRY: @@ -2058,8 +2133,9 @@ struct ahc_devinfo devinfo; struct scsi_inquiry_data *sid; struct ahc_initiator_tinfo *targ_info; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; struct ahc_syncrate *syncrate; + struct ahc_linux_device *dev; u_int scsiid; u_int maxsync; int minlen; @@ -2078,15 +2154,20 @@ /* * Determine if this lun actually exists. If so, * hold on to its corresponding device structure. - */ + * If not, make sure we release the device and + * don't bother processing the rest of this inquiry + * command. + */ + dev = ahc_linux_get_device(ahc, cmd->channel, + cmd->target, cmd->lun, + /*alloc*/FALSE); if (cmd->request_bufflen >= 1 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - struct ahc_linux_device *dev; - dev = ahc_get_device(ahc, cmd->channel, - cmd->target, cmd->lun, - /*alloc*/FALSE); dev->flags &= ~AHC_DEV_UNCONFIGURED; + } else { + dev->flags |= AHC_DEV_UNCONFIGURED; + break; } /* @@ -2108,17 +2189,17 @@ ppr_options = targ_info->user.ppr_options; minlen = offsetof(struct scsi_inquiry_data, version) + 1; if (cmd->request_bufflen >= minlen) { - targ_info->current.protocol_version = SID_ANSI_REV(sid); + targ_info->curr.protocol_version = SID_ANSI_REV(sid); /* * Only attempt SPI3 once we've verified that * the device claims to support SPI3 features. */ - if (targ_info->current.protocol_version < SCSI_REV_2) - targ_info->current.transport_version = + if (targ_info->curr.protocol_version < SCSI_REV_2) + targ_info->curr.transport_version = SID_ANSI_REV(sid); else - targ_info->current.transport_version = + targ_info->curr.transport_version = SCSI_REV_2; } @@ -2137,18 +2218,26 @@ break; } minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1; - if (cmd->request_bufflen >= minlen - && (sid->additional_length + 4) >= minlen) { - if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0) + /* + * This is a kludge to deal with inquiry requests that + * are not large enough for us to pull the spi3 bits. + * In this case, we assume that a device that tells us + * they can provide inquiry data that spans the SPI3 + * bits can handle a PPR request. If the inquiry + * request has sufficient buffer space to cover these + * bits, we check them to see if any ppr options are + * available. + */ + if ((sid->additional_length + 4) >= minlen) { + if (cmd->request_bufflen >= minlen + && (sid->spi3data & SID_SPI_CLOCK_DT) == 0) ppr_options = 0; - if ((sid->spi3data & SID_SPI_MASK) != 0 - && targ_info->current.protocol_version > SCSI_REV_2) - targ_info->current.transport_version = 3; + if (targ_info->curr.protocol_version > SCSI_REV_2) + targ_info->curr.transport_version = 3; } else { ppr_options = 0; } - ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN); if ((ahc->features & AHC_ULTRA2) != 0) @@ -2162,6 +2251,11 @@ &ppr_options, maxsync); ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate, &offset, width, ROLE_UNKNOWN); + if (offset == 0 || period == 0) { + period = 0; + offset = 0; + ppr_options = 0; + } /* Apply our filtered user settings. */ ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, /*paused*/FALSE); @@ -2171,14 +2265,14 @@ break; } default: - panic("ahc_filter_command: Unexpected Command type %x\n", + panic("ahc_linux_filter_command: Unexpected Command type %x\n", cmd->cmnd[0]); break; } } static void -ahc_sem_timeout(u_long arg) +ahc_linux_sem_timeout(u_long arg) { struct semaphore *sem; @@ -2187,22 +2281,42 @@ } static void -ahc_release_sim_queue(u_long arg) +ahc_linux_freeze_sim_queue(struct ahc_softc *ahc) +{ + ahc->platform_data->qfrozen++; + if (ahc->platform_data->qfrozen == 1) + scsi_block_requests(ahc->platform_data->host); +} + +static void +ahc_linux_release_sim_queue(u_long arg) { struct ahc_softc *ahc; u_long s; + int unblock_reqs; ahc = (struct ahc_softc *)arg; + unblock_reqs = 0; ahc_lock(ahc, &s); if (ahc->platform_data->qfrozen > 0) ahc->platform_data->qfrozen--; - if (ahc->platform_data->qfrozen == 0) - ahc_run_device_queues(ahc); + if (ahc->platform_data->qfrozen == 0) { + unblock_reqs = 1; + ahc_linux_run_device_queues(ahc); + } ahc_unlock(ahc, &s); + /* + * There is still a race here. The mid-layer + * should keep its own freeze count and use + * a bottom half handler to run the queues + * so we can unblock with our own lock held. + */ + if (unblock_reqs) + scsi_unblock_requests(ahc->platform_data->host); } static int -aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) +ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2242,8 +2356,8 @@ * at all, and the system wanted us to just abort the * command return success. */ - dev = ahc_get_device(ahc, cmd->channel, cmd->target, - cmd->lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/FALSE); if (dev == NULL) { /* @@ -2267,7 +2381,7 @@ if (flag == SCB_ABORT) { TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); cmd->result = DID_ABORT << 16; - ahc_queue_cmd_complete(ahc, cmd); + ahc_linux_queue_cmd_complete(ahc, cmd); retval = SUCCESS; goto done; } @@ -2315,7 +2429,7 @@ ahc->flags |= AHC_ALL_INTERRUPTS; do { ahc_intr(ahc); - pause_sequencer(ahc); + ahc_pause(ahc); ahc_clear_critical_section(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND); ahc->flags &= ~AHC_ALL_INTERRUPTS; @@ -2455,7 +2569,7 @@ retval = SUCCESS; done: if (paused) - unpause_sequencer(ahc); + ahc_unpause(ahc); if (wait) { struct timer_list timer; int ret; @@ -2464,7 +2578,7 @@ init_timer(&timer); timer.data = (u_long)&ahc->platform_data->eh_sem; timer.expires = jiffies + (5 * HZ); - timer.function = ahc_sem_timeout; + timer.function = ahc_linux_sem_timeout; add_timer(&timer); printf("Recovery code sleeping\n"); down(&ahc->platform_data->eh_sem); @@ -2476,12 +2590,12 @@ } ahc_lock(ahc, &s); } - ahc_run_device_queues(ahc); + ahc_linux_run_device_queues(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); ahc_unlock(ahc, &s); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return (retval); } @@ -2490,11 +2604,11 @@ * Abort the current SCSI command(s). */ int -aic7xxx_abort(Scsi_Cmnd *cmd) +ahc_linux_abort(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); if (error != 0) printf("aic7xxx_abort returns %d\n", error); return (error); @@ -2504,11 +2618,11 @@ * Attempt to send a target reset message to the device that timed out. */ int -aic7xxx_dev_reset(Scsi_Cmnd *cmd) +ahc_linux_dev_reset(Scsi_Cmnd *cmd) { int error; - error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); if (error != 0) printf("aic7xxx_dev_reset returns %d\n", error); return (error); @@ -2518,7 +2632,7 @@ * Reset the SCSI bus. */ int -aic7xxx_bus_reset(Scsi_Cmnd *cmd) +ahc_linux_bus_reset(Scsi_Cmnd *cmd) { struct ahc_softc *ahc; struct ahc_cmd *acmd; @@ -2543,7 +2657,7 @@ "%d SCBs aborted.\n", ahc_name(ahc), found); if (acmd != NULL) - ahc_run_complete_queue(ahc, acmd); + ahc_linux_run_complete_queue(ahc, acmd); spin_lock_irq(&io_request_lock); return SUCCESS; @@ -2553,7 +2667,7 @@ * Return the disk geometry for the given SCSI device. */ int -aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) +ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) { int heads; int sectors; @@ -2597,14 +2711,23 @@ * module. */ int -aic7xxx_release(struct Scsi_Host * host) +ahc_linux_release(struct Scsi_Host * host) { struct ahc_softc *ahc; if (host != NULL) { + ahc = *(struct ahc_softc **)host->hostdata; ahc_free(ahc); } + if (TAILQ_EMPTY(&ahc_tailq)) { + unregister_reboot_notifier(&ahc_linux_notifier); +#ifdef CONFIG_PCI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_unregister_driver(&aic7xxx_pci_driver); +#endif +#endif + } return (0); } @@ -2626,8 +2749,8 @@ for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct ahc_cmd *acmd; - dev = ahc_get_device(ahc, channel, target, - lun, /*alloc*/FALSE); + dev = ahc_linux_get_device(ahc, channel, target, + lun, /*alloc*/FALSE); if (dev == NULL) continue; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Fri May 4 15:16:28 2001 @@ -28,24 +28,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#2 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#3 $ */ #ifndef _AIC7XXX_LINUX_HOST_H_ #define _AIC7XXX_LINUX_HOST_H_ -int aic7xxx_proc_info(char *, char **, off_t, int, int, int); -int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -int aic7xxx_detect(Scsi_Host_Template *); -int aic7xxx_release(struct Scsi_Host *); -const char *aic7xxx_info(struct Scsi_Host *); -int aic7xxx_biosparam(Disk *, kdev_t, int[]); -int aic7xxx_bus_reset(Scsi_Cmnd *); -int aic7xxx_dev_reset(Scsi_Cmnd *); -int aic7xxx_abort(Scsi_Cmnd *); +int ahc_linux_proc_info(char *, char **, off_t, int, int, int); +int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +int ahc_linux_detect(Scsi_Host_Template *); +int ahc_linux_release(struct Scsi_Host *); +const char *ahc_linux_info(struct Scsi_Host *); +int ahc_linux_biosparam(Disk *, kdev_t, int[]); +int ahc_linux_bus_reset(Scsi_Cmnd *); +int ahc_linux_dev_reset(Scsi_Cmnd *); +int ahc_linux_abort(Scsi_Cmnd *); #if defined(__i386__) -# define AIC7XXX_BIOSPARAM aic7xxx_biosparam +# define AIC7XXX_BIOSPARAM ahc_linux_biosparam #else # define AIC7XXX_BIOSPARAM NULL #endif @@ -58,23 +58,23 @@ next: NULL, \ module: NULL, \ proc_dir: NULL, \ - proc_info: aic7xxx_proc_info, \ + proc_info: ahc_linux_proc_info, \ name: NULL, \ - detect: aic7xxx_detect, \ - release: aic7xxx_release, \ - info: aic7xxx_info, \ + detect: ahc_linux_detect, \ + release: ahc_linux_release, \ + info: ahc_linux_info, \ command: NULL, \ - queuecommand: aic7xxx_queue, \ + queuecommand: ahc_linux_queue, \ eh_strategy_handler: NULL, \ - eh_abort_handler: aic7xxx_abort, \ - eh_device_reset_handler: aic7xxx_dev_reset, \ - eh_bus_reset_handler: aic7xxx_bus_reset, \ + eh_abort_handler: ahc_linux_abort, \ + eh_device_reset_handler: ahc_linux_dev_reset, \ + eh_bus_reset_handler: ahc_linux_bus_reset, \ eh_host_reset_handler: NULL, \ abort: NULL, \ reset: NULL, \ slave_attach: NULL, \ bios_param: AIC7XXX_BIOSPARAM, \ - can_queue: 254, /* max simultaneous cmds */\ + can_queue: 253, /* max simultaneous cmds */\ this_id: -1, /* scsi id of host adapter */\ sg_tablesize: 0, /* max scatter-gather cmds */\ cmd_per_lun: 2, /* cmds per lun */\ diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Tue Mar 6 22:44:16 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#15 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#17 $ */ #include "aic7xxx_osm.h" @@ -57,7 +57,7 @@ { 0 } }; -static struct pci_driver aic7xxx_pci_driver = { +struct pci_driver aic7xxx_pci_driver = { name: "aic7xxx", probe: ahc_linux_pci_dev_probe, remove: ahc_linux_pci_dev_remove, @@ -133,7 +133,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pdev->driver_data = ahc; if (aic7xxx_detect_complete) - aic7xxx_register_host(ahc, aic7xxx_driver_template); + ahc_linux_register_host(ahc, aic7xxx_driver_template); #endif return (0); } @@ -191,11 +191,9 @@ { uint32_t command; u_long base; -#ifdef MMAPIO u_long start; u_long base_page; u_long base_offset; -#endif uint8_t *maddr; command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); @@ -306,11 +304,47 @@ int error; ahc->platform_data->irq = ahc->dev_softc->irq; - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_INTERRUPT|SA_SHIRQ, "aic7xxx", ahc); - if (error < 0) - error = request_irq(ahc->platform_data->irq, aic7xxx_isr, - SA_SHIRQ, "aic7xxx", ahc); + error = request_irq(ahc->platform_data->irq, ahc_linux_isr, + SA_SHIRQ, "aic7xxx", ahc); return (-error); +} + +void +ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_set_power_state(ahc->dev_softc, new_state); +#else + uint32_t cap; + u_int cap_offset; + + /* + * Traverse the capability list looking for + * the power management capability. + */ + cap = 0; + cap_offset = ahc_pci_read_config(ahc->dev_softc, + PCIR_CAP_PTR, /*bytes*/1); + while (cap_offset != 0) { + + cap = ahc_pci_read_config(ahc->dev_softc, + cap_offset, /*bytes*/4); + if ((cap & 0xFF) == 1 + && ((cap >> 16) & 0x3) > 0) { + uint32_t pm_control; + + pm_control = ahc_pci_read_config(ahc->dev_softc, + cap_offset + 4, + /*bytes*/4); + pm_control &= ~0x3; + pm_control |= new_state; + ahc_pci_write_config(ahc->dev_softc, + cap_offset + 4, + pm_control, /*bytes*/2); + break; + } + cap_offset = (cap >> 8) & 0xFF; + } +#endif } diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Thu Apr 12 12:16:35 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Fri May 4 15:16:28 2001 @@ -18,7 +18,7 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $ * * Copyright (c) 2000, 2001 Adaptec Inc. * All rights reserved. @@ -47,7 +47,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -62,6 +62,10 @@ #include #include +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #include #endif @@ -79,14 +83,6 @@ #include "queue.h" #include "scsi_message.h" -/* - * We never have to reference the current task, and the driver core - * makes ample use of this "name". - */ -#ifdef current -#undef current -#endif - /************************* Forward Declarations *******************************/ struct ahc_softc; typedef struct pci_dev *ahc_dev_softc_t; @@ -114,7 +110,7 @@ /***************************** Bus Space/DMA **********************************/ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17) typedef dma_addr_t bus_addr_t; #else typedef uint32_t bus_addr_t; @@ -353,11 +349,7 @@ #include #endif -#define AIC7XXX_DRIVER_VERSION "6.1.5" - -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) -#endif +#define AIC7XXX_DRIVER_VERSION "6.1.13" /**************************** Front End Queues ********************************/ /* @@ -401,7 +393,9 @@ AHC_DEV_UNCONFIGURED = 0x01, AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHC_DEV_ON_RUN_LIST = 0x08 /* Queued to be run later */ + AHC_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ + AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ + AHC_DEV_Q_TAGGED = 0x20 /* Allow full SCSI2 command queueing */ } ahc_dev_flags; struct ahc_linux_target; @@ -434,7 +428,7 @@ /* * Cumulative command counter. */ - u_int num_commands; + u_long commands_issued; /* * The number of tagged transactions when @@ -465,8 +459,16 @@ * on devices with a fixed number of tags. */ u_int last_queuefull_same_count; - #define AHC_LOCK_TAGS_COUNT 50 + + /* + * How many transactions have been queued + * without the device going idle. We use + * this statistic to + */ + u_int commands_since_idle_or_otag; +#define AHC_OTAG_THRESH 250 + int lun; struct ahc_linux_target *target; }; @@ -570,9 +572,6 @@ #endif #define mb() \ __asm__ __volatile__("mb": : :"memory") -#elif defined(__sparc__) -#define MMAPIO -/* The default mb() define does what this driver wants. -DaveM */ #endif static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port); @@ -644,8 +643,8 @@ } /**************************** Initialization **********************************/ -int aic7xxx_register_host(struct ahc_softc *ahc, - Scsi_Host_Template *template); +int ahc_linux_register_host(struct ahc_softc *, + Scsi_Host_Template *); /*************************** Pretty Printing **********************************/ struct info_str { @@ -784,11 +783,24 @@ #define PCIR_SUBVEND_0 0x2c #define PCIR_SUBDEV_0 0x2e +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +extern struct pci_driver aic7xxx_pci_driver; +#endif + +typedef enum +{ + AHC_POWER_STATE_D0, + AHC_POWER_STATE_D1, + AHC_POWER_STATE_D2, + AHC_POWER_STATE_D3 +} ahc_power_state; + +void ahc_power_state_change(struct ahc_softc *ahc, + ahc_power_state new_state); /**************************** VL/EISA Routines ********************************/ int aic7770_linux_probe(Scsi_Host_Template *); int aic7770_map_registers(struct ahc_softc *ahc); -int aic7770_map_int(struct ahc_softc *ahc, - u_int irq, int shared); +int aic7770_map_int(struct ahc_softc *ahc, u_int irq); /******************************* PCI Routines *********************************/ /* @@ -1047,16 +1059,16 @@ } void ahc_platform_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, ahc_queue_alg); int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -void aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs); +void ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahc_platform_flushwork(struct ahc_softc *ahc); int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *); void ahc_done(struct ahc_softc*, struct scb*); void ahc_send_async(struct ahc_softc *, char channel, - u_int target, u_int lun, ac_code); + u_int target, u_int lun, ac_code, void *); void ahc_print_path(struct ahc_softc *, struct scb *); void ahc_platform_dump_card_state(struct ahc_softc *ahc); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_pci.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_pci.c Fri May 4 15:16:28 2001 @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#17 $ + * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#24 $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $ */ @@ -263,7 +263,7 @@ { ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec 2930C SCSI adapter (VAR)", + "Adaptec 2930C Ultra SCSI adapter (VAR)", ahc_aic7860_setup }, /* aic7870 based controllers */ @@ -452,7 +452,7 @@ { ID_AIC7892_ARO, ID_ALL_MASK, - "Adaptec aic7892 Ultra2 SCSI adapter (ARO)", + "Adaptec aic7892 Ultra160 SCSI adapter (ARO)", ahc_aic7892_setup }, /* aic7895 based controllers */ @@ -546,13 +546,13 @@ { ID_AIC7859 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7859 Ultra SCSI adapter", + "Adaptec aic7859 SCSI adapter", ahc_aic7860_setup }, { ID_AIC7860 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7860 SCSI adapter", + "Adaptec aic7860 Ultra SCSI adapter", ahc_aic7860_setup }, { @@ -644,16 +644,6 @@ #define CACHESIZE 0x0000003ful /* only 5 bits */ #define LATTIME 0x0000ff00ul -typedef enum -{ - AHC_POWER_STATE_D0, - AHC_POWER_STATE_D1, - AHC_POWER_STATE_D2, - AHC_POWER_STATE_D3 -} ahc_power_state; - -static void ahc_power_state_change(struct ahc_softc *ahc, - ahc_power_state new_state); static int ahc_ext_scbram_present(struct ahc_softc *ahc); static void ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast, int large); @@ -761,9 +751,11 @@ if (error != 0) return (error); + ahc->bus_intr = ahc_pci_intr; + /* Remeber how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { - pause_sequencer(ahc); + ahc_pause(ahc); if ((ahc->features & AHC_ULTRA2) != 0) our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; else @@ -786,7 +778,8 @@ /* Perform ALT-Mode Setup */ sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS); + ahc_outb(ahc, OPTIONMODE, + OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS); ahc_outb(ahc, SFUNCT, sfunct); /* Normal mode setup */ @@ -794,9 +787,6 @@ |TARGCRCENDEN); } - error = ahc_pci_map_int(ahc); - if (error != 0) - return (error); dscommand0 = ahc_inb(ahc, DSCOMMAND0); dscommand0 |= MPARCKEN|CACHETHEN; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -825,6 +815,19 @@ /*bytes*/1) & CACHESIZE; ahc->pci_cachesize *= 4; + /* + * We cannot perform ULTRA speeds without the presense + * of the external precision resistor. + */ + if ((ahc->features & AHC_ULTRA) != 0) { + uint32_t devconfig; + + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + if ((devconfig & REXTVALID) == 0) + ahc->features &= ~AHC_ULTRA; + } + /* See if we have a SEEPROM and perform auto-term */ check_extport(ahc, &sxfrctl1); @@ -879,20 +882,6 @@ if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; - /* - * We cannot perform ULTRA speeds without - * the presense of the external precision - * resistor. - */ - if ((ahc->features & AHC_ULTRA) != 0) { - uint32_t devconfig; - - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, /*bytes*/4); - if ((devconfig & REXTVALID) == 0) - ahc->flags |= AHC_ULTRA_DISABLED; - } - /* Core initialization */ error = ahc_init(ahc); if (error != 0) @@ -903,42 +892,16 @@ */ ahc_softc_insert(ahc); - return (0); -} - -static void -ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) -{ - uint32_t cap; - u_int cap_offset; - /* - * Traverse the capability list looking for - * the power management capability. + * Allow interrupts now that we are completely setup. */ - cap = 0; - cap_offset = ahc_pci_read_config(ahc->dev_softc, - PCIR_CAP_PTR, /*bytes*/1); - while (cap_offset != 0) { - - cap = ahc_pci_read_config(ahc->dev_softc, - cap_offset, /*bytes*/4); - if ((cap & 0xFF) == 1 - && ((cap >> 16) & 0x3) > 0) { - uint32_t pm_control; - - pm_control = ahc_pci_read_config(ahc->dev_softc, - cap_offset + 4, - /*bytes*/4); - pm_control &= ~0x3; - pm_control |= new_state; - ahc_pci_write_config(ahc->dev_softc, - cap_offset + 4, - pm_control, /*bytes*/2); - break; - } - cap_offset = (cap >> 8) & 0xFF; - } + error = ahc_pci_map_int(ahc); + if (error != 0) + return (error); + + ahc_intr_enable(ahc, TRUE); + + return (0); } /* @@ -1190,32 +1153,37 @@ } sd.sd_chip = C56_66; } + release_seeprom(&sd); } -#if 0 if (!have_seeprom) { /* * Pull scratch ram settings and treat them as * if they are the contents of an seeprom if * the 'ADPT' signature is found in SCB2. + * We manually compose the data as 16bit values + * to avoid endian issues. */ ahc_outb(ahc, SCBPTR, 2); if (ahc_inb(ahc, SCB_BASE) == 'A' && ahc_inb(ahc, SCB_BASE + 1) == 'D' && ahc_inb(ahc, SCB_BASE + 2) == 'P' && ahc_inb(ahc, SCB_BASE + 3) == 'T') { - uint8_t *sc_bytes; + uint16_t *sc_data; int i; - sc_bytes = (uint8_t *)≻ - for (i = 0; i < 64; i++) - sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i); - /* Byte 0x1c is stored in byte 4 of SCB2 */ - sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4); + sc_data = (uint16_t *)≻ + for (i = 0; i < 32; i++) { + uint16_t val; + int j; + + j = i * 2; + val = ahc_inb(ahc, SRAM_BASE + j) + | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; + } have_seeprom = verify_cksum(&sc); } } -#endif if (!have_seeprom) { if (bootverbose) @@ -1301,9 +1269,8 @@ if (sc.adapter_control & CFRESETB) scsi_conf |= RESET_SCSI; - if ((sc.adapter_control & CFCHNLBPRIMARY) != 0 - && (ahc->features & AHC_MULTI_FUNC) != 0) - ahc->flags |= AHC_CHANNEL_B_PRIMARY; + ahc->flags |= + (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; if (sc.bios_control & CFEXTEND) ahc->flags |= AHC_EXTENDED_TRANS_A; @@ -1318,7 +1285,8 @@ ultraenb = 0; } - if (sc.signature == CFSIGNATURE) { + if (sc.signature == CFSIGNATURE + || sc.signature == CFSIGNATURE2) { uint32_t devconfig; /* Honor the STPWLEVEL settings */ @@ -1362,10 +1330,11 @@ have_autoterm = FALSE; } - if (have_autoterm) + if (have_autoterm) { + acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, adapter_control, sxfrctl1); - - release_seeprom(&sd); + release_seeprom(&sd); + } } static void @@ -1806,7 +1775,7 @@ ahc_outb(ahc, CLRINT, CLRPARERR); } - unpause_sequencer(ahc); + ahc_unpause(ahc); } static int diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c Fri May 4 15:16:28 2001 @@ -29,7 +29,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#7 $ + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#11 $ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" @@ -174,7 +174,7 @@ { struct ahc_linux_target *targ; struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; + struct ahc_tmode_tstate *tstate; int lun; tinfo = ahc_fetch_transinfo(ahc, channel, our_id, @@ -190,7 +190,7 @@ copy_info(info, "\tGoal: "); ahc_format_transinfo(info, &tinfo->goal); copy_info(info, "\tCurr: "); - ahc_format_transinfo(info, &tinfo->current); + ahc_format_transinfo(info, &tinfo->curr); for (lun = 0; lun < AHC_NUM_LUNS; lun++) { struct ahc_linux_device *dev; @@ -210,7 +210,7 @@ copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", dev->target->channel + 'A', dev->target->target, dev->lun); - copy_info(info, "\t\tCommands Queued %d\n", dev->num_commands); + copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); copy_info(info, "\t\tCommands Active %d\n", dev->active); copy_info(info, "\t\tCommand Openings %d\n", dev->openings); copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); @@ -221,7 +221,7 @@ * Return information to handle /proc support for the driver. */ int -aic7xxx_proc_info(char *buffer, char **start, off_t offset, +ahc_linux_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct ahc_softc *ahc; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h linux/drivers/scsi/aic7xxx/aic7xxx_reg.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h Tue Mar 6 19:18:16 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_reg.h Fri May 4 15:16:28 2001 @@ -86,8 +86,8 @@ #define SELDO 0x40 #define SELDI 0x20 #define SELINGO 0x10 -#define IOERR 0x08 #define SWRAP 0x08 +#define IOERR 0x08 #define SDONE 0x04 #define SPIORDY 0x02 #define DMADONE 0x01 @@ -191,8 +191,8 @@ #define BRDDAT5 0x20 #define BRDDAT4 0x10 #define BRDSTB 0x10 -#define BRDCS 0x08 #define BRDDAT3 0x08 +#define BRDCS 0x08 #define BRDDAT2 0x04 #define BRDRW 0x04 #define BRDRW_ULTRA2 0x02 @@ -242,8 +242,8 @@ #define PRELOADEN 0x80 #define WIDEODD 0x40 #define SCSIEN 0x20 -#define SDMAENACK 0x10 #define SDMAEN 0x10 +#define SDMAENACK 0x10 #define HDMAEN 0x08 #define HDMAENACK 0x08 #define DIRECTION 0x04 @@ -271,8 +271,8 @@ #define P_MESGOUT 0xa0 #define P_COMMAND 0x80 #define CDI 0x80 -#define IOI 0x40 #define P_DATAIN 0x40 +#define IOI 0x40 #define MSGI 0x20 #define P_BUSFREE 0x01 #define P_DATAOUT 0x00 @@ -314,9 +314,7 @@ #define LAST_MSG 0x53 -#define TARGET_MSG_REQUEST 0x54 - -#define SCSISEQ_TEMPLATE 0x56 +#define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 #define ENSELI 0x20 #define ENRSELI 0x10 @@ -324,11 +322,11 @@ #define ENAUTOATNI 0x04 #define ENAUTOATNP 0x02 -#define DATA_COUNT_ODD 0x57 +#define DATA_COUNT_ODD 0x55 -#define INITIATOR_TAG 0x58 +#define INITIATOR_TAG 0x56 -#define SEQ_FLAGS2 0x59 +#define SEQ_FLAGS2 0x57 #define SCB_DMA 0x01 #define SCSICONF 0x5a @@ -345,8 +343,8 @@ #define HOSTCONF 0x5d #define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 #define BIOSDISABLED 0x30 +#define BIOSMODE 0x30 #define CHANNEL_B_PRIMARY 0x08 #define SEQCTL 0x60 @@ -483,7 +481,8 @@ #define DFSTATUS 0x94 #define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 +#define DFCACHETH 0x40 +#define FIFOQWDEMP 0x20 #define MREQPEND 0x10 #define HDONE 0x08 #define DFTHRESH 0x04 @@ -521,18 +520,19 @@ #define COMMAND_PHASE 0x10 #define MSG_IN_PHASE 0x08 #define MSG_OUT_PHASE 0x04 +#define DATA_PHASE_MASK 0x03 #define DATA_IN_PHASE 0x02 #define DATA_OUT_PHASE 0x01 #define SFUNCT 0x9f #define ALT_MODE 0x80 +#define SCB_BASE 0xa0 + #define SCB_CDB_PTR 0xa0 +#define SCB_RESIDUAL_DATACNT 0xa0 #define SCB_CDB_STORE 0xa0 #define SCB_TARGET_INFO 0xa0 -#define SCB_RESIDUAL_DATACNT 0xa0 - -#define SCB_BASE 0xa0 #define SCB_RESIDUAL_SGPTR 0xa4 @@ -579,13 +579,13 @@ #define SCB_NEXT 0xbf +#define SCB_64_SPARE 0xc0 + #define SEECTL_2840 0xc0 #define CS_2840 0x04 #define CK_2840 0x02 #define DO_2840 0x01 -#define SCB_64_SPARE 0xc0 - #define STATUS_2840 0xc1 #define EEPROM_TF 0x80 #define BIOS_SEL 0x60 @@ -648,8 +648,8 @@ #define WR_DFTHRSH_63 0x30 #define WR_DFTHRSH_50 0x20 #define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH_90 0x06 #define RD_DFTHRSH_85 0x05 #define RD_DFTHRSH_75 0x04 @@ -668,39 +668,39 @@ #define SG_CACHE_PRE 0xfc -#define CMD_GROUP_CODE_SHIFT 0x05 +#define SCB_INITIATOR_TAG 0x03 +#define SCB_TARGET_DATA_DIR 0x01 +#define SCB_TARGET_PHASES 0x00 +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 #define BUS_8_BIT 0x00 -#define CCSGRAM_MAXSEGS 0x10 -#define TARGET_DATA_IN 0x01 +#define TARGET_CMD_CMPLT 0xfe #define STATUS_QUEUE_FULL 0x28 #define STATUS_BUSY 0x08 #define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 #define TID_SHIFT 0x04 #define SCB_DOWNLOAD_SIZE_64 0x30 -#define SCB_UPLOAD_SIZE 0x20 #define HOST_MAILBOX_SHIFT 0x04 -#define SCB_INITIATOR_TAG 0x03 #define SCB_TARGET_STATUS 0x02 -#define SCB_TARGET_DATA_DIR 0x01 -#define SCB_TARGET_PHASES 0x00 -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define TARGET_CMD_CMPLT 0xfe +#define CMD_GROUP_CODE_SHIFT 0x05 +#define CCSGRAM_MAXSEGS 0x10 #define SCB_LIST_NULL 0xff #define SG_SIZEOF 0x08 #define SCB_DOWNLOAD_SIZE 0x20 #define SEQ_MAILBOX_SHIFT 0x00 +#define TARGET_DATA_IN 0x01 #define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 +#define BUS_16_BIT 0x01 +#define SCB_UPLOAD_SIZE 0x20 /* Downloaded Constant Definitions */ +#define INVERTED_CACHESIZE_MASK 0x03 #define SG_PREFETCH_ADDR_MASK 0x06 #define SG_PREFETCH_ALIGN_MASK 0x05 #define QOUTFIFO_OFFSET 0x00 #define SG_PREFETCH_CNT 0x04 -#define INVERTED_CACHESIZE_MASK 0x03 #define CACHESIZE_MASK 0x02 #define QINFIFO_OFFSET 0x01 diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h linux/drivers/scsi/aic7xxx/aic7xxx_seq.h --- v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h Tue Mar 6 19:18:16 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.h Fri May 4 15:16:28 2001 @@ -4,7 +4,7 @@ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xde, 0x59, + 0x00, 0x65, 0xe4, 0x59, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x6a, 0x24, 0x08, 0x40, 0x00, 0x40, 0x68, @@ -17,21 +17,21 @@ 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x92, 0x5e, 0x01, 0x51, 0x20, 0x31, - 0x01, 0x59, 0xb2, 0x00, + 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x5d, + 0x00, 0x51, 0xec, 0x5d, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xde, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0x96, 0x5e, + 0xc1, 0x6a, 0xaa, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, 0x01, 0xf6, 0xd4, 0x30, 0x01, 0x4d, 0x9a, 0x18, - 0xfe, 0x59, 0xb2, 0x08, + 0xfe, 0x57, 0xae, 0x08, 0x01, 0x40, 0x20, 0x31, 0x00, 0x65, 0xe2, 0x58, 0x60, 0x0b, 0x40, 0x78, @@ -48,10 +48,10 @@ 0x08, 0x3c, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xd6, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xc4, 0x5d, + 0x48, 0x6a, 0xd6, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -62,7 +62,7 @@ 0x80, 0x3d, 0x7a, 0x00, 0x01, 0x3d, 0xd8, 0x31, 0x01, 0x3d, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x80, 0x66, 0xa8, 0x78, 0x01, 0x66, 0xd8, 0x31, @@ -77,33 +77,33 @@ 0x00, 0x65, 0xb0, 0x48, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x10, 0x03, 0x56, 0x79, + 0x10, 0x03, 0x5c, 0x79, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xd8, 0x31, 0x01, 0x66, 0x32, 0x31, - 0x01, 0x66, 0xb0, 0x30, + 0x01, 0x66, 0xac, 0x30, 0x40, 0x3c, 0x78, 0x00, 0x10, 0x03, 0xa6, 0x78, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xb0, 0x40, - 0x61, 0x6a, 0x96, 0x5e, - 0x08, 0x51, 0x2e, 0x71, + 0x61, 0x6a, 0xaa, 0x5e, + 0x08, 0x51, 0x34, 0x71, 0x02, 0x0b, 0xac, 0x78, 0x00, 0x65, 0xa8, 0x40, 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0xc2, 0x60, - 0xc4, 0x6a, 0x32, 0x5d, + 0xc4, 0x6a, 0x44, 0x5d, 0x40, 0x3c, 0xbe, 0x78, - 0x28, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x08, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, + 0x28, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x08, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, 0xff, 0x6a, 0xd8, 0x01, 0xff, 0x6a, 0x32, 0x01, 0x90, 0x3c, 0x78, 0x00, - 0x10, 0x03, 0x4a, 0x69, - 0x00, 0x65, 0x2e, 0x41, + 0x10, 0x03, 0x50, 0x69, + 0x00, 0x65, 0x34, 0x41, 0x1a, 0x01, 0x02, 0x00, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x0f, 0xc8, 0x08, @@ -112,8 +112,8 @@ 0x08, 0x1f, 0xda, 0x78, 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x8a, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xe8, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -125,11 +125,11 @@ 0x01, 0xb9, 0x1e, 0x30, 0x7f, 0xb9, 0x0a, 0x08, 0x01, 0xb9, 0x0a, 0x30, - 0x01, 0x56, 0xca, 0x30, + 0x01, 0x54, 0xca, 0x30, 0x80, 0xb8, 0xfc, 0x78, 0x80, 0x65, 0xca, 0x00, 0x01, 0x65, 0x00, 0x34, - 0x01, 0x56, 0x00, 0x34, + 0x01, 0x54, 0x00, 0x34, 0x1a, 0x01, 0x02, 0x00, 0x08, 0xb8, 0x06, 0x79, 0x20, 0x01, 0x02, 0x00, @@ -146,40 +146,43 @@ 0x01, 0xb9, 0x7a, 0x30, 0x01, 0xba, 0x7c, 0x30, 0x00, 0x65, 0x00, 0x59, - 0x80, 0x0b, 0xba, 0x79, - 0xe4, 0x6a, 0x32, 0x5d, - 0x80, 0xba, 0x48, 0x5d, + 0x80, 0x0b, 0xc0, 0x79, + 0xe4, 0x6a, 0x44, 0x5d, + 0x80, 0xba, 0x5a, 0x5d, 0x20, 0xb8, 0x2c, 0x79, - 0x20, 0x6a, 0x48, 0x5d, - 0x00, 0xa3, 0x48, 0x5d, + 0x20, 0x6a, 0x5a, 0x5d, + 0x00, 0xa3, 0x5a, 0x5d, 0x01, 0xa0, 0x78, 0x30, - 0x10, 0x03, 0x46, 0x69, - 0x08, 0x3c, 0x62, 0x69, - 0x04, 0x3c, 0x88, 0x69, - 0x02, 0x3c, 0x8e, 0x69, - 0x01, 0x3c, 0x4c, 0x79, - 0x00, 0x6a, 0x7e, 0x5e, + 0x10, 0xb8, 0x34, 0x79, + 0xe4, 0x6a, 0x44, 0x5d, + 0x00, 0x65, 0xa8, 0x40, + 0x10, 0x03, 0x4c, 0x69, + 0x08, 0x3c, 0x68, 0x69, + 0x04, 0x3c, 0x8e, 0x69, + 0x02, 0x3c, 0x94, 0x69, + 0x01, 0x3c, 0x52, 0x79, 0x01, 0x6a, 0xa2, 0x30, - 0x00, 0x65, 0x9a, 0x59, - 0x04, 0x51, 0x3e, 0x61, + 0x00, 0x65, 0xa0, 0x59, + 0x04, 0x51, 0x42, 0x61, + 0x00, 0x6a, 0x92, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, + 0x00, 0xbb, 0xec, 0x5d, 0x00, 0x65, 0x2c, 0x41, 0xa4, 0x6a, 0x06, 0x00, 0x00, 0x65, 0x0a, 0x59, 0x00, 0x65, 0xa8, 0x40, - 0xe4, 0x6a, 0x32, 0x5d, - 0x20, 0x3c, 0x52, 0x79, - 0x02, 0x6a, 0x48, 0x5d, - 0x04, 0x6a, 0x48, 0x5d, - 0x01, 0x03, 0x54, 0x69, + 0xe4, 0x6a, 0x44, 0x5d, + 0x20, 0x3c, 0x58, 0x79, + 0x02, 0x6a, 0x5a, 0x5d, + 0x04, 0x6a, 0x5a, 0x5d, + 0x01, 0x03, 0x5a, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, 0xff, 0x6a, 0x06, 0x08, 0x01, 0x6a, 0x7e, 0x00, - 0x00, 0x65, 0x9a, 0x59, + 0x00, 0x65, 0xa0, 0x59, 0x00, 0x65, 0x04, 0x40, - 0x84, 0x6a, 0x32, 0x5d, + 0x84, 0x6a, 0x44, 0x5d, 0x00, 0x65, 0x0a, 0x59, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -187,60 +190,60 @@ 0x5b, 0x64, 0xc8, 0x28, 0x30, 0x64, 0xca, 0x18, 0x01, 0x6c, 0xc8, 0x30, - 0xff, 0x64, 0x84, 0x79, + 0xff, 0x64, 0x8a, 0x79, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x76, 0x79, - 0x01, 0x64, 0x7c, 0x61, + 0x02, 0x0b, 0x7c, 0x79, + 0x01, 0x64, 0x82, 0x61, 0xf7, 0x01, 0x02, 0x08, 0x01, 0x06, 0xd8, 0x31, 0x01, 0x06, 0x32, 0x31, 0xff, 0x64, 0xc8, 0x18, - 0xff, 0x64, 0x76, 0x69, + 0xff, 0x64, 0x7c, 0x69, 0xf7, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x2e, 0x41, + 0x00, 0x65, 0x34, 0x41, 0x40, 0xa1, 0x7e, 0x10, - 0x04, 0xa1, 0x32, 0x5d, - 0x00, 0x65, 0x62, 0x42, - 0xc4, 0x6a, 0x32, 0x5d, + 0x04, 0xa1, 0x44, 0x5d, + 0x00, 0x65, 0x68, 0x42, + 0xc4, 0x6a, 0x44, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa2, 0x48, 0x5d, + 0x00, 0xa2, 0x5a, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x48, 0x5d, - 0x00, 0x65, 0x54, 0x41, - 0x10, 0x3c, 0x9e, 0x69, - 0x00, 0xbb, 0x64, 0x44, + 0x00, 0x6a, 0x5a, 0x5d, + 0x00, 0x65, 0x5a, 0x41, + 0x10, 0x3c, 0xa4, 0x69, + 0x00, 0xbb, 0x6c, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xa6, 0x79, + 0x80, 0xee, 0xac, 0x79, 0xff, 0x6a, 0xdc, 0x09, 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xa8, 0x5d, + 0x1c, 0x6a, 0xba, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x80, 0x6a, 0x74, 0x00, 0x80, 0x3c, 0x78, 0x00, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0xb2, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x62, 0x7a, - 0x80, 0x64, 0x82, 0x73, - 0xa0, 0x64, 0xd8, 0x73, - 0xc0, 0x64, 0xd0, 0x73, - 0xe0, 0x64, 0x18, 0x74, - 0x01, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0xbf, 0x64, 0x68, 0x7a, + 0x80, 0x64, 0x96, 0x73, + 0xa0, 0x64, 0xf0, 0x73, + 0xc0, 0x64, 0xe6, 0x73, + 0xe0, 0x64, 0x20, 0x74, + 0x01, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, 0xff, 0x6a, 0x24, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xd8, 0x79, + 0x09, 0x0c, 0xde, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0x96, 0x5e, + 0xb1, 0x6a, 0xaa, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -253,47 +256,47 @@ 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0x9a, 0x7e, - 0x80, 0xeb, 0xf8, 0x79, + 0x08, 0xeb, 0xae, 0x7e, + 0x80, 0xeb, 0xfe, 0x79, 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0xfc, 0x69, + 0x08, 0xeb, 0x02, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0xeb, 0x12, 0x72, - 0x08, 0xeb, 0x9a, 0x6e, - 0x80, 0xa3, 0x9a, 0x6e, - 0x04, 0xea, 0x16, 0xe2, - 0x08, 0xee, 0x9a, 0x6e, + 0x80, 0xa3, 0xae, 0x6e, + 0x88, 0xeb, 0x18, 0x72, + 0x08, 0xeb, 0xae, 0x6e, + 0x04, 0xea, 0x1c, 0xe2, + 0x08, 0xee, 0xae, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0x65, 0x00, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0x9a, 0x7e, + 0x80, 0x94, 0xae, 0x7e, 0x04, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, - 0x01, 0x65, 0x20, 0x7a, - 0x01, 0x57, 0xae, 0x10, + 0x01, 0x65, 0x26, 0x7a, + 0x01, 0x55, 0xaa, 0x10, 0x01, 0x65, 0x18, 0x31, 0x02, 0xe9, 0x1a, 0x31, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0xf2, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x01, 0x57, 0x2e, 0x7a, + 0x01, 0x55, 0x34, 0x7a, 0x04, 0x65, 0xca, 0x00, - 0x80, 0xa3, 0x32, 0x7a, + 0x80, 0xa3, 0x38, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, - 0x01, 0x3b, 0x26, 0x31, + 0x80, 0x93, 0x26, 0x01, 0xff, 0x6a, 0xd4, 0x0c, 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0x9a, 0x7e, - 0xff, 0x8d, 0x48, 0x6a, - 0xff, 0x8e, 0x48, 0x6a, + 0xff, 0x64, 0xae, 0x7e, + 0xff, 0x8d, 0x4e, 0x6a, + 0xff, 0x8e, 0x4e, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0x9a, 0x56, + 0x00, 0x65, 0xae, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, @@ -304,139 +307,146 @@ 0x03, 0xa0, 0x18, 0x31, 0x03, 0xa0, 0x10, 0x30, 0x08, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbe, 0x5d, - 0x01, 0xa0, 0xae, 0x08, - 0x00, 0x65, 0x88, 0x42, + 0xa0, 0x6a, 0xd0, 0x5d, + 0x01, 0xa0, 0xaa, 0x08, + 0x00, 0x65, 0x8e, 0x42, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x6a, 0x6a, + 0x40, 0x3f, 0x70, 0x6a, 0x04, 0x3b, 0x76, 0x00, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0x64, 0x5d, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x54, 0x6a, + 0x20, 0x3c, 0x5a, 0x6a, 0x20, 0x3c, 0x78, 0x00, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xb6, 0x5d, + 0xac, 0x6a, 0xc8, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xba, 0x5d, - 0x00, 0x65, 0x38, 0x5a, + 0xb3, 0x6a, 0xcc, 0x5d, + 0x00, 0x65, 0x3e, 0x5a, 0xfd, 0xa4, 0x48, 0x09, - 0x01, 0x8c, 0xae, 0x08, + 0x01, 0x8c, 0xaa, 0x08, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0xa4, 0x98, 0x7a, + 0x00, 0x65, 0xc0, 0x5d, + 0x01, 0xa4, 0xa0, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x90, 0x7a, + 0x10, 0x0c, 0x96, 0x7a, + 0x03, 0x9e, 0x98, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xbe, 0x41, + 0x91, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xc4, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9e, 0x7a, + 0x80, 0xa3, 0xa6, 0x7a, 0x02, 0x65, 0xca, 0x00, - 0x01, 0x57, 0xa2, 0x7a, + 0x01, 0x55, 0xaa, 0x7a, 0x04, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0xfc, 0xae, 0x6a, - 0x80, 0x0b, 0xa6, 0x6a, - 0x10, 0x0c, 0xa6, 0x7a, - 0x04, 0x93, 0xc0, 0x6a, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0xb2, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0xfc, 0xb8, 0x6a, + 0x80, 0x0b, 0xae, 0x6a, + 0x10, 0x0c, 0xae, 0x7a, + 0x20, 0x93, 0xae, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x01, 0x94, 0xb4, 0x7a, - 0x10, 0x94, 0xc0, 0x6a, - 0xd7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xc4, 0x6a, - 0x02, 0xfc, 0xce, 0x7a, - 0x01, 0xfc, 0x4e, 0x7b, + 0x02, 0xfc, 0xc2, 0x7a, + 0x40, 0x0d, 0xdc, 0x6a, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x40, 0x0d, 0xd4, 0x6a, - 0x00, 0x65, 0x00, 0x5a, - 0x00, 0x65, 0xc6, 0x42, - 0x80, 0xfc, 0xde, 0x7a, - 0x80, 0xa4, 0xde, 0x6a, + 0x00, 0x65, 0xdc, 0x42, + 0x40, 0x0d, 0xc8, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x00, 0x65, 0xba, 0x42, + 0x80, 0xfc, 0xd2, 0x7a, + 0x80, 0xa4, 0xd2, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, - 0xff, 0x6a, 0xae, 0x08, - 0x04, 0xfc, 0xe6, 0x7a, - 0x01, 0x57, 0xae, 0x00, + 0xff, 0x6a, 0xaa, 0x08, + 0x04, 0xfc, 0xda, 0x7a, + 0x01, 0x55, 0xaa, 0x00, 0xff, 0x6a, 0x46, 0x09, - 0xff, 0x38, 0xf2, 0x6a, - 0x80, 0xa3, 0xf2, 0x7a, - 0x80, 0x0b, 0xf0, 0x7a, - 0x04, 0x3b, 0xf2, 0x7a, + 0x04, 0x3b, 0xf4, 0x6a, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0x94, 0xde, 0x7a, + 0x01, 0xa4, 0xf2, 0x7a, + 0x01, 0xfc, 0xec, 0x7a, + 0x01, 0x94, 0xf4, 0x6a, + 0x00, 0x65, 0x8e, 0x42, + 0x01, 0x94, 0xf2, 0x7a, + 0x10, 0x94, 0xf4, 0x6a, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xf8, 0x6a, + 0xff, 0x38, 0x04, 0x6b, + 0x80, 0xa3, 0x04, 0x7b, + 0x80, 0x0b, 0x02, 0x7b, + 0x04, 0x3b, 0x04, 0x7b, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x00, 0x5a, - 0x01, 0x0b, 0x00, 0x6b, - 0x10, 0x0c, 0xf4, 0x7a, - 0x04, 0x93, 0xfe, 0x6a, - 0x01, 0x94, 0xfc, 0x7a, - 0x10, 0x94, 0xfe, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x01, 0x0b, 0x12, 0x6b, + 0x10, 0x0c, 0x06, 0x7b, + 0x04, 0x93, 0x10, 0x6b, + 0x01, 0x94, 0x0e, 0x7b, + 0x10, 0x94, 0x10, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x02, 0x6b, - 0xff, 0x08, 0x4e, 0x6b, - 0xff, 0x09, 0x4e, 0x6b, - 0xff, 0x0a, 0x4e, 0x6b, - 0xff, 0x38, 0x1e, 0x7b, + 0x38, 0x93, 0x14, 0x6b, + 0xff, 0x08, 0x60, 0x6b, + 0xff, 0x09, 0x60, 0x6b, + 0xff, 0x0a, 0x60, 0x6b, + 0xff, 0x38, 0x30, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0x00, 0x38, 0xa8, 0x5d, + 0x14, 0x6a, 0xce, 0x5d, + 0x00, 0x38, 0xba, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x44, 0x43, - 0x80, 0xa3, 0x24, 0x7b, + 0x00, 0x65, 0x56, 0x43, + 0x80, 0xa3, 0x36, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x4e, 0x43, - 0x08, 0xeb, 0x2a, 0x7b, - 0x00, 0x65, 0x00, 0x5a, - 0x08, 0xeb, 0x26, 0x6b, + 0x00, 0x65, 0x60, 0x43, + 0x08, 0xeb, 0x3c, 0x7b, + 0x00, 0x65, 0x06, 0x5a, + 0x08, 0xeb, 0x38, 0x6b, 0x07, 0xe9, 0x10, 0x31, - 0x80, 0xe9, 0x30, 0x7b, + 0x80, 0xe9, 0x42, 0x7b, 0x80, 0xa3, 0x46, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xbc, 0x5d, - 0x08, 0x6a, 0xa8, 0x5d, + 0xa4, 0x6a, 0xce, 0x5d, + 0x08, 0x6a, 0xba, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x4e, 0x5e, + 0x00, 0x65, 0x62, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0x65, 0x38, 0x5a, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0x3e, 0x5a, + 0x00, 0x65, 0xf2, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xae, 0x5d, - 0x01, 0x8c, 0x4c, 0x7b, - 0x01, 0x57, 0xae, 0x10, - 0x80, 0x0b, 0x88, 0x6a, - 0x80, 0x0b, 0x54, 0x6b, - 0x01, 0x0c, 0x50, 0x7b, - 0x10, 0x0c, 0x88, 0x7a, - 0x00, 0x65, 0xf6, 0x59, - 0xff, 0x38, 0x66, 0x7b, + 0x00, 0x65, 0xc0, 0x5d, + 0x01, 0x8c, 0x5e, 0x7b, + 0x01, 0x55, 0xaa, 0x10, + 0x80, 0x0b, 0x8e, 0x6a, + 0x80, 0x0b, 0x68, 0x6b, + 0x01, 0x0c, 0x62, 0x7b, + 0x10, 0x0c, 0x8e, 0x7a, + 0x03, 0x9e, 0x8e, 0x6a, + 0x00, 0x65, 0xfc, 0x59, + 0xff, 0x38, 0x7a, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x68, 0x43, + 0x00, 0x65, 0x7c, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -445,13 +455,13 @@ 0xfd, 0xb4, 0x68, 0x09, 0x12, 0x01, 0x02, 0x00, 0x12, 0x01, 0x02, 0x00, - 0x04, 0x3c, 0xbe, 0x79, + 0x04, 0x3c, 0xc4, 0x79, 0xfb, 0x3c, 0x78, 0x08, - 0x04, 0x93, 0x2e, 0x79, - 0x01, 0x0c, 0x7c, 0x6b, - 0x00, 0x65, 0x2e, 0x41, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x04, 0x93, 0x34, 0x79, + 0x01, 0x0c, 0x90, 0x6b, + 0x00, 0x65, 0x34, 0x41, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x64, 0x5d, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -461,16 +471,16 @@ 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xaa, 0x53, + 0xa0, 0x6a, 0xbe, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xbc, 0x5d, - 0x00, 0xbc, 0xa8, 0x5d, + 0xa0, 0x6a, 0xce, 0x5d, + 0x00, 0xbc, 0xba, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xc2, 0x43, + 0x00, 0x65, 0xd6, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -480,114 +490,112 @@ 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x60, 0x5e, - 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x74, 0x5e, + 0x00, 0x65, 0x74, 0x5e, 0x02, 0x93, 0x26, 0x01, - 0x04, 0x0b, 0xc6, 0x6b, - 0x10, 0x0c, 0xc2, 0x7b, - 0x01, 0x03, 0xc6, 0x6b, + 0x04, 0x0b, 0xda, 0x6b, + 0x10, 0x0c, 0xd6, 0x7b, + 0x01, 0x03, 0xda, 0x6b, + 0x20, 0x93, 0xd6, 0x6b, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xca, 0x6b, + 0x38, 0x93, 0xe0, 0x6b, 0x10, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x00, 0x65, 0x52, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x00, 0x65, 0x64, 0x5d, 0x01, 0x06, 0x50, 0x31, - 0x00, 0x65, 0xbe, 0x41, + 0x00, 0x65, 0xc4, 0x41, 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x04, 0x64, - 0x10, 0xb8, 0x28, 0x6c, - 0x01, 0xb9, 0xdc, 0x30, - 0x01, 0x6e, 0xc8, 0x30, - 0x01, 0x54, 0xca, 0x30, - 0x80, 0xb9, 0xe8, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x80, 0xb9, 0xec, 0x7b, - 0x01, 0x55, 0xca, 0x30, - 0x00, 0x65, 0x28, 0x6c, + 0x80, 0x65, 0x0c, 0x64, + 0x10, 0xb8, 0x30, 0x6c, 0xc0, 0xba, 0xca, 0x00, - 0x40, 0xb8, 0xf4, 0x6b, + 0x40, 0xb8, 0xfc, 0x6b, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x08, 0x7c, + 0x20, 0xb8, 0x10, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0x18, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0x10, 0x64, - 0x00, 0xbb, 0x08, 0x44, - 0xff, 0x65, 0x08, 0x64, - 0x00, 0x65, 0x28, 0x44, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0x18, 0x64, + 0x00, 0xbb, 0x10, 0x44, + 0xff, 0x65, 0x10, 0x64, + 0x00, 0x65, 0x30, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xa0, 0x5d, - 0xa0, 0x3f, 0xd6, 0x73, + 0x00, 0x65, 0xb2, 0x5d, + 0xa0, 0x3f, 0xec, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, - 0x00, 0x65, 0xbe, 0x41, - 0x64, 0x6a, 0x2c, 0x5d, - 0x80, 0x64, 0x9e, 0x6c, - 0x04, 0x64, 0x74, 0x74, - 0x02, 0x64, 0x82, 0x74, - 0x00, 0x6a, 0x44, 0x74, - 0x03, 0x64, 0x90, 0x74, - 0x23, 0x64, 0x30, 0x74, - 0x08, 0x64, 0x40, 0x74, - 0x61, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0xa0, 0x5d, - 0x08, 0x51, 0xc0, 0x71, - 0x00, 0x65, 0x28, 0x44, - 0x80, 0x04, 0x3e, 0x7c, - 0x51, 0x6a, 0x22, 0x5d, - 0x01, 0x51, 0x3e, 0x64, - 0x01, 0xa4, 0x3a, 0x7c, - 0x01, 0x57, 0x40, 0x7c, - 0x41, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, - 0x07, 0x6a, 0x1a, 0x5d, + 0x00, 0x65, 0xc4, 0x41, + 0x64, 0x6a, 0x3e, 0x5d, + 0x80, 0x64, 0xae, 0x6c, + 0x04, 0x64, 0x7c, 0x74, + 0x02, 0x64, 0x8a, 0x74, + 0x00, 0x6a, 0x4c, 0x74, + 0x03, 0x64, 0xa0, 0x74, + 0x23, 0x64, 0x38, 0x74, + 0x08, 0x64, 0x48, 0x74, + 0x61, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0xb2, 0x5d, + 0x08, 0x51, 0xc6, 0x71, + 0x00, 0x65, 0x30, 0x44, + 0x80, 0x04, 0x46, 0x7c, + 0x51, 0x6a, 0x34, 0x5d, + 0x01, 0x51, 0x46, 0x64, + 0x01, 0xa4, 0x42, 0x7c, + 0x01, 0x55, 0x48, 0x7c, + 0x41, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x48, 0x44, + 0x07, 0x6a, 0x2a, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xbe, 0x41, - 0x10, 0xb8, 0x48, 0x7c, - 0xa1, 0x6a, 0x96, 0x5e, - 0x01, 0xb4, 0x4e, 0x6c, - 0x02, 0xb4, 0x50, 0x6c, - 0x01, 0xa4, 0x50, 0x7c, - 0xff, 0xa8, 0x60, 0x7c, + 0x00, 0x65, 0xc4, 0x41, + 0x10, 0xb8, 0x50, 0x7c, + 0xa1, 0x6a, 0xaa, 0x5e, + 0x01, 0xb4, 0x56, 0x6c, + 0x02, 0xb4, 0x58, 0x6c, + 0x01, 0xa4, 0x58, 0x7c, + 0xff, 0xa8, 0x68, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x5d, - 0xff, 0xa8, 0x60, 0x7c, - 0x71, 0x6a, 0x96, 0x5e, - 0x40, 0x51, 0x60, 0x64, - 0x00, 0x65, 0x76, 0x5e, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0xbb, 0x64, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x00, 0x65, 0x76, 0x5e, + 0x00, 0xbb, 0xec, 0x5d, + 0xff, 0xa8, 0x68, 0x7c, + 0x71, 0x6a, 0xaa, 0x5e, + 0x40, 0x51, 0x68, 0x64, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0xbb, 0x6c, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0x7e, 0xdd, - 0x00, 0x51, 0x90, 0x5d, + 0x00, 0x6a, 0x90, 0xdd, + 0x00, 0x51, 0xa2, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0x92, 0x5e, - 0x20, 0xb8, 0xd0, 0x69, + 0x00, 0x65, 0xa6, 0x5e, + 0x20, 0xb8, 0xd6, 0x69, 0x01, 0xbb, 0xa2, 0x30, 0x01, 0xba, 0x7c, 0x30, - 0x00, 0xb9, 0x94, 0x5c, - 0x00, 0x65, 0xd0, 0x41, - 0x20, 0x3c, 0x40, 0x7c, + 0x00, 0xb9, 0xa4, 0x5c, + 0x00, 0x65, 0xd6, 0x41, + 0x01, 0x06, 0xd4, 0x30, + 0x20, 0x3c, 0xc4, 0x79, + 0x20, 0x3c, 0x48, 0x7c, 0x04, 0x14, 0x58, 0x31, + 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xbc, 0x5d, - 0xa0, 0x6a, 0xb4, 0x5d, - 0x00, 0x65, 0x40, 0x44, + 0x14, 0x6a, 0xce, 0x5d, + 0x01, 0x06, 0xd4, 0x30, + 0xa0, 0x6a, 0xc6, 0x5d, + 0x00, 0x65, 0xc4, 0x41, 0xdf, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0x48, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -598,103 +606,104 @@ 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xac, 0x4c, + 0x00, 0x65, 0xbc, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xb4, 0x54, + 0x00, 0x65, 0xc4, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xbe, 0x4c, + 0x00, 0x65, 0xce, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xc6, 0x54, + 0x00, 0x65, 0xd6, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0xd8, 0x74, - 0x00, 0x51, 0x56, 0x5d, + 0xff, 0x51, 0xe8, 0x74, + 0x00, 0x51, 0x68, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0xfa, 0x44, + 0x00, 0x65, 0x0a, 0x45, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0xfa, 0x74, - 0x00, 0x65, 0x74, 0x5e, + 0x00, 0x3e, 0x0a, 0x75, + 0x00, 0x65, 0x88, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xa0, 0x5d, + 0x00, 0x65, 0xb2, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x16, 0x65, + 0xe0, 0x3f, 0x26, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x16, 0x65, - 0x51, 0x6a, 0x22, 0x5d, - 0x00, 0x51, 0x56, 0x5d, - 0x51, 0x6a, 0x22, 0x5d, + 0x20, 0x12, 0x26, 0x65, + 0x51, 0x6a, 0x34, 0x5d, + 0x00, 0x51, 0x68, 0x5d, + 0x51, 0x6a, 0x34, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x14, 0x65, + 0x00, 0x3d, 0x24, 0x65, 0x08, 0x3c, 0x78, 0x00, 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x14, 0x65, + 0x00, 0x3e, 0x24, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x14, 0x7d, + 0x04, 0xb8, 0x24, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x0a, 0x6d, + 0x20, 0xb8, 0x1a, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0x94, 0x5c, + 0x00, 0x3d, 0xa4, 0x5c, 0x01, 0x64, 0x20, 0x31, 0x80, 0x6a, 0x78, 0x00, 0x00, 0x65, 0x02, 0x59, - 0x10, 0xb8, 0x40, 0x7c, - 0xff, 0x6a, 0x1a, 0x5d, - 0x00, 0x65, 0x40, 0x44, - 0x00, 0x65, 0x74, 0x5e, - 0x31, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x40, 0x44, + 0x10, 0xb8, 0x48, 0x7c, + 0xff, 0x6a, 0x2a, 0x5d, + 0x00, 0x65, 0x48, 0x44, + 0x00, 0x65, 0x88, 0x5e, + 0x31, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x48, 0x44, 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0x96, 0x5e, - 0x00, 0x65, 0x24, 0x45, + 0x81, 0x6a, 0xaa, 0x5e, + 0x00, 0x65, 0x36, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x24, 0x7d, - 0x04, 0x0c, 0x1e, 0x6d, + 0x01, 0x0c, 0x36, 0x7d, + 0x04, 0x0c, 0x30, 0x6d, 0xe0, 0x03, 0x7e, 0x08, - 0xe0, 0x3f, 0xbe, 0x61, + 0xe0, 0x3f, 0xc4, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x32, 0x6d, + 0x01, 0x03, 0x44, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x40, 0x75, - 0x40, 0x65, 0x40, 0x7d, - 0x00, 0x65, 0x40, 0x5d, + 0x00, 0x66, 0x52, 0x75, + 0x40, 0x65, 0x52, 0x7d, + 0x00, 0x65, 0x52, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x4a, 0x7d, + 0x02, 0x0b, 0x5c, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x4e, 0x7d, + 0x02, 0x0b, 0x60, 0x7d, 0xf7, 0x01, 0x02, 0x0c, - 0x80, 0x3c, 0x9a, 0x6e, - 0x21, 0x6a, 0x96, 0x46, + 0x80, 0x3c, 0xae, 0x6e, + 0x21, 0x6a, 0xaa, 0x46, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0x76, 0x75, + 0xff, 0x41, 0x88, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x66, 0x45, - 0xff, 0xbf, 0x76, 0x75, + 0x00, 0x65, 0x78, 0x45, + 0xff, 0xbf, 0x88, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x60, 0x65, - 0xff, 0x52, 0x74, 0x75, + 0x00, 0xbb, 0x72, 0x65, + 0xff, 0x52, 0x86, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -702,28 +711,28 @@ 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0x7e, 0x5e, + 0x00, 0x6a, 0x92, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0xda, 0x45, + 0x00, 0x51, 0xec, 0x45, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, + 0x48, 0x6a, 0xe0, 0x5d, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xce, 0x5d, - 0x01, 0x6a, 0xa8, 0x5d, + 0x48, 0x6a, 0xe0, 0x5d, + 0x01, 0x6a, 0xba, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x94, 0x7d, + 0x80, 0xee, 0xa6, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, - 0x81, 0x6a, 0x96, 0x5e, - 0x01, 0x0c, 0xa0, 0x7d, - 0x04, 0x0c, 0x9e, 0x6d, + 0x00, 0x65, 0x80, 0x46, + 0x81, 0x6a, 0xaa, 0x5e, + 0x01, 0x0c, 0xb2, 0x7d, + 0x04, 0x0c, 0xb0, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -742,7 +751,7 @@ 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0xce, 0x45, + 0x00, 0x65, 0xe0, 0x45, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -753,61 +762,62 @@ 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, + 0x44, 0x6a, 0xdc, 0x5d, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0xee, 0x7d, + 0x04, 0x3b, 0x00, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xea, 0x65, - 0x00, 0x65, 0x06, 0x46, + 0xdc, 0xee, 0xfc, 0x65, + 0x00, 0x65, 0x18, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xf6, 0x7d, + 0x80, 0xee, 0x08, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0xfa, 0x65, + 0x50, 0xee, 0x0c, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x00, 0x66, + 0x88, 0xee, 0x12, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x04, 0x66, + 0xd8, 0xee, 0x16, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x08, 0x6e, + 0x18, 0xee, 0x1a, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0xca, 0x5d, - 0x20, 0x6a, 0xa8, 0x5d, + 0x44, 0x6a, 0xdc, 0x5d, + 0x20, 0x6a, 0xba, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x22, 0x6e, + 0x04, 0x3b, 0x34, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x5c, 0x5e, - 0x00, 0x65, 0x1a, 0x66, + 0x00, 0x65, 0x70, 0x5e, + 0x00, 0x65, 0x2c, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x6c, 0x46, + 0x00, 0x65, 0x80, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x01, 0x94, 0x26, 0x6e, - 0x10, 0x94, 0x28, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, - 0x08, 0x94, 0x3e, 0x6e, + 0x20, 0x94, 0x38, 0x6e, + 0x10, 0x94, 0x3a, 0x6e, + 0x08, 0x94, 0x52, 0x6e, + 0x08, 0x94, 0x52, 0x6e, + 0x08, 0x94, 0x52, 0x6e, 0x07, 0x8c, 0xca, 0x18, 0x3d, 0x65, 0xca, 0x28, 0x00, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x42, 0x5e, + 0x00, 0x65, 0x56, 0x5e, 0xff, 0x65, 0xca, 0x10, 0x05, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x26, 0x46, + 0x04, 0x64, 0x82, 0x76, + 0x00, 0x65, 0x38, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x40, 0x6e, + 0x08, 0x93, 0x54, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0x6c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, - 0x00, 0x65, 0x4c, 0x5e, + 0x00, 0x65, 0x80, 0x5e, + 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x60, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -824,23 +834,23 @@ 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0x6c, 0x7e, + 0x08, 0x94, 0x80, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x70, 0x6e, + 0x08, 0x93, 0x84, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0x92, 0x6e, + 0x04, 0xb8, 0xa6, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, 0xff, 0x6a, 0x76, 0x05, - 0xff, 0x42, 0x8e, 0x66, - 0xff, 0x41, 0x86, 0x66, - 0xd1, 0x6a, 0x96, 0x5e, + 0xff, 0x42, 0xa2, 0x66, + 0xff, 0x41, 0x9a, 0x66, + 0xd1, 0x6a, 0xaa, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0xda, 0x45, + 0x00, 0xbb, 0xec, 0x45, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -919,7 +929,7 @@ static int ahc_patch14_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_DT) == 0); + return ((ahc->features & AHC_ULTRA2) == 0); } static int ahc_patch13_func(struct ahc_softc *ahc); @@ -927,7 +937,7 @@ static int ahc_patch13_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_ULTRA2) == 0); + return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); } static int ahc_patch12_func(struct ahc_softc *ahc); @@ -935,7 +945,7 @@ static int ahc_patch12_func(struct ahc_softc *ahc) { - return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); + return ((ahc->features & AHC_ULTRA) != 0); } static int ahc_patch11_func(struct ahc_softc *ahc); @@ -943,7 +953,7 @@ static int ahc_patch11_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_ULTRA) != 0); + return ((ahc->features & AHC_HS_MAILBOX) != 0); } static int ahc_patch10_func(struct ahc_softc *ahc); @@ -951,7 +961,7 @@ static int ahc_patch10_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_HS_MAILBOX) != 0); + return ((ahc->features & AHC_MULTI_TID) != 0); } static int ahc_patch9_func(struct ahc_softc *ahc); @@ -959,7 +969,7 @@ static int ahc_patch9_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_MULTI_TID) != 0); + return ((ahc->features & AHC_CMD_CHAN) != 0); } static int ahc_patch8_func(struct ahc_softc *ahc); @@ -967,7 +977,7 @@ static int ahc_patch8_func(struct ahc_softc *ahc) { - return ((ahc->features & AHC_CMD_CHAN) != 0); + return ((ahc->flags & AHC_INITIATORROLE) != 0); } static int ahc_patch7_func(struct ahc_softc *ahc); @@ -975,7 +985,7 @@ static int ahc_patch7_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_INITIATORROLE) != 0); + return ((ahc->flags & AHC_TARGETROLE) != 0); } static int ahc_patch6_func(struct ahc_softc *ahc); @@ -983,7 +993,7 @@ static int ahc_patch6_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_TARGETROLE) != 0); + return ((ahc->features & AHC_DT) == 0); } static int ahc_patch5_func(struct ahc_softc *ahc); @@ -1051,28 +1061,29 @@ { ahc_patch5_func, 22, 2, 1 }, { ahc_patch3_func, 27, 1, 2 }, { ahc_patch0_func, 28, 1, 1 }, - { ahc_patch6_func, 37, 65, 21 }, - { ahc_patch7_func, 37, 1, 1 }, - { ahc_patch8_func, 45, 3, 2 }, + { ahc_patch6_func, 34, 1, 1 }, + { ahc_patch7_func, 37, 65, 21 }, + { ahc_patch8_func, 37, 1, 1 }, + { ahc_patch9_func, 45, 3, 2 }, { ahc_patch0_func, 48, 3, 1 }, - { ahc_patch9_func, 52, 1, 2 }, + { ahc_patch10_func, 52, 1, 2 }, { ahc_patch0_func, 53, 2, 3 }, { ahc_patch1_func, 53, 1, 2 }, { ahc_patch0_func, 54, 1, 1 }, { ahc_patch2_func, 56, 2, 1 }, - { ahc_patch8_func, 58, 1, 2 }, + { ahc_patch9_func, 58, 1, 2 }, { ahc_patch0_func, 59, 1, 1 }, - { ahc_patch8_func, 63, 1, 2 }, + { ahc_patch9_func, 63, 1, 2 }, { ahc_patch0_func, 64, 1, 1 }, - { ahc_patch8_func, 73, 1, 2 }, + { ahc_patch9_func, 73, 1, 2 }, { ahc_patch0_func, 74, 1, 1 }, - { ahc_patch8_func, 77, 1, 2 }, + { ahc_patch9_func, 77, 1, 2 }, { ahc_patch0_func, 78, 1, 1 }, - { ahc_patch10_func, 88, 1, 2 }, + { ahc_patch11_func, 88, 1, 2 }, { ahc_patch0_func, 89, 1, 1 }, - { ahc_patch8_func, 97, 1, 2 }, + { ahc_patch9_func, 97, 1, 2 }, { ahc_patch0_func, 98, 1, 1 }, - { ahc_patch7_func, 102, 9, 4 }, + { ahc_patch8_func, 102, 9, 4 }, { ahc_patch1_func, 104, 1, 2 }, { ahc_patch0_func, 105, 1, 1 }, { ahc_patch2_func, 107, 2, 1 }, @@ -1081,147 +1092,162 @@ { ahc_patch0_func, 121, 2, 3 }, { ahc_patch2_func, 121, 1, 2 }, { ahc_patch0_func, 122, 1, 1 }, - { ahc_patch6_func, 123, 4, 2 }, + { ahc_patch7_func, 123, 4, 2 }, { ahc_patch0_func, 127, 1, 1 }, - { ahc_patch11_func, 129, 2, 1 }, + { ahc_patch12_func, 129, 2, 1 }, { ahc_patch1_func, 131, 1, 2 }, { ahc_patch0_func, 132, 1, 1 }, - { ahc_patch6_func, 133, 4, 1 }, - { ahc_patch6_func, 144, 77, 9 }, - { ahc_patch4_func, 156, 1, 1 }, - { ahc_patch1_func, 172, 1, 1 }, - { ahc_patch8_func, 180, 1, 2 }, - { ahc_patch0_func, 181, 1, 1 }, - { ahc_patch8_func, 190, 1, 2 }, - { ahc_patch0_func, 191, 1, 1 }, - { ahc_patch8_func, 207, 6, 2 }, - { ahc_patch0_func, 213, 6, 1 }, - { ahc_patch7_func, 221, 18, 2 }, - { ahc_patch1_func, 234, 1, 1 }, - { ahc_patch1_func, 241, 1, 2 }, - { ahc_patch0_func, 242, 2, 2 }, - { ahc_patch11_func, 243, 1, 1 }, - { ahc_patch8_func, 251, 33, 2 }, - { ahc_patch1_func, 267, 16, 1 }, - { ahc_patch12_func, 284, 14, 1 }, - { ahc_patch1_func, 298, 2, 2 }, - { ahc_patch0_func, 300, 3, 3 }, - { ahc_patch8_func, 300, 1, 2 }, - { ahc_patch0_func, 301, 2, 1 }, - { ahc_patch1_func, 305, 1, 2 }, - { ahc_patch0_func, 306, 1, 1 }, - { ahc_patch8_func, 310, 1, 1 }, - { ahc_patch8_func, 313, 2, 2 }, - { ahc_patch0_func, 315, 4, 1 }, - { ahc_patch12_func, 319, 1, 1 }, - { ahc_patch13_func, 322, 2, 3 }, - { ahc_patch8_func, 322, 1, 2 }, - { ahc_patch0_func, 323, 1, 1 }, - { ahc_patch1_func, 332, 40, 6 }, - { ahc_patch6_func, 341, 1, 1 }, - { ahc_patch7_func, 342, 1, 1 }, - { ahc_patch14_func, 344, 2, 1 }, - { ahc_patch15_func, 346, 5, 1 }, - { ahc_patch0_func, 372, 51, 15 }, - { ahc_patch12_func, 372, 1, 1 }, - { ahc_patch6_func, 374, 2, 2 }, - { ahc_patch16_func, 375, 1, 1 }, - { ahc_patch8_func, 378, 1, 1 }, - { ahc_patch17_func, 385, 1, 1 }, - { ahc_patch12_func, 390, 9, 3 }, - { ahc_patch8_func, 391, 3, 2 }, - { ahc_patch0_func, 394, 3, 1 }, - { ahc_patch8_func, 402, 6, 2 }, - { ahc_patch0_func, 408, 8, 1 }, - { ahc_patch12_func, 416, 1, 1 }, - { ahc_patch8_func, 418, 1, 2 }, - { ahc_patch0_func, 419, 1, 1 }, - { ahc_patch6_func, 422, 1, 1 }, - { ahc_patch6_func, 423, 1, 1 }, - { ahc_patch7_func, 424, 2, 1 }, - { ahc_patch8_func, 426, 1, 1 }, - { ahc_patch12_func, 427, 9, 4 }, - { ahc_patch8_func, 427, 1, 1 }, - { ahc_patch8_func, 434, 2, 1 }, - { ahc_patch0_func, 436, 4, 3 }, - { ahc_patch8_func, 436, 1, 2 }, - { ahc_patch0_func, 437, 3, 1 }, - { ahc_patch1_func, 441, 2, 1 }, - { ahc_patch6_func, 443, 5, 2 }, - { ahc_patch0_func, 448, 1, 1 }, - { ahc_patch7_func, 449, 113, 22 }, - { ahc_patch1_func, 450, 3, 2 }, - { ahc_patch0_func, 453, 5, 3 }, - { ahc_patch8_func, 453, 2, 2 }, - { ahc_patch0_func, 455, 3, 1 }, - { ahc_patch1_func, 460, 2, 2 }, - { ahc_patch0_func, 462, 6, 3 }, - { ahc_patch8_func, 462, 2, 2 }, - { ahc_patch0_func, 464, 3, 1 }, + { ahc_patch7_func, 133, 4, 1 }, + { ahc_patch7_func, 144, 80, 9 }, + { ahc_patch4_func, 162, 1, 1 }, + { ahc_patch1_func, 175, 1, 1 }, + { ahc_patch9_func, 183, 1, 2 }, + { ahc_patch0_func, 184, 1, 1 }, + { ahc_patch9_func, 193, 1, 2 }, + { ahc_patch0_func, 194, 1, 1 }, + { ahc_patch9_func, 210, 6, 2 }, + { ahc_patch0_func, 216, 6, 1 }, + { ahc_patch8_func, 224, 18, 2 }, + { ahc_patch1_func, 237, 1, 1 }, + { ahc_patch1_func, 244, 1, 2 }, + { ahc_patch0_func, 245, 2, 2 }, + { ahc_patch12_func, 246, 1, 1 }, + { ahc_patch9_func, 254, 33, 2 }, + { ahc_patch1_func, 270, 16, 1 }, + { ahc_patch13_func, 287, 14, 1 }, + { ahc_patch1_func, 301, 2, 2 }, + { ahc_patch0_func, 303, 3, 3 }, + { ahc_patch9_func, 303, 1, 2 }, + { ahc_patch0_func, 304, 2, 1 }, + { ahc_patch1_func, 308, 1, 2 }, + { ahc_patch0_func, 309, 1, 1 }, + { ahc_patch9_func, 313, 1, 1 }, + { ahc_patch9_func, 316, 2, 2 }, + { ahc_patch0_func, 318, 4, 1 }, + { ahc_patch13_func, 322, 1, 1 }, + { ahc_patch14_func, 325, 2, 3 }, + { ahc_patch9_func, 325, 1, 2 }, + { ahc_patch0_func, 326, 1, 1 }, + { ahc_patch6_func, 331, 1, 2 }, + { ahc_patch0_func, 332, 1, 1 }, + { ahc_patch1_func, 336, 45, 10 }, + { ahc_patch6_func, 345, 2, 4 }, + { ahc_patch7_func, 345, 1, 1 }, + { ahc_patch8_func, 346, 1, 1 }, + { ahc_patch0_func, 347, 1, 1 }, + { ahc_patch15_func, 348, 1, 1 }, + { ahc_patch6_func, 367, 6, 3 }, + { ahc_patch15_func, 367, 5, 1 }, + { ahc_patch0_func, 373, 5, 1 }, + { ahc_patch0_func, 381, 51, 15 }, + { ahc_patch13_func, 381, 1, 1 }, + { ahc_patch7_func, 383, 2, 2 }, + { ahc_patch16_func, 384, 1, 1 }, + { ahc_patch9_func, 387, 1, 1 }, + { ahc_patch17_func, 394, 1, 1 }, + { ahc_patch13_func, 399, 9, 3 }, + { ahc_patch9_func, 400, 3, 2 }, + { ahc_patch0_func, 403, 3, 1 }, + { ahc_patch9_func, 411, 6, 2 }, + { ahc_patch0_func, 417, 8, 1 }, + { ahc_patch13_func, 425, 1, 1 }, + { ahc_patch9_func, 427, 1, 2 }, + { ahc_patch0_func, 428, 1, 1 }, + { ahc_patch7_func, 431, 1, 1 }, + { ahc_patch7_func, 432, 1, 1 }, + { ahc_patch8_func, 433, 3, 3 }, + { ahc_patch6_func, 434, 1, 2 }, + { ahc_patch0_func, 435, 1, 1 }, + { ahc_patch9_func, 436, 1, 1 }, + { ahc_patch13_func, 437, 9, 4 }, + { ahc_patch9_func, 437, 1, 1 }, + { ahc_patch9_func, 444, 2, 1 }, + { ahc_patch0_func, 446, 4, 3 }, + { ahc_patch9_func, 446, 1, 2 }, + { ahc_patch0_func, 447, 3, 1 }, + { ahc_patch1_func, 451, 2, 1 }, + { ahc_patch7_func, 453, 5, 2 }, + { ahc_patch0_func, 458, 1, 1 }, + { ahc_patch8_func, 459, 107, 23 }, + { ahc_patch1_func, 460, 3, 2 }, + { ahc_patch0_func, 463, 5, 3 }, + { ahc_patch9_func, 463, 2, 2 }, + { ahc_patch0_func, 465, 3, 1 }, { ahc_patch1_func, 470, 2, 2 }, - { ahc_patch0_func, 472, 9, 7 }, - { ahc_patch8_func, 472, 5, 6 }, - { ahc_patch18_func, 472, 1, 2 }, - { ahc_patch0_func, 473, 1, 1 }, - { ahc_patch18_func, 475, 1, 2 }, - { ahc_patch0_func, 476, 1, 1 }, - { ahc_patch0_func, 477, 4, 1 }, - { ahc_patch1_func, 486, 1, 1 }, - { ahc_patch2_func, 498, 2, 2 }, - { ahc_patch0_func, 500, 2, 2 }, - { ahc_patch19_func, 500, 2, 1 }, - { ahc_patch19_func, 536, 7, 1 }, - { ahc_patch3_func, 564, 1, 2 }, - { ahc_patch0_func, 565, 1, 1 }, - { ahc_patch20_func, 568, 1, 1 }, - { ahc_patch7_func, 570, 95, 26 }, - { ahc_patch4_func, 571, 1, 1 }, - { ahc_patch8_func, 578, 2, 2 }, - { ahc_patch0_func, 580, 3, 1 }, - { ahc_patch18_func, 587, 2, 2 }, - { ahc_patch0_func, 589, 1, 1 }, - { ahc_patch18_func, 593, 10, 3 }, - { ahc_patch5_func, 595, 8, 1 }, - { ahc_patch0_func, 603, 9, 2 }, - { ahc_patch5_func, 604, 8, 1 }, - { ahc_patch4_func, 614, 1, 2 }, - { ahc_patch0_func, 615, 1, 1 }, - { ahc_patch18_func, 616, 1, 2 }, - { ahc_patch0_func, 617, 3, 2 }, - { ahc_patch4_func, 619, 1, 1 }, - { ahc_patch5_func, 620, 1, 1 }, - { ahc_patch5_func, 623, 1, 1 }, - { ahc_patch5_func, 625, 1, 1 }, - { ahc_patch4_func, 627, 2, 2 }, - { ahc_patch0_func, 629, 2, 1 }, + { ahc_patch0_func, 472, 6, 3 }, + { ahc_patch9_func, 472, 2, 2 }, + { ahc_patch0_func, 474, 3, 1 }, + { ahc_patch1_func, 480, 2, 2 }, + { ahc_patch0_func, 482, 9, 7 }, + { ahc_patch9_func, 482, 5, 6 }, + { ahc_patch18_func, 482, 1, 2 }, + { ahc_patch0_func, 483, 1, 1 }, + { ahc_patch18_func, 485, 1, 2 }, + { ahc_patch0_func, 486, 1, 1 }, + { ahc_patch0_func, 487, 4, 1 }, + { ahc_patch6_func, 491, 3, 2 }, + { ahc_patch0_func, 494, 1, 1 }, + { ahc_patch1_func, 497, 1, 1 }, + { ahc_patch6_func, 502, 1, 2 }, + { ahc_patch0_func, 503, 1, 1 }, + { ahc_patch19_func, 540, 7, 1 }, + { ahc_patch3_func, 568, 1, 2 }, + { ahc_patch0_func, 569, 1, 1 }, + { ahc_patch20_func, 572, 1, 1 }, + { ahc_patch8_func, 574, 100, 31 }, + { ahc_patch4_func, 575, 1, 1 }, + { ahc_patch1_func, 581, 2, 2 }, + { ahc_patch0_func, 583, 1, 1 }, + { ahc_patch9_func, 584, 3, 3 }, + { ahc_patch14_func, 585, 1, 1 }, + { ahc_patch0_func, 587, 4, 1 }, + { ahc_patch18_func, 595, 2, 2 }, + { ahc_patch0_func, 597, 1, 1 }, + { ahc_patch18_func, 601, 10, 3 }, + { ahc_patch5_func, 603, 8, 1 }, + { ahc_patch0_func, 611, 9, 2 }, + { ahc_patch5_func, 612, 8, 1 }, + { ahc_patch4_func, 622, 1, 2 }, + { ahc_patch0_func, 623, 1, 1 }, + { ahc_patch18_func, 624, 1, 2 }, + { ahc_patch0_func, 625, 3, 2 }, + { ahc_patch4_func, 627, 1, 1 }, + { ahc_patch5_func, 628, 1, 1 }, { ahc_patch5_func, 631, 1, 1 }, - { ahc_patch5_func, 634, 1, 1 }, - { ahc_patch5_func, 637, 1, 1 }, - { ahc_patch18_func, 641, 1, 1 }, - { ahc_patch18_func, 644, 1, 1 }, - { ahc_patch4_func, 650, 1, 1 }, - { ahc_patch6_func, 665, 16, 1 }, - { ahc_patch4_func, 683, 20, 1 }, - { ahc_patch8_func, 704, 4, 2 }, - { ahc_patch0_func, 708, 4, 1 }, - { ahc_patch8_func, 712, 4, 2 }, - { ahc_patch0_func, 716, 3, 1 }, - { ahc_patch21_func, 724, 14, 1 }, - { ahc_patch6_func, 738, 3, 1 }, - { ahc_patch8_func, 750, 24, 8 }, - { ahc_patch18_func, 754, 1, 2 }, - { ahc_patch0_func, 755, 1, 1 }, - { ahc_patch13_func, 760, 4, 2 }, - { ahc_patch0_func, 764, 7, 3 }, - { ahc_patch22_func, 764, 5, 2 }, - { ahc_patch0_func, 769, 2, 1 }, - { ahc_patch0_func, 774, 40, 3 }, - { ahc_patch17_func, 786, 16, 2 }, - { ahc_patch0_func, 802, 1, 1 }, - { ahc_patch4_func, 826, 1, 1 }, - { ahc_patch4_func, 827, 3, 2 }, - { ahc_patch0_func, 830, 1, 1 }, - { ahc_patch4_func, 831, 12, 1 } + { ahc_patch5_func, 633, 1, 1 }, + { ahc_patch4_func, 635, 2, 2 }, + { ahc_patch0_func, 637, 2, 1 }, + { ahc_patch5_func, 639, 1, 1 }, + { ahc_patch5_func, 642, 1, 1 }, + { ahc_patch5_func, 645, 1, 1 }, + { ahc_patch18_func, 649, 1, 1 }, + { ahc_patch18_func, 652, 1, 1 }, + { ahc_patch4_func, 658, 1, 1 }, + { ahc_patch6_func, 661, 1, 2 }, + { ahc_patch0_func, 662, 1, 1 }, + { ahc_patch7_func, 674, 16, 1 }, + { ahc_patch4_func, 692, 20, 1 }, + { ahc_patch9_func, 713, 4, 2 }, + { ahc_patch0_func, 717, 4, 1 }, + { ahc_patch9_func, 721, 4, 2 }, + { ahc_patch0_func, 725, 3, 1 }, + { ahc_patch6_func, 731, 1, 1 }, + { ahc_patch21_func, 733, 14, 1 }, + { ahc_patch7_func, 747, 3, 1 }, + { ahc_patch9_func, 759, 24, 8 }, + { ahc_patch18_func, 763, 1, 2 }, + { ahc_patch0_func, 764, 1, 1 }, + { ahc_patch14_func, 769, 4, 2 }, + { ahc_patch0_func, 773, 7, 3 }, + { ahc_patch22_func, 773, 5, 2 }, + { ahc_patch0_func, 778, 2, 1 }, + { ahc_patch0_func, 783, 41, 3 }, + { ahc_patch17_func, 795, 17, 2 }, + { ahc_patch0_func, 812, 1, 1 }, + { ahc_patch4_func, 836, 1, 1 }, + { ahc_patch4_func, 837, 3, 2 }, + { ahc_patch0_func, 840, 1, 1 }, + { ahc_patch4_func, 841, 12, 1 } }; struct cs { u_int16_t begin; @@ -1229,11 +1255,11 @@ } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 683, 699 }, - { 827, 830 }, - { 831, 837 }, - { 839, 841 }, - { 841, 843 } + { 692, 708 }, + { 837, 840 }, + { 841, 847 }, + { 849, 851 }, + { 851, 853 } }; const int num_critical_sections = sizeof(critical_sections) / sizeof(*critical_sections); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/Makefile linux/drivers/scsi/aic7xxx/aicasm/Makefile --- v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/Makefile Tue Mar 6 22:44:16 2001 +++ linux/drivers/scsi/aic7xxx/aicasm/Makefile Fri May 4 15:16:28 2001 @@ -2,17 +2,23 @@ CSRCS= aicasm.c aicasm_symbol.c GENSRCS= aicasm_gram.c aicasm_scan.c - -GENHDRS= y.tab.h +DEPHDRS= aicdb.h +GENHDRS= y.tab.h aicdb.h SRCS= ${GENSRCS} ${CSRCS} CLEANFILES= ${GENSRCS} ${GENHDRS} y.output # Override default kernel CFLAGS. This is a userland app. -AICASM_CFLAGS:= -I/usr/include -ldb1 +AICASM_CFLAGS:= -I/usr/include -I. -ldb YFLAGS= -d NOMAN= noman +ifneq ($(HOSTCC),) +AICASM_CC= $(HOSTCC) +else +AICASM_CC= $(CC) +endif + ifdef DEBUG CFLAGS+= -DDEBUG -g YFLAGS+= -t -v @@ -21,8 +27,21 @@ .SUFFIXES= .l .y .c -$(PROG): $(SRCS) - $(HOSTCC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) +$(PROG): $(SRCS) $(DEPHDRS) + $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) + +aicdb.h: + @if [ -e "/usr/include/db3/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db2/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + elif [ -e "/usr/include/db_185.h" ]; then \ + echo "#include " > aicdb.h; \ + else \ + echo "*** Install db development libraries"; \ + fi clean: rm -f $(CLEANFILES) $(PROG) diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c --- v2.4.4/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Fri May 4 15:16:28 2001 @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#4 $ + * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#5 $ * * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $ */ @@ -36,7 +36,7 @@ #include #ifdef __linux__ -#include +#include "aicdb.h" #else #include #endif diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.4.4/linux/drivers/scsi/fdomain.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/fdomain.c Fri May 4 15:11:42 2001 @@ -587,9 +587,7 @@ static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */ { - do { - udelay(10*1000); - } while (--amount); + mdelay(10*amount); } inline static void fdomain_make_bus_idle( void ) @@ -971,7 +969,7 @@ return 0; shpnt->irq = interrupt_level; shpnt->io_port = port_base; - scsi_set_pci_device(shpnt->pci_dev, pdev); + scsi_set_pci_device(shpnt, pdev); shpnt->n_io_port = 0x10; print_banner( shpnt ); diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.4.4/linux/drivers/scsi/ibmmca.c Fri Mar 2 18:38:38 2001 +++ linux/drivers/scsi/ibmmca.c Tue May 1 16:05:00 2001 @@ -50,7 +50,7 @@ /* driver debugging - #undef all for normal operation */ /* if defined: count interrupts and ignore this special one: */ -#undef IM_DEBUG_TIMEOUT 50 +#undef IM_DEBUG_TIMEOUT //50 #define TIMEOUT_PUN 0 #define TIMEOUT_LUN 0 /* verbose interrupt: */ diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.4.4/linux/drivers/scsi/pci2220i.c Fri Apr 27 13:59:19 2001 +++ linux/drivers/scsi/pci2220i.c Mon Apr 30 17:13:07 2001 @@ -2657,7 +2657,7 @@ for ( z = 0; z < BIGD_MAXDRIVES; z++ ) DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z); - scsi_set_pci_info(pshost, pcidev); + scsi_set_pci_device(pshost, pcidev); pshost->max_id = padapter->numberOfDrives; padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE); for ( z = 0; z < padapter->numberOfDrives; z++ ) diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.4.4/linux/drivers/scsi/scsi.c Wed Apr 25 16:18:54 2001 +++ linux/drivers/scsi/scsi.c Mon Apr 30 16:31:18 2001 @@ -104,7 +104,7 @@ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, - 16, 12, 10, 10 + 12, 12, 10, 10 }; static unsigned long serial_number; static Scsi_Cmnd *scsi_bh_queue_head; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.4.4/linux/drivers/scsi/scsi_lib.c Fri Mar 2 18:38:39 2001 +++ linux/drivers/scsi/scsi_lib.c Fri May 4 15:16:28 2001 @@ -1108,9 +1108,13 @@ */ void scsi_unblock_requests(struct Scsi_Host * SHpnt) { + Scsi_Device *SDloop; + SHpnt->host_self_blocked = FALSE; + /* Now that we are unblocked, try to start the queues. */ + for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) + scsi_queue_next_request(&SDloop->request_queue, NULL); } - /* * Function: scsi_report_bus_reset() diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.4.4/linux/drivers/scsi/sd.c Sat Feb 3 11:45:55 2001 +++ linux/drivers/scsi/sd.c Sat Apr 28 11:28:08 2001 @@ -993,8 +993,7 @@ the_result = SRpnt->sr_result; if (the_result) { - printk("%s: test WP failed, assume Write Protected\n", nbuff); - rscsi_disks[i].write_prot = 1; + printk("%s: test WP failed, assume Write Enabled\n", nbuff); } else { rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0); printk("%s: Write Protect is %s\n", nbuff, @@ -1261,12 +1260,7 @@ for (i = max_p - 1; i >= 0; i--) { int index = start + i; - kdev_t devi = MKDEV_SD_PARTITION(index); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV_SD_PARTITION(index), 1); sd_gendisks->part[index].start_sect = 0; sd_gendisks->part[index].nr_sects = 0; /* @@ -1314,12 +1308,7 @@ for (j = max_p - 1; j >= 0; j--) { int index = start + j; - kdev_t devi = MKDEV_SD_PARTITION(index); - struct super_block *sb = get_super(devi); - sync_dev(devi); - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV_SD_PARTITION(index), 1); sd_gendisks->part[index].start_sect = 0; sd_gendisks->part[index].nr_sects = 0; sd_sizes[index] = 0; diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.4.4/linux/drivers/scsi/sr.c Mon Feb 19 10:25:17 2001 +++ linux/drivers/scsi/sr.c Sat Apr 28 11:28:08 2001 @@ -496,13 +496,6 @@ return 0; } -/* - * do_sr_request() is the request handler function for the sr driver. - * Its function in life is to take block device requests, and - * translate them to SCSI commands. - */ - - static int sr_detect(Scsi_Device * SDp) { @@ -869,16 +862,11 @@ for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) if (cpnt->device == SDp) { - kdev_t devi = MKDEV(MAJOR_NR, i); - struct super_block *sb = get_super(devi); - /* * Since the cdrom is read-only, no need to sync the device. * We should be kind to our buffer cache, however. */ - if (sb) - invalidate_inodes(sb); - invalidate_buffers(devi); + invalidate_device(MKDEV(MAJOR_NR, i), 0); /* * Reset things back to a sane state so that one can re-load a new diff -u --recursive --new-file v2.4.4/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c --- v2.4.4/linux/drivers/sound/cs4281/cs4281m.c Wed Apr 18 11:49:11 2001 +++ linux/drivers/sound/cs4281/cs4281m.c Tue May 1 16:05:00 2001 @@ -194,9 +194,6 @@ } \ }) -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - //LIST_HEAD(cs4281_devs); struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs }; diff -u --recursive --new-file v2.4.4/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.4/linux/drivers/sound/i810_audio.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/sound/i810_audio.c Tue May 1 16:05:00 2001 @@ -1520,7 +1520,9 @@ val = 16384; if (val > 65536) val = 65536; - dmabuf->ossfragsize = val/dmabuf->ossmaxfrags; + dmabuf->ossmaxfrags = val/dmabuf->ossfragsize; + if(dmabuf->ossmaxfrags<4) + dmabuf->ossfragsize = val/4; dmabuf->ready = 0; #ifdef DEBUG printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, diff -u --recursive --new-file v2.4.4/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.4.4/linux/drivers/sound/nm256_audio.c Sat Nov 11 18:33:14 2000 +++ linux/drivers/sound/nm256_audio.c Tue May 1 16:05:00 2001 @@ -15,6 +15,8 @@ * Changes: * 11-10-2000 Bartlomiej Zolnierkiewicz * Added some __init + * 19-04-2001 Marcus Meissner + * Ported to 2.4 PCI API. */ #define __NO_VERSION__ @@ -49,8 +51,6 @@ #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 -#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) - /* List of cards. */ static struct nm256_info *nmcard_list; @@ -1042,6 +1042,9 @@ struct pm_dev *pmdev; int x; + if (pci_enable_device(pcidev)) + return 0; + card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL); if (card == NULL) { printk (KERN_ERR "NM256: out of memory!\n"); @@ -1055,7 +1058,7 @@ /* Init the memory port info. */ for (x = 0; x < 2; x++) { - card->port[x].physaddr = RSRCADDRESS (pcidev, x); + card->port[x].physaddr = pci_resource_start (pcidev, x); card->port[x].ptr = NULL; card->port[x].start_offset = 0; card->port[x].end_offset = 0; @@ -1201,6 +1204,8 @@ } } + pci_set_drvdata(pcidev,card); + /* Insert the card in the list. */ card->next_card = nmcard_list; nmcard_list = card; @@ -1251,37 +1256,38 @@ return 0; } -/* - * This loop walks the PCI configuration database and finds where - * the sound cards are. - */ - -int __init -init_nm256(void) +static int __devinit +nm256_probe(struct pci_dev *pcidev,const struct pci_device_id *pciid) { - struct pci_dev *pcidev = NULL; - int count = 0; - - if(! pci_present()) - return -ENODEV; - - while((pcidev = pci_find_device(PCI_VENDOR_ID_NEOMAGIC, - PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, - pcidev)) != NULL) { - count += nm256_install(pcidev, REV_NM256AV, "256AV"); - } - - while((pcidev = pci_find_device(PCI_VENDOR_ID_NEOMAGIC, - PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, - pcidev)) != NULL) { - count += nm256_install(pcidev, REV_NM256ZX, "256ZX"); + if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO) + return nm256_install(pcidev, REV_NM256AV, "256AV"); + if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO) + return nm256_install(pcidev, REV_NM256ZX, "256ZX"); + return -1; /* should not come here ... */ +} + +static void __devinit +nm256_remove(struct pci_dev *pcidev) { + struct nm256_info *xcard = pci_get_drvdata(pcidev); + struct nm256_info *card,*next_card = NULL; + + for (card = nmcard_list; card != NULL; card = next_card) { + next_card = card->next_card; + if (card == xcard) { + stopPlay (card); + stopRecord (card); + if (card->has_irq) + free_irq (card->irq, card); + nm256_release_ports (card); + sound_unload_mixerdev (card->mixer_oss_dev); + sound_unload_audiodev (card->dev[0]); + sound_unload_audiodev (card->dev[1]); + kfree (card); + break; + } } - - if (count == 0) - return -ENODEV; - - printk (KERN_INFO "Done installing NM256 audio driver.\n"); - return 0; + if (nmcard_list == card) + nmcard_list = next_card; } /* @@ -1639,9 +1645,21 @@ local_qlen: nm256_audio_local_qlen, }; -EXPORT_SYMBOL(init_nm256); +static struct pci_device_id nm256_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0}, + {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, nm256_pci_tbl); -static int loaded = 0; +struct pci_driver nm256_pci_driver = { + name:"nm256_audio", + id_table:nm256_pci_tbl, + probe:nm256_probe, + remove:nm256_remove, +}; MODULE_PARM (usecache, "i"); MODULE_PARM (buffertop, "i"); @@ -1650,37 +1668,13 @@ static int __init do_init_nm256(void) { - nmcard_list = NULL; - printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n"); - - if (init_nm256 () == 0) { - loaded = 1; - return 0; - } - else - return -ENODEV; + printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1p\n"); + return pci_module_init(&nm256_pci_driver); } static void __exit cleanup_nm256 (void) { - if (loaded) { - struct nm256_info *card; - struct nm256_info *next_card; - - for (card = nmcard_list; card != NULL; card = next_card) { - stopPlay (card); - stopRecord (card); - if (card->has_irq) - free_irq (card->irq, card); - nm256_release_ports (card); - sound_unload_mixerdev (card->mixer_oss_dev); - sound_unload_audiodev (card->dev[0]); - sound_unload_audiodev (card->dev[1]); - next_card = card->next_card; - kfree (card); - } - nmcard_list = NULL; - } + pci_unregister_driver(&nm256_pci_driver); pm_unregister_all (&handle_pm_event); } diff -u --recursive --new-file v2.4.4/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.4.4/linux/drivers/sound/sb_card.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/sound/sb_card.c Tue May 1 16:05:00 2001 @@ -339,6 +339,11 @@ 0,0,0,0, 0,1,1,-1}, {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, diff -u --recursive --new-file v2.4.4/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.4/linux/drivers/sound/trident.c Fri Apr 6 10:51:19 2001 +++ linux/drivers/sound/trident.c Tue May 1 16:05:00 2001 @@ -1967,9 +1967,9 @@ case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && dmabuf->enable) + if ((file->f_mode & FMODE_READ) && dmabuf->enable) val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && dmabuf->enable) + if ((file->f_mode & FMODE_WRITE) && dmabuf->enable) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); @@ -3309,6 +3309,9 @@ struct trident_card *card; u8 revision; + if (pci_enable_device(pci_dev)) + return -ENODEV; + if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) { printk(KERN_ERR "trident: architecture does not support" " 30bit PCI busmaster DMA\n"); @@ -3322,9 +3325,6 @@ iobase); return -ENODEV; } - - if (pci_enable_device(pci_dev)) - return -ENODEV; if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "trident: out of memory\n"); diff -u --recursive --new-file v2.4.4/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.4.4/linux/drivers/sound/via82cxxx_audio.c Fri Mar 2 11:02:15 2001 +++ linux/drivers/sound/via82cxxx_audio.c Tue May 1 16:05:00 2001 @@ -3020,6 +3020,11 @@ if (printed_version++ == 0) printk (KERN_INFO "Via 686a audio driver " VIA_VERSION "\n"); + if (pci_enable_device (pdev)) { + rc = -EIO; + goto err_out_none; + } + if (!request_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0), VIA_MODULE_NAME)) { @@ -3028,10 +3033,6 @@ goto err_out; } - if (pci_enable_device (pdev)) { - rc = -EIO; - goto err_out_none; - } card = kmalloc (sizeof (*card), GFP_KERNEL); if (!card) { diff -u --recursive --new-file v2.4.4/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c --- v2.4.4/linux/drivers/sound/ymfpci.c Thu Apr 26 22:17:27 2001 +++ linux/drivers/sound/ymfpci.c Fri May 4 23:40:46 2001 @@ -989,11 +989,6 @@ status = ymfpci_readl(codec, YDSXGR_STATUS); if (status & 0x80000000) { - spin_lock(&codec->reg_lock); - ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); - mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; - ymfpci_writel(codec, YDSXGR_MODE, mode); - spin_unlock(&codec->reg_lock); codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1; spin_lock(&codec->voice_lock); for (nvoice = 0; nvoice < 64; nvoice++) { @@ -1007,6 +1002,11 @@ ymf_cap_interrupt(codec, cap); } spin_unlock(&codec->voice_lock); + spin_lock(&codec->reg_lock); + ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); + mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; + ymfpci_writel(codec, YDSXGR_MODE, mode); + spin_unlock(&codec->reg_lock); } status = ymfpci_readl(codec, YDSXGR_INTFLAG); @@ -2106,6 +2106,8 @@ pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03); pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); } + pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0); + pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0); } static void ymfpci_enable_dsp(ymfpci_t *codec) diff -u --recursive --new-file v2.4.4/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.4.4/linux/drivers/usb/Config.in Mon Nov 27 18:10:35 2000 +++ linux/drivers/usb/Config.in Sat Apr 28 11:28:08 2001 @@ -32,6 +32,7 @@ if [ "$CONFIG_USB_STORAGE" != "n" ]; then bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG bool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM + bool ' Microtech CompactFlash/SmartMedia reader' CONFIG_USB_STORAGE_DPCM fi dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB diff -u --recursive --new-file v2.4.4/linux/drivers/usb/storage/dpcm.c linux/drivers/usb/storage/dpcm.c --- v2.4.4/linux/drivers/usb/storage/dpcm.c Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/dpcm.c Sat Apr 28 11:28:08 2001 @@ -10,7 +10,7 @@ * (c) 2000 Brian Webb (webbb@earthlink.net) * * This device contains both a CompactFlash card reader, which - * usest the Control/Bulk w/o Interrupt protocol and + * uses the Control/Bulk w/o Interrupt protocol and * a SmartMedia card reader that uses the same protocol * as the SDDR09. * diff -u --recursive --new-file v2.4.4/linux/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h --- v2.4.4/linux/drivers/usb/storage/unusual_devs.h Fri Apr 27 15:49:28 2001 +++ linux/drivers/usb/storage/unusual_devs.h Tue May 15 00:34:26 2001 @@ -79,6 +79,12 @@ "CameraMate (DPCM_USB)", US_SC_SCSI, US_PR_DPCM_USB, NULL, US_FL_START_STOP ), + +UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, + "SCM Microsystems Inc", + "eUSB SmartMedia / CompactFlash Adapter", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP ), #endif UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0200, diff -u --recursive --new-file v2.4.4/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.4.4/linux/drivers/usb/uhci.c Wed Apr 25 14:10:49 2001 +++ linux/drivers/usb/uhci.c Tue May 1 18:23:01 2001 @@ -644,21 +644,23 @@ urb->hcpriv = urbp; - if (urb->transfer_buffer_length) { - urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev, - urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : - PCI_DMA_TODEVICE); - if (!urbp->transfer_buffer_dma_handle) - return NULL; - } + if (urb->dev != uhci->rh.dev) { + if (urb->transfer_buffer_length) { + urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev, + urb->transfer_buffer, urb->transfer_buffer_length, + usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : + PCI_DMA_TODEVICE); + if (!urbp->transfer_buffer_dma_handle) + return NULL; + } - if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) { - urbp->setup_packet_dma_handle = pci_map_single(uhci->dev, - urb->setup_packet, sizeof(devrequest), - PCI_DMA_TODEVICE); - if (!urbp->setup_packet_dma_handle) - return NULL; + if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) { + urbp->setup_packet_dma_handle = pci_map_single(uhci->dev, + urb->setup_packet, sizeof(devrequest), + PCI_DMA_TODEVICE); + if (!urbp->setup_packet_dma_handle) + return NULL; + } } return urbp; @@ -722,11 +724,11 @@ uhci_free_td(uhci, td); } - if (urb->setup_packet) + if (urbp->setup_packet_dma_handle) pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(devrequest), PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length) + if (urbp->transfer_buffer_dma_handle) pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); @@ -2247,12 +2249,12 @@ if (!killed) urb->status = status; - if (urb->transfer_buffer_length) + if (urbp->transfer_buffer_dma_handle) pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) + if (urbp->setup_packet_dma_handle) pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(devrequest), PCI_DMA_TODEVICE); diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.4/linux/drivers/usb/usb.c Wed Apr 25 14:10:47 2001 +++ linux/drivers/usb/usb.c Sat Apr 28 11:28:09 2001 @@ -569,7 +569,7 @@ * The most specific match specifiers use device descriptor * data. These are commonly used with product-specific matches; * the USB_DEVICE macro lets you provide vendor and product IDs, - * and you can also matche against ranges of product revisions. + * and you can also match against ranges of product revisions. * These are widely used for devices with application or vendor * specific bDeviceClass values. * diff -u --recursive --new-file v2.4.4/linux/drivers/video/sis/sis_main.c linux/drivers/video/sis/sis_main.c --- v2.4.4/linux/drivers/video/sis/sis_main.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/video/sis/sis_main.c Fri May 4 15:10:17 2001 @@ -1029,6 +1029,8 @@ if (heap.pohFreeList == NULL) { poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL); + if (!poha) + return NULL; poha->pohaNext = heap.pohaChain; heap.pohaChain = poha; diff -u --recursive --new-file v2.4.4/linux/fs/block_dev.c linux/fs/block_dev.c --- v2.4.4/linux/fs/block_dev.c Fri Feb 9 11:29:44 2001 +++ linux/fs/block_dev.c Mon Apr 30 19:54:03 2001 @@ -554,7 +554,6 @@ { int i; const struct block_device_operations * bdops = NULL; - struct super_block * sb; i = MAJOR(dev); if (i < MAX_BLKDEV) @@ -576,11 +575,8 @@ printk(KERN_DEBUG "VFS: Disk change detected on device %s\n", bdevname(dev)); - sb = get_super(dev); - if (sb && invalidate_inodes(sb)) + if (invalidate_device(dev, 0)) printk("VFS: busy inodes on changed media.\n"); - - destroy_buffers(dev); if (bdops->revalidate) bdops->revalidate(dev); diff -u --recursive --new-file v2.4.4/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.4/linux/fs/buffer.c Fri Apr 27 14:23:25 2001 +++ linux/fs/buffer.c Tue May 15 00:36:38 2001 @@ -1034,7 +1034,6 @@ int balance_dirty_state(kdev_t dev) { unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit; - int shortage; dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT; tot = nr_free_buffer_pages(); @@ -1050,16 +1049,6 @@ return 0; } - /* - * If we are about to get low on free pages and - * cleaning the inactive_dirty pages would help - * fix this, wake up bdflush. - */ - shortage = free_shortage(); - if (shortage && nr_inactive_dirty_pages > shortage && - nr_inactive_dirty_pages > freepages.high) - return 0; - return -1; } @@ -2578,16 +2567,15 @@ return flushed; } -struct task_struct *bdflush_tsk = 0; +DECLARE_WAIT_QUEUE_HEAD(bdflush_wait); void wakeup_bdflush(int block) { - if (current != bdflush_tsk) { - wake_up_process(bdflush_tsk); + if (waitqueue_active(&bdflush_wait)) + wake_up_interruptible(&bdflush_wait); - if (block) - flush_dirty_buffers(0); - } + if (block) + flush_dirty_buffers(0); } /* @@ -2688,7 +2676,6 @@ tsk->session = 1; tsk->pgrp = 1; strcpy(tsk->comm, "bdflush"); - bdflush_tsk = tsk; /* avoid getting signals */ spin_lock_irq(&tsk->sigmask_lock); @@ -2703,22 +2690,16 @@ CHECK_EMERGENCY_SYNC flushed = flush_dirty_buffers(0); - if (free_shortage()) - flushed += page_launder(GFP_KERNEL, 0); /* * If there are still a lot of dirty buffers around, * skip the sleep and flush some more. Otherwise, we * go to sleep waiting a wakeup. */ - set_current_state(TASK_INTERRUPTIBLE); if (!flushed || balance_dirty_state(NODEV) < 0) { run_task_queue(&tq_disk); - schedule(); + interruptible_sleep_on(&bdflush_wait); } - /* Remember to mark us as running otherwise - the next schedule will block. */ - __set_current_state(TASK_RUNNING); } } diff -u --recursive --new-file v2.4.4/linux/fs/devfs/base.c linux/fs/devfs/base.c --- v2.4.4/linux/fs/devfs/base.c Tue Apr 17 15:04:10 2001 +++ linux/fs/devfs/base.c Sat Apr 28 11:27:54 2001 @@ -2156,7 +2156,6 @@ int tmp; kdev_t dev = MKDEV (de->u.fcb.u.device.major, de->u.fcb.u.device.minor); struct block_device_operations *bdops = de->u.fcb.ops; - struct super_block * sb; extern int warn_no_part; if ( !S_ISBLK (de->mode) ) return 0; @@ -2165,10 +2164,8 @@ if ( !bdops->check_media_change (dev) ) return 0; printk ( KERN_DEBUG "VFS: Disk change detected on device %s\n", kdevname (dev) ); - sb = get_super (dev); - if ( sb && invalidate_inodes (sb) ) + if (invalidate_device(dev, 0)) printk("VFS: busy inodes on changed media..\n"); - invalidate_buffers (dev); /* Ugly hack to disable messages about unable to read partition table */ tmp = warn_no_part; warn_no_part = 0; diff -u --recursive --new-file v2.4.4/linux/fs/inode.c linux/fs/inode.c --- v2.4.4/linux/fs/inode.c Fri Apr 27 14:11:30 2001 +++ linux/fs/inode.c Mon Apr 30 19:47:51 2001 @@ -591,6 +591,22 @@ return busy; } + +int invalidate_device(kdev_t dev, int do_sync) +{ + struct super_block *sb = get_super(dev); + int res; + + if (do_sync) + fsync_dev(dev); + + res = 0; + if (sb) + res = invalidate_inodes(sb); + invalidate_buffers(dev); + return res; +} + /* * This is called with the inode lock held. It searches @@ -612,12 +628,13 @@ { LIST_HEAD(list); struct list_head *entry, *freeable = &list; - int count = 0, synced = 0; + int count, synced = 0; struct inode * inode; spin_lock(&inode_lock); free_unused: + count = 0; entry = inode_unused.prev; while (entry != &inode_unused) { diff -u --recursive --new-file v2.4.4/linux/fs/isofs/util.c linux/fs/isofs/util.c --- v2.4.4/linux/fs/isofs/util.c Wed Nov 29 10:11:38 2000 +++ linux/fs/isofs/util.c Tue May 1 18:21:01 2001 @@ -1,90 +1,10 @@ /* * linux/fs/isofs/util.c - * - * The special functions in the file are numbered according to the section - * of the iso 9660 standard in which they are described. isonum_733 will - * convert numbers according to section 7.3.3, etc. - * - * isofs special functions. This file was lifted in its entirety from - * the 386BSD iso9660 filesystem, by Pace Willisson . */ #include - -int -isonum_711 (char * p) -{ - return (*p & 0xff); -} - -int -isonum_712 (char * p) -{ - int val; - - val = *p; - if (val & 0x80) - val |= 0xffffff00; - return (val); -} - -int -isonum_721 (char * p) -{ - return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); -} - -int -isonum_722 (char * p) -{ - return (((p[0] & 0xff) << 8) | (p[1] & 0xff)); -} - -int -isonum_723 (char * p) -{ -#if 0 - if (p[0] != p[3] || p[1] != p[2]) { - fprintf (stderr, "invalid format 7.2.3 number\n"); - exit (1); - } -#endif - return (isonum_721 (p)); -} - -int -isonum_731 (char * p) -{ - return ((p[0] & 0xff) - | ((p[1] & 0xff) << 8) - | ((p[2] & 0xff) << 16) - | ((p[3] & 0xff) << 24)); -} - -int -isonum_732 (char * p) -{ - return (((p[0] & 0xff) << 24) - | ((p[1] & 0xff) << 16) - | ((p[2] & 0xff) << 8) - | (p[3] & 0xff)); -} - -int -isonum_733 (char * p) -{ -#if 0 - int i; - - for (i = 0; i < 4; i++) { - if (p[i] != p[7-i]) { - fprintf (stderr, "bad format 7.3.3 number\n"); - exit (1); - } - } -#endif - return (isonum_731 (p)); -} +#include +#include /* * We have to convert from a MM/DD/YY format to the Unix ctime format. diff -u --recursive --new-file v2.4.4/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.4.4/linux/fs/nfsd/nfsfh.c Fri Feb 9 11:29:44 2001 +++ linux/fs/nfsd/nfsfh.c Mon Apr 30 17:12:51 2001 @@ -156,6 +156,7 @@ result = list_entry(lp,struct dentry, d_alias); if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { dget_locked(result); + result->d_vfs_flags |= DCACHE_REFERENCED; spin_unlock(&dcache_lock); iput(inode); return result; diff -u --recursive --new-file v2.4.4/linux/fs/nls/nls_koi8-u.c linux/fs/nls/nls_koi8-u.c --- v2.4.4/linux/fs/nls/nls_koi8-u.c Fri Apr 6 10:51:19 2001 +++ linux/fs/nls/nls_koi8-u.c Wed May 2 15:07:57 2001 @@ -146,9 +146,9 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ + 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ }; static unsigned char page22[256] = { diff -u --recursive --new-file v2.4.4/linux/fs/proc/Makefile linux/fs/proc/Makefile --- v2.4.4/linux/fs/proc/Makefile Fri Dec 29 14:07:23 2000 +++ linux/fs/proc/Makefile Tue May 8 16:41:32 2001 @@ -9,10 +9,10 @@ O_TARGET := proc.o -export-objs := procfs_syms.o +export-objs := root.o obj-y := inode.o root.o base.o generic.o array.o \ - kmsg.o proc_tty.o proc_misc.o kcore.o procfs_syms.o + kmsg.o proc_tty.o proc_misc.o kcore.o ifeq ($(CONFIG_PROC_DEVICETREE),y) obj-y += proc_devtree.o diff -u --recursive --new-file v2.4.4/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.4.4/linux/fs/proc/array.c Fri Apr 6 10:51:19 2001 +++ linux/fs/proc/array.c Fri May 4 14:44:06 2001 @@ -157,7 +157,7 @@ "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), - p->pid, p->p_opptr->pid, p->p_pptr->pid != p->p_opptr->pid ? p->p_pptr->pid : 0, + p->pid, p->pid ? p->p_opptr->pid : 0, 0, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); read_unlock(&tasklist_lock); @@ -339,7 +339,7 @@ nice = task->nice; read_lock(&tasklist_lock); - ppid = task->p_opptr->pid; + ppid = task->pid ? task->p_opptr->pid : 0; read_unlock(&tasklist_lock); res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ diff -u --recursive --new-file v2.4.4/linux/fs/proc/base.c linux/fs/proc/base.c --- v2.4.4/linux/fs/proc/base.c Mon Mar 19 12:34:55 2001 +++ linux/fs/proc/base.c Fri May 4 14:44:06 2001 @@ -586,7 +586,7 @@ struct pid_entry *p; pid = inode->u.proc_i.task->pid; - if (!inode->u.proc_i.task->p_pptr) + if (!pid) return -ENOENT; i = filp->f_pos; switch (i) { @@ -641,7 +641,7 @@ */ inode->u.proc_i.task = task; get_task_struct(task); - if (!task->p_pptr) + if (!task->pid) goto out_unlock; inode->i_uid = 0; @@ -673,7 +673,7 @@ */ static int pid_base_revalidate(struct dentry * dentry, int flags) { - if (dentry->d_inode->u.proc_i.task->p_pptr) + if (dentry->d_inode->u.proc_i.task->pid) return 1; d_drop(dentry); return 0; diff -u --recursive --new-file v2.4.4/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c --- v2.4.4/linux/fs/proc/procfs_syms.c Mon Sep 11 08:41:07 2000 +++ linux/fs/proc/procfs_syms.c Wed Dec 31 16:00:00 1969 @@ -1,46 +0,0 @@ -#include -#include -#include -#include -#include - -extern struct proc_dir_entry *proc_sys_root; - -#ifdef CONFIG_SYSCTL -EXPORT_SYMBOL(proc_sys_root); -#endif -EXPORT_SYMBOL(proc_symlink); -EXPORT_SYMBOL(proc_mknod); -EXPORT_SYMBOL(proc_mkdir); -EXPORT_SYMBOL(create_proc_entry); -EXPORT_SYMBOL(remove_proc_entry); -EXPORT_SYMBOL(proc_root); -EXPORT_SYMBOL(proc_root_fs); -EXPORT_SYMBOL(proc_net); -EXPORT_SYMBOL(proc_bus); -EXPORT_SYMBOL(proc_root_driver); - -static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE); - -static int __init init_proc_fs(void) -{ - int err = register_filesystem(&proc_fs_type); - if (!err) { - proc_mnt = kern_mount(&proc_fs_type); - err = PTR_ERR(proc_mnt); - if (IS_ERR(proc_mnt)) - unregister_filesystem(&proc_fs_type); - else - err = 0; - } - return err; -} - -static void __exit exit_proc_fs(void) -{ - unregister_filesystem(&proc_fs_type); - kern_umount(proc_mnt); -} - -module_init(init_proc_fs) -module_exit(exit_proc_fs) diff -u --recursive --new-file v2.4.4/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.4.4/linux/fs/proc/root.c Thu Nov 23 09:07:36 2000 +++ linux/fs/proc/root.c Tue May 8 16:41:32 2001 @@ -14,6 +14,7 @@ #include #include #include +#include #include struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; @@ -22,8 +23,19 @@ struct proc_dir_entry *proc_sys_root; #endif +static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE); + void __init proc_root_init(void) { + int err = register_filesystem(&proc_fs_type); + if (err) + return; + proc_mnt = kern_mount(&proc_fs_type); + err = PTR_ERR(proc_mnt); + if (IS_ERR(proc_mnt)) { + unregister_filesystem(&proc_fs_type); + return; + } proc_misc_init(); proc_net = proc_mkdir("net", 0); #ifdef CONFIG_SYSVIPC @@ -106,3 +118,17 @@ proc_fops: &proc_root_operations, parent: &proc_root, }; + +#ifdef CONFIG_SYSCTL +EXPORT_SYMBOL(proc_sys_root); +#endif +EXPORT_SYMBOL(proc_symlink); +EXPORT_SYMBOL(proc_mknod); +EXPORT_SYMBOL(proc_mkdir); +EXPORT_SYMBOL(create_proc_entry); +EXPORT_SYMBOL(remove_proc_entry); +EXPORT_SYMBOL(proc_root); +EXPORT_SYMBOL(proc_root_fs); +EXPORT_SYMBOL(proc_net); +EXPORT_SYMBOL(proc_bus); +EXPORT_SYMBOL(proc_root_driver); diff -u --recursive --new-file v2.4.4/linux/fs/super.c linux/fs/super.c --- v2.4.4/linux/fs/super.c Fri Apr 27 14:11:31 2001 +++ linux/fs/super.c Sat Apr 28 11:30:08 2001 @@ -1288,12 +1288,18 @@ } /* - * Flags is a 32-bit value that allows up to 32 non-fs dependent flags to + * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). + * + * Pre-0.97 versions of mount() didn't have a flags word. + * When the flags word was introduced its top half was required + * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9. + * Therefore, if this magic number is present, it carries no information + * and must be discarded. */ long do_mount(char * dev_name, char * dir_name, char *type_page, unsigned long flags, void *data_page) @@ -1303,6 +1309,10 @@ struct vfsmount *mnt = NULL; struct super_block *sb; int retval = 0; + + /* Discard magic */ + if ((flags & MS_MGC_MSK) == MS_MGC_VAL) + flags &= ~MS_MGC_MSK; /* Basic sanity checks */ diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/axisflashmap.h linux/include/asm-cris/axisflashmap.h --- v2.4.4/linux/include/asm-cris/axisflashmap.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/axisflashmap.h Tue May 1 16:05:00 2001 @@ -15,7 +15,7 @@ * tools/mkptable is used to generate the ptable. */ -/* The partition table start with kod to "jump over" it: */ +/* The partition table starts with code to "jump over" it: */ #define PARTITIONTABLE_CODE_START { \ 0x0f, 0x05, /* nop 0 */\ 0x25, 0xf0, /* di 2 */\ @@ -24,7 +24,7 @@ /* The actual offset depend on the number of entries */ #define PARTITIONTABLE_CODE_END { \ 0x00, 0x00, /* ba offset 6 */\ - 0x0f, 0x0f /* nop 8 */} + 0x0f, 0x05 /* nop 8 */} #define PARTITION_TABLE_OFFSET 10 #define PARTITION_TABLE_MAGIC 0xbeef /* Not a good magic */ diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/elf.h linux/include/asm-cris/elf.h --- v2.4.4/linux/include/asm-cris/elf.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/elf.h Tue May 1 16:05:00 2001 @@ -36,7 +36,14 @@ that have been loaded before the code runs. A value of 0 tells we have no such handler. */ -#define ELF_PLAT_INIT(_r) ((_r)->r10 = 0) + + /* Explicitly set registers to 0 to increase determinism. */ +#define ELF_PLAT_INIT(_r) do { \ + (_r)->r13 = 0; (_r)->r12 = 0; (_r)->r11 = 0; (_r)->r10 = 0; \ + (_r)->r9 = 0; (_r)->r8 = 0; (_r)->r7 = 0; (_r)->r6 = 0; \ + (_r)->r5 = 0; (_r)->r4 = 0; (_r)->r3 = 0; (_r)->r2 = 0; \ + (_r)->r1 = 0; (_r)->r0 = 0; (_r)->mof = 0; (_r)->srp = 0; \ +} while (0) #undef USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 8192 diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/etraxgpio.h linux/include/asm-cris/etraxgpio.h --- v2.4.4/linux/include/asm-cris/etraxgpio.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/etraxgpio.h Tue May 1 16:05:00 2001 @@ -28,5 +28,7 @@ #define IO_SETOUTPUT 0xA /* Set direction 0=unchanged 1=output, returns current dir */ +/* LED ioctl extended */ +#define IO_LED_SETBIT 0xB +#define IO_LED_CLRBIT 0xC #endif - diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/io.h linux/include/asm-cris/io.h --- v2.4.4/linux/include/asm-cris/io.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/io.h Tue May 1 16:05:00 2001 @@ -9,9 +9,9 @@ use will be evident. */ #ifdef CONFIG_SVINTO_SIM /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) asm ("moveq 4,r9\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\ +#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\ \n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \ - : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") + : : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory") #define TRACE_ON() __extension__ \ ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ (255)); _Foofoo; }) @@ -36,7 +36,14 @@ extern unsigned char port_pb_dir_shadow; extern unsigned char port_pb_data_shadow; extern unsigned long r_timer_ctrl_shadow; -extern unsigned long port_90000000_shadow; + +extern unsigned long port_cse1_shadow; +extern unsigned long port_csp0_shadow; +extern unsigned long port_csp4_shadow; + +extern volatile unsigned long *port_cse1_addr; +extern volatile unsigned long *port_csp0_addr; +extern volatile unsigned long *port_csp4_addr; /* macro for setting regs through a shadow - * r = register name (like R_PORT_PA_DATA) @@ -45,74 +52,104 @@ * v = value (0 or 1) */ -#define REG_SHADOW_SET(r,s,b,v) *r = s = (s & ~(1 << b)) | ((v) << b) +#define REG_SHADOW_SET(r,s,b,v) *r = s = (s & ~(1 << (b))) | ((v) << (b)) /* The LED's on various Etrax-based products are set differently. */ #if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM) #undef CONFIG_ETRAX_PA_LEDS #undef CONFIG_ETRAX_PB_LEDS -#undef CONFIG_ETRAX_90000000_LEDS -#define LED_NETWORK_RX_SET(x) -#define LED_NETWORK_TX_SET(x) -#define LED_ACTIVE_SET(x) +#undef CONFIG_ETRAX_CSP0_LEDS +#define LED_NETWORK_SET_G(x) +#define LED_NETWORK_SET_R(x) #define LED_ACTIVE_SET_G(x) #define LED_ACTIVE_SET_R(x) #define LED_DISK_WRITE(x) #define LED_DISK_READ(x) #endif +#if !defined(CONFIG_ETRAX_CSP0_LEDS) +#define LED_BIT_SET(x) +#define LED_BIT_CLR(x) +#endif + +#define LED_OFF 0x00 +#define LED_GREEN 0x01 +#define LED_RED 0x02 +#define LED_ORANGE (LED_GREEN | LED_RED) + +#if CONFIG_ETRAX_LED1G == CONFIG_ETRAX_LED1R +#define LED_NETWORK_SET(x) \ + do { \ + LED_NETWORK_SET_G((x) & LED_GREEN); \ + } while (0) +#else +#define LED_NETWORK_SET(x) \ + do { \ + LED_NETWORK_SET_G((x) & LED_GREEN); \ + LED_NETWORK_SET_R((x) & LED_RED); \ + } while (0) +#endif +#if CONFIG_ETRAX_LED2G == CONFIG_ETRAX_LED2R +#define LED_ACTIVE_SET(x) \ + do { \ + LED_ACTIVE_SET_G((x) & LED_GREEN); \ + } while (0) +#else +#define LED_ACTIVE_SET(x) \ + do { \ + LED_ACTIVE_SET_G((x) & LED_GREEN); \ + LED_ACTIVE_SET_R((x) & LED_RED); \ + } while (0) +#endif + #ifdef CONFIG_ETRAX_PA_LEDS -#define LED_NETWORK_RX_SET(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1G, !x) -#define LED_NETWORK_TX_SET(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1R, !x) -#define LED_ACTIVE_SET(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !x) +#define LED_NETWORK_SET_G(x) \ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1G, !(x)) +#define LED_NETWORK_SET_R(x) \ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1R, !(x)) #define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !x) + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !(x)) #define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !x) + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x)) #define LED_DISK_WRITE(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !x) + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x)) #define LED_DISK_READ(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !x) + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) #endif #ifdef CONFIG_ETRAX_PB_LEDS -#define LED_NETWORK_RX_SET(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1G, !x) -#define LED_NETWORK_TX_SET(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1R, !x) -#define LED_ACTIVE_SET(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !x) +#define LED_NETWORK_SET_G(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1G, !(x)) +#define LED_NETWORK_SET_R(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1R, !(x)) #define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !x) + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !(x)) #define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !x) + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x)) #define LED_DISK_WRITE(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !x) + REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x)) #define LED_DISK_READ(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !x) + REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) #endif -#ifdef CONFIG_ETRAX_90000000_LEDS -/* TODO: this won't work, need a vremap into kernel virtual memory of 90000000 */ -#define LED_PORT_90 (volatile unsigned long*)0x90000000 -#define LED_ACTIVE_SET(x) \ - REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED2G, !x) -#define LED_NETWORK_RX_SET(x) \ - REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED1G, !x) -#define LED_NETWORK_TX_SET(x) \ - REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED1R, !x) +#ifdef CONFIG_ETRAX_CSP0_LEDS +#define LED_NETWORK_SET_G(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1G, !(x)) +#define LED_NETWORK_SET_R(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1R, !(x)) #define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED2G, !x) + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2G, !(x)) #define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED2R, !x) + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x)) #define LED_DISK_WRITE(x) \ - REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED3R, !x) + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x)) #define LED_DISK_READ(x) \ - REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED3G, !x) + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x)) +#define LED_BIT_SET(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1) +#define LED_BIT_CLR(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0) #endif /* diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h --- v2.4.4/linux/include/asm-cris/irq.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/irq.h Tue May 1 16:05:00 2001 @@ -45,7 +45,7 @@ /* SAVE_ALL saves registers so they match pt_regs */ #define SAVE_ALL \ - "push irp\n\t" /* push instruction pointer */ \ + "move irp,[sp=sp-16]\n\t" /* push instruction pointer and fake SBFS struct */ \ "push srp\n\t" /* push subroutine return pointer */ \ "push dccr\n\t" /* push condition codes */ \ "push mof\n\t" /* push multiply overflow reg */ \ @@ -94,7 +94,9 @@ "_bad_IRQ" #nr "_interrupt:\n\t" \ "push r0\n\t" \ BLOCK_IRQ(mask,nr) \ - "pop r0\n\t"); + "pop r0\n\t" \ + "reti\n\t" \ + "nop\n"); #endif /* _ASM_IRQ_H */ diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/pgalloc.h linux/include/asm-cris/pgalloc.h --- v2.4.4/linux/include/asm-cris/pgalloc.h Mon Apr 23 15:28:07 2001 +++ linux/include/asm-cris/pgalloc.h Tue May 1 16:05:00 2001 @@ -1,24 +1,25 @@ #ifndef _CRIS_PGALLOC_H #define _CRIS_PGALLOC_H -#include #include #include -/* bunch of protos */ +extern struct pgtable_cache_struct { + unsigned long *pgd_cache; + unsigned long *pte_cache; + unsigned long pgtable_cache_sz; +} quicklists; -extern pgd_t *get_pgd_slow(void); -extern void free_pgd_slow(pgd_t *pgd); -extern __inline__ void free_pmd_slow(pmd_t *pmd) { } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); +#define pgd_quicklist (quicklists.pgd_cache) +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist (quicklists.pte_cache) +#define pgtable_cache_size (quicklists.pgtable_cache_sz) -/* first the non-cached versions */ +#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte) -extern __inline__ void free_pte_slow(pte_t *pte) -{ - free_page((unsigned long)pte); -} +/* + * Allocate and free page tables. + */ extern __inline__ pgd_t *get_pgd_slow(void) { @@ -37,27 +38,6 @@ free_page((unsigned long)pgd); } -/* - * Now for the page table cache versions - */ - -#ifndef CONFIG_NO_PGT_CACHE - -#ifdef CONFIG_SMP -#error Pgtable caches have to be per-CPU, so that no locking is needed. -#endif /* CONFIG_SMP */ - -extern struct pgtable_cache_struct { - unsigned long *pgd_cache; - unsigned long *pte_cache; - unsigned long pgtable_cache_sz; -} quicklists; - -#define pgd_quicklist (quicklists.pgd_cache) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist (quicklists.pte_cache) -#define pgtable_cache_size (quicklists.pgtable_cache_sz) - extern __inline__ pgd_t *get_pgd_fast(void) { unsigned long *ret; @@ -78,16 +58,17 @@ pgtable_cache_size++; } -/* We don't use pmd cache, so this is a dummy routine */ - -extern __inline__ pmd_t *get_pmd_fast(void) +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) { - return (pmd_t *)0; -} + pte_t *pte; -extern __inline__ void free_pmd_fast(pmd_t *pmd) { } + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} -extern __inline__ pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; @@ -99,99 +80,33 @@ return (pte_t *)ret; } -extern __inline__ void free_pte_fast(pte_t *pte) +static __inline__ void pte_free_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -#else /* CONFIG_NO_PGT_CACHE */ - -#define pgd_quicklist ((unsigned long *)0) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist ((unsigned long *)0) - -#define get_pgd_fast() ((pgd_t *)0) -#define get_pmd_fast() ((pmd_t *)0) -#define get_pte_fast() ((pte_t *)0) - -#define free_pgd_fast(pgd) free_pgd_slow(pgd) -#define free_pmd_fast(pmd) free_pmd_slow(pmd) -#define free_pte_fast(pte) free_pte_slow(pte) - -#endif /* CONFIG_NO_PGT_CACHE */ - -/* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. - */ - -#define pte_free_kernel(pte) free_pte_slow(pte) -#define pte_free(pte) free_pte_slow(pte) - -extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) +static __inline__ void pte_free_slow(pte_t *pte) { - if (!pmd) - BUG(); - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t * page = (pte_t *) get_pte_fast(); - if (!page) - return get_pte_kernel_slow(pmd, address); - pmd_set_kernel(pmd, page); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; + free_page((unsigned long)pte); } -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - - if (pmd_none(*pmd)) - goto getnew; - if (pmd_bad(*pmd)) - goto fix; - return (pte_t *)pmd_page(*pmd) + address; - getnew: - { - pte_t * page = (pte_t *) get_pte_fast(); - if (!page) - return get_pte_slow(pmd, address); - pmd_set(pmd, page); - return page + address; - } - fix: - __handle_bad_pmd(pmd); - return NULL; -} +#define pte_free(pte) pte_free_slow(pte) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc(mm) get_pgd_fast() /* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. + * We don't have any real pmd's, and this code never triggers because + * the pgd will always be present.. */ -#define pmd_free(pmd) free_pmd_slow(pmd) -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc - -extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - if (!pgd) - BUG(); - return (pmd_t *) pgd; -} - -/* pgd handling */ - -#define pgd_free(pgd) free_pgd_slow(pgd) -#define pgd_alloc(mm) get_pgd_fast() +#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free_slow(x) do { } while (0) +#define pmd_free_fast(x) do { } while (0) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() /* other stuff */ diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/pgtable.h linux/include/asm-cris/pgtable.h --- v2.4.4/linux/include/asm-cris/pgtable.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/pgtable.h Tue May 1 16:05:00 2001 @@ -3,6 +3,12 @@ * HISTORY: * * $Log: pgtable.h,v $ + * Revision 1.11 2001/04/04 14:38:36 bjornw + * Removed bad_pagetable handling and the _kernel functions + * + * Revision 1.10 2001/03/23 07:46:42 starvik + * Corrected according to review remarks + * * Revision 1.9 2000/11/22 14:57:53 bjornw * * extern inline -> static inline * * include asm-generic/pgtable.h @@ -97,7 +103,9 @@ * the CRIS page table tree. */ -/* The cache doesn't need to be flushed when TLB entries change (I think!) */ +/* The cache doesn't need to be flushed when TLB entries change because + * the cache is mapped to physical memory, not virtual memory + */ #define flush_cache_all() do { } while (0) #define flush_cache_mm(mm) do { } while (0) #define flush_cache_range(mm, start, end) do { } while (0) @@ -244,27 +252,8 @@ /* zero page used for uninitialized stuff */ extern unsigned long empty_zero_page; - -/* - * BAD_PAGETABLE is used when we need a bogus page-table, while - * BAD_PAGE is used for a bogus page. - * - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern pte_t __bad_page(void); -extern pte_t * __bad_pagetable(void); - -#define BAD_PAGETABLE __bad_pagetable() -#define BAD_PAGE __bad_page() #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) -/* - * Handling allocation failures during page table setup. - */ -extern void __handle_bad_pmd(pmd_t * pmd); -extern void __handle_bad_pmd_kernel(pmd_t * pmd); - /* number of bits that fit into a memory pointer */ #define BITS_PER_PTR (8*sizeof(unsigned long)) @@ -452,9 +441,6 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep) { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; } - -static inline void pmd_set_kernel(pmd_t * pmdp, pte_t * ptep) -{ pmd_val(*pmdp) = _KERNPG_TABLE | (unsigned long) ptep; } /* to find an entry in a page-table-directory. */ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/processor.h linux/include/asm-cris/processor.h --- v2.4.4/linux/include/asm-cris/processor.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/processor.h Tue May 1 16:05:00 2001 @@ -18,7 +18,7 @@ * Default implementation of macro that returns current * instruction pointer ("program counter"). */ -#define current_text_addr() ({ __label__ _l; _l: &&_l;}) +#define current_text_addr() ({void *pc; __asm__ ("move.d pc,%0" : "=rm" (pc)); pc; }) /* CRIS has no problems with write protection */ @@ -40,6 +40,14 @@ */ #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) +/* THREAD_SIZE is the size of the task_struct/kernel_stack combo. + * normally, the stack is found by doing something like p + THREAD_SIZE + * in CRIS, a page is 8192 bytes, which seems like a sane size + */ + +#define THREAD_SIZE PAGE_SIZE +#define KERNEL_STACK_SIZE PAGE_SIZE + /* CRIS thread_struct. this really has nothing to do with the processor itself, since * CRIS does not do any hardware task-switching, but it's here for legacy reasons. * The thread_struct here is used when task-switching using _resume defined in entry.S. @@ -50,13 +58,24 @@ struct thread_struct { unsigned long ksp; /* kernel stack pointer */ unsigned long usp; /* user stack pointer */ - unsigned long esp0; /* points to start of saved stack frame, set in entry.S */ unsigned long dccr; /* saved flag register */ }; -/* saved stack-frame upon syscall entry, points to registers */ +/* + * At user->kernel entry, the pt_regs struct is stacked on the top of the kernel-stack. + * This macro allows us to find those regs for a task. + * Notice that subsequent pt_regs stackings, like recursive interrupts occuring while + * we're in the kernel, won't affect this - only the first user->kernel transition + * registers are reached by this. + */ -#define current_regs() (current->thread.esp0) +#define user_regs(task) (((struct pt_regs *)((unsigned long)(task) + THREAD_SIZE)) - 1) + +/* + * Dito but for the currently running task + */ + +#define current_regs() user_regs(current) /* INIT_MMAP is the kernels map of memory, between KSEG_C and KSEG_D */ @@ -69,11 +88,7 @@ #endif #define INIT_THREAD { \ - 0, 0, 0, 0x20 } /* ccr = int enable, nothing else */ - -/* TODO: REMOVE */ -#define alloc_kernel_stack() __get_free_page(GFP_KERNEL) -#define free_kernel_stack(page) free_page((page)) + 0, 0, 0x20 } /* ccr = int enable, nothing else */ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); @@ -94,9 +109,10 @@ #define KSTK_EIP(tsk) \ ({ \ unsigned long eip = 0; \ - if ((tsk)->thread.esp0 > PAGE_SIZE && \ - VALID_PAGE(virt_to_page((tsk)->thread.esp0))) \ - eip = ((struct pt_regs *) (tsk)->thread.esp0)->irp; \ + unsigned long regs = (unsigned long)user_regs(tsk); \ + if (regs > PAGE_SIZE && \ + VALID_PAGE(virt_to_page(regs))) \ + eip = ((struct pt_regs *)regs)->irp; \ eip; }) #define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) @@ -111,11 +127,13 @@ static inline void exit_thread(void) { + /* Nothing needs to be done. */ } /* Free all resources held by a thread. */ static inline void release_thread(struct task_struct *dead_task) { + /* Nothing needs to be done. */ } /* @@ -123,16 +141,8 @@ */ extern inline unsigned long thread_saved_pc(struct thread_struct *t) { - return (unsigned long)((struct pt_regs *)t->esp0)->irp; + return (unsigned long)user_regs(t)->irp; } - -/* THREAD_SIZE is the size of the task_struct/kernel_stack combo. - * normally, the stack is found by doing something like p + THREAD_SIZE - * in CRIS, a page is 8192 bytes, which seems like a sane size - */ - -#define THREAD_SIZE PAGE_SIZE -#define KERNEL_STACK_SIZE PAGE_SIZE #define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) #define free_task_struct(p) free_pages((unsigned long) (p), 1) diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/ptrace.h linux/include/asm-cris/ptrace.h --- v2.4.4/linux/include/asm-cris/ptrace.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/ptrace.h Tue May 1 16:05:00 2001 @@ -23,14 +23,16 @@ #define PT_DCCR 17 #define PT_SRP 18 #define PT_IRP 19 -#define PT_USP 20 /* special case - USP is not in the pt_regs */ -#define PT_MAX 20 +#define PT_CSRINSTR 20 /* CPU Status record remnants - valid if frametype == busfault */ +#define PT_CSRADDR 21 +#define PT_CSRDATA 22 +#define PT_USP 23 /* special case - USP is not in the pt_regs */ +#define PT_MAX 23 /* Frame types */ -#define CRIS_FRAME_NORMAL 0 /* normal frame like pt_regs struct */ -#define CRIS_FRAME_BUSFAULT 1 /* SBFS frame of 4 longwords on top, including irp */ -#define CRIS_FRAME_FIXUP 2 /* SBFS frame which should do a normal return, not RBF */ +#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ +#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return path */ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ #define PTRACE_GETREGS 12 @@ -63,6 +65,9 @@ unsigned long dccr; unsigned long srp; unsigned long irp; + unsigned long csrinstr; + unsigned long csraddr; + unsigned long csrdata; }; /* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) when diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/rtc.h linux/include/asm-cris/rtc.h --- v2.4.4/linux/include/asm-cris/rtc.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/rtc.h Tue May 1 16:05:00 2001 @@ -1,4 +1,4 @@ -/* $Id: rtc.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ +/* $Id: rtc.h,v 1.3 2001/03/21 09:56:31 magnusmn Exp $ */ #ifndef RTC_H #define RTC_H @@ -14,8 +14,21 @@ #define RTC_MONTH 4 #define RTC_WEEKDAY 5 #define RTC_YEAR 6 +#define RTC_CONTROL 7 -#ifdef CONFIG_DS1302 +/* Bits in CONTROL register */ +#define RTC_CONTROL_WRITEPROTECT 0x80 +#define RTC_TRICKLECHARGER 8 +/* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS */ +#define RTC_TCR_PATTERN 0xA0 /* 1010xxxx */ +#define RTC_TCR_1DIOD 0x04 /* xxxx01xx */ +#define RTC_TCR_2DIOD 0x08 /* xxxx10xx */ +#define RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */ +#define RTC_TCR_2KOHM 0x01 /* xxxxxx01 2KOhm */ +#define RTC_TCR_4KOHM 0x02 /* xxxxxx10 4kOhm */ +#define RTC_TCR_8KOHM 0x03 /* xxxxxx11 8kOhm */ + +#ifdef CONFIG_ETRAX_DS1302 #define CMOS_READ(x) ds1302_readreg(x) #define CMOS_WRITE(val,reg) ds1302_writereg(reg,val) #define RTC_INIT() ds1302_init() @@ -55,5 +68,8 @@ #define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */ #define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ +#define RTC_SET_CHARGE _IOW('p', 0x0b, int) /* Set CHARGE mode */ #endif + + diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/segment.h linux/include/asm-cris/segment.h --- v2.4.4/linux/include/asm-cris/segment.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/segment.h Tue May 1 16:05:00 2001 @@ -1,14 +1,6 @@ #ifndef _ASM_SEGMENT_H #define _ASM_SEGMENT_H -/* argh. really legacy. totally misnomed. */ - -#define __KERNEL_CS 0x10 -#define __KERNEL_DS 0x18 - -#define __USER_CS 0x23 -#define __USER_DS 0x2B - typedef struct { unsigned long seg; } mm_segment_t; diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/semaphore-helper.h linux/include/asm-cris/semaphore-helper.h --- v2.4.4/linux/include/asm-cris/semaphore-helper.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/semaphore-helper.h Tue May 1 16:05:00 2001 @@ -1,4 +1,4 @@ -/* $Id: semaphore-helper.h,v 1.1 2000/07/13 16:52:42 bjornw Exp $ +/* $Id: semaphore-helper.h,v 1.3 2001/03/26 15:00:33 orjanf Exp $ * * SMP- and interrupt-safe semaphores helper functions. Generic versions, no * optimizations whatsoever... @@ -10,6 +10,12 @@ #include +#define read(a) ((a)->counter) +#define inc(a) (((a)->counter)++) +#define dec(a) (((a)->counter)--) + +#define count_inc(a) ((*(a))++) + /* * These two _must_ execute atomically wrt each other. */ @@ -17,12 +23,6 @@ { atomic_inc(&sem->waking); } - -#define read(a) ((a)->counter) -#define inc(a) (((a)->counter)++) -#define dec(a) (((a)->counter)--) - -#define count_inc(a) ((*(a))++) static inline int waking_non_zero(struct semaphore *sem) { diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/stat.h linux/include/asm-cris/stat.h --- v2.4.4/linux/include/asm-cris/stat.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/stat.h Tue May 1 16:05:00 2001 @@ -1,7 +1,8 @@ #ifndef _CRIS_STAT_H #define _CRIS_STAT_H -/* verbatim copy of i386 version */ +/* Keep this a verbatim copy of i386 version; tweak CRIS-specific bits in + the kernel if necessary. */ struct __old_kernel_stat { unsigned short st_dev; @@ -47,7 +48,9 @@ unsigned short st_dev; unsigned char __pad0[10]; - unsigned long st_ino; +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; + unsigned int st_mode; unsigned int st_nlink; @@ -72,8 +75,7 @@ unsigned long st_ctime; unsigned long __pad7; /* will be high 32 bits of ctime someday */ - unsigned long __unused1; - unsigned long __unused2; + unsigned long long st_ino; }; #endif diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/system.h linux/include/asm-cris/system.h --- v2.4.4/linux/include/asm-cris/system.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/system.h Tue May 1 16:05:00 2001 @@ -1,14 +1,11 @@ -/* $Id: system.h,v 1.3 2000/10/17 14:56:27 bjornw Exp $ */ +/* $Id: system.h,v 1.4 2001/03/20 19:46:00 bjornw Exp $ */ #ifndef __ASM_CRIS_SYSTEM_H #define __ASM_CRIS_SYSTEM_H -#include - -/* I need a task-specific debug struct (and the define for #ifdef - RELOC_DEBUG) to kludge into task_struct. */ #include -#include + +#include /* the switch_to macro calls resume, an asm function in entry.S which does the actual * task switching. diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/timex.h linux/include/asm-cris/timex.h --- v2.4.4/linux/include/asm-cris/timex.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/timex.h Tue May 1 16:05:00 2001 @@ -6,7 +6,7 @@ #ifndef _ASM_CRIS_TIMEX_H #define _ASM_CRIS_TIMEX_H -#define CLOCK_TICK_RATE 9600 /* Underlying frequency of the HZ timer */ +#define CLOCK_TICK_RATE 19200 /* Underlying frequency of the HZ timer */ /* * We don't have a cycle-counter.. but we do not support SMP anyway where this is diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/unistd.h linux/include/asm-cris/unistd.h --- v2.4.4/linux/include/asm-cris/unistd.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/unistd.h Tue May 1 16:05:00 2001 @@ -57,7 +57,7 @@ #define __NR_geteuid 49 #define __NR_getegid 50 #define __NR_acct 51 -#define __NR_phys 52 +#define __NR_umount2 52 #define __NR_lock 53 #define __NR_ioctl 54 #define __NR_fcntl 55 diff -u --recursive --new-file v2.4.4/linux/include/asm-i386/mtrr.h linux/include/asm-i386/mtrr.h --- v2.4.4/linux/include/asm-i386/mtrr.h Fri Apr 27 15:48:21 2001 +++ linux/include/asm-i386/mtrr.h Tue May 15 00:33:16 2001 @@ -88,6 +88,7 @@ unsigned int type, char increment); extern int mtrr_del (int reg, unsigned long base, unsigned long size); extern int mtrr_del_page (int reg, unsigned long base, unsigned long size); +extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); # else static __inline__ int mtrr_add (unsigned long base, unsigned long size, unsigned int type, char increment) @@ -109,6 +110,9 @@ { return -ENODEV; } + +static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;} + # endif /* The following functions are for initialisation: don't use them! */ diff -u --recursive --new-file v2.4.4/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h --- v2.4.4/linux/include/asm-i386/pci.h Fri Apr 27 15:49:20 2001 +++ linux/include/asm-i386/pci.h Tue May 15 00:34:09 2001 @@ -9,8 +9,9 @@ #define pcibios_assign_all_busses() 0 +extern unsigned long pci_mem_start; #define PCIBIOS_MIN_IO 0x1000 -#define PCIBIOS_MIN_MEM 0x10000000 +#define PCIBIOS_MIN_MEM (pci_mem_start) void pcibios_set_master(struct pci_dev *dev); void pcibios_penalize_isa_irq(int irq); diff -u --recursive --new-file v2.4.4/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.4.4/linux/include/asm-i386/system.h Fri Apr 27 15:48:21 2001 +++ linux/include/asm-i386/system.h Tue May 15 00:33:16 2001 @@ -288,7 +288,7 @@ /* interrupt control.. */ #define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) -#define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") +#define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") #define __cli() __asm__ __volatile__("cli": : :"memory") #define __sti() __asm__ __volatile__("sti": : :"memory") /* used in the idle loop; sti takes one instruction cycle to complete */ diff -u --recursive --new-file v2.4.4/linux/include/linux/cciss_ioctl.h linux/include/linux/cciss_ioctl.h --- v2.4.4/linux/include/linux/cciss_ioctl.h Mon Dec 11 12:50:40 2000 +++ linux/include/linux/cciss_ioctl.h Tue May 1 16:05:00 2001 @@ -80,25 +80,28 @@ #define CISS_MAX_LUN 16 +#define LEVEL2LUN 1 // index into Target(x) structure, due to byte swapping +#define LEVEL3LUN 0 + #pragma pack(1) //Command List Structure typedef union _SCSI3Addr_struct { struct { + BYTE Dev; BYTE Bus:6; BYTE Mode:2; // b00 - BYTE Dev; } PeripDev; struct { + BYTE DevLSB; BYTE DevMSB:6; BYTE Mode:2; // b01 - BYTE DevLSB; } LogDev; struct { - BYTE Targ:6; - BYTE Mode:2; // b10 BYTE Dev:5; BYTE Bus:3; + BYTE Targ:6; + BYTE Mode:2; // b10 } LogUnit; } SCSI3Addr_struct; diff -u --recursive --new-file v2.4.4/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.4/linux/include/linux/fs.h Fri Apr 27 15:48:28 2001 +++ linux/include/linux/fs.h Tue May 15 00:33:17 2001 @@ -121,6 +121,12 @@ #define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|\ MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME) +/* + * Old magic mount flag and mask + */ +#define MS_MGC_VAL 0xC0ED0000 +#define MS_MGC_MSK 0xffff0000 + /* Inode flags - they have nothing to superblock flags now */ #define S_SYNC 1 /* Writes are synced at once */ @@ -1086,6 +1092,7 @@ extern void balance_dirty(kdev_t); extern int check_disk_change(kdev_t); extern int invalidate_inodes(struct super_block *); +extern int invalidate_device(kdev_t, int); extern void invalidate_inode_pages(struct inode *); extern void invalidate_inode_buffers(struct inode *); #define invalidate_buffers(dev) __invalidate_buffers((dev), 0) diff -u --recursive --new-file v2.4.4/linux/include/linux/i2o.h linux/include/linux/i2o.h --- v2.4.4/linux/include/linux/i2o.h Mon Dec 11 13:20:00 2000 +++ linux/include/linux/i2o.h Tue May 1 16:17:18 2001 @@ -69,6 +69,7 @@ struct i2o_controller *controller; /* Controlling IOP */ struct i2o_device *next; /* Chain */ + struct i2o_device *prev; char dev_name[8]; /* linux /dev name if available */ }; @@ -78,6 +79,9 @@ struct i2o_pci { int irq; + int queue_buggy:1; /* Don't send a lot of messages */ + int short_req:1; /* Use small block sizes */ + int dpt:1; /* Don't quiesce */ #ifdef CONFIG_MTRR int mtrr_reg0; int mtrr_reg1; @@ -120,6 +124,8 @@ u32 mem_offset; /* MFA offset */ u32 mem_phys; /* MFA physical */ + + int battery:1; /* Has a battery backup */ struct proc_dir_entry* proc_entry; /* /proc dir */ @@ -295,6 +301,7 @@ extern int i2o_post_this(struct i2o_controller *, u32 *, int); extern int i2o_post_wait(struct i2o_controller *, u32 *, int, int); +extern int i2o_post_wait_mem(struct i2o_controller *, u32 *, int, int, void *, void *); extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *, int); extern int i2o_set_scalar(struct i2o_controller *, int, int, int, void *, int); diff -u --recursive --new-file v2.4.4/linux/include/linux/ide.h linux/include/linux/ide.h --- v2.4.4/linux/include/linux/ide.h Fri Apr 27 15:48:56 2001 +++ linux/include/linux/ide.h Tue May 15 00:34:38 2001 @@ -648,6 +648,7 @@ extern ide_module_t *ide_modules; extern ide_module_t *ide_probe; #endif +extern int noautodma; /* * We need blk.h, but we replace its end_request by our own version. diff -u --recursive --new-file v2.4.4/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h --- v2.4.4/linux/include/linux/iso_fs.h Fri Apr 27 15:48:20 2001 +++ linux/include/linux/iso_fs.h Tue May 15 00:33:22 2001 @@ -165,14 +165,46 @@ #define ISOFS_SUPER_MAGIC 0x9660 #ifdef __KERNEL__ -extern int isonum_711(char *); -extern int isonum_712(char *); -extern int isonum_721(char *); -extern int isonum_722(char *); -extern int isonum_723(char *); -extern int isonum_731(char *); -extern int isonum_732(char *); -extern int isonum_733(char *); +/* Number conversion inlines, named after the section in ISO 9660 + they correspond to. */ + +#include +#include + +static inline int isonum_711(char *p) +{ + return *(u8 *)p; +} +static inline int isonum_712(char *p) +{ + return *(s8 *)p; +} +static inline int isonum_721(char *p) +{ + return le16_to_cpu(get_unaligned((u16 *)p)); +} +static inline int isonum_722(char *p) +{ + return be16_to_cpu(get_unaligned((u16 *)p)); +} +static inline int isonum_723(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le16_to_cpu(get_unaligned((u16 *)p)); +} +static inline int isonum_731(char *p) +{ + return le32_to_cpu(get_unaligned((u32 *)p)); +} +static inline int isonum_732(char *p) +{ + return be32_to_cpu(get_unaligned((u32 *)p)); +} +static inline int isonum_733(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le32_to_cpu(get_unaligned((u32 *)p)); +} extern int iso_date(char *, int); extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); diff -u --recursive --new-file v2.4.4/linux/include/linux/nbd.h linux/include/linux/nbd.h --- v2.4.4/linux/include/linux/nbd.h Wed Apr 11 19:02:30 2001 +++ linux/include/linux/nbd.h Tue May 1 14:20:25 2001 @@ -2,6 +2,9 @@ * 1999 Copyright (C) Pavel Machek, pavel@ucw.cz. This code is GPL. * 1999/11/04 Copyright (C) 1999 VMware, Inc. (Regis "HPReg" Duchesne) * Made nbd_end_request() use the io_request_lock + * 2001 Copyright (C) Steven Whitehouse + * New nbd_end_request() for compatibility with new linux block + * layer code. */ #ifndef LINUX_NBD_H diff -u --recursive --new-file v2.4.4/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h --- v2.4.4/linux/include/linux/serial_reg.h Tue Mar 6 19:28:35 2001 +++ linux/include/linux/serial_reg.h Tue May 1 16:05:00 2001 @@ -260,8 +260,8 @@ #define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */ #define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */ #define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */ -#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occured (1) */ -#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occured */ +#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */ +#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */ #define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */ diff -u --recursive --new-file v2.4.4/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.4.4/linux/include/linux/skbuff.h Fri Apr 27 15:48:50 2001 +++ linux/include/linux/skbuff.h Tue May 15 00:33:28 2001 @@ -1069,7 +1069,7 @@ static inline int skb_cow(struct sk_buff *skb, unsigned int headroom) { - int delta = headroom - skb_headroom(skb); + int delta = (headroom > 16 ? headroom : 16) - skb_headroom(skb); if (delta < 0) delta = 0; diff -u --recursive --new-file v2.4.4/linux/include/linux/synclink.h linux/include/linux/synclink.h --- v2.4.4/linux/include/linux/synclink.h Tue Mar 6 19:44:37 2001 +++ linux/include/linux/synclink.h Tue May 1 16:05:00 2001 @@ -1,17 +1,17 @@ /* * SyncLink Multiprotocol Serial Adapter Driver * - * $Id: synclink.h,v 3.2 2000/11/06 22:34:38 paul Exp $ + * $Id: synclink.h,v 3.5 2001/03/26 17:04:36 ez Exp $ * * Copyright (C) 1998-2000 by Microgate Corporation * * Redistribution of this file is permitted under - * the terms of the GNU General Public License (GPL) + * the terms of the GNU Public License (GPL) */ #ifndef _SYNCLINK_H_ #define _SYNCLINK_H_ -#define SYNCLINK_H_VERSION 3.2 +#define SYNCLINK_H_VERSION 3.5 #define BOOLEAN int #define TRUE 1 @@ -84,6 +84,11 @@ #define HDLC_CRC_NONE 0 #define HDLC_CRC_16_CCITT 1 #define HDLC_CRC_32_CCITT 2 +#define HDLC_CRC_MASK 0x00ff +#define HDLC_CRC_RETURN_EX 0x8000 + +#define RX_OK 0 +#define RX_CRC_ERROR 1 #define HDLC_TXIDLE_FLAGS 0 #define HDLC_TXIDLE_ALT_ZEROS_ONES 1 @@ -117,6 +122,7 @@ #define MGSL_MODE_ASYNC 1 #define MGSL_MODE_HDLC 2 +#define MGSL_MODE_RAW 6 #define MGSL_BUS_TYPE_ISA 1 #define MGSL_BUS_TYPE_EISA 2 @@ -150,6 +156,8 @@ #define MICROGATE_VENDOR_ID 0x13c0 #define SYNCLINK_DEVICE_ID 0x0010 +#define MGSCC_DEVICE_ID 0x0020 +#define SYNCLINK_SCA_DEVICE_ID 0x0030 #define MGSL_MAX_SERIAL_NUMBER 30 /* diff -u --recursive --new-file v2.4.4/linux/include/linux/timer.h linux/include/linux/timer.h --- v2.4.4/linux/include/linux/timer.h Fri Apr 27 15:48:20 2001 +++ linux/include/linux/timer.h Tue May 15 00:33:16 2001 @@ -5,17 +5,13 @@ #include /* - * This is completely separate from the above, and is the - * "new and improved" way of handling timers more dynamically. - * Hopefully efficient and general enough for most things. + * In Linux 2.4, static timers have been removed from the kernel. + * Timers may be dynamically created and destroyed, and should be initialized + * by a call to init_timer() upon creation. * - * The "hardcoded" timers above are still useful for well- - * defined problems, but the timer-list is probably better - * when you need multiple outstanding timers or similar. - * - * The "data" field is in case you want to use the same - * timeout function for several timeouts. You can use this - * to distinguish between the different invocations. + * The "data" field enables use of a common timeout function for several + * timeouts. You can use this field to distinguish between the different + * invocations. */ struct timer_list { struct list_head list; diff -u --recursive --new-file v2.4.4/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.4.4/linux/include/linux/videodev.h Thu Apr 12 12:20:31 2001 +++ linux/include/linux/videodev.h Tue May 1 16:05:00 2001 @@ -374,6 +374,7 @@ #define VID_HARDWARE_OV511 27 #define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ #define VID_HARDWARE_W9966 29 +#define VID_HARDWARE_SE401 30 /* SE401 USB webcams */ /* diff -u --recursive --new-file v2.4.4/linux/include/net/ipconfig.h linux/include/net/ipconfig.h --- v2.4.4/linux/include/net/ipconfig.h Mon Jan 4 15:31:35 1999 +++ linux/include/net/ipconfig.h Tue May 1 20:59:24 2001 @@ -1,21 +1,38 @@ /* - * $Id: ipconfig.h,v 1.3 1999/01/04 20:13:29 davem Exp $ + * $Id: ipconfig.h,v 1.4 2001/04/30 04:51:46 davem Exp $ * * Copyright (C) 1997 Martin Mares * * Automatic IP Layer Configuration */ -extern __u32 root_server_addr; -extern u8 root_server_path[]; -extern u32 ic_myaddr; -extern u32 ic_servaddr; -extern u32 ic_gateway; -extern u32 ic_netmask; -extern int ic_enable; -extern int ic_host_name_set; -extern int ic_set_manually; -extern int ic_proto_enabled; +/* The following are initdata: */ -#define IC_BOOTP 1 -#define IC_RARP 2 +extern int ic_enable; /* Enable or disable the whole shebang */ + +extern int ic_proto_enabled; /* Protocols enabled (see IC_xxx) */ +extern int ic_host_name_set; /* Host name set by ipconfig? */ +extern int ic_set_manually; /* IPconfig parameters set manually */ + +extern u32 ic_myaddr; /* My IP address */ +extern u32 ic_netmask; /* Netmask for local subnet */ +extern u32 ic_gateway; /* Gateway IP address */ + +extern u32 ic_servaddr; /* Boot server IP address */ + +extern u32 root_server_addr; /* Address of NFS server */ +extern u8 root_server_path[]; /* Path to mount as root */ + + + +/* The following are persistent (not initdata): */ + +extern int ic_proto_used; /* Protocol used, if any */ +extern u32 ic_nameserver; /* DNS server IP address */ +extern u8 ic_domain[]; /* DNS (not NIS) domain name */ + +/* bits in ic_proto_{enabled,used} */ +#define IC_PROTO 0xFF /* Protocols mask: */ +#define IC_BOOTP 0x01 /* BOOTP (or DHCP, see below) */ +#define IC_RARP 0x02 /* RARP */ +#define IC_USE_DHCP 0x100 /* If on, use DHCP instead of BOOTP */ diff -u --recursive --new-file v2.4.4/linux/include/net/irda/irda-usb.h linux/include/net/irda/irda-usb.h --- v2.4.4/linux/include/net/irda/irda-usb.h Wed Dec 31 16:00:00 1969 +++ linux/include/net/irda/irda-usb.h Tue May 1 16:05:00 2001 @@ -0,0 +1,120 @@ +/***************************************************************************** + * + * Filename: irda-usb.h + * Version: 0.8 + * Description: IrDA-USB Driver + * Status: Experimental + * Author: Dag Brattli + * + * Copyright (C) 2001, Dag Brattli + * Copyright (C) 2000, Roman Weissgaerber + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *****************************************************************************/ + +#include + +#include +#include +#include + +#define RX_COPY_THRESHOLD 200 +#define IRDA_USB_MAX_MTU 2051 +#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ + +/* + * Maximum number of URB on the Rx and Tx path, a number larger than 1 + * is required for handling back-to-back (brickwalled) frames + */ +#define IU_MAX_ACTIVE_RX_URBS 1 +#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1) +#define IU_MAX_TX_URBS 1 + +/* Inbound header */ +#define MEDIA_BUSY 0x80 + +#define SPEED_2400 0x01 +#define SPEED_9600 0x02 +#define SPEED_19200 0x03 +#define SPEED_38400 0x04 +#define SPEED_57600 0x05 +#define SPEED_115200 0x06 +#define SPEED_576000 0x07 +#define SPEED_1152000 0x08 +#define SPEED_4000000 0x09 + +/* device_info flags in struct usb_device_id */ +#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ +#define IUC_SPEED_BUG 0x01 /* Device doesn't set speed after the frame */ +#define IUC_SIR_ONLY 0x02 /* Device doesn't behave at FIR speeds */ +#define IUC_SMALL_PKT 0x04 /* Device doesn't behave with big Rx packets */ +#define IUC_NO_WINDOW 0x08 /* Device doesn't behave with big Rx window */ +#define IUC_MAX_WINDOW 0x10 /* Device underestimate the Rx window */ +#define IUC_MAX_XBOFS 0x20 /* Device need more xbofs than advertised */ + +#define USB_IRDA_HEADER 0x01 +#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ +#define USB_DT_IRDA 0x21 + +struct irda_class_desc { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdSpecRevision; + __u8 bmDataSize; + __u8 bmWindowSize; + __u8 bmMinTurnaroundTime; + __u16 wBaudRate; + __u8 bmAdditionalBOFs; + __u8 bIrdaRateSniff; + __u8 bMaxUnicastList; +} __attribute__ ((packed)); + +struct irda_usb_cb { + struct irda_class_desc *irda_desc; + struct usb_device *usbdev; /* init: probe_irda */ + unsigned int ifnum; /* Interface number of the USB dev. */ + int netopen; /* Device is active for network */ + int present; /* Device is present on the bus */ + __u32 capability; /* Capability of the hardware */ + __u8 bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ + __u16 bulk_out_mtu; + + wait_queue_head_t wait_q; /* for timeouts */ + + struct urb rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */ + struct urb *rx_idle_urb; /* Pointer to idle URB in Rx path */ + struct urb tx_urb; /* URB used to send data frames */ + struct urb speed_urb; /* URB used to send speed commands */ + + struct net_device *netdev; /* Yes! we are some kind of netdev. */ + struct net_device_stats stats; + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; + hashbin_t *tx_list; /* Queued transmit skb's */ + + struct timeval stamp; + struct timeval now; + + spinlock_t lock; /* For serializing operations */ + + __u16 xbofs; /* Current xbofs setting */ + __s16 new_xbofs; /* xbofs we need to set */ + __u32 speed; /* Current speed */ + __s32 new_speed; /* speed we need to set */ + __u32 flags; /* Interface flags */ +}; + + diff -u --recursive --new-file v2.4.4/linux/include/net/irda/irda.h linux/include/net/irda/irda.h --- v2.4.4/linux/include/net/irda/irda.h Fri Apr 27 15:48:59 2001 +++ linux/include/net/irda/irda.h Tue May 15 00:33:33 2001 @@ -71,7 +71,9 @@ func } #else #define IRDA_DEBUG(n, args...) -#define ASSERT(expr, func) +#define ASSERT(expr, func) \ +if(!(expr)) do { \ + func } while (0) #endif /* CONFIG_IRDA_DEBUG */ #define WARNING(args...) printk(KERN_WARNING args) diff -u --recursive --new-file v2.4.4/linux/init/main.c linux/init/main.c --- v2.4.4/linux/init/main.c Fri Apr 27 14:23:40 2001 +++ linux/init/main.c Tue May 8 16:41:32 2001 @@ -561,9 +561,6 @@ #endif mem_init(); kmem_cache_sizes_init(); -#ifdef CONFIG_PROC_FS - proc_root_init(); -#endif mempages = num_physpages; fork_init(mempages); @@ -577,6 +574,9 @@ signals_init(); bdev_init(); inode_init(mempages); +#ifdef CONFIG_PROC_FS + proc_root_init(); +#endif #if defined(CONFIG_SYSVIPC) ipc_init(); #endif @@ -718,6 +718,7 @@ do_initcalls(); #ifdef CONFIG_IRDA + irda_proto_init(); irda_device_init(); /* Must be done after protocol initialization */ #endif #ifdef CONFIG_PCMCIA diff -u --recursive --new-file v2.4.4/linux/kernel/exit.c linux/kernel/exit.c --- v2.4.4/linux/kernel/exit.c Fri Feb 9 11:29:44 2001 +++ linux/kernel/exit.c Fri May 4 14:44:06 2001 @@ -62,6 +62,7 @@ current->counter += p->counter; if (current->counter >= MAX_COUNTER) current->counter = MAX_COUNTER; + p->pid = 0; free_task_struct(p); } else { printk("task releasing itself\n"); diff -u --recursive --new-file v2.4.4/linux/kernel/fork.c linux/kernel/fork.c --- v2.4.4/linux/kernel/fork.c Thu Apr 26 06:11:17 2001 +++ linux/kernel/fork.c Mon Apr 30 22:23:29 2001 @@ -666,17 +666,15 @@ p->pdeath_signal = 0; /* - * Give the parent's dynamic priority entirely to the child. The - * total amount of dynamic priorities in the system doesn't change - * (more scheduling fairness), but the child will run first, which - * is especially useful in avoiding a lot of copy-on-write faults - * if the child for a fork() just wants to do a few simple things - * and then exec(). This is only important in the first timeslice. - * In the long run, the scheduling behavior is unchanged. + * "share" dynamic priority between parent and child, thus the + * total amount of dynamic priorities in the system doesnt change, + * more scheduling fairness. This is only important in the first + * timeslice, on the long run the scheduling behaviour is unchanged. */ - p->counter = current->counter; - current->counter = 0; - current->need_resched = 1; + p->counter = (current->counter + 1) >> 1; + current->counter >>= 1; + if (!current->counter) + current->need_resched = 1; /* * Ok, add it to the run-queues and make it diff -u --recursive --new-file v2.4.4/linux/kernel/kmod.c linux/kernel/kmod.c --- v2.4.4/linux/kernel/kmod.c Sat Dec 30 18:16:13 2000 +++ linux/kernel/kmod.c Tue May 1 16:05:00 2001 @@ -157,19 +157,18 @@ } /** - * request_module - try to load a kernel module - * @module_name: Name of module + * request_module - try to load a kernel module + * @module_name: Name of module * - * Load a module using the user mode module loader. The function returns - * zero on success or a negative errno code on failure. Note that a - * successful module load does not mean the module did not then unload - * and exit on an error of its own. Callers must check that the service - * they requested is now available not blindly invoke it. + * Load a module using the user mode module loader. The function returns + * zero on success or a negative errno code on failure. Note that a + * successful module load does not mean the module did not then unload + * and exit on an error of its own. Callers must check that the service + * they requested is now available not blindly invoke it. * - * If module auto-loading support is disabled then this function - * becomes a no-operation. + * If module auto-loading support is disabled then this function + * becomes a no-operation. */ - int request_module(const char * module_name) { pid_t pid; diff -u --recursive --new-file v2.4.4/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.4.4/linux/kernel/ksyms.c Fri Apr 27 14:23:25 2001 +++ linux/kernel/ksyms.c Sat Apr 28 11:27:54 2001 @@ -174,6 +174,7 @@ EXPORT_SYMBOL(check_disk_change); EXPORT_SYMBOL(__invalidate_buffers); EXPORT_SYMBOL(invalidate_inodes); +EXPORT_SYMBOL(invalidate_device); EXPORT_SYMBOL(invalidate_inode_pages); EXPORT_SYMBOL(truncate_inode_pages); EXPORT_SYMBOL(fsync_dev); diff -u --recursive --new-file v2.4.4/linux/kernel/module.c linux/kernel/module.c --- v2.4.4/linux/kernel/module.c Fri Feb 16 16:02:37 2001 +++ linux/kernel/module.c Tue May 1 16:05:00 2001 @@ -554,8 +554,8 @@ put_mod_name(name); /* Initialize the module. */ - mod->flags |= MOD_INITIALIZING; atomic_set(&mod->uc.usecount,1); + mod->flags |= MOD_INITIALIZING; if (mod->init && (error = mod->init()) != 0) { atomic_set(&mod->uc.usecount,0); mod->flags &= ~MOD_INITIALIZING; @@ -613,11 +613,6 @@ if (name_user) { if ((error = get_mod_name(name_user, &name)) < 0) goto out; - if (error == 0) { - error = -EINVAL; - put_mod_name(name); - goto out; - } error = -ENOENT; if ((mod = find_module(name)) == NULL) { put_mod_name(name); @@ -847,7 +842,6 @@ bufsize -= len; space += len; } - if (put_user(i, ret)) return -EFAULT; else @@ -876,8 +870,11 @@ info.addr = (unsigned long)mod; info.size = mod->size; info.flags = mod->flags; + + /* usecount is one too high here - report appropriately to + compensate for locking */ info.usecount = (mod_member_present(mod, can_unload) - && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount)); + && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount)-1); if (copy_to_user(buf, &info, sizeof(struct module_info))) return -EFAULT; @@ -909,15 +906,17 @@ goto out; } err = -ENOENT; - if (namelen == 0) - mod = &kernel_module; - else if ((mod = find_module(name)) == NULL) { + if ((mod = find_module(name)) == NULL) { put_mod_name(name); goto out; } put_mod_name(name); } + /* __MOD_ touches the flags. We must avoid that */ + + atomic_inc(&mod->uc.usecount); + switch (which) { case 0: @@ -942,6 +941,8 @@ err = -EINVAL; break; } + atomic_dec(&mod->uc.usecount); + out: unlock_kernel(); return err; diff -u --recursive --new-file v2.4.4/linux/mm/oom_kill.c linux/mm/oom_kill.c --- v2.4.4/linux/mm/oom_kill.c Tue Nov 14 10:56:46 2000 +++ linux/mm/oom_kill.c Tue May 15 00:25:41 2001 @@ -191,8 +191,6 @@ */ int out_of_memory(void) { - struct sysinfo swp_info; - /* Enough free memory? Not OOM. */ if (nr_free_pages() > freepages.min) return 0; @@ -201,8 +199,7 @@ return 0; /* Enough swap space left? Not OOM. */ - si_swapinfo(&swp_info); - if (swp_info.freeswap > 0) + if (nr_swap_pages > 0) return 0; /* Else... */ diff -u --recursive --new-file v2.4.4/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.4.4/linux/mm/vmscan.c Thu Apr 12 12:10:25 2001 +++ linux/mm/vmscan.c Tue May 15 00:30:24 2001 @@ -869,7 +869,6 @@ DECLARE_WAIT_QUEUE_HEAD(kswapd_wait); DECLARE_WAIT_QUEUE_HEAD(kswapd_done); -struct task_struct *kswapd_task; /* * The background pageout daemon, started as a kernel thread @@ -892,7 +891,6 @@ tsk->pgrp = 1; strcpy(tsk->comm, "kswapd"); sigfillset(&tsk->blocked); - kswapd_task = tsk; /* * Tell the memory management that we're a "memory allocator", @@ -964,8 +962,8 @@ void wakeup_kswapd(void) { - if (current != kswapd_task) - wake_up_process(kswapd_task); + if (waitqueue_active(&kswapd_wait)) + wake_up_interruptible(&kswapd_wait); } /* diff -u --recursive --new-file v2.4.4/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c --- v2.4.4/linux/net/decnet/af_decnet.c Thu Apr 12 12:11:39 2001 +++ linux/net/decnet/af_decnet.c Tue May 1 16:05:00 2001 @@ -1431,7 +1431,7 @@ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); struct linkinfo_dn link; - int r_len; + unsigned int r_len; void *r_data = NULL; unsigned int val; diff -u --recursive --new-file v2.4.4/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.4.4/linux/net/ipv4/Config.in Tue Aug 22 08:59:00 2000 +++ linux/net/ipv4/Config.in Tue May 1 20:59:24 2001 @@ -20,6 +20,7 @@ fi bool ' IP: kernel level autoconfiguration' CONFIG_IP_PNP if [ "$CONFIG_IP_PNP" = "y" ]; then + bool ' IP: DHCP support' CONFIG_IP_PNP_DHCP bool ' IP: BOOTP support' CONFIG_IP_PNP_BOOTP bool ' IP: RARP support' CONFIG_IP_PNP_RARP # not yet ready.. diff -u --recursive --new-file v2.4.4/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.4.4/linux/net/ipv4/af_inet.c Thu Apr 12 12:11:39 2001 +++ linux/net/ipv4/af_inet.c Tue May 1 20:59:24 2001 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.129 2001/03/02 03:13:05 davem Exp $ + * Version: $Id: af_inet.c,v 1.130 2001/04/29 08:21:32 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -135,11 +135,11 @@ #endif #ifdef CONFIG_DLCI_MODULE -int (*dlci_ioctl_hook)(unsigned int, void *) = NULL; +int (*dlci_ioctl_hook)(unsigned int, void *); #endif #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -int (*br_ioctl_hook)(unsigned long) = NULL; +int (*br_ioctl_hook)(unsigned long); #endif /* New destruction routine */ @@ -361,19 +361,19 @@ sk->destruct = inet_sock_destruct; - sk->zapped = 0; - sk->family = PF_INET; - sk->protocol = protocol; + sk->zapped = 0; + sk->family = PF_INET; + sk->protocol = protocol; - sk->prot = prot; + sk->prot = prot; sk->backlog_rcv = prot->backlog_rcv; - sk->protinfo.af_inet.ttl=sysctl_ip_default_ttl; + sk->protinfo.af_inet.ttl = sysctl_ip_default_ttl; - sk->protinfo.af_inet.mc_loop=1; - sk->protinfo.af_inet.mc_ttl=1; - sk->protinfo.af_inet.mc_index=0; - sk->protinfo.af_inet.mc_list=NULL; + sk->protinfo.af_inet.mc_loop = 1; + sk->protinfo.af_inet.mc_ttl = 1; + sk->protinfo.af_inet.mc_index = 0; + sk->protinfo.af_inet.mc_list = NULL; #ifdef INET_REFCNT_DEBUG atomic_inc(&inet_sock_nr); @@ -815,8 +815,7 @@ int err; int pid; - switch(cmd) - { + switch(cmd) { case FIOSETOWN: case SIOCSPGRP: err = get_user(pid, (int *) arg); @@ -962,8 +961,8 @@ }; struct net_proto_family inet_family_ops = { - PF_INET, - inet_create + family: PF_INET, + create: inet_create }; @@ -982,8 +981,7 @@ printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n"); - if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) - { + if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) { printk(KERN_CRIT "inet_proto_init: panic\n"); return -EINVAL; } @@ -999,8 +997,7 @@ */ printk(KERN_INFO "IP Protocols: "); - for(p = inet_protocol_base; p != NULL;) - { + for (p = inet_protocol_base; p != NULL;) { struct inet_protocol *tmp = (struct inet_protocol *) p->next; inet_add_protocol(p); printk("%s%s",p->name,tmp?", ":"\n"); diff -u --recursive --new-file v2.4.4/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.4.4/linux/net/ipv4/arp.c Thu Apr 12 12:11:39 2001 +++ linux/net/ipv4/arp.c Tue May 1 20:59:24 2001 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.96 2001/02/02 08:42:59 davem Exp $ + * Version: $Id: arp.c,v 1.97 2001/04/30 04:36:12 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * @@ -123,69 +123,71 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); static void parp_redo(struct sk_buff *skb); -static struct neigh_ops arp_generic_ops = -{ - AF_INET, - NULL, - arp_solicit, - arp_error_report, - neigh_resolve_output, - neigh_connected_output, - dev_queue_xmit, - dev_queue_xmit +static struct neigh_ops arp_generic_ops = { + family: AF_INET, + solicit: arp_solicit, + error_report: arp_error_report, + output: neigh_resolve_output, + connected_output: neigh_connected_output, + hh_output: dev_queue_xmit, + queue_xmit: dev_queue_xmit, }; -static struct neigh_ops arp_hh_ops = -{ - AF_INET, - NULL, - arp_solicit, - arp_error_report, - neigh_resolve_output, - neigh_resolve_output, - dev_queue_xmit, - dev_queue_xmit +static struct neigh_ops arp_hh_ops = { + family: AF_INET, + solicit: arp_solicit, + error_report: arp_error_report, + output: neigh_resolve_output, + connected_output: neigh_resolve_output, + hh_output: dev_queue_xmit, + queue_xmit: dev_queue_xmit, }; -static struct neigh_ops arp_direct_ops = -{ - AF_INET, - NULL, - NULL, - NULL, - dev_queue_xmit, - dev_queue_xmit, - dev_queue_xmit, - dev_queue_xmit +static struct neigh_ops arp_direct_ops = { + family: AF_INET, + output: dev_queue_xmit, + connected_output: dev_queue_xmit, + hh_output: dev_queue_xmit, + queue_xmit: dev_queue_xmit, }; -struct neigh_ops arp_broken_ops = -{ - AF_INET, - NULL, - arp_solicit, - arp_error_report, - neigh_compat_output, - neigh_compat_output, - dev_queue_xmit, - dev_queue_xmit, +struct neigh_ops arp_broken_ops = { + family: AF_INET, + solicit: arp_solicit, + error_report: arp_error_report, + output: neigh_compat_output, + connected_output: neigh_compat_output, + hh_output: dev_queue_xmit, + queue_xmit: dev_queue_xmit, }; -struct neigh_table arp_tbl = -{ - NULL, - AF_INET, - sizeof(struct neighbour) + 4, - 4, - arp_hash, - arp_constructor, - NULL, - NULL, - parp_redo, - "arp_cache", - { NULL, NULL, &arp_tbl, 0, NULL, NULL, - 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 1*HZ }, - 30*HZ, 128, 512, 1024, +struct neigh_table arp_tbl = { + family: AF_INET, + entry_size: sizeof(struct neighbour) + 4, + key_len: 4, + hash: arp_hash, + constructor: arp_constructor, + proxy_redo: parp_redo, + id: "arp_cache", + parms: { + tbl: &arp_tbl, + base_reachable_time: 30 * HZ, + retrans_time: 1 * HZ, + gc_staletime: 60 * HZ, + reachable_time: 30 * HZ, + delay_probe_time: 5 * HZ, + queue_len: 3, + ucast_probes: 3, + mcast_probes: 3, + anycast_delay: 1 * HZ, + proxy_delay: (8 * HZ) / 10, + proxy_qlen: 64, + locktime: 1 * HZ, + }, + gc_interval: 30 * HZ, + gc_thresh1: 128, + gc_thresh2: 512, + gc_thresh3: 1024, }; int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) @@ -194,10 +196,10 @@ case ARPHRD_ETHER: case ARPHRD_FDDI: case ARPHRD_IEEE802: - ip_eth_mc_map(addr, haddr) ; - return 0 ; + ip_eth_mc_map(addr, haddr); + return 0; case ARPHRD_IEEE802_TR: - ip_tr_mc_map(addr, haddr) ; + ip_tr_mc_map(addr, haddr); return 0; default: if (dir) { @@ -1162,13 +1164,10 @@ * Called once on startup. */ -static struct packet_type arp_packet_type = -{ - __constant_htons(ETH_P_ARP), - NULL, /* All devices */ - arp_rcv, - (void*)1, - NULL +static struct packet_type arp_packet_type = { + type: __constant_htons(ETH_P_ARP), + func: arp_rcv, + data: (void*) 1, /* understand shared skbs */ }; void __init arp_init (void) diff -u --recursive --new-file v2.4.4/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.4.4/linux/net/ipv4/fib_frontend.c Wed Dec 22 19:55:38 1999 +++ linux/net/ipv4/fib_frontend.c Tue May 1 20:59:24 2001 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: FIB frontend. * - * Version: $Id: fib_frontend.c,v 1.21 1999/12/15 22:39:07 davem Exp $ + * Version: $Id: fib_frontend.c,v 1.23 2001/05/01 23:21:37 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -569,9 +569,9 @@ #undef BRD1_OK } -static void fib_disable_ip(struct net_device *dev, int force) +static void fib_disable_ip(struct net_device *dev, u32 addr, int force) { - if (fib_sync_down(0, dev, force)) + if (fib_sync_down(addr, dev, force)) fib_flush(); rt_cache_flush(0); arp_ifdown(dev); @@ -591,7 +591,7 @@ /* Last address was deleted from this interface. Disable IP. */ - fib_disable_ip(ifa->ifa_dev->dev, 1); + fib_disable_ip(ifa->ifa_dev->dev, ifa->ifa_local, 1); } else { fib_del_ifaddr(ifa); rt_cache_flush(-1); @@ -620,10 +620,10 @@ rt_cache_flush(-1); break; case NETDEV_DOWN: - fib_disable_ip(dev, 0); + fib_disable_ip(dev, 0, 0); break; case NETDEV_UNREGISTER: - fib_disable_ip(dev, 1); + fib_disable_ip(dev, 0, 1); break; case NETDEV_CHANGEMTU: case NETDEV_CHANGE: @@ -634,15 +634,11 @@ } struct notifier_block fib_inetaddr_notifier = { - fib_inetaddr_event, - NULL, - 0 + notifier_call: fib_inetaddr_event, }; struct notifier_block fib_netdev_notifier = { - fib_netdev_event, - NULL, - 0 + notifier_call: fib_netdev_event, }; void __init ip_fib_init(void) diff -u --recursive --new-file v2.4.4/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c --- v2.4.4/linux/net/ipv4/fib_rules.c Mon Apr 24 13:59:56 2000 +++ linux/net/ipv4/fib_rules.c Tue May 1 20:59:24 2001 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: policy rules. * - * Version: $Id: fib_rules.c,v 1.15 2000/04/15 01:48:10 davem Exp $ + * Version: $Id: fib_rules.c,v 1.16 2001/04/30 04:39:14 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -76,9 +76,27 @@ int r_dead; }; -static struct fib_rule default_rule = { NULL, ATOMIC_INIT(2), 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST, }; -static struct fib_rule main_rule = { &default_rule, ATOMIC_INIT(2), 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST, }; -static struct fib_rule local_rule = { &main_rule, ATOMIC_INIT(2), 0, RT_TABLE_LOCAL, RTN_UNICAST, }; +static struct fib_rule default_rule = { + r_clntref: ATOMIC_INIT(2), + r_preference: 0x7FFF, + r_table: RT_TABLE_DEFAULT, + r_action: RTN_UNICAST, +}; + +static struct fib_rule main_rule = { + r_next: &default_rule, + r_clntref: ATOMIC_INIT(2), + r_preference: 0x7FFE, + r_table: RT_TABLE_MAIN, + r_action: RTN_UNICAST, +}; + +static struct fib_rule local_rule = { + r_next: &main_rule, + r_clntref: ATOMIC_INIT(2), + r_table: RT_TABLE_LOCAL, + r_action: RTN_UNICAST, +}; static struct fib_rule *fib_rules = &local_rule; static rwlock_t fib_rules_lock = RW_LOCK_UNLOCKED; @@ -374,9 +392,7 @@ struct notifier_block fib_rules_notifier = { - fib_rules_event, - NULL, - 0 + notifier_call: fib_rules_event, }; #ifdef CONFIG_RTNETLINK diff -u --recursive --new-file v2.4.4/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.4.4/linux/net/ipv4/icmp.c Thu Apr 19 08:38:50 2001 +++ linux/net/ipv4/icmp.c Tue May 1 20:59:24 2001 @@ -3,7 +3,7 @@ * * Alan Cox, * - * Version: $Id: icmp.c,v 1.74 2001/04/16 23:58:51 davem Exp $ + * Version: $Id: icmp.c,v 1.75 2001/04/30 04:40:40 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -139,11 +139,11 @@ }; /* Control parameters for ECHO relies. */ -int sysctl_icmp_echo_ignore_all = 0; -int sysctl_icmp_echo_ignore_broadcasts = 0; +int sysctl_icmp_echo_ignore_all; +int sysctl_icmp_echo_ignore_broadcasts; /* Control parameter - ignore bogus broadcast responses? */ -int sysctl_icmp_ignore_bogus_error_responses =0; +int sysctl_icmp_ignore_bogus_error_responses; /* * ICMP control array. This specifies what to do with each ICMP. @@ -167,7 +167,7 @@ */ struct inode icmp_inode; -struct socket *icmp_socket=&icmp_inode.u.socket_i; +struct socket *icmp_socket = &icmp_inode.u.socket_i; /* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6, which is strongly non-reenterable). A bit later it will be made @@ -651,7 +651,7 @@ */ ipprot = (struct inet_protocol *) inet_protos[hash]; - while(ipprot != NULL) { + while (ipprot) { struct inet_protocol *nextip; nextip = (struct inet_protocol *) ipprot->next; @@ -695,7 +695,7 @@ iph = (struct iphdr *) skb->data; ip = iph->daddr; - switch(skb->h.icmph->code & 7) { + switch (skb->h.icmph->code & 7) { case ICMP_REDIR_NET: case ICMP_REDIR_NETTOS: /* @@ -753,7 +753,7 @@ * Too short. */ - if(skb->len<4) { + if (skb->len < 4) { ICMP_INC_STATS_BH(IcmpInErrors); return; } @@ -945,7 +945,7 @@ int sysctl_icmp_destunreach_time = 1*HZ; int sysctl_icmp_timeexceed_time = 1*HZ; int sysctl_icmp_paramprob_time = 1*HZ; -int sysctl_icmp_echoreply_time = 0; /* don't limit it per default. */ +int sysctl_icmp_echoreply_time; /* don't limit it per default. */ /* * This table is the definition of how we handle ICMP. diff -u --recursive --new-file v2.4.4/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.4.4/linux/net/ipv4/ipconfig.c Fri Feb 9 11:34:13 2001 +++ linux/net/ipv4/ipconfig.c Tue May 1 20:59:24 2001 @@ -1,10 +1,10 @@ /* - * $Id: ipconfig.c,v 1.35 2000/12/30 06:46:36 davem Exp $ + * $Id: ipconfig.c,v 1.37 2001/04/30 18:54:12 davem Exp $ * - * Automatic Configuration of IP -- use BOOTP or RARP or user-supplied - * information to configure own IP address and routes. + * Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or + * user-supplied information to configure own IP address and routes. * - * Copyright (C) 1996--1998 Martin Mares + * Copyright (C) 1996-1998 Martin Mares * * Derived from network configuration code in fs/nfs/nfsroot.c, * originally Copyright (C) 1995, 1996 Gero Kuhlmann and me. @@ -16,6 +16,16 @@ * Fixed ip_auto_config_setup calling at startup in the new "Linker Magic" * initialization scheme. * - Arnaldo Carvalho de Melo , 08/11/1999 + * + * DHCP support added. To users this looks like a whole separate + * protocol, but we know it's just a bag on the side of BOOTP. + * -- Chip Salzenberg , May 2000 + * + * Ported DHCP support from 2.2.16 to 2.4.0-test4 + * -- Eric Biederman , 30 Aug 2000 + * + * Merged changes from 2.2.19 into 2.4.3 + * -- Eric Biederman , 22 April Aug 2001 */ #include @@ -36,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -52,48 +63,94 @@ #define DBG(x) do { } while(0) #endif -/* Define the timeout for waiting for a RARP/BOOTP reply */ -#define CONF_BASE_TIMEOUT (HZ*5) /* Initial timeout: 5 seconds */ -#define CONF_RETRIES 10 /* 10 retries */ +#if defined(CONFIG_IP_PNP_DHCP) +#define IPCONFIG_DHCP +#endif +#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_DHCP) +#define IPCONFIG_BOOTP +#endif +#if defined(CONFIG_IP_PNP_RARP) +#define IPCONFIG_RARP +#endif +#if defined(IPCONFIG_BOOTP) || defined(IPCONFIG_RARP) +#define IPCONFIG_DYNAMIC +#endif + +/* Define the friendly delay before and after opening net devices */ +#define CONF_PRE_OPEN (HZ/2) /* Before opening: 1/2 second */ +#define CONF_POST_OPEN (1*HZ) /* After opening: 1 second */ + +/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */ +#define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */ +#define CONF_SEND_RETRIES 6 /* Send six requests per open */ +#define CONF_INTER_TIMEOUT (HZ/2) /* Inter-device timeout: 1/2 second */ +#define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */ #define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */ -#define CONF_TIMEOUT_MULT *5/4 /* Rate of timeout growth */ +#define CONF_TIMEOUT_MULT *7/4 /* Rate of timeout growth */ #define CONF_TIMEOUT_MAX (HZ*30) /* Maximum allowed timeout */ -/* IP configuration */ -static char user_dev_name[IFNAMSIZ] __initdata = { 0, };/* Name of user-selected boot device */ -u32 ic_myaddr __initdata = INADDR_NONE; /* My IP address */ -u32 ic_servaddr __initdata = INADDR_NONE; /* Server IP address */ -u32 ic_gateway __initdata = INADDR_NONE; /* Gateway IP address */ -u32 ic_netmask __initdata = INADDR_NONE; /* Netmask for local subnet */ -int ic_enable __initdata = 1; /* Automatic IP configuration enabled */ -int ic_host_name_set __initdata = 0; /* Host name configured manually */ -int ic_set_manually __initdata = 0; /* IPconfig parameters set manually */ -u32 root_server_addr __initdata = INADDR_NONE; /* Address of boot server */ -u8 root_server_path[256] __initdata = { 0, }; /* Path to mount as root */ +/* + * Public IP configuration + */ -#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP) +/* This is used by platforms which might be able to set the ipconfig + * variabled using firmware environment vars. If this is set, it will + * ignore such firmware variables. + */ +int ic_set_manually __initdata = 0; /* IPconfig parameters set manually */ -#define CONFIG_IP_PNP_DYNAMIC +int ic_enable __initdata = 0; /* IP config enabled? */ -int ic_proto_enabled __initdata = 0 /* Protocols enabled */ -#ifdef CONFIG_IP_PNP_BOOTP +/* Protocol choice */ +int ic_proto_enabled __initdata = 0 +#ifdef IPCONFIG_BOOTP | IC_BOOTP #endif -#ifdef CONFIG_IP_PNP_RARP +#ifdef CONFIG_IP_PNP_DHCP + | IC_USE_DHCP +#endif +#ifdef IPCONFIG_RARP | IC_RARP #endif ; -static int ic_got_reply __initdata = 0; /* Protocol(s) we got reply from */ -#else +int ic_host_name_set __initdata = 0; /* Host name set by us? */ -static int ic_proto_enabled __initdata = 0; +u32 ic_myaddr __initdata = INADDR_NONE; /* My IP address */ +u32 ic_netmask __initdata = INADDR_NONE; /* Netmask for local subnet */ +u32 ic_gateway __initdata = INADDR_NONE; /* Gateway IP address */ -#endif +u32 ic_servaddr __initdata = INADDR_NONE; /* Boot server IP address */ +u32 root_server_addr __initdata = INADDR_NONE; /* Address of NFS server */ +u8 root_server_path[256] __initdata = { 0, }; /* Path to mount as root */ + +/* Persistent data: */ + +int ic_proto_used; /* Protocol used, if any */ +u32 ic_nameserver = INADDR_NONE; /* DNS Server IP address */ +u8 ic_domain[64]; /* DNS (not NIS) domain name */ + +/* + * Private state. + */ + +/* Name of user-selected boot device */ +static char user_dev_name[IFNAMSIZ] __initdata = { 0, }; + +/* Protocols supported by available interfaces */ static int ic_proto_have_if __initdata = 0; +#ifdef IPCONFIG_DYNAMIC +static spinlock_t ic_recv_lock = SPIN_LOCK_UNLOCKED; +static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */ +#endif +#ifdef IPCONFIG_DHCP +static int ic_dhcp_msgtype __initdata = 0; /* DHCP msg type received */ +#endif + + /* * Network devices */ @@ -102,11 +159,12 @@ struct ic_device *next; struct net_device *dev; unsigned short flags; - int able; + short able; + u32 xid; }; static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ -static struct net_device *ic_dev __initdata = NULL; /* Selected device */ +static struct net_device *ic_dev __initdata = NULL; /* Selected device */ static int __init ic_open_devs(void) { @@ -125,7 +183,7 @@ if (dev->mtu >= 364) able |= IC_BOOTP; else - printk(KERN_WARNING "BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu); + printk(KERN_WARNING "DHCP/BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu); if (!(dev->flags & IFF_NOARP)) able |= IC_RARP; able &= ic_proto_enabled; @@ -143,8 +201,13 @@ last = &d->next; d->flags = oflags; d->able = able; + if (able & IC_BOOTP) + get_random_bytes(&d->xid, sizeof(u32)); + else + d->xid = 0; ic_proto_have_if |= able; - DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able)); + DBG(("IP-Config: %s UP (able=%d, xid=%08x)\n", + dev->name, able, d->xid)); } } rtnl_shunlock(); @@ -282,18 +345,18 @@ */ if (!ic_host_name_set) - strcpy(system_utsname.nodename, in_ntoa(ic_myaddr)); + sprintf(system_utsname.nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); if (root_server_addr == INADDR_NONE) root_server_addr = ic_servaddr; if (ic_netmask == INADDR_NONE) { if (IN_CLASSA(ntohl(ic_myaddr))) - ic_netmask = htonl(IN_CLASSA_NET); + ic_netmask = __constant_htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(ic_myaddr))) - ic_netmask = htonl(IN_CLASSB_NET); + ic_netmask = __constant_htonl(IN_CLASSB_NET); else if (IN_CLASSC(ntohl(ic_myaddr))) - ic_netmask = htonl(IN_CLASSC_NET); + ic_netmask = __constant_htonl(IN_CLASSC_NET); else { printk(KERN_ERR "IP-Config: Unable to guess netmask for address %u.%u.%u.%u\n", NIPQUAD(ic_myaddr)); @@ -309,16 +372,13 @@ * RARP support. */ -#ifdef CONFIG_IP_PNP_RARP +#ifdef IPCONFIG_RARP static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt); static struct packet_type rarp_packet_type __initdata = { - __constant_htons(ETH_P_RARP), - NULL, /* Listen to all devices */ - ic_rarp_recv, - NULL, - NULL + type: __constant_htons(ETH_P_RARP), + func: ic_rarp_recv, }; static inline void ic_rarp_init(void) @@ -341,21 +401,32 @@ unsigned char *rarp_ptr = (unsigned char *) (rarp + 1); unsigned long sip, tip; unsigned char *sha, *tha; /* s for "source", t for "target" */ + struct ic_device *d; + + /* One reply at a time, please. */ + spin_lock(&ic_recv_lock); /* If we already have a reply, just drop the packet */ if (ic_got_reply) goto drop; + /* Find the ic_device that the packet arrived on */ + d = ic_first_dev; + while (d && d->dev != dev) + d = d->next; + if (!d) + goto drop; /* should never happen */ + /* If this test doesn't pass, it's not IP, or we should ignore it anyway */ if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) goto drop; /* If it's not a RARP reply, delete it. */ - if (rarp->ar_op != htons(ARPOP_RREPLY)) + if (rarp->ar_op != __constant_htons(ARPOP_RREPLY)) goto drop; /* If it's not Ethernet, delete it. */ - if (rarp->ar_pro != htons(ETH_P_IP)) + if (rarp->ar_pro != __constant_htons(ETH_P_IP)) goto drop; /* Extract variable-width fields */ @@ -375,44 +446,39 @@ if (ic_servaddr != INADDR_NONE && ic_servaddr != sip) goto drop; - /* Victory! The packet is what we were looking for! */ - if (!ic_got_reply) { - ic_got_reply = IC_RARP; - ic_dev = dev; - if (ic_myaddr == INADDR_NONE) - ic_myaddr = tip; - ic_servaddr = sip; - } + /* We have a winner! */ + ic_dev = dev; + if (ic_myaddr == INADDR_NONE) + ic_myaddr = tip; + ic_servaddr = sip; + ic_got_reply = IC_RARP; - /* And throw the packet out... */ drop: + /* Show's over. Nothing to see here. */ + spin_unlock(&ic_recv_lock); + + /* Throw the packet out. */ kfree_skb(skb); return 0; } /* - * Send RARP request packet over all devices which allow RARP. + * Send RARP request packet over a signle interface. */ -static void __init ic_rarp_send(void) +static void __init ic_rarp_send_if(struct ic_device *d) { - struct ic_device *d; - - for (d=ic_first_dev; d; d=d->next) - if (d->able & IC_RARP) { - struct net_device *dev = d->dev; - arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, - dev->dev_addr, dev->dev_addr); - } + struct net_device *dev = d->dev; + arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, + dev->dev_addr, dev->dev_addr); } - #endif /* - * BOOTP support. + * DHCP/BOOTP support. */ -#ifdef CONFIG_IP_PNP_BOOTP +#ifdef IPCONFIG_BOOTP struct bootp_pkt { /* BOOTP packet format */ struct iphdr iph; /* IP header */ @@ -426,45 +492,110 @@ u16 flags; /* Just what it says */ u32 client_ip; /* Client's IP address if known */ u32 your_ip; /* Assigned IP address */ - u32 server_ip; /* Server's IP address */ + u32 server_ip; /* (Next, e.g. NFS) Server's IP address */ u32 relay_ip; /* IP address of BOOTP relay */ u8 hw_addr[16]; /* Client's HW address */ u8 serv_name[64]; /* Server host name */ u8 boot_file[128]; /* Name of boot file */ - u8 vendor_area[128]; /* Area for extensions */ + u8 exten[312]; /* DHCP options / BOOTP vendor extensions */ }; -#define BOOTP_REQUEST 1 -#define BOOTP_REPLY 2 - -static u32 ic_bootp_xid; +/* packet ops */ +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +/* DHCP message types */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt); static struct packet_type bootp_packet_type __initdata = { - __constant_htons(ETH_P_IP), - NULL, /* Listen to all devices */ - ic_bootp_recv, - NULL, - NULL + type: __constant_htons(ETH_P_IP), + func: ic_bootp_recv, }; /* - * Initialize BOOTP extension fields in the request. + * Initialize DHCP/BOOTP extension fields in the request. */ + +static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 }; + +#ifdef IPCONFIG_DHCP + +static void __init +ic_dhcp_init_options(u8 *options) +{ + u8 mt = ((ic_servaddr == INADDR_NONE) + ? DHCPDISCOVER : DHCPREQUEST); + u8 *e = options; + +#ifdef IPCONFIG_DEBUG + printk("DHCP: Sending message type %d\n", mt); +#endif + + memcpy(e, ic_bootp_cookie, 4); /* RFC1048 Magic Cookie */ + e += 4; + + *e++ = 53; /* DHCP message type */ + *e++ = 1; + *e++ = mt; + + if (mt == DHCPREQUEST) { + *e++ = 54; /* Server ID (IP address) */ + *e++ = 4; + memcpy(e, &ic_servaddr, 4); + e += 4; + + *e++ = 50; /* Requested IP address */ + *e++ = 4; + memcpy(e, &ic_myaddr, 4); + e += 4; + } + + /* always? */ + { + static const u8 ic_req_params[] = { + 1, /* Subnet mask */ + 3, /* Default gateway */ + 6, /* DNS server */ + 12, /* Host name */ + 15, /* Domain name */ + 17, /* Boot path */ + 40, /* NIS domain name */ + }; + + *e++ = 55; /* Parameter request list */ + *e++ = sizeof(ic_req_params); + memcpy(e, ic_req_params, sizeof(ic_req_params)); + e += sizeof(ic_req_params); + } + + *e++ = 255; /* End of the list */ +} + +#endif /* IPCONFIG_DHCP */ + static void __init ic_bootp_init_ext(u8 *e) { - *e++ = 99; /* RFC1048 Magic Cookie */ - *e++ = 130; - *e++ = 83; - *e++ = 99; + memcpy(e, ic_bootp_cookie, 4); /* RFC1048 Magic Cookie */ + e += 4; *e++ = 1; /* Subnet mask request */ *e++ = 4; e += 4; *e++ = 3; /* Default gateway request */ *e++ = 4; e += 4; + *e++ = 5; /* Name server reqeust */ + *e++ = 8; + e += 8; *e++ = 12; /* Host name request */ *e++ = 32; e += 32; @@ -472,25 +603,23 @@ *e++ = 32; e += 32; *e++ = 17; /* Boot path */ - *e++ = 32; - e += 32; - *e = 255; /* End of the list */ + *e++ = 40; + e += 40; + *e++ = 255; /* End of the list */ } /* - * Initialize the BOOTP mechanism. + * Initialize the DHCP/BOOTP mechanism. */ static inline void ic_bootp_init(void) { - get_random_bytes(&ic_bootp_xid, sizeof(u32)); - DBG(("BOOTP: XID=%08x\n", ic_bootp_xid)); dev_add_pack(&bootp_packet_type); } /* - * BOOTP cleanup. + * DHCP/BOOTP cleanup. */ static inline void ic_bootp_cleanup(void) { @@ -499,7 +628,7 @@ /* - * Send BOOTP request to single interface. + * Send DHCP/BOOTP request to single interface. */ static void __init ic_bootp_send_if(struct ic_device *d, u32 jiffies) { @@ -522,19 +651,19 @@ h->version = 4; h->ihl = 5; h->tot_len = htons(sizeof(struct bootp_pkt)); - h->frag_off = htons(IP_DF); + h->frag_off = __constant_htons(IP_DF); h->ttl = 64; h->protocol = IPPROTO_UDP; h->daddr = INADDR_BROADCAST; h->check = ip_fast_csum((unsigned char *) h, h->ihl); /* Construct UDP header */ - b->udph.source = htons(68); - b->udph.dest = htons(67); + b->udph.source = __constant_htons(68); + b->udph.dest = __constant_htons(67); b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr)); /* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */ - /* Construct BOOTP header */ + /* Construct DHCP/BOOTP header */ b->op = BOOTP_REQUEST; if (dev->type < 256) /* check for false types */ b->htype = dev->type; @@ -545,10 +674,19 @@ b->htype = dev->type; /* can cause undefined behavior */ } b->hlen = dev->addr_len; + b->your_ip = INADDR_NONE; + b->server_ip = INADDR_NONE; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies / HZ); - b->xid = ic_bootp_xid; - ic_bootp_init_ext(b->vendor_area); + b->xid = d->xid; + + /* add DHCP options or BOOTP extensions */ +#ifdef IPCONFIG_DHCP + if (ic_proto_enabled & IC_USE_DHCP) + ic_dhcp_init_options(b->exten); + else +#endif + ic_bootp_init_ext(b->exten); /* Chain packet down the line... */ skb->dev = dev; @@ -561,19 +699,6 @@ /* - * Send BOOTP requests to all interfaces. - */ -static void __init ic_bootp_send(u32 jiffies) -{ - struct ic_device *d; - - for(d=ic_first_dev; d; d=d->next) - if (d->able & IC_BOOTP) - ic_bootp_send_if(d, jiffies); -} - - -/* * Copy BOOTP-supplied string if not already set. */ static int __init ic_bootp_string(char *dest, char *src, int len, int max) @@ -582,21 +707,21 @@ return 0; if (len > max-1) len = max-1; - strncpy(dest, src, len); + memcpy(dest, src, len); dest[len] = '\0'; return 1; } /* - * Process BOOTP extension. + * Process BOOTP extensions. */ static void __init ic_do_bootp_ext(u8 *ext) { #ifdef IPCONFIG_DEBUG u8 *c; - printk("BOOTP: Got extension %02x",*ext); + printk("DHCP/BOOTP: Got extension %d:",*ext); for(c=ext+2; cnh.iph; struct iphdr *h = &b->iph; + struct ic_device *d; int len; + /* One reply at a time, please. */ + spin_lock(&ic_recv_lock); + /* If we already have a reply, just drop the packet */ if (ic_got_reply) goto drop; + /* Find the ic_device that the packet arrived on */ + d = ic_first_dev; + while (d && d->dev != dev) + d = d->next; + if (!d) + goto drop; /* should never happen */ + /* Check whether it's a BOOTP packet */ if (skb->pkt_type == PACKET_OTHERHOST || skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) || @@ -647,14 +790,14 @@ ip_fast_csum((char *) h, h->ihl) != 0 || skb->len < ntohs(h->tot_len) || h->protocol != IPPROTO_UDP || - b->udph.source != htons(67) || - b->udph.dest != htons(68) || + b->udph.source != __constant_htons(67) || + b->udph.dest != __constant_htons(68) || ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr)) goto drop; /* Fragments are not supported */ - if (h->frag_off & htons(IP_OFFSET|IP_MF)) { - printk(KERN_ERR "BOOTP: Ignoring fragmented reply.\n"); + if (h->frag_off & __constant_htons(IP_OFFSET | IP_MF)) { + printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented reply.\n"); goto drop; } @@ -662,41 +805,103 @@ len = ntohs(b->udph.len) - sizeof(struct udphdr); if (len < 300 || /* See RFC 951:2.1 */ b->op != BOOTP_REPLY || - b->xid != ic_bootp_xid) { + b->xid != d->xid) { printk("?"); goto drop; } - /* Extract basic fields */ - ic_myaddr = b->your_ip; - ic_servaddr = b->server_ip; - ic_got_reply = IC_BOOTP; - ic_dev = dev; - /* Parse extensions */ - if (b->vendor_area[0] == 99 && /* Check magic cookie */ - b->vendor_area[1] == 130 && - b->vendor_area[2] == 83 && - b->vendor_area[3] == 99) { - u8 *ext = &b->vendor_area[4]; + if (!memcmp(b->exten, ic_bootp_cookie, 4)) { /* Check magic cookie */ u8 *end = (u8 *) b + ntohs(b->iph.tot_len); + u8 *ext; + +#ifdef IPCONFIG_DHCP + + u32 server_id = INADDR_NONE; + int mt = 0; + + ext = &b->exten[4]; while (ext < end && *ext != 0xff) { - if (*ext == 0) /* Padding */ - ext++; - else { - u8 *opt = ext; - ext += ext[1] + 2; - if (ext <= end) - ic_do_bootp_ext(opt); + u8 *opt = ext++; + if (*opt == 0) /* Padding */ + continue; + ext += *ext + 1; + if (ext >= end) + break; + switch (*opt) { + case 53: /* Message type */ + if (opt[1]) + mt = opt[2]; + break; + case 54: /* Server ID (IP address) */ + if (opt[1] >= 4) + memcpy(&server_id, opt + 2, 4); + break; } } + +#ifdef IPCONFIG_DEBUG + printk("DHCP: Got message type %d\n", mt); +#endif + + switch (mt) { + case DHCPOFFER: + /* While in the process of accepting one offer, + ignore all others. */ + if (ic_myaddr != INADDR_NONE) + goto drop; + /* Let's accept that offer. */ + ic_myaddr = b->your_ip; + ic_servaddr = server_id; +#ifdef IPCONFIG_DEBUG + printk("DHCP: Offered address %u.%u.%u.%u", NIPQUAD(ic_myaddr)); + printk(" by server %u.%u.%u.%u\n", NIPQUAD(ic_servaddr)); +#endif + break; + + case DHCPACK: + /* Yeah! */ + break; + + default: + /* Urque. Forget it*/ + ic_myaddr = INADDR_NONE; + ic_servaddr = INADDR_NONE; + goto drop; + } + + ic_dhcp_msgtype = mt; + +#endif /* IPCONFIG_DHCP */ + + ext = &b->exten[4]; + while (ext < end && *ext != 0xff) { + u8 *opt = ext++; + if (*opt == 0) /* Padding */ + continue; + ext += *ext + 1; + if (ext < end) + ic_do_bootp_ext(opt); + } } + /* We have a winner! */ + ic_dev = dev; + ic_myaddr = b->your_ip; + ic_servaddr = b->server_ip; if (ic_gateway == INADDR_NONE && b->relay_ip) ic_gateway = b->relay_ip; + if (ic_nameserver == INADDR_NONE) + ic_nameserver = ic_servaddr; + ic_got_reply = IC_BOOTP; drop: + /* Show's over. Nothing to see here. */ + spin_unlock(&ic_recv_lock); + + /* Throw the packet out. */ kfree_skb(skb); + return 0; } @@ -705,36 +910,34 @@ /* - * Dynamic IP configuration -- BOOTP and RARP. + * Dynamic IP configuration -- DHCP, BOOTP, RARP. */ -#ifdef CONFIG_IP_PNP_DYNAMIC +#ifdef IPCONFIG_DYNAMIC static int __init ic_dynamic(void) { int retries; - unsigned long timeout, jiff; - unsigned long start_jiffies; - int do_rarp = ic_proto_have_if & IC_RARP; + struct ic_device *d; + unsigned long start_jiffies, timeout, jiff; int do_bootp = ic_proto_have_if & IC_BOOTP; + int do_rarp = ic_proto_have_if & IC_RARP; /* - * If neither BOOTP nor RARP was selected, return with an error. This - * routine gets only called when some pieces of information are mis- - * sing, and without BOOTP and RARP we are not able to get that in- - * formation. + * If none of DHCP/BOOTP/RARP was selected, return with an error. + * This routine gets only called when some pieces of information + * are missing, and without DHCP/BOOTP/RARP we are unable to get it. */ if (!ic_proto_enabled) { printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n"); return -1; } -#ifdef CONFIG_IP_PNP_BOOTP +#ifdef IPCONFIG_BOOTP if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP) - printk(KERN_ERR "BOOTP: No suitable device found.\n"); + printk(KERN_ERR "DHCP/BOOTP: No suitable device found.\n"); #endif - -#ifdef CONFIG_IP_PNP_RARP +#ifdef IPCONFIG_RARP if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP) printk(KERN_ERR "RARP: No suitable device found.\n"); #endif @@ -744,16 +947,16 @@ return -1; /* - * Setup RARP and BOOTP protocols + * Setup protocols */ -#ifdef CONFIG_IP_PNP_RARP - if (do_rarp) - ic_rarp_init(); -#endif -#ifdef CONFIG_IP_PNP_BOOTP +#ifdef IPCONFIG_BOOTP if (do_bootp) ic_bootp_init(); #endif +#ifdef IPCONFIG_RARP + if (do_rarp) + ic_rarp_init(); +#endif /* * Send requests and wait, until we get an answer. This loop @@ -763,61 +966,119 @@ * [Actually we could now, but the nothing else running note still * applies.. - AC] */ - printk(KERN_NOTICE "Sending %s%s%s requests...", - do_bootp ? "BOOTP" : "", - do_bootp && do_rarp ? " and " : "", - do_rarp ? "RARP" : ""); + printk(KERN_NOTICE "Sending %s%s%s requests .", + do_bootp + ? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "", + (do_bootp && do_rarp) ? " and " : "", + do_rarp ? "RARP" : ""); + start_jiffies = jiffies; - retries = CONF_RETRIES; + d = ic_first_dev; + retries = CONF_SEND_RETRIES; get_random_bytes(&timeout, sizeof(timeout)); timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM); for(;;) { -#ifdef CONFIG_IP_PNP_BOOTP - if (do_bootp) - ic_bootp_send(jiffies - start_jiffies); +#ifdef IPCONFIG_BOOTP + if (do_bootp && (d->able & IC_BOOTP)) + ic_bootp_send_if(d, jiffies - start_jiffies); #endif -#ifdef CONFIG_IP_PNP_RARP - if (do_rarp) - ic_rarp_send(); +#ifdef IPCONFIG_RARP + if (do_rarp && (d->able & IC_RARP)) + ic_rarp_send_if(d); #endif - printk("."); - jiff = jiffies + timeout; + + jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout); while (jiffies < jiff && !ic_got_reply) barrier(); +#ifdef IPCONFIG_DHCP + /* DHCP isn't done until we get a DHCPACK. */ + if ((ic_got_reply & IC_BOOTP) + && (ic_proto_enabled & IC_USE_DHCP) + && ic_dhcp_msgtype != DHCPACK) + { + ic_got_reply = 0; + printk(","); + continue; + } +#endif /* IPCONFIG_DHCP */ + if (ic_got_reply) { printk(" OK\n"); break; } + + if ((d = d->next)) + continue; + if (! --retries) { printk(" timed out!\n"); break; } + + d = ic_first_dev; + timeout = timeout CONF_TIMEOUT_MULT; if (timeout > CONF_TIMEOUT_MAX) timeout = CONF_TIMEOUT_MAX; + + printk("."); } -#ifdef CONFIG_IP_PNP_RARP - if (do_rarp) - ic_rarp_cleanup(); -#endif -#ifdef CONFIG_IP_PNP_BOOTP +#ifdef IPCONFIG_BOOTP if (do_bootp) ic_bootp_cleanup(); #endif +#ifdef IPCONFIG_RARP + if (do_rarp) + ic_rarp_cleanup(); +#endif if (!ic_got_reply) return -1; printk("IP-Config: Got %s answer from %u.%u.%u.%u, ", - (ic_got_reply & IC_BOOTP) ? "BOOTP" : "RARP", + ((ic_got_reply & IC_RARP) ? "RARP" + : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), NIPQUAD(ic_servaddr)); printk("my address is %u.%u.%u.%u\n", NIPQUAD(ic_myaddr)); return 0; } -#endif +#endif /* IPCONFIG_DYNAMIC */ + +#ifdef CONFIG_PROC_FS + +static int pnp_get_info(char *buffer, char **start, + off_t offset, int length) +{ + int len; + + if (ic_proto_used & IC_PROTO) + sprintf(buffer, "#PROTO: %s\n", + (ic_proto_used & IC_RARP) ? "RARP" + : (ic_proto_used & IC_USE_DHCP) ? "DHCP" : "BOOTP"); + else + strcpy(buffer, "#MANUAL\n"); + len = strlen(buffer); + + if (ic_domain[0]) + len += sprintf(buffer + len, + "domain %s\n", ic_domain); + if (ic_nameserver != INADDR_NONE) + len += sprintf(buffer + len, + "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameserver)); + + if (offset > len) + offset = len; + *start = buffer + offset; + + if (offset + length > len) + length = len - offset; + return length; +} + +#endif /* CONFIG_PROC_FS */ /* * IP Autoconfig dispatcher. @@ -825,15 +1086,33 @@ static int __init ip_auto_config(void) { + int retries = CONF_OPEN_RETRIES; + unsigned long jiff; + +#ifdef CONFIG_PROC_FS + proc_net_create("pnp", 0, pnp_get_info); +#endif /* CONFIG_PROC_FS */ + if (!ic_enable) return 0; DBG(("IP-Config: Entered.\n")); + try_try_again: + /* Give hardware a chance to settle */ + jiff = jiffies + CONF_PRE_OPEN; + while (jiffies < jiff) + ; + /* Setup all network devices */ if (ic_open_devs() < 0) return -1; + /* Give drivers a chance to settle */ + jiff = jiffies + CONF_POST_OPEN; + while (jiffies < jiff) + ; + /* * If the config information is insufficient (e.g., our IP address or * IP address of the boot server is missing or we have multiple network @@ -845,19 +1124,51 @@ (root_server_addr == INADDR_NONE && ic_servaddr == INADDR_NONE) || #endif ic_first_dev->next) { -#ifdef CONFIG_IP_PNP_DYNAMIC +#ifdef IPCONFIG_DYNAMIC + if (ic_dynamic() < 0) { - printk(KERN_ERR "IP-Config: Auto-configuration of network failed.\n"); ic_close_devs(); + + /* + * I don't know why, but sometimes the + * eepro100 driver (at least) gets upset and + * doesn't work the first time it's opened. + * But then if you close it and reopen it, it + * works just fine. So we need to try that at + * least once before giving up. + * + * Also, if the root will be NFS-mounted, we + * have nowhere to go if DHCP fails. So we + * just have to keep trying forever. + * + * -- Chip + */ +#ifdef CONFIG_ROOT_NFS + if (ROOT_DEV == MKDEV(UNNAMED_MAJOR, 255)) { + printk(KERN_ERR + "IP-Config: Retrying forever (NFS root)...\n"); + goto try_try_again; + } +#endif + + if (--retries) { + printk(KERN_ERR + "IP-Config: Reopening network devices...\n"); + goto try_try_again; + } + + /* Oh, well. At least we tried. */ + printk(KERN_ERR "IP-Config: Auto-configuration of network failed.\n"); return -1; } -#else +#else /* !DYNAMIC */ printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n"); ic_close_devs(); return -1; -#endif +#endif /* IPCONFIG_DYNAMIC */ } else { - ic_dev = ic_first_dev->dev; /* Device selected manually or only one device -> use it */ + /* Device selected manually or only one device -> use it */ + ic_dev = ic_first_dev->dev; } /* @@ -874,10 +1185,30 @@ if (ic_setup_if() < 0 || ic_setup_routes() < 0) return -1; - DBG(("IP-Config: device=%s, local=%08x, server=%08x, boot=%08x, gw=%08x, mask=%08x\n", - ic_dev->name, ic_myaddr, ic_servaddr, root_server_addr, ic_gateway, ic_netmask)); - DBG(("IP-Config: host=%s, domain=%s, path=`%s'\n", system_utsname.nodename, - system_utsname.domainname, root_server_path)); + /* + * Record which protocol was actually used. + */ +#ifdef IPCONFIG_DYNAMIC + ic_proto_used = ic_got_reply | (ic_proto_enabled & IC_USE_DHCP); +#endif + +#ifndef IPCONFIG_SILENT + /* + * Clue in the operator. + */ + printk("IP-Config: Complete:"); + printk("\n device=%s", ic_dev->name); + printk(", addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr)); + printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask)); + printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway)); + printk(",\n host=%s, domain=%s, nis-domain=%s", + system_utsname.nodename, ic_domain, system_utsname.domainname); + printk(",\n bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr)); + printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr)); + printk(", rootpath=%s", root_server_path); + printk("\n"); +#endif /* !SILENT */ + return 0; } @@ -889,7 +1220,7 @@ * command line parameter. It consists of option fields separated by colons in * the following order: * - * :::::: + * :::::: * * Any of the fields can be empty which means to use a default value: * - address given by BOOTP or RARP @@ -900,28 +1231,38 @@ * - in ASCII notation, or the name returned * by BOOTP * - use all available devices - * - use both protocols to determine my own address + * : + * off|none - don't do autoconfig at all (DEFAULT) + * on|any - use any configured protocol + * dhcp|bootp|rarp - use only the specified protocol + * both - use both BOOTP and RARP (not DHCP) */ static int __init ic_proto_name(char *name) { - if (!strcmp(name, "off")) { - ic_proto_enabled = 0; + if (!strcmp(name, "on") || !strcmp(name, "any")) { + return 1; + } +#ifdef CONFIG_IP_PNP_DHCP + else if (!strcmp(name, "dhcp")) { + ic_proto_enabled &= ~IC_RARP; return 1; } +#endif #ifdef CONFIG_IP_PNP_BOOTP else if (!strcmp(name, "bootp")) { - ic_proto_enabled &= ~IC_RARP; + ic_proto_enabled &= ~(IC_RARP | IC_USE_DHCP); return 1; } #endif #ifdef CONFIG_IP_PNP_RARP else if (!strcmp(name, "rarp")) { - ic_proto_enabled &= ~IC_BOOTP; + ic_proto_enabled &= ~(IC_BOOTP | IC_USE_DHCP); return 1; } #endif -#ifdef CONFIG_IP_PNP_DYNAMIC +#ifdef IPCONFIG_DYNAMIC else if (!strcmp(name, "both")) { + ic_proto_enabled &= ~IC_USE_DHCP; /* backward compat :-( */ return 1; } #endif @@ -934,10 +1275,13 @@ int num = 0; ic_set_manually = 1; - if (!strcmp(addrs, "off")) { - ic_enable = 0; + + ic_enable = (*addrs && + (strcmp(addrs, "off") != 0) && + (strcmp(addrs, "none") != 0)); + if (!ic_enable) return 1; - } + if (ic_proto_name(addrs)) return 1; diff -u --recursive --new-file v2.4.4/linux/net/ipv4/protocol.c linux/net/ipv4/protocol.c --- v2.4.4/linux/net/ipv4/protocol.c Tue Oct 10 10:33:52 2000 +++ linux/net/ipv4/protocol.c Tue May 1 20:59:24 2001 @@ -5,7 +5,7 @@ * * INET protocol dispatch tables. * - * Version: $Id: protocol.c,v 1.12 2000/10/03 07:29:00 anton Exp $ + * Version: $Id: protocol.c,v 1.13 2001/04/30 01:59:55 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -50,15 +50,11 @@ #ifdef CONFIG_IP_MULTICAST -static struct inet_protocol igmp_protocol = -{ - igmp_rcv, /* IGMP handler */ - NULL, /* IGMP error control */ - IPPROTO_PREVIOUS, /* next */ - IPPROTO_IGMP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "IGMP" /* name */ +static struct inet_protocol igmp_protocol = { + handler: igmp_rcv, + next: IPPROTO_PREVIOUS, + protocol: IPPROTO_IGMP, + name: "IGMP" }; #undef IPPROTO_PREVIOUS @@ -66,44 +62,33 @@ #endif -static struct inet_protocol tcp_protocol = -{ - tcp_v4_rcv, /* TCP handler */ - tcp_v4_err, /* TCP error control */ - IPPROTO_PREVIOUS, - IPPROTO_TCP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "TCP" /* name */ +static struct inet_protocol tcp_protocol = { + handler: tcp_v4_rcv, + err_handler: tcp_v4_err, + next: IPPROTO_PREVIOUS, + protocol: IPPROTO_TCP, + name: "TCP" }; #undef IPPROTO_PREVIOUS #define IPPROTO_PREVIOUS &tcp_protocol -static struct inet_protocol udp_protocol = -{ - udp_rcv, /* UDP handler */ - udp_err, /* UDP error control */ - IPPROTO_PREVIOUS, /* next */ - IPPROTO_UDP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "UDP" /* name */ +static struct inet_protocol udp_protocol = { + handler: udp_rcv, + err_handler: udp_err, + next: IPPROTO_PREVIOUS, + protocol: IPPROTO_UDP, + name: "UDP" }; #undef IPPROTO_PREVIOUS #define IPPROTO_PREVIOUS &udp_protocol - -static struct inet_protocol icmp_protocol = -{ - icmp_rcv, /* ICMP handler */ - NULL, /* ICMP error control */ - IPPROTO_PREVIOUS, /* next */ - IPPROTO_ICMP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "ICMP" /* name */ +static struct inet_protocol icmp_protocol = { + handler: icmp_rcv, + next: IPPROTO_PREVIOUS, + protocol: IPPROTO_ICMP, + name: "ICMP" }; #undef IPPROTO_PREVIOUS @@ -134,10 +119,8 @@ */ p2 = (struct inet_protocol *) prot->next; - while(p2 != NULL) - { - if (p2->protocol == prot->protocol) - { + while (p2) { + if (p2->protocol == prot->protocol) { prot->copy = 1; break; } @@ -158,23 +141,20 @@ hash = prot->protocol & (MAX_INET_PROTOS - 1); br_write_lock_bh(BR_NETPROTO_LOCK); - if (prot == inet_protos[hash]) - { + if (prot == inet_protos[hash]) { inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next; br_write_unlock_bh(BR_NETPROTO_LOCK); - return(0); + return 0; } p = (struct inet_protocol *) inet_protos[hash]; - while(p != NULL) - { + while (p) { /* * We have to worry if the protocol being deleted is * the last one on the list, then we may need to reset * someone's copied bit. */ - if (p->next != NULL && p->next == prot) - { + if (p->next && p->next == prot) { /* * if we are the last one with this protocol and * there is a previous one, reset its copy bit. @@ -183,7 +163,7 @@ lp->copy = 0; p->next = prot->next; br_write_unlock_bh(BR_NETPROTO_LOCK); - return(0); + return 0; } if (p->next != NULL && p->next->protocol == prot->protocol) lp = p; @@ -191,5 +171,5 @@ p = (struct inet_protocol *) p->next; } br_write_unlock_bh(BR_NETPROTO_LOCK); - return(-1); + return -1; } diff -u --recursive --new-file v2.4.4/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.4.4/linux/net/ipv4/tcp.c Wed Apr 25 14:57:39 2001 +++ linux/net/ipv4/tcp.c Tue May 1 20:59:24 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.202 2001/04/20 20:46:19 davem Exp $ + * Version: $Id: tcp.c,v 1.204 2001/05/01 23:07:49 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1122,8 +1122,16 @@ /* Time to copy data. We are close to the end! */ err = tcp_copy_to_page(sk, from, skb, page, off, copy); - if (err) + if (err) { + /* If this page was new, give it to the + * socket so it does not get leaked. + */ + if (TCP_PAGE(sk) == NULL) { + TCP_PAGE(sk) = page; + TCP_OFF(sk) = 0; + } goto do_error; + } /* Update the skb. */ if (merge) { @@ -1182,12 +1190,9 @@ return copied; do_fault: - if (skb->len==0) { - if (tp->send_head == skb) { - tp->send_head = skb->prev; - if (tp->send_head == (struct sk_buff*)&sk->write_queue) - tp->send_head = NULL; - } + if (skb->len == 0) { + if (tp->send_head == skb) + tp->send_head = NULL; __skb_unlink(skb, skb->list); tcp_free_skb(sk, skb); } diff -u --recursive --new-file v2.4.4/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.4.4/linux/net/ipv6/addrconf.c Fri Apr 27 14:15:01 2001 +++ linux/net/ipv6/addrconf.c Tue May 1 20:59:24 2001 @@ -6,7 +6,7 @@ * Pedro Roque * Alexey Kuznetsov * - * $Id: addrconf.c,v 1.62 2001/04/26 19:11:59 davem Exp $ + * $Id: addrconf.c,v 1.64 2001/05/01 23:05:47 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,6 +22,10 @@ * Andi Kleen : kill doube kfree on module * unload. * Maciej W. Rozycki : FDDI support + * sekiya@USAGI : Don't send too many RS + * packets. + * yoshfuji@USAGI : Fixed interval between DAD + * packets. */ #include @@ -1509,7 +1513,7 @@ } ifp->probes--; - addrconf_mod_timer(ifp, AC_DAD, ifp->idev->cnf.rtr_solicit_interval); + addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); spin_unlock_bh(&ifp->lock); /* send a neighbour solicitation for our addr */ diff -u --recursive --new-file v2.4.4/linux/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.4.4/linux/net/irda/af_irda.c Thu Apr 12 12:11:39 2001 +++ linux/net/irda/af_irda.c Tue May 1 16:05:00 2001 @@ -218,8 +218,7 @@ self->max_data_size); memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); - - skb_queue_tail(&sk->receive_queue, skb); + kfree_skb(skb); /* We are now connected! */ sk->state = TCP_ESTABLISHED; @@ -439,7 +438,7 @@ * We were waiting for a node to be discovered, but nothing has come up * so far. Wake up the user and tell him that we failed... */ -static void irda_discovery_timeout(u_long priv) +static void irda_discovery_timeout(u_long priv) { struct irda_sock *self; @@ -776,7 +775,6 @@ struct sock *sk = sock->sk; struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr; struct irda_sock *self; - __u16 hints = 0; int err; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -821,15 +819,6 @@ self->stsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->ias_obj); -#if 1 /* Will be removed in near future */ - - /* Fill in some default hint bits values */ - if (strncmp(addr->sir_name, "OBEX", 4) == 0) - hints = irlmp_service_to_hint(S_OBEX); - - if (hints) - self->skey = irlmp_register_service(hints); -#endif return 0; } @@ -1633,34 +1622,54 @@ { struct sock *sk = sock->sk; unsigned int mask; + struct irda_sock *self; IRDA_DEBUG(4, __FUNCTION__ "()\n"); + self = sk->protinfo.irda; poll_wait(file, sk->sleep, wait); mask = 0; - /* exceptional events? */ + /* Exceptional events? */ if (sk->err) mask |= POLLERR; if (sk->shutdown & RCV_SHUTDOWN) mask |= POLLHUP; - /* readable? */ + /* Readable? */ if (!skb_queue_empty(&sk->receive_queue)) { IRDA_DEBUG(4, "Socket is readable\n"); mask |= POLLIN | POLLRDNORM; } + /* Connection-based need to check for termination and startup */ - if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE) - mask |= POLLHUP; + switch (sk->type) { + case SOCK_STREAM: + if (sk->state == TCP_CLOSE) + mask |= POLLHUP; - /* - * we set writable also when the other side has shut down the - * connection. This prevents stuck sockets. - */ - if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE) + if (sk->state == TCP_ESTABLISHED) { + if ((self->tx_flow == FLOW_START) && + (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)) + { + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + } + } + break; + case SOCK_SEQPACKET: + if ((self->tx_flow == FLOW_START) && + (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)) + { mask |= POLLOUT | POLLWRNORM | POLLWRBAND; - + } + break; + case SOCK_DGRAM: + if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + break; + default: + break; + } return mask; } @@ -2328,6 +2337,9 @@ SOCKOPS_WRAP(irda_stream, PF_IRDA); SOCKOPS_WRAP(irda_seqpacket, PF_IRDA); SOCKOPS_WRAP(irda_dgram, PF_IRDA); +#ifdef CONFIG_IRDA_ULTRA +SOCKOPS_WRAP(irda_ultra, PF_IRDA); +#endif /* CONFIG_IRDA_ULTRA */ /* * Function irda_device_event (this, event, ptr) @@ -2416,7 +2428,9 @@ #endif return 0; } -module_init(irda_proto_init); +#ifdef MODULE +module_init(irda_proto_init); /* If non-module, called from init/main.c */ +#endif /* * Function irda_proto_cleanup (void) diff -u --recursive --new-file v2.4.4/linux/net/irda/irias_object.c linux/net/irda/irias_object.c --- v2.4.4/linux/net/irda/irias_object.c Fri Mar 2 11:12:12 2001 +++ linux/net/irda/irias_object.c Tue May 1 16:05:00 2001 @@ -34,7 +34,7 @@ /* * Used when a missing value needs to be returned */ -struct ias_value missing = { IAS_MISSING, 0, 0, 0}; +struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}}; /* * Function strdup (str) diff -u --recursive --new-file v2.4.4/linux/net/irda/irlap.c linux/net/irda/irlap.c --- v2.4.4/linux/net/irda/irlap.c Fri Mar 2 11:12:12 2001 +++ linux/net/irda/irlap.c Tue May 1 16:05:00 2001 @@ -860,13 +860,6 @@ /* Free sliding window buffered packets */ while ((skb = skb_dequeue(&self->wx_list)) != NULL) dev_kfree_skb(skb); - -#ifdef CONFIG_IRDA_RECYCLE_RR - if (self->recycle_rr_skb) { - dev_kfree_skb(self->recycle_rr_skb); - self->recycle_rr_skb = NULL; - } -#endif } /* @@ -1076,7 +1069,7 @@ /* Set the negociated xbofs value */ self->next_bofs = self->qos_tx.additional_bofs.value; - if(now) + if (now) self->bofs_count = self->next_bofs; /* Set the negociated link speed (may need the new xbofs value) */ @@ -1107,13 +1100,13 @@ */ self->N1 = -1; /* Disable */ else - self->N1 = 3000 / self->qos_tx.max_turn_time.value; + self->N1 = 3000 / self->qos_rx.max_turn_time.value; IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1); self->N2 = self->qos_tx.link_disc_time.value * 1000 / - self->qos_tx.max_turn_time.value; + self->qos_rx.max_turn_time.value; IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2); /* diff -u --recursive --new-file v2.4.4/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c --- v2.4.4/linux/net/irda/irlap_frame.c Thu Feb 8 15:14:08 2001 +++ linux/net/irda/irlap_frame.c Tue May 1 16:05:00 2001 @@ -742,12 +742,6 @@ return; } - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* * Insert frame in store, in case of retransmissions */ @@ -788,12 +782,6 @@ return; } - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* * Insert frame in store, in case of retransmissions */ @@ -863,9 +851,6 @@ return; } - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Insert frame in store */ skb_queue_tail(&self->wx_list, skb_get(skb)); @@ -917,9 +902,6 @@ return; } - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Insert frame in store */ skb_queue_tail(&self->wx_list, skb_get(skb)); @@ -973,12 +955,6 @@ tx_skb->next = tx_skb->prev = NULL; tx_skb->list = NULL; - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; @@ -1058,12 +1034,6 @@ /* Unlink tx_skb from list */ tx_skb->next = tx_skb->prev = NULL; tx_skb->list = NULL; - - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; diff -u --recursive --new-file v2.4.4/linux/net/irda/irlmp.c linux/net/irda/irlmp.c --- v2.4.4/linux/net/irda/irlmp.c Fri Mar 2 11:12:12 2001 +++ linux/net/irda/irlmp.c Tue May 1 16:05:00 2001 @@ -959,6 +959,7 @@ { ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + ASSERT(skb->sk == NULL, /* Just a warning - NOP */;); /* Make room for MUX header */ ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;); diff -u --recursive --new-file v2.4.4/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c --- v2.4.4/linux/net/irda/irlmp_event.c Sat Nov 11 18:11:22 2000 +++ linux/net/irda/irlmp_event.c Tue May 1 16:05:00 2001 @@ -472,8 +472,6 @@ irlmp_start_watchdog_timer(self, 5*HZ); break; case LM_CONNECT_INDICATION: - irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); - if (self->conn_skb) { WARNING(__FUNCTION__ "(), busy with another request!\n"); @@ -481,6 +479,8 @@ } self->conn_skb = skb; + irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); break; default: @@ -562,6 +562,15 @@ switch (event) { case LM_CONNECT_REQUEST: /* Keep state */ + break; + case LM_CONNECT_INDICATION: + /* Will happen in some rare cases when the socket get stuck, + * the other side retries the connect request. + * We just unstuck the socket - Jean II */ + IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, " + "LSAP stuck in CONNECT_PEND state...\n"); + /* Keep state */ + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); break; case LM_CONNECT_RESPONSE: IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h --- v2.4.4/linux/net/irda/irnet/irnet.h Fri Mar 2 11:12:12 2001 +++ linux/net/irda/irnet/irnet.h Tue May 1 16:05:00 2001 @@ -5,7 +5,7 @@ * * This file contains definitions and declarations global to the IrNET module, * all grouped in one place... - * This file is a private header, so other modules don't want to know + * This file is a *private* header, so other modules don't want to know * what's in there... * * Note : as most part of the Linux kernel, this module is available @@ -52,15 +52,13 @@ * o multipoint operation (limited by IrLAP specification) * o information in /proc/net/irda/irnet * o IrNET events on /dev/irnet (for user space daemon) - * o IrNET deamon (irnetd) to automatically handle incoming requests + * o IrNET daemon (irnetd) to automatically handle incoming requests * o Windows 2000 compatibility (tested, but need more work) * Currently missing : * o Lot's of testing (that's your job) * o Connection retries (may be too hard to do) * o Check pppd persist mode - * o User space deamon (to automatically handle incoming requests) - * o A registered device number (coming, waiting from an answer) - * o Final integration in Linux-IrDA (up to Dag) + * o User space daemon (to automatically handle incoming requests) * * The setup is not currently the most easy, but this should get much * better when everything will get integrated... @@ -159,6 +157,17 @@ * o Add IRNET_NOANSWER_FROM event (mostly to help support) * o Release flow control in disconnect_indication * o Block packets while connecting (speed up connections) + * + * v5 - 11/01/01 - Jean II + * o Init self->max_header_size, just in case... + * o Set up ap->chan.hdrlen, to get zero copy on tx side working. + * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state + * Thanks to Christian Gennerat for finding this bug ! + * --- + * o Declare the proper MTU/MRU that we can support + * (but PPP doesn't read the MTU value :-() + * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid + * disabling and enabling irq twice */ /***************************** INCLUDES *****************************/ @@ -375,7 +384,7 @@ struct irda_device_info *discoveries; /* Copy of the discovery log */ int disco_index; /* Last read in the discovery log */ int disco_number; /* Size of the discovery log */ -#endif INITIAL_DISCOVERY +#endif /* INITIAL_DISCOVERY */ } irnet_socket; @@ -450,4 +459,4 @@ /* Control channel stuff - allocated in irnet_irda.h */ extern struct irnet_ctrl_channel irnet_events; -#endif IRNET_H +#endif /* IRNET_H */ diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c --- v2.4.4/linux/net/irda/irnet/irnet_irda.c Fri Mar 2 11:12:12 2001 +++ linux/net/irda/irnet/irnet_irda.c Tue May 1 16:05:00 2001 @@ -380,9 +380,9 @@ self->ckey = irlmp_register_client(0, NULL, NULL, NULL); #ifdef DISCOVERY_NOMASK self->mask = 0xffff; /* For W2k compatibility */ -#else DISCOVERY_NOMASK +#else /* DISCOVERY_NOMASK */ self->mask = irlmp_service_to_hint(S_LAN); -#endif DISCOVERY_NOMASK +#endif /* DISCOVERY_NOMASK */ self->tx_flow = FLOW_START; /* Flow control from IrTTP */ DEXIT(IRDA_SOCK_TRACE, "\n"); @@ -692,7 +692,7 @@ /* If we want to receive "stream sockets" */ if(max_sdu_size == 0) new->max_data_size = irttp_get_max_seg_size(new->tsap); -#endif STREAM_COMPAT +#endif /* STREAM_COMPAT */ /* Clean up the original one to keep it in listen state */ self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY; @@ -708,7 +708,7 @@ * Also, not doing it give IrDA a chance to finish the setup properly * before beeing swamped with packets... */ ppp_output_wakeup(&new->chan); -#endif CONNECT_INDIC_KICK +#endif /* CONNECT_INDIC_KICK */ /* Notify the control channel */ irnet_post_event(new, IRNET_CONNECT_FROM, new->daddr, self->rname); @@ -738,7 +738,7 @@ /* Hum... Is it the right thing to do ? And do we need to send * a connect response before ? It looks ok without this... */ irttp_disconnect_request(self->tsap, NULL, P_NORMAL); -#endif FAIL_SEND_DISCONNECT +#endif /* FAIL_SEND_DISCONNECT */ /* Clean up the server to keep it in listen state */ self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY; @@ -788,7 +788,7 @@ #ifdef ADVERTISE_HINT /* Register with IrLMP as a service (advertise our hint bit) */ irnet_server.skey = irlmp_register_service(hints); -#endif ADVERTISE_HINT +#endif /* ADVERTISE_HINT */ /* Register with LM-IAS (so that people can connect to us) */ irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies); @@ -823,7 +823,7 @@ #ifdef ADVERTISE_HINT /* Unregister with IrLMP */ irlmp_unregister_service(irnet_server.skey); -#endif ADVERTISE_HINT +#endif /* ADVERTISE_HINT */ /* Unregister with LM-IAS */ if(irnet_server.ias_obj) @@ -995,7 +995,7 @@ #ifdef STREAM_COMPAT if(max_sdu_size == 0) self->max_data_size = irttp_get_max_seg_size(self->tsap); -#endif STREAM_COMPAT +#endif /* STREAM_COMPAT */ /* At this point, IrLMP has assigned our source address */ self->saddr = irttp_get_saddr(self->tsap); @@ -1012,10 +1012,10 @@ DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); /* Try to pass it to PPP */ irnet_data_indication(instance, sap, skb); -#else PASS_CONNECT_PACKETS +#else /* PASS_CONNECT_PACKETS */ DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); kfree_skb(skb); /* Note : will be optimised with other kfree... */ -#endif PASS_CONNECT_PACKETS +#endif /* PASS_CONNECT_PACKETS */ } else kfree_skb(skb); @@ -1039,6 +1039,7 @@ LOCAL_FLOW flow) { irnet_socket * self = (irnet_socket *) instance; + LOCAL_FLOW oldflow = self->tx_flow; DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow); @@ -1050,7 +1051,11 @@ { case FLOW_START: DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n"); - ppp_output_wakeup(&self->chan); + /* Check if we really need to wake up PPP */ + if(oldflow == FLOW_STOP) + ppp_output_wakeup(&self->chan); + else + DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n"); break; case FLOW_STOP: DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n"); @@ -1157,10 +1162,10 @@ * WARNING : This need more testing ! */ irttp_close_tsap(new->tsap); /* Note : no return, fall through... */ -#else ALLOW_SIMULT_CONNECT +#else /* ALLOW_SIMULT_CONNECT */ irnet_disconnect_server(self, skb); return; -#endif ALLOW_SIMULT_CONNECT +#endif /* ALLOW_SIMULT_CONNECT */ } /* So : at this point, we have a socket, and it is idle. Good ! */ @@ -1173,10 +1178,10 @@ DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); /* Try to pass it to PPP */ irnet_data_indication(new, new->tsap, skb); -#else PASS_CONNECT_PACKETS +#else /* PASS_CONNECT_PACKETS */ DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); kfree_skb(skb); /* Note : will be optimised with other kfree... */ -#endif PASS_CONNECT_PACKETS +#endif /* PASS_CONNECT_PACKETS */ } else kfree_skb(skb); @@ -1312,7 +1317,7 @@ DEXIT(IRDA_OCB_TRACE, "\n"); } -#endif DISCOVERY_EVENTS +#endif /* DISCOVERY_EVENTS */ /*********************** PROC ENTRY CALLBACKS ***********************/ @@ -1426,7 +1431,7 @@ memset(&irnet_server, 0, sizeof(struct irnet_root)); /* Setup start of irnet instance list */ - irnet_server.list = hashbin_new(HB_LOCAL); + irnet_server.list = hashbin_new(HB_NOLOCK); DABORT(irnet_server.list == NULL, -ENOMEM, MODULE_ERROR, "Can't allocate hashbin!\n"); /* Init spinlock for instance list */ @@ -1469,7 +1474,7 @@ #ifdef CONFIG_PROC_FS /* Remove our /proc file */ remove_proc_entry("irnet", proc_irda); -#endif CONFIG_PROC_FS +#endif /* CONFIG_PROC_FS */ /* Remove our IrNET server from existence */ irnet_destroy_server(); diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_irda.h linux/net/irda/irnet/irnet_irda.h --- v2.4.4/linux/net/irda/irnet/irnet_irda.h Mon Dec 11 13:33:15 2000 +++ linux/net/irda/irnet/irnet_irda.h Tue May 1 16:05:00 2001 @@ -13,8 +13,9 @@ #define IRNET_IRDA_H /***************************** INCLUDES *****************************/ - #include +/* Please add other headers in irnet.h */ + #include "irnet.h" /* Module global include */ /************************ CONSTANTS & MACROS ************************/ @@ -149,7 +150,7 @@ char **, off_t, int); -#endif CONFIG_PROC_FS +#endif /* CONFIG_PROC_FS */ /**************************** VARIABLES ****************************/ @@ -164,6 +165,6 @@ /* The /proc/net/irda directory, defined elsewhere... */ #ifdef CONFIG_PROC_FS extern struct proc_dir_entry *proc_irda; -#endif CONFIG_PROC_FS +#endif /* CONFIG_PROC_FS */ -#endif IRNET_IRDA_H +#endif /* IRNET_IRDA_H */ diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_ppp.c linux/net/irda/irnet/irnet_ppp.c --- v2.4.4/linux/net/irda/irnet/irnet_ppp.c Fri Apr 20 11:54:24 2001 +++ linux/net/irda/irnet/irnet_ppp.c Tue May 1 16:05:00 2001 @@ -186,7 +186,7 @@ return done_event; } -#endif INITIAL_DISCOVERY +#endif /* INITIAL_DISCOVERY */ /*------------------------------------------------------------------*/ /* @@ -221,7 +221,7 @@ DEXIT(CTRL_TRACE, "\n"); return(strlen(event)); } -#endif INITIAL_DISCOVERY +#endif /* INITIAL_DISCOVERY */ /* Put ourselves on the wait queue to be woken up */ add_wait_queue(&irnet_events.rwait, &wait); @@ -346,7 +346,7 @@ #ifdef INITIAL_DISCOVERY if(ap->disco_number != -1) mask |= POLLIN | POLLRDNORM; -#endif INITIAL_DISCOVERY +#endif /* INITIAL_DISCOVERY */ DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask); return mask; @@ -379,7 +379,7 @@ /* This could (should?) be enforced by the permissions on /dev/irnet. */ if(!capable(CAP_NET_ADMIN)) return -EPERM; -#endif SECURE_DEVIRNET +#endif /* SECURE_DEVIRNET */ /* Allocate a private structure for this IrNET instance */ ap = kmalloc(sizeof(*ap), GFP_KERNEL); @@ -394,8 +394,11 @@ /* PPP channel setup */ ap->ppp_open = 0; ap->chan.private = ap; + ap->chan.ops = &irnet_ppp_ops; + ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); + ap->chan.hdrlen = 2 + TTP_MAX_HEADER; /* for A/C + Max IrDA hdr */ /* PPP parameters */ - ap->mru = PPP_MRU; + ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); ap->xaccm[0] = ~0U; ap->xaccm[3] = 0x60000000U; ap->raccm = ~0U; @@ -554,7 +557,7 @@ #ifdef SECURE_DEVIRNET if(!capable(CAP_NET_ADMIN)) return -EPERM; -#endif SECURE_DEVIRNET +#endif /* SECURE_DEVIRNET */ err = -EFAULT; switch(cmd) @@ -566,10 +569,7 @@ if((val == N_SYNC_PPP) || (val == N_PPP)) { DEBUG(FS_INFO, "Entering PPP discipline.\n"); - /* PPP channel setup */ - ap->chan.private = ap; - ap->chan.ops = &irnet_ppp_ops; - ap->chan.mtu = PPP_MRU; + /* PPP channel setup (ap->chan in configued in dev_irnet_open())*/ err = ppp_register_channel(&ap->chan); if(err == 0) { @@ -672,7 +672,7 @@ * we get rid of our own buffers */ #ifdef FLUSH_TO_PPP ppp_output_wakeup(&ap->chan); -#endif FLUSH_TO_PPP +#endif /* FLUSH_TO_PPP */ err = 0; break; @@ -758,7 +758,7 @@ /* prepend address/control fields if necessary */ if(needaddr) { - skb_push(skb,2); + skb_push(skb, 2); skb->data[0] = PPP_ALLSTATIONS; skb->data[1] = PPP_UI; } @@ -800,7 +800,7 @@ * go through interruptible_sleep_on() in irnet_find_lsap_sel() * We need to find another way... */ irda_irnet_connect(self); -#endif CONNECT_IN_SEND +#endif /* CONNECT_IN_SEND */ DEBUG(PPP_INFO, "IrTTP not ready ! (%d-0x%X)\n", self->ttp_open, (unsigned int) self->tsap); @@ -831,7 +831,7 @@ /* Blocking packet, ppp_generic will retry later */ return 0; } -#endif BLOCK_WHEN_CONNECT +#endif /* BLOCK_WHEN_CONNECT */ /* Dropping packet, pppd will retry later */ dev_kfree_skb(skb); diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_ppp.h linux/net/irda/irnet/irnet_ppp.h --- v2.4.4/linux/net/irda/irnet/irnet_ppp.h Mon Dec 11 13:33:14 2000 +++ linux/net/irda/irnet/irnet_ppp.h Mon Apr 30 16:26:09 2001 @@ -27,8 +27,8 @@ * Should be defined in */ #ifndef PPPIOCSLINKNAME #define PPPIOCSLINKNAME _IOW('t', 74, struct ppp_option_data) -#endif PPPIOCSLINKNAME -#endif LINKNAME_IOCTL +#endif /* PPPIOCSLINKNAME */ +#endif /* LINKNAME_IOCTL */ /* PPP hardcore stuff */ @@ -127,4 +127,4 @@ ppp_irnet_ioctl }; -#endif IRNET_PPP_H +#endif /* IRNET_PPP_H */ diff -u --recursive --new-file v2.4.4/linux/net/irda/irttp.c linux/net/irda/irttp.c --- v2.4.4/linux/net/irda/irttp.c Thu Feb 8 15:14:08 2001 +++ linux/net/irda/irttp.c Tue May 1 16:05:00 2001 @@ -369,7 +369,7 @@ } else { /* * Fragment the frame, this function will also queue the - * fragments, we don't care about the fact the the transmit + * fragments, we don't care about the fact the transmit * queue may be overfilled by all the segments for a little * while */ @@ -454,6 +454,46 @@ */ skb->data[0] |= (n & 0x7f); + /* Detach from socket. + * The current skb has a reference to the socket that sent + * it (skb->sk). When we pass it to IrLMP, the skb will be + * stored in in IrLAP (self->wx_list). When we are within + * IrLAP, we loose the notion of socket, so we should not + * have a reference to a socket. So, we drop it here. + * + * Why does it matter ? + * When the skb is freed (kfree_skb), if it is associated + * with a socket, it release buffer space on the socket + * (through sock_wfree() and sock_def_write_space()). + * If the socket no longer exist, we may crash. Hard. + * When we close a socket, we make sure that associated packets + * in IrTTP are freed. However, we have no way to cancel + * the packet that we have passed to IrLAP. So, if a packet + * remains in IrLAP (retry on the link or else) after we + * close the socket, we are dead ! + * Jean II */ + if (skb->sk != NULL) { + struct sk_buff *tx_skb; + + /* IrSOCK application, IrOBEX, ... */ + IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n"); + /* Note : still looking for a more efficient way + * to do that - Jean II */ + + /* Get another skb on the same buffer, but without + * a reference to the socket (skb->sk = NULL) */ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb != NULL) { + /* Release the skb associated with the + * socket, and use the new skb insted */ + kfree_skb(skb); + skb = tx_skb; + } + } else { + /* IrCOMM over IrTTP, IrLAN, ... */ + IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n"); + } + irlmp_data_request(self->lsap, skb); self->stats.tx_packets++; diff -u --recursive --new-file v2.4.4/linux/net/irda/qos.c linux/net/irda/qos.c --- v2.4.4/linux/net/irda/qos.c Thu Feb 8 15:14:08 2001 +++ linux/net/irda/qos.c Mon Apr 30 16:26:09 2001 @@ -346,7 +346,7 @@ WARNING(__FUNCTION__ "(), nothing more we can do!\n"); } } -#endif CONFIG_IRDA_DYNAMIC_WINDOW +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ } /* diff -u --recursive --new-file v2.4.4/linux/net/irda/wrapper.c linux/net/irda/wrapper.c --- v2.4.4/linux/net/irda/wrapper.c Sat Nov 11 18:11:23 2000 +++ linux/net/irda/wrapper.c Mon Apr 30 16:26:09 2001 @@ -130,7 +130,7 @@ #ifdef __LITTLE_ENDIAN n += stuff_byte(fcs.bytes[0], tx_buff+n); n += stuff_byte(fcs.bytes[1], tx_buff+n); -#else ifdef __BIG_ENDIAN +#else /* ifdef __BIG_ENDIAN */ n += stuff_byte(fcs.bytes[1], tx_buff+n); n += stuff_byte(fcs.bytes[0], tx_buff+n); #endif